├── .gitattributes ├── .github ├── codecov.yml └── workflows │ ├── build.yml │ ├── coverage.yml │ └── lint.yml ├── .gitignore ├── .gitmodules ├── .swift-format ├── .vscode ├── extensions.json ├── settings.json └── tasks.json ├── CMakeLists.txt ├── CMakePresets.json ├── Documentation ├── BundleLayout.md ├── Images │ └── screenshot.png └── PrincipalClass.md ├── Examples ├── CMakeLists.txt ├── Calculator │ ├── CMakeLists.txt │ ├── Calculator.exe.manifest │ ├── Calculator.swift │ └── Info.plist └── UICatalog │ ├── Assets │ └── CoffeeCup.jpg │ ├── CMakeLists.txt │ ├── Info.plist │ ├── UICatalog.exe.manifest │ └── UICatalog.swift ├── LICENSE.txt ├── Package.swift ├── Package@swift-5.4.swift ├── Package@swift-5.5.swift ├── Package@swift-5.6.swift ├── Package@swift-5.7.swift ├── Package@swift-5.8.swift ├── README.md ├── Sources ├── CMakeLists.txt ├── SwiftWin32 │ ├── Animation and Haptics │ │ ├── Property-Based Animations │ │ │ ├── CubicTimingParameters.swift │ │ │ ├── SpringTimingParameters.swift │ │ │ ├── TimingCurveProvider.swift │ │ │ ├── ViewAnimating.swift │ │ │ └── ViewImplicitlyAnimating.swift │ │ ├── View Controller Transitions │ │ │ ├── ViewControllerAnimatedTransitioning.swift │ │ │ ├── ViewControllerInteractiveTransitioning.swift │ │ │ ├── ViewControllerTransitionCoordinator.swift │ │ │ ├── ViewControllerTransitionCoordinatorContext.swift │ │ │ └── ViewControllerTransitioningDelegate.swift │ │ └── ViewControllerContextTransitioning.swift │ ├── App Extensions │ │ └── InputViewController.swift │ ├── App and Environment │ │ ├── AdaptivePresentationControllerDelegate.swift │ │ ├── Application.swift │ │ ├── ApplicationDelegate.swift │ │ ├── ApplicationMain.swift │ │ ├── Device.swift │ │ ├── Scenes │ │ │ ├── Scene.swift │ │ │ ├── SceneConfiguration.swift │ │ │ ├── SceneDelegate.swift │ │ │ ├── SceneSession.swift │ │ │ ├── WindowScene.swift │ │ │ └── WindowSceneDelegate.swift │ │ ├── TraitCollection.swift │ │ └── TraitEnvironment.swift │ ├── Appearance Customization │ │ ├── Appearance.swift │ │ ├── AppearanceContainer.swift │ │ └── Configurations │ │ │ ├── BackgroundConfiguration.swift │ │ │ ├── CellConfigurationState.swift │ │ │ ├── ConfigurationColorTransformer.swift │ │ │ ├── ConfigurationState.swift │ │ │ ├── ConfigurationStateCustomKey.swift │ │ │ ├── ContentConfiguration.swift │ │ │ ├── ContentView.swift │ │ │ ├── ListContentConfiguration.swift │ │ │ └── ViewConfigurationState.swift │ ├── Application │ │ ├── Information.swift │ │ ├── LaunchKeyOptions.swift │ │ └── _TriviallyConstructible.swift │ ├── AutoLayout │ │ ├── LayoutAnchor.swift │ │ ├── LayoutConstraint+Cassowary.swift │ │ ├── LayoutConstraint.swift │ │ ├── LayoutDimension.swift │ │ ├── LayoutGuide.swift │ │ ├── LayoutPriority.swift │ │ ├── LayoutSupport.swift │ │ ├── LayoutXAxisAnchor.swift │ │ └── LayoutYAxisAnchor.swift │ ├── CMakeLists.txt │ ├── CoreAnimation │ │ └── Transform3D.swift │ ├── CoreGraphics │ │ ├── AffineTransform.swift │ │ ├── Point.swift │ │ ├── Rect.swift │ │ ├── Size.swift │ │ └── Vector.swift │ ├── Drag and Drop │ │ └── SpringLoadedInteractionContext.swift │ ├── Drawing │ │ ├── BezierPath.swift │ │ └── Color.swift │ ├── Focus-Based Navigation │ │ ├── FocusAnimationCoordinator.swift │ │ ├── FocusEnvironment.swift │ │ ├── FocusItem.swift │ │ ├── FocusItemContainer.swift │ │ ├── FocusMovementHint.swift │ │ └── FocusUpdateContext.swift │ ├── Images and PDF │ │ └── Image.swift │ ├── Keyboards and Input │ │ └── TextInputTraits.swift │ ├── Menus and Shortcuts │ │ ├── Action.swift │ │ ├── Command.swift │ │ ├── ContextMenuConfiguration.swift │ │ ├── ContextMenuInteraction.swift │ │ ├── ContextMenuInteractionAnimating.swift │ │ ├── ContextMenuInteractionCommitAnimating.swift │ │ ├── ContextMenuInteractionDelegate.swift │ │ ├── Menu.swift │ │ ├── MenuBuilder.swift │ │ ├── MenuElement.swift │ │ ├── MenuSystem.swift │ │ ├── PreviewParameters.swift │ │ ├── PreviewTarget.swift │ │ └── TargetedPreview.swift │ ├── Platform │ │ ├── BatteryMonitor.swift │ │ ├── Error.swift │ │ ├── OrientationSensor.swift │ │ ├── Win32+Menu.swift │ │ ├── Win32+PropertyWrappers.swift │ │ ├── WindowClass.swift │ │ └── WindowsHandle.swift │ ├── Pointer Interactions │ │ ├── PointerInteraction.swift │ │ ├── PointerInteractionAnimating.swift │ │ ├── PointerInteractionDelegate.swift │ │ ├── PointerRegion.swift │ │ ├── PointerRegionRequest.swift │ │ └── PointerStyle.swift │ ├── Support │ │ ├── Array+Extensions.swift │ │ ├── Date+Extensions.swift │ │ ├── IndexPath+UIExtensions.swift │ │ ├── Logging.swift │ │ ├── Point+UIExtensions.swift │ │ ├── Rect+UIExtensions.swift │ │ ├── Size+UIExtensions.swift │ │ ├── String+UIExtensions.swift │ │ ├── WinSDK+Extensions.swift │ │ ├── WinSDK+UIExtensions.swift │ │ ├── WindowMessage.swift │ │ └── WindowsHandle+UIExtensions.swift │ ├── Text Display and Fonts │ │ ├── Font.swift │ │ ├── FontDescriptor.swift │ │ └── FontMetrics.swift │ ├── Text Storage │ │ └── ParagraphStyle.swift │ ├── Touches, Presses, and Gestures │ │ ├── Event.swift │ │ ├── GestureRecognizer.swift │ │ ├── GestureRecognizerDelegate.swift │ │ ├── Press.swift │ │ ├── PressesEvent.swift │ │ ├── Responder.swift │ │ ├── TapGestureRecognizer.swift │ │ └── Touch.swift │ ├── UI │ │ ├── ContentSizeCategoryAdjusting.swift │ │ ├── ContentSizeCategoryImageAdjusting.swift │ │ ├── Interaction.swift │ │ └── SceneSizeRestrictions.swift │ ├── View Controllers │ │ ├── ContentContainer.swift │ │ ├── PresentationController.swift │ │ └── ViewController.swift │ ├── Views and Controls │ │ ├── Axis.swift │ │ ├── BarButtonItem.swift │ │ ├── BarButtonItemGroup.swift │ │ ├── BarItem.swift │ │ ├── BarPositioning.swift │ │ ├── Button.swift │ │ ├── Control.swift │ │ ├── DatePicker.swift │ │ ├── DirectionalEdgeInsets.swift │ │ ├── DirectionalRectEdge.swift │ │ ├── EdgeInsets.swift │ │ ├── ImageView.swift │ │ ├── Label.swift │ │ ├── Offset.swift │ │ ├── PickerView.swift │ │ ├── ProgressView.swift │ │ ├── Slider.swift │ │ ├── Stepper.swift │ │ ├── Switch.swift │ │ ├── Table Views │ │ │ ├── ContextualAction.swift │ │ │ ├── SwipeActionsConfiguration.swift │ │ │ ├── TableView.swift │ │ │ ├── TableViewCell.swift │ │ │ ├── TableViewDataSource.swift │ │ │ ├── TableViewDelegate.swift │ │ │ ├── TableViewFocusUpdateContext.swift │ │ │ └── TableViewHeaderFooterView.swift │ │ ├── TextAlignment.swift │ │ ├── TextField.swift │ │ ├── TextView.swift │ │ ├── View.swift │ │ └── VisualEffect.swift │ └── Windows and Screens │ │ ├── AlertAction.swift │ │ ├── AlertController.swift │ │ ├── CoordinateSpace.swift │ │ ├── Screen.swift │ │ └── Window.swift └── SwiftWin32UI │ ├── App Structure and Behaviour │ ├── App.swift │ ├── Scene.swift │ ├── SceneBuilder.swift │ └── WindowGroup.swift │ ├── CMakeLists.txt │ ├── EmptyView.swift │ ├── Framework Integration │ └── UIApplicationDelegateAdaptor.swift │ ├── Never+SwiftUI.swift │ ├── View Layout and Presentation │ ├── AnyView.swift │ ├── EquatableView.swift │ └── Group.swift │ └── Views and Controls │ ├── Label.swift │ ├── View.swift │ └── ViewBuilder.swift ├── Tests ├── AutoLayoutTests │ └── AutoLayoutTests.swift ├── CoreGraphicsTests │ └── CoreGraphicsTests.swift ├── SupportTests │ └── DateTests.swift ├── UICoreTests │ ├── BarButtonItemTests.swift │ ├── BarItemTests.swift │ ├── ButtonTests.swift │ ├── ColorTests.swift │ ├── CubicTimingParametersTests.swift │ ├── DatePickerTests.swift │ ├── EventTests.swift │ ├── LabelTests.swift │ ├── MenuBuilderTests.swift │ ├── OffsetTests.swift │ ├── PresentationControllerTests.swift │ ├── PressTests.swift │ ├── PressesEventTests.swift │ ├── ResponderTests.swift │ ├── SpringTimingParametersTests.swift │ ├── StepperTests.swift │ ├── TextViewTests.swift │ ├── ViewTests.swift │ └── WindowTests.swift ├── Utilities │ └── Utilities.swift └── main.swift └── cmake └── Modules └── SwiftSupport.cmake /.gitattributes: -------------------------------------------------------------------------------- 1 | *.swift text eol=lf 2 | *.md text eol=lf 3 | .gitmodules text eol=lf 4 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | layout: "diff,files" 3 | behavior: new 4 | coverage: 5 | status: 6 | project: true 7 | patch: true 8 | changes: true 9 | ignore: 10 | - "Examples/**/*" 11 | - "Tests/**/*" 12 | - "Packages/**/*" 13 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | paths: 8 | - '**/*.swift' 9 | - '.github/workflows/build.yml' 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build: 14 | runs-on: windows-latest 15 | 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | include: 20 | - branch: swift-5.4.3-release 21 | tag: 5.4.3-RELEASE 22 | options: '-Xmanifest -use-ld=link -Xswiftc -use-ld=link' 23 | 24 | - branch: swift-5.5.3-release 25 | tag: 5.5.3-RELEASE 26 | options: '-Xmanifest -use-ld=link -Xswiftc -use-ld=link' 27 | 28 | - branch: swift-5.6.3-release 29 | tag: 5.6.3-RELEASE 30 | options: '' 31 | 32 | - branch: swift-5.7.3-release 33 | tag: 5.7.3-RELEASE 34 | options: '' 35 | 36 | - branch: swift-5.8.1-release 37 | tag: 5.8.1-RELEASE 38 | options: '' 39 | 40 | - branch: swift-5.9.1-release 41 | tag: 5.9.1-RELEASE 42 | options: '' 43 | 44 | - branch: development 45 | tag: DEVELOPMENT-SNAPSHOT-2023-08-12-a 46 | options: '' 47 | 48 | name: Swift ${{ matrix.tag }} 49 | 50 | steps: 51 | - uses: compnerd/gha-setup-swift@main 52 | with: 53 | tag: ${{ matrix.tag }} 54 | branch: ${{ matrix.branch }} 55 | 56 | - uses: actions/checkout@v3 57 | 58 | - name: Build 59 | run: swift build -v ${{ matrix.options }} 60 | 61 | - name: Run tests 62 | run: swift test -v -Xswiftc -DENABLE_TESTING ${{ matrix.options }} 63 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - '**/*.swift' 9 | - '.github/workflows/coverage.yml' 10 | - '!Examples/**/*.swift' 11 | pull_request: 12 | branches: 13 | - main 14 | paths: 15 | - '**/*.swift' 16 | - '.github/workflows/coverage.yml' 17 | - '!Examples/**/*.swift' 18 | workflow_dispatch: 19 | 20 | jobs: 21 | coverage: 22 | runs-on: windows-latest 23 | 24 | strategy: 25 | matrix: 26 | include: 27 | - branch: swift-5.9-release 28 | tag: 5.9-RELEASE 29 | 30 | steps: 31 | - uses: actions/checkout@v2 32 | - uses: seanmiddleditch/gha-setup-vsdevenv@master 33 | - uses: compnerd/gha-setup-swift@main 34 | with: 35 | tag: ${{ matrix.tag }} 36 | branch: ${{ matrix.branch }} 37 | 38 | - name: Build 39 | run: swift build -v 40 | 41 | - name: Run tests 42 | run: swift test -v -Xswiftc -DENABLE_TESTING --enable-code-coverage 43 | 44 | - name: Process Coverage 45 | run: | 46 | llvm-cov export -format lcov -ignore-filename-regex ".build|Tests|Examples" -instr-profile .build\x86_64-unknown-windows-msvc\debug\codecov\default.profdata .build\x86_64-unknown-windows-msvc\debug\SwiftWin32PackageTests.xctest > coverage.lcov 47 | 48 | - uses: codecov/codecov-action@v3 49 | with: 50 | token: ${{ secrets.CODECOV_TOKEN }} 51 | files: coverage.lcov 52 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | paths: 8 | - '**/*.swift' 9 | 10 | jobs: 11 | lint: 12 | runs-on: windows-latest 13 | 14 | steps: 15 | - uses: compnerd/gha-setup-swift@main 16 | with: 17 | branch: swift-5.8-release 18 | tag: 5.8-RELEASE 19 | - name: Install swift-format 20 | run: | 21 | Install-Binary -Url "https://github.com/compnerd/swift-build/releases/download/swift-format-5.8-RELEASE/swift-format.msi" -Name "swift-format.msi" -ArgumentList ("-q") 22 | 23 | - uses: actions/checkout@v2 24 | 25 | - uses: compnerd/swift-format-linter-action@main 26 | with: 27 | github-token: ${{ secrets.GITHUB_TOKEN }} 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # git ls-files --others --exclude-from=.git/info/exclude 2 | # Lines that start with '#' are comments. 3 | # For a project mostly in C, the following would be a good set of 4 | # exclude patterns (uncomment them if you want to use them): 5 | 6 | .*.sw[nop] 7 | *~ 8 | 9 | /build/ 10 | 11 | /package.resolved 12 | /Packages/ 13 | .build/ 14 | 15 | .vscode/ 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Packages/cassowary"] 2 | path = Packages/cassowary 3 | url = https://github.com/compnerd/cassowary 4 | [submodule "Packages/SwiftCOM"] 5 | path = Packages/SwiftCOM 6 | url = https://github.com/compnerd/swift-com 7 | [submodule "Packages/swift-log"] 8 | path = Packages/swift-log 9 | url = https://github.com/apple/swift-log 10 | [submodule "Packages/swift-collections"] 11 | path = Packages/swift-collections 12 | url = https://github.com/apple/swift-collections 13 | -------------------------------------------------------------------------------- /.swift-format: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "rules": { 4 | "AllPublicDeclarationsHaveDocumentation": true, 5 | "AlwaysUseLowerCamelCase": false, 6 | "UseShorthandTypeNames": false, 7 | "ValidateDocumentationComments": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "exodiusstudios.comment-anchors" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.configureOnOpen": false, 3 | "commentAnchors.tags.list": [ 4 | { 5 | "tag": "MARK", 6 | "iconColor": "default", 7 | "highlightColor": "#A8C023", 8 | "scope": "file" 9 | }, 10 | { 11 | "tag": "TODO", 12 | "iconColor": "blue", 13 | "highlightColor": "#3ea8ff", 14 | "scope": "workspace" 15 | }, 16 | { 17 | "tag": "FIXME", 18 | "iconColor": "red", 19 | "highlightColor": "#F44336", 20 | "scope": "workspace" 21 | }, 22 | { 23 | "tag": "NOTE", 24 | "iconColor": "orange", 25 | "highlightColor": "#FFB300", 26 | "scope": "file" 27 | }, 28 | ], 29 | "files.exclude": { 30 | ".git": true, 31 | ".build": true, 32 | ".*.sw?": true, 33 | "**/.DS_Store": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright © 2019 Saleem Abdulrasool 3 | All rights reserved. 4 | 5 | SPDX-License-Identifier: BSD-3-Clause 6 | #]] 7 | 8 | cmake_minimum_required(VERSION 3.16.0) 9 | 10 | project(SwiftWin32 11 | LANGUAGES C Swift) 12 | 13 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules) 14 | 15 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 16 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) 17 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 18 | set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift) 19 | 20 | find_package(dispatch CONFIG QUIET) 21 | find_package(Foundation CONFIG QUIET) 22 | 23 | find_package(Git REQUIRED) 24 | execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive 25 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 26 | RESULT_VARIABLE GIT_SUBMODULE_UPDATE_RESULT) 27 | if(NOT GIT_SUBMODULE_UPDATE_RESULT EQUAL "0") 28 | message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMODULE_UPDATE_RESULT}, please checkout submodules") 29 | endif() 30 | 31 | execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD 32 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Packages/Cassowary" 33 | OUTPUT_VARIABLE CASSOWARY_GIT_REVISION 34 | ERROR_QUIET 35 | OUTPUT_STRIP_TRAILING_WHITESPACE) 36 | execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD 37 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Packages/SwiftCOM" 38 | OUTPUT_VARIABLE SWIFT_COM_GIT_REVISION 39 | ERROR_QUIET 40 | OUTPUT_STRIP_TRAILING_WHITESPACE) 41 | execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD 42 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Packages/swift-log" 43 | OUTPUT_VARIABLE SWIFT_LOG_GIT_REVISION 44 | ERROR_QUIET 45 | OUTPUT_STRIP_TRAILING_WHITESPACE) 46 | execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD 47 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/Packages/swift-collections" 48 | OUTPUT_VARIABLE COLLECTIONS_GIT_REVISION 49 | ERROR_QUIET 50 | OUTPUT_STRIP_TRAILING_WHITESPACE) 51 | 52 | include(SwiftSupport) 53 | 54 | add_subdirectory(Packages/swift-collections) 55 | 56 | add_subdirectory(Sources) 57 | add_subdirectory(Examples) 58 | 59 | message("-- Building with sub-modules:") 60 | message("-- Cassowary rG${CASSOWARY_GIT_REVISION}") 61 | message("-- Swift/COM rG${SWIFT_COM_GIT_REVISION}") 62 | message("-- swift-log rG${SWIFT_LOG_GIT_REVISION}") 63 | message("-- Collections rG${COLLECTIONS_GIT_REVISION}") 64 | 65 | if(Swift_COMPILER_VERSION VERSION_LESS 5.5) 66 | export(TARGETS Logging SwiftCOM SwiftWin32 67 | FILE SwiftWin32Config.cmake) 68 | else() 69 | export(TARGETS SwiftCOM SwiftWin32 70 | FILE SwiftWin32Config.cmake) 71 | endif() 72 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 21, 6 | "patch": 0 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "Default", 11 | "displayName": "Release Build (Ninja)", 12 | "description": "Defaults", 13 | "generator": "Ninja", 14 | "binaryDir": "${sourceDir}/.build/x86_64-unknown-windows-msvc/Release", 15 | "cacheVariables": { 16 | "BUILD_SHARED_LIBS": "YES", 17 | "CMAKE_BUILD_TYPE": "Release", 18 | "CMAKE_Swift_FLAGS": "-sdk $env{SDKROOT}" 19 | } 20 | } 21 | ], 22 | "buildPresets": [ 23 | { 24 | "name": "Default", 25 | "configurePreset": "Default" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /Documentation/BundleLayout.md: -------------------------------------------------------------------------------- 1 | ## Bundle Layout 2 | 3 | ### What Files Go Into an Application Bundle? 4 | 5 | The following table summarises the types of files that need to be included in an application distribution. 6 | 7 | | File | Description | 8 | | ---- | ----------- | 9 | | Info.plist | **(Optional)** The *information property list* file is a structured file that contains configuration information for the application. | 10 | | Executable | The application's main entry point and any statically linked code. | 11 | | Libraries | Any additional dependent libraries needed by the main executable. | 12 | | Application Manifest | The Windows application manifest which is used to enable features for modern Windows APIs. | 13 | | Swift Runtime | **(Optional)** The runtime libraries for the Swift runtime. | 14 | 15 | ### Anatomy of a Windows Application Bundle 16 | 17 | #### The Windows Application Bundle Structure 18 | 19 | The Windows application bundle contains the application executable and any resources required for the application. The following listing shows the structure of a simple application called `Application`. 20 | 21 | ``` 22 | Application.app 23 | Application.exe 24 | Application.exe.manifest 25 | Resources 26 | Image.png 27 | ``` 28 | 29 | | File | Description | 30 | | ---- | ----------- | 31 | | Application.exe | (Required) The executable file containing the application code. | 32 | | Application.exe.manifest | (Required) The executable manifest. This must be named the same as the executable with an additional `.manifest` suffix. | 33 | | Info.plist | (Recommended) The file contains confituration information for the application. | 34 | | Custom resource files | Any additional resources, including but not limited to images, sound files, and custom data files needed for the application. | 35 | 36 | ### The Information Property List File 37 | 38 | Applications should provide an information property list (`Info.plist`) file 39 | containing the application's configuration information. If one is not provided, 40 | the framework wil attempt to subsitute defaults. The following table lists some 41 | of the keys which are commonly used. Although the file nor the keys are 42 | required, they provide a way to adjust the configuration of the application at 43 | launch time. Providing the configuration helps ensure te proper presentation of 44 | the application to the user. 45 | 46 | | Key | Description | 47 | | --- | ----------- | 48 | | `PrincipalClass` (Principal class) | The entry point for for the application. This is either the default `Application` or a subclass. | 49 | -------------------------------------------------------------------------------- /Documentation/Images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/compnerd/swift-win32/3515be4261785796172b6943f834f5d50d89be9a/Documentation/Images/screenshot.png -------------------------------------------------------------------------------- /Documentation/PrincipalClass.md: -------------------------------------------------------------------------------- 1 | ## Principal Class 2 | 3 | Defining a PrincipalClass allows to use a subclass of the `Application` class. 4 | 5 | ### How to use an Application subclass ? 6 | 7 | - Define a class that inherits from `SwiftWin32.Application`. Here is an example: 8 | 9 | ```swift 10 | import SwiftWin32 11 | 12 | public class MyApplication: Application { 13 | let message = "This is a message from MyApplication subclass" 14 | } 15 | ``` 16 | 17 | - In `Info.plist`, define a `PrincipalClass` entry with a String value of `{Module}.{CustomClassName}`. For example, if the product module name is `CustomPrincipalClass`, then we can register `MyApplication` (defined above) as follows: 18 | 19 | ```xml 20 | 21 | 22 | 23 | 24 | PrincipalClass 25 | CustomPrincipalClass.MyApplication 26 | 27 | 28 | 29 | ``` 30 | -------------------------------------------------------------------------------- /Examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(Calculator) 2 | add_subdirectory(UICatalog) 3 | -------------------------------------------------------------------------------- /Examples/Calculator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(Calculator 2 | Calculator.swift) 3 | add_custom_command(TARGET Calculator POST_BUILD 4 | COMMAND 5 | mt -nologo -manifest ${CMAKE_CURRENT_SOURCE_DIR}/Calculator.exe.manifest -outputresource:$ 6 | COMMAND 7 | ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist $) 8 | # FIXME(SR-12683) `@main` requires `-parse-as-library` 9 | target_compile_options(Calculator PRIVATE 10 | -parse-as-library) 11 | target_link_libraries(Calculator PRIVATE 12 | SwiftWin32) 13 | -------------------------------------------------------------------------------- /Examples/Calculator/Calculator.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | PerMonitorV2 18 | true 19 | 20 | 21 | 22 | Calculator 23 | 24 | 25 | 26 | 27 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Examples/Calculator/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ApplicationSceneManifest 6 | 7 | ApplicationSupportsMultipleScenes 8 | 9 | SceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | SceneConfigurationName 15 | Default Configuration 16 | SceneDelegateClassName 17 | Calculator.CalculatorDelegate 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Examples/UICatalog/Assets/CoffeeCup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/compnerd/swift-win32/3515be4261785796172b6943f834f5d50d89be9a/Examples/UICatalog/Assets/CoffeeCup.jpg -------------------------------------------------------------------------------- /Examples/UICatalog/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(UICatalog 2 | UICatalog.swift) 3 | add_custom_command(TARGET UICatalog POST_BUILD 4 | COMMAND 5 | mt -nologo -manifest ${CMAKE_CURRENT_SOURCE_DIR}/UICatalog.exe.manifest -outputresource:$ 6 | COMMAND 7 | ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist $ 8 | COMMAND 9 | ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/Assets/CoffeeCup.jpg $) 10 | # FIXME(SR-12683) `@main` requires `-parse-as-library` 11 | target_compile_options(UICatalog PRIVATE 12 | -parse-as-library) 13 | target_link_libraries(UICatalog PRIVATE 14 | SwiftWin32) 15 | -------------------------------------------------------------------------------- /Examples/UICatalog/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ApplicationSceneManifest 6 | 7 | ApplicationSupportsMultipleScenes 8 | 9 | SceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | SceneConfigurationName 15 | Default Configuration 16 | SceneDelegateClassName 17 | UICatalog.UICatalog 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Examples/UICatalog/UICatalog.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | PerMonitorV2 18 | true 19 | 20 | 21 | 22 | UICatalog 23 | 24 | 25 | 26 | 27 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, Saleem Abdulrasool 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Package@swift-5.4.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.4 2 | 3 | import PackageDescription 4 | 5 | let SwiftWin32 = Package( 6 | name: "SwiftWin32", 7 | products: [ 8 | .library(name: "SwiftWin32", type: .dynamic, targets: ["SwiftWin32"]), 9 | .library(name: "SwiftWin32UI", type: .dynamic, targets: ["SwiftWin32UI"]), 10 | .executable(name: "UICatalog", targets: ["UICatalog"]), 11 | .executable(name: "Calculator", targets: ["Calculator"]), 12 | ], 13 | dependencies: [ 14 | .package(url: "https://github.com/apple/swift-log.git", 15 | .upToNextMajor(from: "1.4.3")), 16 | .package(url: "https://github.com/apple/swift-collections.git", 17 | .upToNextMinor(from: "1.0.0")), 18 | .package(url: "https://github.com/compnerd/cassowary.git", .branch("main")), 19 | .package(name: "SwiftCOM", url: "https://github.com/compnerd/swift-com.git", 20 | .revision("ebbc617d3b7ba3a2023988a74bebd118deea4cc5")), 21 | ], 22 | targets: [ 23 | .target( 24 | name: "SwiftWin32", 25 | dependencies: [ 26 | .product(name: "Logging", package: "swift-log"), 27 | .product(name: "OrderedCollections", package: "swift-collections"), 28 | .product(name: "cassowary", package: "cassowary"), 29 | .product(name: "SwiftCOM", package: "SwiftCOM"), 30 | ], 31 | path: "Sources/SwiftWin32", 32 | exclude: ["CMakeLists.txt"], 33 | linkerSettings: [ 34 | .linkedLibrary("User32"), 35 | .linkedLibrary("ComCtl32"), 36 | ] 37 | ), 38 | .target( 39 | name: "SwiftWin32UI", 40 | dependencies: ["SwiftWin32"], 41 | path: "Sources/SwiftWin32UI", 42 | exclude: ["CMakeLists.txt"] 43 | ), 44 | .executableTarget( 45 | name: "Calculator", 46 | dependencies: ["SwiftWin32"], 47 | path: "Examples/Calculator", 48 | exclude: [ 49 | "CMakeLists.txt", 50 | "Calculator.exe.manifest", 51 | "Info.plist", 52 | ], 53 | swiftSettings: [.unsafeFlags(["-parse-as-library"])] 54 | ), 55 | .executableTarget( 56 | name: "UICatalog", 57 | dependencies: ["SwiftWin32"], 58 | path: "Examples/UICatalog", 59 | exclude: [ 60 | "CMakeLists.txt", 61 | "Info.plist", 62 | "UICatalog.exe.manifest", 63 | ], 64 | resources: [.copy("Assets/CoffeeCup.jpg")], 65 | swiftSettings: [.unsafeFlags(["-parse-as-library"])] 66 | ), 67 | .target(name: "TestUtilities", path: "Tests/Utilities"), 68 | .testTarget(name: "AutoLayoutTests", dependencies: ["SwiftWin32"]), 69 | .testTarget(name: "CoreGraphicsTests", dependencies: ["SwiftWin32"]), 70 | .testTarget(name: "SupportTests", dependencies: ["SwiftWin32"]), 71 | .testTarget( 72 | name: "UICoreTests", 73 | dependencies: ["SwiftWin32", "TestUtilities"] 74 | ) 75 | ] 76 | ) 77 | -------------------------------------------------------------------------------- /Package@swift-5.5.swift: -------------------------------------------------------------------------------- 1 | Package@swift-5.4.swift -------------------------------------------------------------------------------- /Package@swift-5.6.swift: -------------------------------------------------------------------------------- 1 | Package@swift-5.4.swift -------------------------------------------------------------------------------- /Package@swift-5.8.swift: -------------------------------------------------------------------------------- 1 | Package@swift-5.7.swift -------------------------------------------------------------------------------- /Sources/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright © 2019 Saleem Abdulrasool 3 | All rights reserved. 4 | 5 | SPDX-License-Identifier: BSD-3-Clause 6 | #]] 7 | 8 | # NOTE(compnerd) because these modules are meant to be static and pristine, 9 | # there can be no changes to the sources here. As such, these modules are safe 10 | # to glob because they cannot impact the build. 11 | 12 | file(GLOB CASSOWARY_SOURCES 13 | ${PROJECT_SOURCE_DIR}/Packages/cassowary/Sources/Cassowary/*.swift) 14 | add_library(Cassowary SHARED 15 | ${CASSOWARY_SOURCES}) 16 | set_target_properties(Cassowary PROPERTIES 17 | INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) 18 | _install_target(Cassowary) 19 | 20 | file(GLOB_RECURSE COM_SOURCES 21 | ${PROJECT_SOURCE_DIR}/Packages/SwiftCOM/Sources/SwiftCOM/*.swift 22 | ${PROJECT_SOURCE_DIR}/Packages/SwiftCOM/Sources/SwiftCOM/**/*.swift) 23 | add_library(SwiftCOM SHARED 24 | ${COM_SOURCES}) 25 | target_link_libraries(SwiftCOM PUBLIC 26 | Ole32 27 | PortableDeviceGUIDs) 28 | set_target_properties(SwiftCOM PROPERTIES 29 | INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY}) 30 | _install_target(SwiftCOM) 31 | 32 | file(GLOB LOGGING_SOURCES 33 | ${PROJECT_SOURCE_DIR}/Packages/swift-log/Sources/Logging/*.swift) 34 | # FIXME(compnerd) 5.5 does not officially support static libraries on Windows 35 | # either. The support requires a version strictly greater than 5.5. Once the 36 | # branch is introduced, adjust this accordingly. 37 | if(Swift_COMPILER_VERSION VERSION_LESS 5.5) 38 | add_library(Logging SHARED 39 | ${LOGGING_SOURCES}) 40 | _install_target(Logging) 41 | else() 42 | add_library(Logging STATIC 43 | ${LOGGING_SOURCES}) 44 | endif() 45 | 46 | add_subdirectory(SwiftWin32) 47 | add_subdirectory(SwiftWin32UI) 48 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Animation and Haptics/Property-Based Animations/CubicTimingParameters.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | /// The timing information for animations in the form of a cubic Bézier curve. 9 | public class CubicTimingParameters { 10 | // MARK - Initializing a Cubic Timing Parameters Object 11 | 12 | /// Initializes the object with the system’s default timing curve. 13 | public init() { 14 | self.animationCurve = .linear 15 | self.controlPoint1 = .zero 16 | self.controlPoint2 = Point(x: 1, y: 1) 17 | } 18 | 19 | /// Initializes the object with the specified builtin timing curve. 20 | public init(animationCurve curve: View.AnimationCurve) { 21 | self.animationCurve = curve 22 | self.controlPoint1 = .zero 23 | self.controlPoint2 = .zero 24 | } 25 | 26 | /// Initializes the object with the specified control points for a cubic 27 | /// Bézier curve. 28 | public init(controlPoint1 point1: Point, controlPoint2 point2: Point) { 29 | self.animationCurve = .linear 30 | self.controlPoint1 = point1 31 | self.controlPoint2 = point2 32 | } 33 | 34 | // MARK - Getting the Timing Parameters 35 | 36 | /// The standard builtin animation curve to use for timing. 37 | public private(set) var animationCurve: View.AnimationCurve 38 | 39 | /// The first control point for the cubic Bézier curve. 40 | public private(set) var controlPoint1: Point 41 | 42 | /// The second control point of the cubic Bézier curve. 43 | public private(set) var controlPoint2: Point 44 | } 45 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Animation and Haptics/Property-Based Animations/SpringTimingParameters.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | /// The timing information for animations that mimics the behavior of a spring. 9 | public class SpringTimingParameters { 10 | // MARK - Initializing a Spring Timing Parameters Object 11 | 12 | /// Creates a default timing parameters object. 13 | /// 14 | /// This method sets the initial velocity of any animated properties to 0.0 15 | /// and sets the damping ratio to 4.56. 16 | public init() { 17 | self.initialVelocity = .zero 18 | } 19 | 20 | /// Creates a timing parameters object with the specified damping ratio. 21 | /// 22 | /// This method sets the initial velocity of any animated properties to 0.0. 23 | public convenience init(dampingRatio ratio: Double) { 24 | self.init(dampingRatio: ratio, initialVelocity: .zero) 25 | } 26 | 27 | /// Creates a timing parameters object with the specified damping ratio and 28 | /// initial velocity. 29 | public init(dampingRatio ratio: Double, initialVelocity velocity: Vector) { 30 | self.initialVelocity = velocity 31 | } 32 | 33 | /// Creates a timing parameters object with the specified spring stiffness, 34 | /// mass, damping coefficient, and initial velocity. 35 | /// 36 | /// The damping ratio for the spring is computed from the formula: 37 | /// `damping / (2 * sqrt (stiffness * mass))`. 38 | public init(mass: Double, stiffness: Double, damping: Double, 39 | initialVelocity velocity: Vector) { 40 | self.initialVelocity = velocity 41 | } 42 | 43 | // MARK - Getting the Initial Velocity 44 | 45 | /// The target property’s rate of change at the start of a spring animation, 46 | /// enabling a smooth transition into the animation. 47 | public private(set) var initialVelocity: Vector 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Animation and Haptics/Property-Based Animations/TimingCurveProvider.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// Constants indicating the type of timing information to use. 5 | public enum TimingCurveType: Int { 6 | /// Use the built-in timing curves. Specify this value when you want to use 7 | /// one of the constants in the `View.AnimationCurve` type. Specify the 8 | /// desired curve using the `cubicTimingParameters` property. 9 | case builtin 10 | 11 | /// Use a custom cubic Bézier curve. Specify the curve information using the 12 | /// `cubicTimingParameters` property. 13 | case cubic 14 | 15 | /// Use a custom spring animation. Specify the desired curve using the 16 | /// `springTimingParameters` property. 17 | case spring 18 | 19 | /// Use a combination of timing parameters. This type of curve starts with the 20 | /// curve defined by the `cubicTimingParameters` property and modifies it 21 | /// using the spring information in the `springTimingParameters` property. 22 | case composed 23 | } 24 | 25 | /// An interface for providing the timing information needed to perform 26 | /// animations. 27 | public protocol TimingCurveProvider { 28 | // MARK - Getting the Timing Information 29 | 30 | /// The type of timing information to use. 31 | var timingCurveType: TimingCurveType { get } 32 | 33 | /// The cubic timing parameters to use. 34 | var cubicTimingParameters: CubicTimingParameters? { get } 35 | 36 | /// The spring-based timing parameters to use. 37 | var springTimingParameters: SpringTimingParameters? { get } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Animation and Haptics/Property-Based Animations/ViewAnimating.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import struct Foundation.TimeInterval 5 | 6 | /// Constants indicating positions within the animation. 7 | public enum ViewAnimatingPosition: Int { 8 | /// The end point of the animation. Use this constant when you want the final 9 | /// values for any animatable properties — that is, you want to refer to the 10 | /// values you specified in your animation blocks. 11 | case end 12 | 13 | /// The beginning of the animation. Use this constant when you want the 14 | /// starting values for any animatable properties—that is, the values of the 15 | /// properties before you applied any animations. 16 | case start 17 | 18 | /// The current position. Use this constant when you want the most recent 19 | /// value set by an animator object. 20 | case current 21 | } 22 | 23 | /// Constants indicating the current state of the animation. 24 | public enum ViewAnimatingState: Int { 25 | /// The animations have not yet started executing. This is the initial state 26 | /// of the animator object. 27 | case inactive 28 | 29 | /// The animator object is active and animations are either running or paused. 30 | /// An animator moves to this state after the first call to `startAnimation()` 31 | /// or `pauseAnimation()`. It stays in the active state until the animations 32 | /// finish naturally or until you call the `stopAnimation(_:)` method. 33 | case active 34 | 35 | /// The animation is stopped. Putting an animation into this state ends the 36 | /// animation and leaves any animatable properties at their current values, 37 | /// instead of updating them to their intended final values. An animation 38 | /// cannot be started while in this state. 39 | case stopped 40 | } 41 | 42 | /// An interface for implementing custom animator objects. 43 | public protocol ViewAnimating { 44 | // MARK - Starting and Stopping the Animations 45 | 46 | /// Starts the animation from its current position. 47 | func startAnimation() 48 | 49 | /// Starts the animation after the specified delay. 50 | func startAnimation(afterDelay delay: TimeInterval) 51 | 52 | /// Pauses a running animation at its current position. 53 | func pauseAnimation() 54 | 55 | /// Stops the animations at their current positions. 56 | func stopAnimation(_ withoutFinishing: Bool) 57 | 58 | /// Finishes the animations and returns the animator to the inactive state. 59 | func finishAnimation(at finalPositiong: ViewAnimatingPosition) 60 | 61 | // MARK - Getting the Animator's State 62 | 63 | /// The completion percentage of the animation. 64 | var fractionComplete: Double { get set } 65 | 66 | /// A boolean value indicating whether the animation is running in the reverse 67 | /// direction. 68 | var isReversed: Bool { get set } 69 | 70 | /// The current state of the animation. 71 | var state: ViewAnimatingState { get } 72 | 73 | /// A boolean value indicating whether the animation is currently running. 74 | var isRunning: Bool { get } 75 | } 76 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Animation and Haptics/Property-Based Animations/ViewImplicitlyAnimating.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// An interface for modifying an animation while it is running. 5 | public protocol ViewImplicitlyAnimating: ViewAnimating { 6 | // MARK - Modifying Animations 7 | 8 | /// Adds the specified animation block to the animator. 9 | func addAnimations(_ animation: @escaping () -> Void) 10 | 11 | /// Adds the specified animation block to the animator with a delay. 12 | func addAnimations(_ animation: @escaping () -> Void, delayFactor: Double) 13 | 14 | /// Adds the specified completion block to the animator. 15 | func addCompletion(_ completion: @escaping (ViewAnimatingPosition) -> Void) 16 | 17 | /// Adjusts the final timing and duration of a paused animation. 18 | func continueAnimation(withTimingParameters paramters: TimingCurveProvider?, 19 | durationFactor: Double) 20 | } 21 | 22 | extension ViewImplicitlyAnimating { 23 | public func addAnimations(_ animation: @escaping () -> Void) { 24 | self.addAnimations(animation, delayFactor: 0.0) 25 | } 26 | 27 | public func addAnimations(_ animation: @escaping () -> Void, 28 | delayFactor: Double) { 29 | } 30 | 31 | public func addCompletion(_ completion: @escaping (ViewAnimatingPosition) -> Void) { 32 | } 33 | 34 | public func continueAnimation(withTimingParameters paramters: TimingCurveProvider?, 35 | durationFactor: Double) { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Animation and Haptics/View Controller Transitions/ViewControllerAnimatedTransitioning.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import struct Foundation.TimeInterval 5 | 6 | /// A set of methods for implementing the animations for a custom view controller 7 | /// transition. 8 | public protocol ViewControllerAnimatedTransitioning { 9 | // MARK - Performing a Transition 10 | 11 | /// Tells your animator object to perform the transition animations. 12 | func animateTransition(using transitionContext: ViewControllerContextTransitioning) 13 | 14 | /// Tells your animator object that the transition animations have finished. 15 | func animationEnded(_ transitionCompleted: Bool) 16 | 17 | // MARK - Reporting Transition Duration 18 | 19 | /// Asks your animator object for the duration (in seconds) of the transition 20 | /// animation. 21 | func transitionDuration(using transitionContext: ViewControllerContextTransitioning?) 22 | -> TimeInterval 23 | 24 | // MARK - Returning an Interruptible Animator 25 | 26 | /// Returns the interruptible animator to use during the transition. 27 | func interruptibleAnimator(using transitionContext: ViewControllerContextTransitioning) 28 | -> ViewImplicitlyAnimating 29 | } 30 | 31 | extension ViewControllerAnimatedTransitioning { 32 | public func animationEnded(_ transitionCompleted: Bool) { 33 | } 34 | } 35 | 36 | extension ViewControllerAnimatedTransitioning { 37 | func interruptibleAnimator(using transitionContext: ViewControllerContextTransitioning) 38 | -> ViewImplicitlyAnimating { 39 | fatalError("\(#function) not yet implemented") 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Animation and Haptics/View Controller Transitions/ViewControllerInteractiveTransitioning.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A set of methods that enable an object (such as a navigation controller) to 5 | /// drive a view controller transition. 6 | public protocol ViewControllerInteractiveTransitioning { 7 | // MARK - Starting an Interactive Transition 8 | 9 | /// Called when the system needs to set up the interactive portions of a view 10 | /// controller transition and start the animations. 11 | func startInteractiveTransition(_ transitionContext: ViewControllerContextTransitioning) 12 | 13 | /// A boolean value indicating whether the transition is interactive when it 14 | /// starts. 15 | /// 16 | /// The value of this property is `true` when the transition is interactive 17 | /// from the moment it starts. The property is `false` when the transition 18 | /// starts off as noninteractive. However, even a transition that starts off 19 | /// as noninteractive may become interactive later if it implements the 20 | /// `interruptibleAnimator(using:)` method of the 21 | /// `ViewControllerAnimatedTransitioning` protocol. 22 | var wantsInteractiveStart: Bool { get } 23 | 24 | // MARK - Providing a Transition's Completion Characteristics 25 | 26 | /// Called when the system needs the animation completion curve for an 27 | /// interactive view controller transition. 28 | var completionCurve: View.AnimationCurve { get } 29 | 30 | /// Called when the system needs the speed at which to complete an interactive 31 | /// transition, after the interactive portion is finished. 32 | var completionSpeed: Double { get } 33 | } 34 | 35 | extension ViewControllerInteractiveTransitioning { 36 | public var wantsInteractiveStart: Bool { true } 37 | } 38 | 39 | extension ViewControllerInteractiveTransitioning { 40 | public var completionCurve: View.AnimationCurve { .easeInOut } 41 | 42 | public var completionSpeed: Double { 1.0 } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Animation and Haptics/View Controller Transitions/ViewControllerTransitionCoordinator.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | public protocol ViewControllerTransitionCoordinator: ViewControllerTransitionCoordinatorContext { 5 | /// Responding to View Controller Transition Progress 6 | func animate(alongsideTransition animation: ((ViewControllerTransitionCoordinatorContext) -> Void)?, 7 | completion: ((ViewControllerTransitionCoordinatorContext) -> Void)?) 8 | -> Bool 9 | func animateAlongsideTransition(in view: View?, 10 | animation: ((ViewControllerTransitionCoordinatorContext) -> Void)?, 11 | completion: ((ViewControllerTransitionCoordinatorContext) -> Void)?) 12 | -> Bool 13 | func notifyWhenInteractionChanges(_ handler: @escaping (ViewControllerTransitionCoordinatorContext) -> Void) 14 | } 15 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/App Extensions/InputViewController.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | public class InputViewController: ViewController { 5 | } 6 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/App and Environment/Scenes/Scene.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | import class Foundation.NSNotification 6 | 7 | extension Scene { 8 | public class ConnectionOptions { 9 | } 10 | } 11 | 12 | public class Scene: Responder { 13 | /// Creating a Scene Object 14 | 15 | /// Creates a scene object using the specified session and connection 16 | /// information. 17 | public required init(session: SceneSession, 18 | connectionOptions: Scene.ConnectionOptions) { 19 | self.session = session 20 | } 21 | 22 | /// Managing the Life Cycle of a Scene 23 | 24 | /// The object you use to recieve life-cycle events associated with the scene. 25 | public var delegate: SceneDelegate? 26 | 27 | /// Getting the Scene's Session 28 | 29 | /// The session associated with the scene. 30 | public let session: SceneSession 31 | } 32 | 33 | extension Scene { 34 | /// A notification indicating that a scene was added to the application. 35 | public class var willConnectNotification: NSNotification.Name { 36 | NSNotification.Name(rawValue: "UISceneWillConnectNotification") 37 | } 38 | 39 | /// A notification indicating that a scene was removed from the application. 40 | public class var didDisconnectNotification: NSNotification.Name { 41 | NSNotification.Name(rawValue: "UISceneDidDisconnectNotification") 42 | } 43 | 44 | /// A notification indicating that a scene is about to begin running in the 45 | /// foreground and become visible to the user. 46 | public class var willEnterForegroundNotification: NSNotification.Name { 47 | NSNotification.Name(rawValue: "UISceneWillEnterForegroundNotification") 48 | } 49 | 50 | /// A notification indicating that the scene is now onscreen and reponding to 51 | /// user events. 52 | public class var didActivateNotification: NSNotification.Name { 53 | NSNotification.Name(rawValue: "UISceneDidActivateNotification") 54 | } 55 | 56 | /// A notification indicating that the scene is about to resign the active 57 | /// state and stop responding to user events. 58 | public class var willDeactivateNotification: NSNotification.Name { 59 | NSNotification.Name(rawValue: "UISceneWillDeactivateNotification") 60 | } 61 | 62 | /// A notification indicating that the scene is running in the background and 63 | /// is no longer onscreen. 64 | public class var didEnterBackgroundNotification: NSNotification.Name { 65 | NSNotification.Name(rawValue: "UISceneDidEnterBackgroundNotification") 66 | } 67 | } 68 | 69 | extension Scene: Hashable { 70 | public static func == (lhs: Scene, rhs: Scene) -> Bool { 71 | // TODO(compnerd) figure out the proper equality check for Scene 72 | return lhs === rhs 73 | } 74 | 75 | public func hash(into hasher: inout Hasher) { 76 | // TODO(compnerd) figure out the proper hashing for Scene 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/App and Environment/Scenes/SceneConfiguration.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import func Foundation.NSClassFromString 5 | 6 | public class SceneConfiguration { 7 | /// Creating a Configuration Object 8 | 9 | /// Creates a scene-configuration object with the specified role and 10 | /// application-specific name. 11 | public init(name: String?, sessionRole: SceneSession.Role) { 12 | self.name = name 13 | self.role = sessionRole 14 | 15 | // Try to load the configuration from the Info.plist ... 16 | 17 | // ... which requires that we have an Info.plist 18 | guard let info = Application.shared.information else { 19 | return 20 | } 21 | 22 | // ... which requires that the Info.plist contains scene configuration 23 | guard let configurations = 24 | info.scene?.configurations?[sessionRole.rawValue] else { 25 | return 26 | } 27 | 28 | // ... taking the configuration which matches the name or the first entry 29 | guard let scene = name == nil 30 | ? configurations.first 31 | : configurations.filter({ $0.name == name }).first else { 32 | return 33 | } 34 | // ... overwriting the scene name to the current configuration's scene name 35 | self.name = scene.name 36 | 37 | // ... deserialising the scene class if one was provided 38 | if let sceneClass = scene.class { 39 | self.sceneClass = NSClassFromString(sceneClass) 40 | } 41 | 42 | // .. deserialising the delegate class if one was provided 43 | if let delegateClass = scene.delegate { 44 | self.delegateClass = NSClassFromString(delegateClass) 45 | } 46 | } 47 | 48 | /// Specifying the Scene Creation Details 49 | 50 | /// The class of the scene object you want to create. 51 | public var sceneClass: AnyClass? 52 | 53 | /// The class of the delegate object you want to create. 54 | public var delegateClass: AnyClass? 55 | 56 | /// Getting the Configuration Attributes 57 | 58 | /// The application-specific name assigned to the scene configuration. 59 | public private(set) var name: String? 60 | 61 | /// The role assigned to the scene configuration. 62 | public let role: SceneSession.Role 63 | } 64 | 65 | extension SceneConfiguration: Hashable { 66 | public static func == (lhs: SceneConfiguration, rhs: SceneConfiguration) 67 | -> Bool { 68 | return lhs.name == rhs.name && lhs.role == rhs.role 69 | } 70 | 71 | public func hash(into hasher: inout Hasher) { 72 | hasher.combine(self.name) 73 | hasher.combine(self.role) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/App and Environment/Scenes/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | 6 | public protocol SceneDelegate: _TriviallyConstructible { 7 | // MARK - Connecting and Disconnecting the Scene 8 | 9 | /// Informs the delegate about the addition of a scene to the application. 10 | func scene(_ scene: Scene, willConnectTo: SceneSession, 11 | options: Scene.ConnectionOptions) 12 | 13 | /// Informs the delegate that a scene was removed from the application. 14 | func sceneDidDisconnect(_ scene: Scene) 15 | 16 | // MARK - Transitioning to the Foreground 17 | 18 | /// Informs the delegate that the scene is about to begin running in the 19 | /// foreground and become visible to the user. 20 | func sceneWillEnterForeground(_ scene: Scene) 21 | 22 | /// Informs the delegate that the scene became active and is now responding to 23 | /// user events. 24 | func sceneDidBecomeActive(_ scene: Scene) 25 | 26 | // MARK - Transitioning to the Background 27 | 28 | /// Informs the delegate that the scene is about to resign the active state 29 | /// and stop responding to user events. 30 | func sceneWillResignActive(_ scene: Scene) 31 | 32 | /// Informs the delegate that the scene is running in the background and is no 33 | /// longer onscreen. 34 | func sceneDidEnterBackground(_ scene: Scene) 35 | } 36 | 37 | extension SceneDelegate { 38 | public func scene(_ scene: Scene, willConnectTo: SceneSession, 39 | options: Scene.ConnectionOptions) { 40 | } 41 | 42 | public func sceneDidDisconnect(_ scene: Scene) { 43 | } 44 | } 45 | 46 | extension SceneDelegate { 47 | public func sceneWillEnterForeground(_ scene: Scene) { 48 | } 49 | 50 | public func sceneDidBecomeActive(_ scene: Scene) { 51 | } 52 | } 53 | 54 | extension SceneDelegate { 55 | public func sceneWillResignActive(_ scene: Scene) { 56 | } 57 | 58 | public func sceneDidEnterBackground(_ scene: Scene) { 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/App and Environment/Scenes/SceneSession.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | extension SceneSession { 5 | /// Constants that indicate the possible roles for a scene. 6 | public struct Role: Equatable, Hashable, RawRepresentable { 7 | public typealias RawValue = String 8 | 9 | public let rawValue: RawValue 10 | 11 | public init(rawValue: RawValue) { 12 | self.rawValue = rawValue 13 | } 14 | } 15 | } 16 | 17 | extension SceneSession.Role { 18 | /// The scene displays noninteractive windows on an externally connected 19 | /// screen. 20 | public static var windowApplication: SceneSession.Role { 21 | SceneSession.Role(rawValue: "UIWindowSceneSessionRoleApplication") 22 | } 23 | 24 | /// The scene displays interactive content on the device's main screen. 25 | public static var windowExternalDisplay: SceneSession.Role { 26 | SceneSession.Role(rawValue: "UIWindowSceneSessionRoleExternalDisplay") 27 | } 28 | } 29 | 30 | public class SceneSession { 31 | // MARK - Getting the Scene Information 32 | 33 | /// The scene associated with the current session. 34 | public internal(set) weak var scene: Scene? 35 | 36 | /// The role played by the scene's content. 37 | public let role: SceneSession.Role 38 | 39 | // MARK - Getting the Scene Configuration Details 40 | 41 | /// The configuration data for creating the secene. 42 | // This is mutable as the configuration is only finalized after the deleate 43 | // has formed the final configuration. 44 | public internal(set) var configuration: SceneConfiguration 45 | 46 | // MARK - Identifying the Scene 47 | 48 | /// A unique identifier that persists for the lifetime of the session 49 | public let persistentIdentifier: String 50 | 51 | internal init(identifier: String, role: SceneSession.Role, 52 | configuration name: String? = nil) { 53 | self.persistentIdentifier = identifier 54 | self.role = role 55 | self.configuration = SceneConfiguration(name: name, sessionRole: role) 56 | } 57 | } 58 | 59 | extension SceneSession: Hashable { 60 | public static func == (lhs: SceneSession, rhs: SceneSession) -> Bool { 61 | return lhs.persistentIdentifier == rhs.persistentIdentifier 62 | } 63 | 64 | public func hash(into hasher: inout Hasher) { 65 | hasher.combine(self.persistentIdentifier) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/App and Environment/Scenes/WindowScene.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | public class WindowScene: Scene { 5 | public required init(session: SceneSession, 6 | connectionOptions: Scene.ConnectionOptions) { 7 | // TODO(compnerd) we really should base this on the device properties. 8 | // Windows Phone should have set the sizeRestrictions to nil. Similarly, 9 | // Surface Neo and Surface Duo Devices will not permit the window resizing. 10 | self.sizeRestrictions = SceneSizeRestrictions() 11 | 12 | // FIXME(compnerd) how do you attach a different screen to the window scene? 13 | self.screen = Screen.main 14 | 15 | super.init(session: session, connectionOptions: connectionOptions) 16 | } 17 | 18 | /// Getting the Active Windows 19 | 20 | /// The windows associated with the scene. 21 | public internal(set) var windows: [Window] = [] 22 | 23 | /// The screen that displays the content of the scene. 24 | public private(set) var screen: Screen 25 | 26 | /// Getting the Interface Attributes 27 | 28 | /// The minimum and maximum size of the application's windows. 29 | public private(set) var sizeRestrictions: SceneSizeRestrictions? 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/App and Environment/Scenes/WindowSceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// Additional methods that you can use to manage application specific tasks 5 | /// occurring in a scene. 6 | public protocol WindowSceneDelegate: SceneDelegate { 7 | // MARK - Managing the Scene's Main Window 8 | 9 | /// The main window associated with the scene. 10 | var window: Window? { get set } 11 | 12 | // MARK - Responding to Scene Changes 13 | 14 | /// Notifies you when the size, orientation, or traits of a scene change. 15 | func windowScene(_ windowScene: WindowScene, 16 | didUpdate previousCoordinateSpace: CoordinateSpace, 17 | interfaceOrientation previousInterfaceOrientation: InterfaceOrientation, 18 | traitCollection previousTraitCollection: TraitCollection) 19 | } 20 | 21 | extension WindowSceneDelegate { 22 | public var window: Window? { 23 | get { return nil } 24 | set { } 25 | } 26 | } 27 | 28 | extension WindowSceneDelegate { 29 | public func windowScene(_ windowScene: WindowScene, 30 | didUpdate previousCoordinateSpace: CoordinateSpace, 31 | interfaceOrientation previousInterfaceOrientation: InterfaceOrientation, 32 | traitCollection previousTraitCollection: TraitCollection) { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/App and Environment/TraitEnvironment.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A set of methods that makes the interface environment available to your 5 | /// application. 6 | public protocol TraitEnvironment { 7 | // MARK - Accessing a Trait Collection 8 | 9 | /// The traits, such as the size class and scale factor, that describe the 10 | /// current environment of the object. 11 | var traitCollection: TraitCollection { get } 12 | 13 | // MARK - Responding to a Change in the Interface Environment 14 | 15 | /// Called when the interface environment changes. 16 | func traitCollectionDidChange(_ previousTraitCollection: TraitCollection?) 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Appearance Customization/Appearance.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A collection of methods that gives you access to the appearance proxy for a 5 | /// class. 6 | public protocol Appearance { 7 | // MARK - Appearance Methods 8 | 9 | /// Returns the appearance proxy for the receiver. 10 | static func appearance() -> Self 11 | 12 | /// Returns the appearance proxy for the receiver that has the passed trait 13 | /// collection. 14 | static func appearance(for trait: TraitCollection) -> Self 15 | 16 | /// Returns the appearance proxy for the object when it is contained in the 17 | /// hierarchy the specified classes describe. 18 | static func appearance(whenContainedInInstancesOf containerTypes: [AppearanceContainer.Type]) 19 | -> Self 20 | 21 | /// Returns the appearance proxy for the object when it is contained in the 22 | /// hierarchy the specified classes describe and has the specified trait 23 | /// collection. 24 | static func appearance(for trait: TraitCollection, 25 | whenContainedInInstancesOf containerTypes: [AppearanceContainer.Type]) -> Self 26 | } 27 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Appearance Customization/AppearanceContainer.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A protocol that a class must adopt to allow appearance customization using 5 | /// the `Appearance` API. 6 | public protocol AppearanceContainer { 7 | } 8 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Appearance Customization/Configurations/CellConfigurationState.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A structure that encapsulates a cell's state. 5 | public struct CellConfigurationState: ConfigurationState { 6 | // MARK - Managing View Configuration States 7 | 8 | /// The traits that describe the current layout environment of the view, such 9 | /// as the user interface style and layout direction. 10 | public var traitCollection: TraitCollection 11 | 12 | /// A boolean value that indicates whether the cell is in a selected state. 13 | public var isSelected: Bool = false 14 | 15 | /// A boolean value that indicates whether the cell is in a highlighted state. 16 | public var isHighlighted: Bool = false 17 | 18 | /// A boolean value that indicates whether the cell is in a focused state. 19 | public var isFocused: Bool = false 20 | 21 | /// A boolean value that indicates whether the cell is in a disabled state. 22 | public var isDisabled: Bool = false 23 | 24 | /// Accesses custom states by key. 25 | public subscript(key: ConfigurationStateCustomKey) -> AnyHashable? { 26 | get { return nil } 27 | set { } 28 | } 29 | 30 | // MARK - Creating a Configuration State Manually 31 | 32 | /// Creates a cell configuration state with the specified trait collection. 33 | public init(traitCollection: TraitCollection) { 34 | self.traitCollection = traitCollection 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Appearance Customization/Configurations/ConfigurationColorTransformer.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A transformer that generates a modified output color from an input color. 5 | public struct ConfigurationColorTransformer { 6 | // MARK - Creating a Color Transformer 7 | 8 | /// Creates a color transformer with the specified closure. 9 | public init(_ transform: @escaping (Color) -> Color) { 10 | self.transform = transform 11 | } 12 | 13 | /// Creates a color transformer that generates a grayscale version of the 14 | /// color. 15 | public static var grayscale: ConfigurationColorTransformer { 16 | fatalError("\(#function) not yet implemented") 17 | } 18 | 19 | /// A color transformer that returns the preferred system accent color. 20 | public static var preferredTint: ConfigurationColorTransformer { 21 | fatalError("\(#function) not yet implemented") 22 | } 23 | 24 | /// A color transformer that returns the color with a monochrome tint. 25 | public static var monochromeTint: ConfigurationColorTransformer { 26 | fatalError("\(#function) not yet implemented") 27 | } 28 | 29 | // MARK - Calling the Color Transformer 30 | 31 | /// The transform closure of the color transformer. 32 | public private(set) var transform: (Color) -> Color 33 | 34 | /// Calls the transform closure of the color transformer. 35 | public func callAsFunction(_ input: Color) -> Color { 36 | return self.transform(input) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Appearance Customization/Configurations/ConfigurationState.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// The requirements for an object that encapsulate a view's state. 5 | public protocol ConfigurationState { 6 | // MARK - Managing Configuration States 7 | 8 | /// The traits that describe the current layout environment of the view, such 9 | /// as the user interface style and layout direction. 10 | var traitCollection: TraitCollection { get set } 11 | 12 | /// Accesses custom states by key. 13 | subscript(key: ConfigurationStateCustomKey) -> AnyHashable? { get set } 14 | 15 | // MARK - Creating a Configuration State Manually 16 | 17 | /// Creates a View configuration state with the specified trait collection. 18 | init(traitCollection: TraitCollection) 19 | } 20 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Appearance Customization/Configurations/ConfigurationStateCustomKey.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A key that defines a custom state for a view. 5 | public struct ConfigurationStateCustomKey: Equatable, Hashable, RawRepresentable { 6 | public typealias RawValue = String 7 | 8 | public let rawValue: RawValue 9 | 10 | public init(rawValue: RawValue) { 11 | self.rawValue = rawValue 12 | } 13 | } 14 | 15 | extension ConfigurationStateCustomKey { 16 | public init(_ rawValue: String) { 17 | self.rawValue = rawValue 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Appearance Customization/Configurations/ContentConfiguration.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// The requirements for an object that provides the configuration for a content 5 | /// view. 6 | public protocol ContentConfiguration { 7 | // MARK - Creating a Content Configuration 8 | 9 | /// Creates a new instance of the content view using this configuration. 10 | func makeContentView() -> View & ContentView 11 | 12 | // MARK - Updating a Content Configuration 13 | 14 | /// Generates a configuration for the specified state by applying the 15 | /// configuration's default values for that state to any properties that you 16 | /// haven't customized. 17 | func updated(for state: ConfigurationState) -> Self 18 | } 19 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Appearance Customization/Configurations/ContentView.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// The requirements for a content view that you create using a configuration. 5 | public protocol ContentView { 6 | // MARK - Managing the Content Configuration 7 | 8 | /// The current configuration of the view. 9 | var configuration: ContentConfiguration { get set } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Appearance Customization/Configurations/ViewConfigurationState.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A structure that encapsulates a view's state. 5 | public struct ViewConfigurationState: ConfigurationState { 6 | // MARK - Managing View Configuration States 7 | 8 | /// The traits that describe the current layout environment of the view, such 9 | /// as the user interface style and layout direction. 10 | public var traitCollection: TraitCollection 11 | 12 | /// A boolean value that indicates whether the view is in a selected state. 13 | public var isSelected: Bool 14 | 15 | /// A boolean value that indicates whether the view is in a highlighted state. 16 | public var isHighlighted: Bool 17 | 18 | /// A boolean value that indicates whether the view is in a focused state. 19 | public var isFocused: Bool 20 | 21 | /// A boolean value that indicates whether the view is in a disabled state. 22 | public var isDisabled: Bool 23 | 24 | /// Accesses custom states by key. 25 | public subscript(key: ConfigurationStateCustomKey) -> AnyHashable? { 26 | get { fatalError("\(#function) not yet implemented") } 27 | set { fatalError("\(#function) not yet implemented") } 28 | } 29 | 30 | // MARK - Creating a Configuration State Manually 31 | 32 | public init(traitCollection: TraitCollection) { 33 | self.traitCollection = traitCollection 34 | 35 | self.isSelected = false 36 | self.isHighlighted = false 37 | self.isFocused = false 38 | self.isDisabled = false 39 | } 40 | } 41 | 42 | extension ViewConfigurationState: Hashable { 43 | public static func ==(_ lhs: ViewConfigurationState, 44 | _ rhs: ViewConfigurationState) -> Bool { 45 | fatalError("\(#function) not yet implemented") 46 | } 47 | 48 | public func hash(into hasher: inout Hasher) { 49 | fatalError("\(#function) not yet implemented") 50 | } 51 | } 52 | 53 | extension ViewConfigurationState: CustomStringConvertible { 54 | public var description: String { 55 | fatalError("\(#function) not yet implemented") 56 | } 57 | } 58 | 59 | extension ViewConfigurationState: CustomDebugStringConvertible { 60 | public var debugDescription: String { 61 | fatalError("\(#function) not yet implemented") 62 | } 63 | } 64 | 65 | extension ViewConfigurationState: CustomReflectable { 66 | public var customMirror: Mirror { 67 | fatalError("\(#function) not yet implemented") 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Application/Information.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | extension Application { 5 | internal struct SceneConfiguration { 6 | let name: String? 7 | let `class`: String? 8 | let delegate: String? 9 | } 10 | } 11 | 12 | extension Application.SceneConfiguration: Decodable { 13 | enum CodingKeys: String, CodingKey { 14 | case name = "SceneConfigurationName" 15 | case `class` = "SceneClassName" 16 | case delegate = "SceneDelegateClassName" 17 | } 18 | } 19 | 20 | extension Application { 21 | internal struct SceneManifest { 22 | // Enable Multiple Windows 23 | let supportsMultipleScenes: Bool? 24 | // Scene Configuration 25 | let configurations: [String:[Application.SceneConfiguration]]? 26 | } 27 | } 28 | 29 | extension Application.SceneManifest: Decodable { 30 | enum CodingKeys: String, CodingKey { 31 | case supportsMultipleScenes = "ApplicationSupportsMultipleScenes" 32 | case configurations = "SceneConfigurations" 33 | } 34 | } 35 | 36 | extension Application { 37 | internal struct Information { 38 | let scene: Application.SceneManifest? 39 | let principalClass: String? 40 | } 41 | } 42 | 43 | extension Application.Information: Decodable { 44 | enum CodingKeys: String, CodingKey { 45 | case scene = "ApplicationSceneManifest" 46 | case principalClass = "PrincipalClass" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Application/_TriviallyConstructible.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | // TODO(compnerd) determine if there is a way to avoid this conformance. It is 5 | // required to initialize the class from `ApplicationMain` which takes class 6 | // names. 7 | public protocol _TriviallyConstructible { 8 | init() 9 | } 10 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/AutoLayout/LayoutConstraint+Cassowary.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool . 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import Cassowary 5 | 6 | extension LayoutConstraint.Attribute { 7 | internal var name: String { 8 | switch self { 9 | case .left: return "Left" 10 | case .right: return "Right" 11 | case .top: return "Top" 12 | case .bottom: return "Bottom" 13 | case .leading: return "Leading" 14 | case .trailing: return "Trailing" 15 | case .width: return "Width" 16 | case .height: return "Height" 17 | case .centerX: return "CenterX" 18 | case .centerY: return "CenterY" 19 | case .lastBaseline: return "lastBaseline" 20 | case .firstBaseline: return "FirstBaseline" 21 | case .leftMargin: return "LeftMargin" 22 | case .rightMargin: return "RightMargin" 23 | case .topMargin: return "TopMargin" 24 | case .bottomMargin: return "BottomMargin" 25 | case .leadingMargin: return "LeadingMargin" 26 | case .trailingMargin: return "TrailingMargin" 27 | case .centerXWithinMargins: return "CenterXWithinMargins" 28 | case .centerYWithinMargins: return "CenterYWithinMargins" 29 | case .notAnAttribute: return "NotAnAttribute" 30 | } 31 | } 32 | } 33 | 34 | extension LayoutAnchor { 35 | internal var variable: Variable { 36 | Variable("\(type(of: self.item)):0x\(String(UInt(bitPattern: ObjectIdentifier(self.item)), radix: 16)).\(self.attribute.name)") 37 | } 38 | } 39 | 40 | extension LayoutConstraint { 41 | internal var constraint: Constraint { 42 | let lhs = firstAnchor.variable 43 | let rhs: Cassowary.Variable? = secondAnchor?.variable 44 | 45 | switch self.relation { 46 | case .lessThanOrEqual: 47 | if let rhs = rhs { 48 | return Constraint(lhs <= rhs * self.multiplier + self.constant, .required) 49 | } 50 | return Constraint(lhs <= self.constant, .required) 51 | 52 | case .equal: 53 | if let rhs = rhs { 54 | return Constraint(lhs * self.multiplier + self.constant == rhs, .required) 55 | } 56 | return Constraint(lhs * self.multiplier == self.constant, .required) 57 | 58 | case .greaterThanOrEqual: 59 | if let rhs = rhs { 60 | return Constraint(lhs * self.multiplier + self.constant >= rhs, .required) 61 | } 62 | return Constraint(lhs * self.multiplier >= self.constant, .required) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/AutoLayout/LayoutGuide.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool . 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | public class LayoutGuide { 9 | // MARK - Working with Layout Guides 10 | 11 | /// A string used to identify the layout guide. 12 | public var identifier: String = "" 13 | 14 | /// The layout guide's frame in its owning view's coordinate system. 15 | public private(set) var layoutFrame: Rect = .zero 16 | 17 | /// The view that owns the layout guide. 18 | public weak var owningView: View? 19 | 20 | // MARK - Creating Constraints Using Layout Anchors 21 | 22 | /// A layout anchor representing the bottom edge of the layout guide's frame. 23 | public var bottomAnchor: LayoutYAxisAnchor { 24 | LayoutYAxisAnchor(item: owningView!, attribute: .bottom) 25 | } 26 | 27 | /// A layout anchor representing the horizontal center of the layout guide's 28 | /// frame. 29 | public var centerXAnchor: LayoutXAxisAnchor { 30 | LayoutXAxisAnchor(item: owningView!, attribute: .centerX) 31 | } 32 | 33 | /// A layout anchor representing the vertical center of the layout guide's 34 | /// frame. 35 | public var centerYAnchor: LayoutYAxisAnchor { 36 | LayoutYAxisAnchor(item: owningView!, attribute: .centerY) 37 | } 38 | 39 | /// A layout anchor representing the height of the layout guide's frame. 40 | public var heightAnchor: LayoutDimension { 41 | LayoutDimension(item: owningView!, attribute: .height) 42 | } 43 | 44 | /// A layout anchor representing the leading edge of the layout guide's frame. 45 | public var leadingAnchor: LayoutXAxisAnchor { 46 | LayoutXAxisAnchor(item: owningView!, attribute: .leading) 47 | } 48 | 49 | /// A layout anchor representing the left edge of the layout guide's frame. 50 | public var leftAnchor: LayoutXAxisAnchor { 51 | LayoutXAxisAnchor(item: owningView!, attribute: .left) 52 | } 53 | 54 | /// A layout anchor representing the right edge of the layout guide's frame. 55 | public var rightAnchor: LayoutXAxisAnchor { 56 | LayoutXAxisAnchor(item: owningView!, attribute: .right) 57 | } 58 | 59 | /// A layout anchor representing the top edge of teh layout guide's frame. 60 | public var topAnchor: LayoutYAxisAnchor { 61 | LayoutYAxisAnchor(item: owningView!, attribute: .top) 62 | } 63 | 64 | /// A layout anchor representing the trailing edge of teh layout guide's 65 | /// frame. 66 | public var trailingAnchor: LayoutXAxisAnchor { 67 | LayoutXAxisAnchor(item: owningView!, attribute: .trailing) 68 | } 69 | 70 | /// A layout anchor representing the width of the layout guide's frame. 71 | public var widthAnchor: LayoutDimension { 72 | LayoutDimension(item: owningView!, attribute: .width) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/AutoLayout/LayoutPriority.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool . 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// The layout priority is used to indicate to the constraint-based layout 5 | /// system which constraints are more important, allowing the system to make 6 | /// appropriate tradeoffs when satisfying the constraints of the system as a 7 | /// whole. 8 | public struct LayoutPriority: Equatable, Hashable, RawRepresentable { 9 | public typealias RawValue = Float 10 | 11 | public let rawValue: RawValue 12 | 13 | public init(rawValue: RawValue) { 14 | self.rawValue = rawValue 15 | } 16 | } 17 | 18 | extension LayoutPriority { 19 | public init(_ rawValue: RawValue) { 20 | self.rawValue = rawValue 21 | } 22 | } 23 | 24 | extension LayoutPriority { 25 | /// A required constraint. 26 | public static var required: LayoutPriority { 27 | LayoutPriority(rawValue: 1000.0) 28 | } 29 | 30 | /// The priority level with which a button resists compressing its content. 31 | public static var defaultHigh: LayoutPriority { 32 | LayoutPriority(rawValue: 750.0) 33 | } 34 | 35 | /// The priority level with which a button hugs its contents horizontally. 36 | public static var defaultLow: LayoutPriority { 37 | LayoutPriority(rawValue: 250.0) 38 | } 39 | 40 | /// The priority level with which the view wants to conform to the target size 41 | /// in that computation. 42 | public static var fittingSizeLevel: LayoutPriority { 43 | LayoutPriority(rawValue: 50.0) 44 | } 45 | 46 | /// The priority with which a drag may end up resizing the window's scene. 47 | public static var dragThatCanResizeScene: LayoutPriority { 48 | LayoutPriority(rawValue: 510.0) 49 | } 50 | 51 | /// The priority with which the a split view divider is dragged. 52 | public static var dragThatCannotResizeScene: LayoutPriority { 53 | LayoutPriority(rawValue: 490.0) 54 | } 55 | 56 | /// The priority with which the window's scene prefers to stay the same size. 57 | public static var sceneSizeStayPut: LayoutPriority { 58 | LayoutPriority(rawValue: 500.0) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/AutoLayout/LayoutSupport.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool . 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A set of methods that provide layout support and access to layout anchors. 5 | public protocol LayoutSupport { 6 | // MARK - Layout Support 7 | 8 | /// Provides the length, in points, of the portion of the view controller's 9 | /// view that is overlaid by translucent or transparent bars. 10 | var length: Double { get } 11 | 12 | // MARK - Creating Constraints Using Layout Anchors 13 | 14 | /// A layout anchor representing the guide's bottom edge. 15 | var bottomAnchor: LayoutYAxisAnchor { get } 16 | 17 | /// A layout anchor repreenting the guide's height. 18 | var heightAnchor: LayoutDimension { get } 19 | 20 | /// A layout anchor representing the guide's top edge. 21 | var topAnchor: LayoutYAxisAnchor { get } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/AutoLayout/LayoutXAxisAnchor.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool . 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A factory class for creating horizontal layout constraint objects using a 5 | /// fluent API. 6 | public class LayoutXAxisAnchor: LayoutAnchor { 7 | // MARK - Building System Spacing Constraints 8 | 9 | /// Returns a constraint that defines by how much the current anchor trails 10 | /// the specified anchor. 11 | public func constraint(equalToSystemSpacingBelow anchor: LayoutXAxisAnchor, 12 | multiplier: Double) -> LayoutConstraint { 13 | return LayoutConstraint(item: self.item, attribute: self.attribute, 14 | relatedBy: .equal, 15 | toItem: anchor.item, attribute: anchor.attribute, 16 | multiplier: multiplier, constant: 8.0) 17 | } 18 | 19 | /// Returns a constraint that defines by how much the current anchor trails 20 | /// the specified anchor. 21 | public func constraint(greaterThanOrEqualToSystemSpacingBelow anchor: LayoutXAxisAnchor, 22 | multiplier: Double) -> LayoutConstraint { 23 | return LayoutConstraint(item: self.item, attribute: self.attribute, 24 | relatedBy: .greaterThanOrEqual, 25 | toItem: anchor.item, attribute: anchor.attribute, 26 | multiplier: multiplier, constant: 8.0) 27 | } 28 | 29 | /// Returns a constraint that defines the minimum distance by which the 30 | /// current anchor is positioned below the specified anchor. 31 | public func constraint(lessThanOrEqualToSystemSpacingBelow anchor: LayoutXAxisAnchor, 32 | multiplier: Double) -> LayoutConstraint { 33 | return LayoutConstraint(item: self.item, attribute: self.attribute, 34 | relatedBy: .lessThanOrEqual, 35 | toItem: anchor.item, attribute: anchor.attribute, 36 | multiplier: multiplier, constant: 8.0) 37 | } 38 | 39 | // MARK - Creating a Layout Dimension 40 | 41 | /// Creates a layout dimension object from two anchors. 42 | public func anchorWithOffset(to anchor: LayoutXAxisAnchor) -> LayoutDimension { 43 | fatalError("\(#function) not yet implemented") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/AutoLayout/LayoutYAxisAnchor.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool . 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A factory class for creating vertical layout constraint objects using a 5 | /// fluent API. 6 | public class LayoutYAxisAnchor: LayoutAnchor { 7 | // MARK - Building System Spacing Constraints 8 | 9 | /// Returns a constraint that defines the specific distance at which the 10 | /// current anchor is positioned below the specified anchor. 11 | public func constraint(equalToSystemSpacingBelow anchor: LayoutYAxisAnchor, 12 | multiplier: Double) -> LayoutConstraint { 13 | return LayoutConstraint(item: self.item, attribute: self.attribute, 14 | relatedBy: .equal, 15 | toItem: anchor.item, attribute: anchor.attribute, 16 | multiplier: multiplier, constant: 8.0) 17 | } 18 | 19 | /// Returns a constraint that defines the minimum distance by which the 20 | /// current anchor is positioned below the specified anchor. 21 | public func constraint(greaterThanOrEqualToSystemSpacingBelow anchor: LayoutYAxisAnchor, 22 | multiplier: Double) -> LayoutConstraint { 23 | return LayoutConstraint(item: self.item, attribute: self.attribute, 24 | relatedBy: .greaterThanOrEqual, 25 | toItem: anchor.item, attribute: anchor.attribute, 26 | multiplier: multiplier, constant: 8.0) 27 | } 28 | 29 | /// Returns a constraint that defines the maximum distance by which the 30 | /// current anchor is positioned below the specified anchor. 31 | public func constraint(lessThanOrEqualToSystemSpacingBelow anchor: LayoutYAxisAnchor, 32 | multiplier: Double) -> LayoutConstraint { 33 | return LayoutConstraint(item: self.item, attribute: self.attribute, 34 | relatedBy: .lessThanOrEqual, 35 | toItem: anchor.item, attribute: anchor.attribute, 36 | multiplier: multiplier, constant: 8.0) 37 | } 38 | 39 | // MARK - Creating a Layout Dimension 40 | 41 | /// Creates a layout dimension object from two anchors. 42 | public func anchorWithOffset(to anchor: LayoutYAxisAnchor) -> LayoutDimension { 43 | fatalError("\(#function) not yet implemented") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/CoreGraphics/Point.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A structure that contains a point in a two-dimensional coordinate system. 5 | public struct Point { 6 | // MARK - Creating Point Values 7 | 8 | /// Creates a point with coordinates specified as floating-point values. 9 | public init(x: Double, y: Double) { 10 | self.x = x 11 | self.y = y 12 | } 13 | 14 | /// Creates a point with coordinates specified as integer values. 15 | public init(x: Int, y: Int) { 16 | self.init(x: Double(x), y: Double(y)) 17 | } 18 | 19 | // MARK - Special Values 20 | 21 | /// The point with location (0,0). 22 | public static var zero: Point { 23 | Point(x: 0, y: 0) 24 | } 25 | 26 | /// Creates a point with location (0,0). 27 | public init() { 28 | self.x = 0.0 29 | self.y = 0.0 30 | } 31 | 32 | // MARK - Geometric Properties 33 | 34 | /// The x-coordinate of the point. 35 | public var x: Double 36 | 37 | /// The y-coordinate of the point. 38 | public var y: Double 39 | 40 | // MARK - Transforming Points 41 | 42 | /// Returns the point resulting from an affine transformation of an existing 43 | /// point. 44 | public func applying(_ transform: AffineTransform) -> Point { 45 | return Point(x: transform.a * self.x + transform.c * self.y + transform.tx, 46 | y: transform.b * self.x + transform.d * self.y + transform.ty) 47 | } 48 | } 49 | 50 | extension Point: Equatable { 51 | } 52 | 53 | extension Point: CustomDebugStringConvertible { 54 | public var debugDescription: String { 55 | return "Point(x: \(x), y: \(y))" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/CoreGraphics/Size.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A structure that contains width and height values. 5 | public struct Size { 6 | // MARK - Geometric Properties 7 | 8 | /// A width value. 9 | public var width: Double 10 | 11 | /// A height value. 12 | public var height: Double 13 | 14 | // MARK - Special Values 15 | 16 | /// The size whose width and height are both zero. 17 | public static var zero: Size { 18 | Size(width: 0, height: 0) 19 | } 20 | 21 | /// Creates a size with zero width and height. 22 | public init() { 23 | self = .zero 24 | } 25 | 26 | // MARK - Transforming Sizes 27 | 28 | /// Returns the height and width resulting from a transformation of an 29 | /// existing height and width. 30 | func applying(_ transform: AffineTransform) -> Size { 31 | return Size(width: transform.a * self.width + transform.c * self.height, 32 | height: transform.b * self.width + transform.d * self.height) 33 | } 34 | 35 | // MARK - Initializers 36 | 37 | /// Creates a size with dimensions specified as floating-point values. 38 | public init(width: Double, height: Double) { 39 | self.height = height 40 | self.width = width 41 | } 42 | 43 | public init(width: Int, height: Int) { 44 | self.init(width: Double(width), height: Double(height)) 45 | } 46 | } 47 | 48 | extension Size: Equatable { 49 | } 50 | 51 | extension Size: CustomDebugStringConvertible { 52 | public var debugDescription: String { 53 | return "Size(width: \(width), height: \(height))" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/CoreGraphics/Vector.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A structure that contains a two-dimensional vector. 5 | public struct Vector { 6 | // MARK - Special Values 7 | 8 | /// The vector whose components are both zero. 9 | public static var zero: Vector { 10 | Vector(dx: 0.0, dy: 0.0) 11 | } 12 | 13 | /// Creates a vector whose components are both zero. 14 | public init() { 15 | self.dx = 0.0 16 | self.dy = 0.0 17 | } 18 | 19 | // MARK - Geometric Properties 20 | 21 | /// The x component of the vector. 22 | public var dx: Double 23 | 24 | /// The y component of the vector. 25 | public var dy: Double 26 | 27 | // MARK - Initializers 28 | 29 | /// Creates a vector with components specified as floating-point values. 30 | public init(dx: Double, dy: Double) { 31 | self.dx = dx 32 | self.dy = dy 33 | } 34 | 35 | /// Creates a vector with components specified as floating-point values. 36 | public init(dx: Float, dy: Float) { 37 | self.dx = Double(dx) 38 | self.dy = Double(dy) 39 | } 40 | 41 | /// Creates a vector with components specified as integer values. 42 | public init(dx: Int, dy: Int) { 43 | self.dx = Double(dx) 44 | self.dy = Double(dy) 45 | } 46 | } 47 | 48 | extension Vector: CustomDebugStringConvertible { 49 | public var debugDescription: String { 50 | return "(\(dx), \(dy))" 51 | } 52 | } 53 | 54 | extension Vector: Decodable { 55 | } 56 | 57 | extension Vector: Encodable { 58 | } 59 | 60 | extension Vector: Equatable { 61 | } 62 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Drag and Drop/SpringLoadedInteractionContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// The spring-loaded interaction states that determine the style of the 5 | /// interaction view. 6 | public enum SpringLoadedInteractionEffectState: Int { 7 | /// An interaction state that indicates that the view was spring loaded. 8 | case activated 9 | /// An interaction state that indicates that spring loading is about to start. 10 | case activating 11 | /// An interaction state that indicates that spring loading is not engaged. 12 | case inactive 13 | /// An interaction state that indicates that spring loading is available. 14 | case possible 15 | } 16 | 17 | /// The interface an object implements to provide information about a 18 | /// spring-loaded interaction. 19 | public protocol SpringLoadedInteractionContext { 20 | /// The current view style for the string-loaded interaction. 21 | var state: SpringLoadedInteractionEffectState { get } 22 | 23 | /// The specific subview, or associated model object, of the target view to 24 | /// use for the spring-loaded interaction. 25 | var targetItem: Any? { get set } 26 | 27 | /// The view to which the current spring-loaded interaction view style is 28 | /// applied. 29 | var targetView: View? { get set } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Drawing/BezierPath.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | public class BezierPath { 5 | } 6 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Focus-Based Navigation/FocusAnimationCoordinator.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import struct Foundation.TimeInterval 5 | 6 | /// Information about focusing animations being performed by the system. 7 | public protocol FocusAnimationContext { 8 | // MARK - Getting the Animation Attributes 9 | 10 | /// The duration (measured in seconds) of the focus animation. 11 | var duration: TimeInterval { get } 12 | } 13 | 14 | /// A coordinator of focus-related animations during a focus update. 15 | public class FocusAnimationCoordinator { 16 | // MARK - Adding Animations to Focus Updates 17 | 18 | /// Runs the specified set of animations together with the system animations 19 | /// for adding focus to an item. 20 | public func addCoordinatedFocusingAnimations(_ animations: ((FocusAnimationContext) -> Void)?, 21 | completion: (() -> Void)? = nil) { 22 | } 23 | 24 | /// Runs the specified set of animations together with the system animations 25 | /// for removing focus from an item. 26 | public func addCoordinatedUnfocusingAnimations(_ animations: ((FocusAnimationContext) -> Void)?, 27 | completion: (() -> Void)? = nil) { 28 | } 29 | 30 | /// Specifies the animations to coordinate with the active focus animation. 31 | public func addCoordinatedAnimations(_ animations: (() -> Void)?, 32 | completion: (() -> Void)? = nil) { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Focus-Based Navigation/FocusItem.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | /// An object that can become focused. 9 | public protocol FocusItem: FocusEnvironment { 10 | // MARK - Determining Focusability 11 | 12 | /// A boolean value that indicates whether the item can become focused. 13 | var canBecomeFocused: Bool { get } 14 | 15 | /// A boolean value indicating whether the item is currently focused. 16 | var isFocused: Bool { get } 17 | 18 | // MARK - Retrieving the Item Frame 19 | 20 | /// The geometric frame of the item. 21 | var frame: Rect { get } 22 | 23 | // MARK - Providing Movement Hints 24 | 25 | func didHintFocusMovement(_ hint: FocusMovementHint) 26 | } 27 | 28 | extension FocusItem { 29 | public var isFocused: Bool { false } 30 | } 31 | 32 | extension FocusItem { 33 | public func didHintFocusMovement(_ hint: FocusMovementHint) { 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Focus-Based Navigation/FocusItemContainer.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | /// The container responsible for providing geometric context to focus items 9 | /// within a given focus environment. 10 | public protocol FocusItemContainer { 11 | // MARK - Retrieving Focus Items 12 | 13 | /// Retrieves all of the focus items within this container that intersect with 14 | /// the provided rectangle. 15 | func focusItems(in rect: Rect) -> [FocusItem] 16 | 17 | /// The coordinate space of the focus items contained in the focus item 18 | /// container. 19 | var coordinateSpace: CoordinateSpace { get } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Focus-Based Navigation/FocusMovementHint.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreAnimation 6 | import CoreGraphics 7 | #endif 8 | 9 | /// Provides movement hint information for the focused item. 10 | public class FocusMovementHint { 11 | // MARK - 12 | 13 | internal init () { 14 | fatalError("\(#function) not yet implemented") 15 | } 16 | 17 | // MARK - Moving Focus 18 | 19 | /// A vector representing how close focus is to moving to another item in the 20 | /// swiped direction. 21 | public private(set) var movementDirection: Vector 22 | 23 | // MARK - Transforming a Hint 24 | 25 | /// A 3D transform that contains the combined transformations of perspective, 26 | /// rotation, and translation. 27 | public private(set) var interactionTransform: Transform3D 28 | 29 | /// A 3D transform that represents a perspective matrix to be applied to match 30 | /// the system interaction hinting. 31 | public private(set) var perspectiveTransform: Transform3D 32 | 33 | /// A vector to apply to a transform to match system interaction hinting. 34 | public private(set) var rotation: Vector 35 | 36 | /// A vector to apply to a transform to match system interaction hinting. 37 | public private(set) var translation: Vector 38 | } 39 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Keyboards and Input/TextInputTraits.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | public protocol TextInputTraits { 5 | /// Managing the Keyboard Behaviour 6 | var isSecureTextEntry: Bool { get set } 7 | } 8 | 9 | extension TextInputTraits { 10 | public var isSecureTextEntry: Bool { 11 | get { return false } 12 | set { } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Menus and Shortcuts/Action.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | extension Action { 5 | /// A type that represents an action identifier. 6 | public struct Identifier: Equatable, Hashable, RawRepresentable { 7 | public typealias RawValue = String 8 | 9 | public let rawValue: RawValue 10 | 11 | public init(rawValue: RawValue) { 12 | self.rawValue = rawValue 13 | } 14 | } 15 | } 16 | 17 | extension Action.Identifier { 18 | public init(_ rawValue: String) { 19 | self.rawValue = rawValue 20 | } 21 | } 22 | 23 | /// A menu element that performs its action in a closure. 24 | open class Action: MenuElement { 25 | // MARK - Creating an Action 26 | 27 | /// Creates an action. 28 | public /*convenience*/ init(title: String = "", image: Image? = nil, 29 | identifier: Action.Identifier? = nil, 30 | discoverabilityTitle: String? = nil, 31 | attributes: MenuElement.Attributes = [], 32 | state: MenuElement.State = .off, 33 | handler: @escaping ActionHandler) { 34 | self.identifier = identifier ?? Action.Identifier("") 35 | self.discoverabilityTitle = discoverabilityTitle 36 | self.attributes = attributes 37 | self.state = state 38 | self.handler = handler 39 | 40 | super.init(title: title, image: image) 41 | } 42 | 43 | /// A type that defines the closure for an action handler. 44 | public typealias ActionHandler = (Action) -> Void 45 | 46 | // MARK - Getting Information About the Action 47 | 48 | /// The action's title. 49 | open override var title: String { 50 | get { super.title } 51 | set { super.title = newValue } 52 | } 53 | 54 | /// The action's image. 55 | open override var image: Image? { 56 | get { super.image } 57 | set { super.image = newValue } 58 | } 59 | 60 | /// The unique identifier for the action. 61 | open private(set) var identifier: Action.Identifier 62 | 63 | /// An elaborated title that explains the purpose of the action. 64 | open var discoverabilityTitle: String? 65 | 66 | /// The attributes indicating the style of the action. 67 | open var attributes: MenuElement.Attributes 68 | 69 | /// The state of the action. 70 | open var state: MenuElement.State 71 | 72 | /// The object responsible for the action handler. 73 | open internal(set) var sender: Any? 74 | 75 | internal private(set) var handler: ActionHandler 76 | } 77 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Menus and Shortcuts/ContextMenuConfiguration.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import class Foundation.NSUUID 5 | import protocol Foundation.NSCopying 6 | 7 | /// Returns the configuration data to use when previewing the content. 8 | public class ContextMenuConfiguration { 9 | internal var previewProvider: ContextMenuContentPreviewProvider 10 | 11 | internal var actionProvider: ContextMenuActionProvider? 12 | 13 | // MARK - Creating the Menu Configuration Object 14 | 15 | /// Returns the custom view controller to use when previewing your content. 16 | public typealias ContextMenuContentPreviewProvider = () -> ViewController? 17 | 18 | /// Returns an action-based contextual menu, optionally incorporating the 19 | /// system-suggested actions. 20 | public typealias ContextMenuActionProvider = ([MenuElement]) -> Menu? 21 | 22 | /// Creates a menu configuration object with the specified action and preview 23 | /// providers. 24 | public convenience init(identifier: NSCopying?, 25 | previewProvider: ContextMenuContentPreviewProvider?, 26 | actionProvider: ContextMenuActionProvider? = nil) { 27 | // TODO(compnerd) fill out the default preview provider 28 | self.init(identifier: identifier ?? NSUUID(), 29 | previewProvider: previewProvider ?? { return nil }, 30 | actionProvider: actionProvider) 31 | } 32 | 33 | private init(identifier: NSCopying, 34 | previewProvider: @escaping ContextMenuContentPreviewProvider, 35 | actionProvider: ContextMenuActionProvider?) { 36 | self.identifier = identifier 37 | self.previewProvider = previewProvider 38 | self.actionProvider = actionProvider 39 | } 40 | 41 | // MARK - Getting the Configuration Identifier 42 | 43 | /// The unique identifier for this configuration object. 44 | public let identifier: NSCopying 45 | } 46 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Menus and Shortcuts/ContextMenuInteraction.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | extension ContextMenuInteraction { 9 | /// Constants that describe the appearance of the menu. 10 | public enum Appearance: Int { 11 | /// No menu appearance. 12 | case unknown 13 | 14 | /// A modal menu with an optional preview. 15 | case rich 16 | 17 | /// A nonmodal, compact menu with no preview. 18 | case compact 19 | } 20 | } 21 | 22 | /// An interaction object that you use to display relevant actions for your 23 | /// content. 24 | public class ContextMenuInteraction: Interaction { 25 | // MARK - Creating a Context Menu Interaction Object 26 | 27 | /// Creates a context menu interaction object with the specified delegate 28 | /// object. 29 | public init(delegate: ContextMenuInteractionDelegate) { 30 | self.delegate = delegate 31 | } 32 | 33 | // MARK - Previewing and Managing the Content 34 | 35 | /// The object that provides the preview and contextual menu for your content 36 | /// and responds to interaction-related events. 37 | public private(set) weak var delegate: ContextMenuInteractionDelegate? 38 | 39 | public private(set) weak var view: View? 40 | 41 | public func willMove(to view: View?) { 42 | } 43 | 44 | public func didMove(to view: View?) { 45 | self.view = view 46 | } 47 | 48 | // MARK - Getting the Interaction's Location 49 | 50 | /// Returns the location of the user interaction in the specified view's 51 | /// coordinate system. 52 | public func location(in view: View?) -> Point { 53 | fatalError("\(#function) not yet implemented") 54 | } 55 | 56 | // MARK - Getting the Menu Appearance 57 | 58 | /// The appearance of the context menu. 59 | public var appearance: ContextMenuInteraction.Appearance = .compact 60 | 61 | // MARK - Managing Menu Interactions 62 | 63 | /// Dismisses the context menu. 64 | public func dismissMenu() { 65 | } 66 | 67 | /// Updates the currently visible menu. 68 | public func updateVisibleMenu(_ block: (Menu) -> Menu) { 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Menus and Shortcuts/ContextMenuInteractionAnimating.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// Methods adopted by system-supplied animator objects when interacting with 5 | /// context menus. 6 | public protocol ContextMenuInteractionAnimating { 7 | /// Adding Custom Animations 8 | 9 | /// Adds the specified animation block to the animator. 10 | func addAnimations(_ animations: @escaping () -> Void) 11 | 12 | /// Adds the specified completion block to the animator. 13 | func addCompletion(_ completion: @escaping () -> Void) 14 | 15 | /// Previewing the Content 16 | 17 | /// The current preview controller. 18 | var previewViewController: ViewController? { get } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Menus and Shortcuts/ContextMenuInteractionCommitAnimating.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// Constants that control the interaction commit style. 5 | public enum ContextMenuInteractionCommitStyle: Int { 6 | /// An interaction with no animations. 7 | case dismiss 8 | /// An interaction that uses animations. 9 | case pop 10 | } 11 | 12 | /// Methods adopted by system-supplied animator objects when committing 13 | /// preview-related animations. 14 | public protocol ContextMenuInteractionCommitAnimating: ContextMenuInteractionAnimating { 15 | /// Specifying the Commit Style 16 | var preferredCommitStyle: ContextMenuInteractionCommitStyle { get set } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Menus and Shortcuts/MenuBuilder.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// An interface for adding and removing menus from a menu system. 5 | public protocol MenuBuilder { 6 | // MARK - Getting Menu Systems and Elements 7 | 8 | /// The menu system that the menu builder modifies. 9 | var system: MenuSystem { get } 10 | 11 | /// Gets the menu for the specified menu identifier. 12 | func menu(for identifier: Menu.Identifier) -> Menu? 13 | 14 | /// Gets the action for the specified action identifier. 15 | func action(for identifier: Action.Identifier) -> Action? 16 | 17 | /// Gets the command for the specified selector and property list. 18 | func command(for action: @escaping (_: AnyObject?) -> Void, 19 | propertyList: Any?) -> Command? 20 | 21 | // MARK - Inserting Child Menus 22 | 23 | /// Adds a child menu as the first element of the specified parent menu. 24 | func insertChild(_ childMenu: Menu, 25 | atStartOfMenu parentIdentifier: Menu.Identifier) 26 | 27 | /// Adds a child menu as the last element of the specified parent menu. 28 | func insertChild(_ childMenu: Menu, 29 | atEndOfMenu parentIdentifier: Menu.Identifier) 30 | 31 | // MARK - Inserting Sibling Menus 32 | 33 | /// Inserts a sibling menu before the specified menu. 34 | func insertSibling(_ siblingMenu: Menu, 35 | beforeMenu siblingIdentifier: Menu.Identifier) 36 | 37 | /// Inserts a sibling menu after the specified menu. 38 | func insertSibling(_ siblingMenu: Menu, 39 | afterMenu siblingIdentifier: Menu.Identifier) 40 | 41 | // MARK - Replacing Menus and Child Menu Elements 42 | 43 | /// Replaces the specified menu with a new menu. 44 | func replace(menu replacedIdentifier: Menu.Identifier, 45 | with replacementMenu: Menu) 46 | 47 | /// Replaces the elements in a menu with the elements returned by the 48 | /// specified handler block. 49 | func replaceChildren(ofMenu parentIdentifier: Menu.Identifier, 50 | from childrenBlock: ([MenuElement]) -> [MenuElement]) 51 | 52 | // MARK - Removing a Menu 53 | 54 | /// Removes a menu from the menu system. 55 | func remove(menu removedIdentifier: Menu.Identifier) 56 | } 57 | 58 | extension MenuBuilder { 59 | func command(for action: @escaping (_: AnyObject?) -> Void, 60 | propertyList: Any?) -> Command? { 61 | return nil 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Menus and Shortcuts/MenuElement.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | extension MenuElement { 5 | /// Attributes that determine the style of the menu element. 6 | public struct Attributes: OptionSet { 7 | public typealias RawValue = Int 8 | 9 | public let rawValue: RawValue 10 | 11 | public init(rawValue: RawValue) { 12 | self.rawValue = rawValue 13 | } 14 | } 15 | } 16 | 17 | extension MenuElement.Attributes { 18 | /// An attribute indicating the destructive style. 19 | public static var destructive: MenuElement.Attributes { 20 | MenuElement.Attributes(rawValue: 1 << 1) 21 | } 22 | 23 | /// An attribute indicating the disabled style. 24 | public static var disabled: MenuElement.Attributes { 25 | MenuElement.Attributes(rawValue: 1 << 0) 26 | } 27 | 28 | /// An attribute indicating the hidden style. 29 | public static var hidden: MenuElement.Attributes { 30 | MenuElement.Attributes(rawValue: 1 << 2) 31 | } 32 | } 33 | 34 | extension MenuElement { 35 | /// Constants that indicate the state of an action-based or command-based 36 | /// menu element. 37 | public enum State: Int { 38 | /// A constant indicating the menu element is in the "off" state. 39 | case off 40 | 41 | /// A constant indicating the menu element is in the "on" state. 42 | case on 43 | 44 | /// A constant indicating the menu element is in the "mixed" state. 45 | case mixed 46 | } 47 | } 48 | 49 | /// An object representing a menu, action, or command. 50 | open class MenuElement { 51 | // MARK - Getting the Element Attributes 52 | 53 | /// The title of the menu element. 54 | open internal(set) var title: String 55 | 56 | /// The image to display alongside the menu element's title. 57 | open internal(set) var image: Image? 58 | 59 | // MARK - Creating a Menu Element 60 | 61 | /// Creates and returns a `MenuElement` initialized with the given title and 62 | /// image. 63 | public init(title: String, image: Image? = nil) { 64 | self.title = title 65 | self.image = image 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Menus and Shortcuts/MenuSystem.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// An object representing a main or contextual menu system. 5 | open class MenuSystem { 6 | // MARK - Getting a Menu System 7 | 8 | /// The main menu system. 9 | open class var main: MenuSystem { 10 | fatalError("\(#function) not yet implemented") 11 | } 12 | 13 | /// The context menu system. 14 | open class var context: MenuSystem { 15 | fatalError("\(#function) not yet implemented") 16 | } 17 | 18 | // MARK - Rebuilding a Menu System 19 | 20 | /// Tells the menu system to rebuild all of its menus. 21 | open func setNeedsRebuild() { 22 | } 23 | 24 | // MARK - Revalidating a Menu System 25 | 26 | /// Tells the menu system to validate all of its menus. 27 | open func setNeedsRevalidate() { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Menus and Shortcuts/PreviewParameters.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import class Foundation.NSValue 5 | 6 | /// Additional parameters to use when animating a preview interface. 7 | public class PreviewParameters { 8 | /// Creating Preview Parameters 9 | 10 | /// Creates a default set of preview parameters. 11 | public init() { 12 | // TODO(compnerd) initialize the default parameters 13 | } 14 | 15 | /// Creates a preview paramters object with information about the text you 16 | /// want to preview. 17 | public init(textLineRects: [NSValue]) { 18 | // TODO(compnerd) store the rects 19 | } 20 | 21 | /// Configuring the Preview Attributes 22 | 23 | /// The background color to display behind the preview. 24 | public var backgroundColor: Color! 25 | 26 | /// The portion of the view to show in the preview. 27 | public var visiblePath: BezierPath? 28 | 29 | public var shadowPath: BezierPath? 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Menus and Shortcuts/PreviewTarget.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | /// An object that specifies the container view to use for animations. 9 | public class PreviewTarget { 10 | /// Creating a Preview Target Object 11 | 12 | /// Creates a preview target object using the specified container view and 13 | /// configuration details. 14 | public init(container: View, center: Point, transform: AffineTransform) { 15 | self.container = container 16 | self.center = center 17 | self.transform = transform 18 | } 19 | 20 | /// Creates a preview target object using the specified container view and 21 | /// center point. 22 | public convenience init(container: View, center: Point) { 23 | self.init(container: container, center: center, transform: .identity) 24 | } 25 | 26 | /// Getting the Target Attributes 27 | 28 | /// The container for the view being animated. 29 | public let container: View 30 | 31 | /// The point in the containing view at which to place the center of the view 32 | /// being animated. 33 | public let center: Point 34 | 35 | /// An affine transform to apply to the view being animated. 36 | public let transform: AffineTransform 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Menus and Shortcuts/TargetedPreview.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | public class TargetedPreview { 9 | /// Creting a Targeted Preview Object 10 | 11 | /// Creates a targeted preview with the specified view, parameters, and target 12 | /// container. 13 | public init(view: View, parameters: PreviewParameters, target: PreviewTarget) { 14 | self.view = view 15 | // FIXME(compnerd) is this correct? 16 | self.size = view.frame.size 17 | self.target = target 18 | self.parameters = parameters 19 | } 20 | 21 | /// Creates a targeted preview for a view in the current window and including 22 | /// the specified parameters. 23 | public convenience init(view: View, parameters: PreviewParameters) { 24 | self.init(view: view, parameters: parameters, 25 | target: PreviewTarget(container: view, center: view.center)) 26 | } 27 | 28 | /// Creates a targeted preview for a view in the current window. 29 | public convenience init(view: View) { 30 | self.init(view: view, parameters: PreviewParameters()) 31 | } 32 | 33 | /// Getting the Preview Attributes 34 | 35 | /// The view that is the target of the animation 36 | public let view: View 37 | 38 | /// The view that is the container for the target view. 39 | public let target: PreviewTarget 40 | 41 | /// The size of the view. 42 | public let size: Size 43 | 44 | /// Additional parameters to use when configuring the animations. 45 | public let parameters: PreviewParameters 46 | 47 | /// Changing the Target's Container 48 | 49 | /// Returns a targeted preview object with the same view and parameters, but 50 | /// with a different target container. 51 | public func retargetedPreview(with newTarget: PreviewTarget) 52 | -> TargetedPreview { 53 | return TargetedPreview(view: self.view, parameters: self.parameters, 54 | target: newTarget) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Platform/BatteryMonitor.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | import class Foundation.NotificationCenter 6 | 7 | private let SwiftBatteryMonitorProc: SUBCLASSPROC = { (hWnd, uMsg, wParam, lParam, uIdSubclass, dwRefData) in 8 | let monitor: BatteryMonitor? = 9 | unsafeBitCast(dwRefData, to: AnyObject.self) as? BatteryMonitor 10 | 11 | switch uMsg { 12 | case UINT(WM_POWERBROADCAST): 13 | guard wParam == PBT_POWERSETTINGCHANGE else { 14 | log.info("\(#function): uMsg: \(uMsg), wParam: \(wParam), lParam: \(lParam)") 15 | break 16 | } 17 | 18 | let pSetting: UnsafeMutablePointer = 19 | UnsafeMutablePointer(bitPattern: UInt(lParam))! 20 | let dwDataLength: DWORD = pSetting.pointee.DataLength 21 | 22 | switch pSetting.pointee.PowerSetting { 23 | case GUID_BATTERY_PERCENTAGE_REMAINING: 24 | assert(dwDataLength == MemoryLayout.size) 25 | let dwBatteryLevel: DWORD = 26 | withUnsafePointer(to: &pSetting.pointee.Data) { 27 | $0.withMemoryRebound(to: DWORD.self, capacity: 1) { $0.pointee } 28 | } 29 | 30 | NotificationCenter.default 31 | .post(name: Device.batteryLevelDidChangeNotification, object: nil) 32 | default: 33 | break 34 | } 35 | 36 | default: 37 | break 38 | } 39 | 40 | return DefSubclassProc(hWnd, uMsg, wParam, lParam) 41 | } 42 | 43 | internal struct BatteryMonitor { 44 | private static let `class`: WindowClass = 45 | WindowClass(hInst: GetModuleHandleW(nil), name: "Swift.BatteryMonitor") 46 | 47 | private var hWnd: HWND? 48 | private var hBatteryStateNotification: HPOWERNOTIFY? 49 | private var hPowerSourceNotification: HPOWERNOTIFY? 50 | 51 | public init() { 52 | self.hWnd = CreateWindowExW(0, BatteryMonitor.class.name, nil, 0, 0, 0, 0, 0, 53 | HWND_MESSAGE, nil, GetModuleHandleW(nil), nil) 54 | guard let hWnd = self.hWnd else { 55 | log.warning("CreateWindowExW: \(Error(win32: GetLastError()))") 56 | return 57 | } 58 | 59 | SetWindowSubclass(hWnd, SwiftBatteryMonitorProc, UINT_PTR(0), 60 | unsafeBitCast(self as AnyObject, to: DWORD_PTR.self)) 61 | 62 | var setting: GUID = GUID_BATTERY_PERCENTAGE_REMAINING 63 | self.hBatteryStateNotification = 64 | RegisterPowerSettingNotification(self.hWnd, &setting, 65 | DWORD(DEVICE_NOTIFY_WINDOW_HANDLE)) 66 | if self.hBatteryStateNotification == nil { 67 | log.warning("RegisterPowerSettingNotification: \(Error(win32: GetLastError()))") 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Platform/OrientationSensor.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | import SwiftCOM 6 | 7 | internal class OrientationSensorEventListener: SwiftCOM.ISensorEvents { 8 | public func OnEvent(_ pSensor: SwiftCOM.ISensor, _ eventID: REFGUID, 9 | _ pEventData: SwiftCOM.IPortableDeviceValues) -> HRESULT { 10 | switch eventID.pointee { 11 | case SENSOR_EVENT_PROPERTY_CHANGED: 12 | break 13 | default: 14 | break 15 | } 16 | return S_OK 17 | } 18 | } 19 | 20 | internal class OrientationSensorManager { 21 | private var SensorManager: SwiftCOM.ISensorManager? 22 | private var OrientationSensor: SwiftCOM.ISensor? 23 | private var EventListener: SwiftWin32.OrientationSensorEventListener = 24 | OrientationSensorEventListener() 25 | 26 | public lazy var shared: OrientationSensorManager? = OrientationSensorManager() 27 | 28 | private init?() { 29 | do { 30 | self.SensorManager = 31 | try ISensorManager.CreateInstance(class: CLSID_SensorManager) 32 | } catch where (error as? COMError)?.hr == HRESULT_FROM_WIN32(DWORD(ERROR_ACCESS_DISABLED_BY_POLICY)) { 33 | // TODO(compnerd) unable to access SensorManager due to Group Policy 34 | // Settings, surface to the user 35 | return nil 36 | } catch { 37 | log.error("CoCreateInstance(CLSID_SensorManager, IID_ISensorManager): \(error)") 38 | return nil 39 | } 40 | 41 | guard let sensors = 42 | try? SensorManager?.GetSensorsByType(SENSOR_TYPE_AGGREGATED_DEVICE_ORIENTATION) else { 43 | return nil 44 | } 45 | 46 | // FIXME(compnerd) can we select a sensor in a better way? 47 | self.OrientationSensor = try? sensors.GetAt(0) 48 | if self.OrientationSensor == nil { return nil } 49 | 50 | // FIXME(compnerd) can we continue to an alternative sensor? 51 | switch try? self.OrientationSensor?.GetState() { 52 | case .some(SENSOR_STATE_ACCESS_DENIED): 53 | // Request Sensor Access 54 | do { 55 | try self.SensorManager?.RequestPermissions(nil, sensors, false) 56 | } catch where (error as? COMError)?.hr == HRESULT_FROM_WIN32(DWORD(ERROR_ACCESS_DENIED)) { 57 | // The user denied access to the sensor 58 | return nil 59 | } catch where (error as? COMError)?.hr == HRESULT_FROM_WIN32(DWORD(ERROR_CANCELLED)) { 60 | // The user cancelled the requested 61 | return nil 62 | } catch { 63 | log.error("ISensorManager::RequestPermissions: \(error)") 64 | return nil 65 | } 66 | case .none, .some(_): 67 | return nil 68 | } 69 | 70 | try? self.OrientationSensor?.SetEventSink(self.EventListener) 71 | } 72 | 73 | deinit { 74 | _ = try? self.OrientationSensor?.SetEventSink(nil) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Platform/Win32+PropertyWrappers.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | 6 | @propertyWrapper 7 | public struct _Win32WindowText { 8 | public var wrappedValue: String? { 9 | get { fatalError() } 10 | set { fatalError() } 11 | } 12 | 13 | public static subscript(_enclosingInstance view: EnclosingSelf, 14 | wrapped wrappedKeyPath: ReferenceWritableKeyPath, 15 | storage storageKeyPath: ReferenceWritableKeyPath) 16 | -> String? { 17 | get { 18 | let szLength: Int32 = GetWindowTextLengthW(view.hWnd) 19 | guard szLength > 0 else { return nil } 20 | 21 | let buffer: [WCHAR] = Array(unsafeUninitializedCapacity: Int(szLength) + 1) { 22 | $1 = Int(GetWindowTextW(view.hWnd, $0.baseAddress!, CInt($0.count))) + 1 23 | } 24 | return String(decodingCString: buffer, as: UTF16.self) 25 | } 26 | set(value) { 27 | SetWindowTextW(view.hWnd, value?.wide) 28 | } 29 | } 30 | 31 | public init() { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Platform/WindowClass.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | 6 | internal typealias WindowProc = 7 | @convention(c) (HWND?, UINT, WPARAM, LPARAM) -> LRESULT 8 | 9 | internal final class WindowClass { 10 | internal var name: [WCHAR] 11 | 12 | internal var hInstance: HINSTANCE? 13 | internal var value: WNDCLASSEXW? 14 | internal var atom: ATOM? 15 | 16 | public init(hInst hInstance: HINSTANCE, name: String, 17 | WindowProc lpfnWindowProc: WindowProc? = DefWindowProcW, 18 | style: UInt32 = 0, hbrBackground: HBRUSH? = nil, 19 | hCursor: HCURSOR? = nil) { 20 | self.name = name.wide 21 | 22 | self.hInstance = hInstance 23 | self.name.withUnsafeBufferPointer { 24 | self.value = WNDCLASSEXW(cbSize: UINT(MemoryLayout.size), 25 | style: style, 26 | lpfnWndProc: lpfnWindowProc, 27 | cbClsExtra: 0, 28 | cbWndExtra: 0, 29 | hInstance: hInstance, 30 | hIcon: nil, 31 | hCursor: hCursor, 32 | hbrBackground: hbrBackground, 33 | lpszMenuName: nil, 34 | lpszClassName: $0.baseAddress!, 35 | hIconSm: nil) 36 | } 37 | } 38 | 39 | public init(named: String) { 40 | self.name = named.wide 41 | } 42 | 43 | public func register() -> Bool { 44 | guard value != nil, atom == nil else { return true } 45 | self.atom = RegisterClassExW(&value!) 46 | return self.atom != nil 47 | } 48 | 49 | public func unregister() -> Bool { 50 | guard value != nil, atom != nil else { return false } 51 | if UnregisterClassW(self.name, self.hInstance) { 52 | self.atom = nil 53 | } 54 | return self.atom == nil 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Platform/WindowsHandle.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | internal protocol HandleValue { 5 | associatedtype HandleType 6 | static func release(_: HandleType?) 7 | } 8 | 9 | internal class ManagedHandle { 10 | typealias HandleType = Value.HandleType 11 | 12 | private enum ValueType { 13 | case owning(HandleType?) 14 | case referencing(HandleType?) 15 | } 16 | 17 | private var handle: ValueType 18 | 19 | public var value: HandleType? { 20 | switch self.handle { 21 | case .owning(let handle): 22 | return handle 23 | case .referencing(let handle): 24 | return handle 25 | } 26 | } 27 | 28 | init(owning handle: HandleType?) { 29 | self.handle = .owning(handle) 30 | } 31 | 32 | init(referencing handle: HandleType?) { 33 | self.handle = .referencing(handle) 34 | } 35 | 36 | deinit { 37 | switch self.handle { 38 | case .owning(let handle): 39 | if let handle = handle { 40 | Value.release(handle) 41 | } 42 | case .referencing(_): 43 | break 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Pointer Interactions/PointerInteraction.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// An interaction that enables support for effects on a view or customizes the 5 | /// pointer's appearance within a region of an app. 6 | public class PointerInteraction { 7 | // MARK - Creating Pointer Interactions 8 | 9 | /// Initializes a pointer interaction object with a specified delegate object. 10 | public init(delegate: PointerInteractionDelegate?) { 11 | self.delegate = delegate 12 | } 13 | 14 | // MARK - Managing Pointer Interactions 15 | 16 | /// An object that responds to pointer movements. 17 | public private(set) weak var delegate: PointerInteractionDelegate? 18 | 19 | // MARK - Activating Pointer Interactions 20 | 21 | /// A boolean value that indicates whether the pointer interaction is enabled. 22 | public var isEnabled: Bool = true 23 | 24 | // MARK - Triggering a Pointer Update 25 | 26 | /// Causes the interaction to update the pointer in response to an event. 27 | public func invalidate() { 28 | } 29 | 30 | // MARK - Interaction 31 | public private(set) weak var view: View? 32 | } 33 | 34 | extension PointerInteraction: Interaction { 35 | public func didMove(to view: View?) { 36 | } 37 | 38 | public func willMove(to view: View?) { 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Pointer Interactions/PointerInteractionAnimating.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// An interface for modifying an interaction animation in coordination with the 5 | /// pointer effect animations. 6 | public protocol PointerInteractionAnimating { 7 | // MARK - Managing Animations 8 | 9 | /// Adds the specified animation block to the animator. 10 | func addAnimations(_ animations: @escaping () -> Void) 11 | 12 | /// Adds the specified completion block to the animator. 13 | func addCompletion(_ completion: @escaping (Bool) -> Void) 14 | } 15 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Pointer Interactions/PointerInteractionDelegate.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// An interface for handling pointer movements within the interaction's view. 5 | public protocol PointerInteractionDelegate: AnyObject { 6 | // MARK - Defining Pointer Styles for Regions 7 | 8 | /// Asks the delegate for a region as the pointer moves within the 9 | /// interaction's view. 10 | func pointerInteraction(_ interaction: PointerInteraction, 11 | regionFor request: PointerRegionRequest, 12 | defaultRegion: PointerRegion) -> PointerRegion? 13 | 14 | /// Asks the delegate for a pointer style after an interaction receives a new 15 | /// region. 16 | func pointerInteraction(_ interaction: PointerInteraction, 17 | styleFor region: PointerRegion) -> PointerStyle? 18 | 19 | // MARK - Handling Animations for Pointer Regions 20 | 21 | /// Informs the delegate when the pointer enters a given region. 22 | func pointerInteraction(_ interaction: PointerInteraction, 23 | willEnter region: PointerRegion, 24 | animator: PointerInteractionAnimating) 25 | 26 | /// Informs the delegate when the pointer exits a given region. 27 | func pointerInteraction(_ interaction: PointerInteraction, 28 | willExit region: PointerRegion, 29 | animator: PointerInteractionAnimating) 30 | } 31 | 32 | extension PointerInteractionDelegate { 33 | public func pointerInteraction(_ interaction: PointerInteraction, 34 | regionFor request: PointerRegionRequest, 35 | defaultRegion: PointerRegion) 36 | -> PointerRegion? { 37 | return nil 38 | } 39 | 40 | public func pointerInteraction(_ interaction: PointerInteraction, 41 | styleFor region: PointerRegion) 42 | -> PointerStyle? { 43 | return nil 44 | } 45 | } 46 | 47 | extension PointerInteractionDelegate { 48 | public func pointerInteraction(_ interaction: PointerInteraction, 49 | willEnter region: PointerRegion, 50 | animator: PointerInteractionAnimating) { 51 | } 52 | 53 | public func pointerInteraction(_ interaction: PointerInteraction, 54 | willExit region: PointerRegion, 55 | animator: PointerInteractionAnimating) { 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Pointer Interactions/PointerRegion.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | public class PointerRegion { 9 | // MARK - Configuring a Region 10 | 11 | /// The rectangle bounds of the region. 12 | public private(set) var rect: Rect 13 | 14 | // MARK - Initializers 15 | 16 | public /*convenience*/ init(rect: Rect, identifier: AnyHashable? = nil) { 17 | self.rect = rect 18 | self.identifier = identifier 19 | } 20 | 21 | // MARK - Instance Property 22 | 23 | public private(set) var identifier: AnyHashable? 24 | } 25 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Pointer Interactions/PointerRegionRequest.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | /// An object to describe the pointer's location in the interaction's view. 9 | public class PointerRegionRequest { 10 | // MARK - Inspecting the Region Request 11 | 12 | /// The location of the pointer in the interaction's view's coordinate space. 13 | public private(set) var location: Point 14 | 15 | /// Key modifier flags representing keyboard keys pressed by the user at the 16 | /// time of this request. 17 | public private(set) var modifiers: KeyModifierFlags 18 | 19 | internal init(location: Point, modifiers: KeyModifierFlags) { 20 | self.location = location 21 | self.modifiers = modifiers 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Support/Array+Extensions.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool . 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import ucrt 5 | 6 | extension Array where Element == UInt16 { 7 | internal init(from string: String) { 8 | self = string.withCString(encodedAs: UTF16.self) { buffer in 9 | Array(unsafeUninitializedCapacity: string.utf16.count + 1) { 10 | wcscpy_s($0.baseAddress, $0.count, buffer) 11 | $1 = $0.count 12 | } 13 | } 14 | } 15 | } 16 | 17 | extension Array where Element: Equatable { 18 | mutating func remove(object: Element) { 19 | if let index = firstIndex(of: object) { remove(at: index) } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Support/Date+Extensions.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | 6 | import struct Foundation.Date 7 | import struct Foundation.TimeInterval 8 | 9 | // 100 nanosecond ticks 10 | @_transparent 11 | internal var WindowsTick: Double { 10_000_000 } 12 | 13 | // NT to Unix Epoch (seconds) 14 | @_transparent 15 | internal var NTToUnixEpochBias: Double { 11_644_473_600 } 16 | 17 | extension FILETIME { 18 | @inline(__always) 19 | internal init(_ systemTime: SYSTEMTIME) { 20 | self = FILETIME() 21 | withUnsafePointer(to: systemTime) { 22 | guard SystemTimeToFileTime($0, &self) else { 23 | fatalError("SystemTimeToFileTime: \(Error(win32: GetLastError()))") 24 | } 25 | } 26 | } 27 | 28 | @inline(__always) 29 | internal init(timeIntervalSince1970 interval: TimeInterval) { 30 | let value = UInt64((interval + NTToUnixEpochBias) * WindowsTick) 31 | self = FILETIME(dwLowDateTime: DWORD((value >> 0) & 0xffffffff), 32 | dwHighDateTime: DWORD((value >> 32) & 0xffffffff)) 33 | } 34 | 35 | @inline(__always) 36 | internal var timeIntervalSince1970: TimeInterval { 37 | var ulTime: ULARGE_INTEGER = ULARGE_INTEGER() 38 | ulTime.LowPart = self.dwLowDateTime 39 | ulTime.HighPart = self.dwHighDateTime 40 | return Double(ulTime.QuadPart) / WindowsTick - NTToUnixEpochBias 41 | } 42 | } 43 | 44 | extension SYSTEMTIME { 45 | @inline(__always) 46 | internal init(_ fileTime: FILETIME) { 47 | self = SYSTEMTIME() 48 | withUnsafePointer(to: fileTime) { 49 | guard FileTimeToSystemTime($0, &self) else { 50 | fatalError("FileTimeToSystemTime: \(Error(win32: GetLastError()))") 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Support/IndexPath+UIExtensions.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import struct Foundation.IndexPath 5 | 6 | extension IndexPath { 7 | /// An index number identifying a section in a table view or collection view. 8 | public var section: Int { 9 | return self[0] 10 | } 11 | } 12 | 13 | extension IndexPath { 14 | /// An index number identifying a row in a section of a table view. 15 | public var row: Int { 16 | return self[1] 17 | } 18 | 19 | /// Initializes an index path with the indexes of a specific row and section 20 | /// in a table view. 21 | public init(row: Int, section: Int) { 22 | self.init(indexes: [section, row]) 23 | } 24 | } 25 | 26 | extension IndexPath { 27 | /// An index number identifying an item in a section of a collection view. 28 | public var item: Int { 29 | return 1 30 | } 31 | 32 | /// Initializes an index path with the index of a specific item and section in 33 | /// a collection view. 34 | public init(item: Int, section: Int) { 35 | self.init(indexes: [section, item]) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Support/Logging.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.9) 5 | internal import Logging 6 | #else 7 | @_implementationOnly 8 | import Logging 9 | #endif 10 | 11 | internal let log: Logger = Logger(label: "org.compnerd.swift-win32") 12 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Support/Point+UIExtensions.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | #if swift(>=5.7) 6 | import CoreGraphics 7 | #endif 8 | 9 | extension Point { 10 | internal init(from: POINT) { 11 | self.init(x: Double(from.x), y: Double(from.y)) 12 | } 13 | } 14 | 15 | extension POINT { 16 | internal init(from: Point) { 17 | self.init(x: LONG(from.x), y: LONG(from.y)) 18 | } 19 | } 20 | 21 | extension Size { 22 | internal init(from: POINT) { 23 | self.init(width: Double(from.x), height: Double(from.y)) 24 | } 25 | } 26 | 27 | extension POINT { 28 | internal init(from: Size) { 29 | self.init(x: LONG(from.width), y: LONG(from.height)) 30 | } 31 | } 32 | 33 | extension Point { 34 | internal init(x: Integer, y: Integer) { 35 | self.init(x: Int(x), y: Int(y)) 36 | } 37 | } 38 | 39 | extension Point { 40 | internal static func + (_ lhs: Point, _ rhs: Point) -> Point { 41 | return Point(x: lhs.x + rhs.x, y: lhs.y + rhs.y) 42 | } 43 | 44 | internal static func - (_ lhs: Point, _ rhs: Point) -> Point { 45 | return Point(x: lhs.x - rhs.x, y: lhs.y - rhs.y) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Support/Rect+UIExtensions.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | #if swift(>=5.7) 6 | import CoreGraphics 7 | #endif 8 | 9 | extension Rect { 10 | internal init(from: RECT) { 11 | self.init(origin: Point(x: from.left, y: from.top), 12 | size: Size(width: from.right - from.left, 13 | height: from.bottom - from.top)) 14 | } 15 | } 16 | 17 | extension RECT { 18 | internal init(from: Rect) { 19 | self.init(left: LONG(from.origin.x), 20 | top: LONG(from.origin.y), 21 | right: LONG(from.origin.x + from.size.width), 22 | bottom: LONG(from.origin.y + from.size.height)) 23 | } 24 | } 25 | 26 | extension Rect { 27 | internal var center: Point { 28 | Point(x: self.midX, y: self.midY) 29 | } 30 | } 31 | 32 | extension Rect { 33 | internal func scaled(for dpi: UINT, style: WindowStyle) -> Rect { 34 | let scale: Double = Double(dpi) / Double(USER_DEFAULT_SCREEN_DPI) 35 | 36 | var r: RECT = 37 | RECT(from: self.applying(AffineTransform(scaleX: scale, y: scale))) 38 | if !AdjustWindowRectExForDpi(&r, style.base, false, style.extended, dpi) { 39 | log.warning("AdjustWindowRectExForDpi: \(Error(win32: GetLastError()))") 40 | } 41 | 42 | return Rect(from: r) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Support/Size+UIExtensions.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | extension Size { 9 | internal init(width: Integer, height: Integer) { 10 | self.init(width: Int(width), height: Int(height)) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Support/String+UIExtensions.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | extension String { 5 | public var wide: [UInt16] { 6 | return Array(from: self) 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Support/WinSDK+UIExtensions.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3 3 | 4 | import WinSDK 5 | 6 | internal func UserData(from hWnd: HWND?) -> Type? { 7 | guard let hWnd = hWnd else { return nil } 8 | 9 | let lpUserData = GetWindowLongPtrW(hWnd, GWLP_USERDATA) 10 | return lpUserData == 0 ? nil 11 | : unsafeBitCast(lpUserData, to: AnyObject.self) as? Type 12 | } 13 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Support/WindowsHandle+UIExtensions.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | 6 | extension HBITMAP__: HandleValue { 7 | typealias HandleType = HBITMAP 8 | internal static func release(_ hBitmap: HandleType?) { 9 | if let hBitmap = hBitmap { 10 | DeleteObject(hBitmap) 11 | } 12 | } 13 | } 14 | 15 | internal typealias BitmapHandle = ManagedHandle 16 | 17 | extension HBRUSH__: HandleValue { 18 | typealias HandleType = HBRUSH 19 | internal static func release(_ hBrush: HandleType?) { 20 | if let hBrush = hBrush { 21 | DeleteObject(hBrush) 22 | } 23 | } 24 | } 25 | 26 | internal typealias BrushHandle = ManagedHandle 27 | 28 | extension HDC__: HandleValue { 29 | typealias HandleType = HDC 30 | internal static func release(_ hDC: HandleType?) { 31 | if let hDC = hDC { 32 | DeleteDC(hDC) 33 | } 34 | } 35 | } 36 | 37 | internal typealias DeviceContextHandle = ManagedHandle 38 | 39 | extension HFONT__: HandleValue { 40 | typealias HandleType = HFONT 41 | internal static func release(_ hFont: HandleType?) { 42 | if let hFont = hFont { 43 | DeleteObject(hFont) 44 | } 45 | } 46 | } 47 | 48 | internal typealias FontHandle = ManagedHandle 49 | 50 | extension HMENU: HandleValue { 51 | typealias HandleType = HMENU 52 | internal static func release(_ hMenu: HandleType?) { 53 | if let hMenu = hMenu { 54 | DestroyMenu(hMenu) 55 | } 56 | } 57 | } 58 | 59 | internal typealias MenuHandle = ManagedHandle 60 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Text Display and Fonts/FontMetrics.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | public class FontMetrics { 5 | /// Creating a Font Metrics Object 6 | 7 | /// Creates a font metrics object for the specified text style. 8 | public init (forTextStyle style: Font.TextStyle) { 9 | } 10 | 11 | /// The default font metrics object for content. 12 | public static let `default`: FontMetrics = FontMetrics(forTextStyle: .body) 13 | 14 | /// Creating Scaled Fonts 15 | 16 | /// Returns a version of the specified font that adopts the current font 17 | /// metrics. 18 | public func scaledFont(for font: Font) -> Font { 19 | return scaledFont(for: font, compatibleWith: nil) 20 | } 21 | 22 | /// Returns a version of the specified font that adopts the current font 23 | /// metrics and suports the specified traitss. 24 | public func scaledFont(for font: Font, 25 | compatibleWith traitCollection: TraitCollection?) 26 | -> Font { 27 | return scaledFont(for: font, maximumPointSize: Double.greatestFiniteMagnitude, 28 | compatibleWith: traitCollection) 29 | } 30 | 31 | /// Returns a version of the specified font that adopts the current font 32 | /// metrics and is constrained to the specified maximum size. 33 | public func scaledFont(for font: Font, maximumPointSize: Double) -> Font { 34 | return scaledFont(for: font, maximumPointSize: maximumPointSize, 35 | compatibleWith: nil) 36 | } 37 | 38 | /// Returns a version of the specified font that adopts the current font 39 | /// metrics and is constrained to the specified traits and size. 40 | public func scaledFont(for font: Font, maximumPointSize: Double, 41 | compatibleWith traitCollection: TraitCollection?) 42 | -> Font { 43 | let _ = traitCollection ?? TraitCollection.current 44 | // TODO(compnerd) adjust the font size for the trait collection and cap the 45 | // size. 46 | fatalError("\(#function) not yet implemented") 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Text Storage/ParagraphStyle.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// Constants that specify what happens when a line is too long for its 5 | /// container. 6 | public enum LineBreakMode: Int { 7 | // MARK - Constants 8 | 9 | /// Wrapping occurs at word boundaries, unless the word doesn’t fit on a 10 | /// single line. 11 | case byWordWrapping 12 | 13 | /// Wrapping occurs before the first character that doesn’t fit. 14 | case byCharWrapping 15 | 16 | /// Lines don't extend past the edge of the text container. 17 | case byClipping 18 | 19 | /// The line displays so that the end fits in the container and an ellipsis 20 | /// glyph indicates the missing text at the beginning of the line. 21 | case byTruncatingHead 22 | 23 | /// The line displays so that the beginning fits in the container and an 24 | /// ellipsis glyph indicates the missing text at the end of the line. 25 | case byTruncatingTail 26 | 27 | /// The line displays so that the beginning and end fit in the container and 28 | /// an ellipsis glyph indicates the missing text in the middle. 29 | case byTruncatingMiddle 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Touches, Presses, and Gestures/PressesEvent.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import struct Foundation.TimeInterval 5 | 6 | /// An event that describes the state of a set of physical buttons that are 7 | /// available to the device, such as those on an associated remote or game 8 | /// controller. 9 | open class PressesEvent: Event { 10 | // MARK - Reading the Event Button Presses 11 | 12 | /// Returns the state of all physical buttons in the event. 13 | open private(set) var allPresses: Set 14 | 15 | /// Returns the state of all physical buttons in the event that are associated 16 | /// with a particular gesture recognizer. 17 | open func presses(for guesture: GestureRecognizer) -> Set { 18 | fatalError("\(#function) not yet implemented") 19 | } 20 | 21 | // MARK - 22 | 23 | internal init(presses: Set, timestamp: TimeInterval) { 24 | self.allPresses = presses 25 | super.init(type: .presses, subtype: .none, timestamp: timestamp) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Touches, Presses, and Gestures/TapGestureRecognizer.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A discrete gesture recognizer that interprets single or multiple taps. 5 | public class TapGestureRecognizer: GestureRecognizer { 6 | // MARK - Configuring the Gesture 7 | 8 | /// The bitmask of the buttons the user must press for gesture recognition. 9 | public var buttonMaskRequired: Event.ButtonMask = [.primary] 10 | 11 | /// The number of taps necessary for gesture recognition. 12 | public var numberOfTapsRequired: Int = 1 13 | 14 | /// The number of fingers that the user must tap for gesture recognition. 15 | public var numberOfTouchesRequired: Int = 1 16 | } 17 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Touches, Presses, and Gestures/Touch.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import struct Foundation.TimeInterval 5 | 6 | extension Touch { 7 | /// The type of touch received. 8 | public enum TouchType: Int { 9 | /// A touch resulting from direct contact with the screen. 10 | case direct 11 | 12 | /// A touch that did not result from direct contact with the screen. 13 | case indirect 14 | 15 | /// A touch from a stylus. 16 | case pencil 17 | } 18 | } 19 | 20 | extension Touch { 21 | /// The phase of a touch event. 22 | public enum Phase: Int { 23 | /// A touch for a given event has pressed down on the screen. 24 | case began 25 | 26 | /// A touch for a given event has moved over the screen. 27 | case moved 28 | 29 | /// A touch for a given event is presseddown on the screen, but hasn't moved 30 | /// since the previous event. 31 | case stationary 32 | 33 | /// A touch for a given event has lifted from the screen. 34 | case ended 35 | 36 | /// The system cancelled tracking for a touch, for example, when the user 37 | /// moves the device against their face. 38 | case cancelled 39 | 40 | /// A touch for a given event has entered a window on the screen. 41 | case regionEntered 42 | 43 | /// A touch for the given event is within a window on the screen, but has not 44 | /// yet pressed down. 45 | case regionMoved 46 | 47 | /// A touch for given event has left a window on the screen. 48 | case regionExited 49 | } 50 | } 51 | 52 | /// An object representing the location, size, movement, and force of a touch 53 | /// occurring on the screen. 54 | public class Touch { 55 | /// Getting the Location of a Touch 56 | 57 | /// The view to which touches are being delivered, if any. 58 | public let view: View? 59 | 60 | /// Getting Touch Attriutes 61 | 62 | /// The time when the touch occurred or when it was last mutated. 63 | public let timestamp: TimeInterval 64 | 65 | internal init(for view: View?, at time: TimeInterval) { 66 | self.view = view 67 | self.timestamp = time 68 | } 69 | } 70 | 71 | extension Touch: Hashable { 72 | public static func ==(_ lhs: Touch, _ rhs: Touch) -> Bool { 73 | return lhs.view == rhs.view && lhs.timestamp == rhs.timestamp 74 | } 75 | 76 | public func hash(into hasher: inout Hasher) { 77 | // TODO(compnerd) figure out how to hash a Touch 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/UI/ContentSizeCategoryAdjusting.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A collection of methods that gives controls an easy way to adopt automatic 5 | /// adjustment to content category changes. 6 | public protocol ContentSizeCategoryAdjusting { 7 | /// Adjusting the Size of Fonts 8 | 9 | /// A boolean that indicates whether the object automatically updates its font 10 | /// when the device's context size category changes. 11 | var adjustsFontForContentSizeCategory: Bool { get set } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/UI/ContentSizeCategoryImageAdjusting.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// Methods to determine when to adjust images for different content size 5 | /// categories. 6 | public protocol ContentSizeCategoryImageAdjusting { 7 | /// Preferring Accessibility-Specific Images 8 | 9 | /// A boolean that indicates whether the image size increases to support 10 | /// accessibility content size categories. 11 | var adjustsImageSizeForAccessibilityContentSizeCategory: Bool { get set } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/UI/Interaction.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// The protocol that an interaction implements to access the view that owns it. 5 | public protocol Interaction: AnyObject { 6 | // MARK - Getting the View 7 | 8 | /// The view that owns the interaction. 9 | /* weak */ var view: View? { get } 10 | 11 | // MARK - Tracking the Movements 12 | 13 | /// Tells the interaction that a view added or removed it from the view's 14 | /// interaction array. 15 | func didMove(to view: View?) 16 | 17 | /// Tells the interaction that a view will add or remove it from the view's 18 | /// interaction array. 19 | func willMove(to view: View?) 20 | } 21 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/UI/SceneSizeRestrictions.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | public class SceneSizeRestrictions { 9 | /// Setting the Size Restrictions 10 | 11 | /// The minimum width and height supported by your application's windows. 12 | public var minimumSize: Size = Size(width: 768, height: 768) 13 | 14 | /// The maximum width and height supported by your application's windows. 15 | public var maximumSize: Size = Size(width: 768, height: 768) 16 | } 17 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/View Controllers/ContentContainer.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | /// A set of methods for adapting the contents of your view controllers to size 9 | /// and trait changes. 10 | public protocol ContentContainer { 11 | // MARK - Responding to Environment Changes 12 | 13 | /// Notifies the container that the size of its view is about to change. 14 | func willTransition(to: Size, 15 | with coodinator: ViewControllerTransitionCoordinator) 16 | 17 | /// Notifies the container that its trait collection changed. 18 | func willTransition(to: TraitCollection, 19 | with coordinator: ViewControllerTransitionCoordinator) 20 | 21 | // MARK - Responding to Changes in Child View Controllers 22 | 23 | /// The preferred size for the container's content. 24 | var preferredContentSize: Size { get } 25 | 26 | /// Returns the size of the specified child view controller's content. 27 | func size(forChildContentContainer container: ContentContainer, 28 | withParentContainerSize parentSize: Size) -> Size 29 | 30 | /// Notifies an interested controller that the preferred content size of one of 31 | /// its children changed. 32 | func preferredContentSizeDidChange(forChildContentContainer container: ContentContainer) 33 | 34 | /// Notifies the container that a child view controller was resized using auto 35 | /// layout. 36 | func systemLayoutFittingSizeDidChange(forChildContentContainer container: ContentContainer) 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/Axis.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// Defines a structure that specifies the layout axes. 5 | public struct Axis: OptionSet { 6 | public typealias RawValue = UInt 7 | 8 | public let rawValue: RawValue 9 | 10 | // MARK - Initializers 11 | 12 | public init(rawValue: RawValue) { 13 | self.rawValue = rawValue 14 | } 15 | } 16 | 17 | extension Axis { 18 | public static var both: Axis { 19 | [.horizontal, .vertical] 20 | } 21 | 22 | public static var horizontal: Axis { 23 | Axis(rawValue: 1 << 0) 24 | } 25 | 26 | public static var vertical: Axis { 27 | Axis(rawValue: 1 << 1) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/BarButtonItemGroup.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A set of bar button items on the shortcuts bar. 5 | open class BarButtonItemGroup { 6 | // MARK - Initializing a Bar Button Item Group 7 | 8 | /// Initializes and returns a bar button item group with the specified items. 9 | public init(barButtonItems: [BarButtonItem], representativeItem: BarButtonItem?) { 10 | self.barButtonItems = barButtonItems 11 | self.representativeItem = representativeItem 12 | } 13 | 14 | // MARK - Configuring the Group 15 | 16 | /// The bar button items to display on the shortcuts bar. 17 | /// 18 | /// You may include any number of bar button items in a group, but you should 19 | /// keep the total number of items relatively small because of space 20 | /// considerations. The items in a group are typically related to each other, 21 | /// but need not be. The array must contain at least one item. 22 | /// 23 | /// Items can belong to only one group at a time. If you specify an item that 24 | /// is already in a group, the framework removes the item from its previous 25 | /// group before assigning it to the current group. 26 | open var barButtonItems: [BarButtonItem] 27 | 28 | /// The item to display for a group when space is constrained. 29 | /// 30 | /// When space is constrained on the shortcuts bar, the framework may display 31 | /// a group's representative item in place of its actual items. The 32 | /// representative item is a single bar button item that is unique from the 33 | /// other items in the group. Tapping the representative item calls its action 34 | /// method normally. If you omit that action method, the framework responds by 35 | /// automatically displaying the group’s items in a standard interface. 36 | /// 37 | /// If you do not specify a representative item for a group, the framework 38 | /// tries to display the group's items in the shortcuts bar. If space is still 39 | /// constrained, the framework may modify the appearance of items in the group 40 | /// to make room for all of the items. For example, the framework may truncate 41 | /// the titles of textual bar button items. When space is severely 42 | /// constrained, the framework may not even display a group's representative 43 | /// item. 44 | open var representativeItem: BarButtonItem? 45 | 46 | // MARK - Determining the Group's Appearance 47 | 48 | /// A boolean value indicating whether the representative item is being 49 | /// displayed in place of the group's items. 50 | /// 51 | /// The value of this property is `true` when the representative item is being 52 | /// displayed in the shortcuts bar. The value is false when the individual bar 53 | /// button items are being displayed in the shortcuts bar. 54 | open private(set) var isDisplayingRepresentativeItem: Bool = true 55 | } 56 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/BarPositioning.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// Constants to specify metrics to use for appearance. 5 | public enum BarMetrics: Int { 6 | /// Specifies default metrics for the device. 7 | case `default` 8 | 9 | /// Specifies metrics when using the phone idiom. 10 | case compact 11 | 12 | /// Specifies default metrics for the device for bars with the 13 | /// prompt property, such as `NavigationBar` and `SearchBar`. 14 | case defaultPrompt 15 | 16 | /// Specifies metrics for bars with the prompt property when using 17 | /// the phone idiom, such as `NavigationBar` and `SearchBar`. 18 | case compactPrompt 19 | } 20 | 21 | extension BarMetrics { 22 | /// Specifies metrics for landscape orientation using the phone idiom. 23 | @available(*, unavailable) 24 | public static var landscapePhone: BarMetrics { 25 | return .compact 26 | } 27 | 28 | /// Specifies metrics for landscape orientation using the phone idiom 29 | /// for bars with the prompt property, such as `NavigationBar` and 30 | /// `SearchBar`. 31 | @available(*, unavailable) 32 | public static var landscapePhonePrompt: BarMetrics { 33 | return .compactPrompt 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/Button.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | 6 | #if swift(>=5.7) 7 | import CoreGraphics 8 | #endif 9 | 10 | private let SwiftButtonProc: SUBCLASSPROC = { (hWnd, uMsg, wParam, lParam, uIdSubclass, dwRefData) in 11 | let button: Button? = unsafeBitCast(dwRefData, to: AnyObject.self) as? Button 12 | 13 | switch uMsg { 14 | case UINT(WM_LBUTTONUP): 15 | button?.sendActions(for: .primaryActionTriggered) 16 | default: 17 | break 18 | } 19 | 20 | return DefSubclassProc(hWnd, uMsg, wParam, lParam) 21 | } 22 | 23 | extension Button { 24 | /// Specifies the style of a button. 25 | public enum ButtonType: Int { 26 | /// No button style. 27 | case custom 28 | 29 | /// A system style button, such as those shown in navigation bars and 30 | /// toolbars. 31 | case system 32 | 33 | /// A detail disclosure button. 34 | case detailDisclosure 35 | 36 | /// An information button that has a light background. 37 | case infoLight 38 | 39 | /// An information button that has a dark background. 40 | case infoDark 41 | 42 | /// A contact add button. 43 | case contactAdd 44 | 45 | /// A standard system button without a blurred background view. 46 | case plain 47 | 48 | /// A close button to dismiss panels and views. 49 | case close 50 | } 51 | } 52 | 53 | /// A control that executes your custom code in response to user interactions. 54 | public class Button: Control { 55 | private static let `class`: WindowClass = WindowClass(named: WC_BUTTON) 56 | 57 | // MSDN: 58 | // A button sends the `BN_DISABLE`, `BN_PUSHED`, `BN_KILLFOCUS`, `BN_PAINT`, 59 | // `BN_SETFOCUS`, and `BN_UNPUSHED` notification codes only if it has the 60 | // `BS_NOFITY` style. 61 | private static let style: WindowStyle = 62 | (base: WS_TABSTOP | DWORD(BS_MULTILINE | BS_NOTIFY | BS_PUSHBUTTON), 63 | extended: 0) 64 | 65 | // MARK - Creating Buttons 66 | 67 | /// Creates a new button with the specified frame. 68 | public init(frame: Rect) { 69 | super.init(frame: frame, class: Button.class, style: Button.style) 70 | 71 | _ = SetWindowSubclass(hWnd, SwiftButtonProc, UINT_PTR(1), 72 | unsafeBitCast(self as AnyObject, to: DWORD_PTR.self)) 73 | } 74 | 75 | /// Creates a new button with the specified frame, registers the primary 76 | /// action event, and sets the title and image to the action's title and 77 | /// image. 78 | public convenience init(frame: Rect, primaryAction: Action?) { 79 | self.init(frame: frame) 80 | if let action = primaryAction { 81 | self.setTitle(action.title, forState: .normal) 82 | self.addAction(action, for: .primaryActionTriggered) 83 | } 84 | } 85 | 86 | // MARK - Configuring the Button Title 87 | 88 | /// Sets the title to use for the specified state. 89 | public func setTitle(_ title: String?, forState state: Control.State) { 90 | // FIXME(compnerd) handle title setting for different states 91 | assert(state == .normal, "state handling not yet implemented") 92 | SetWindowTextW(hWnd, title?.wide) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/DatePicker.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | 6 | import struct Foundation.Date 7 | 8 | #if swift(>=5.7) 9 | import CoreGraphics 10 | #endif 11 | 12 | private let SwiftDatePickerProc: SUBCLASSPROC = { (hWnd, uMsg, wParam, lParam, uIdSubclass, dwRefData) in 13 | let datepicker: DatePicker? = 14 | unsafeBitCast(dwRefData, to: AnyObject.self) as? DatePicker 15 | return DefSubclassProc(hWnd, uMsg, wParam, lParam) 16 | } 17 | 18 | public enum DatePickerStyle: Int { 19 | case automatic 20 | case wheels 21 | case compact 22 | case inline 23 | } 24 | 25 | public class DatePicker: Control { 26 | private static let `class`: WindowClass = 27 | WindowClass(named: DATETIMEPICK_CLASS) 28 | private static let style: WindowStyle = 29 | (base: WS_POPUP | WS_TABSTOP, extended: 0) 30 | 31 | // MARK - Managing the Date and Calendar 32 | 33 | /// The date displayed by the date picker. 34 | public var date: Date { 35 | get { 36 | var stDateTime: SYSTEMTIME = SYSTEMTIME() 37 | // FIXME(compnerd) ensure that GDT_VALID is returned 38 | _ = withUnsafeMutablePointer(to: &stDateTime) { 39 | SendMessageW(self.hWnd, UINT(DTM_GETSYSTEMTIME), 40 | WPARAM(0), LPARAM(UInt(bitPattern: $0))) 41 | } 42 | 43 | let ftDateTime: FILETIME = FILETIME(stDateTime) 44 | return Date(timeIntervalSince1970: ftDateTime.timeIntervalSince1970) 45 | } 46 | set { self.setDate(newValue, animated: false) } 47 | } 48 | 49 | /// Sets the date to display in the date picker, with an option to animate the 50 | /// setting. 51 | public func setDate(_ date: Date, animated: Bool) { 52 | assert(!animated, "not yet implemented") 53 | 54 | let ftSystemTime: FILETIME = 55 | FILETIME(timeIntervalSince1970: date.timeIntervalSince1970) 56 | let stSystemTime: SYSTEMTIME = SYSTEMTIME(ftSystemTime) 57 | 58 | _ = withUnsafePointer(to: stSystemTime) { 59 | SendMessageW(self.hWnd, UINT(DTM_SETSYSTEMTIME), 60 | WPARAM(GDT_VALID), LPARAM(UInt(bitPattern: $0))) 61 | } 62 | } 63 | 64 | // MARK - Configuring the Date Picker Style 65 | 66 | public private(set) var datePickerStyle: DatePickerStyle = .inline 67 | public private(set) var preferredDatePickerStyle: DatePickerStyle = .automatic { 68 | didSet { fatalError("not yet implemented") } 69 | } 70 | 71 | public init(frame: Rect) { 72 | super.init(frame: frame, class: DatePicker.class, style: DatePicker.style) 73 | SetWindowSubclass(hWnd, SwiftDatePickerProc, UINT_PTR(1), 74 | unsafeBitCast(self as AnyObject, to: DWORD_PTR.self)) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/DirectionalEdgeInsets.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// Edge insets that take language direction into account. 5 | public struct DirectionalEdgeInsets { 6 | // MARK - Creating Directional Edge Insets 7 | 8 | /// Initializes the edge inset struct to default values. 9 | public init() { 10 | self.bottom = 0.0 11 | self.leading = 0.0 12 | self.top = 0.0 13 | self.trailing = 0.0 14 | } 15 | 16 | init(top: Double, leading: Double, bottom: Double, trailing: Double) { 17 | self.bottom = bottom 18 | self.leading = leading 19 | self.top = top 20 | self.trailing = trailing 21 | } 22 | 23 | // MARK - Getting the Edge Values 24 | 25 | /// The bottom edge inset value. 26 | public var bottom: Double 27 | 28 | /// The leading edge inset value. 29 | public var leading: Double 30 | 31 | /// The top edge inset value. 32 | public var top: Double 33 | 34 | /// The trailing edge inset value. 35 | public var trailing: Double 36 | 37 | // MARK - Converting To and From a String 38 | 39 | /// Returns a string formatted to contain the data from a directional edge 40 | /// insets structure. 41 | public static func string(for insets: DirectionalEdgeInsets) -> String { 42 | return "{\(insets.bottom),\(insets.leading),\(insets.top),\(insets.trailing)}" 43 | } 44 | 45 | /// Returns a directional edge insets structure based on the data in the 46 | /// specified string. 47 | public static func directionalEdgeInsets(for: String) 48 | -> DirectionalEdgeInsets { 49 | fatalError("\(#function) not yet implemented") 50 | } 51 | 52 | // MARK - Getting the Empty Edge Insets 53 | 54 | /// A directional edge insets struct whose top, leading, bottom, and trailing 55 | /// fields are all set to 0. 56 | public static var zero: DirectionalEdgeInsets { 57 | DirectionalEdgeInsets(top: 0.0, leading: 0.0, bottom: 0.0, trailing: 0.0) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/DirectionalRectEdge.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// Constants that specify an edge or a set of edges, taking the user interface 5 | /// layout direction into account. 6 | public struct DirectionalRectEdge: OptionSet { 7 | public let rawValue: UInt 8 | 9 | public init(rawValue: UInt) { 10 | self.rawValue = rawValue 11 | } 12 | } 13 | 14 | extension DirectionalRectEdge { 15 | /// No specified edge. 16 | public static var none: DirectionalRectEdge { 17 | DirectionalRectEdge(rawValue: 0 << 0) 18 | } 19 | 20 | /// The top edge. 21 | public static var top: DirectionalRectEdge { 22 | DirectionalRectEdge(rawValue: 1 << 0) 23 | } 24 | 25 | /// The leading edge. 26 | public static var leading: DirectionalRectEdge { 27 | DirectionalRectEdge(rawValue: 1 << 1) 28 | } 29 | 30 | /// The bottom edge. 31 | public static var bottom: DirectionalRectEdge { 32 | DirectionalRectEdge(rawValue: 1 << 2) 33 | } 34 | 35 | /// The trailing edge. 36 | public static var trailing: DirectionalRectEdge { 37 | DirectionalRectEdge(rawValue: 1 << 3) 38 | } 39 | 40 | /// All edges. 41 | public static var all: DirectionalRectEdge { 42 | [.top, .leading, .bottom, .trailing] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/EdgeInsets.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | public class EdgeInsets { 5 | public static let zero: EdgeInsets = EdgeInsets() 6 | 7 | public let bottom: Double 8 | public let left: Double 9 | public let right: Double 10 | public let top: Double 11 | 12 | public init() { 13 | self.bottom = 0.0 14 | self.left = 0.0 15 | self.right = 0.0 16 | self.top = 0.0 17 | } 18 | 19 | public init(top: Double, left: Double, bottom: Double, right: Double) { 20 | self.bottom = bottom 21 | self.left = left 22 | self.right = right 23 | self.top = top 24 | } 25 | } 26 | 27 | extension EdgeInsets: Equatable { 28 | public static func == (_ lhs: EdgeInsets, _ rhs: EdgeInsets) -> Bool { 29 | return lhs.bottom == rhs.bottom && 30 | lhs.left == rhs.left && 31 | lhs.right == rhs.right && 32 | lhs.top == rhs.top 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/Offset.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import class Foundation.Scanner 5 | 6 | /// A structure that specifies an amount to offset a position. 7 | public struct Offset { 8 | // MARK - Initializing Offsets 9 | 10 | public init() { 11 | self = .zero 12 | } 13 | 14 | public init(horizontal: Double, vertical: Double) { 15 | self.horizontal = horizontal 16 | self.vertical = vertical 17 | } 18 | 19 | // MARK - Getting the Offset Values 20 | 21 | public private(set) var horizontal: Double 22 | 23 | public private(set) var vertical: Double 24 | } 25 | 26 | extension Offset: Equatable { 27 | public static func ==(_ lhs: Offset, _ rhs: Offset) -> Bool { 28 | return lhs.horizontal == rhs.horizontal && lhs.vertical == rhs.vertical 29 | } 30 | } 31 | extension Offset { 32 | /// Returns a string formatted to contain the data from an offset structure. 33 | public static func string(for offset: Offset) -> String { 34 | return String(format: "{%.17g, %.17g}", offset.horizontal, offset.vertical) 35 | } 36 | 37 | /// Returns an `Offset` structure corresponding to the data in a given string. 38 | /// 39 | /// In general, you should use this function only to convert strings that were 40 | // previously created using the `string(for:)` function. 41 | public static func offset(for string: String) -> Offset { 42 | let scanner: Scanner = Scanner(string: string) 43 | guard scanner.scanCharacter() == "{", 44 | let horizontal = scanner.scanDouble(), 45 | scanner.scanCharacter() == ",", 46 | let vertical = scanner.scanDouble(), 47 | scanner.scanCharacter() == "}" else { 48 | return .zero 49 | } 50 | return Offset(horizontal: horizontal, vertical: vertical) 51 | } 52 | } 53 | 54 | extension Offset { 55 | /// A `Offset` struct whose horizontal and vertical fields are set to the 56 | /// value 0. 57 | public static var zero: Offset { 58 | Offset(horizontal: 0.0, vertical: 0.0) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/ProgressView.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | 6 | #if swift(>=5.7) 7 | import CoreGraphics 8 | #endif 9 | 10 | public class ProgressView: Control { 11 | private static let `class`: WindowClass = WindowClass(named: PROGRESS_CLASS) 12 | private static let style: WindowStyle = (base: WS_POPUP, extended: 0) 13 | 14 | public init(frame: Rect) { 15 | super.init(frame: frame, class: ProgressView.class, style: ProgressView.style) 16 | SendMessageW(hWnd, UINT(PBM_SETRANGE32), 0, 100) 17 | SendMessageW(hWnd, UINT(PBM_SETPOS), 0, 0) 18 | } 19 | 20 | public func setProgress(_ progress: Float, animated: Bool) { 21 | SendMessageW(hWnd, UINT(PBM_SETPOS), WPARAM(100 * progress), 0) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/Slider.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | 6 | #if swift(>=5.7) 7 | import CoreGraphics 8 | #endif 9 | 10 | /// A control for selecting a single value from a continuous range of values. 11 | public class Slider: Control { 12 | private static let `class`: WindowClass = WindowClass(named: TRACKBAR_CLASS) 13 | private static let style: WindowStyle = 14 | (base: WS_POPUP | DWORD(TBS_HORZ | TBS_TRANSPARENTBKGND), extended: 0) 15 | 16 | // MARK - Accessing the Slider's Value 17 | 18 | /// The slider’s current value. 19 | public var value: Float { 20 | get { 21 | Float(SendMessageW(hWnd, UINT(TBM_GETPOS), 0, 0)) / 100.0 22 | } 23 | set(value) { 24 | _ = SendMessageW(hWnd, UINT(TBM_SETPOS), WPARAM(1), LPARAM(value * 100.0)) 25 | } 26 | } 27 | 28 | // MARK - Accessing the Slider's Value Limits 29 | 30 | /// The minimum value of the slider. 31 | public var minimumValue: Float { 32 | get { 33 | Float(SendMessageW(self.hWnd, UINT(TBM_GETRANGEMIN), 0, 0)) / 100.0 34 | } 35 | set(value) { 36 | _ = SendMessageW(self.hWnd, UINT(TBM_SETRANGEMIN), 37 | WPARAM(1), LPARAM(value * 100.0)) 38 | } 39 | } 40 | 41 | /// The maximum value of the slider. 42 | public var maximumValue: Float { 43 | get { 44 | Float(SendMessageW(self.hWnd, UINT(TBM_GETRANGEMAX), 0, 0)) / 100.0 45 | } 46 | set(value) { 47 | _ = SendMessageW(self.hWnd, UINT(TBM_SETRANGEMAX), 48 | WPARAM(1), LPARAM(value * 100.0)) 49 | } 50 | } 51 | 52 | // MARK - 53 | 54 | public init(frame: Rect) { 55 | super.init(frame: frame, class: Slider.class, style: Slider.style) 56 | _ = SendMessageW(self.hWnd, UINT(TBM_SETLINESIZE), WPARAM(1), LPARAM(100)) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/Switch.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | 6 | #if swift(>=5.7) 7 | import CoreGraphics 8 | #endif 9 | 10 | /// A control that offers a binary choice, such as on/off. 11 | public class Switch: Control { 12 | private static let `class`: WindowClass = WindowClass(named: WC_BUTTON) 13 | // MSDN: 14 | // A button sends the `BN_DISABLE`, `BN_PUSHED`, `BN_KILLFOCUS`, `BN_PAINT`, 15 | // `BN_SETFOCUS`, and `BN_UNPUSHED` notification codes only if it has the 16 | // `BS_NOFITY` style. 17 | private static let style: WindowStyle = 18 | (base: WS_TABSTOP | DWORD(BS_AUTOCHECKBOX | BS_NOTIFY), extended: 0) 19 | 20 | // MARK - Setting the Off/On State 21 | 22 | /// A Boolean value that determines the off/on state of the switch. 23 | public var isOn: Bool { 24 | get { SendMessageW(self.hWnd, UINT(BM_GETCHECK), 0, 0) == BST_CHECKED } 25 | set(value) { self.setOn(value, animated: false) } 26 | } 27 | 28 | /// Set the state of the switch to On or Off, optionally animating the 29 | /// transition. 30 | public func setOn(_ on: Bool, animated: Bool) { 31 | assert(!animated, "not yet implemented") 32 | _ = SendMessageW(self.hWnd, UINT(BM_SETCHECK), WPARAM(on ? 1 : 0), 0) 33 | } 34 | 35 | // MARK - Setting the Display Style 36 | 37 | /// The preferred display style for the switch. 38 | public var preferredStyle: Switch.Style = .automatic { 39 | didSet { fatalError("not yet implemented") } 40 | } 41 | 42 | /// The display style for the switch. 43 | public private(set) var style: Switch.Style = .checkbox 44 | 45 | /// The title displayed next to a checkbox-style switch. 46 | @_Win32WindowText 47 | public var title: String? 48 | 49 | // MARK - Initializing the Switch Object 50 | 51 | /// Returns an initialized switch object. 52 | public init(frame: Rect) { 53 | super.init(frame: frame, class: Switch.class, style: Switch.style) 54 | } 55 | } 56 | 57 | extension Switch { 58 | /// Styles that determine the appearance of the switch. 59 | public enum Style: Int { 60 | /// A style indicating that the system chooses the appearance of the switch 61 | /// according to the current user interface idiom. 62 | case automatic 63 | 64 | /// A style indicating that the switch appears as a checkbox. 65 | case checkbox 66 | 67 | /// A style indicating that the switch appears as an on/off slider. 68 | case sliding 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/Table Views/ContextualAction.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | 6 | extension ContextualAction { 7 | /// Constants indicating the style information that is applied to the action 8 | /// button. 9 | public enum Style: Int { 10 | /// A normal action. 11 | case normal 12 | 13 | /// An action that deletes data or performs some type of destructive task. 14 | case destructive 15 | } 16 | } 17 | 18 | /// An action to display when the user swipes a table row. 19 | public class ContextualAction { 20 | // MARK - Creating the Contexual Action 21 | 22 | /// Creates a new contextual action with the specified title and handler. 23 | public /*convenience*/ init(style: ContextualAction.Style, title: String?, 24 | handler: @escaping ContextualAction.Handler) { 25 | self.title = title 26 | self.handler = handler 27 | self.style = style 28 | 29 | // XXX(compnerd) should this be stylized from a global? 30 | switch style { 31 | case .normal: 32 | // FIXME(compnerd) should this be `.clear`? 33 | self.backgroundColor = Color(color: GetSysColor(COLOR_3DFACE)) 34 | case .destructive: 35 | self.backgroundColor = .red 36 | } 37 | } 38 | 39 | // MARK - Configuring the Appearance 40 | 41 | /// The title displayed on the action button. 42 | public var title: String? 43 | 44 | /// The background color of the action button. 45 | public let backgroundColor: Color! 46 | 47 | /// The image to display in the action button. 48 | public var image: Image? 49 | 50 | // MARK - Getting the Configuration Details 51 | 52 | /// The handler block to execute when the user selects the action. 53 | public let handler: ContextualAction.Handler 54 | 55 | /// The handler block to call in response to the selection of an action. 56 | public typealias Handler = 57 | (ContextualAction, View, @escaping (Bool) -> Void) -> Void 58 | 59 | /// The style that is applied to the action button. 60 | public let style: ContextualAction.Style 61 | } 62 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/Table Views/SwipeActionsConfiguration.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// The set of actions to perform when swiping on rows of a table. 5 | public class SwipeActionsConfiguration { 6 | // MARK - Initializing the Swipe Actions 7 | 8 | /// Creates a swipe action configuration object with the specified set of 9 | /// actions. 10 | public init(actions: [ContextualAction]) { 11 | // convenience 12 | self.actions = actions 13 | } 14 | 15 | // MARK - Getting the Swipe Action Information 16 | 17 | /// The swipe actions. 18 | public private(set) var actions: [ContextualAction] 19 | 20 | /// A boolean value indicating whether a full swipe automatically performs the 21 | /// first action. 22 | public var performsFirstActionWithFullSwipe: Bool = true 23 | } 24 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/Table Views/TableViewDataSource.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import struct Foundation.IndexPath 5 | 6 | public protocol TableViewDataSource: AnyObject { 7 | // MARK - Providng the Number of Rows and Sections 8 | 9 | /// Informs the data source to return the number of rows in a given section of 10 | /// a table view. 11 | func tableView(_ tableView: TableView, numberOfRowsInSection section: Int) 12 | -> Int 13 | 14 | /// Asks the data source to return the number of sections in the table view. 15 | func numberOfSections(in tableView: TableView) -> Int 16 | 17 | // MARK - Providing Cells, Headers, and Footers 18 | 19 | /// Asks the data source for a cell to insert in a particular location of the 20 | /// table view. 21 | func tableView(_ tableView: TableView, cellForRowAt indexPath: IndexPath) 22 | -> TableViewCell 23 | 24 | /// Asks the data source for the title of the header of the specified section 25 | /// of the table view. 26 | func tableView(_ tableView: TableView, titleForHeaderInSection section: Int) 27 | -> String? 28 | 29 | /// Asks the data source for the title of the footer of the specified section 30 | /// of the table view. 31 | func tableView(_ tableView: TableView, titleForFooterInSection section: Int) 32 | -> String? 33 | } 34 | 35 | extension TableViewDataSource { 36 | public func numberOfSections(in tableView: TableView) -> Int { 37 | return 1 38 | } 39 | } 40 | 41 | extension TableViewDataSource { 42 | public func tableView(_ tableView: TableView, 43 | titleForHeaderInSection section: Int) -> String? { 44 | return nil 45 | } 46 | 47 | public func tableView(_ tableView: TableView, 48 | titleForFooterInSection section: Int) -> String? { 49 | return nil 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/Table Views/TableViewFocusUpdateContext.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import struct Foundation.IndexPath 5 | 6 | /// A context object that provides information relevant to a specific focus 7 | /// update from one view to another. 8 | public class TableViewFocusUpdateContext: FocusUpdateContext { 9 | // MARK - Locating Focusable Items in a Table View 10 | 11 | /// Returns the index path of the cell containing the context's previously 12 | /// focused view. 13 | public internal(set) var previouslyFocusedIndexPath: IndexPath? 14 | 15 | /// Returns the index path of the cell containing the context's next focused 16 | /// view. 17 | public internal(set) var nextFocusedIndexPath: IndexPath? 18 | } 19 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/TextAlignment.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// Constants that specify text alignment. 5 | public enum TextAlignment: Int { 6 | /// Text uses the default alignment for the current localization of the app. 7 | case natural 8 | /// Text is left-aligned. 9 | case left 10 | /// Text is right-aligned. 11 | case right 12 | /// Text is center-aligned. 13 | case center 14 | /// Text is justified. 15 | case justified 16 | } 17 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/TextView.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import WinSDK 5 | import Foundation 6 | 7 | #if swift(>=5.7) 8 | import CoreGraphics 9 | #endif 10 | 11 | // FIXME(compnerd) we would like this to derive from ScrollView 12 | public class TextView: View { 13 | private static let `class`: WindowClass = WindowClass(named: MSFTEDIT_CLASS) 14 | private static let style: WindowStyle = 15 | (base: WS_BORDER | WS_HSCROLL | WS_POPUP | WS_TABSTOP | WS_VSCROLL | DWORD(ES_MULTILINE), 16 | extended: 0) 17 | 18 | public var editable: Bool { 19 | get { 20 | self.GWL_STYLE & ES_READONLY == ES_READONLY 21 | } 22 | set(editable) { 23 | SendMessageW(hWnd, UINT(EM_SETREADONLY), editable ? 0 : 1, 0) 24 | } 25 | } 26 | 27 | public override var font: Font? { 28 | get { return super.font } 29 | set(value) { super.font = value } 30 | } 31 | 32 | @_Win32WindowText 33 | public var text: String? 34 | 35 | public init(frame: Rect) { 36 | super.init(frame: frame, class: TextView.class, style: TextView.style) 37 | 38 | // Remove the `WS_EX_CLIENTEDGE` which gives it a flat appearance 39 | self.GWL_EXSTYLE &= ~WS_EX_CLIENTEDGE 40 | 41 | // Disable compatibility with the original Rich Edit and use the extended 42 | // text limit. 43 | _ = SendMessageW(self.hWnd, UINT(EM_EXLIMITTEXT), WPARAM(0), LPARAM(-1)) 44 | } 45 | 46 | public func scrollRangeToVisible(_ range: NSRange) { 47 | SendMessageW(hWnd, UINT(EM_SETSEL), WPARAM(range.location), 48 | LPARAM(range.location + range.length)) 49 | SendMessageW(hWnd, UINT(EM_SETSEL), UInt64(bitPattern: -1), -1) 50 | SendMessageW(hWnd, UINT(EM_SCROLLCARET), 0, 0) 51 | } 52 | 53 | // ContentSizeCategoryAdjusting 54 | public var adjustsFontForContentSizeCategory = false 55 | 56 | // TraitEnvironment 57 | override public func traitCollectionDidChange(_ previousTraitCollection: TraitCollection?) { 58 | super.traitCollectionDidChange(previousTraitCollection) 59 | guard self.adjustsFontForContentSizeCategory else { return } 60 | self.font = FontMetrics.default.scaledFont(for: self.font!, 61 | compatibleWith: traitCollection) 62 | } 63 | } 64 | 65 | extension TextView: ContentSizeCategoryAdjusting { 66 | } 67 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Views and Controls/VisualEffect.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// An initializer for visual effect views and blur and vibrancy effect objects. 5 | public class VisualEffect { 6 | } 7 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Windows and Screens/AlertAction.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | extension AlertAction { 5 | /// Styles to apply to action buttons in an alert. 6 | public enum Style: Int { 7 | /// Apply the default style to the action’s button. 8 | case `default` 9 | 10 | /// Apply a style that indicates the action cancels the operation and leaves 11 | /// things unchanged. 12 | case cancel 13 | 14 | /// Apply a style that indicates the action might change or delete data. 15 | case destructive 16 | } 17 | } 18 | 19 | /// An action that can be taken when the user taps a button in an alert. 20 | public class AlertAction { 21 | private let handler: ((AlertAction) -> Void)? 22 | 23 | // MARK - Creating an Alert Action 24 | 25 | /// Create and return an action with the specified title and behavior. 26 | public init(title: String?, style: AlertAction.Style, 27 | handler: ((AlertAction) -> Void)? = nil) { 28 | self.title = title 29 | self.style = style 30 | self.isEnabled = true 31 | self.handler = handler 32 | } 33 | 34 | // MARK - Getting the Action's Attributes 35 | 36 | /// The title of the action’s button. 37 | public let title: String? 38 | 39 | /// The style that is applied to the action’s button. 40 | public let style: AlertAction.Style 41 | 42 | /// A Boolean value indicating whether the action is currently enabled. 43 | public var isEnabled: Bool 44 | } 45 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Windows and Screens/AlertController.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | extension AlertController { 5 | /// Constants indicating the type of alert to display. 6 | public enum Style: Int { 7 | /// An action sheet displayed in the context of the view controller that 8 | /// presented it. 9 | case actionSheet 10 | 11 | /// An alert displayed modally for the app. 12 | case alert 13 | } 14 | } 15 | 16 | /// An object that displays an alert message to the user. 17 | public class AlertController: ViewController { 18 | // MARK - Configuring the Alert 19 | 20 | /// Descriptive text that provides more details about the reason for the 21 | /// alert. 22 | public var message: String? 23 | 24 | /// The style of the alert controller. 25 | public let preferredStyle: AlertController.Style 26 | 27 | // MARK - Creating an Alert Controller 28 | 29 | /// Creates and returns a view controller for displaying an alert to the user. 30 | public init(title: String?, message: String?, 31 | preferredStyle: AlertController.Style) { 32 | self.message = message 33 | self.preferredStyle = preferredStyle 34 | super.init() 35 | } 36 | 37 | // MARK - Configuring the User Actions 38 | 39 | /// Attaches an action object to the alert or action sheet. 40 | public func addAction(_ action: AlertAction) { 41 | } 42 | 43 | /// The actions that the user can take in response to the alert or action 44 | /// sheet. 45 | public private(set) var actions: [AlertAction] = [] 46 | 47 | /// The preferred action for the user to take from an alert. 48 | public var preferredAction: AlertAction? 49 | 50 | // MARK - Configuring Text Fields 51 | 52 | /// Adds a text field to an alert. 53 | public func addTextField(configurationHandler: ((TextField) -> Void)? = nil) { 54 | } 55 | 56 | /// The array of text fields displayed by the alert. 57 | public private(set) var textFields: [TextField]? 58 | } 59 | -------------------------------------------------------------------------------- /Sources/SwiftWin32/Windows and Screens/CoordinateSpace.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | #if swift(>=5.7) 5 | import CoreGraphics 6 | #endif 7 | 8 | /// A set of methods for converting between different frames of reference on a 9 | /// screen. 10 | public protocol CoordinateSpace { 11 | /// Getting the Bounds Rectangle 12 | 13 | /// The bounds rectangle describing the item's location and size in its own 14 | /// coordinate system. 15 | var bounds: Rect { get } 16 | 17 | /// Converting Between Coordinate Spaces 18 | 19 | /// Converts a point from the coordinate space of the current object to the 20 | /// specified coordinate space. 21 | func convert(_: Point, to: CoordinateSpace) -> Point 22 | 23 | /// Converts a point from the specified coordinate space to the coordinate 24 | /// space of the current object. 25 | func convert(_: Point, from: CoordinateSpace) -> Point 26 | 27 | /// Converts a rectangle from the coordinate space of the current object to 28 | /// the specified coordinate space. 29 | func convert(_: Rect, to: CoordinateSpace) -> Rect 30 | 31 | /// Converts a rectangle from the specified coordinate space to the coordinate 32 | /// space of the current object. 33 | func convert(_: Rect, from: CoordinateSpace) -> Rect 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/App Structure and Behaviour/App.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import SwiftWin32 5 | 6 | /// A type that represents the structure and behaviour of an application. 7 | public protocol App { 8 | // MARK - Implementing an App 9 | 10 | /// The type of scene representing the content of the application. 11 | associatedtype Body: Scene 12 | 13 | /// The content and behaviour of the application. 14 | @SceneBuilder 15 | var body: Self.Body { get } 16 | 17 | // MARK - Running an Application 18 | 19 | /// Creates an instance of the application using the body as the content. 20 | init() 21 | 22 | /// Initializes and runs the application. 23 | static func main() 24 | } 25 | 26 | extension App { 27 | public static func main() { 28 | ApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, 29 | String(describing: String(reflecting: Self.self))) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/App Structure and Behaviour/Scene.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A part of the application's user interface. 5 | public protocol Scene { 6 | // MARK - Creating a Scene 7 | 8 | /// The type of scene representing the body of this scene. 9 | associatedtype Body: Scene 10 | 11 | /// The content and behaviour of the scene. 12 | @SceneBuilder 13 | var body: Self.Body { get } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/App Structure and Behaviour/SceneBuilder.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | @resultBuilder 5 | public struct SceneBuilder { 6 | public static func buildBlock(_ content: Content) -> Content { 7 | fatalError("\(#function) not yet implemented") 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/App Structure and Behaviour/WindowGroup.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A scene that presents a group of identically structured windows. 5 | public struct WindowGroup: Scene { 6 | public var body: some Scene { 7 | fatalError("\(#function) not yet implemented") 8 | } 9 | 10 | // MARK - Creating a Window Group 11 | 12 | /// Creates a window group. 13 | public init(@ViewBuilder content: () -> Content) { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #[[ 2 | Copyright © 2019 Saleem Abdulrasool 3 | All rights reserved. 4 | 5 | SPDX-License-Identifier: BSD-3-Clause 6 | #]] 7 | 8 | add_library(SwiftWin32UI SHARED 9 | EmptyView.swift 10 | Never+SwiftUI.swift) 11 | target_sources(SwiftWin32UI PRIVATE 12 | "App Structure and Behaviour/App.swift" 13 | "App Structure and Behaviour/Scene.swift" 14 | "App Structure and Behaviour/SceneBuilder.swift" 15 | "App Structure and Behaviour/WindowGroup.swift") 16 | target_sources(SwiftWin32UI PRIVATE 17 | "Views and Controls/View.swift" 18 | "Views and Controls/ViewBuilder.swift") 19 | target_sources(SwiftWin32UI PRIVATE 20 | "View Layout and Presentation/Group.swift") 21 | target_link_libraries(SwiftWin32UI PUBLIC 22 | SwiftWin32) 23 | set_target_properties(SwiftWin32UI PROPERTIES 24 | INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY} 25 | INTERFACE_LINK_DIRECTORIES $) 26 | 27 | 28 | _install_target(SwiftWin32UI) 29 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/EmptyView.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | @frozen 5 | public struct EmptyView: View { 6 | public typealias Body = Never 7 | 8 | @inlinable 9 | public init() { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/Framework Integration/UIApplicationDelegateAdaptor.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import SwiftWin32 5 | 6 | /// A property wrapper that is used in `App` to provide an application delegate 7 | /// from Swift/Win32. 8 | @propertyWrapper 9 | public struct UIApplicationDelegateAdaptor { 10 | /// The underlying delegate. 11 | public private(set) var wrappedValue: DelegateType 12 | 13 | /// Creates an `UIApplicationDelegateAdaptor` using an ApplicationDelegate. 14 | public init(_ delegateType: DelegateType.Type = DelegateType.self) { 15 | self.wrappedValue = delegateType.init() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/Never+SwiftUI.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | extension Never: View { 5 | } 6 | 7 | extension Never: Scene { 8 | } 9 | 10 | extension Never { 11 | public typealias Body = Never 12 | } 13 | 14 | extension View where Body == Never { 15 | public var body: Never { 16 | fatalError("\(#function): View \(type(of: self)) does not have a body") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/View Layout and Presentation/AnyView.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | @usableFromInline 5 | internal class AnyViewStorageBase { 6 | } 7 | 8 | internal class AnyViewStorage: AnyViewStorageBase { 9 | public var view: ViewType 10 | 11 | init(_ view: ViewType) { 12 | self.view = view 13 | } 14 | } 15 | 16 | /// A type-erased view. 17 | /// 18 | /// An `AnyView` allows changing the type of view used in a given view 19 | /// hierarchy. Whenever the type of view used with an `AnyView` changes, the old 20 | /// hierarchy is destroyed and a new hierarchy is created for the new type. 21 | @frozen 22 | public struct AnyView: View { 23 | public typealias Body = Never 24 | 25 | internal var storage: AnyViewStorageBase 26 | 27 | // MARK - Creating a View 28 | 29 | /// Create an instance that type-erases `view`. 30 | public init(_ view: ViewType) { 31 | self.storage = AnyViewStorage(view) 32 | } 33 | 34 | @_alwaysEmitIntoClient 35 | public init(erasing view: ViewType) { 36 | self.init(view) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/View Layout and Presentation/EquatableView.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A view type that compares itself against its previous value and prevents its 5 | /// child updating if its new value is the same as its old value. 6 | @frozen 7 | public struct EquatableView: View { 8 | public typealias Body = Never 9 | 10 | // MARK - Creating an Equatable View 11 | 12 | public var content: Content 13 | 14 | @inlinable 15 | public init(content: Content) { 16 | self.content = content 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/View Layout and Presentation/Group.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// An affordance for grouping view content. 5 | @frozen 6 | public struct Group { 7 | public typealias Body = Never 8 | 9 | @usableFromInline 10 | internal var content: Content 11 | } 12 | 13 | // MARK - Creating a Group 14 | 15 | extension Group where Content: View { 16 | /// Available when `Content` conforms to `View`. 17 | @inlinable 18 | public init(@ViewBuilder content: () -> Content) { 19 | self.content = content() 20 | } 21 | } 22 | 23 | extension Group where Content: Scene { 24 | /// Available when `Content` conforms to `Scene`. 25 | @inlinable 26 | public init(@SceneBuilder content: () -> Content) { 27 | self.content = content() 28 | } 29 | } 30 | 31 | extension Group: CustomStringConvertible { 32 | public var description: String { 33 | "" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/Views and Controls/Label.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2022 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import SwiftWin32 5 | 6 | public struct Label { 7 | } 8 | 9 | extension Label: View { 10 | public typealias Body = SwiftWin32.Label 11 | 12 | public var body: SwiftWin32.Label { 13 | return SwiftWin32.Label(frame: .zero) 14 | } 15 | } 16 | 17 | extension SwiftWin32.Label: View { 18 | public typealias Body = Never 19 | } 20 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/Views and Controls/View.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | /// A type that represents part of your app’s user interface and provides 5 | /// modifiers that you use to configure views. 6 | public protocol View { 7 | /// The type of view representing the body of this view. 8 | associatedtype Body: View 9 | 10 | /// The content and behavior of the view. 11 | @ViewBuilder 12 | var body: Self.Body { get } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/SwiftWin32UI/Views and Controls/ViewBuilder.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | @resultBuilder 5 | public struct ViewBuilder { 6 | public static func buildBlock() -> EmptyView { 7 | return EmptyView() 8 | } 9 | 10 | public static func buildBlock(_ content: Content) -> Content { 11 | return content 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/AutoLayoutTests/AutoLayoutTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool . 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | 6 | import SwiftWin32 7 | 8 | final class AutoLayoutTests: XCTestCase { 9 | func testLayoutConstraintInactiveByDefault() { 10 | XCTAssertFalse(LayoutConstraint(item: self, attribute: .left, 11 | relatedBy: .equal, 12 | toItem: nil, attribute: .notAnAttribute, 13 | multiplier: 1.0, constant: 0.0).isActive) 14 | } 15 | 16 | func testLayoutConstraintActivate() { 17 | let view: View = View(frame: .zero) 18 | let container: View = View(frame: .zero) 19 | 20 | withExtendedLifetime(view) { 21 | let constraint: LayoutConstraint = 22 | LayoutConstraint(item: view, attribute: .top, relatedBy: .equal, 23 | toItem: container, attribute: .top, multiplier: 1, 24 | constant: 100) 25 | constraint.isActive = true 26 | XCTAssertTrue(constraint.isActive) 27 | } 28 | } 29 | 30 | func testLayoutConstraintActivateList() { 31 | let view: View = View(frame: .zero) 32 | let container: View = View(frame: .zero) 33 | 34 | withExtendedLifetime(view) { 35 | let constraints: [LayoutConstraint] = [ 36 | LayoutConstraint(item: view, attribute: .top, relatedBy: .equal, 37 | toItem: container, attribute: .top, multiplier: 1, 38 | constant: 100) 39 | ] 40 | LayoutConstraint.activate(constraints) 41 | 42 | XCTAssertTrue(constraints[0].isActive) 43 | } 44 | } 45 | 46 | static var allTests = [ 47 | ("testLayoutConstraintInactiveByDefault", testLayoutConstraintInactiveByDefault), 48 | ("testLayoutConstraintActivate", testLayoutConstraintActivate), 49 | ("testLayoutConstraintActivateList", testLayoutConstraintActivateList), 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /Tests/UICoreTests/BarButtonItemTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | import SwiftWin32 6 | 7 | final class BarBttonItemTests: XCTestCase { 8 | func testDefaultState() { 9 | let item: BarButtonItem = BarButtonItem() 10 | XCTAssertNil(item.target) 11 | /* XCTAssertNil(item.action) */ 12 | XCTAssertEqual(item.style, .plain) 13 | XCTAssertNil(item.possibleTitles) 14 | XCTAssertEqual(item.width, 0.0) 15 | XCTAssertNil(item.customView) 16 | XCTAssertNil(item.menu) 17 | XCTAssertNil(item.primaryAction) 18 | XCTAssertNil(item.primaryAction) 19 | XCTAssertNil(item.buttonGroup) 20 | } 21 | 22 | static var allTests = [ 23 | ("testDefaultState", testDefaultState) 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /Tests/UICoreTests/BarItemTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | import SwiftWin32 6 | 7 | final class BarItemTests: XCTestCase { 8 | func testDefaultState() { 9 | let item = BarItem() 10 | XCTAssertNil(item.title) 11 | XCTAssertNil(item.image) 12 | XCTAssertNil(item.landscapeImage) 13 | XCTAssertNil(item.largeContentSizeImage) 14 | XCTAssertEqual(item.imageInsets, .zero) 15 | XCTAssertEqual(item.landscapeImageInsets, .zero) 16 | XCTAssertEqual(item.largeContentSizeImageInsets, .zero) 17 | XCTAssertTrue(item.isEnabled) 18 | XCTAssertEqual(item.tag, 0) 19 | } 20 | 21 | static var allTests = [ 22 | ("testDefaultState", testDefaultState) 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /Tests/UICoreTests/ButtonTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | import WinSDK 6 | @testable import SwiftWin32 7 | 8 | final class ButtonTests: XCTestCase { 9 | func testConstructWithAction() { 10 | let expectation: XCTestExpectation = 11 | self.expectation(description: "action is performed") 12 | 13 | let button: Button = 14 | Button(frame: .zero, primaryAction: Action { _ in 15 | expectation.fulfill() 16 | }) 17 | 18 | // TODO(compnerd) migrate to UI automation API 19 | _ = SendMessageW(button.hWnd, UINT(WM_LBUTTONUP), 0, 0) 20 | 21 | // FIXME(compnerd) what is a good timeout value to use? 22 | waitForExpectations(timeout: 1) 23 | } 24 | 25 | static var allTests = [ 26 | ("testConstructWithAction", testConstructWithAction), 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /Tests/UICoreTests/CubicTimingParametersTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | import SwiftWin32 6 | 7 | final class CubicTimingParametersTests: XCTestCase { 8 | func testDefaultState() { 9 | let parameters1: CubicTimingParameters = CubicTimingParameters() 10 | XCTAssertEqual(parameters1.animationCurve, .linear) 11 | XCTAssertEqual(parameters1.controlPoint1, .zero) 12 | 13 | let parameters2: CubicTimingParameters = 14 | CubicTimingParameters(animationCurve: .linear) 15 | XCTAssertEqual(parameters2.animationCurve, .linear) 16 | XCTAssertEqual(parameters2.controlPoint1, .zero) 17 | XCTAssertEqual(parameters2.controlPoint2, .zero) 18 | 19 | let parameters3: CubicTimingParameters = 20 | CubicTimingParameters(controlPoint1: .zero, controlPoint2: .zero) 21 | XCTAssertEqual(parameters3.animationCurve, .linear) 22 | XCTAssertEqual(parameters3.controlPoint1, .zero) 23 | XCTAssertEqual(parameters3.controlPoint2, .zero) 24 | } 25 | 26 | static var allTests = [ 27 | ("testDefaultState", testDefaultState) 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /Tests/UICoreTests/DatePickerTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | import WinSDK 6 | import Foundation 7 | @testable import SwiftWin32 8 | 9 | final class DatePickerTests: XCTestCase { 10 | func testDateAccessors() { 11 | var ftSystemTime: FILETIME = FILETIME() 12 | GetSystemTimeAsFileTime(&ftSystemTime) 13 | var ftLocalSystemTime: FILETIME = FILETIME() 14 | FileTimeToLocalFileTime(&ftSystemTime, &ftLocalSystemTime) 15 | 16 | let datepicker: DatePicker = DatePicker(frame: .zero) 17 | 18 | let time: Date = 19 | Date(timeIntervalSince1970: ftLocalSystemTime.timeIntervalSince1970) 20 | // FIXME(compnerd) can we use a tigher bounds? 21 | XCTAssertTrue(datepicker.date.distance(to: time) <= 1.0) 22 | 23 | datepicker.date = Date(timeIntervalSinceReferenceDate: 410220000) 24 | XCTAssertEqual(datepicker.date, 25 | Date(timeIntervalSinceReferenceDate: 410220000)) 26 | } 27 | 28 | static var allTests = [ 29 | ("testDateAccessors", testDateAccessors), 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /Tests/UICoreTests/EventTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | @testable import SwiftWin32 6 | 7 | final class EventTests: XCTestCase { 8 | func testConstructPressesEvent() { 9 | let event: Event = .init(type: .presses, subtype: .none, timestamp: 0) 10 | XCTAssertEqual(event.buttonMask, []) 11 | XCTAssertEqual(event.modifierFlags, []) 12 | XCTAssertEqual(event.timestamp, 0) 13 | } 14 | 15 | static var allTests = [ 16 | ("testConstructPressesEvent", testConstructPressesEvent) 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /Tests/UICoreTests/LabelTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | @testable import SwiftWin32 6 | 7 | final class LabelTests: XCTestCase { 8 | func testAlignment() { 9 | let label: Label = Label(frame: .zero) 10 | 11 | // FIXME(compnerd) this should be `natural` 12 | XCTAssertEqual(label.textAlignment, .left) 13 | 14 | label.textAlignment = .right 15 | XCTAssertEqual(label.textAlignment, .right) 16 | } 17 | 18 | static var allTests = [ 19 | ("testAlignment", testAlignment), 20 | ] 21 | } 22 | 23 | -------------------------------------------------------------------------------- /Tests/UICoreTests/OffsetTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | import SwiftWin32 6 | 7 | final class OffsetTests: XCTestCase { 8 | func testOffsetConstructor() { 9 | XCTAssertEqual(Offset(), .zero) 10 | 11 | let offset: Offset = Offset(horizontal: .infinity, vertical: .infinity) 12 | XCTAssertEqual(offset.horizontal, .infinity) 13 | XCTAssertEqual(offset.vertical, .infinity) 14 | } 15 | 16 | func testOffsetStringForOffset() { 17 | XCTAssertEqual(Offset.offset(for: "invalid"), .zero) 18 | XCTAssertEqual(Offset.offset(for: "{"), .zero) 19 | XCTAssertEqual(Offset.offset(for: "{1"), .zero) 20 | XCTAssertEqual(Offset.offset(for: "{1,"), .zero) 21 | XCTAssertEqual(Offset.offset(for: "{1,1"), .zero) 22 | XCTAssertEqual(Offset.offset(for: "{1,1}"), Offset(horizontal: 1, vertical: 1)) 23 | } 24 | 25 | func testOffsetStringRoundtrip() { 26 | let offset: Offset = Offset(horizontal: 1, vertical: 2) 27 | let string: String = Offset.string(for: offset) 28 | XCTAssertEqual(string, "{1, 2}") 29 | XCTAssertEqual(offset, Offset.offset(for: string)) 30 | } 31 | 32 | static var allTests = [ 33 | ("testOffsetConstructor", testOffsetConstructor), 34 | ("testOffsetStringForOffset", testOffsetStringForOffset), 35 | ("testOffsetStringRoundtrip", testOffsetStringRoundtrip), 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /Tests/UICoreTests/PresentationControllerTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | import SwiftWin32 6 | 7 | final class PresentationControllerTests: XCTestCase { 8 | func testDefaultProperties() { 9 | let presentedViewController: ViewController = ViewController() 10 | let presentingViewController: ViewController = ViewController() 11 | let controller: PresentationController = 12 | PresentationController(presentedViewController: presentedViewController, 13 | presenting: presentingViewController) 14 | 15 | XCTAssertNil(controller.delegate) 16 | XCTAssertTrue(controller.presentingViewController === presentingViewController) 17 | XCTAssertTrue(controller.presentedViewController === presentedViewController) 18 | XCTAssertNil(controller.overrideTraitCollection) 19 | XCTAssertTrue(controller.shouldPresentInFullscreen) 20 | XCTAssertFalse(controller.shouldRemovePresentersView) 21 | } 22 | 23 | static var allTests = [ 24 | ("testDefaultProperties", testDefaultProperties), 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /Tests/UICoreTests/PressTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | @testable import SwiftWin32 6 | 7 | final class PressTests: XCTestCase { 8 | func testPressEquality() { 9 | let p: Press = .init(type: .select, phase: .began, force: 0.0, timestamp: 0) 10 | XCTAssertEqual(p, p) 11 | 12 | // FIXME(compnerd) is this correct? 13 | let q: Press = .init(type: .select, phase: .began, force: 0.0, timestamp: 0) 14 | XCTAssertNotEqual(p, q) 15 | } 16 | 17 | static var allTests = [ 18 | ("testPressEquality", testPressEquality), 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /Tests/UICoreTests/PressesEventTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | @testable import SwiftWin32 6 | 7 | final class PressesEventTests: XCTestCase { 8 | func testConstruct() { 9 | let event: PressesEvent = .init(presses: [], timestamp: 0) 10 | XCTAssertEqual(event.type, .presses) 11 | XCTAssertEqual(event.subtype, .none) 12 | XCTAssertEqual(event.timestamp, 0) 13 | } 14 | 15 | static var allTests = [ 16 | ("testConstruct", testConstruct), 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /Tests/UICoreTests/ResponderTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | @testable import SwiftWin32 6 | 7 | final class ResponderTests: XCTestCase { 8 | func testDefaultProperties() { 9 | let responder: Responder = Responder() 10 | XCTAssertNil(responder.next) 11 | XCTAssertFalse(responder.isFirstResponder) 12 | XCTAssertFalse(responder.canBecomeFirstResponder) 13 | XCTAssertTrue(responder.canResignFirstResponder) 14 | } 15 | 16 | static var allTests = [ 17 | ("testDefaultProperties", testDefaultProperties), 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /Tests/UICoreTests/SpringTimingParametersTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | import SwiftWin32 6 | 7 | final class SpringTimingParametersTests: XCTestCase { 8 | func testDefaultState() { 9 | let parameters1: SpringTimingParameters = SpringTimingParameters() 10 | XCTAssertEqual(parameters1.initialVelocity, .zero) 11 | 12 | let parameters2: SpringTimingParameters = 13 | SpringTimingParameters(dampingRatio: 1.0) 14 | XCTAssertEqual(parameters2.initialVelocity, .zero) 15 | 16 | let parameters3: SpringTimingParameters = 17 | SpringTimingParameters(mass: 0.0, stiffness: 0.0, damping: 0.0, 18 | initialVelocity: .zero) 19 | XCTAssertEqual(parameters3.initialVelocity, .zero) 20 | } 21 | 22 | static var allTests = [ 23 | ("testDefaultState", testDefaultState) 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /Tests/UICoreTests/StepperTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3 3 | 4 | import XCTest 5 | import WinSDK 6 | import TestUtilities 7 | @testable import SwiftWin32 8 | 9 | final class StepperTests: XCTestCase { 10 | func testValueChangedNotification() { 11 | let stepper: Stepper = Stepper(frame: .zero) 12 | 13 | let expectation: XCTestExpectation = 14 | self.expectation(description: "value change notification dispatched") 15 | let observer: ControlEventObserver = 16 | ControlEventObserver(expectation: expectation) 17 | 18 | withExtendedLifetime(observer) { 19 | stepper.addTarget(observer, action: ControlEventObserver.observe, 20 | for: .valueChanged) 21 | 22 | // TODO(compnerd) this is a workaround until UIAutomation is properly 23 | // wired up. We bypass the Windows UI subsystem, sending the underlying 24 | // `WM_HSCROLL` directly to the proxy. 25 | if let hWnd = FindWindowW("Swift.Stepper.Proxy".wide, nil) { 26 | _ = SendMessageW(hWnd, DWORD(WM_HSCROLL), WPARAM(0), 27 | LPARAM(UInt(bitPattern: stepper.hWnd))) 28 | } 29 | } 30 | 31 | // FIXME(compnerd) what is a good timeout value to use? 32 | waitForExpectations(timeout: 1) 33 | } 34 | 35 | func testValueChangedNotificationFailure() { 36 | let stepper: Stepper = Stepper(frame: .zero) 37 | 38 | let expectation: XCTestExpectation = 39 | self.expectation(description: "value change notification dispatched") 40 | expectation.isInverted = true 41 | 42 | let observer: ControlEventObserver = 43 | ControlEventObserver(expectation: expectation) 44 | 45 | withExtendedLifetime(observer) { 46 | stepper.addTarget(observer, action: ControlEventObserver.observe, 47 | for: .valueChanged) 48 | 49 | // TODO(compnerd) this is a workaround until UIAutomation is properly 50 | // wired up. We bypass the Windows UI subsystem, sending the underlying 51 | // `WM_HSCROLL` directly to the proxy. 52 | if let hWnd = FindWindowW("Swift.Stepper.Proxy".wide, nil) { 53 | _ = SendMessageW(hWnd, DWORD(WM_HSCROLL), WPARAM(0), LPARAM(0)) 54 | } 55 | } 56 | 57 | // FIXME(compnerd) what is a good timeout value to use? 58 | waitForExpectations(timeout: 1) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Tests/UICoreTests/TextViewTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | import WinSDK 6 | @testable import SwiftWin32 7 | 8 | final class TextViewTests: XCTestCase { 9 | static var hModule: HMODULE? 10 | 11 | override class func setUp() { 12 | TextViewTests.hModule = "Msftedit.dll".withCString(encodedAs: UTF16.self) { 13 | LoadLibraryW($0) 14 | } 15 | } 16 | 17 | func testConstruct() throws { 18 | try XCTSkipIf(TextViewTests.hModule == nil, "Msftedit.dll not loaded") 19 | 20 | let view: TextView = TextView(frame: .zero) 21 | XCTAssertNotEqual(view.hWnd, INVALID_HANDLE_VALUE) 22 | } 23 | 24 | static var allTests = [ 25 | ("testConstruct", testConstruct), 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /Tests/UICoreTests/WindowTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | import WinSDK 6 | #if swift(>=5.7) 7 | import CoreGraphics 8 | #endif 9 | @testable import SwiftWin32 10 | 11 | final class WindowTests: XCTestCase { 12 | func testWindowMenuEmpty() { 13 | let viewController = ViewController() 14 | viewController.view = View(frame: Rect(x: 0, y: 0, width: 100, height: 100)) 15 | 16 | let window = Window(frame: Rect(x: 0, y: 0, width: 200, height: 200)) 17 | XCTAssertNil(GetMenu(window.hWnd)) 18 | 19 | window.rootViewController = viewController 20 | 21 | let hMenu = GetMenu(window.hWnd) 22 | XCTAssertEqual(GetMenuItemCount(hMenu), 0) 23 | } 24 | 25 | func testWindowMenuWithSubmenus() { 26 | // TODO: uncomment when ViewController is `open` 27 | /* 28 | class ViewControllerWithWindowMenu: ViewController { 29 | override func buildMenu(with builder: MenuBuilder) { 30 | builder.insertSibling(Menu(title: "title1", children: [Action(title: "action", handler: { _ in })]), 31 | afterMenu: .root) 32 | builder.insertSibling(Menu(title: "title2", children: [Command(title: "command", action: { _ in })]), 33 | afterMenu: .root) 34 | } 35 | } 36 | 37 | let viewController = ViewControllerWithWindowMenu() 38 | viewController.view = View(frame: Rect(x: 0, y: 0, width: 100, height: 100)) 39 | 40 | let window = Window(frame: Rect(x: 0, y: 0, width: 200, height: 200)) 41 | window.rootViewController = viewController 42 | 43 | let hMenu = GetMenu(window.hWnd) 44 | XCTAssertEqual(GetMenuItemCount(hMenu), 2) 45 | */ 46 | } 47 | 48 | static var allTests = [ 49 | ("testWindowMenu", testWindowMenuEmpty), 50 | ("testWindowMenuWithSubmenus", testWindowMenuWithSubmenus), 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /Tests/Utilities/Utilities.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2021 Saleem Abdulrasool 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | 6 | public class ControlEventObserver { 7 | private var expectation: XCTestExpectation 8 | 9 | public init(expectation: XCTestExpectation) { 10 | self.expectation = expectation 11 | } 12 | 13 | public func observe() { 14 | self.expectation.fulfill() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Tests/main.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Saleem Abdulrasool . 2 | // SPDX-License-Identifier: BSD-3-Clause 3 | 4 | import XCTest 5 | 6 | @testable import AutoLayoutTests 7 | @testable import CoreGraphicsTests 8 | @testable import UICoreTests 9 | 10 | XCTMain([ 11 | testCase(AutoLayoutTests.allTests), 12 | testCase(CoreGraphicsTests.allTests), 13 | testCase(UICoreTests.allTests), 14 | ]) 15 | --------------------------------------------------------------------------------