From 6c71ab31eb7f02d5e5c1b558775dae0f10f598e0 Mon Sep 17 00:00:00 2001 From: Ryan Hanson Date: Tue, 14 Jan 2020 17:11:37 +0100 Subject: [PATCH] Added gaps --- Rectangle.xcodeproj/project.pbxproj | 4 ++ Rectangle/Defaults.swift | 1 + Rectangle/WindowAction.swift | 10 +++ .../WindowCalculation/GapCalculation.swift | 68 +++++++++++++++++++ .../WindowCalculation/WindowCalculation.swift | 2 +- Rectangle/WindowManager.swift | 7 +- 6 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 Rectangle/WindowCalculation/GapCalculation.swift diff --git a/Rectangle.xcodeproj/project.pbxproj b/Rectangle.xcodeproj/project.pbxproj index 2633c7de0..2cbf06ccb 100644 --- a/Rectangle.xcodeproj/project.pbxproj +++ b/Rectangle.xcodeproj/project.pbxproj @@ -67,6 +67,7 @@ 98C2755E231FF6A9009B9292 /* EventMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98C2755D231FF6A9009B9292 /* EventMonitor.swift */; }; 98C27561231FFA5F009B9292 /* SnappingManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98C27560231FFA5F009B9292 /* SnappingManager.swift */; }; 98C275672322E2DA009B9292 /* WindowHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98C275662322E2DA009B9292 /* WindowHistory.swift */; }; + 98C6DEF023CE191700CC0C1E /* GapCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98C6DEEF23CE191700CC0C1E /* GapCalculation.swift */; }; 98FA9497235A2D7600F95C4F /* RepeatedExecutionsCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98FA9496235A2D7600F95C4F /* RepeatedExecutionsCalculation.swift */; }; CC0B7937429AC28C21ABF5B4 /* Pods_RectangleLauncher.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2D8480CC730811C953FC1B6 /* Pods_RectangleLauncher.framework */; }; F0A0DFB36FCC3FCE6E184500 /* Pods_Rectangle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20A533B9F2D3215AC7B85D1F /* Pods_Rectangle.framework */; }; @@ -188,6 +189,7 @@ 98C2755D231FF6A9009B9292 /* EventMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventMonitor.swift; sourceTree = ""; }; 98C27560231FFA5F009B9292 /* SnappingManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnappingManager.swift; sourceTree = ""; }; 98C275662322E2DA009B9292 /* WindowHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowHistory.swift; sourceTree = ""; }; + 98C6DEEF23CE191700CC0C1E /* GapCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GapCalculation.swift; sourceTree = ""; }; 98ED1C722393DEE600CD0955 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Main.strings; sourceTree = ""; }; 98ED1C732393DEE600CD0955 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Main.strings; sourceTree = ""; }; 98ED1C742393DEF200CD0955 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Main.strings"; sourceTree = ""; }; @@ -299,6 +301,7 @@ 988D067C22EB4E17004EABD7 /* AlmostMaximizeCalculation.swift */, 98C1008D230B9EF6006E5344 /* NextPrevDisplayCalculation.swift */, 98FA9496235A2D7600F95C4F /* RepeatedExecutionsCalculation.swift */, + 98C6DEEF23CE191700CC0C1E /* GapCalculation.swift */, ); path = WindowCalculation; sourceTree = ""; @@ -730,6 +733,7 @@ 9824702C22AFA22E0037B409 /* AccessibilityWindowController.swift in Sources */, 988D066122EB4C7C004EABD7 /* FirstThirdCalculation.swift in Sources */, 988D067F22EB4EDE004EABD7 /* MoveLeftRightCalculation.swift in Sources */, + 98C6DEF023CE191700CC0C1E /* GapCalculation.swift in Sources */, 98910B3E231130AF0066EC23 /* SettingsViewController.swift in Sources */, 9824700D22AF9B7D0037B409 /* AppDelegate.swift in Sources */, 9824704F22B189250037B409 /* BestEffortWindowMover.swift in Sources */, diff --git a/Rectangle/Defaults.swift b/Rectangle/Defaults.swift index 4fedc3bbd..8374b1c29 100644 --- a/Rectangle/Defaults.swift +++ b/Rectangle/Defaults.swift @@ -18,6 +18,7 @@ class Defaults { static let windowSnapping = OptionalBoolDefault(key: "windowSnapping") static let almostMaximizeHeight = FloatDefault(key: "almostMaximizeHeight") static let almostMaximizeWidth = FloatDefault(key: "almostMaximizeWidth") + static let gapSize = FloatDefault(key: "gapSize") } class BoolDefault { diff --git a/Rectangle/WindowAction.swift b/Rectangle/WindowAction.swift index 62cce4d75..ed1d2380a 100644 --- a/Rectangle/WindowAction.swift +++ b/Rectangle/WindowAction.swift @@ -279,6 +279,16 @@ enum WindowAction: Int { } } + var gapEdge: Edge { + switch self { + case .leftHalf: return .right + case .rightHalf: return .left + case .bottomHalf: return .bottom + case .topHalf: return .top + default: + return .none + } + } } struct Shortcut { diff --git a/Rectangle/WindowCalculation/GapCalculation.swift b/Rectangle/WindowCalculation/GapCalculation.swift new file mode 100644 index 000000000..4b7825efe --- /dev/null +++ b/Rectangle/WindowCalculation/GapCalculation.swift @@ -0,0 +1,68 @@ +// +// GapCalculation.swift +// Rectangle +// +// Created by Ryan Hanson on 1/14/20. +// Copyright © 2020 Ryan Hanson. All rights reserved. +// + +import Foundation + +class GapCalculation { + + static func applyGaps(_ rect: CGRect, sharedEdges: Edge = .none, gapSize: Float) -> CGRect { + + let cgGapSize = CGFloat(gapSize) + var withGaps = rect.insetBy(dx: cgGapSize, dy: cgGapSize) + + if (sharedEdges.contains(.left)) { + withGaps = CGRect( + x: withGaps.origin.x - (cgGapSize / 2), + y: withGaps.origin.y, + width: withGaps.width + (cgGapSize / 2), + height: withGaps.height + ) + } + + if (sharedEdges.contains(.right)) { + withGaps = CGRect( + x: withGaps.origin.x, + y: withGaps.origin.y, + width: withGaps.width + (cgGapSize / 2), + height: withGaps.height + ) + } + + if (sharedEdges.contains(.top)) { + withGaps = CGRect( + x: withGaps.origin.x, + y: withGaps.origin.y - (cgGapSize / 2), + width: withGaps.width, + height: withGaps.height + (cgGapSize / 2) + ) + } + + if (sharedEdges.contains(.bottom)) { + withGaps = CGRect( + x: withGaps.origin.x, + y: withGaps.origin.y, + width: withGaps.width, + height: withGaps.height + (cgGapSize / 2) + ) + } + + return withGaps + } +} + +struct Edge: OptionSet { + let rawValue: Int + + static let left = Edge(rawValue: 1 << 0) + static let right = Edge(rawValue: 1 << 1) + static let top = Edge(rawValue: 1 << 2) + static let bottom = Edge(rawValue: 1 << 3) + + static let all: Edge = [.left, .right, .top, .bottom] + static let none: Edge = [] +} diff --git a/Rectangle/WindowCalculation/WindowCalculation.swift b/Rectangle/WindowCalculation/WindowCalculation.swift index eb937ea19..c2b4bb536 100644 --- a/Rectangle/WindowCalculation/WindowCalculation.swift +++ b/Rectangle/WindowCalculation/WindowCalculation.swift @@ -44,7 +44,7 @@ extension WindowCalculation { } struct WindowCalculationResult { - let rect: CGRect + var rect: CGRect let screen: NSScreen let resultingAction: WindowAction } diff --git a/Rectangle/WindowManager.swift b/Rectangle/WindowManager.swift index b86c3c45c..17ff4cc46 100644 --- a/Rectangle/WindowManager.swift +++ b/Rectangle/WindowManager.swift @@ -15,6 +15,7 @@ class WindowManager { private let fixedSizeWindowMoverChain: [WindowMover] private let windowCalculationFactory: WindowCalculationFactory private let windowHistory: WindowHistory + private let gapSize = Defaults.gapSize.value init(windowCalculationFactory: WindowCalculationFactory, windowHistory: WindowHistory) { self.windowCalculationFactory = windowCalculationFactory @@ -85,10 +86,14 @@ class WindowManager { let windowCalculation = windowCalculationFactory.calculation(for: action) - guard let calcResult = windowCalculation?.calculate(currentNormalizedRect, lastAction: lastRectangleAction, usableScreens: usableScreens, action: action) else { + guard var calcResult = windowCalculation?.calculate(currentNormalizedRect, lastAction: lastRectangleAction, usableScreens: usableScreens, action: action) else { NSSound.beep() return } + + if gapSize > 0, calcResult.resultingAction.gapEdge != .none { + calcResult.rect = GapCalculation.applyGaps(calcResult.rect, sharedEdges: calcResult.resultingAction.gapEdge, gapSize: gapSize) + } let newNormalizedRect = AccessibilityElement.normalizeCoordinatesOf(calcResult.rect, frameOfScreen: usableScreens.frameOfCurrentScreen)