diff --git a/Rectangle.xcodeproj/project.pbxproj b/Rectangle.xcodeproj/project.pbxproj index 7f0c0e60..bd87e200 100644 --- a/Rectangle.xcodeproj/project.pbxproj +++ b/Rectangle.xcodeproj/project.pbxproj @@ -119,6 +119,7 @@ 98FA9497235A2D7600F95C4F /* RepeatedExecutionsCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98FA9496235A2D7600F95C4F /* RepeatedExecutionsCalculation.swift */; }; 98FD7C5F2687BC14009E9DAF /* FirstThreeFourthsCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98FD7C5E2687BC14009E9DAF /* FirstThreeFourthsCalculation.swift */; }; 98FD7C612687BCB6009E9DAF /* LastThreeFourthsCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98FD7C602687BCB6009E9DAF /* LastThreeFourthsCalculation.swift */; }; + 9FF740232E34DE9000D22955 /* CenterThreeFourthsCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF740222E34DE9000D22955 /* CenterThreeFourthsCalculation.swift */; }; AA040C67290B2640003181D5 /* RunLoopThread.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA040C66290B2640003181D5 /* RunLoopThread.swift */; }; AA0AC000291C1B5E00D125D2 /* CGExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0ABFFF291C1B5E00D125D2 /* CGExtension.swift */; }; AA0AC002291C1B9100D125D2 /* AXExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0AC001291C1B9100D125D2 /* AXExtension.swift */; }; @@ -296,6 +297,7 @@ 98FA9496235A2D7600F95C4F /* RepeatedExecutionsCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatedExecutionsCalculation.swift; sourceTree = ""; }; 98FD7C5E2687BC14009E9DAF /* FirstThreeFourthsCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstThreeFourthsCalculation.swift; sourceTree = ""; }; 98FD7C602687BCB6009E9DAF /* LastThreeFourthsCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastThreeFourthsCalculation.swift; sourceTree = ""; }; + 9FF740222E34DE9000D22955 /* CenterThreeFourthsCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenterThreeFourthsCalculation.swift; sourceTree = ""; }; AA040C66290B2640003181D5 /* RunLoopThread.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunLoopThread.swift; sourceTree = ""; }; AA0ABFFF291C1B5E00D125D2 /* CGExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGExtension.swift; sourceTree = ""; }; AA0AC001291C1B9100D125D2 /* AXExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AXExtension.swift; sourceTree = ""; }; @@ -402,6 +404,7 @@ 982140E922B7DA3100ABFB3F /* WindowCalculation */ = { isa = PBXGroup; children = ( + 9FF740222E34DE9000D22955 /* CenterThreeFourthsCalculation.swift */, 74804F0A2E25521C009F1F7D /* CenterTwoThirdsCalculation.swift */, 98A009AA2512491300CFBF0C /* CenterHalfCalculation.swift */, 98A009AC2512498000CFBF0C /* FirstFourthCalculation.swift */, @@ -890,6 +893,7 @@ 9821402722B3888100ABFB3F /* ChangeSizeCalculation.swift in Sources */, 6490B39927BF97BB0056C220 /* TopCenterRightEighthCalculation.swift in Sources */, 98B3559823CE025700E410E0 /* CenteringFixedSizedWindowMover.swift in Sources */, + 9FF740232E34DE9000D22955 /* CenterThreeFourthsCalculation.swift in Sources */, 729E0A982AFF76B1006E2F48 /* CenterProminentlyCalculation.swift in Sources */, 9824704E22B189250037B409 /* QuantizedWindowMover.swift in Sources */, AA536C2729005DD000579AC6 /* TimeoutCache.swift in Sources */, diff --git a/Rectangle/Assets.xcassets/WindowPositions/centerThreeFourthsTemplate.imageset/Contents.json b/Rectangle/Assets.xcassets/WindowPositions/centerThreeFourthsTemplate.imageset/Contents.json new file mode 100644 index 00000000..d705533e --- /dev/null +++ b/Rectangle/Assets.xcassets/WindowPositions/centerThreeFourthsTemplate.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "centerThreeFourthsTemplate.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/Rectangle/Assets.xcassets/WindowPositions/centerThreeFourthsTemplate.imageset/centerThreeFourthsTemplate.png b/Rectangle/Assets.xcassets/WindowPositions/centerThreeFourthsTemplate.imageset/centerThreeFourthsTemplate.png new file mode 100644 index 00000000..92db77a4 Binary files /dev/null and b/Rectangle/Assets.xcassets/WindowPositions/centerThreeFourthsTemplate.imageset/centerThreeFourthsTemplate.png differ diff --git a/Rectangle/Assets.xcassets/WindowPositions/centerTwoThirdsTemplate.imageset/centerTwoThirdsTemplate.png b/Rectangle/Assets.xcassets/WindowPositions/centerTwoThirdsTemplate.imageset/centerTwoThirdsTemplate.png index 3056b454..b6ad0dcb 100644 Binary files a/Rectangle/Assets.xcassets/WindowPositions/centerTwoThirdsTemplate.imageset/centerTwoThirdsTemplate.png and b/Rectangle/Assets.xcassets/WindowPositions/centerTwoThirdsTemplate.imageset/centerTwoThirdsTemplate.png differ diff --git a/Rectangle/Base.lproj/Main.storyboard b/Rectangle/Base.lproj/Main.storyboard index 02964244..4c95ce0e 100644 --- a/Rectangle/Base.lproj/Main.storyboard +++ b/Rectangle/Base.lproj/Main.storyboard @@ -319,14 +319,14 @@ - + - + - + @@ -1311,10 +1311,10 @@ - + - + @@ -1340,13 +1340,13 @@ - + - + - + @@ -1395,7 +1395,7 @@ - + @@ -1444,7 +1444,7 @@ - + @@ -1493,7 +1493,7 @@ - + @@ -1542,7 +1542,7 @@ - + @@ -1591,7 +1591,7 @@ - + @@ -1640,14 +1640,14 @@ - + - + @@ -1696,7 +1696,7 @@ - + @@ -1745,7 +1745,7 @@ - + @@ -1794,7 +1794,7 @@ - + @@ -1843,7 +1843,7 @@ - + @@ -1891,6 +1891,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1955,6 +2004,7 @@ + @@ -1970,10 +2020,11 @@ + - + @@ -2550,6 +2601,7 @@ + @@ -4348,6 +4400,7 @@ DQ + diff --git a/Rectangle/PrefsWindow/PrefsViewController.swift b/Rectangle/PrefsWindow/PrefsViewController.swift index bdf92001..04ce8d40 100644 --- a/Rectangle/PrefsWindow/PrefsViewController.swift +++ b/Rectangle/PrefsWindow/PrefsViewController.swift @@ -55,6 +55,7 @@ class PrefsViewController: NSViewController { @IBOutlet weak var thirdFourthShortcutView: MASShortcutView! @IBOutlet weak var lastFourthShortcutView: MASShortcutView! @IBOutlet weak var firstThreeFourthsShortcutView: MASShortcutView! + @IBOutlet weak var centerThreeFourthsShortcutView: MASShortcutView! @IBOutlet weak var lastThreeFourthsShortcutView: MASShortcutView! @IBOutlet weak var topLeftSixthShortcutView: MASShortcutView! @@ -105,6 +106,7 @@ class PrefsViewController: NSViewController { .thirdFourth: thirdFourthShortcutView, .lastFourth: lastFourthShortcutView, .firstThreeFourths: firstThreeFourthsShortcutView, + .centerThreeFourths: centerThreeFourthsShortcutView, .lastThreeFourths: lastThreeFourthsShortcutView, .topLeftSixth: topLeftSixthShortcutView, .topCenterSixth: topCenterSixthShortcutView, diff --git a/Rectangle/WindowAction.swift b/Rectangle/WindowAction.swift index 7e70c64d..e0ab7397 100644 --- a/Rectangle/WindowAction.swift +++ b/Rectangle/WindowAction.swift @@ -97,7 +97,8 @@ enum WindowAction: Int, Codable { smallerWidth = 81, largerHeight = 82, smallerHeight = 83, - centerTwoThirds = 84 + centerTwoThirds = 84, + centerThreeFourths = 85 // Order matters here - it's used in the menu static let active = [leftHalf, rightHalf, centerHalf, topHalf, bottomHalf, @@ -107,7 +108,7 @@ enum WindowAction: Int, Codable { center, centerProminently, restore, nextDisplay, previousDisplay, moveLeft, moveRight, moveUp, moveDown, - firstFourth, secondFourth, thirdFourth, lastFourth, firstThreeFourths, lastThreeFourths, + firstFourth, secondFourth, thirdFourth, lastFourth, firstThreeFourths, centerThreeFourths, lastThreeFourths, topLeftSixth, topCenterSixth, topRightSixth, bottomLeftSixth, bottomCenterSixth, bottomRightSixth, specified, reverseAll, topLeftNinth, topCenterNinth, topRightNinth, @@ -188,6 +189,7 @@ enum WindowAction: Int, Codable { case .thirdFourth: return "thirdFourth" case .lastFourth: return "lastFourth" case .firstThreeFourths: return "firstThreeFourths" + case .centerThreeFourths: return "centerThreeFourths" case .lastThreeFourths: return "lastThreeFourths" case .topLeftSixth: return "topLeftSixth" case .topCenterSixth: return "topCenterSixth" @@ -343,6 +345,9 @@ enum WindowAction: Int, Codable { case .firstThreeFourths: key = "T9Z-QF-gwc.title" value = "First Three Fourths" + case .centerThreeFourths: + key = "Vph-Z0-euH.title" + value = "Center Three Fourths" case .lastThreeFourths: key = "nwX-h6-fwm.title" value = "Last Three Fourths" @@ -509,6 +514,7 @@ enum WindowAction: Int, Codable { case .thirdFourth: return NSImage(imageLiteralResourceName: "centerRightFourthTemplate") case .lastFourth: return NSImage(imageLiteralResourceName: "rightFourthTemplate") case .firstThreeFourths: return NSImage(imageLiteralResourceName: "firstThreeFourthsTemplate") + case .centerThreeFourths: return NSImage(imageLiteralResourceName: "centerThreeFourthsTemplate") case .lastThreeFourths: return NSImage(imageLiteralResourceName: "lastThreeFourthsTemplate") case .topLeftSixth: return NSImage(imageLiteralResourceName: "topLeftSixthTemplate") case .topCenterSixth: return NSImage(imageLiteralResourceName: "topCenterSixthTemplate") @@ -581,7 +587,7 @@ enum WindowAction: Int, Codable { var gapsApplicable: Dimension { switch self { case .leftHalf, .rightHalf, .bottomHalf, .topHalf, .centerHalf, .bottomLeft, .bottomRight, .topLeft, .topRight, .firstThird, .firstTwoThirds, .centerThird, .centerTwoThirds, .lastTwoThirds, .lastThird, - .firstFourth, .secondFourth, .thirdFourth, .lastFourth, .firstThreeFourths, .lastThreeFourths, .topLeftSixth, .topCenterSixth, .topRightSixth, .bottomLeftSixth, .bottomCenterSixth, .bottomRightSixth, + .firstFourth, .secondFourth, .thirdFourth, .lastFourth, .firstThreeFourths, .centerThreeFourths, .lastThreeFourths, .topLeftSixth, .topCenterSixth, .topRightSixth, .bottomLeftSixth, .bottomCenterSixth, .bottomRightSixth, .topLeftNinth, .topCenterNinth, .topRightNinth, .middleLeftNinth, .middleCenterNinth, .middleRightNinth, .bottomLeftNinth, .bottomCenterNinth, .bottomRightNinth, .topLeftThird, .topRightThird, .bottomLeftThird, .bottomRightThird, .topLeftEighth, .topCenterLeftEighth, .topCenterRightEighth, .topRightEighth, @@ -605,7 +611,7 @@ enum WindowAction: Int, Codable { var category: WindowActionCategory? { // used to specify a submenu switch self { - case .firstFourth, .secondFourth, .thirdFourth, .lastFourth, .firstThreeFourths, .lastThreeFourths: return .fourths + case .firstFourth, .secondFourth, .thirdFourth, .lastFourth, .firstThreeFourths, .centerThreeFourths, .lastThreeFourths: return .fourths case .topLeftSixth, .topCenterSixth, .topRightSixth, .bottomLeftSixth, .bottomCenterSixth, .bottomRightSixth: return .sixths case .moveUp, .moveDown, .moveLeft, .moveRight: return .move default: return nil @@ -652,6 +658,8 @@ enum SubWindowAction { bottomThreeFourths, leftThreeFourths, topThreeFourths, + centerVerticalThreeFourths, + centerHorizontalThreeFourths, centerVerticalHalf, centerHorizontalHalf, @@ -733,6 +741,8 @@ enum SubWindowAction { case .bottomThreeFourths: return .top case .leftThreeFourths: return .right case .topThreeFourths: return .bottom + case .centerVerticalThreeFourths: return [.right, .left] + case .centerHorizontalThreeFourths: return [.top, .bottom] case .centerVerticalHalf: return [.right, .left] case .centerHorizontalHalf: return [.top, .bottom] case .topLeftSixthLandscape: return [.right, .bottom] diff --git a/Rectangle/WindowCalculation/CenterThreeFourthsCalculation.swift b/Rectangle/WindowCalculation/CenterThreeFourthsCalculation.swift new file mode 100644 index 00000000..4820a341 --- /dev/null +++ b/Rectangle/WindowCalculation/CenterThreeFourthsCalculation.swift @@ -0,0 +1,36 @@ +// +// CenterThreeFourthsCalculation.swift +// Rectangle +// +// Created by Tom Grimwood-Taylor on 26/07/2025. +// Copyright © 2025 Ryan Hanson. All rights reserved. +// + +import Foundation + +class CenterThreeFourthsCalculation: WindowCalculation, OrientationAware { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.origin.x = visibleFrameOfScreen.minX + floor(visibleFrameOfScreen.width / 4.0) / 2 + rect.origin.y = visibleFrameOfScreen.minY + rect.size.width = visibleFrameOfScreen.width / 4.0 * 3 + rect.size.height = visibleFrameOfScreen.height + return RectResult(rect, subAction: .centerVerticalThreeFourths) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.origin.x = visibleFrameOfScreen.minX + rect.origin.y = visibleFrameOfScreen.minY + floor(visibleFrameOfScreen.height / 4.0) / 2 + rect.size.width = visibleFrameOfScreen.width + rect.size.height = visibleFrameOfScreen.height / 4.0 * 3 + return RectResult(rect, subAction: .centerHorizontalThreeFourths) + } +} + diff --git a/Rectangle/WindowCalculation/WindowCalculation.swift b/Rectangle/WindowCalculation/WindowCalculation.swift index d739c2c2..e410e266 100644 --- a/Rectangle/WindowCalculation/WindowCalculation.swift +++ b/Rectangle/WindowCalculation/WindowCalculation.swift @@ -153,6 +153,7 @@ class WindowCalculationFactory { static let thirdFourthCalculation = ThirdFourthCalculation() static let lastFourthCalculation = LastFourthCalculation() static let firstThreeFourthsCalculation = FirstThreeFourthsCalculation() + static let centerThreeFourthsCalculation = CenterThreeFourthsCalculation() static let lastThreeFourthsCalculation = LastThreeFourthsCalculation() static let topLeftSixthCalculation = TopLeftSixthCalculation() static let topCenterSixthCalculation = TopCenterSixthCalculation() @@ -223,6 +224,7 @@ class WindowCalculationFactory { .thirdFourth: thirdFourthCalculation, .lastFourth: lastFourthCalculation, .firstThreeFourths: firstThreeFourthsCalculation, + .centerThreeFourths: centerThreeFourthsCalculation, .lastThreeFourths: lastThreeFourthsCalculation, .topLeftSixth: topLeftSixthCalculation, .topCenterSixth: topCenterSixthCalculation, diff --git a/Rectangle/mul.lproj/Main.xcstrings b/Rectangle/mul.lproj/Main.xcstrings index 1419a68e..a2a95cde 100644 --- a/Rectangle/mul.lproj/Main.xcstrings +++ b/Rectangle/mul.lproj/Main.xcstrings @@ -45004,6 +45004,24 @@ } } }, + "Vph-Z0-euH.title" : { + "comment" : "Class = \"NSTextFieldCell\"; title = \"Center Three Fourths\"; ObjectID = \"Vph-Z0-euH\";", + "extractionState" : "extracted_with_value", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Center Three Fourths" + } + }, + "en-GB" : { + "stringUnit" : { + "state" : "translated", + "value" : "Centre Three Quarters" + } + } + } + }, "w0m-vy-SC9.title" : { "comment" : "Class = \"NSMenu\"; title = \"Ligatures\"; ObjectID = \"w0m-vy-SC9\";", "extractionState" : "manual", @@ -49908,4 +49926,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file