diff --git a/Rectangle.xcodeproj/project.pbxproj b/Rectangle.xcodeproj/project.pbxproj index 9d82e53a..d29a7ce9 100644 --- a/Rectangle.xcodeproj/project.pbxproj +++ b/Rectangle.xcodeproj/project.pbxproj @@ -19,6 +19,36 @@ 6490B39D27BF984D0056C220 /* BottomCenterLeftEighthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6490B39C27BF984D0056C220 /* BottomCenterLeftEighthCalculation.swift */; }; 6490B39F27BF98840056C220 /* BottomCenterRightEighthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6490B39E27BF98840056C220 /* BottomCenterRightEighthCalculation.swift */; }; 6490B3A127BF98C70056C220 /* BottomRightEighthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6490B3A027BF98C70056C220 /* BottomRightEighthCalculation.swift */; }; + 7EC9E3BAD5BC57E49A7BCEE5 /* TwelfthsRepeated.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3592F8E85CE82B8FA662A31 /* TwelfthsRepeated.swift */; }; + BAB3F495AD1F3454FAA31AFB /* TopLeftTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9FDCA1333C1BF6930A8D7F3 /* TopLeftTwelfthCalculation.swift */; }; + 924919761FC491952752A147 /* TopCenterLeftTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9698D1D9EE0180D7C4468304 /* TopCenterLeftTwelfthCalculation.swift */; }; + 14DBE979E4453E13A3BF5C17 /* TopCenterRightTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4D034DBD7EFAC4CF5F8D67B /* TopCenterRightTwelfthCalculation.swift */; }; + F4EED30B47FB6C55EA937254 /* TopRightTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E8357E928530D10A806F3CD /* TopRightTwelfthCalculation.swift */; }; + 05DBEA44B55E6F8C5FC3D6E0 /* MiddleLeftTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEABF10E66D648DDB37DABBA /* MiddleLeftTwelfthCalculation.swift */; }; + 9FDA3D672AE475B83CA1A34A /* MiddleCenterLeftTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5070DE9100E45D374053F0C2 /* MiddleCenterLeftTwelfthCalculation.swift */; }; + DCD3CF2993E9AFAF30820117 /* MiddleCenterRightTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCF2AC59501448BD3BAA16EC /* MiddleCenterRightTwelfthCalculation.swift */; }; + 8B1D14E3A55936EBCCC1E807 /* MiddleRightTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA84AB4DB9E7EEFCE50AA6D8 /* MiddleRightTwelfthCalculation.swift */; }; + BF9871B3BCF0E652444E0C56 /* BottomLeftTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 246168B345ECE6C375ACEEB7 /* BottomLeftTwelfthCalculation.swift */; }; + 52953B57D48A4F110779E9BD /* BottomCenterLeftTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FE3EBE50F91F9EE2989279 /* BottomCenterLeftTwelfthCalculation.swift */; }; + 666598377754D51045353CD0 /* BottomCenterRightTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A362206B9F76C269D8F469 /* BottomCenterRightTwelfthCalculation.swift */; }; + 15E8CA7F6AC3EA2C4FB1424C /* BottomRightTwelfthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D038C68560DC11F14496F6 /* BottomRightTwelfthCalculation.swift */; }; + B6366EE24FA928086846969B /* SixteenthsRepeated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16B4044DB4809116039F96EB /* SixteenthsRepeated.swift */; }; + 3FA1D2E6C9B4623227F680CF /* TopLeftSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6294D2CB6E3D8ED982F418AE /* TopLeftSixteenthCalculation.swift */; }; + A0844B53B14365D0278BC124 /* TopCenterLeftSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BE9E5E2C8BA2590DD0B6F59 /* TopCenterLeftSixteenthCalculation.swift */; }; + A32D3739AA16C537F6427C4F /* TopCenterRightSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 918F847FF15D524B6DB2E6DA /* TopCenterRightSixteenthCalculation.swift */; }; + F51A7467767F8EAF97321A00 /* TopRightSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD222258713B13274FB651B0 /* TopRightSixteenthCalculation.swift */; }; + D8644560FF112B0748CE1975 /* UpperMiddleLeftSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E2DBE0733F31BC159BC99C /* UpperMiddleLeftSixteenthCalculation.swift */; }; + E791B00A88D90C24A4C3D2D1 /* UpperMiddleCenterLeftSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B8CA6901E6FE134E930135B /* UpperMiddleCenterLeftSixteenthCalculation.swift */; }; + 895C73559E1ACEFBBE8DC32D /* UpperMiddleCenterRightSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEBF3EA35F0C110A170EAD33 /* UpperMiddleCenterRightSixteenthCalculation.swift */; }; + 0F29956694B5BB31EBDAE445 /* UpperMiddleRightSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3B5B09465C38F8B766B3C3C /* UpperMiddleRightSixteenthCalculation.swift */; }; + 562018A56BC897E769500F1F /* LowerMiddleLeftSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C796BCAA3DA5F85B55A7EE83 /* LowerMiddleLeftSixteenthCalculation.swift */; }; + 88763FEFFA3AECF8502604D6 /* LowerMiddleCenterLeftSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378C96D832D4CC6BCCF9D604 /* LowerMiddleCenterLeftSixteenthCalculation.swift */; }; + A73749B5FB00D2CC2DB08744 /* LowerMiddleCenterRightSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AE08B666CCCD1805CAB08BD /* LowerMiddleCenterRightSixteenthCalculation.swift */; }; + 4266090403BAF4B8A654A28B /* LowerMiddleRightSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87EC57F37CFD790695177AC8 /* LowerMiddleRightSixteenthCalculation.swift */; }; + F7B6C43BB57F8064F49DDBB6 /* BottomLeftSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEE147786B2CD7350FAFB700 /* BottomLeftSixteenthCalculation.swift */; }; + 9988C2A18B6AF03E09204981 /* BottomCenterLeftSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88454ABE5C62BD610AEA3EB5 /* BottomCenterLeftSixteenthCalculation.swift */; }; + 630644571003EB468CB643D8 /* BottomCenterRightSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D24EBF1F9A6209449A988E15 /* BottomCenterRightSixteenthCalculation.swift */; }; + 2D240EE416CC03AC921E3A4F /* BottomRightSixteenthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 482EA970820F37C6917FCD98 /* BottomRightSixteenthCalculation.swift */; }; 729E0A982AFF76B1006E2F48 /* CenterProminentlyCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 729E0A972AFF76B1006E2F48 /* CenterProminentlyCalculation.swift */; }; 74804F0B2E25521C009F1F7D /* CenterTwoThirdsCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74804F0A2E25521C009F1F7D /* CenterTwoThirdsCalculation.swift */; }; 7BE578EF2C5BF4EE0083DAE3 /* CycleSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BE578EE2C5BF4ED0083DAE3 /* CycleSize.swift */; }; @@ -104,6 +134,7 @@ 98A009BD251253A000CFBF0C /* BottomCenterSixthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A009BC251253A000CFBF0C /* BottomCenterSixthCalculation.swift */; }; 98A009BF251253AB00CFBF0C /* BottomRightSixthCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A009BE251253AB00CFBF0C /* BottomRightSixthCalculation.swift */; }; 98A6EDDD251F3F4A00F74B10 /* SixthsRepeated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A6EDDC251F3F4A00F74B10 /* SixthsRepeated.swift */; }; + BB0000000000000000000001 /* QuartersRepeated.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB0000000000000000000002 /* QuartersRepeated.swift */; }; 98A6EDEC2528FFC100F74B10 /* WindowActionCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A6EDEB2528FFC100F74B10 /* WindowActionCategory.swift */; }; 98B3559823CE025700E410E0 /* CenteringFixedSizedWindowMover.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98B3559723CE025700E410E0 /* CenteringFixedSizedWindowMover.swift */; }; 98BEFA482620DEDD00D9D54F /* NSImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BEFA472620DEDC00D9D54F /* NSImageExtension.swift */; }; @@ -196,6 +227,36 @@ 6490B39C27BF984D0056C220 /* BottomCenterLeftEighthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomCenterLeftEighthCalculation.swift; sourceTree = ""; }; 6490B39E27BF98840056C220 /* BottomCenterRightEighthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomCenterRightEighthCalculation.swift; sourceTree = ""; }; 6490B3A027BF98C70056C220 /* BottomRightEighthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomRightEighthCalculation.swift; sourceTree = ""; }; + F3592F8E85CE82B8FA662A31 /* TwelfthsRepeated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwelfthsRepeated.swift; sourceTree = ""; }; + D9FDCA1333C1BF6930A8D7F3 /* TopLeftTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopLeftTwelfthCalculation.swift; sourceTree = ""; }; + 9698D1D9EE0180D7C4468304 /* TopCenterLeftTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopCenterLeftTwelfthCalculation.swift; sourceTree = ""; }; + A4D034DBD7EFAC4CF5F8D67B /* TopCenterRightTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopCenterRightTwelfthCalculation.swift; sourceTree = ""; }; + 7E8357E928530D10A806F3CD /* TopRightTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopRightTwelfthCalculation.swift; sourceTree = ""; }; + EEABF10E66D648DDB37DABBA /* MiddleLeftTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiddleLeftTwelfthCalculation.swift; sourceTree = ""; }; + 5070DE9100E45D374053F0C2 /* MiddleCenterLeftTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiddleCenterLeftTwelfthCalculation.swift; sourceTree = ""; }; + BCF2AC59501448BD3BAA16EC /* MiddleCenterRightTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiddleCenterRightTwelfthCalculation.swift; sourceTree = ""; }; + AA84AB4DB9E7EEFCE50AA6D8 /* MiddleRightTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiddleRightTwelfthCalculation.swift; sourceTree = ""; }; + 246168B345ECE6C375ACEEB7 /* BottomLeftTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomLeftTwelfthCalculation.swift; sourceTree = ""; }; + 71FE3EBE50F91F9EE2989279 /* BottomCenterLeftTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomCenterLeftTwelfthCalculation.swift; sourceTree = ""; }; + C1A362206B9F76C269D8F469 /* BottomCenterRightTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomCenterRightTwelfthCalculation.swift; sourceTree = ""; }; + D7D038C68560DC11F14496F6 /* BottomRightTwelfthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomRightTwelfthCalculation.swift; sourceTree = ""; }; + 16B4044DB4809116039F96EB /* SixteenthsRepeated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SixteenthsRepeated.swift; sourceTree = ""; }; + 6294D2CB6E3D8ED982F418AE /* TopLeftSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopLeftSixteenthCalculation.swift; sourceTree = ""; }; + 5BE9E5E2C8BA2590DD0B6F59 /* TopCenterLeftSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopCenterLeftSixteenthCalculation.swift; sourceTree = ""; }; + 918F847FF15D524B6DB2E6DA /* TopCenterRightSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopCenterRightSixteenthCalculation.swift; sourceTree = ""; }; + FD222258713B13274FB651B0 /* TopRightSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopRightSixteenthCalculation.swift; sourceTree = ""; }; + 84E2DBE0733F31BC159BC99C /* UpperMiddleLeftSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpperMiddleLeftSixteenthCalculation.swift; sourceTree = ""; }; + 8B8CA6901E6FE134E930135B /* UpperMiddleCenterLeftSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpperMiddleCenterLeftSixteenthCalculation.swift; sourceTree = ""; }; + BEBF3EA35F0C110A170EAD33 /* UpperMiddleCenterRightSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpperMiddleCenterRightSixteenthCalculation.swift; sourceTree = ""; }; + A3B5B09465C38F8B766B3C3C /* UpperMiddleRightSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpperMiddleRightSixteenthCalculation.swift; sourceTree = ""; }; + C796BCAA3DA5F85B55A7EE83 /* LowerMiddleLeftSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LowerMiddleLeftSixteenthCalculation.swift; sourceTree = ""; }; + 378C96D832D4CC6BCCF9D604 /* LowerMiddleCenterLeftSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LowerMiddleCenterLeftSixteenthCalculation.swift; sourceTree = ""; }; + 8AE08B666CCCD1805CAB08BD /* LowerMiddleCenterRightSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LowerMiddleCenterRightSixteenthCalculation.swift; sourceTree = ""; }; + 87EC57F37CFD790695177AC8 /* LowerMiddleRightSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LowerMiddleRightSixteenthCalculation.swift; sourceTree = ""; }; + FEE147786B2CD7350FAFB700 /* BottomLeftSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomLeftSixteenthCalculation.swift; sourceTree = ""; }; + 88454ABE5C62BD610AEA3EB5 /* BottomCenterLeftSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomCenterLeftSixteenthCalculation.swift; sourceTree = ""; }; + D24EBF1F9A6209449A988E15 /* BottomCenterRightSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomCenterRightSixteenthCalculation.swift; sourceTree = ""; }; + 482EA970820F37C6917FCD98 /* BottomRightSixteenthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomRightSixteenthCalculation.swift; sourceTree = ""; }; 729E0A972AFF76B1006E2F48 /* CenterProminentlyCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenterProminentlyCalculation.swift; sourceTree = ""; }; 74804F0A2E25521C009F1F7D /* CenterTwoThirdsCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenterTwoThirdsCalculation.swift; sourceTree = ""; }; 7BE578EE2C5BF4ED0083DAE3 /* CycleSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CycleSize.swift; sourceTree = ""; }; @@ -289,6 +350,7 @@ 98A009BC251253A000CFBF0C /* BottomCenterSixthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomCenterSixthCalculation.swift; sourceTree = ""; }; 98A009BE251253AB00CFBF0C /* BottomRightSixthCalculation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomRightSixthCalculation.swift; sourceTree = ""; }; 98A6EDDC251F3F4A00F74B10 /* SixthsRepeated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SixthsRepeated.swift; sourceTree = ""; }; + BB0000000000000000000002 /* QuartersRepeated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuartersRepeated.swift; sourceTree = ""; }; 98A6EDEB2528FFC100F74B10 /* WindowActionCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowActionCategory.swift; sourceTree = ""; }; 98B3559723CE025700E410E0 /* CenteringFixedSizedWindowMover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenteringFixedSizedWindowMover.swift; sourceTree = ""; }; 98BEFA472620DEDC00D9D54F /* NSImageExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSImageExtension.swift; sourceTree = ""; }; @@ -466,6 +528,7 @@ 98C6DEEF23CE191700CC0C1E /* GapCalculation.swift */, 9851A5C2251BEBA300ECF78C /* OrientationAware.swift */, 98A6EDDC251F3F4A00F74B10 /* SixthsRepeated.swift */, + BB0000000000000000000002 /* QuartersRepeated.swift */, 866661F1257D248A00A9CD2D /* RepeatedExecutionsInThirdsCalculation.swift */, 30166BCF24F27D6A00A38608 /* SpecifiedCalculation.swift */, D04CE31127817C9B00BD47B3 /* NinthsRepeated.swift */, @@ -492,6 +555,36 @@ 6490B39C27BF984D0056C220 /* BottomCenterLeftEighthCalculation.swift */, 6490B39E27BF98840056C220 /* BottomCenterRightEighthCalculation.swift */, 6490B3A027BF98C70056C220 /* BottomRightEighthCalculation.swift */, + F3592F8E85CE82B8FA662A31 /* TwelfthsRepeated.swift */, + D9FDCA1333C1BF6930A8D7F3 /* TopLeftTwelfthCalculation.swift */, + 9698D1D9EE0180D7C4468304 /* TopCenterLeftTwelfthCalculation.swift */, + A4D034DBD7EFAC4CF5F8D67B /* TopCenterRightTwelfthCalculation.swift */, + 7E8357E928530D10A806F3CD /* TopRightTwelfthCalculation.swift */, + 246168B345ECE6C375ACEEB7 /* BottomLeftTwelfthCalculation.swift */, + 71FE3EBE50F91F9EE2989279 /* BottomCenterLeftTwelfthCalculation.swift */, + C1A362206B9F76C269D8F469 /* BottomCenterRightTwelfthCalculation.swift */, + D7D038C68560DC11F14496F6 /* BottomRightTwelfthCalculation.swift */, + EEABF10E66D648DDB37DABBA /* MiddleLeftTwelfthCalculation.swift */, + 5070DE9100E45D374053F0C2 /* MiddleCenterLeftTwelfthCalculation.swift */, + BCF2AC59501448BD3BAA16EC /* MiddleCenterRightTwelfthCalculation.swift */, + AA84AB4DB9E7EEFCE50AA6D8 /* MiddleRightTwelfthCalculation.swift */, + 16B4044DB4809116039F96EB /* SixteenthsRepeated.swift */, + 6294D2CB6E3D8ED982F418AE /* TopLeftSixteenthCalculation.swift */, + 5BE9E5E2C8BA2590DD0B6F59 /* TopCenterLeftSixteenthCalculation.swift */, + 918F847FF15D524B6DB2E6DA /* TopCenterRightSixteenthCalculation.swift */, + FD222258713B13274FB651B0 /* TopRightSixteenthCalculation.swift */, + 84E2DBE0733F31BC159BC99C /* UpperMiddleLeftSixteenthCalculation.swift */, + 8B8CA6901E6FE134E930135B /* UpperMiddleCenterLeftSixteenthCalculation.swift */, + BEBF3EA35F0C110A170EAD33 /* UpperMiddleCenterRightSixteenthCalculation.swift */, + A3B5B09465C38F8B766B3C3C /* UpperMiddleRightSixteenthCalculation.swift */, + C796BCAA3DA5F85B55A7EE83 /* LowerMiddleLeftSixteenthCalculation.swift */, + 378C96D832D4CC6BCCF9D604 /* LowerMiddleCenterLeftSixteenthCalculation.swift */, + 8AE08B666CCCD1805CAB08BD /* LowerMiddleCenterRightSixteenthCalculation.swift */, + 87EC57F37CFD790695177AC8 /* LowerMiddleRightSixteenthCalculation.swift */, + FEE147786B2CD7350FAFB700 /* BottomLeftSixteenthCalculation.swift */, + 88454ABE5C62BD610AEA3EB5 /* BottomCenterLeftSixteenthCalculation.swift */, + D24EBF1F9A6209449A988E15 /* BottomCenterRightSixteenthCalculation.swift */, + 482EA970820F37C6917FCD98 /* BottomRightSixteenthCalculation.swift */, AA69F83B29909A95001A81AF /* RightTodoCalculation.swift */, AA69F83F2992DCB1001A81AF /* LeftTodoCalculation.swift */, B4521F922BD7CEFB00FD43CC /* ChangeWindowDimensionCalculation.swift */, @@ -991,6 +1084,7 @@ BB0B804D2EFB0AF900A9B165 /* TopVerticalThirdCalculation.swift in Sources */, 6490B39D27BF984D0056C220 /* BottomCenterLeftEighthCalculation.swift in Sources */, 98A6EDDD251F3F4A00F74B10 /* SixthsRepeated.swift in Sources */, + BB0000000000000000000001 /* QuartersRepeated.swift in Sources */, AAADE1AF28CBAB0000036331 /* WindowUtil.swift in Sources */, 98A009B72512538200CFBF0C /* TopCenterSixthCalculation.swift in Sources */, AA69F8402992DCB1001A81AF /* LeftTodoCalculation.swift in Sources */, @@ -1006,6 +1100,36 @@ D04CE30E27817AB500BD47B3 /* BottomCenterNinthCalculation.swift in Sources */, 6490B39727BF96EA0056C220 /* TopCenterLeftEighthCalculation.swift in Sources */, 9818E00D28B59205004AA524 /* CompoundSnapArea.swift in Sources */, + 7EC9E3BAD5BC57E49A7BCEE5 /* TwelfthsRepeated.swift in Sources */, + BAB3F495AD1F3454FAA31AFB /* TopLeftTwelfthCalculation.swift in Sources */, + 924919761FC491952752A147 /* TopCenterLeftTwelfthCalculation.swift in Sources */, + 14DBE979E4453E13A3BF5C17 /* TopCenterRightTwelfthCalculation.swift in Sources */, + F4EED30B47FB6C55EA937254 /* TopRightTwelfthCalculation.swift in Sources */, + BF9871B3BCF0E652444E0C56 /* BottomLeftTwelfthCalculation.swift in Sources */, + 52953B57D48A4F110779E9BD /* BottomCenterLeftTwelfthCalculation.swift in Sources */, + 666598377754D51045353CD0 /* BottomCenterRightTwelfthCalculation.swift in Sources */, + 15E8CA7F6AC3EA2C4FB1424C /* BottomRightTwelfthCalculation.swift in Sources */, + 05DBEA44B55E6F8C5FC3D6E0 /* MiddleLeftTwelfthCalculation.swift in Sources */, + 9FDA3D672AE475B83CA1A34A /* MiddleCenterLeftTwelfthCalculation.swift in Sources */, + DCD3CF2993E9AFAF30820117 /* MiddleCenterRightTwelfthCalculation.swift in Sources */, + 8B1D14E3A55936EBCCC1E807 /* MiddleRightTwelfthCalculation.swift in Sources */, + B6366EE24FA928086846969B /* SixteenthsRepeated.swift in Sources */, + 3FA1D2E6C9B4623227F680CF /* TopLeftSixteenthCalculation.swift in Sources */, + A0844B53B14365D0278BC124 /* TopCenterLeftSixteenthCalculation.swift in Sources */, + A32D3739AA16C537F6427C4F /* TopCenterRightSixteenthCalculation.swift in Sources */, + F51A7467767F8EAF97321A00 /* TopRightSixteenthCalculation.swift in Sources */, + D8644560FF112B0748CE1975 /* UpperMiddleLeftSixteenthCalculation.swift in Sources */, + E791B00A88D90C24A4C3D2D1 /* UpperMiddleCenterLeftSixteenthCalculation.swift in Sources */, + 895C73559E1ACEFBBE8DC32D /* UpperMiddleCenterRightSixteenthCalculation.swift in Sources */, + 0F29956694B5BB31EBDAE445 /* UpperMiddleRightSixteenthCalculation.swift in Sources */, + 562018A56BC897E769500F1F /* LowerMiddleLeftSixteenthCalculation.swift in Sources */, + 88763FEFFA3AECF8502604D6 /* LowerMiddleCenterLeftSixteenthCalculation.swift in Sources */, + A73749B5FB00D2CC2DB08744 /* LowerMiddleCenterRightSixteenthCalculation.swift in Sources */, + 4266090403BAF4B8A654A28B /* LowerMiddleRightSixteenthCalculation.swift in Sources */, + F7B6C43BB57F8064F49DDBB6 /* BottomLeftSixteenthCalculation.swift in Sources */, + 9988C2A18B6AF03E09204981 /* BottomCenterLeftSixteenthCalculation.swift in Sources */, + 630644571003EB468CB643D8 /* BottomCenterRightSixteenthCalculation.swift in Sources */, + 2D240EE416CC03AC921E3A4F /* BottomRightSixteenthCalculation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Rectangle/AppDelegate.swift b/Rectangle/AppDelegate.swift index 719f3bea..67bd1d70 100644 --- a/Rectangle/AppDelegate.swift +++ b/Rectangle/AppDelegate.swift @@ -37,7 +37,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { private var prevActiveAppObservation: NSKeyValueObservation? private var prevActiveApp: NSRunningApplication? - + private var additionalSizeMenuItems: [NSMenuItem] = [] + private var dynamicMenuItemCount: Int = 0 + @IBOutlet weak var mainStatusMenu: NSMenu! @IBOutlet weak var unauthorizedMenu: NSMenu! @IBOutlet weak var ignoreMenuItem: NSMenuItem! @@ -45,14 +47,13 @@ class AppDelegate: NSObject, NSApplicationDelegate { @IBOutlet weak var updatesMenuItem: NSMenuItem! @IBOutlet weak var quitMenuItem: NSMenuItem! - var eighthsMenuItem: NSMenuItem? - static var instance: AppDelegate { NSApp.delegate as! AppDelegate } func applicationDidFinishLaunching(_ aNotification: Notification) { Defaults.loadFromSupportDir() + migrateShowEighthsInMenu() checkVersion() mainStatusMenu.delegate = self @@ -77,7 +78,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { mainStatusMenu.autoenablesItems = false addWindowActionMenuItems() - + + NotificationCenter.default.addObserver(self, selector: #selector(rebuildMenu), name: .showAdditionalSizesInMenuChanged, object: nil) + updaterController = SPUStandardUpdaterController(updaterDelegate: nil, userDriverDelegate: self) checkAutoCheckForUpdates() @@ -379,6 +382,9 @@ extension AppDelegate: NSMenuDelegate { } func addWindowActionMenuItems() { + let additionalSizeCategories: Set = [.eighths, .ninths, .twelfths, .sixteenths] + let submenuOnlyWhenAdditional: Set = [.thirds, .size] + let showAdditional = Defaults.showAdditionalSizesInMenu.userEnabled var menuIndex = 0 var categoryMenus: [CategoryMenu] = [] for action in WindowAction.active { @@ -387,16 +393,23 @@ extension AppDelegate: NSMenuDelegate { newMenuItem.representedObject = action if !Defaults.showAllActionsInMenu.userEnabled, let category = action.category { - if menuIndex != 0 && action.firstInGroup { - let menu = NSMenu(title: category.displayName) - menu.autoenablesItems = false - categoryMenus.append(CategoryMenu(menu: menu, category: category)) + // When additional sizes are off, keep Thirds and Size as flat items + if submenuOnlyWhenAdditional.contains(category) && !showAdditional { + // Fall through to flat item handling below + } else { + if menuIndex != 0 && action.firstInGroup { + let menu = NSMenu(title: category.displayName) + menu.autoenablesItems = false + categoryMenus.append(CategoryMenu(menu: menu, category: category)) + } + categoryMenus.last?.menu.addItem(newMenuItem) + continue } - categoryMenus.last?.menu.addItem(newMenuItem) - continue } - - if menuIndex != 0 && action.firstInGroup { + + // Flat item - suppress extra separator for almostMaximize when Size is not a submenu + let showSeparator = action.firstInGroup && !(action == .almostMaximize && !showAdditional) + if menuIndex != 0 && showSeparator { mainStatusMenu.insertItem(NSMenuItem.separator(), at: menuIndex) menuIndex += 1 } @@ -407,31 +420,52 @@ extension AppDelegate: NSMenuDelegate { if !categoryMenus.isEmpty { mainStatusMenu.insertItem(NSMenuItem.separator(), at: menuIndex) menuIndex += 1 - - for categoryMenu in categoryMenus { + + let sortedCategoryMenus = categoryMenus.sorted { $0.category.menuOrder < $1.category.menuOrder } + for categoryMenu in sortedCategoryMenus { categoryMenu.menu.delegate = self let menuMenuItem = NSMenuItem(title: categoryMenu.category.displayName, action: nil, keyEquivalent: "") - if categoryMenu.category == .eighths { - eighthsMenuItem = menuMenuItem - eighthsMenuItem?.isHidden = !Defaults.showEighthsInMenu.userEnabled + if additionalSizeCategories.contains(categoryMenu.category) { + menuMenuItem.isHidden = !Defaults.showAdditionalSizesInMenu.userEnabled + additionalSizeMenuItems.append(menuMenuItem) } mainStatusMenu.insertItem(menuMenuItem, at: menuIndex) mainStatusMenu.setSubmenu(categoryMenu.menu, for: menuMenuItem) menuIndex += 1 } } - + mainStatusMenu.insertItem(NSMenuItem.separator(), at: menuIndex) menuIndex += 1 addTodoModeMenuItems(startingIndex: menuIndex) + // Track total dynamic items: window actions + separators + todo items (4 items + 1 separator) + dynamicMenuItemCount = menuIndex + 5 } - + + @objc func rebuildMenu() { + // Remove all dynamically added items + for _ in 0.. + diff --git a/Rectangle/Defaults.swift b/Rectangle/Defaults.swift index a6fa1ca9..c523c690 100644 --- a/Rectangle/Defaults.swift +++ b/Rectangle/Defaults.swift @@ -47,6 +47,7 @@ class Defaults { static let lastVersion = StringDefault(key: "lastVersion") static let installVersion = StringDefault(key: "installVersion") static let showAllActionsInMenu = OptionalBoolDefault(key: "showAllActionsInMenu") + static let showAdditionalSizesInMenu = OptionalBoolDefault(key: "showAdditionalSizesInMenu") static var SUHasLaunchedBefore: Bool { UserDefaults.standard.bool(forKey: "SUHasLaunchedBefore") } static let footprintAlpha = FloatDefault(key: "footprintAlpha", defaultValue: 0.3) static let footprintBorderWidth = FloatDefault(key: "footprintBorderWidth", defaultValue: 2) @@ -98,8 +99,6 @@ class Defaults { static let systemWideMouseDownApps = JSONDefault>(key:"systemWideMouseDownApps", defaultValue: Set(["org.languagetool.desktop", "com.microsoft.teams2"])) static let internalTilingNotified = BoolDefault(key: "internalTilingNotified") static let screensOrderedByX = OptionalBoolDefault(key: "screensOrderedByX") - static let showEighthsInMenu = OptionalBoolDefault(key: "showEighthsInMenu") - static var array: [Default] = [ launchOnLogin, disabledApps, @@ -136,6 +135,7 @@ class Defaults { screenEdgeGapsOnMainScreenOnly, screenEdgeGapTopNotch, showAllActionsInMenu, + showAdditionalSizesInMenu, footprintAlpha, footprintBorderWidth, footprintFade, @@ -183,7 +183,7 @@ class Defaults { systemWideMouseDown, systemWideMouseDownApps, screensOrderedByX, - showEighthsInMenu + showAdditionalSizesInMenu ] } diff --git a/Rectangle/PrefsWindow/SettingsViewController.swift b/Rectangle/PrefsWindow/SettingsViewController.swift index 57585648..f89ff7aa 100644 --- a/Rectangle/PrefsWindow/SettingsViewController.swift +++ b/Rectangle/PrefsWindow/SettingsViewController.swift @@ -107,10 +107,10 @@ class SettingsViewController: NSViewController { Notification.Name.allowAnyShortcut.post(object: newSetting) } - @objc func toggleShowEighthsInMenu(_ sender: NSButton) { + @objc func toggleShowAdditionalSizesInMenu(_ sender: NSButton) { let enabled: Bool = sender.state == .on - Defaults.showEighthsInMenu.enabled = enabled - AppDelegate.instance.eighthsMenuItem?.isHidden = !enabled + Defaults.showAdditionalSizesInMenu.enabled = enabled + Notification.Name.showAdditionalSizesInMenuChanged.post() } @IBAction func checkForUpdates(_ sender: Any) { @@ -732,6 +732,92 @@ class SettingsViewController: NSViewController { mainStackView.addArrangedSubview(bottomVerticalThirdRow) mainStackView.addArrangedSubview(topVerticalTwoThirdsRow) mainStackView.addArrangedSubview(bottomVerticalTwoThirdsRow) + // Grid Positions - cycling shortcuts for larger grids + let showAdditionalSizesCheckbox = NSButton(checkboxWithTitle: NSLocalizedString("Show additional sizes in menu", tableName: "Main", value: "", comment: ""), target: self, action: #selector(toggleShowAdditionalSizesInMenu(_:))) + showAdditionalSizesCheckbox.state = Defaults.showAdditionalSizesInMenu.userEnabled ? .on : .off + showAdditionalSizesCheckbox.translatesAutoresizingMaskIntoConstraints = false + showAdditionalSizesCheckbox.alignment = .left + showAdditionalSizesCheckbox.imageHugsTitle = true + + // + let gridHeaderLabel = NSTextField(labelWithString: NSLocalizedString("Grid Positions", tableName: "Main", value: "", comment: "")) + gridHeaderLabel.font = NSFont.boldSystemFont(ofSize: NSFont.systemFontSize) + gridHeaderLabel.alignment = .center + gridHeaderLabel.translatesAutoresizingMaskIntoConstraints = false + + let cyclingHintLabel = NSTextField(wrappingLabelWithString: NSLocalizedString("Press the shortcut repeatedly to cycle through all positions in the grid.", tableName: "Main", value: "", comment: "")) + cyclingHintLabel.font = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize) + cyclingHintLabel.textColor = .secondaryLabelColor + cyclingHintLabel.alignment = .center + cyclingHintLabel.translatesAutoresizingMaskIntoConstraints = false + + // Cycling shortcut rows - Ninths, Twelfths, Sixteenths + let ninthsCyclingLabel = NSTextField(labelWithString: NSLocalizedString("Ninths (3\u{00d7}3)", tableName: "Main", value: "", comment: "")) + ninthsCyclingLabel.alignment = .right + ninthsCyclingLabel.translatesAutoresizingMaskIntoConstraints = false + let twelfthsCyclingLabel = NSTextField(labelWithString: NSLocalizedString("Twelfths (4\u{00d7}3)", tableName: "Main", value: "", comment: "")) + twelfthsCyclingLabel.alignment = .right + twelfthsCyclingLabel.translatesAutoresizingMaskIntoConstraints = false + + let sixteenthsCyclingLabel = NSTextField(labelWithString: NSLocalizedString("Sixteenths (4\u{00d7}4)", tableName: "Main", value: "", comment: "")) + sixteenthsCyclingLabel.alignment = .right + sixteenthsCyclingLabel.translatesAutoresizingMaskIntoConstraints = false + + let ninthsCyclingShortcutView = MASShortcutView(frame: NSRect(x: 0, y: 0, width: 160, height: 19)) + let twelfthsCyclingShortcutView = MASShortcutView(frame: NSRect(x: 0, y: 0, width: 160, height: 19)) + let sixteenthsCyclingShortcutView = MASShortcutView(frame: NSRect(x: 0, y: 0, width: 160, height: 19)) + + ninthsCyclingShortcutView.setAssociatedUserDefaultsKey(WindowAction.topLeftNinth.name, withTransformerName: MASDictionaryTransformerName) + twelfthsCyclingShortcutView.setAssociatedUserDefaultsKey(WindowAction.topLeftTwelfth.name, withTransformerName: MASDictionaryTransformerName) + sixteenthsCyclingShortcutView.setAssociatedUserDefaultsKey(WindowAction.topLeftSixteenth.name, withTransformerName: MASDictionaryTransformerName) + + let ninthsCyclingIcon = NSImageView(frame: NSRect(x: 0, y: 0, width: 21, height: 14)) + ninthsCyclingIcon.image = WindowAction.topLeftNinth.image + ninthsCyclingIcon.image?.size = NSSize(width: 21, height: 14) + let twelfthsCyclingIcon = NSImageView(frame: NSRect(x: 0, y: 0, width: 21, height: 14)) + twelfthsCyclingIcon.image = WindowAction.topLeftTwelfth.image + twelfthsCyclingIcon.image?.size = NSSize(width: 21, height: 14) + let sixteenthsCyclingIcon = NSImageView(frame: NSRect(x: 0, y: 0, width: 21, height: 14)) + sixteenthsCyclingIcon.image = WindowAction.topLeftSixteenth.image + sixteenthsCyclingIcon.image?.size = NSSize(width: 21, height: 14) + + func makeLabelStack(_ label: NSTextField, _ icon: NSImageView) -> NSStackView { + let stack = NSStackView() + stack.orientation = .horizontal + stack.alignment = .centerY + stack.spacing = 8 + stack.addArrangedSubview(label) + stack.addArrangedSubview(icon) + return stack + } + + func makeRow(_ labelStack: NSStackView, _ shortcutView: MASShortcutView) -> NSStackView { + let row = NSStackView() + row.orientation = .horizontal + row.alignment = .centerY + row.spacing = 18 + row.addArrangedSubview(labelStack) + row.addArrangedSubview(shortcutView) + return row + } + + let ninthsCyclingRow = makeRow(makeLabelStack(ninthsCyclingLabel, ninthsCyclingIcon), ninthsCyclingShortcutView) + let twelfthsCyclingRow = makeRow(makeLabelStack(twelfthsCyclingLabel, twelfthsCyclingIcon), twelfthsCyclingShortcutView) + let sixteenthsCyclingRow = makeRow(makeLabelStack(sixteenthsCyclingLabel, sixteenthsCyclingIcon), sixteenthsCyclingShortcutView) + + if Defaults.allowAnyShortcut.enabled { + let passThroughValidator = PassthroughShortcutValidator() + ninthsCyclingShortcutView.shortcutValidator = passThroughValidator + twelfthsCyclingShortcutView.shortcutValidator = passThroughValidator + sixteenthsCyclingShortcutView.shortcutValidator = passThroughValidator + } + + mainStackView.addArrangedSubview(gridHeaderLabel) + mainStackView.setCustomSpacing(4, after: gridHeaderLabel) + mainStackView.addArrangedSubview(showAdditionalSizesCheckbox) + mainStackView.setCustomSpacing(8, after: showAdditionalSizesCheckbox) + mainStackView.addArrangedSubview(cyclingHintLabel) + mainStackView.setCustomSpacing(8, after: cyclingHintLabel) mainStackView.addArrangedSubview(topLeftEighthRow) mainStackView.addArrangedSubview(topCenterLeftEighthRow) mainStackView.addArrangedSubview(topCenterRightEighthRow) @@ -740,14 +826,11 @@ class SettingsViewController: NSViewController { mainStackView.addArrangedSubview(bottomCenterLeftEighthRow) mainStackView.addArrangedSubview(bottomCenterRightEighthRow) mainStackView.addArrangedSubview(bottomRightEighthRow) - - let showEighthsCheckbox = NSButton(checkboxWithTitle: NSLocalizedString("Show Eighths in menu", tableName: "Main", value: "", comment: ""), target: self, action: #selector(toggleShowEighthsInMenu(_:))) - showEighthsCheckbox.state = Defaults.showEighthsInMenu.userEnabled ? .on : .off - showEighthsCheckbox.translatesAutoresizingMaskIntoConstraints = false - showEighthsCheckbox.alignment = .right - showEighthsCheckbox.imageHugsTitle = true - - mainStackView.addArrangedSubview(showEighthsCheckbox) + mainStackView.addArrangedSubview(ninthsCyclingRow) + mainStackView.addArrangedSubview(twelfthsCyclingRow) + mainStackView.addArrangedSubview(sixteenthsCyclingRow) + + mainStackView.addArrangedSubview(splitRatioHeaderLabel) mainStackView.setCustomSpacing(10, after: splitRatioHeaderLabel) mainStackView.addArrangedSubview(hSplitRow) @@ -771,7 +854,10 @@ class SettingsViewController: NSViewController { bottomLeftEighthLabel.widthAnchor.constraint(equalTo: bottomCenterLeftEighthLabel.widthAnchor), bottomCenterLeftEighthLabel.widthAnchor.constraint(equalTo: bottomCenterRightEighthLabel.widthAnchor), bottomCenterRightEighthLabel.widthAnchor.constraint(equalTo: bottomRightEighthLabel.widthAnchor), - bottomVerticalTwoThirdsLabel.widthAnchor.constraint(equalTo: hSplitLabel.widthAnchor), + bottomRightEighthLabel.widthAnchor.constraint(equalTo: ninthsCyclingLabel.widthAnchor), + ninthsCyclingLabel.widthAnchor.constraint(equalTo: twelfthsCyclingLabel.widthAnchor), + twelfthsCyclingLabel.widthAnchor.constraint(equalTo: sixteenthsCyclingLabel.widthAnchor), + sixteenthsCyclingLabel.widthAnchor.constraint(equalTo: hSplitLabel.widthAnchor), hSplitLabel.widthAnchor.constraint(equalTo: vSplitLabel.widthAnchor), largerWidthLabelStack.widthAnchor.constraint(equalTo: smallerWidthLabelStack.widthAnchor), largerWidthShortcutView.widthAnchor.constraint(equalToConstant: 160), @@ -790,11 +876,13 @@ class SettingsViewController: NSViewController { bottomCenterLeftEighthShortcutView.widthAnchor.constraint(equalToConstant: 160), bottomCenterRightEighthShortcutView.widthAnchor.constraint(equalToConstant: 160), bottomRightEighthShortcutView.widthAnchor.constraint(equalToConstant: 160), + ninthsCyclingShortcutView.widthAnchor.constraint(equalToConstant: 160), + twelfthsCyclingShortcutView.widthAnchor.constraint(equalToConstant: 160), + sixteenthsCyclingShortcutView.widthAnchor.constraint(equalToConstant: 160), widthStepField.trailingAnchor.constraint(equalTo: largerWidthShortcutView.trailingAnchor), hSplitField.widthAnchor.constraint(equalToConstant: 160), vSplitField.widthAnchor.constraint(equalToConstant: 160), - widthStepField.trailingAnchor.constraint(equalTo: largerWidthShortcutView.trailingAnchor), - showEighthsCheckbox.leadingAnchor.constraint(equalTo: largerWidthShortcutView.leadingAnchor), + showAdditionalSizesCheckbox.leadingAnchor.constraint(equalTo: largerWidthShortcutView.leadingAnchor), smallerWidthShortcutView.leadingAnchor.constraint(equalTo: largerWidthShortcutView.leadingAnchor), topVerticalThirdShortcutView.leadingAnchor.constraint(equalTo: largerWidthShortcutView.leadingAnchor), middleVerticalThirdShortcutView.leadingAnchor.constraint(equalTo: largerWidthShortcutView.leadingAnchor), @@ -809,6 +897,11 @@ class SettingsViewController: NSViewController { bottomCenterLeftEighthShortcutView.leadingAnchor.constraint(equalTo: largerWidthShortcutView.leadingAnchor), bottomCenterRightEighthShortcutView.leadingAnchor.constraint(equalTo: largerWidthShortcutView.leadingAnchor), bottomRightEighthShortcutView.leadingAnchor.constraint(equalTo: largerWidthShortcutView.leadingAnchor), + ninthsCyclingShortcutView.leadingAnchor.constraint(equalTo: largerWidthShortcutView.leadingAnchor), + twelfthsCyclingShortcutView.leadingAnchor.constraint(equalTo: largerWidthShortcutView.leadingAnchor), + sixteenthsCyclingShortcutView.leadingAnchor.constraint(equalTo: largerWidthShortcutView.leadingAnchor), + gridHeaderLabel.widthAnchor.constraint(equalTo: mainStackView.widthAnchor), + cyclingHintLabel.widthAnchor.constraint(equalTo: mainStackView.widthAnchor, constant: -20), hSplitField.trailingAnchor.constraint(equalTo: largerWidthShortcutView.trailingAnchor), vSplitField.trailingAnchor.constraint(equalTo: largerWidthShortcutView.trailingAnchor) ]) diff --git a/Rectangle/SubsequentExecutionMode.swift b/Rectangle/SubsequentExecutionMode.swift index 7070c95c..1a96ddb1 100644 --- a/Rectangle/SubsequentExecutionMode.swift +++ b/Rectangle/SubsequentExecutionMode.swift @@ -14,6 +14,7 @@ enum SubsequentExecutionMode: Int { case none = 2 case acrossAndResize = 3 // across monitor for right/left, spectacle resize for all else case cycleMonitor = 4 + case resizeAndCycleQuadrants = 5 } class SubsequentExecutionDefault: Default { @@ -36,7 +37,14 @@ class SubsequentExecutionDefault: Default { var resizes: Bool { switch value { - case .resize, .acrossAndResize: return true + case .resize, .acrossAndResize, .resizeAndCycleQuadrants: return true + default: return false + } + } + + var cyclesQuadrantPositions: Bool { + switch value { + case .resizeAndCycleQuadrants: return true default: return false } } diff --git a/Rectangle/Utilities/NotificationExtension.swift b/Rectangle/Utilities/NotificationExtension.swift index 79319c57..3b15a77c 100644 --- a/Rectangle/Utilities/NotificationExtension.swift +++ b/Rectangle/Utilities/NotificationExtension.swift @@ -22,6 +22,7 @@ extension Notification.Name { static let windowTitleBar = Notification.Name("windowTitleBar") static let defaultSnapAreas = Notification.Name("defaultSnapAreas") static let updateAvailability = Notification.Name("updateAvailability") + static let showAdditionalSizesInMenuChanged = Notification.Name("showAdditionalSizesInMenuChanged") func post( center: NotificationCenter = NotificationCenter.default, diff --git a/Rectangle/WindowAction.swift b/Rectangle/WindowAction.swift index 4ca3104f..d2a5d62b 100644 --- a/Rectangle/WindowAction.swift +++ b/Rectangle/WindowAction.swift @@ -104,7 +104,35 @@ enum WindowAction: Int, Codable { middleVerticalThird = 88, bottomVerticalThird = 89, topVerticalTwoThirds = 90, - bottomVerticalTwoThirds = 91 + bottomVerticalTwoThirds = 91, + topLeftTwelfth = 92, + topCenterLeftTwelfth = 93, + topCenterRightTwelfth = 94, + topRightTwelfth = 95, + middleLeftTwelfth = 96, + middleCenterLeftTwelfth = 97, + middleCenterRightTwelfth = 98, + middleRightTwelfth = 99, + bottomLeftTwelfth = 100, + bottomCenterLeftTwelfth = 101, + bottomCenterRightTwelfth = 102, + bottomRightTwelfth = 103, + topLeftSixteenth = 104, + topCenterLeftSixteenth = 105, + topCenterRightSixteenth = 106, + topRightSixteenth = 107, + upperMiddleLeftSixteenth = 108, + upperMiddleCenterLeftSixteenth = 109, + upperMiddleCenterRightSixteenth = 110, + upperMiddleRightSixteenth = 111, + lowerMiddleLeftSixteenth = 112, + lowerMiddleCenterLeftSixteenth = 113, + lowerMiddleCenterRightSixteenth = 114, + lowerMiddleRightSixteenth = 115, + bottomLeftSixteenth = 116, + bottomCenterLeftSixteenth = 117, + bottomCenterRightSixteenth = 118, + bottomRightSixteenth = 119 // Order matters here - it's used in the menu static let active = [leftHalf, rightHalf, centerHalf, topHalf, bottomHalf, @@ -118,12 +146,19 @@ enum WindowAction: Int, Codable { firstFourth, secondFourth, thirdFourth, lastFourth, firstThreeFourths, centerThreeFourths, lastThreeFourths, topLeftSixth, topCenterSixth, topRightSixth, bottomLeftSixth, bottomCenterSixth, bottomRightSixth, specified, reverseAll, - topLeftNinth, topCenterNinth, topRightNinth, - middleLeftNinth, middleCenterNinth, middleRightNinth, - bottomLeftNinth, bottomCenterNinth, bottomRightNinth, topLeftThird, topRightThird, bottomLeftThird, bottomRightThird, topLeftEighth, topCenterLeftEighth, topCenterRightEighth, topRightEighth, bottomLeftEighth, bottomCenterLeftEighth, bottomCenterRightEighth, bottomRightEighth, + topLeftNinth, topCenterNinth, topRightNinth, + middleLeftNinth, middleCenterNinth, middleRightNinth, + bottomLeftNinth, bottomCenterNinth, bottomRightNinth, + topLeftTwelfth, topCenterLeftTwelfth, topCenterRightTwelfth, topRightTwelfth, + middleLeftTwelfth, middleCenterLeftTwelfth, middleCenterRightTwelfth, middleRightTwelfth, + bottomLeftTwelfth, bottomCenterLeftTwelfth, bottomCenterRightTwelfth, bottomRightTwelfth, + topLeftSixteenth, topCenterLeftSixteenth, topCenterRightSixteenth, topRightSixteenth, + upperMiddleLeftSixteenth, upperMiddleCenterLeftSixteenth, upperMiddleCenterRightSixteenth, upperMiddleRightSixteenth, + lowerMiddleLeftSixteenth, lowerMiddleCenterLeftSixteenth, lowerMiddleCenterRightSixteenth, lowerMiddleRightSixteenth, + bottomLeftSixteenth, bottomCenterLeftSixteenth, bottomCenterRightSixteenth, bottomRightSixteenth, doubleHeightUp, doubleHeightDown, doubleWidthLeft, doubleWidthRight, halveHeightUp, halveHeightDown, halveWidthLeft, halveWidthRight, tileAll, cascadeAll, @@ -154,7 +189,7 @@ enum WindowAction: Int, Codable { // Determines where separators should be used in the menu var firstInGroup: Bool { switch self { - case .leftHalf, .topLeft, .firstThird, .maximize, .nextDisplay, .moveLeft, .firstFourth, .topLeftSixth, .topLeftEighth: + case .leftHalf, .topLeft, .firstThird, .maximize, .almostMaximize, .nextDisplay, .moveLeft, .firstFourth, .topLeftSixth, .topLeftEighth, .topLeftNinth, .topLeftTwelfth, .topLeftSixteenth: return true default: return false @@ -251,6 +286,34 @@ enum WindowAction: Int, Codable { case .bottomVerticalThird: return "bottomVerticalThird" case .topVerticalTwoThirds: return "topVerticalTwoThirds" case .bottomVerticalTwoThirds: return "bottomVerticalTwoThirds" + case .topLeftTwelfth: return "topLeftTwelfth" + case .topCenterLeftTwelfth: return "topCenterLeftTwelfth" + case .topCenterRightTwelfth: return "topCenterRightTwelfth" + case .topRightTwelfth: return "topRightTwelfth" + case .middleLeftTwelfth: return "middleLeftTwelfth" + case .middleCenterLeftTwelfth: return "middleCenterLeftTwelfth" + case .middleCenterRightTwelfth: return "middleCenterRightTwelfth" + case .middleRightTwelfth: return "middleRightTwelfth" + case .bottomLeftTwelfth: return "bottomLeftTwelfth" + case .bottomCenterLeftTwelfth: return "bottomCenterLeftTwelfth" + case .bottomCenterRightTwelfth: return "bottomCenterRightTwelfth" + case .bottomRightTwelfth: return "bottomRightTwelfth" + case .topLeftSixteenth: return "topLeftSixteenth" + case .topCenterLeftSixteenth: return "topCenterLeftSixteenth" + case .topCenterRightSixteenth: return "topCenterRightSixteenth" + case .topRightSixteenth: return "topRightSixteenth" + case .upperMiddleLeftSixteenth: return "upperMiddleLeftSixteenth" + case .upperMiddleCenterLeftSixteenth: return "upperMiddleCenterLeftSixteenth" + case .upperMiddleCenterRightSixteenth: return "upperMiddleCenterRightSixteenth" + case .upperMiddleRightSixteenth: return "upperMiddleRightSixteenth" + case .lowerMiddleLeftSixteenth: return "lowerMiddleLeftSixteenth" + case .lowerMiddleCenterLeftSixteenth: return "lowerMiddleCenterLeftSixteenth" + case .lowerMiddleCenterRightSixteenth: return "lowerMiddleCenterRightSixteenth" + case .lowerMiddleRightSixteenth: return "lowerMiddleRightSixteenth" + case .bottomLeftSixteenth: return "bottomLeftSixteenth" + case .bottomCenterLeftSixteenth: return "bottomCenterLeftSixteenth" + case .bottomCenterRightSixteenth: return "bottomCenterRightSixteenth" + case .bottomRightSixteenth: return "bottomRightSixteenth" } } @@ -382,8 +445,33 @@ enum WindowAction: Int, Codable { case .bottomRightSixth: key = "m2F-eA-g7w.title" value = "Bottom Right Sixth" - case .topLeftNinth, .topCenterNinth, .topRightNinth, .middleLeftNinth, .middleCenterNinth, .middleRightNinth, .bottomLeftNinth, .bottomCenterNinth, .bottomRightNinth: - return nil + case .topLeftNinth: + key = "topLeftNinth.title" + value = "Top Left Ninth" + case .topCenterNinth: + key = "topCenterNinth.title" + value = "Top Center Ninth" + case .topRightNinth: + key = "topRightNinth.title" + value = "Top Right Ninth" + case .middleLeftNinth: + key = "middleLeftNinth.title" + value = "Middle Left Ninth" + case .middleCenterNinth: + key = "middleCenterNinth.title" + value = "Middle Center Ninth" + case .middleRightNinth: + key = "middleRightNinth.title" + value = "Middle Right Ninth" + case .bottomLeftNinth: + key = "bottomLeftNinth.title" + value = "Bottom Left Ninth" + case .bottomCenterNinth: + key = "bottomCenterNinth.title" + value = "Bottom Center Ninth" + case .bottomRightNinth: + key = "bottomRightNinth.title" + value = "Bottom Right Ninth" case .topLeftThird, .topRightThird, .bottomLeftThird, .bottomRightThird: return nil case .topLeftEighth: @@ -418,6 +506,90 @@ enum WindowAction: Int, Codable { return nil case .topVerticalThird, .middleVerticalThird, .bottomVerticalThird, .topVerticalTwoThirds, .bottomVerticalTwoThirds: return nil + case .topLeftTwelfth: + key = "topLeftTwelfth.title" + value = "Top Left Twelfth" + case .topCenterLeftTwelfth: + key = "topCenterLeftTwelfth.title" + value = "Top Center Left Twelfth" + case .topCenterRightTwelfth: + key = "topCenterRightTwelfth.title" + value = "Top Center Right Twelfth" + case .topRightTwelfth: + key = "topRightTwelfth.title" + value = "Top Right Twelfth" + case .middleLeftTwelfth: + key = "middleLeftTwelfth.title" + value = "Middle Left Twelfth" + case .middleCenterLeftTwelfth: + key = "middleCenterLeftTwelfth.title" + value = "Middle Center Left Twelfth" + case .middleCenterRightTwelfth: + key = "middleCenterRightTwelfth.title" + value = "Middle Center Right Twelfth" + case .middleRightTwelfth: + key = "middleRightTwelfth.title" + value = "Middle Right Twelfth" + case .bottomLeftTwelfth: + key = "bottomLeftTwelfth.title" + value = "Bottom Left Twelfth" + case .bottomCenterLeftTwelfth: + key = "bottomCenterLeftTwelfth.title" + value = "Bottom Center Left Twelfth" + case .bottomCenterRightTwelfth: + key = "bottomCenterRightTwelfth.title" + value = "Bottom Center Right Twelfth" + case .bottomRightTwelfth: + key = "bottomRightTwelfth.title" + value = "Bottom Right Twelfth" + case .topLeftSixteenth: + key = "topLeftSixteenth.title" + value = "Top Left Sixteenth" + case .topCenterLeftSixteenth: + key = "topCenterLeftSixteenth.title" + value = "Top Center Left Sixteenth" + case .topCenterRightSixteenth: + key = "topCenterRightSixteenth.title" + value = "Top Center Right Sixteenth" + case .topRightSixteenth: + key = "topRightSixteenth.title" + value = "Top Right Sixteenth" + case .upperMiddleLeftSixteenth: + key = "upperMiddleLeftSixteenth.title" + value = "Upper Middle Left Sixteenth" + case .upperMiddleCenterLeftSixteenth: + key = "upperMiddleCenterLeftSixteenth.title" + value = "Upper Middle Center Left Sixteenth" + case .upperMiddleCenterRightSixteenth: + key = "upperMiddleCenterRightSixteenth.title" + value = "Upper Middle Center Right Sixteenth" + case .upperMiddleRightSixteenth: + key = "upperMiddleRightSixteenth.title" + value = "Upper Middle Right Sixteenth" + case .lowerMiddleLeftSixteenth: + key = "lowerMiddleLeftSixteenth.title" + value = "Lower Middle Left Sixteenth" + case .lowerMiddleCenterLeftSixteenth: + key = "lowerMiddleCenterLeftSixteenth.title" + value = "Lower Middle Center Left Sixteenth" + case .lowerMiddleCenterRightSixteenth: + key = "lowerMiddleCenterRightSixteenth.title" + value = "Lower Middle Center Right Sixteenth" + case .lowerMiddleRightSixteenth: + key = "lowerMiddleRightSixteenth.title" + value = "Lower Middle Right Sixteenth" + case .bottomLeftSixteenth: + key = "bottomLeftSixteenth.title" + value = "Bottom Left Sixteenth" + case .bottomCenterLeftSixteenth: + key = "bottomCenterLeftSixteenth.title" + value = "Bottom Center Left Sixteenth" + case .bottomCenterRightSixteenth: + key = "bottomCenterRightSixteenth.title" + value = "Bottom Center Right Sixteenth" + case .bottomRightSixteenth: + key = "bottomRightSixteenth.title" + value = "Bottom Right Sixteenth" } return NSLocalizedString(key, tableName: "Main", value: value, comment: "") @@ -556,15 +728,15 @@ enum WindowAction: Int, Codable { case .bottomLeftSixth: return NSImage(imageLiteralResourceName: "bottomLeftSixthTemplate") case .bottomCenterSixth: return NSImage(imageLiteralResourceName: "bottomCenterSixthTemplate") case .bottomRightSixth: return NSImage(imageLiteralResourceName: "bottomRightSixthTemplate") - case .topLeftNinth: return NSImage() - case .topCenterNinth: return NSImage() - case .topRightNinth: return NSImage() - case .middleLeftNinth: return NSImage() - case .middleCenterNinth: return NSImage() - case .middleRightNinth: return NSImage() - case .bottomLeftNinth: return NSImage() - case .bottomCenterNinth: return NSImage() - case .bottomRightNinth: return NSImage() + case .topLeftNinth: return NSImage(imageLiteralResourceName: "topLeftNinthTemplate") + case .topCenterNinth: return NSImage(imageLiteralResourceName: "topCenterNinthTemplate") + case .topRightNinth: return NSImage(imageLiteralResourceName: "topRightNinthTemplate") + case .middleLeftNinth: return NSImage(imageLiteralResourceName: "middleLeftNinthTemplate") + case .middleCenterNinth: return NSImage(imageLiteralResourceName: "middleCenterNinthTemplate") + case .middleRightNinth: return NSImage(imageLiteralResourceName: "middleRightNinthTemplate") + case .bottomLeftNinth: return NSImage(imageLiteralResourceName: "bottomLeftNinthTemplate") + case .bottomCenterNinth: return NSImage(imageLiteralResourceName: "bottomCenterNinthTemplate") + case .bottomRightNinth: return NSImage(imageLiteralResourceName: "bottomRightNinthTemplate") case .topLeftThird: return NSImage() case .topRightThird: return NSImage() case .bottomLeftThird: return NSImage() @@ -602,6 +774,34 @@ enum WindowAction: Int, Codable { case .bottomVerticalThird: return NSImage(imageLiteralResourceName: "bottomThirdTemplate") case .topVerticalTwoThirds: return NSImage(imageLiteralResourceName: "topTwoThirdsTemplate") case .bottomVerticalTwoThirds: return NSImage(imageLiteralResourceName: "bottomTwoThirdsTemplate") + case .topLeftTwelfth: return NSImage(imageLiteralResourceName: "topLeftTwelfthTemplate") + case .topCenterLeftTwelfth: return NSImage(imageLiteralResourceName: "topCenterLeftTwelfthTemplate") + case .topCenterRightTwelfth: return NSImage(imageLiteralResourceName: "topCenterRightTwelfthTemplate") + case .topRightTwelfth: return NSImage(imageLiteralResourceName: "topRightTwelfthTemplate") + case .middleLeftTwelfth: return NSImage(imageLiteralResourceName: "middleLeftTwelfthTemplate") + case .middleCenterLeftTwelfth: return NSImage(imageLiteralResourceName: "middleCenterLeftTwelfthTemplate") + case .middleCenterRightTwelfth: return NSImage(imageLiteralResourceName: "middleCenterRightTwelfthTemplate") + case .middleRightTwelfth: return NSImage(imageLiteralResourceName: "middleRightTwelfthTemplate") + case .bottomLeftTwelfth: return NSImage(imageLiteralResourceName: "bottomLeftTwelfthTemplate") + case .bottomCenterLeftTwelfth: return NSImage(imageLiteralResourceName: "bottomCenterLeftTwelfthTemplate") + case .bottomCenterRightTwelfth: return NSImage(imageLiteralResourceName: "bottomCenterRightTwelfthTemplate") + case .bottomRightTwelfth: return NSImage(imageLiteralResourceName: "bottomRightTwelfthTemplate") + case .topLeftSixteenth: return NSImage(imageLiteralResourceName: "topLeftSixteenthTemplate") + case .topCenterLeftSixteenth: return NSImage(imageLiteralResourceName: "topCenterLeftSixteenthTemplate") + case .topCenterRightSixteenth: return NSImage(imageLiteralResourceName: "topCenterRightSixteenthTemplate") + case .topRightSixteenth: return NSImage(imageLiteralResourceName: "topRightSixteenthTemplate") + case .upperMiddleLeftSixteenth: return NSImage(imageLiteralResourceName: "upperMiddleLeftSixteenthTemplate") + case .upperMiddleCenterLeftSixteenth: return NSImage(imageLiteralResourceName: "upperMiddleCenterLeftSixteenthTemplate") + case .upperMiddleCenterRightSixteenth: return NSImage(imageLiteralResourceName: "upperMiddleCenterRightSixteenthTemplate") + case .upperMiddleRightSixteenth: return NSImage(imageLiteralResourceName: "upperMiddleRightSixteenthTemplate") + case .lowerMiddleLeftSixteenth: return NSImage(imageLiteralResourceName: "lowerMiddleLeftSixteenthTemplate") + case .lowerMiddleCenterLeftSixteenth: return NSImage(imageLiteralResourceName: "lowerMiddleCenterLeftSixteenthTemplate") + case .lowerMiddleCenterRightSixteenth: return NSImage(imageLiteralResourceName: "lowerMiddleCenterRightSixteenthTemplate") + case .lowerMiddleRightSixteenth: return NSImage(imageLiteralResourceName: "lowerMiddleRightSixteenthTemplate") + case .bottomLeftSixteenth: return NSImage(imageLiteralResourceName: "bottomLeftSixteenthTemplate") + case .bottomCenterLeftSixteenth: return NSImage(imageLiteralResourceName: "bottomCenterLeftSixteenthTemplate") + case .bottomCenterRightSixteenth: return NSImage(imageLiteralResourceName: "bottomCenterRightSixteenthTemplate") + case .bottomRightSixteenth: return NSImage(imageLiteralResourceName: "bottomRightSixteenthTemplate") } } @@ -632,6 +832,13 @@ enum WindowAction: Int, Codable { .topLeftThird, .topRightThird, .bottomLeftThird, .bottomRightThird, .topLeftEighth, .topCenterLeftEighth, .topCenterRightEighth, .topRightEighth, .bottomLeftEighth, .bottomCenterLeftEighth, .bottomCenterRightEighth, .bottomRightEighth, + .topLeftTwelfth, .topCenterLeftTwelfth, .topCenterRightTwelfth, .topRightTwelfth, + .middleLeftTwelfth, .middleCenterLeftTwelfth, .middleCenterRightTwelfth, .middleRightTwelfth, + .bottomLeftTwelfth, .bottomCenterLeftTwelfth, .bottomCenterRightTwelfth, .bottomRightTwelfth, + .topLeftSixteenth, .topCenterLeftSixteenth, .topCenterRightSixteenth, .topRightSixteenth, + .upperMiddleLeftSixteenth, .upperMiddleCenterLeftSixteenth, .upperMiddleCenterRightSixteenth, .upperMiddleRightSixteenth, + .lowerMiddleLeftSixteenth, .lowerMiddleCenterLeftSixteenth, .lowerMiddleCenterRightSixteenth, .lowerMiddleRightSixteenth, + .bottomLeftSixteenth, .bottomCenterLeftSixteenth, .bottomCenterRightSixteenth, .bottomRightSixteenth, .doubleHeightUp, .doubleHeightDown, .doubleWidthLeft, .doubleWidthRight, .halveHeightUp, .halveHeightDown, .halveWidthLeft, .halveWidthRight, .leftTodo, .rightTodo, @@ -652,14 +859,19 @@ enum WindowAction: Int, Codable { var category: WindowActionCategory? { // used to specify a submenu switch self { + case .firstThird, .centerThird, .lastThird, .firstTwoThirds, .centerTwoThirds, .lastTwoThirds: return .thirds case .firstFourth, .secondFourth, .thirdFourth, .lastFourth, .firstThreeFourths, .centerThreeFourths, .lastThreeFourths: return .fourths case .topLeftSixth, .topCenterSixth, .topRightSixth, .bottomLeftSixth, .bottomCenterSixth, .bottomRightSixth: return .sixths case .topLeftEighth, .topCenterLeftEighth, .topCenterRightEighth, .topRightEighth, .bottomLeftEighth, .bottomCenterLeftEighth, .bottomCenterRightEighth, .bottomRightEighth: return .eighths + case .topLeftNinth, .topCenterNinth, .topRightNinth, .middleLeftNinth, .middleCenterNinth, .middleRightNinth, .bottomLeftNinth, .bottomCenterNinth, .bottomRightNinth: return .ninths + case .topLeftTwelfth, .topCenterLeftTwelfth, .topCenterRightTwelfth, .topRightTwelfth, .middleLeftTwelfth, .middleCenterLeftTwelfth, .middleCenterRightTwelfth, .middleRightTwelfth, .bottomLeftTwelfth, .bottomCenterLeftTwelfth, .bottomCenterRightTwelfth, .bottomRightTwelfth: return .twelfths + case .topLeftSixteenth, .topCenterLeftSixteenth, .topCenterRightSixteenth, .topRightSixteenth, .upperMiddleLeftSixteenth, .upperMiddleCenterLeftSixteenth, .upperMiddleCenterRightSixteenth, .upperMiddleRightSixteenth, .lowerMiddleLeftSixteenth, .lowerMiddleCenterLeftSixteenth, .lowerMiddleCenterRightSixteenth, .lowerMiddleRightSixteenth, .bottomLeftSixteenth, .bottomCenterLeftSixteenth, .bottomCenterRightSixteenth, .bottomRightSixteenth: return .sixteenths case .moveUp, .moveDown, .moveLeft, .moveRight: return .move + case .almostMaximize, .maximizeHeight, .larger, .smaller, .largerWidth, .smallerWidth, .largerHeight, .smallerHeight: return .size default: return nil } } - + var classification: WindowActionCategory? { switch self { case .firstThird, .firstTwoThirds, .centerThird, .centerTwoThirds, .lastTwoThirds, .lastThird: @@ -744,7 +956,12 @@ enum SubWindowAction { topRightThird, bottomLeftThird, bottomRightThird, - + + topLeftQuarter, + topRightQuarter, + bottomLeftQuarter, + bottomRightQuarter, + topLeftEighth, topCenterLeftEighth, topCenterRightEighth, @@ -753,7 +970,37 @@ enum SubWindowAction { bottomCenterLeftEighth, bottomCenterRightEighth, bottomRightEighth, - + + topLeftTwelfth, + topCenterLeftTwelfth, + topCenterRightTwelfth, + topRightTwelfth, + middleLeftTwelfth, + middleCenterLeftTwelfth, + middleCenterRightTwelfth, + middleRightTwelfth, + bottomLeftTwelfth, + bottomCenterLeftTwelfth, + bottomCenterRightTwelfth, + bottomRightTwelfth, + + topLeftSixteenth, + topCenterLeftSixteenth, + topCenterRightSixteenth, + topRightSixteenth, + upperMiddleLeftSixteenth, + upperMiddleCenterLeftSixteenth, + upperMiddleCenterRightSixteenth, + upperMiddleRightSixteenth, + lowerMiddleLeftSixteenth, + lowerMiddleCenterLeftSixteenth, + lowerMiddleCenterRightSixteenth, + lowerMiddleRightSixteenth, + bottomLeftSixteenth, + bottomCenterLeftSixteenth, + bottomCenterRightSixteenth, + bottomRightSixteenth, + maximize, leftTodo, @@ -820,6 +1067,10 @@ enum SubWindowAction { case .topRightThird: return [.left, .bottom] case .bottomLeftThird: return [.right, .top] case .bottomRightThird: return [.left, .top] + case .topLeftQuarter: return [.right, .bottom] + case .topRightQuarter: return [.left, .bottom] + case .bottomLeftQuarter: return [.right, .top] + case .bottomRightQuarter: return [.left, .top] case .topLeftEighth: return [.right, .bottom] case .topCenterLeftEighth: return [.right, .left, .bottom] case .topCenterRightEighth: return [.right, .left, .bottom] @@ -828,6 +1079,34 @@ enum SubWindowAction { case .bottomCenterLeftEighth: return [.right, .left, .top] case .bottomCenterRightEighth: return [.right, .left, .top] case .bottomRightEighth: return [.left, .top] + case .topLeftTwelfth: return [.right, .bottom] + case .topCenterLeftTwelfth: return [.right, .left, .bottom] + case .topCenterRightTwelfth: return [.right, .left, .bottom] + case .topRightTwelfth: return [.left, .bottom] + case .middleLeftTwelfth: return [.top, .right, .bottom] + case .middleCenterLeftTwelfth: return [.top, .right, .bottom, .left] + case .middleCenterRightTwelfth: return [.top, .right, .bottom, .left] + case .middleRightTwelfth: return [.left, .top, .bottom] + case .bottomLeftTwelfth: return [.top, .right] + case .bottomCenterLeftTwelfth: return [.left, .top, .right] + case .bottomCenterRightTwelfth: return [.left, .top, .right] + case .bottomRightTwelfth: return [.left, .top] + case .topLeftSixteenth: return [.right, .bottom] + case .topCenterLeftSixteenth: return [.right, .left, .bottom] + case .topCenterRightSixteenth: return [.right, .left, .bottom] + case .topRightSixteenth: return [.left, .bottom] + case .upperMiddleLeftSixteenth: return [.top, .right, .bottom] + case .upperMiddleCenterLeftSixteenth: return [.top, .right, .bottom, .left] + case .upperMiddleCenterRightSixteenth: return [.top, .right, .bottom, .left] + case .upperMiddleRightSixteenth: return [.left, .top, .bottom] + case .lowerMiddleLeftSixteenth: return [.top, .right, .bottom] + case .lowerMiddleCenterLeftSixteenth: return [.top, .right, .bottom, .left] + case .lowerMiddleCenterRightSixteenth: return [.top, .right, .bottom, .left] + case .lowerMiddleRightSixteenth: return [.left, .top, .bottom] + case .bottomLeftSixteenth: return [.top, .right] + case .bottomCenterLeftSixteenth: return [.left, .top, .right] + case .bottomCenterRightSixteenth: return [.left, .top, .right] + case .bottomRightSixteenth: return [.left, .top] case .maximize: return .none case .leftTodo: return .right case .rightTodo: return .left diff --git a/Rectangle/WindowActionCategory.swift b/Rectangle/WindowActionCategory.swift index d24051f2..6a61073d 100644 --- a/Rectangle/WindowActionCategory.swift +++ b/Rectangle/WindowActionCategory.swift @@ -10,8 +10,23 @@ import Foundation enum WindowActionCategory { - case halves, corners, thirds, max, size, display, move, other, sixths, fourths, eighths - + case halves, corners, thirds, max, size, display, move, other, sixths, fourths, eighths, ninths, twelfths, sixteenths + + var menuOrder: Int { + switch self { + case .size: return 0 + case .move: return 1 + case .thirds: return 2 + case .fourths: return 3 + case .sixths: return 4 + case .eighths: return 5 + case .ninths: return 6 + case .twelfths: return 7 + case .sixteenths: return 8 + default: return 99 + } + } + var displayName: String { switch self { case .halves: @@ -36,6 +51,12 @@ enum WindowActionCategory { return NSLocalizedString("Sixths", tableName: "Main", value: "", comment: "") case .eighths: return NSLocalizedString("Eighths", tableName: "Main", value: "", comment: "") + case .ninths: + return NSLocalizedString("Ninths", tableName: "Main", value: "Ninths", comment: "") + case .twelfths: + return NSLocalizedString("Twelfths", tableName: "Main", value: "Twelfths", comment: "") + case .sixteenths: + return NSLocalizedString("Sixteenths", tableName: "Main", value: "Sixteenths", comment: "") } } } diff --git a/Rectangle/WindowCalculation/BottomCenterLeftSixteenthCalculation.swift b/Rectangle/WindowCalculation/BottomCenterLeftSixteenthCalculation.swift new file mode 100644 index 00000000..530eb8e9 --- /dev/null +++ b/Rectangle/WindowCalculation/BottomCenterLeftSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// BottomCenterLeftSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class BottomCenterLeftSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .bottomCenterLeftSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .bottomCenterLeftSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .bottomCenterLeftSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/BottomCenterLeftTwelfthCalculation.swift b/Rectangle/WindowCalculation/BottomCenterLeftTwelfthCalculation.swift new file mode 100644 index 00000000..1c3b6a6f --- /dev/null +++ b/Rectangle/WindowCalculation/BottomCenterLeftTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// BottomCenterLeftTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class BottomCenterLeftTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .bottomCenterLeftTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .bottomCenterLeftTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .bottomCenterLeftTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/BottomCenterRightSixteenthCalculation.swift b/Rectangle/WindowCalculation/BottomCenterRightSixteenthCalculation.swift new file mode 100644 index 00000000..63367ad7 --- /dev/null +++ b/Rectangle/WindowCalculation/BottomCenterRightSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// BottomCenterRightSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class BottomCenterRightSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .bottomCenterRightSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 2 + return RectResult(rect, subAction: .bottomCenterRightSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 2 + return RectResult(rect, subAction: .bottomCenterRightSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/BottomCenterRightTwelfthCalculation.swift b/Rectangle/WindowCalculation/BottomCenterRightTwelfthCalculation.swift new file mode 100644 index 00000000..1da0f6f4 --- /dev/null +++ b/Rectangle/WindowCalculation/BottomCenterRightTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// BottomCenterRightTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class BottomCenterRightTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .bottomCenterRightTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + floor(visibleFrameOfScreen.width / 4.0) * 2.0 + return RectResult(rect, subAction: .bottomCenterRightTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .bottomCenterRightTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/BottomLeftSixteenthCalculation.swift b/Rectangle/WindowCalculation/BottomLeftSixteenthCalculation.swift new file mode 100644 index 00000000..4cd153ca --- /dev/null +++ b/Rectangle/WindowCalculation/BottomLeftSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// BottomLeftSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class BottomLeftSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .bottomLeftSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .bottomLeftSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .bottomLeftSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/BottomLeftTwelfthCalculation.swift b/Rectangle/WindowCalculation/BottomLeftTwelfthCalculation.swift new file mode 100644 index 00000000..438a3842 --- /dev/null +++ b/Rectangle/WindowCalculation/BottomLeftTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// BottomLeftTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class BottomLeftTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .bottomLeftTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .bottomLeftTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - (3.0 * rect.height) + rect.origin.x = visibleFrameOfScreen.minX + (2.0 * rect.width) + return RectResult(rect, subAction: .bottomLeftTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/BottomRightSixteenthCalculation.swift b/Rectangle/WindowCalculation/BottomRightSixteenthCalculation.swift new file mode 100644 index 00000000..26073655 --- /dev/null +++ b/Rectangle/WindowCalculation/BottomRightSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// BottomRightSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class BottomRightSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .bottomRightSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 3 + return RectResult(rect, subAction: .bottomRightSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 3 + return RectResult(rect, subAction: .bottomRightSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/BottomRightTwelfthCalculation.swift b/Rectangle/WindowCalculation/BottomRightTwelfthCalculation.swift new file mode 100644 index 00000000..7608bc24 --- /dev/null +++ b/Rectangle/WindowCalculation/BottomRightTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// BottomRightTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class BottomRightTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .bottomRightTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + floor(visibleFrameOfScreen.width / 4.0) * 3.0 + return RectResult(rect, subAction: .bottomRightTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.origin.x = visibleFrameOfScreen.minX + floor(visibleFrameOfScreen.width / 3.0) * 2.0 + return RectResult(rect, subAction: .bottomRightTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/LeftRightHalfCalculation.swift b/Rectangle/WindowCalculation/LeftRightHalfCalculation.swift index b75f3eff..049d2926 100644 --- a/Rectangle/WindowCalculation/LeftRightHalfCalculation.swift +++ b/Rectangle/WindowCalculation/LeftRightHalfCalculation.swift @@ -23,7 +23,7 @@ class LeftRightHalfCalculation: WindowCalculation, RepeatedExecutionsInThirdsCal return calculateResize(params) } return calculateAcrossDisplays(params) - case .resize: + case .resize, .resizeAndCycleQuadrants: return calculateResize(params) case .none, .cycleMonitor: let screen = usableScreens.currentScreen diff --git a/Rectangle/WindowCalculation/LowerLeftCalculation.swift b/Rectangle/WindowCalculation/LowerLeftCalculation.swift index 323593ac..4b52c573 100644 --- a/Rectangle/WindowCalculation/LowerLeftCalculation.swift +++ b/Rectangle/WindowCalculation/LowerLeftCalculation.swift @@ -8,26 +8,41 @@ import Foundation -class LowerLeftCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation { +class LowerLeftCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation, QuartersRepeated { override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + if Defaults.subsequentExecutionMode.cyclesQuadrantPositions { + if let last = params.lastAction, + let lastSubAction = last.subAction, + last.action == .bottomLeft || lastSubAction == .bottomLeftQuarter { + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(params.visibleFrameOfScreen) + } + } + return quarterRect(params.visibleFrameOfScreen) + } + if params.lastAction == nil || !Defaults.subsequentExecutionMode.resizes { return calculateFirstRect(params) } - + return calculateRepeatedRect(params) } - + + func quarterRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 2.0) + rect.size.height = floor(visibleFrameOfScreen.height / 2.0) + return RectResult(rect, subAction: .bottomLeftQuarter) + } + func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult { let visibleFrameOfScreen = params.visibleFrameOfScreen var rect = visibleFrameOfScreen - rect.size.width = floor(visibleFrameOfScreen.width * CGFloat(fraction)) - rect.size.height = floor(visibleFrameOfScreen.height / 2.0) - return RectResult(rect) } } diff --git a/Rectangle/WindowCalculation/LowerMiddleCenterLeftSixteenthCalculation.swift b/Rectangle/WindowCalculation/LowerMiddleCenterLeftSixteenthCalculation.swift new file mode 100644 index 00000000..e95ad794 --- /dev/null +++ b/Rectangle/WindowCalculation/LowerMiddleCenterLeftSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// LowerMiddleCenterLeftSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class LowerMiddleCenterLeftSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .lowerMiddleCenterLeftSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .lowerMiddleCenterLeftSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .lowerMiddleCenterLeftSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/LowerMiddleCenterRightSixteenthCalculation.swift b/Rectangle/WindowCalculation/LowerMiddleCenterRightSixteenthCalculation.swift new file mode 100644 index 00000000..60f785b0 --- /dev/null +++ b/Rectangle/WindowCalculation/LowerMiddleCenterRightSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// LowerMiddleCenterRightSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class LowerMiddleCenterRightSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .lowerMiddleCenterRightSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 2 + return RectResult(rect, subAction: .lowerMiddleCenterRightSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 2 + return RectResult(rect, subAction: .lowerMiddleCenterRightSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/LowerMiddleLeftSixteenthCalculation.swift b/Rectangle/WindowCalculation/LowerMiddleLeftSixteenthCalculation.swift new file mode 100644 index 00000000..2f45dae0 --- /dev/null +++ b/Rectangle/WindowCalculation/LowerMiddleLeftSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// LowerMiddleLeftSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class LowerMiddleLeftSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .lowerMiddleLeftSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .lowerMiddleLeftSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .lowerMiddleLeftSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/LowerMiddleRightSixteenthCalculation.swift b/Rectangle/WindowCalculation/LowerMiddleRightSixteenthCalculation.swift new file mode 100644 index 00000000..097fd1aa --- /dev/null +++ b/Rectangle/WindowCalculation/LowerMiddleRightSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// LowerMiddleRightSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class LowerMiddleRightSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .lowerMiddleRightSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 3 + return RectResult(rect, subAction: .lowerMiddleRightSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 3 + return RectResult(rect, subAction: .lowerMiddleRightSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/LowerRightCalculation.swift b/Rectangle/WindowCalculation/LowerRightCalculation.swift index 30f64f11..257cb1fe 100644 --- a/Rectangle/WindowCalculation/LowerRightCalculation.swift +++ b/Rectangle/WindowCalculation/LowerRightCalculation.swift @@ -8,26 +8,43 @@ import Foundation -class LowerRightCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation { +class LowerRightCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation, QuartersRepeated { override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + if Defaults.subsequentExecutionMode.cyclesQuadrantPositions { + if let last = params.lastAction, + let lastSubAction = last.subAction, + last.action == .bottomRight || lastSubAction == .bottomRightQuarter { + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(params.visibleFrameOfScreen) + } + } + return quarterRect(params.visibleFrameOfScreen) + } + if params.lastAction == nil || !Defaults.subsequentExecutionMode.resizes { return calculateFirstRect(params) } - + return calculateRepeatedRect(params) } - + + func quarterRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 2.0) + rect.origin.x = visibleFrameOfScreen.maxX - rect.width + rect.size.height = floor(visibleFrameOfScreen.height / 2.0) + return RectResult(rect, subAction: .bottomRightQuarter) + } + func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult { let visibleFrameOfScreen = params.visibleFrameOfScreen var rect = visibleFrameOfScreen - rect.size.width = floor(visibleFrameOfScreen.width * CGFloat(fraction)) rect.origin.x = visibleFrameOfScreen.maxX - rect.width rect.size.height = floor(visibleFrameOfScreen.height / 2.0) - return RectResult(rect) } } diff --git a/Rectangle/WindowCalculation/MiddleCenterLeftTwelfthCalculation.swift b/Rectangle/WindowCalculation/MiddleCenterLeftTwelfthCalculation.swift new file mode 100644 index 00000000..b4258a66 --- /dev/null +++ b/Rectangle/WindowCalculation/MiddleCenterLeftTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// MiddleCenterLeftTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class MiddleCenterLeftTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .middleCenterLeftTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .middleCenterLeftTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - (2.0 * rect.height) + rect.origin.x = visibleFrameOfScreen.minX + (2.0 * rect.width) + return RectResult(rect, subAction: .middleCenterLeftTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/MiddleCenterRightTwelfthCalculation.swift b/Rectangle/WindowCalculation/MiddleCenterRightTwelfthCalculation.swift new file mode 100644 index 00000000..0dda6bd4 --- /dev/null +++ b/Rectangle/WindowCalculation/MiddleCenterRightTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// MiddleCenterRightTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class MiddleCenterRightTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .middleCenterRightTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + floor(visibleFrameOfScreen.width / 4.0) * 2.0 + return RectResult(rect, subAction: .middleCenterRightTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - (3.0 * rect.height) + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .middleCenterRightTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/MiddleLeftTwelfthCalculation.swift b/Rectangle/WindowCalculation/MiddleLeftTwelfthCalculation.swift new file mode 100644 index 00000000..2324bdc9 --- /dev/null +++ b/Rectangle/WindowCalculation/MiddleLeftTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// MiddleLeftTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class MiddleLeftTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .middleLeftTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .middleLeftTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - (2.0 * rect.height) + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .middleLeftTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/MiddleRightTwelfthCalculation.swift b/Rectangle/WindowCalculation/MiddleRightTwelfthCalculation.swift new file mode 100644 index 00000000..deba74f1 --- /dev/null +++ b/Rectangle/WindowCalculation/MiddleRightTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// MiddleRightTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class MiddleRightTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .middleRightTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.minY + rect.height + rect.origin.x = visibleFrameOfScreen.minX + floor(visibleFrameOfScreen.width / 4.0) * 3.0 + return RectResult(rect, subAction: .middleRightTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - (3.0 * rect.height) + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .middleRightTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/QuartersRepeated.swift b/Rectangle/WindowCalculation/QuartersRepeated.swift new file mode 100644 index 00000000..2a971ecd --- /dev/null +++ b/Rectangle/WindowCalculation/QuartersRepeated.swift @@ -0,0 +1,47 @@ +// +// QuartersRepeated.swift +// Rectangle +// +// Copyright © 2026 Ryan Hanson. All rights reserved. +// + +import Foundation + +protocol QuartersRepeated { + func nextCalculation(subAction: SubWindowAction, direction: Direction) -> SimpleCalc? +} + +extension QuartersRepeated { + func nextCalculation(subAction: SubWindowAction, direction: Direction) -> SimpleCalc? { + + if direction == .left { + switch subAction { + case .topLeftQuarter: + return WindowCalculationFactory.lowerRightCalculation.quarterRect + case .topRightQuarter: + return WindowCalculationFactory.upperLeftCalculation.quarterRect + case .bottomLeftQuarter: + return WindowCalculationFactory.upperRightCalculation.quarterRect + case .bottomRightQuarter: + return WindowCalculationFactory.lowerLeftCalculation.quarterRect + default: break + } + } + + else if direction == .right { + switch subAction { + case .topLeftQuarter: + return WindowCalculationFactory.upperRightCalculation.quarterRect + case .topRightQuarter: + return WindowCalculationFactory.lowerLeftCalculation.quarterRect + case .bottomLeftQuarter: + return WindowCalculationFactory.lowerRightCalculation.quarterRect + case .bottomRightQuarter: + return WindowCalculationFactory.upperLeftCalculation.quarterRect + default: break + } + } + + return nil + } +} diff --git a/Rectangle/WindowCalculation/SixteenthsRepeated.swift b/Rectangle/WindowCalculation/SixteenthsRepeated.swift new file mode 100644 index 00000000..feb99e27 --- /dev/null +++ b/Rectangle/WindowCalculation/SixteenthsRepeated.swift @@ -0,0 +1,95 @@ +// +// SixteenthsRepeated.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +protocol SixteenthsRepeated { + func nextCalculation(subAction: SubWindowAction, direction: Direction) -> SimpleCalc? +} + +extension SixteenthsRepeated { + func nextCalculation(subAction: SubWindowAction, direction: Direction) -> SimpleCalc? { + + if direction == .left { + switch subAction { + case .topLeftSixteenth: + return WindowCalculationFactory.bottomRightSixteenthCalculation.orientationBasedRect + case .topCenterLeftSixteenth: + return WindowCalculationFactory.topLeftSixteenthCalculation.orientationBasedRect + case .topCenterRightSixteenth: + return WindowCalculationFactory.topCenterLeftSixteenthCalculation.orientationBasedRect + case .topRightSixteenth: + return WindowCalculationFactory.topCenterRightSixteenthCalculation.orientationBasedRect + case .upperMiddleLeftSixteenth: + return WindowCalculationFactory.topRightSixteenthCalculation.orientationBasedRect + case .upperMiddleCenterLeftSixteenth: + return WindowCalculationFactory.upperMiddleLeftSixteenthCalculation.orientationBasedRect + case .upperMiddleCenterRightSixteenth: + return WindowCalculationFactory.upperMiddleCenterLeftSixteenthCalculation.orientationBasedRect + case .upperMiddleRightSixteenth: + return WindowCalculationFactory.upperMiddleCenterRightSixteenthCalculation.orientationBasedRect + case .lowerMiddleLeftSixteenth: + return WindowCalculationFactory.upperMiddleRightSixteenthCalculation.orientationBasedRect + case .lowerMiddleCenterLeftSixteenth: + return WindowCalculationFactory.lowerMiddleLeftSixteenthCalculation.orientationBasedRect + case .lowerMiddleCenterRightSixteenth: + return WindowCalculationFactory.lowerMiddleCenterLeftSixteenthCalculation.orientationBasedRect + case .lowerMiddleRightSixteenth: + return WindowCalculationFactory.lowerMiddleCenterRightSixteenthCalculation.orientationBasedRect + case .bottomLeftSixteenth: + return WindowCalculationFactory.lowerMiddleRightSixteenthCalculation.orientationBasedRect + case .bottomCenterLeftSixteenth: + return WindowCalculationFactory.bottomLeftSixteenthCalculation.orientationBasedRect + case .bottomCenterRightSixteenth: + return WindowCalculationFactory.bottomCenterLeftSixteenthCalculation.orientationBasedRect + case .bottomRightSixteenth: + return WindowCalculationFactory.bottomCenterRightSixteenthCalculation.orientationBasedRect + default: break + } + } + + else if direction == .right { + switch subAction { + case .topLeftSixteenth: + return WindowCalculationFactory.topCenterLeftSixteenthCalculation.orientationBasedRect + case .topCenterLeftSixteenth: + return WindowCalculationFactory.topCenterRightSixteenthCalculation.orientationBasedRect + case .topCenterRightSixteenth: + return WindowCalculationFactory.topRightSixteenthCalculation.orientationBasedRect + case .topRightSixteenth: + return WindowCalculationFactory.upperMiddleLeftSixteenthCalculation.orientationBasedRect + case .upperMiddleLeftSixteenth: + return WindowCalculationFactory.upperMiddleCenterLeftSixteenthCalculation.orientationBasedRect + case .upperMiddleCenterLeftSixteenth: + return WindowCalculationFactory.upperMiddleCenterRightSixteenthCalculation.orientationBasedRect + case .upperMiddleCenterRightSixteenth: + return WindowCalculationFactory.upperMiddleRightSixteenthCalculation.orientationBasedRect + case .upperMiddleRightSixteenth: + return WindowCalculationFactory.lowerMiddleLeftSixteenthCalculation.orientationBasedRect + case .lowerMiddleLeftSixteenth: + return WindowCalculationFactory.lowerMiddleCenterLeftSixteenthCalculation.orientationBasedRect + case .lowerMiddleCenterLeftSixteenth: + return WindowCalculationFactory.lowerMiddleCenterRightSixteenthCalculation.orientationBasedRect + case .lowerMiddleCenterRightSixteenth: + return WindowCalculationFactory.lowerMiddleRightSixteenthCalculation.orientationBasedRect + case .lowerMiddleRightSixteenth: + return WindowCalculationFactory.bottomLeftSixteenthCalculation.orientationBasedRect + case .bottomLeftSixteenth: + return WindowCalculationFactory.bottomCenterLeftSixteenthCalculation.orientationBasedRect + case .bottomCenterLeftSixteenth: + return WindowCalculationFactory.bottomCenterRightSixteenthCalculation.orientationBasedRect + case .bottomCenterRightSixteenth: + return WindowCalculationFactory.bottomRightSixteenthCalculation.orientationBasedRect + case .bottomRightSixteenth: + return WindowCalculationFactory.topLeftSixteenthCalculation.orientationBasedRect + default: break + } + } + + return nil + } +} diff --git a/Rectangle/WindowCalculation/TopCenterLeftSixteenthCalculation.swift b/Rectangle/WindowCalculation/TopCenterLeftSixteenthCalculation.swift new file mode 100644 index 00000000..bfd13dfc --- /dev/null +++ b/Rectangle/WindowCalculation/TopCenterLeftSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// TopCenterLeftSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class TopCenterLeftSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .topCenterLeftSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .topCenterLeftSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .topCenterLeftSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/TopCenterLeftTwelfthCalculation.swift b/Rectangle/WindowCalculation/TopCenterLeftTwelfthCalculation.swift new file mode 100644 index 00000000..fcfc46ff --- /dev/null +++ b/Rectangle/WindowCalculation/TopCenterLeftTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// TopCenterLeftTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class TopCenterLeftTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .topCenterLeftTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .topCenterLeftTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .topCenterLeftTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/TopCenterRightSixteenthCalculation.swift b/Rectangle/WindowCalculation/TopCenterRightSixteenthCalculation.swift new file mode 100644 index 00000000..95b0f725 --- /dev/null +++ b/Rectangle/WindowCalculation/TopCenterRightSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// TopCenterRightSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class TopCenterRightSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .topCenterRightSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 2 + return RectResult(rect, subAction: .topCenterRightSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 2 + return RectResult(rect, subAction: .topCenterRightSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/TopCenterRightTwelfthCalculation.swift b/Rectangle/WindowCalculation/TopCenterRightTwelfthCalculation.swift new file mode 100644 index 00000000..4d2c7442 --- /dev/null +++ b/Rectangle/WindowCalculation/TopCenterRightTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// TopCenterRightTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class TopCenterRightTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .topCenterRightTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + floor(visibleFrameOfScreen.width / 4.0) * 2.0 + return RectResult(rect, subAction: .topCenterRightTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + floor(visibleFrameOfScreen.width / 3.0) * 2.0 + return RectResult(rect, subAction: .topCenterRightTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/TopLeftSixteenthCalculation.swift b/Rectangle/WindowCalculation/TopLeftSixteenthCalculation.swift new file mode 100644 index 00000000..2727465a --- /dev/null +++ b/Rectangle/WindowCalculation/TopLeftSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// TopLeftSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class TopLeftSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .topLeftSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .topLeftSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .topLeftSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/TopLeftTwelfthCalculation.swift b/Rectangle/WindowCalculation/TopLeftTwelfthCalculation.swift new file mode 100644 index 00000000..ed124918 --- /dev/null +++ b/Rectangle/WindowCalculation/TopLeftTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// TopLeftTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class TopLeftTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .topLeftTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .topLeftTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .topLeftTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/TopRightSixteenthCalculation.swift b/Rectangle/WindowCalculation/TopRightSixteenthCalculation.swift new file mode 100644 index 00000000..0e22357a --- /dev/null +++ b/Rectangle/WindowCalculation/TopRightSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// TopRightSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class TopRightSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .topRightSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 3 + return RectResult(rect, subAction: .topRightSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 3 + return RectResult(rect, subAction: .topRightSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/TopRightTwelfthCalculation.swift b/Rectangle/WindowCalculation/TopRightTwelfthCalculation.swift new file mode 100644 index 00000000..158be267 --- /dev/null +++ b/Rectangle/WindowCalculation/TopRightTwelfthCalculation.swift @@ -0,0 +1,50 @@ +// +// TopRightTwelfthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class TopRightTwelfthCalculation: WindowCalculation, OrientationAware, TwelfthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .topRightTwelfth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 3.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + rect.origin.x = visibleFrameOfScreen.minX + floor(visibleFrameOfScreen.width / 4.0) * 3.0 + return RectResult(rect, subAction: .topRightTwelfth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 3.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - (2.0 * rect.height) + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .topRightTwelfth) + } +} diff --git a/Rectangle/WindowCalculation/TwelfthsRepeated.swift b/Rectangle/WindowCalculation/TwelfthsRepeated.swift new file mode 100644 index 00000000..abc18ab3 --- /dev/null +++ b/Rectangle/WindowCalculation/TwelfthsRepeated.swift @@ -0,0 +1,79 @@ +// +// TwelfthsRepeated.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +protocol TwelfthsRepeated { + func nextCalculation(subAction: SubWindowAction, direction: Direction) -> SimpleCalc? +} + +extension TwelfthsRepeated { + func nextCalculation(subAction: SubWindowAction, direction: Direction) -> SimpleCalc? { + + if direction == .left { + switch subAction { + case .topLeftTwelfth: + return WindowCalculationFactory.bottomRightTwelfthCalculation.orientationBasedRect + case .topCenterLeftTwelfth: + return WindowCalculationFactory.topLeftTwelfthCalculation.orientationBasedRect + case .topCenterRightTwelfth: + return WindowCalculationFactory.topCenterLeftTwelfthCalculation.orientationBasedRect + case .topRightTwelfth: + return WindowCalculationFactory.topCenterRightTwelfthCalculation.orientationBasedRect + case .middleLeftTwelfth: + return WindowCalculationFactory.topRightTwelfthCalculation.orientationBasedRect + case .middleCenterLeftTwelfth: + return WindowCalculationFactory.middleLeftTwelfthCalculation.orientationBasedRect + case .middleCenterRightTwelfth: + return WindowCalculationFactory.middleCenterLeftTwelfthCalculation.orientationBasedRect + case .middleRightTwelfth: + return WindowCalculationFactory.middleCenterRightTwelfthCalculation.orientationBasedRect + case .bottomLeftTwelfth: + return WindowCalculationFactory.middleRightTwelfthCalculation.orientationBasedRect + case .bottomCenterLeftTwelfth: + return WindowCalculationFactory.bottomLeftTwelfthCalculation.orientationBasedRect + case .bottomCenterRightTwelfth: + return WindowCalculationFactory.bottomCenterLeftTwelfthCalculation.orientationBasedRect + case .bottomRightTwelfth: + return WindowCalculationFactory.bottomCenterRightTwelfthCalculation.orientationBasedRect + default: break + } + } + + else if direction == .right { + switch subAction { + case .topLeftTwelfth: + return WindowCalculationFactory.topCenterLeftTwelfthCalculation.orientationBasedRect + case .topCenterLeftTwelfth: + return WindowCalculationFactory.topCenterRightTwelfthCalculation.orientationBasedRect + case .topCenterRightTwelfth: + return WindowCalculationFactory.topRightTwelfthCalculation.orientationBasedRect + case .topRightTwelfth: + return WindowCalculationFactory.middleLeftTwelfthCalculation.orientationBasedRect + case .middleLeftTwelfth: + return WindowCalculationFactory.middleCenterLeftTwelfthCalculation.orientationBasedRect + case .middleCenterLeftTwelfth: + return WindowCalculationFactory.middleCenterRightTwelfthCalculation.orientationBasedRect + case .middleCenterRightTwelfth: + return WindowCalculationFactory.middleRightTwelfthCalculation.orientationBasedRect + case .middleRightTwelfth: + return WindowCalculationFactory.bottomLeftTwelfthCalculation.orientationBasedRect + case .bottomLeftTwelfth: + return WindowCalculationFactory.bottomCenterLeftTwelfthCalculation.orientationBasedRect + case .bottomCenterLeftTwelfth: + return WindowCalculationFactory.bottomCenterRightTwelfthCalculation.orientationBasedRect + case .bottomCenterRightTwelfth: + return WindowCalculationFactory.bottomRightTwelfthCalculation.orientationBasedRect + case .bottomRightTwelfth: + return WindowCalculationFactory.topLeftTwelfthCalculation.orientationBasedRect + default: break + } + } + + return nil + } +} diff --git a/Rectangle/WindowCalculation/UpperLeftCalculation.swift b/Rectangle/WindowCalculation/UpperLeftCalculation.swift index a3a5d2df..ffd2da62 100644 --- a/Rectangle/WindowCalculation/UpperLeftCalculation.swift +++ b/Rectangle/WindowCalculation/UpperLeftCalculation.swift @@ -8,24 +8,41 @@ import Foundation -class UpperLeftCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation { +class UpperLeftCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation, QuartersRepeated { override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + if Defaults.subsequentExecutionMode.cyclesQuadrantPositions { + if let last = params.lastAction, + let lastSubAction = last.subAction, + last.action == .topLeft || lastSubAction == .topLeftQuarter { + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(params.visibleFrameOfScreen) + } + } + return quarterRect(params.visibleFrameOfScreen) + } + if params.lastAction == nil || !Defaults.subsequentExecutionMode.resizes { return calculateFirstRect(params) } - + return calculateRepeatedRect(params) } - + + func quarterRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 2.0) + rect.size.height = floor(visibleFrameOfScreen.height / 2.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + return RectResult(rect, subAction: .topLeftQuarter) + } + func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult { let visibleFrameOfScreen = params.visibleFrameOfScreen var rect = visibleFrameOfScreen - rect.size.width = floor(visibleFrameOfScreen.width * CGFloat(fraction)) - rect.size.height = floor(visibleFrameOfScreen.height / 2.0) rect.origin.y = visibleFrameOfScreen.maxY - rect.height return RectResult(rect) diff --git a/Rectangle/WindowCalculation/UpperMiddleCenterLeftSixteenthCalculation.swift b/Rectangle/WindowCalculation/UpperMiddleCenterLeftSixteenthCalculation.swift new file mode 100644 index 00000000..546bd9d3 --- /dev/null +++ b/Rectangle/WindowCalculation/UpperMiddleCenterLeftSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// UpperMiddleCenterLeftSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class UpperMiddleCenterLeftSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .upperMiddleCenterLeftSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height * 2 + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .upperMiddleCenterLeftSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height * 2 + rect.origin.x = visibleFrameOfScreen.minX + rect.width + return RectResult(rect, subAction: .upperMiddleCenterLeftSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/UpperMiddleCenterRightSixteenthCalculation.swift b/Rectangle/WindowCalculation/UpperMiddleCenterRightSixteenthCalculation.swift new file mode 100644 index 00000000..a29495ca --- /dev/null +++ b/Rectangle/WindowCalculation/UpperMiddleCenterRightSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// UpperMiddleCenterRightSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class UpperMiddleCenterRightSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .upperMiddleCenterRightSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height * 2 + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 2 + return RectResult(rect, subAction: .upperMiddleCenterRightSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height * 2 + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 2 + return RectResult(rect, subAction: .upperMiddleCenterRightSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/UpperMiddleLeftSixteenthCalculation.swift b/Rectangle/WindowCalculation/UpperMiddleLeftSixteenthCalculation.swift new file mode 100644 index 00000000..eac6b600 --- /dev/null +++ b/Rectangle/WindowCalculation/UpperMiddleLeftSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// UpperMiddleLeftSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class UpperMiddleLeftSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .upperMiddleLeftSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height * 2 + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .upperMiddleLeftSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height * 2 + rect.origin.x = visibleFrameOfScreen.minX + return RectResult(rect, subAction: .upperMiddleLeftSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/UpperMiddleRightSixteenthCalculation.swift b/Rectangle/WindowCalculation/UpperMiddleRightSixteenthCalculation.swift new file mode 100644 index 00000000..99c447fb --- /dev/null +++ b/Rectangle/WindowCalculation/UpperMiddleRightSixteenthCalculation.swift @@ -0,0 +1,50 @@ +// +// UpperMiddleRightSixteenthCalculation.swift +// Rectangle +// +// Copyright © 2024 Ryan Hanson. All rights reserved. +// + +import Foundation + +class UpperMiddleRightSixteenthCalculation: WindowCalculation, OrientationAware, SixteenthsRepeated { + + override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + let visibleFrameOfScreen = params.visibleFrameOfScreen + + guard Defaults.subsequentExecutionMode.value != .none, + let last = params.lastAction, + let lastSubAction = last.subAction + else { + return orientationBasedRect(visibleFrameOfScreen) + } + + if last.action != .upperMiddleRightSixteenth { + return orientationBasedRect(visibleFrameOfScreen) + } + + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(visibleFrameOfScreen) + } + + return orientationBasedRect(visibleFrameOfScreen) + } + + func landscapeRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height * 2 + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 3 + return RectResult(rect, subAction: .upperMiddleRightSixteenth) + } + + func portraitRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 4.0) + rect.size.height = floor(visibleFrameOfScreen.height / 4.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height * 2 + rect.origin.x = visibleFrameOfScreen.minX + rect.width * 3 + return RectResult(rect, subAction: .upperMiddleRightSixteenth) + } +} diff --git a/Rectangle/WindowCalculation/UpperRightCalculation.swift b/Rectangle/WindowCalculation/UpperRightCalculation.swift index 6c14f2d2..e3e2da68 100644 --- a/Rectangle/WindowCalculation/UpperRightCalculation.swift +++ b/Rectangle/WindowCalculation/UpperRightCalculation.swift @@ -8,22 +8,41 @@ import Foundation -class UpperRightCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation { +class UpperRightCalculation: WindowCalculation, RepeatedExecutionsInThirdsCalculation, QuartersRepeated { override func calculateRect(_ params: RectCalculationParameters) -> RectResult { + if Defaults.subsequentExecutionMode.cyclesQuadrantPositions { + if let last = params.lastAction, + let lastSubAction = last.subAction, + last.action == .topRight || lastSubAction == .topRightQuarter { + if let calculation = self.nextCalculation(subAction: lastSubAction, direction: .right) { + return calculation(params.visibleFrameOfScreen) + } + } + return quarterRect(params.visibleFrameOfScreen) + } + if params.lastAction == nil || !Defaults.subsequentExecutionMode.resizes { return calculateFirstRect(params) } - + return calculateRepeatedRect(params) } - + + func quarterRect(_ visibleFrameOfScreen: CGRect) -> RectResult { + var rect = visibleFrameOfScreen + rect.size.width = floor(visibleFrameOfScreen.width / 2.0) + rect.origin.x = visibleFrameOfScreen.maxX - rect.width + rect.size.height = floor(visibleFrameOfScreen.height / 2.0) + rect.origin.y = visibleFrameOfScreen.maxY - rect.height + return RectResult(rect, subAction: .topRightQuarter) + } + func calculateFractionalRect(_ params: RectCalculationParameters, fraction: Float) -> RectResult { let visibleFrameOfScreen = params.visibleFrameOfScreen var rect = visibleFrameOfScreen - rect.size.width = floor(visibleFrameOfScreen.width * CGFloat(fraction)) rect.origin.x = visibleFrameOfScreen.maxX - rect.width rect.size.height = floor(visibleFrameOfScreen.height / 2.0) diff --git a/Rectangle/WindowCalculation/WindowCalculation.swift b/Rectangle/WindowCalculation/WindowCalculation.swift index 99d0633a..9de42bd1 100644 --- a/Rectangle/WindowCalculation/WindowCalculation.swift +++ b/Rectangle/WindowCalculation/WindowCalculation.swift @@ -190,6 +190,34 @@ class WindowCalculationFactory { static let bottomVerticalThirdCalculation = BottomVerticalThirdCalculation() static let topVerticalThirdCalculation = TopVerticalThirdCalculation() static let middleVerticalThirdCalculation = MiddleVerticalThirdCalculation() + static let topLeftTwelfthCalculation = TopLeftTwelfthCalculation() + static let topCenterLeftTwelfthCalculation = TopCenterLeftTwelfthCalculation() + static let topCenterRightTwelfthCalculation = TopCenterRightTwelfthCalculation() + static let topRightTwelfthCalculation = TopRightTwelfthCalculation() + static let middleLeftTwelfthCalculation = MiddleLeftTwelfthCalculation() + static let middleCenterLeftTwelfthCalculation = MiddleCenterLeftTwelfthCalculation() + static let middleCenterRightTwelfthCalculation = MiddleCenterRightTwelfthCalculation() + static let middleRightTwelfthCalculation = MiddleRightTwelfthCalculation() + static let bottomLeftTwelfthCalculation = BottomLeftTwelfthCalculation() + static let bottomCenterLeftTwelfthCalculation = BottomCenterLeftTwelfthCalculation() + static let bottomCenterRightTwelfthCalculation = BottomCenterRightTwelfthCalculation() + static let bottomRightTwelfthCalculation = BottomRightTwelfthCalculation() + static let topLeftSixteenthCalculation = TopLeftSixteenthCalculation() + static let topCenterLeftSixteenthCalculation = TopCenterLeftSixteenthCalculation() + static let topCenterRightSixteenthCalculation = TopCenterRightSixteenthCalculation() + static let topRightSixteenthCalculation = TopRightSixteenthCalculation() + static let upperMiddleLeftSixteenthCalculation = UpperMiddleLeftSixteenthCalculation() + static let upperMiddleCenterLeftSixteenthCalculation = UpperMiddleCenterLeftSixteenthCalculation() + static let upperMiddleCenterRightSixteenthCalculation = UpperMiddleCenterRightSixteenthCalculation() + static let upperMiddleRightSixteenthCalculation = UpperMiddleRightSixteenthCalculation() + static let lowerMiddleLeftSixteenthCalculation = LowerMiddleLeftSixteenthCalculation() + static let lowerMiddleCenterLeftSixteenthCalculation = LowerMiddleCenterLeftSixteenthCalculation() + static let lowerMiddleCenterRightSixteenthCalculation = LowerMiddleCenterRightSixteenthCalculation() + static let lowerMiddleRightSixteenthCalculation = LowerMiddleRightSixteenthCalculation() + static let bottomLeftSixteenthCalculation = BottomLeftSixteenthCalculation() + static let bottomCenterLeftSixteenthCalculation = BottomCenterLeftSixteenthCalculation() + static let bottomCenterRightSixteenthCalculation = BottomCenterRightSixteenthCalculation() + static let bottomRightSixteenthCalculation = BottomRightSixteenthCalculation() static let calculationsByAction: [WindowAction: WindowCalculation] = [ .leftHalf: leftHalfCalculation, @@ -273,7 +301,35 @@ class WindowCalculationFactory { .middleVerticalThird: middleVerticalThirdCalculation, .bottomVerticalThird: bottomVerticalThirdCalculation, .topVerticalTwoThirds: topVerticalTwoThirdsCalculation, - .bottomVerticalTwoThirds: bottomVerticalTwoThirdsCalculation + .bottomVerticalTwoThirds: bottomVerticalTwoThirdsCalculation, + .topLeftTwelfth: topLeftTwelfthCalculation, + .topCenterLeftTwelfth: topCenterLeftTwelfthCalculation, + .topCenterRightTwelfth: topCenterRightTwelfthCalculation, + .topRightTwelfth: topRightTwelfthCalculation, + .middleLeftTwelfth: middleLeftTwelfthCalculation, + .middleCenterLeftTwelfth: middleCenterLeftTwelfthCalculation, + .middleCenterRightTwelfth: middleCenterRightTwelfthCalculation, + .middleRightTwelfth: middleRightTwelfthCalculation, + .bottomLeftTwelfth: bottomLeftTwelfthCalculation, + .bottomCenterLeftTwelfth: bottomCenterLeftTwelfthCalculation, + .bottomCenterRightTwelfth: bottomCenterRightTwelfthCalculation, + .bottomRightTwelfth: bottomRightTwelfthCalculation, + .topLeftSixteenth: topLeftSixteenthCalculation, + .topCenterLeftSixteenth: topCenterLeftSixteenthCalculation, + .topCenterRightSixteenth: topCenterRightSixteenthCalculation, + .topRightSixteenth: topRightSixteenthCalculation, + .upperMiddleLeftSixteenth: upperMiddleLeftSixteenthCalculation, + .upperMiddleCenterLeftSixteenth: upperMiddleCenterLeftSixteenthCalculation, + .upperMiddleCenterRightSixteenth: upperMiddleCenterRightSixteenthCalculation, + .upperMiddleRightSixteenth: upperMiddleRightSixteenthCalculation, + .lowerMiddleLeftSixteenth: lowerMiddleLeftSixteenthCalculation, + .lowerMiddleCenterLeftSixteenth: lowerMiddleCenterLeftSixteenthCalculation, + .lowerMiddleCenterRightSixteenth: lowerMiddleCenterRightSixteenthCalculation, + .lowerMiddleRightSixteenth: lowerMiddleRightSixteenthCalculation, + .bottomLeftSixteenth: bottomLeftSixteenthCalculation, + .bottomCenterLeftSixteenth: bottomCenterLeftSixteenthCalculation, + .bottomCenterRightSixteenth: bottomCenterRightSixteenthCalculation, + .bottomRightSixteenth: bottomRightSixteenthCalculation // .restore: nil ] }