├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── funding.yml
└── workflows
│ └── build.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── Rectangle.xcodeproj
├── project.pbxproj
└── xcshareddata
│ └── xcschemes
│ └── Rectangle.xcscheme
├── Rectangle
├── AccessibilityAuthorization
│ ├── AccessibilityAuthorization.swift
│ └── AccessibilityWindowController.swift
├── AccessibilityElement.swift
├── AppDelegate.swift
├── ApplicationToggle.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── mac016pts1x.png
│ │ ├── mac016pts2x.png
│ │ ├── mac032pts1x.png
│ │ ├── mac032pts2x.png
│ │ ├── mac128pts1x.png
│ │ ├── mac128pts2x.png
│ │ ├── mac256pts1x.png
│ │ ├── mac256pts2x.png
│ │ ├── mac512pts1x.png
│ │ └── mac512pts2x.png
│ ├── Contents.json
│ ├── StatusTemplate.imageset
│ │ ├── Contents.json
│ │ ├── RectangleStatusTemplate.png
│ │ ├── RectangleStatusTemplate22.png
│ │ └── RectangleStatusTemplate44.png
│ ├── Untilted.imageset
│ │ ├── Contents.json
│ │ └── mac256pts1x.png
│ ├── WindowPositions
│ │ ├── Contents.json
│ │ ├── almostMaximizeTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── almostMaximizeTemplate.png
│ │ ├── bottomCenterSixthTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── bottomCenterSixthTemplate.png
│ │ ├── bottomHalfTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── bottomHalfTemplate.png
│ │ ├── bottomLeftSixthTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── bottomLeftSixthTemplate.png
│ │ ├── bottomLeftTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── bottomLeftTemplate.png
│ │ ├── bottomRightSixthTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── bottomRightSixthTemplate.png
│ │ ├── bottomRightTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── bottomRightTemplate.png
│ │ ├── centerLeftFourthTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── centerLeftFourthTemplate.png
│ │ ├── centerRightFourthTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── centerRightFourthTemplate.png
│ │ ├── centerTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── centerTemplate.png
│ │ ├── centerThirdTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── centerThirdTemplate.png
│ │ ├── firstThirdTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── firstThirdTemplate.png
│ │ ├── firstThreeFourthsTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── firstThreeFourthsTemplate.png
│ │ ├── firstTwoThirdsTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── firstTwoThirdsTemplate.png
│ │ ├── halfWidthCenterTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── halfWidthCenterTemplate.png
│ │ ├── lastThirdTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── lastThirdTemplate.png
│ │ ├── lastThreeFourthsTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── lastThreeFourthsTemplate.png
│ │ ├── lastTwoThirdsTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── lastTwoThirdsTemplate.png
│ │ ├── leftFourthTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── leftFourthTemplate.png
│ │ ├── leftHalfTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── leftHalfTemplate.png
│ │ ├── makeLargerTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── makeLargerTemplate.png
│ │ ├── makeSmallerTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── makeSmallerTemplate.png
│ │ ├── maximizeHeightTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── maximizeHeightTemplate.png
│ │ ├── maximizeTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── maximizeTemplate.png
│ │ ├── moveDownTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── moveDownTemplate.png
│ │ ├── moveLeftTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── moveLeftTemplate.png
│ │ ├── moveRightTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── moveRightTemplate.png
│ │ ├── moveUpTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── moveUpTemplate.png
│ │ ├── nextDisplayTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── nextDisplayTemplate.png
│ │ ├── prevDisplayTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── prevDisplayTemplate.png
│ │ ├── restoreTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── restoreTemplate.png
│ │ ├── rightFourthTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── rightFourthTemplate.png
│ │ ├── rightHalfTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── rightHalfTemplate.png
│ │ ├── topCenterSixthTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── topCenterSixthTemplate.png
│ │ ├── topHalfTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── topHalfTemplate.png
│ │ ├── topLeftSixthTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── topLeftSixthTemplate.png
│ │ ├── topLeftTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── topLeftTemplate.png
│ │ ├── topRightSixthTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── topRightSixthTemplate.png
│ │ └── topRightTemplate.imageset
│ │ │ ├── Contents.json
│ │ │ └── topRightTemplate.png
│ ├── keyboardToolbarTemplate.imageset
│ │ ├── Contents.json
│ │ ├── keyboardToolbarTemplate.png
│ │ └── keyboardToolbarTemplateSmall.png
│ ├── snapAreaTemplate.imageset
│ │ ├── Contents.json
│ │ ├── snapAreaTemplate.png
│ │ └── snapAreaTemplateSmall.png
│ ├── square.and.arrow.down.imageset
│ │ ├── Contents.json
│ │ └── square.and.arrow.down.png
│ ├── square.and.arrow.up.imageset
│ │ ├── Contents.json
│ │ └── square.and.arrow.up.png
│ ├── toolbarSettingsTemplate.imageset
│ │ ├── Contents.json
│ │ ├── toolbarSettingsTemplate copy.png
│ │ └── toolbarSettingsTemplate.png
│ ├── wallpaperTiger.imageset
│ │ ├── Contents.json
│ │ └── wallpaperTiger.png
│ └── wallpaperTigerVertical.imageset
│ │ ├── Contents.json
│ │ └── wallpaperTigerVertical.png
├── Base.lproj
│ └── Main.storyboard
├── CycleSize.swift
├── Defaults.swift
├── Info.plist
├── InternetAccessPolicy.plist
├── LaunchOnLogin.swift
├── Logging
│ ├── LogViewer.storyboard
│ └── LogViewer.swift
├── MultiWindow
│ ├── MultiWindowManager.swift
│ └── ReverseAllManager.swift
├── Popover
│ ├── MessageView.swift
│ └── MessageView.xib
├── PrefsWindow
│ ├── Config.swift
│ ├── PrefsViewController.swift
│ ├── SettingsViewController.swift
│ └── SnapAreaViewController.swift
├── Rectangle-Bridging-Header.h
├── Rectangle.entitlements
├── RectangleRelease.entitlements
├── RectangleStatusItem.swift
├── ScreenDetection.swift
├── ShortcutManager.swift
├── Snapping
│ ├── CompoundSnapArea
│ │ ├── CompoundSnapArea.swift
│ │ ├── FourthsCompoundCalculation.swift
│ │ ├── HalvesCompoundCalculation.swift
│ │ ├── SixthsCompoundCalculation.swift
│ │ └── ThirdsCompoundCalculation.swift
│ ├── FootprintWindow.swift
│ ├── SnapAreaModel.swift
│ └── SnappingManager.swift
├── SubsequentExecutionMode.swift
├── TitleBarManager.swift
├── TodoMode
│ └── TodoManager.swift
├── Utilities
│ ├── AXExtension.swift
│ ├── AlertUtil.swift
│ ├── CFExtension.swift
│ ├── CGExtension.swift
│ ├── CUtil.swift
│ ├── Debounce.swift
│ ├── DispatchTimeExtension.swift
│ ├── EventMonitor.swift
│ ├── MASShortcutMigration.swift
│ ├── MacTilingDefaults.swift
│ ├── NSImageExtension.swift
│ ├── NotificationExtension.swift
│ ├── RunLoopThread.swift
│ ├── SequenceExtension.swift
│ ├── StageUtil.swift
│ ├── StringExtension.swift
│ ├── TimeoutCache.swift
│ └── WindowUtil.swift
├── WelcomeWindow
│ └── WelcomeViewController.swift
├── WindowAction.swift
├── WindowActionCategory.swift
├── WindowCalculation
│ ├── AlmostMaximizeCalculation.swift
│ ├── BottomCenterLeftEighthCalculation.swift
│ ├── BottomCenterNinthCalculation.swift
│ ├── BottomCenterRightEighthCalculation.swift
│ ├── BottomCenterSixthCalculation.swift
│ ├── BottomHalfCalculation.swift
│ ├── BottomLeftEighthCalculation.swift
│ ├── BottomLeftNinthCalculation.swift
│ ├── BottomLeftSixthCalculation.swift
│ ├── BottomLeftThirdCalculation.swift
│ ├── BottomRightEighthCalculation.swift
│ ├── BottomRightNinthCalculation.swift
│ ├── BottomRightSixthCalculation.swift
│ ├── BottomRightThirdCalculation.swift
│ ├── CenterCalculation.swift
│ ├── CenterHalfCalculation.swift
│ ├── CenterProminentlyCalculation.swift
│ ├── CenterThirdCalculation.swift
│ ├── ChangeSizeCalculation.swift
│ ├── ChangeWindowDimensionCalculation.swift
│ ├── EighthsRepeated.swift
│ ├── FirstFourthCalculation.swift
│ ├── FirstThirdCalculation.swift
│ ├── FirstThreeFourthsCalculation.swift
│ ├── FirstTwoThirdsCalculation.swift
│ ├── GapCalculation.swift
│ ├── HalfOrDoubleDimensionCalculation.swift
│ ├── HorizontalThirdsRepeated.swift
│ ├── LastFourthCalculation.swift
│ ├── LastThirdCalculation.swift
│ ├── LastThreeFourthsCalculation.swift
│ ├── LastTwoThirdsCalculation.swift
│ ├── LeftRightHalfCalculation.swift
│ ├── LeftTodoCalculation.swift
│ ├── LowerLeftCalculation.swift
│ ├── LowerRightCalculation.swift
│ ├── MaximizeCalculation.swift
│ ├── MaximizeHeightCalculation.swift
│ ├── MiddleCenterNinthCalculation.swift
│ ├── MiddleLeftNinthCalculation.swift
│ ├── MiddleRightNinthCalculation.swift
│ ├── MoveLeftRightCalculation.swift
│ ├── MoveUpDownCalculation.swift
│ ├── NextPrevDisplayCalculation.swift
│ ├── NinthsRepeated.swift
│ ├── OrientationAware.swift
│ ├── RepeatedExecutionsCalculation.swift
│ ├── RepeatedExecutionsInThirdsCalculation.swift
│ ├── RightTodoCalculation.swift
│ ├── SecondFourthCalculation.swift
│ ├── SixthsRepeated.swift
│ ├── SpecifiedCalculation.swift
│ ├── ThirdFourthCalculation.swift
│ ├── TopCenterLeftEighthCalculation.swift
│ ├── TopCenterNinthCalculation.swift
│ ├── TopCenterRightEighthCalculation.swift
│ ├── TopCenterSixthCalculation.swift
│ ├── TopHalfCalculation.swift
│ ├── TopLeftEighthCalculation.swift
│ ├── TopLeftNinthCalculation.swift
│ ├── TopLeftSixthCalculation.swift
│ ├── TopLeftThirdCalculation.swift
│ ├── TopRightEighthCalculation.swift
│ ├── TopRightNinthCalculation.swift
│ ├── TopRightSixthCalculation.swift
│ ├── TopRightThirdCalculation.swift
│ ├── UpperLeftCalculation.swift
│ ├── UpperRightCalculation.swift
│ └── WindowCalculation.swift
├── WindowHistory.swift
├── WindowManager.swift
├── WindowMover
│ ├── BestEffortWindowMover.swift
│ ├── CenteringFixedSizedWindowMover.swift
│ ├── QuantizedWindowMover.swift
│ ├── StandardWindowMover.swift
│ └── WindowMover.swift
└── mul.lproj
│ └── Main.xcstrings
├── RectangleLauncher
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── Base.lproj
│ └── Main.storyboard
├── Info.plist
├── RectangleLauncher.entitlements
├── RectangleLauncherRelease.entitlements
└── mul.lproj
│ └── Main.xcstrings
├── RectangleTests
├── Info.plist
└── RectangleTests.swift
└── TerminalCommands.md
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: 'bug'
6 | assignees: ''
7 |
8 | ---
9 |
10 | - [ ] This is a new bug that hasn't been documented in a closed issue or in the Readme.
11 |
12 | macOS version:
13 | Rectangle version:
14 | Logs if applicable (In Rectangle menu, hold option, "View Logging..."):
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature idea
3 | about: Please use the Discussions tab to share a feature idea ⬆️
4 | title: ''
5 | labels: 'enhancement'
6 | assignees: ''
7 | contact_links:
8 | - name: Rectangle Discussions
9 | url: https://github.com/rxhanson/Rectangle/discussions
10 | about: Please discuss feature ideas here.
11 | ---
12 |
13 | Feature ideas are now kept in the [discussions tab](https://github.com/rxhanson/Rectangle/discussions). Please create an issue there, not here.
14 |
--------------------------------------------------------------------------------
/.github/funding.yml:
--------------------------------------------------------------------------------
1 | github: rxhanson
2 | custom: https://rectangleapp.com
3 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on: [push, pull_request]
4 |
5 | permissions: read-all
6 |
7 | env:
8 | XCODE_PROJECT: "Rectangle.xcodeproj"
9 | XCODE_SCHEME: "Rectangle"
10 | CODE_SIGN_IDENTITY: "-"
11 | BUILD_DIR: "build"
12 | XCODE_ARCHIVE: "Rectangle.xcarchive"
13 | APP_NAME: "Rectangle.app"
14 | EXPORT_OPTIONS_PLIST: "exportOptions.plist"
15 | DMG_NAME: "Rectangle"
16 | DMG_FILE_NAME: "Rectangle.dmg"
17 |
18 | jobs:
19 | build:
20 | runs-on: macos-latest
21 | steps:
22 | - name: Checkout
23 | uses: actions/checkout@v4
24 | - name: Build
25 | run: xcodebuild -project "$XCODE_PROJECT" -scheme "$XCODE_SCHEME" archive CODE_SIGN_IDENTITY="$CODE_SIGN_IDENTITY" -archivePath "$BUILD_DIR/$XCODE_ARCHIVE"
26 | - name: Export
27 | run: |
28 | plutil -convert xml1 - -o "$EXPORT_OPTIONS_PLIST" << EOF
29 | {
30 | "destination": "export",
31 | "method": "mac-application"
32 | }
33 | EOF
34 |
35 | xcodebuild -exportArchive -archivePath "$BUILD_DIR/$XCODE_ARCHIVE" -exportPath "$BUILD_DIR" -exportOptionsPlist "$EXPORT_OPTIONS_PLIST"
36 | - name: Resign App
37 | run: codesign --force --deep -s "$CODE_SIGN_IDENTITY" "$BUILD_DIR/$APP_NAME"
38 | - name: Make DMG
39 | run: hdiutil create -srcdir "$BUILD_DIR" -volname "$DMG_NAME" "$DMG_FILE_NAME"
40 | - name: Upload
41 | uses: actions/upload-artifact@v4
42 | with:
43 | name: Build
44 | path: ${{ env.DMG_FILE_NAME }}
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | **/.DS_Store
3 | */xcuserdata/
4 | xcuserdata/
5 | **.xcuserstate
6 | *.xcworkspace
7 | Pods
8 |
9 | ## Xcode per-user config
10 | *.mode1
11 | *.mode1v3
12 | *.mode2v3
13 | *.perspective
14 | *.perspectivev3
15 | *.pbxuser
16 |
17 | ## Xcode Patch
18 | *.xcodeproj/*
19 | !*.xcodeproj/project.pbxproj
20 | !*.xcodeproj/xcshareddata/
21 | !*.xcworkspace/contents.xcworkspacedata
22 | /*.gcno
23 |
24 | ## Build products
25 | build/
26 | *.o
27 | *.LinkFileList
28 | *.hmap
29 |
30 | ## Automatic backup files
31 | *~.nib/
32 | *.swp
33 | *~
34 | *.dat
35 | *.dep
36 |
37 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Feature Requests
4 |
5 | Rectangle is not accepting any new feature requests at this time, sorry. You can file a feature request for a feature that you plan to implement and submit a pull request for, so that the feature can be reviewed and you will know ahead of time if the feature will be rejected.
6 |
7 | ## Bugs
8 |
9 | Please search through the existing issues, open and closed, before filing a new bug.
10 | Add the version of Rectangle, the version of the OS, and screenshots or videos as necessary.
11 |
12 | ## Coding Style
13 |
14 | Please match the existing coding style as much as possible.
15 |
16 | ## License
17 |
18 | By contributing to Rectangle you agree that your contributions will be licensed under its MIT license.
19 |
20 | ## Incentives
21 |
22 | Logic from Rectangle is used in the [Multitouch](https://multitouch.app) app. The [Rectangle Pro](https://rectangleapp.com/pro) app is entirely built on top of Rectangle. If you contribute significant code or localizations that get merged into Rectangle, you get a free license of Multitouch or Rectangle Pro. Contributors to Sparkle, MASShortcut, or Spectacle can also receive free Multitouch or Rectangle Pro licenses (just send me a direct message on [Gitter](https://gitter.im)).
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019-2025 Ryan Hanson
4 | Based on the Spectacle app, Copyright (c) 2017 Eric Czarny eczarny@gmail.com
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/Rectangle/AccessibilityAuthorization/AccessibilityAuthorization.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AccessibilityAuthorization.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 6/11/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Cocoa
11 |
12 | class AccessibilityAuthorization {
13 |
14 | private var accessibilityWindowController: NSWindowController?
15 |
16 | public func checkAccessibility(completion: @escaping () -> Void) -> Bool {
17 | if !AXIsProcessTrusted() {
18 |
19 | accessibilityWindowController = NSStoryboard(name: "Main", bundle: nil).instantiateController(withIdentifier: "AccessibilityWindowController") as? NSWindowController
20 |
21 | NSApp.activate(ignoringOtherApps: true)
22 | accessibilityWindowController?.showWindow(self)
23 | pollAccessibility(completion: completion)
24 | return false
25 | } else {
26 | return true
27 | }
28 | }
29 |
30 | private func pollAccessibility(completion: @escaping () -> Void) {
31 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
32 | if AXIsProcessTrusted() {
33 | self.accessibilityWindowController?.close()
34 | self.accessibilityWindowController = nil
35 | completion()
36 | } else {
37 | self.pollAccessibility(completion: completion)
38 | }
39 | }
40 | }
41 |
42 | func showAuthorizationWindow() {
43 | if accessibilityWindowController?.window?.isMiniaturized == true {
44 | accessibilityWindowController?.window?.deminiaturize(self)
45 | }
46 | NSApp.activate(ignoringOtherApps: true)
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/Rectangle/AccessibilityAuthorization/AccessibilityWindowController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AccessibilityWindow.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 6/13/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class AccessibilityWindowController: NSWindowController {
12 |
13 | override func windowDidLoad() {
14 | super.windowDidLoad()
15 | let closeButton = self.window?.standardWindowButton(.closeButton)
16 | closeButton?.target = self
17 | closeButton?.action = #selector(quit)
18 | }
19 |
20 | @objc func quit() {
21 | exit(1)
22 | }
23 |
24 | }
25 |
26 | class AccessibilityViewController: NSViewController {
27 |
28 | @IBOutlet weak var sysPrefsPathField: NSTextField!
29 | @IBOutlet weak var openSysPrefsButton: NSButton!
30 | @IBOutlet weak var padlockField: NSTextField!
31 |
32 | override func viewDidLoad() {
33 | if #available(OSX 13, *) {
34 | sysPrefsPathField.stringValue = NSLocalizedString(
35 | "Go to System Settings → Privacy & Security → Accessibility", tableName: "Main", value: "", comment: "")
36 | openSysPrefsButton.title = NSLocalizedString(
37 | "Open System Settings", tableName: "Main", value: "", comment: "")
38 | padlockField.isHidden = true
39 | }
40 | }
41 |
42 | @IBAction func openSystemPrefs(_ sender: Any) {
43 | NSWorkspace.shared.open(URL(string:"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility")!)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "mac016pts1x.png",
5 | "idiom" : "mac",
6 | "scale" : "1x",
7 | "size" : "16x16"
8 | },
9 | {
10 | "filename" : "mac016pts2x.png",
11 | "idiom" : "mac",
12 | "scale" : "2x",
13 | "size" : "16x16"
14 | },
15 | {
16 | "filename" : "mac032pts1x.png",
17 | "idiom" : "mac",
18 | "scale" : "1x",
19 | "size" : "32x32"
20 | },
21 | {
22 | "filename" : "mac032pts2x.png",
23 | "idiom" : "mac",
24 | "scale" : "2x",
25 | "size" : "32x32"
26 | },
27 | {
28 | "filename" : "mac128pts1x.png",
29 | "idiom" : "mac",
30 | "scale" : "1x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "filename" : "mac128pts2x.png",
35 | "idiom" : "mac",
36 | "scale" : "2x",
37 | "size" : "128x128"
38 | },
39 | {
40 | "filename" : "mac256pts1x.png",
41 | "idiom" : "mac",
42 | "scale" : "1x",
43 | "size" : "256x256"
44 | },
45 | {
46 | "filename" : "mac256pts2x.png",
47 | "idiom" : "mac",
48 | "scale" : "2x",
49 | "size" : "256x256"
50 | },
51 | {
52 | "filename" : "mac512pts1x.png",
53 | "idiom" : "mac",
54 | "scale" : "1x",
55 | "size" : "512x512"
56 | },
57 | {
58 | "filename" : "mac512pts2x.png",
59 | "idiom" : "mac",
60 | "scale" : "2x",
61 | "size" : "512x512"
62 | }
63 | ],
64 | "info" : {
65 | "author" : "xcode",
66 | "version" : 1
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/AppIcon.appiconset/mac016pts1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/AppIcon.appiconset/mac016pts1x.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/AppIcon.appiconset/mac016pts2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/AppIcon.appiconset/mac016pts2x.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/AppIcon.appiconset/mac032pts1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/AppIcon.appiconset/mac032pts1x.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/AppIcon.appiconset/mac032pts2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/AppIcon.appiconset/mac032pts2x.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/AppIcon.appiconset/mac128pts1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/AppIcon.appiconset/mac128pts1x.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/AppIcon.appiconset/mac128pts2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/AppIcon.appiconset/mac128pts2x.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/AppIcon.appiconset/mac256pts1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/AppIcon.appiconset/mac256pts1x.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/AppIcon.appiconset/mac256pts2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/AppIcon.appiconset/mac256pts2x.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/AppIcon.appiconset/mac512pts1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/AppIcon.appiconset/mac512pts1x.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/AppIcon.appiconset/mac512pts2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/AppIcon.appiconset/mac512pts2x.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/StatusTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "RectangleStatusTemplate22.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "RectangleStatusTemplate44.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "RectangleStatusTemplate.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/StatusTemplate.imageset/RectangleStatusTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/StatusTemplate.imageset/RectangleStatusTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/StatusTemplate.imageset/RectangleStatusTemplate22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/StatusTemplate.imageset/RectangleStatusTemplate22.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/StatusTemplate.imageset/RectangleStatusTemplate44.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/StatusTemplate.imageset/RectangleStatusTemplate44.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/Untilted.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "mac256pts1x.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/Untilted.imageset/mac256pts1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/Untilted.imageset/mac256pts1x.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/almostMaximizeTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "almostMaximizeTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/almostMaximizeTemplate.imageset/almostMaximizeTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/almostMaximizeTemplate.imageset/almostMaximizeTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomCenterSixthTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "bottomCenterSixthTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomCenterSixthTemplate.imageset/bottomCenterSixthTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/bottomCenterSixthTemplate.imageset/bottomCenterSixthTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomHalfTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bottomHalfTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomHalfTemplate.imageset/bottomHalfTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/bottomHalfTemplate.imageset/bottomHalfTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomLeftSixthTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "bottomLeftSixthTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomLeftSixthTemplate.imageset/bottomLeftSixthTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/bottomLeftSixthTemplate.imageset/bottomLeftSixthTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomLeftTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bottomLeftTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomLeftTemplate.imageset/bottomLeftTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/bottomLeftTemplate.imageset/bottomLeftTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomRightSixthTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "bottomRightSixthTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomRightSixthTemplate.imageset/bottomRightSixthTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/bottomRightSixthTemplate.imageset/bottomRightSixthTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomRightTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "bottomRightTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/bottomRightTemplate.imageset/bottomRightTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/bottomRightTemplate.imageset/bottomRightTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/centerLeftFourthTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "centerLeftFourthTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/centerLeftFourthTemplate.imageset/centerLeftFourthTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/centerLeftFourthTemplate.imageset/centerLeftFourthTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/centerRightFourthTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "centerRightFourthTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/centerRightFourthTemplate.imageset/centerRightFourthTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/centerRightFourthTemplate.imageset/centerRightFourthTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/centerTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "centerTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/centerTemplate.imageset/centerTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/centerTemplate.imageset/centerTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/centerThirdTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "centerThirdTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/centerThirdTemplate.imageset/centerThirdTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/centerThirdTemplate.imageset/centerThirdTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/firstThirdTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "firstThirdTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/firstThirdTemplate.imageset/firstThirdTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/firstThirdTemplate.imageset/firstThirdTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/firstThreeFourthsTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "firstThreeFourthsTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/firstThreeFourthsTemplate.imageset/firstThreeFourthsTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/firstThreeFourthsTemplate.imageset/firstThreeFourthsTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/firstTwoThirdsTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "firstTwoThirdsTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/firstTwoThirdsTemplate.imageset/firstTwoThirdsTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/firstTwoThirdsTemplate.imageset/firstTwoThirdsTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/halfWidthCenterTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "halfWidthCenterTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/halfWidthCenterTemplate.imageset/halfWidthCenterTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/halfWidthCenterTemplate.imageset/halfWidthCenterTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/lastThirdTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "lastThirdTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/lastThirdTemplate.imageset/lastThirdTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/lastThirdTemplate.imageset/lastThirdTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/lastThreeFourthsTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "lastThreeFourthsTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/lastThreeFourthsTemplate.imageset/lastThreeFourthsTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/lastThreeFourthsTemplate.imageset/lastThreeFourthsTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/lastTwoThirdsTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "lastTwoThirdsTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/lastTwoThirdsTemplate.imageset/lastTwoThirdsTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/lastTwoThirdsTemplate.imageset/lastTwoThirdsTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/leftFourthTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "leftFourthTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/leftFourthTemplate.imageset/leftFourthTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/leftFourthTemplate.imageset/leftFourthTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/leftHalfTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "leftHalfTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/leftHalfTemplate.imageset/leftHalfTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/leftHalfTemplate.imageset/leftHalfTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/makeLargerTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "makeLargerTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/makeLargerTemplate.imageset/makeLargerTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/makeLargerTemplate.imageset/makeLargerTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/makeSmallerTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "makeSmallerTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/makeSmallerTemplate.imageset/makeSmallerTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/makeSmallerTemplate.imageset/makeSmallerTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/maximizeHeightTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "maximizeHeightTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/maximizeHeightTemplate.imageset/maximizeHeightTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/maximizeHeightTemplate.imageset/maximizeHeightTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/maximizeTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "maximizeTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/maximizeTemplate.imageset/maximizeTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/maximizeTemplate.imageset/maximizeTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/moveDownTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "moveDownTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/moveDownTemplate.imageset/moveDownTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/moveDownTemplate.imageset/moveDownTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/moveLeftTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "moveLeftTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/moveLeftTemplate.imageset/moveLeftTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/moveLeftTemplate.imageset/moveLeftTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/moveRightTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "moveRightTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/moveRightTemplate.imageset/moveRightTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/moveRightTemplate.imageset/moveRightTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/moveUpTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "moveUpTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/moveUpTemplate.imageset/moveUpTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/moveUpTemplate.imageset/moveUpTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/nextDisplayTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "nextDisplayTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/nextDisplayTemplate.imageset/nextDisplayTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/nextDisplayTemplate.imageset/nextDisplayTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/prevDisplayTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "prevDisplayTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/prevDisplayTemplate.imageset/prevDisplayTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/prevDisplayTemplate.imageset/prevDisplayTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/restoreTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "restoreTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/restoreTemplate.imageset/restoreTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/restoreTemplate.imageset/restoreTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/rightFourthTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "rightFourthTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/rightFourthTemplate.imageset/rightFourthTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/rightFourthTemplate.imageset/rightFourthTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/rightHalfTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "rightHalfTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/rightHalfTemplate.imageset/rightHalfTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/rightHalfTemplate.imageset/rightHalfTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topCenterSixthTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "topCenterSixthTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topCenterSixthTemplate.imageset/topCenterSixthTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/topCenterSixthTemplate.imageset/topCenterSixthTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topHalfTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "topHalfTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topHalfTemplate.imageset/topHalfTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/topHalfTemplate.imageset/topHalfTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topLeftSixthTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "topLeftSixthTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topLeftSixthTemplate.imageset/topLeftSixthTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/topLeftSixthTemplate.imageset/topLeftSixthTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topLeftTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "topLeftTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topLeftTemplate.imageset/topLeftTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/topLeftTemplate.imageset/topLeftTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topRightSixthTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "topRightSixthTemplate.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topRightSixthTemplate.imageset/topRightSixthTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/topRightSixthTemplate.imageset/topRightSixthTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topRightTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "topRightTemplate.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/WindowPositions/topRightTemplate.imageset/topRightTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/WindowPositions/topRightTemplate.imageset/topRightTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/keyboardToolbarTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "keyboardToolbarTemplateSmall.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "keyboardToolbarTemplate.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/keyboardToolbarTemplate.imageset/keyboardToolbarTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/keyboardToolbarTemplate.imageset/keyboardToolbarTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/keyboardToolbarTemplate.imageset/keyboardToolbarTemplateSmall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/keyboardToolbarTemplate.imageset/keyboardToolbarTemplateSmall.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/snapAreaTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "snapAreaTemplateSmall.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "snapAreaTemplate.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/snapAreaTemplate.imageset/snapAreaTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/snapAreaTemplate.imageset/snapAreaTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/snapAreaTemplate.imageset/snapAreaTemplateSmall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/snapAreaTemplate.imageset/snapAreaTemplateSmall.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/square.and.arrow.down.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "square.and.arrow.down.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "template"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/square.and.arrow.down.imageset/square.and.arrow.down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/square.and.arrow.down.imageset/square.and.arrow.down.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/square.and.arrow.up.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "square.and.arrow.up.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | },
21 | "properties" : {
22 | "template-rendering-intent" : "template"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/square.and.arrow.up.imageset/square.and.arrow.up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/square.and.arrow.up.imageset/square.and.arrow.up.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/toolbarSettingsTemplate.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "toolbarSettingsTemplate copy.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "toolbarSettingsTemplate.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/toolbarSettingsTemplate.imageset/toolbarSettingsTemplate copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/toolbarSettingsTemplate.imageset/toolbarSettingsTemplate copy.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/toolbarSettingsTemplate.imageset/toolbarSettingsTemplate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/toolbarSettingsTemplate.imageset/toolbarSettingsTemplate.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/wallpaperTiger.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "wallpaperTiger.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/wallpaperTiger.imageset/wallpaperTiger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/wallpaperTiger.imageset/wallpaperTiger.png
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/wallpaperTigerVertical.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "wallpaperTigerVertical.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Rectangle/Assets.xcassets/wallpaperTigerVertical.imageset/wallpaperTigerVertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rxhanson/Rectangle/3f65edde130b13dfa267493ff2e9e9d873e8f9b5/Rectangle/Assets.xcassets/wallpaperTigerVertical.imageset/wallpaperTigerVertical.png
--------------------------------------------------------------------------------
/Rectangle/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(MARKETING_VERSION)
21 | CFBundleURLTypes
22 |
23 |
24 | CFBundleURLSchemes
25 |
26 | rectangle
27 |
28 |
29 |
30 | CFBundleVersion
31 | $(CURRENT_PROJECT_VERSION)
32 | LSApplicationCategoryType
33 | public.app-category.productivity
34 | LSMinimumSystemVersion
35 | $(MACOSX_DEPLOYMENT_TARGET)
36 | LSUIElement
37 |
38 | NSHumanReadableCopyright
39 | Copyright © 2019-2025 Ryan Hanson. All rights reserved.
40 | NSMainStoryboardFile
41 | Main
42 | NSPrincipalClass
43 | NSApplication
44 | SUFeedURL
45 | https://rectangleapp.com/downloads/updates.xml
46 | SUPublicEDKey
47 | lpt9M3PhocbZ3MZiLH+crEqRfU11kfoNzGxSqiEIdvM=
48 | SUScheduledCheckInterval
49 | 172800
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Rectangle/InternetAccessPolicy.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ApplicationDescription
6 | Rectangle is the gold standard for window management on macOS. Free and open source.
7 | Connections
8 |
9 |
10 | IsIncoming
11 |
12 | Host
13 | rectangleapp.com
14 | NetworkProtocol
15 | TCP
16 | Port
17 | 443
18 | Purpose
19 | Rectangle checks for new versions
20 | DenyConsequences
21 | If you deny this connection, you will not be notified about new versions.
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Rectangle/LaunchOnLogin.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LaunchOnLogin.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 2/20/23.
6 | // Copyright © 2023 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ServiceManagement
11 | import os.log
12 |
13 | @available(macOS 13.0, *)
14 | public enum LaunchOnLogin {
15 | public static var isEnabled: Bool {
16 | get { SMAppService.mainApp.status == .enabled }
17 | set {
18 | do {
19 | if newValue {
20 | if SMAppService.mainApp.status == .enabled {
21 | try? SMAppService.mainApp.unregister()
22 | }
23 |
24 | try SMAppService.mainApp.register()
25 | } else {
26 | try SMAppService.mainApp.unregister()
27 | }
28 | } catch {
29 | os_log("Failed to \(newValue ? "enable" : "disable") launch at login: \(error.localizedDescription)")
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Rectangle/MultiWindow/ReverseAllManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TodoManager.swift
3 | // Rectangle
4 | //
5 | // Created by Charlie Harding on 7/25/21.
6 | // Copyright © 2021 Ryan Hanson. All rights reserved.
7 | //
8 | import Cocoa
9 | import MASShortcut
10 |
11 | class ReverseAllManager {
12 |
13 | static func reverseAll(windowElement: AccessibilityElement? = nil) {
14 | let sd = ScreenDetection()
15 |
16 | let currentWindow = windowElement ?? AccessibilityElement.getFrontWindowElement()
17 | guard let currentScreen = sd.detectScreens(using: currentWindow)?.currentScreen else { return }
18 |
19 | let windows = AccessibilityElement.getAllWindowElements()
20 |
21 | let screenFrame = currentScreen.adjustedVisibleFrame()
22 |
23 | for w in windows {
24 | let wScreen = sd.detectScreens(using: w)?.currentScreen
25 | if Defaults.todo.userEnabled && TodoManager.isTodoWindow(w) { continue }
26 | if wScreen == currentScreen {
27 | reverseWindowPosition(w, screenFrame: screenFrame)
28 | }
29 | }
30 | }
31 |
32 | private static func reverseWindowPosition(_ w: AccessibilityElement, screenFrame: CGRect) {
33 | var rect = w.frame
34 |
35 | let offsetFromLeft = rect.minX - screenFrame.minX
36 |
37 | rect.origin.x = screenFrame.maxX - offsetFromLeft - rect.width
38 |
39 | w.setFrame(rect)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Rectangle/Popover/MessageView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MessageView.swift
3 | // Multitouch
4 | //
5 | // Created by Ryan Hanson on 9/10/17.
6 | // Copyright © 2017-2018 BrassMonkery, LLC. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class MessagePopover {
12 |
13 | var messageView: MessageView
14 | var popover: NSPopover
15 |
16 | init() {
17 | popover = NSPopover()
18 | messageView = MessageView()
19 | popover.behavior = .transient
20 | popover.contentViewController = messageView
21 | }
22 |
23 | public func show(message: String, sender: NSView) {
24 | let positioningView = sender
25 | let positioningRect = NSZeroRect
26 | let preferredEdge: NSRectEdge = .maxX
27 | messageView.message = message
28 |
29 | popover.show(relativeTo: positioningRect, of: positioningView, preferredEdge: preferredEdge)
30 | }
31 | }
32 |
33 | class MessageView: NSViewController {
34 |
35 | @IBOutlet weak var messageField: NSTextField!
36 |
37 | var message: String?
38 |
39 | override func viewWillAppear() {
40 | super.viewWillAppear()
41 | if let message = message {
42 | self.messageField?.stringValue = message
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Rectangle/Rectangle-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 | #import
6 |
7 | AXError _AXUIElementGetWindow(AXUIElementRef element, uint32_t *identifier);
8 |
--------------------------------------------------------------------------------
/Rectangle/Rectangle.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Rectangle/RectangleRelease.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Rectangle/RectangleStatusItem.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RectangleStatusItem.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 6/11/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class RectangleStatusItem {
12 | static let instance = RectangleStatusItem()
13 |
14 | private var nsStatusItem: NSStatusItem?
15 | private var added: Bool = false
16 | public var statusMenu: NSMenu? {
17 | didSet {
18 | nsStatusItem?.menu = statusMenu
19 | }
20 | }
21 | private var isVisibleObserver: NSKeyValueObservation?
22 |
23 | private init() {}
24 |
25 | public func refreshVisibility() {
26 | if Defaults.hideMenuBarIcon.enabled {
27 | remove()
28 | } else {
29 | add()
30 | }
31 | }
32 |
33 | public func openMenu() {
34 | if !added {
35 | add()
36 | }
37 | nsStatusItem?.button?.performClick(self)
38 | refreshVisibility()
39 | }
40 |
41 | private func add() {
42 | added = true
43 | nsStatusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
44 | nsStatusItem?.menu = self.statusMenu
45 | nsStatusItem?.button?.image = NSImage(named: "StatusTemplate")
46 | nsStatusItem?.behavior = .removalAllowed
47 | isVisibleObserver = nsStatusItem?.observe(\.isVisible, options: [.old, .new]) { nsStatusItem, change in
48 | if change.oldValue == true && change.newValue == false {
49 | Notification.Name.menuBarIconHidden.post()
50 | Defaults.hideMenuBarIcon.enabled = true
51 | }
52 | }
53 | nsStatusItem?.isVisible = true
54 | }
55 |
56 | private func remove() {
57 | added = false
58 | guard let nsStatusItem = nsStatusItem else { return }
59 | NSStatusBar.system.removeStatusItem(nsStatusItem)
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/Rectangle/Snapping/CompoundSnapArea/FourthsCompoundCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FourthsCompoundCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 8/24/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct FourthsColumnCompoundCalculation: CompoundSnapAreaCalculation {
12 |
13 | func snapArea(cursorLocation loc: NSPoint, screen: NSScreen, directional: Directional, priorSnapArea: SnapArea?) -> SnapArea? {
14 | let frame = screen.frame
15 | let quarterWidth = floor(frame.width / 4)
16 |
17 | // check first quarter column
18 | if loc.x <= frame.minX + quarterWidth {
19 | return SnapArea(screen: screen, directional: directional, action: .firstFourth)
20 | }
21 |
22 | // check second quarter column
23 | if loc.x >= frame.minX + quarterWidth && loc.x <= frame.maxX - quarterWidth*2 {
24 | if let priorAction = priorSnapArea?.action {
25 | if priorAction == .firstFourth || priorAction == .firstThreeFourths {
26 | return SnapArea(screen: screen, directional: directional, action: .firstThreeFourths)
27 | }
28 | if priorAction == .thirdFourth || priorAction == .lastThreeFourths || priorAction == .centerHalf {
29 | return SnapArea(screen: screen, directional: directional, action: .centerHalf)
30 | }
31 | }
32 | return SnapArea(screen: screen, directional: directional, action: .secondFourth)
33 | }
34 |
35 | // check third quarter column
36 | if loc.x >= frame.minX + quarterWidth * 2 && loc.x <= frame.maxX - quarterWidth {
37 | if let priorAction = priorSnapArea?.action {
38 | if priorAction == .lastFourth || priorAction == .lastThreeFourths {
39 | return SnapArea(screen: screen, directional: directional, action: .lastThreeFourths)
40 | }
41 | if priorAction == .secondFourth || priorAction == .firstThreeFourths || priorAction == .centerHalf {
42 | return SnapArea(screen: screen, directional: directional, action: .centerHalf)
43 | }
44 | }
45 | return SnapArea(screen: screen, directional: directional, action: .thirdFourth)
46 | }
47 |
48 | // check fourth quarter column
49 | if loc.x >= frame.minX + quarterWidth * 2 {
50 | return SnapArea(screen: screen, directional: directional, action: .lastFourth)
51 | }
52 |
53 | return nil
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Rectangle/SubsequentExecutionMode.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SubsequentExecutionMode.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 8/15/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum SubsequentExecutionMode: Int {
12 | case resize = 0 // based on Spectacle
13 | case acrossMonitor = 1
14 | case none = 2
15 | case acrossAndResize = 3 // across monitor for right/left, spectacle resize for all else
16 | case cycleMonitor = 4
17 | }
18 |
19 | class SubsequentExecutionDefault: Default {
20 | public private(set) var key: String = "subsequentExecutionMode"
21 | private var initialized = false
22 |
23 | var value: SubsequentExecutionMode {
24 | didSet {
25 | if initialized {
26 | UserDefaults.standard.set(value.rawValue, forKey: key)
27 | }
28 | }
29 | }
30 |
31 | init() {
32 | let intValue = UserDefaults.standard.integer(forKey: key)
33 | value = SubsequentExecutionMode(rawValue: intValue) ?? .resize
34 | initialized = true
35 | }
36 |
37 | var resizes: Bool {
38 | switch value {
39 | case .resize, .acrossAndResize: return true
40 | default: return false
41 | }
42 | }
43 |
44 | var traversesDisplays: Bool {
45 | switch value {
46 | case .acrossMonitor, .acrossAndResize: return true
47 | default: return false
48 | }
49 | }
50 |
51 | func load(from codable: CodableDefault) {
52 | if let int = codable.int,
53 | let mode = SubsequentExecutionMode(rawValue: int) {
54 | value = mode
55 | }
56 | }
57 |
58 | func toCodable() -> CodableDefault {
59 | return CodableDefault(int: value.rawValue)
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/AlertUtil.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlertUtil.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 4/26/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class AlertUtil {
12 |
13 | static func oneButtonAlert(question: String, text: String, confirmText: String = "OK") {
14 | let alert = NSAlert()
15 | alert.messageText = question
16 | alert.informativeText = text
17 | alert.alertStyle = .warning
18 | alert.addButton(withTitle: confirmText)
19 | alert.runModal()
20 | }
21 |
22 | static func twoButtonAlert(question: String, text: String, confirmText: String = "OK", cancelText: String = "Cancel") -> NSApplication.ModalResponse {
23 | let alert = NSAlert()
24 | alert.messageText = question
25 | alert.informativeText = text
26 | alert.alertStyle = .warning
27 | alert.addButton(withTitle: confirmText)
28 | alert.addButton(withTitle: cancelText)
29 | return alert.runModal()
30 | }
31 |
32 | static func threeButtonAlert(question: String, text: String, buttonOneText: String, buttonTwoText: String, buttonThreeText: String) -> NSApplication.ModalResponse {
33 | let alert = NSAlert()
34 | alert.messageText = question
35 | alert.informativeText = text
36 | alert.alertStyle = .warning
37 | alert.addButton(withTitle: buttonOneText)
38 | alert.addButton(withTitle: buttonTwoText)
39 | alert.addButton(withTitle: buttonThreeText)
40 | return alert.runModal()
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/CFExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CFExtension.swift
3 | // Rectangle
4 | //
5 | // Copyright © 2022 Ryan Hanson. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | extension CFArray {
11 | func getValue(_ index: CFIndex) -> T {
12 | return unsafeBitCast(CFArrayGetValueAtIndex(self, index), to: T.self)
13 | }
14 |
15 | func getCount() -> CFIndex {
16 | return CFArrayGetCount(self)
17 | }
18 | }
19 |
20 | extension CFDictionary {
21 | func getValue(_ key: CFString) -> T {
22 | return unsafeBitCast(CFDictionaryGetValue(self, unsafeBitCast(key, to: UnsafeRawPointer.self)), to: T.self)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/CGExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CGExtension.swift
3 | // Rectangle
4 | //
5 | // Copyright © 2022 Ryan Hanson. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | extension CGPoint {
11 | var screenFlipped: CGPoint {
12 | .init(x: x, y: NSScreen.screens[0].frame.maxY - y)
13 | }
14 | }
15 |
16 | extension CGRect {
17 | var screenFlipped: CGRect {
18 | guard !isNull else {
19 | return self
20 | }
21 | return .init(origin: .init(x: origin.x, y: NSScreen.screens[0].frame.maxY - maxY), size: size)
22 | }
23 |
24 | var isLandscape: Bool { width > height }
25 |
26 | var centerPoint: CGPoint {
27 | NSMakePoint(NSMidX(self), NSMidY(self))
28 | }
29 |
30 | func numSharedEdges(withRect rect: CGRect) -> Int {
31 | var sharedEdgeCount = 0
32 | if minX == rect.minX { sharedEdgeCount += 1 }
33 | if maxX == rect.maxX { sharedEdgeCount += 1 }
34 | if minY == rect.minY { sharedEdgeCount += 1 }
35 | if maxY == rect.maxY { sharedEdgeCount += 1 }
36 | return sharedEdgeCount
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/CUtil.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CUtil.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 6/12/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class CUtil {
12 |
13 | // bridge object into a pointer to pass into C function
14 | static func bridge(obj : T) -> UnsafeMutableRawPointer {
15 | return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
16 | }
17 |
18 | // bridge pointer back into an object within C function
19 | static func bridge(ptr : UnsafeMutableRawPointer) -> T {
20 | return Unmanaged.fromOpaque(ptr).takeUnretainedValue()
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/Debounce.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Debounce.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 10/7/21.
6 | // Copyright © 2021 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Dispatch
11 |
12 | class Debounce {
13 |
14 | private init() {}
15 |
16 | static func input(_ input: T,
17 | comparedAgainst current: @escaping @autoclosure () -> (T),
18 | perform: @escaping (T) -> ()) {
19 |
20 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
21 | if input == current() { perform(input) }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/DispatchTimeExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DispatchTimeExtension.swift
3 | // Rectangle
4 | //
5 | // Copyright © 2022 Ryan Hanson. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | extension DispatchTime {
11 | var uptimeMilliseconds: UInt64 { uptimeNanoseconds / 1_000_000 }
12 | }
13 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/MASShortcutMigration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MASShortcutMigration.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 12/22/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import MASShortcut
11 |
12 | class MASShortcutMigration {
13 |
14 | static func migrate() {
15 |
16 | guard let dataTransformer = ValueTransformer(forName: .secureUnarchiveFromDataTransformerName) else { return }
17 |
18 | guard let dictTransformer = ValueTransformer(forName: NSValueTransformerName(rawValue: MASDictionaryTransformerName)) else { return }
19 |
20 | for action in WindowAction.active {
21 |
22 | if let dataValue = UserDefaults.standard.data(forKey: action.name) {
23 | if let shortcut = dataTransformer.transformedValue(dataValue) {
24 |
25 | let dictValue = dictTransformer.reverseTransformedValue(shortcut)
26 | UserDefaults.standard.setValue(dictValue, forKey: action.name)
27 | }
28 | }
29 |
30 | }
31 |
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/NSImageExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSImageExtension.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 4/9/21.
6 | // Copyright © 2021 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | extension NSImage {
12 | func rotated(by degrees: CGFloat) -> NSImage {
13 | let sinDegrees = abs(sin(degrees * CGFloat.pi / 180.0))
14 | let cosDegrees = abs(cos(degrees * CGFloat.pi / 180.0))
15 | let newSize = CGSize(width: size.height * sinDegrees + size.width * cosDegrees,
16 | height: size.width * sinDegrees + size.height * cosDegrees)
17 |
18 | let imageBounds = NSRect(x: (newSize.width - size.width) / 2,
19 | y: (newSize.height - size.height) / 2,
20 | width: size.width, height: size.height)
21 |
22 | let otherTransform = NSAffineTransform()
23 | otherTransform.translateX(by: newSize.width / 2, yBy: newSize.height / 2)
24 | otherTransform.rotate(byDegrees: degrees)
25 | otherTransform.translateX(by: -newSize.width / 2, yBy: -newSize.height / 2)
26 |
27 | let rotatedImage = NSImage(size: newSize)
28 | rotatedImage.lockFocus()
29 | otherTransform.concat()
30 | draw(in: imageBounds, from: CGRect.zero, operation: NSCompositingOperation.copy, fraction: 1.0)
31 | rotatedImage.unlockFocus()
32 |
33 | return rotatedImage
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/NotificationExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationExtension.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 12/23/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | extension Notification.Name {
12 |
13 | static let configImported = Notification.Name("configImported")
14 | static let windowSnapping = Notification.Name("windowSnapping")
15 | static let frontAppChanged = Notification.Name("frontAppChanged")
16 | static let allowAnyShortcut = Notification.Name("allowAnyShortcutToggle")
17 | static let changeDefaults = Notification.Name("changeDefaults")
18 | static let todoMenuToggled = Notification.Name("todoMenuToggled")
19 | static let appWillBecomeActive = Notification.Name("appWillBecomeActive")
20 | static let missionControlDragging = Notification.Name("missionControlDragging")
21 | static let menuBarIconHidden = Notification.Name("menuBarIconHidden")
22 | static let windowTitleBar = Notification.Name("windowTitleBar")
23 | static let defaultSnapAreas = Notification.Name("defaultSnapAreas")
24 |
25 | func post(
26 | center: NotificationCenter = NotificationCenter.default,
27 | object: Any? = nil,
28 | userInfo: [AnyHashable : Any]? = nil) {
29 |
30 | center.post(name: self, object: object, userInfo: userInfo)
31 | }
32 |
33 | @discardableResult
34 | func onPost(
35 | center: NotificationCenter = NotificationCenter.default,
36 | object: Any? = nil,
37 | queue: OperationQueue? = nil,
38 | using: @escaping (Notification) -> Void)
39 | -> NSObjectProtocol {
40 |
41 | return center.addObserver(
42 | forName: self,
43 | object: object,
44 | queue: queue,
45 | using: using)
46 | }
47 |
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/RunLoopThread.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RunLoopThread.swift
3 | // Rectangle
4 | //
5 | // Copyright © 2022 Ryan Hanson. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | class RunLoopThread: Thread {
11 | private let startSemaphore = DispatchSemaphore(value: 0)
12 | private let mode: RunLoop.Mode
13 | private(set) var runLoop: RunLoop?
14 |
15 | init(mode: RunLoop.Mode, qualityOfService: QualityOfService? = nil, start: Bool = false) {
16 | self.mode = mode
17 | super.init()
18 | if let qualityOfService = qualityOfService { self.qualityOfService = qualityOfService }
19 | if start { self.start() }
20 | }
21 |
22 | override func start() {
23 | super.start()
24 | startSemaphore.wait()
25 | }
26 |
27 | override func main() {
28 | runLoop = RunLoop.current
29 | startSemaphore.signal()
30 | while !isCancelled {
31 | if !runLoop!.run(mode: mode, before: .distantFuture) {
32 | Thread.sleep(forTimeInterval: 0.1)
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/SequenceExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SequenceExtension.swift
3 | // Rectangle
4 | //
5 | // Copyright © 2022 Ryan Hanson. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Sequence {
11 | func uniqueMap(_ transform: (Element) -> T) -> [T] where T: Hashable {
12 | var set = Set()
13 | var array = Array()
14 | for element in self {
15 | let element = transform(element)
16 | if set.insert(element).inserted {
17 | array.append(element)
18 | }
19 | }
20 | return array
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/StringExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringExtension.swift
3 | // Rectangle
4 | //
5 | // Copyright © 2024 Ryan Hanson. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | extension String {
11 |
12 | var localized: String {
13 | NSLocalizedString(self, tableName: "Main", comment: "")
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/TimeoutCache.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TimeoutCache.swift
3 | // Rectangle
4 | //
5 | // Copyright © 2022 Ryan Hanson. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | class TimeoutCache {
11 | private let timeout: UInt64
12 | private var head: Entry?
13 | private var tail: Entry?
14 | private var cache = [Key: Entry]()
15 | private var purgeRestrictionExpirationTimestamp: UInt64 = 0
16 | private var purgeRestrictionExpired: Bool { DispatchTime.now().uptimeMilliseconds > purgeRestrictionExpirationTimestamp }
17 |
18 | init(timeout: UInt64) {
19 | self.timeout = timeout
20 | }
21 |
22 | subscript(key: Key) -> Value? {
23 | get {
24 | guard let entry = cache[key], !entry.expired else {
25 | remove(key)
26 | return nil
27 | }
28 | return entry.value
29 | }
30 | set {
31 | remove(key)
32 | purge()
33 | guard let value = newValue else { return }
34 | let expirationTimestamp = DispatchTime.now().uptimeMilliseconds + timeout
35 | let entry = Entry(key: key, value: value, expirationTimestamp: expirationTimestamp, previous: tail)
36 | entry.previous?.next = entry
37 | if head == nil { head = entry }
38 | tail = entry
39 | cache[key] = entry
40 | }
41 | }
42 |
43 | private func remove(_ key: Key) {
44 | guard let entry = cache[key] else { return }
45 | cache[key] = nil
46 | if entry === tail { tail = entry.previous }
47 | if entry === head { head = entry.next }
48 | entry.previous?.next = entry.next
49 | entry.next?.previous = entry.previous
50 | }
51 |
52 | private func purge() {
53 | guard purgeRestrictionExpired else { return }
54 | var entry = head
55 | while entry != nil && entry!.expired {
56 | remove(entry!.key)
57 | entry = entry!.next
58 | }
59 | purgeRestrictionExpirationTimestamp = DispatchTime.now().uptimeMilliseconds + (100 * timeout)
60 | }
61 |
62 | private class Entry {
63 | let key: Key
64 | let value: Value
65 | let expirationTimestamp: UInt64
66 | var previous: Entry?
67 | var next: Entry?
68 | var expired: Bool { DispatchTime.now().uptimeMilliseconds > expirationTimestamp }
69 |
70 | init(key: Key, value: Value, expirationTimestamp: UInt64, previous: Entry?) {
71 | self.key = key
72 | self.value = value
73 | self.expirationTimestamp = expirationTimestamp
74 | self.previous = previous
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Rectangle/Utilities/WindowUtil.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WindowUtil.swift
3 | // Rectangle
4 | //
5 | // Copyright © 2022 Ryan Hanson. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | class WindowUtil {
11 | private static var windowListCache = TimeoutCache<[CGWindowID]?, [WindowInfo]>(timeout: 100)
12 |
13 | static func getWindowList(ids: [CGWindowID]? = nil, all: Bool = false) -> [WindowInfo] {
14 | if let infos = windowListCache[ids] {
15 | return infos
16 | }
17 | var infos = [WindowInfo]()
18 | var rawInfos: CFArray?
19 | if let ids {
20 | let values = UnsafeMutablePointer.allocate(capacity: ids.count)
21 | for (i, id) in ids.enumerated() {
22 | values[i] = UnsafeRawPointer(bitPattern: UInt(id))
23 | }
24 | let rawIds = CFArrayCreate(kCFAllocatorDefault, values, ids.count, nil)
25 | rawInfos = CGWindowListCreateDescriptionFromArray(rawIds)
26 | } else {
27 | rawInfos = CGWindowListCopyWindowInfo([all ? .optionAll : .optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID)
28 | }
29 | if let rawInfos {
30 | let count = rawInfos.getCount()
31 | for i in 0.. 1)
19 | ? 0.9
20 | : CGFloat(defaultHeight)
21 |
22 | let defaultWidth = Defaults.almostMaximizeWidth.value
23 | almostMaximizeWidth = (defaultWidth <= 0 || defaultWidth > 1)
24 | ? 0.9
25 | : CGFloat(defaultWidth)
26 | }
27 |
28 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
29 |
30 | let visibleFrameOfScreen = params.visibleFrameOfScreen
31 | var calculatedWindowRect = visibleFrameOfScreen
32 |
33 | // Resize
34 | calculatedWindowRect.size.height = round(visibleFrameOfScreen.height * almostMaximizeHeight)
35 | calculatedWindowRect.size.width = round(visibleFrameOfScreen.width * almostMaximizeWidth)
36 |
37 | // Center
38 | calculatedWindowRect.origin.x = round((visibleFrameOfScreen.width - calculatedWindowRect.width) / 2.0) + visibleFrameOfScreen.minX
39 | calculatedWindowRect.origin.y = round((visibleFrameOfScreen.height - calculatedWindowRect.height) / 2.0) + visibleFrameOfScreen.minY
40 |
41 | return RectResult(calculatedWindowRect)
42 | }
43 |
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomCenterLeftEighthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomCenterLeftEighthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Johannes Trussell Rasch on 2022-02-18.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomCenterLeftEighthCalculation: WindowCalculation, OrientationAware, EighthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .bottomCenterLeftEighth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.minY
39 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
40 | return RectResult(rect, subAction: .bottomCenterLeftEighth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
47 | rect.origin.y = floor(visibleFrameOfScreen.maxY - (visibleFrameOfScreen.height * 0.75))
48 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
49 | return RectResult(rect, subAction: .bottomCenterLeftEighth)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomCenterNinthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomCenterNinthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomCenterNinthCalculation: WindowCalculation, OrientationAware, NinthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .bottomCenterNinth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
38 | rect.origin.y = visibleFrameOfScreen.minY
39 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
40 | return RectResult(rect, subAction: .bottomCenterNinth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.minY
48 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
49 | return RectResult(rect, subAction: .bottomCenterNinth)
50 | }
51 | }
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomCenterRightEighthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomCenterRightEighthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Johannes Trussell Rasch on 2022-02-18.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomCenterRightEighthCalculation: WindowCalculation, OrientationAware, EighthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .bottomCenterRightEighth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.minY
39 | rect.origin.x = visibleFrameOfScreen.minX + (2.0 * rect.width)
40 | return RectResult(rect, subAction: .bottomCenterRightEighth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
47 | rect.origin.y = visibleFrameOfScreen.minY
48 | rect.origin.x = visibleFrameOfScreen.minX
49 | return RectResult(rect, subAction: .bottomCenterRightEighth)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomHalfCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomHalfCalculation.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/14/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomHalfCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | if params.lastAction == nil || !Defaults.subsequentExecutionMode.resizes {
16 | return calculateFirstRect(params)
17 | }
18 |
19 | return calculateRepeatedRect(params)
20 | }
21 |
22 | func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult {
23 | let visibleFrameOfScreen = params.visibleFrameOfScreen
24 |
25 | var rect = visibleFrameOfScreen
26 | rect.size.height = floor(visibleFrameOfScreen.height * CGFloat(fraction))
27 | return RectResult(rect)
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomLeftEighthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomLeftEighthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Johannes Trussell Rasch on 2022-02-18.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomLeftEighthCalculation: WindowCalculation, OrientationAware, EighthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .bottomLeftEighth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.minY
39 | rect.origin.x = visibleFrameOfScreen.minX
40 | return RectResult(rect, subAction: .bottomLeftEighth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
47 | rect.origin.y = floor(visibleFrameOfScreen.maxY - (visibleFrameOfScreen.height * 0.75))
48 | rect.origin.x = visibleFrameOfScreen.minX
49 | return RectResult(rect, subAction: .bottomLeftEighth)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomLeftNinthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomLeftNinthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomLeftNinthCalculation: WindowCalculation, OrientationAware, NinthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .bottomLeftNinth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
38 | rect.origin.y = visibleFrameOfScreen.minY
39 | rect.origin.x = visibleFrameOfScreen.minX
40 | return RectResult(rect, subAction: .bottomLeftNinth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.minY
48 | rect.origin.x = visibleFrameOfScreen.minX
49 | return RectResult(rect, subAction: .bottomLeftNinth)
50 | }
51 | }
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomLeftSixthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomLeftSixthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 9/16/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomLeftSixthCalculation: WindowCalculation, OrientationAware, SixthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .bottomLeftSixth
24 | && lastSubAction != .bottomLeftSixthLandscape
25 | && lastSubAction != .bottomLeftSixthPortrait {
26 | return orientationBasedRect(visibleFrameOfScreen)
27 | }
28 |
29 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
30 | return calculation(visibleFrameOfScreen)
31 | }
32 |
33 | return orientationBasedRect(visibleFrameOfScreen)
34 | }
35 |
36 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
37 | var rect = visibleFrameOfScreen
38 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
39 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
40 | return RectResult(rect, subAction: .bottomLeftSixthLandscape)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
47 | return RectResult(rect, subAction: .bottomLeftSixthPortrait)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomLeftThirdCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomLeftThirdCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomLeftThirdCalculation: WindowCalculation, OrientationAware, HorizontalThirdsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .bottomLeftThird {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(2.0 * visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.minY
39 | rect.origin.x = visibleFrameOfScreen.minX
40 | return RectResult(rect, subAction: .bottomLeftThird)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(2.0 * visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.minY
48 | rect.origin.x = visibleFrameOfScreen.minX
49 | return RectResult(rect, subAction: .bottomLeftThird)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomRightEighthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomRightEighthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Johannes Trussell Rasch on 2022-02-18.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomRightEighthCalculation: WindowCalculation, OrientationAware, EighthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .bottomRightEighth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.minY
39 | rect.origin.x = visibleFrameOfScreen.minX + (3.0 * rect.width)
40 | return RectResult(rect, subAction: .bottomRightEighth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
47 | rect.origin.y = visibleFrameOfScreen.minY
48 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
49 | return RectResult(rect, subAction: .bottomRightEighth)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomRightNinthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomRightNinthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomRightNinthCalculation: WindowCalculation, OrientationAware, NinthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .bottomRightNinth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
38 | rect.origin.y = visibleFrameOfScreen.minY
39 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width - rect.width
40 | return RectResult(rect, subAction: .bottomRightNinth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.minY
48 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width - rect.width
49 | return RectResult(rect, subAction: .bottomRightNinth)
50 | }
51 | }
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomRightSixthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomRightSixthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 9/16/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomRightSixthCalculation: WindowCalculation, OrientationAware, SixthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | let visibleFrameOfScreen = params.visibleFrameOfScreen
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .bottomRightSixth
24 | && lastSubAction != .bottomRightSixthLandscape
25 | && lastSubAction != .bottomRightSixthPortrait {
26 | return orientationBasedRect(visibleFrameOfScreen)
27 | }
28 |
29 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .left) {
30 | return calculation(visibleFrameOfScreen)
31 | }
32 |
33 | return orientationBasedRect(visibleFrameOfScreen)
34 | }
35 |
36 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
37 | var rect = visibleFrameOfScreen
38 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
39 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
40 | rect.origin.x = visibleFrameOfScreen.origin.x + visibleFrameOfScreen.width - rect.width
41 | return RectResult(rect, subAction: .bottomRightSixthLandscape)
42 | }
43 |
44 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
45 | var rect = visibleFrameOfScreen
46 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
47 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
48 | rect.origin.x = visibleFrameOfScreen.origin.x + visibleFrameOfScreen.width - rect.width
49 | return RectResult(rect, subAction: .bottomRightSixthPortrait)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/BottomRightThirdCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BottomRightThirdCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BottomRightThirdCalculation: WindowCalculation, OrientationAware, HorizontalThirdsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .bottomRightThird {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(2.0 * visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.minY
39 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width / 3.0
40 | return RectResult(rect, subAction: .bottomRightThird)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(2.0 * visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.minY
48 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width / 2.0
49 | return RectResult(rect, subAction: .bottomRightThird)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/CenterCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CenterCalculation.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/14/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class CenterCalculation: WindowCalculation {
12 |
13 | override func calculate(_ params: WindowCalculationParameters) -> WindowCalculationResult? {
14 |
15 | var screenFrame: CGRect?
16 | if !Defaults.alwaysAccountForStage.userEnabled {
17 | screenFrame = params.usableScreens.currentScreen.adjustedVisibleFrame(params.ignoreTodo, true)
18 | }
19 |
20 | let rectResult = calculateRect(params.asRectParams(visibleFrame: screenFrame))
21 |
22 | let resultingAction: WindowAction = rectResult.resultingAction ?? params.action
23 |
24 | return WindowCalculationResult(rect: rectResult.rect,
25 | screen: params.usableScreens.currentScreen,
26 | resultingAction: resultingAction,
27 | resultingScreenFrame: screenFrame)
28 | }
29 |
30 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
31 |
32 | let visibleFrameOfScreen = params.visibleFrameOfScreen
33 | var calculatedWindowRect = params.window.rect
34 |
35 | let heightExceeded = params.window.rect.height > visibleFrameOfScreen.height
36 | let widthExceeded = params.window.rect.width > visibleFrameOfScreen.width
37 |
38 | if heightExceeded && widthExceeded {
39 | return RectResult(visibleFrameOfScreen, resultingAction: .maximize)
40 | }
41 |
42 | if heightExceeded {
43 | calculatedWindowRect.size.height = visibleFrameOfScreen.height
44 | calculatedWindowRect.origin.y = visibleFrameOfScreen.minY
45 | } else {
46 | calculatedWindowRect.origin.y = round((visibleFrameOfScreen.height - params.window.rect.height) / 2.0) + visibleFrameOfScreen.minY
47 | }
48 |
49 | if widthExceeded {
50 | calculatedWindowRect.size.width = visibleFrameOfScreen.width
51 | calculatedWindowRect.origin.x = visibleFrameOfScreen.minX
52 | } else {
53 | calculatedWindowRect.origin.x = round((visibleFrameOfScreen.width - params.window.rect.width) / 2.0) + visibleFrameOfScreen.minX
54 | }
55 |
56 | return RectResult(calculatedWindowRect)
57 |
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/CenterProminentlyCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CenterProminentlyCalculation.swift
3 | // Rectangle
4 | //
5 | // Copyright © 2019 Ryan Hanson. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | class CenterProminentlyCalculation: WindowCalculation {
11 |
12 | override func calculate(_ params: WindowCalculationParameters) -> WindowCalculationResult? {
13 |
14 | var screenFrame: CGRect?
15 | if !Defaults.alwaysAccountForStage.userEnabled {
16 | screenFrame = params.usableScreens.currentScreen.adjustedVisibleFrame(params.ignoreTodo, true)
17 | }
18 |
19 | let rectResult = calculateRect(params.asRectParams(visibleFrame: screenFrame))
20 |
21 | let resultingAction: WindowAction = rectResult.resultingAction ?? params.action
22 |
23 | return WindowCalculationResult(rect: rectResult.rect,
24 | screen: params.usableScreens.currentScreen,
25 | resultingAction: resultingAction,
26 | resultingScreenFrame: screenFrame)
27 | }
28 |
29 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
30 |
31 | let rectResult = WindowCalculationFactory.centerCalculation.calculateRect(params)
32 | var rect = rectResult.rect
33 | rect.origin.y += -0.25 * rect.height + 0.25 * params.visibleFrameOfScreen.height
34 | return RectResult(rect, resultingAction: rectResult.resultingAction)
35 |
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/CenterThirdCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HorizCenterThirdCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 7/26/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class CenterThirdCalculation: WindowCalculation, OrientationAware {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 | return orientationBasedRect(visibleFrameOfScreen)
16 | }
17 |
18 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
19 | var rect = visibleFrameOfScreen
20 | rect.origin.x = visibleFrameOfScreen.minX + floor(visibleFrameOfScreen.width / 3.0)
21 | rect.origin.y = visibleFrameOfScreen.minY
22 | rect.size.width = visibleFrameOfScreen.width / 3.0
23 | rect.size.height = visibleFrameOfScreen.height
24 | return RectResult(rect, subAction: .centerVerticalThird)
25 | }
26 |
27 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
28 | var rect = visibleFrameOfScreen
29 | rect.origin.x = visibleFrameOfScreen.minX
30 | rect.origin.y = visibleFrameOfScreen.minY + floor(visibleFrameOfScreen.height / 3.0)
31 | rect.size.width = visibleFrameOfScreen.width
32 | rect.size.height = visibleFrameOfScreen.height / 3.0
33 | return RectResult(rect, subAction: .centerHorizontalThird)
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/ChangeWindowDimensionCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MinimumWindowDimensionAware.swift
3 | // Rectangle
4 | //
5 | // Created by Isaac Young on 23/04/24.
6 | // Copyright © 2024 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol ChangeWindowDimensionCalculation {
12 | func resizedWindowRectIsTooSmall(windowRect: CGRect, visibleFrameOfScreen: CGRect) -> Bool;
13 | }
14 |
15 | extension ChangeWindowDimensionCalculation {
16 | private func minimumWindowWidth() -> CGFloat {
17 | let defaultWidth = Defaults.minimumWindowWidth.value
18 | return (defaultWidth <= 0 || defaultWidth > 1)
19 | ? 0.25
20 | : CGFloat(defaultWidth)
21 | }
22 |
23 | private func minimumWindowHeight() -> CGFloat {
24 | let defaultHeight = Defaults.minimumWindowHeight.value
25 | return (defaultHeight <= 0 || defaultHeight > 1)
26 | ? 0.25
27 | : CGFloat(defaultHeight)
28 | }
29 |
30 | func resizedWindowRectIsTooSmall(windowRect: CGRect, visibleFrameOfScreen: CGRect) -> Bool {
31 | let minimumWindowRectWidth = floor(visibleFrameOfScreen.width * minimumWindowWidth())
32 | let minimumWindowRectHeight = floor(visibleFrameOfScreen.height * minimumWindowHeight())
33 | return (windowRect.width <= minimumWindowRectWidth) || (windowRect.height <= minimumWindowRectHeight)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/FirstFourthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LeftThirdCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 7/26/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class FirstFourthCalculation: WindowCalculation, OrientationAware {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | params.action == .firstFourth,
18 | let last = params.lastAction,
19 | let lastSubAction = last.subAction
20 | else {
21 | return orientationBasedRect(visibleFrameOfScreen)
22 | }
23 |
24 | var calculation: WindowCalculation?
25 | if last.action == .firstFourth {
26 | switch lastSubAction {
27 | case .topFourth, .leftFourth:
28 | calculation = WindowCalculationFactory.secondFourthCalculation
29 | case .centerTopFourth, .centerLeftFourth:
30 | calculation = WindowCalculationFactory.thirdFourthCalculation
31 | case .centerBottomFourth, .centerRightFourth:
32 | calculation = WindowCalculationFactory.lastFourthCalculation
33 | default:
34 | break
35 | }
36 | } else if last.action == .lastFourth {
37 | switch lastSubAction {
38 | case .leftFourth, .topFourth:
39 | calculation = WindowCalculationFactory.secondFourthCalculation
40 | default:
41 | break
42 | }
43 | }
44 |
45 | if let calculation = calculation {
46 | return calculation.calculateRect(params)
47 | }
48 |
49 | return orientationBasedRect(visibleFrameOfScreen)
50 | }
51 |
52 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
53 | var rect = visibleFrameOfScreen
54 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
55 | return RectResult(rect, subAction: .leftFourth)
56 | }
57 |
58 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
59 | var rect = visibleFrameOfScreen
60 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
61 | rect.origin.y = visibleFrameOfScreen.origin.y + visibleFrameOfScreen.height - rect.height
62 | return RectResult(rect, subAction: .topFourth)
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/FirstThirdCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LeftThirdCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 7/26/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class FirstThirdCalculation: WindowCalculation, OrientationAware {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 | guard Defaults.subsequentExecutionMode.value != .none,
16 | let last = params.lastAction, let lastSubAction = last.subAction else {
17 | return orientationBasedRect(visibleFrameOfScreen)
18 | }
19 |
20 | var calculation: WindowCalculation?
21 |
22 | if last.action == .firstThird {
23 | switch lastSubAction {
24 | case .topThird, .leftThird:
25 | calculation = WindowCalculationFactory.centerThirdCalculation
26 | case .centerHorizontalThird, .centerVerticalThird:
27 | calculation = WindowCalculationFactory.lastThirdCalculation
28 | default:
29 | break
30 | }
31 | } else if last.action == .lastThird {
32 | switch lastSubAction {
33 | case .topThird, .leftThird:
34 | calculation = WindowCalculationFactory.centerThirdCalculation
35 | default:
36 | break
37 | }
38 | }
39 |
40 | if let calculation = calculation {
41 | return calculation.calculateRect(params)
42 | }
43 |
44 | return orientationBasedRect(visibleFrameOfScreen)
45 | }
46 |
47 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
48 | var rect = visibleFrameOfScreen
49 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
50 | return RectResult(rect, subAction: .leftThird)
51 | }
52 |
53 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
54 | var rect = visibleFrameOfScreen
55 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
56 | rect.origin.y = visibleFrameOfScreen.minY + visibleFrameOfScreen.height - rect.height
57 | return RectResult(rect, subAction: .topThird)
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/FirstThreeFourthsCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FirstThreeFourthsCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Björn Orri Sæmundsson on 26.06.21.
6 | // Copyright © 2021 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class FirstThreeFourthsCalculation: WindowCalculation, OrientationAware {
12 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
13 | let visibleFrameOfScreen = params.visibleFrameOfScreen
14 |
15 | guard Defaults.subsequentExecutionMode.value != .none,
16 | let last = params.lastAction, let lastSubAction = last.subAction else {
17 | return orientationBasedRect(visibleFrameOfScreen)
18 | }
19 |
20 | if lastSubAction == .leftThreeFourths || lastSubAction == .topThreeFourths {
21 | return WindowCalculationFactory.lastThreeFourthsCalculation.orientationBasedRect(visibleFrameOfScreen)
22 | }
23 |
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
28 | var rect = visibleFrameOfScreen
29 | rect.size.width = floor(visibleFrameOfScreen.width * 3 / 4.0)
30 | return RectResult(rect, subAction: .leftThreeFourths)
31 | }
32 |
33 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
34 | var rect = visibleFrameOfScreen
35 | rect.size.height = floor(visibleFrameOfScreen.height * 3 / 4.0)
36 | rect.origin.y = visibleFrameOfScreen.origin.y + visibleFrameOfScreen.height - rect.height
37 | return RectResult(rect, subAction: .topThreeFourths)
38 | }
39 |
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/FirstTwoThirdsCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LeftTwoThirdsCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 7/26/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class FirstTwoThirdsCalculation: WindowCalculation, OrientationAware {
12 |
13 |
14 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
15 | let visibleFrameOfScreen = params.visibleFrameOfScreen
16 |
17 | guard Defaults.subsequentExecutionMode.value != .none,
18 | let last = params.lastAction, let lastSubAction = last.subAction else {
19 | return orientationBasedRect(visibleFrameOfScreen)
20 | }
21 |
22 | if lastSubAction == .leftTwoThirds || lastSubAction == .topTwoThirds {
23 | return WindowCalculationFactory.lastTwoThirdsCalculation.orientationBasedRect(visibleFrameOfScreen)
24 | }
25 |
26 | return orientationBasedRect(visibleFrameOfScreen)
27 | }
28 |
29 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
30 | var rect = visibleFrameOfScreen
31 | rect.size.width = floor(visibleFrameOfScreen.width * 2 / 3.0)
32 | return RectResult(rect, subAction: .leftTwoThirds)
33 | }
34 |
35 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
36 | var rect = visibleFrameOfScreen
37 | rect.size.height = floor(visibleFrameOfScreen.height * 2 / 3.0)
38 | rect.origin.y = visibleFrameOfScreen.origin.y + visibleFrameOfScreen.height - rect.height
39 | return RectResult(rect, subAction: .topTwoThirds)
40 | }
41 |
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/GapCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GapCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 1/14/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class GapCalculation {
12 |
13 | static func applyGaps(_ rect: CGRect, dimension: Dimension = .both, sharedEdges: Edge = .none, gapSize: Float) -> CGRect {
14 |
15 | let cgGapSize = CGFloat(gapSize)
16 | let halfGapSize = cgGapSize / 2
17 |
18 | var withGaps = rect.insetBy(
19 | dx: dimension.contains(.horizontal) ? cgGapSize : 0,
20 | dy: dimension.contains(.vertical) ? cgGapSize : 0
21 | )
22 |
23 | if dimension.contains(.horizontal) {
24 | if sharedEdges.contains(.left) {
25 | withGaps.origin.x -= halfGapSize
26 | withGaps.size.width += halfGapSize
27 | }
28 |
29 | if sharedEdges.contains(.right) {
30 | withGaps.size.width += halfGapSize
31 | }
32 | }
33 |
34 |
35 | if dimension.contains(.vertical) {
36 | if sharedEdges.contains(.bottom) {
37 | withGaps.origin.y -= halfGapSize
38 | withGaps.size.height += halfGapSize
39 | }
40 |
41 | if sharedEdges.contains(.top) {
42 | withGaps.size.height += halfGapSize
43 | }
44 | }
45 |
46 | return withGaps
47 | }
48 | }
49 |
50 | struct Dimension: OptionSet {
51 | let rawValue: Int
52 |
53 | static let horizontal = Dimension(rawValue: 1 << 0)
54 | static let vertical = Dimension(rawValue: 1 << 1)
55 |
56 | static let both: Dimension = [.horizontal, .vertical]
57 | static let none: Dimension = []
58 | }
59 |
60 | struct Edge: OptionSet {
61 | let rawValue: Int
62 |
63 | static let left = Edge(rawValue: 1 << 0)
64 | static let right = Edge(rawValue: 1 << 1)
65 | static let top = Edge(rawValue: 1 << 2)
66 | static let bottom = Edge(rawValue: 1 << 3)
67 |
68 | static let all: Edge = [.left, .right, .top, .bottom]
69 | static let none: Edge = []
70 | }
71 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/HorizontalThirdsRepeated.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HorizontalThirdsRepeated.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol HorizontalThirdsRepeated {
12 | func nextCalculation(subAction: SubWindowAction, direction: Direction) -> SimpleCalc?
13 | }
14 |
15 | extension HorizontalThirdsRepeated {
16 | func nextCalculation(subAction: SubWindowAction, direction: Direction) -> SimpleCalc? {
17 |
18 | if direction == .left {
19 | switch subAction {
20 | case .topLeftThird:
21 | return WindowCalculationFactory.bottomRightThirdCalculation.orientationBasedRect
22 | case .topRightThird:
23 | return WindowCalculationFactory.topLeftThirdCalculation.orientationBasedRect
24 | case .bottomLeftThird:
25 | return WindowCalculationFactory.topRightThirdCalculation.orientationBasedRect
26 | case .bottomRightThird:
27 | return WindowCalculationFactory.bottomLeftThirdCalculation.orientationBasedRect
28 | default: break
29 | }
30 | }
31 |
32 | else if direction == .right {
33 | switch subAction {
34 | case .topLeftThird:
35 | return WindowCalculationFactory.topRightThirdCalculation.orientationBasedRect
36 | case .topRightThird:
37 | return WindowCalculationFactory.bottomLeftThirdCalculation.orientationBasedRect
38 | case .bottomLeftThird:
39 | return WindowCalculationFactory.bottomRightThirdCalculation.orientationBasedRect
40 | case .bottomRightThird:
41 | return WindowCalculationFactory.topLeftThirdCalculation.orientationBasedRect
42 | default: break
43 | }
44 | }
45 |
46 | return nil
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/LastFourthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LastFourthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 9/16/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class LastFourthCalculation: WindowCalculation, OrientationAware {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 | guard Defaults.subsequentExecutionMode.value != .none,
16 | let last = params.lastAction, let lastSubAction = last.subAction else {
17 | return orientationBasedRect(visibleFrameOfScreen)
18 | }
19 |
20 | var calculation: WindowCalculation?
21 | if last.action == .lastFourth {
22 | switch lastSubAction {
23 | case .bottomFourth, .rightFourth:
24 | calculation = WindowCalculationFactory.thirdFourthCalculation
25 | case .centerBottomFourth, .centerRightFourth:
26 | calculation = WindowCalculationFactory.secondFourthCalculation
27 | case .centerTopFourth, .centerLeftFourth:
28 | calculation = WindowCalculationFactory.firstFourthCalculation
29 | default:
30 | break
31 | }
32 | } else if last.action == .firstFourth {
33 | switch lastSubAction {
34 | case .bottomFourth, .rightFourth:
35 | calculation = WindowCalculationFactory.thirdFourthCalculation
36 | default:
37 | break
38 | }
39 | }
40 |
41 | if let calculation = calculation {
42 | return calculation.calculateRect(params)
43 | }
44 |
45 | return orientationBasedRect(visibleFrameOfScreen)
46 | }
47 |
48 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
49 | var rect = visibleFrameOfScreen
50 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
51 | rect.origin.x = visibleFrameOfScreen.origin.x + visibleFrameOfScreen.width - rect.width
52 | return RectResult(rect, subAction: .rightFourth)
53 | }
54 |
55 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
56 | var rect = visibleFrameOfScreen
57 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
58 | return RectResult(rect, subAction: .bottomFourth)
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/LastThirdCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RightThirdCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 7/26/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class LastThirdCalculation: WindowCalculation, OrientationAware {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction, let lastSubAction = last.subAction else {
18 | return orientationBasedRect(visibleFrameOfScreen)
19 | }
20 |
21 | var calculation: WindowCalculation?
22 |
23 | if last.action == .lastThird {
24 | switch lastSubAction {
25 | case .bottomThird, .rightThird:
26 | calculation = WindowCalculationFactory.centerThirdCalculation
27 | case .centerHorizontalThird, .centerVerticalThird:
28 | calculation = WindowCalculationFactory.firstThirdCalculation
29 | default:
30 | break
31 | }
32 | } else if last.action == .firstThird {
33 | switch lastSubAction {
34 | case .bottomThird, .rightThird:
35 | calculation = WindowCalculationFactory.centerThirdCalculation
36 | default:
37 | break
38 | }
39 | }
40 |
41 | if let calculation = calculation {
42 | return calculation.calculateRect(params)
43 | }
44 |
45 | return orientationBasedRect(visibleFrameOfScreen)
46 | }
47 |
48 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
49 | var rect = visibleFrameOfScreen
50 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
51 | rect.origin.x = visibleFrameOfScreen.origin.x + visibleFrameOfScreen.width - rect.width
52 | return RectResult(rect, subAction: .rightThird)
53 | }
54 |
55 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
56 | var rect = visibleFrameOfScreen
57 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
58 | return RectResult(rect, subAction: .bottomThird)
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/LastThreeFourthsCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LastThreeFourthsCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Björn Orri Sæmundsson on 26.06.21.
6 | // Copyright © 2021 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class LastThreeFourthsCalculation: WindowCalculation, OrientationAware {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction, let lastSubAction = last.subAction else {
18 | return orientationBasedRect(visibleFrameOfScreen)
19 | }
20 |
21 | if lastSubAction == .rightThreeFourths || lastSubAction == .bottomThreeFourths {
22 | return WindowCalculationFactory.firstThreeFourthsCalculation.orientationBasedRect(visibleFrameOfScreen)
23 | }
24 |
25 | return orientationBasedRect(visibleFrameOfScreen)
26 | }
27 |
28 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
29 | var rect = visibleFrameOfScreen
30 | rect.size.width = floor(visibleFrameOfScreen.width * 3 / 4.0)
31 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width - rect.width
32 | return RectResult(rect, subAction: .rightThreeFourths)
33 | }
34 |
35 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
36 | var rect = visibleFrameOfScreen
37 | rect.size.height = floor(visibleFrameOfScreen.height * 3 / 4.0)
38 | return RectResult(rect, subAction: .bottomThreeFourths)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/LastTwoThirdsCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RightTwoThirdsCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 7/26/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class LastTwoThirdsCalculation: WindowCalculation, OrientationAware {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction, let lastSubAction = last.subAction else {
18 | return orientationBasedRect(visibleFrameOfScreen)
19 | }
20 |
21 | if lastSubAction == .rightTwoThirds || lastSubAction == .bottomTwoThirds {
22 | return WindowCalculationFactory.firstTwoThirdsCalculation.orientationBasedRect(visibleFrameOfScreen)
23 | }
24 |
25 | return orientationBasedRect(visibleFrameOfScreen)
26 | }
27 |
28 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
29 | var rect = visibleFrameOfScreen
30 | rect.size.width = floor(visibleFrameOfScreen.width * 2 / 3.0)
31 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width - rect.width
32 | return RectResult(rect, subAction: .rightTwoThirds)
33 | }
34 |
35 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
36 | var rect = visibleFrameOfScreen
37 | rect.size.height = floor(visibleFrameOfScreen.height * 2 / 3.0)
38 | return RectResult(rect, subAction: .bottomTwoThirds)
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/LeftTodoCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LeftTodoCalculation.swift
3 | // Rectangle
4 | //
5 | // Copyright © 2023 Ryan Hanson. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | final class LeftTodoCalculation: WindowCalculation {
11 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
12 | let visibleFrameOfScreen = params.visibleFrameOfScreen
13 | var calculatedWindowRect = visibleFrameOfScreen
14 |
15 | calculatedWindowRect.size.width = Defaults.todoSidebarWidth.cgFloat
16 |
17 | return RectResult(calculatedWindowRect, subAction: .leftTodo)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/LowerLeftCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LowerLeftCalculation.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/14/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class LowerLeftCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | if params.lastAction == nil || !Defaults.subsequentExecutionMode.resizes {
16 | return calculateFirstRect(params)
17 | }
18 |
19 | return calculateRepeatedRect(params)
20 | }
21 |
22 | func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult {
23 | let visibleFrameOfScreen = params.visibleFrameOfScreen
24 |
25 | var rect = visibleFrameOfScreen
26 |
27 | rect.size.width = floor(visibleFrameOfScreen.width * CGFloat(fraction))
28 |
29 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
30 |
31 | return RectResult(rect)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/LowerRightCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LowerRightCalculation.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/14/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class LowerRightCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | if params.lastAction == nil || !Defaults.subsequentExecutionMode.resizes {
16 | return calculateFirstRect(params)
17 | }
18 |
19 | return calculateRepeatedRect(params)
20 | }
21 |
22 | func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult {
23 | let visibleFrameOfScreen = params.visibleFrameOfScreen
24 |
25 | var rect = visibleFrameOfScreen
26 |
27 | rect.size.width = floor(visibleFrameOfScreen.width * CGFloat(fraction))
28 | rect.origin.x = visibleFrameOfScreen.maxX - rect.width
29 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
30 |
31 | return RectResult(rect)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/MaximizeCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MaximizeCalculation.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/14/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class MaximizeCalculation: WindowCalculation {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | return RectResult(visibleFrameOfScreen)
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/MaximizeHeightCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MaximizeHeightCalculation.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/14/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class MaximizeHeightCalculation: WindowCalculation {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | let visibleFrameOfScreen = params.visibleFrameOfScreen
16 | var maxHeightRect = params.window.rect
17 | maxHeightRect.origin.y = visibleFrameOfScreen.minY
18 | maxHeightRect.size.height = visibleFrameOfScreen.height
19 | return RectResult(maxHeightRect)
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/MiddleCenterNinthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MiddleCenterNinthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class MiddleCenterNinthCalculation: WindowCalculation, OrientationAware, NinthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .middleCenterNinth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
38 | rect.origin.y = visibleFrameOfScreen.minY + rect.height
39 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
40 | return RectResult(rect, subAction: .middleCenterNinth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.minY + rect.height
48 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
49 | return RectResult(rect, subAction: .middleCenterNinth)
50 | }
51 | }
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/MiddleLeftNinthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MiddleLeftNinthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class MiddleLeftNinthCalculation: WindowCalculation, OrientationAware, NinthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .middleLeftNinth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
38 | rect.origin.y = visibleFrameOfScreen.minY + rect.height
39 | rect.origin.x = visibleFrameOfScreen.minX
40 | return RectResult(rect, subAction: .middleLeftNinth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.minY + rect.height
48 | rect.origin.x = visibleFrameOfScreen.minX
49 | return RectResult(rect, subAction: .middleLeftNinth)
50 | }
51 | }
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/MiddleRightNinthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MiddleRightNinthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class MiddleRightNinthCalculation: WindowCalculation, OrientationAware, NinthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .middleRightNinth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
38 | rect.origin.y = visibleFrameOfScreen.minY + rect.height
39 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width - rect.width
40 | return RectResult(rect, subAction: .middleRightNinth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.minY + rect.height
48 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width - rect.width
49 | return RectResult(rect, subAction: .middleRightNinth)
50 | }
51 | }
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/MoveUpDownCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MoveUpDownCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 7/26/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class MoveUpDownCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | let visibleFrameOfScreen = params.visibleFrameOfScreen
16 |
17 | var calculatedWindowRect: CGRect
18 |
19 | if Defaults.resizeOnDirectionalMove.enabled {
20 | calculatedWindowRect = calculateRepeatedRect(params).rect
21 | } else {
22 | calculatedWindowRect = calculateGenericRect(params).rect
23 | }
24 |
25 | if Defaults.centeredDirectionalMove.enabled != false {
26 | calculatedWindowRect.origin.x = round((visibleFrameOfScreen.width - calculatedWindowRect.width) / 2.0) + visibleFrameOfScreen.minX
27 | }
28 |
29 | if params.window.rect.width >= visibleFrameOfScreen.width {
30 | calculatedWindowRect.size.width = visibleFrameOfScreen.width
31 | calculatedWindowRect.origin.x = visibleFrameOfScreen.minX
32 | }
33 |
34 | return RectResult(calculatedWindowRect)
35 |
36 | }
37 |
38 | func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult {
39 | return calculateGenericRect(params, fraction: fraction)
40 | }
41 |
42 | func calculateGenericRect(_ params: RectCalculationParameters, fraction: Float? = nil) -> RectResult {
43 | let visibleFrameOfScreen = params.visibleFrameOfScreen
44 |
45 | var rect = params.window.rect
46 | if let requestedFraction = fraction {
47 | rect.size.height = floor(visibleFrameOfScreen.height * CGFloat(requestedFraction))
48 | }
49 |
50 | if params.action == .moveUp {
51 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
52 | } else {
53 | rect.origin.y = visibleFrameOfScreen.minY
54 | }
55 |
56 | return RectResult(rect)
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/OrientationAware.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OrientationAware.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 9/23/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | typealias SimpleCalc = (_ visibleFrameOfScreen: CGRect) -> RectResult
12 |
13 | protocol OrientationAware {
14 |
15 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult
16 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult
17 | func orientationBasedRect(_ visibleFrameOfScreen: CGRect) -> RectResult
18 |
19 | }
20 |
21 | extension OrientationAware {
22 | func orientationBasedRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
23 | return visibleFrameOfScreen.isLandscape
24 | ? landscapeRect(visibleFrameOfScreen)
25 | : portraitRect(visibleFrameOfScreen)
26 | }
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/RepeatedExecutionsCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepeatedExecutionsCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 10/18/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol RepeatedExecutionsCalculation {
12 |
13 | func calculateFirstRect(_ params: RectCalculationParameters) -> RectResult
14 |
15 | func calculateRect(for cycleDivision: CycleSize, params: RectCalculationParameters) -> RectResult
16 |
17 | }
18 |
19 | extension RepeatedExecutionsCalculation {
20 |
21 | func calculateRepeatedRect(_ params: RectCalculationParameters) -> RectResult {
22 |
23 | guard let count = params.lastAction?.count,
24 | params.lastAction?.action == params.action
25 | else {
26 | return calculateFirstRect(params)
27 | }
28 |
29 | let useDefaultPositions = !Defaults.cycleSizesIsChanged.enabled
30 | let positions = useDefaultPositions ? CycleSize.defaultSizes : Defaults.selectedCycleSizes.value
31 |
32 | let sortedPositions = CycleSize.sortedSizes
33 | .filter { positions.contains($0) }
34 |
35 | let position = count % sortedPositions.count
36 |
37 | return calculateRect(for: sortedPositions[position], params: params)
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/RepeatedExecutionsInThirdsCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepeatedExecutionsInThirdsCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Charlie Harding on 12/06/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol RepeatedExecutionsInThirdsCalculation: RepeatedExecutionsCalculation {
12 |
13 | func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult
14 |
15 | }
16 |
17 | extension RepeatedExecutionsInThirdsCalculation {
18 |
19 | func calculateFirstRect(_ params: RectCalculationParameters) -> RectResult {
20 | return calculateFractionalRect(params, fraction: 1 / 2.0)
21 | }
22 |
23 | func calculateRect(for cycleDivision: CycleSize, params: RectCalculationParameters) -> RectResult {
24 | let fraction = cycleDivision.fraction
25 | return calculateFractionalRect(params, fraction: fraction)
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/RightTodoCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RightTodoCalculation.swift
3 | // Rectangle
4 | //
5 | // Copyright © 2023 Ryan Hanson. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | final class RightTodoCalculation: WindowCalculation {
11 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
12 | let visibleFrameOfScreen = params.visibleFrameOfScreen
13 | var calculatedWindowRect = visibleFrameOfScreen
14 |
15 | calculatedWindowRect.origin.x = visibleFrameOfScreen.maxX - Defaults.todoSidebarWidth.cgFloat
16 | calculatedWindowRect.size.width = Defaults.todoSidebarWidth.cgFloat
17 |
18 | return RectResult(calculatedWindowRect, subAction: .rightTodo)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/SecondFourthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SecondFourthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 9/16/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class SecondFourthCalculation: WindowCalculation, OrientationAware {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | let visibleFrameOfScreen = params.visibleFrameOfScreen
16 |
17 | guard Defaults.subsequentExecutionMode.value != .none,
18 | let last = params.lastAction,
19 | let lastSubAction = last.subAction,
20 | last.action == .secondFourth
21 | else {
22 | return orientationBasedRect(visibleFrameOfScreen)
23 | }
24 |
25 | let calc: SimpleCalc
26 | switch lastSubAction {
27 | case .centerLeftFourth:
28 | calc = WindowCalculationFactory.lastThreeFourthsCalculation.landscapeRect
29 | case .centerTopFourth:
30 | calc = WindowCalculationFactory.lastThreeFourthsCalculation.portraitRect
31 | case .rightThreeFourths:
32 | calc = WindowCalculationFactory.centerHalfCalculation.landscapeRect
33 | case .bottomThreeFourths:
34 | calc = WindowCalculationFactory.centerHalfCalculation.portraitRect
35 | default:
36 | calc = orientationBasedRect
37 | }
38 |
39 | return calc(visibleFrameOfScreen)
40 | }
41 |
42 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
43 | var rect = visibleFrameOfScreen
44 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
45 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
46 | return RectResult(rect, subAction: .centerLeftFourth)
47 | }
48 |
49 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
50 | var rect = visibleFrameOfScreen
51 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
52 | rect.origin.y = visibleFrameOfScreen.minY + visibleFrameOfScreen.height - (rect.height * 2.0)
53 | return RectResult(rect, subAction: .centerTopFourth)
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/SpecifiedCalculation.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | final class SpecifiedCalculation: WindowCalculation {
4 |
5 | private let specifiedHeight: CGFloat
6 | private let specifiedWidth: CGFloat
7 |
8 | override init() {
9 | specifiedHeight = CGFloat(Defaults.specifiedHeight.value)
10 | specifiedWidth = CGFloat(Defaults.specifiedWidth.value)
11 | }
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | let visibleFrameOfScreen = params.visibleFrameOfScreen
16 | var calculatedWindowRect = visibleFrameOfScreen
17 |
18 | // Resize
19 | calculatedWindowRect.size.height = specifiedHeight <= 1
20 | ? visibleFrameOfScreen.height * specifiedHeight
21 | : round(specifiedHeight)
22 | calculatedWindowRect.size.width = specifiedWidth <= 1
23 | ? visibleFrameOfScreen.width * specifiedWidth
24 | : min(visibleFrameOfScreen.width, round(specifiedWidth))
25 |
26 | // Center
27 | calculatedWindowRect.origin.x = round((visibleFrameOfScreen.width - calculatedWindowRect.width) / 2.0) + visibleFrameOfScreen.minX
28 | calculatedWindowRect.origin.y = round((visibleFrameOfScreen.height - calculatedWindowRect.height) / 2.0) + visibleFrameOfScreen.minY
29 |
30 | return RectResult(calculatedWindowRect)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/ThirdFourthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThirdFourthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 9/16/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class ThirdFourthCalculation: WindowCalculation, OrientationAware {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | let visibleFrameOfScreen = params.visibleFrameOfScreen
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction,
19 | last.action == .thirdFourth
20 | else {
21 | return orientationBasedRect(visibleFrameOfScreen)
22 | }
23 |
24 | let calc: SimpleCalc
25 | switch lastSubAction {
26 | case .centerRightFourth:
27 | calc = WindowCalculationFactory.firstThreeFourthsCalculation.landscapeRect
28 | case .centerBottomFourth:
29 | calc = WindowCalculationFactory.firstThreeFourthsCalculation.portraitRect
30 | case .leftThreeFourths:
31 | calc = WindowCalculationFactory.centerHalfCalculation.landscapeRect
32 | case .topThreeFourths:
33 | calc = WindowCalculationFactory.centerHalfCalculation.portraitRect
34 | default:
35 | calc = orientationBasedRect
36 | }
37 |
38 | return calc(visibleFrameOfScreen)
39 | }
40 |
41 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
42 | var rect = visibleFrameOfScreen
43 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
44 | rect.origin.x = visibleFrameOfScreen.minX + (rect.width * 2)
45 | return RectResult(rect, subAction: .centerRightFourth)
46 | }
47 |
48 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
49 | var rect = visibleFrameOfScreen
50 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
51 | rect.origin.y = visibleFrameOfScreen.minY + visibleFrameOfScreen.height - (rect.height * 3.0)
52 | return RectResult(rect, subAction: .centerBottomFourth)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopCenterLeftEighthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopCenterLeftEighthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Johannes Trussell Rasch on 2022-02-18.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopCenterLeftEighthCalculation: WindowCalculation, OrientationAware, EighthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .topCenterLeftEighth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
39 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
40 | return RectResult(rect, subAction: .topCenterLeftEighth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
47 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
48 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
49 | return RectResult(rect, subAction: .topCenterLeftEighth)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopCenterNinthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopCenterNinthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopCenterNinthCalculation: WindowCalculation, OrientationAware, NinthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .topCenterNinth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
38 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
39 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
40 | return RectResult(rect, subAction: .topCenterNinth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
48 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
49 | return RectResult(rect, subAction: .topCenterNinth)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopCenterRightEighthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopCenterRightEighthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Johannes Trussell Rasch on 2022-02-18.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopCenterRightEighthCalculation: WindowCalculation, OrientationAware, EighthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .topCenterRightEighth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
39 | rect.origin.x = visibleFrameOfScreen.minX + (2.0 * rect.width)
40 | return RectResult(rect, subAction: .topCenterRightEighth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
47 | rect.origin.y = visibleFrameOfScreen.maxY - (visibleFrameOfScreen.height / 2.0)
48 | rect.origin.x = visibleFrameOfScreen.minX
49 | return RectResult(rect, subAction: .topCenterRightEighth)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopHalfCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopHalfCalculation.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/14/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopHalfCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | if params.lastAction == nil || !Defaults.subsequentExecutionMode.resizes {
16 | return calculateFirstRect(params)
17 | }
18 |
19 | return calculateRepeatedRect(params)
20 | }
21 |
22 | func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult {
23 | let visibleFrameOfScreen = params.visibleFrameOfScreen
24 |
25 | var rect = visibleFrameOfScreen
26 | rect.size.height = floor(visibleFrameOfScreen.height * CGFloat(fraction))
27 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
28 | return RectResult(rect)
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopLeftEighthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopLeftEighthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Johannes Trussell Rasch on 2022-02-18.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopLeftEighthCalculation: WindowCalculation, OrientationAware, EighthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .topLeftEighth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
39 | rect.origin.x = visibleFrameOfScreen.minX
40 | return RectResult(rect, subAction: .topLeftEighth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
47 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
48 | rect.origin.x = visibleFrameOfScreen.minX
49 | return RectResult(rect, subAction: .topLeftEighth)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopLeftNinthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopLeftNinthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopLeftNinthCalculation: WindowCalculation, OrientationAware, NinthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .topLeftNinth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
38 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
39 | rect.origin.x = visibleFrameOfScreen.minX
40 | return RectResult(rect, subAction: .topLeftNinth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
48 | rect.origin.x = visibleFrameOfScreen.minX
49 | return RectResult(rect, subAction: .topLeftNinth)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopLeftSixthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopLeftSixthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 9/16/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopLeftSixthCalculation: WindowCalculation, OrientationAware, SixthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .topLeftSixth
24 | && lastSubAction != .topLeftSixthLandscape
25 | && lastSubAction != .topLeftSixthPortrait {
26 | return orientationBasedRect(visibleFrameOfScreen)
27 | }
28 |
29 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
30 | return calculation(visibleFrameOfScreen)
31 | }
32 |
33 | return orientationBasedRect(visibleFrameOfScreen)
34 | }
35 |
36 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
37 | var rect = visibleFrameOfScreen
38 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
39 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
40 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
41 | return RectResult(rect, subAction: .topLeftSixthLandscape)
42 | }
43 |
44 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
45 | var rect = visibleFrameOfScreen
46 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
47 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
48 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
49 | return RectResult(rect, subAction: .topLeftSixthPortrait)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopLeftThirdCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopLeftThirdCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopLeftThirdCalculation: WindowCalculation, OrientationAware, HorizontalThirdsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .topLeftThird {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(2.0 * visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.maxY - visibleFrameOfScreen.height / 2.0
39 | rect.origin.x = visibleFrameOfScreen.minX
40 | return RectResult(rect, subAction: .topLeftThird)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(2.0 * visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.maxY - visibleFrameOfScreen.height / 3.0
48 | rect.origin.x = visibleFrameOfScreen.minX
49 | return RectResult(rect, subAction: .topLeftThird)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopRightEighthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopRightEighthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Johannes Trussell Rasch on 2022-02-18.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopRightEighthCalculation: WindowCalculation, OrientationAware, EighthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .topRightEighth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 4.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
39 | rect.origin.x = visibleFrameOfScreen.minX + (3.0 * rect.width)
40 | return RectResult(rect, subAction: .topRightEighth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 4.0)
47 | rect.origin.y = visibleFrameOfScreen.maxY - (visibleFrameOfScreen.height / 2.0)
48 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
49 | return RectResult(rect, subAction: .topRightEighth)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopRightNinthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopRightNinthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopRightNinthCalculation: WindowCalculation, OrientationAware, NinthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .topRightNinth {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
38 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
39 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width - rect.width
40 | return RectResult(rect, subAction: .topRightNinth)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
46 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
48 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width - rect.width
49 | return RectResult(rect, subAction: .topRightNinth)
50 | }
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopRightSixthCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopRightSixthCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 9/16/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopRightSixthCalculation: WindowCalculation, OrientationAware, SixthsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 | guard Defaults.subsequentExecutionMode.value != .none,
16 | let last = params.lastAction,
17 | let lastSubAction = last.subAction
18 | else {
19 | return orientationBasedRect(visibleFrameOfScreen)
20 | }
21 |
22 | if last.action != .topRightSixth
23 | && lastSubAction != .topRightSixthLandscape
24 | && lastSubAction != .topRightSixthPortrait {
25 | return orientationBasedRect(visibleFrameOfScreen)
26 | }
27 |
28 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .left) {
29 | return calculation(visibleFrameOfScreen)
30 | }
31 |
32 | return orientationBasedRect(visibleFrameOfScreen)
33 | }
34 |
35 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
36 | var rect = visibleFrameOfScreen
37 | rect.size.width = floor(visibleFrameOfScreen.width / 3.0)
38 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
39 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width - rect.width
40 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
41 | return RectResult(rect, subAction: .topRightSixthLandscape)
42 | }
43 |
44 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
45 | var rect = visibleFrameOfScreen
46 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
47 | rect.size.height = floor(visibleFrameOfScreen.height / 3.0)
48 | rect.origin.x = visibleFrameOfScreen.minX + rect.width
49 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
50 | return RectResult(rect, subAction: .topRightSixthPortrait)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/TopRightThirdCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TopRightThirdCalculation.swift
3 | // Rectangle
4 | //
5 | // Created by Daniel Schultz on 1/2/22.
6 | // Copyright © 2022 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class TopRightThirdCalculation: WindowCalculation, OrientationAware, HorizontalThirdsRepeated {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 | let visibleFrameOfScreen = params.visibleFrameOfScreen
15 |
16 | guard Defaults.subsequentExecutionMode.value != .none,
17 | let last = params.lastAction,
18 | let lastSubAction = last.subAction
19 | else {
20 | return orientationBasedRect(visibleFrameOfScreen)
21 | }
22 |
23 | if last.action != .topRightThird {
24 | return orientationBasedRect(visibleFrameOfScreen)
25 | }
26 |
27 | if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) {
28 | return calculation(visibleFrameOfScreen)
29 | }
30 |
31 | return orientationBasedRect(visibleFrameOfScreen)
32 | }
33 |
34 | func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
35 | var rect = visibleFrameOfScreen
36 | rect.size.width = floor(2.0 * visibleFrameOfScreen.width / 3.0)
37 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
38 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
39 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width / 3.0
40 | return RectResult(rect, subAction: .topRightThird)
41 | }
42 |
43 | func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult {
44 | var rect = visibleFrameOfScreen
45 | rect.size.width = floor(visibleFrameOfScreen.width / 2.0)
46 | rect.size.height = floor(2.0 * visibleFrameOfScreen.height / 3.0)
47 | rect.origin.y = visibleFrameOfScreen.maxY - visibleFrameOfScreen.height / 3.0
48 | rect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width / 2.0
49 | return RectResult(rect, subAction: .topRightThird)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/UpperLeftCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UpperLeftCalculation.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/14/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class UpperLeftCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | if params.lastAction == nil || !Defaults.subsequentExecutionMode.resizes {
16 | return calculateFirstRect(params)
17 | }
18 |
19 | return calculateRepeatedRect(params)
20 | }
21 |
22 | func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult {
23 | let visibleFrameOfScreen = params.visibleFrameOfScreen
24 |
25 | var rect = visibleFrameOfScreen
26 |
27 | rect.size.width = floor(visibleFrameOfScreen.width * CGFloat(fraction))
28 |
29 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
30 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
31 | return RectResult(rect)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Rectangle/WindowCalculation/UpperRightCalculation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UpperRightCalculation.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/14/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class UpperRightCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation {
12 |
13 | override func calculateRect(_ params: RectCalculationParameters) -> RectResult {
14 |
15 | if params.lastAction == nil || !Defaults.subsequentExecutionMode.resizes {
16 | return calculateFirstRect(params)
17 | }
18 |
19 | return calculateRepeatedRect(params)
20 | }
21 |
22 | func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult {
23 | let visibleFrameOfScreen = params.visibleFrameOfScreen
24 |
25 | var rect = visibleFrameOfScreen
26 |
27 | rect.size.width = floor(visibleFrameOfScreen.width * CGFloat(fraction))
28 | rect.origin.x = visibleFrameOfScreen.maxX - rect.width
29 | rect.size.height = floor(visibleFrameOfScreen.height / 2.0)
30 | rect.origin.y = visibleFrameOfScreen.maxY - rect.height
31 | return RectResult(rect)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Rectangle/WindowHistory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WindowHistory.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 9/6/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class WindowHistory {
12 |
13 | var restoreRects = [CGWindowID: CGRect]() // the last window frame that the user positioned
14 |
15 | var lastRectangleActions = [CGWindowID: RectangleAction]() // the last window frame that this app positioned
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/Rectangle/WindowMover/BestEffortWindowMover.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BestEffortWindowMover.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/13/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /**
12 | * After a window has been moved and resized, if the window could not be resized small enough to fit the intended size, then some of the window may appear off the screen. The BestEffortWindowMover will move the window so that it fits entirely on the screen.
13 | */
14 |
15 | class BestEffortWindowMover: WindowMover {
16 | func moveWindowRect(_ windowRect: CGRect, frameOfScreen: CGRect, visibleFrameOfScreen: CGRect, frontmostWindowElement: AccessibilityElement?, action: WindowAction?) {
17 | guard let currentWindowRect: CGRect = frontmostWindowElement?.frame else { return }
18 | if action?.allowedToExtendOutsideCurrentScreenArea == true && !NSScreen.screensHaveSeparateSpaces { return }
19 |
20 | var adjustedWindowRect: CGRect = currentWindowRect
21 |
22 | if adjustedWindowRect.minX < visibleFrameOfScreen.minX {
23 |
24 | adjustedWindowRect.origin.x = visibleFrameOfScreen.minX
25 |
26 | } else if adjustedWindowRect.minX + adjustedWindowRect.width > visibleFrameOfScreen.minX + visibleFrameOfScreen.width {
27 |
28 | adjustedWindowRect.origin.x = visibleFrameOfScreen.minX + visibleFrameOfScreen.width - (adjustedWindowRect.width) - CGFloat(Defaults.gapSize.value)
29 | }
30 |
31 | adjustedWindowRect = adjustedWindowRect.screenFlipped
32 | if adjustedWindowRect.minY < visibleFrameOfScreen.minY {
33 |
34 | adjustedWindowRect.origin.y = visibleFrameOfScreen.minY
35 |
36 | } else if adjustedWindowRect.minY + adjustedWindowRect.height > visibleFrameOfScreen.minY + visibleFrameOfScreen.height {
37 |
38 | adjustedWindowRect.origin.y = visibleFrameOfScreen.minY + visibleFrameOfScreen.height - (adjustedWindowRect.height) - CGFloat(Defaults.gapSize.value)
39 | }
40 |
41 | adjustedWindowRect = adjustedWindowRect.screenFlipped
42 | if !currentWindowRect.equalTo(adjustedWindowRect) {
43 | frontmostWindowElement?.setFrame(adjustedWindowRect)
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Rectangle/WindowMover/CenteringFixedSizedWindowMover.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CenteringFixedSizedWindowMover.swift
3 | // Rectangle
4 | //
5 | // Created by Ryan Hanson on 1/14/20.
6 | // Copyright © 2020 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /**
12 | If the window is fixed size, center it in the proposed window area
13 | */
14 |
15 | class CenteringFixedSizedWindowMover: WindowMover {
16 |
17 | func moveWindowRect(_ windowRect: CGRect, frameOfScreen: CGRect, visibleFrameOfScreen: CGRect, frontmostWindowElement: AccessibilityElement?, action: WindowAction?) {
18 | guard let currentWindowRect: CGRect = frontmostWindowElement?.frame else { return }
19 |
20 | var adjustedWindowRect: CGRect = currentWindowRect
21 |
22 | if currentWindowRect.size.width != windowRect.width {
23 | adjustedWindowRect.origin.x = round((windowRect.width - currentWindowRect.width) / 2.0) + windowRect.minX
24 | }
25 |
26 | if currentWindowRect.size.height != windowRect.height {
27 | adjustedWindowRect.origin.y = round((windowRect.height - currentWindowRect.height) / 2.0) + windowRect.minY
28 | }
29 |
30 | if !adjustedWindowRect.equalTo(currentWindowRect) {
31 | frontmostWindowElement?.setFrame(adjustedWindowRect)
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Rectangle/WindowMover/QuantizedWindowMover.swift:
--------------------------------------------------------------------------------
1 | //
2 | // QuantizedWindowMover.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/13/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class QuantizedWindowMover: WindowMover {
12 | func moveWindowRect(_ windowRect: CGRect, frameOfScreen: CGRect, visibleFrameOfScreen: CGRect, frontmostWindowElement: AccessibilityElement?, action: WindowAction?) {
13 | guard var movedWindowRect: CGRect = frontmostWindowElement?.frame else { return }
14 | if !movedWindowRect.equalTo(windowRect) {
15 | var adjustedWindowRect: CGRect = windowRect
16 | while movedWindowRect.width > windowRect.width || movedWindowRect.height > windowRect.height {
17 |
18 | if movedWindowRect.width > windowRect.width {
19 | adjustedWindowRect.size.width -= 2
20 | }
21 | if movedWindowRect.height > windowRect.height {
22 | adjustedWindowRect.size.height -= 2
23 | }
24 | if adjustedWindowRect.width < windowRect.width * 0.85 || adjustedWindowRect.height < windowRect.height * 0.85 {
25 | break
26 | }
27 | frontmostWindowElement?.setFrame(adjustedWindowRect)
28 | if let frontMostRect = frontmostWindowElement?.frame {
29 | movedWindowRect = frontMostRect
30 | }
31 | }
32 | adjustedWindowRect.origin.x += floor((windowRect.size.width - (movedWindowRect.size.width)) / 2.0)
33 | adjustedWindowRect.origin.y += floor((windowRect.size.height - (movedWindowRect.size.height)) / 2.0)
34 | frontmostWindowElement?.setFrame(adjustedWindowRect)
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Rectangle/WindowMover/StandardWindowMover.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StandardWindowMover.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/13/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class StandardWindowMover: WindowMover {
12 | func moveWindowRect(_ windowRect: CGRect, frameOfScreen: CGRect, visibleFrameOfScreen: CGRect, frontmostWindowElement: AccessibilityElement?, action: WindowAction?) {
13 | let previousWindowRect: CGRect? = frontmostWindowElement?.frame
14 | if previousWindowRect?.isNull == true {
15 | return
16 | }
17 | frontmostWindowElement?.setFrame(windowRect)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Rectangle/WindowMover/WindowMover.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WindowMover.swift
3 | // Rectangle, Ported from Spectacle
4 | //
5 | // Created by Ryan Hanson on 6/13/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol WindowMover {
12 | func moveWindowRect(_ windowRect: CGRect, frameOfScreen: CGRect, visibleFrameOfScreen: CGRect, frontmostWindowElement: AccessibilityElement?, action: WindowAction?)
13 | }
14 |
--------------------------------------------------------------------------------
/RectangleLauncher/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // RectangleLauncher
4 | //
5 | // Created by Ryan Hanson on 6/14/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | @NSApplicationMain
12 | class AppDelegate: NSObject, NSApplicationDelegate {
13 |
14 | func applicationDidFinishLaunching(_ aNotification: Notification) {
15 | if #available(macOS 13, *) {
16 | terminate()
17 | return
18 | }
19 | let mainAppIdentifier = "com.knollsoft.Rectangle"
20 | let running = NSWorkspace.shared.runningApplications
21 | let isRunning = !running.filter({$0.bundleIdentifier == mainAppIdentifier}).isEmpty
22 |
23 | if isRunning {
24 | self.terminate()
25 | } else {
26 | let killNotification = Notification.Name("killLauncher")
27 | DistributedNotificationCenter.default().addObserver(self,
28 | selector: #selector(self.terminate),
29 | name: killNotification,
30 | object: mainAppIdentifier)
31 | let path = Bundle.main.bundlePath as NSString
32 | var components = path.pathComponents
33 | components.removeLast()
34 | components.removeLast()
35 | components.removeLast()
36 | components.append("MacOS")
37 | components.append("Rectangle")
38 | let newPath = NSString.path(withComponents: components)
39 | NSWorkspace.shared.launchApplication(newPath)
40 | }
41 | }
42 |
43 | @objc func terminate() {
44 | NSApp.terminate(nil)
45 | }
46 |
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/RectangleLauncher/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "size" : "128x128",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "size" : "128x128",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "size" : "256x256",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "size" : "256x256",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "size" : "512x512",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "size" : "512x512",
51 | "scale" : "2x"
52 | }
53 | ],
54 | "info" : {
55 | "version" : 1,
56 | "author" : "xcode"
57 | }
58 | }
--------------------------------------------------------------------------------
/RectangleLauncher/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/RectangleLauncher/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSApplicationCategoryType
24 | public.app-category.utilities
25 | LSBackgroundOnly
26 |
27 | LSMinimumSystemVersion
28 | $(MACOSX_DEPLOYMENT_TARGET)
29 | NSHumanReadableCopyright
30 | Copyright © 2019 Ryan Hanson. All rights reserved.
31 | NSMainStoryboardFile
32 | Main
33 | NSPrincipalClass
34 | NSApplication
35 |
36 |
37 |
--------------------------------------------------------------------------------
/RectangleLauncher/RectangleLauncher.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/RectangleLauncher/RectangleLauncherRelease.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/RectangleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/RectangleTests/RectangleTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RectangleTests.swift
3 | // RectangleTests
4 | //
5 | // Created by Ryan Hanson on 6/11/19.
6 | // Copyright © 2019 Ryan Hanson. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Rectangle
11 |
12 | class RectangleTests: XCTestCase {
13 |
14 | override func setUp() {
15 | // Put setup code here. This method is called before the invocation of each test method in the class.
16 | }
17 |
18 | override func tearDown() {
19 | // Put teardown code here. This method is called after the invocation of each test method in the class.
20 | }
21 |
22 | func testExample() {
23 | // This is an example of a functional test case.
24 | // Use XCTAssert and related functions to verify your tests produce the correct results.
25 | }
26 |
27 | func testPerformanceExample() {
28 | // This is an example of a performance test case.
29 | self.measure {
30 | // Put the code you want to measure the time of here.
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------