Skip to content

Commit

Permalink
Allow custom width for vertically positioned panes
Browse files Browse the repository at this point in the history
Also, shrink panes if needed to prevent going beyond screen boundaries
  • Loading branch information
mr-pennyworth committed Jul 26, 2024
1 parent 09b9cc4 commit dc2fb39
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 53 deletions.
8 changes: 6 additions & 2 deletions AlfredExtraPane.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
D03EA8D725551E0700D3656E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D03EA8D625551E0700D3656E /* Assets.xcassets */; };
D040E2422667A4FC00495B2D /* Alfred in Frameworks */ = {isa = PBXBuildFile; productRef = D040E2412667A4FC00495B2D /* Alfred */; };
D04F70D5255893B3008E17A4 /* NSColorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04F70D4255893B3008E17A4 /* NSColorExtension.swift */; };
D07349462C541D6300F004C8 /* PanePosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07349452C541D6300F004C8 /* PanePosition.swift */; };
D07360EA2C3237F600739755 /* NSColorExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07360E92C3237F600739755 /* NSColorExtensionTests.swift */; };
D08B6EE5266F31790099EB36 /* Pane.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08B6EE4266F31790099EB36 /* Pane.swift */; };
D08B6EE7266F9B520099EB36 /* PanePositionCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08B6EE6266F9B520099EB36 /* PanePositionCodable.swift */; };
Expand Down Expand Up @@ -60,6 +61,7 @@
D03EA8D625551E0700D3656E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
D03EA8DB25551E0700D3656E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D04F70D4255893B3008E17A4 /* NSColorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSColorExtension.swift; sourceTree = "<group>"; };
D07349452C541D6300F004C8 /* PanePosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PanePosition.swift; sourceTree = "<group>"; };
D07360E92C3237F600739755 /* NSColorExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSColorExtensionTests.swift; sourceTree = "<group>"; };
D08B6EE4266F31790099EB36 /* Pane.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pane.swift; sourceTree = "<group>"; };
D08B6EE6266F9B520099EB36 /* PanePositionCodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PanePositionCodable.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -119,6 +121,7 @@
D04F70D4255893B3008E17A4 /* NSColorExtension.swift */,
D01646B9255AF27A00646F0C /* utils.swift */,
D08B6EE4266F31790099EB36 /* Pane.swift */,
D07349452C541D6300F004C8 /* PanePosition.swift */,
D08B6EE6266F9B520099EB36 /* PanePositionCodable.swift */,
D0FCE9402C40049200F5006C /* Menu.swift */,
D0FCE9422C400A7600F5006C /* WebViewInjection.swift */,
Expand Down Expand Up @@ -257,6 +260,7 @@
D04F70D5255893B3008E17A4 /* NSColorExtension.swift in Sources */,
D08B6EE7266F9B520099EB36 /* PanePositionCodable.swift in Sources */,
D0FCE9432C400A7600F5006C /* WebViewInjection.swift in Sources */,
D07349462C541D6300F004C8 /* PanePosition.swift in Sources */,
D01646BA255AF27A00646F0C /* utils.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -409,7 +413,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 0.2.1;
MARKETING_VERSION = 0.2.2;
ONLY_ACTIVE_ARCH = NO;
OTHER_CODE_SIGN_FLAGS = "--deep";
PRODUCT_BUNDLE_IDENTIFIER = mr.pennyworth.AlfredExtraPane;
Expand All @@ -430,7 +434,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 0.2.1;
MARKETING_VERSION = 0.2.2;
ONLY_ACTIVE_ARCH = NO;
OTHER_CODE_SIGN_FLAGS = "--deep";
PRODUCT_BUNDLE_IDENTIFIER = mr.pennyworth.AlfredExtraPane;
Expand Down
43 changes: 1 addition & 42 deletions AlfredExtraPane/Pane.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@ import Cocoa
import Foundation
import WebKit

enum PanePosition: Equatable {
enum HorizontalPlacement: String, Codable, CodingKey { case left, right }
enum VerticalPlacement: String, Codable, CodingKey { case top, bottom }

case horizontal(placement: HorizontalPlacement, width: Int, minHeight: Int?)
case vertical(placement: VerticalPlacement, height: Int)
}

public struct WorkflowPaneConfig {
let paneConfig: PaneConfig
Expand Down Expand Up @@ -100,42 +93,8 @@ class Pane {
showWindow()
}

func width() -> CGFloat {
switch self.config.alignment {
case .horizontal(_, let w, _): return CGFloat(w)
case .vertical(_, _): return alfredFrame.width
}
}

func height() -> CGFloat {
switch self.config.alignment {
case .horizontal(_, _, nil): return alfredFrame.height
case .horizontal(_, _, let mh?): return max(CGFloat(mh), alfredFrame.height)
case .vertical(_, let h): return CGFloat(h)
}
}

func x() -> CGFloat {
let alf = alfredFrame.minX
let alfw = alfredFrame.width
switch self.config.alignment {
case .vertical(_, _): return alf
case .horizontal(.left, _, _): return alf - (width() + margin)
case .horizontal(.right, _, _): return alf + (alfw + margin)
}
}

func y() -> CGFloat {
let alf = alfredFrame
switch self.config.alignment {
case .horizontal(_, _, _): return alf.maxY - height()
case .vertical(.top, _): return alf.maxY + margin
case .vertical(.bottom, _): return alf.minY - (height() + margin)
}
}

func frame() -> NSRect {
NSRect(x: x(), y: y(), width: width(), height: height())
NSRect(at: self.config.alignment, wrt: alfredFrame, withMargin: margin)
}

func showWindow() {
Expand Down
83 changes: 83 additions & 0 deletions AlfredExtraPane/PanePosition.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import Cocoa
import Foundation

enum PanePosition: Equatable {
enum HorizontalPlacement: String, Codable, CodingKey { case left, right }
enum VerticalPlacement: String, Codable, CodingKey { case top, bottom }

case horizontal(placement: HorizontalPlacement, width: Int, minHeight: Int?)
case vertical(placement: VerticalPlacement, height: Int, width: Int?)
}

extension NSRect {
init(at position: PanePosition, wrt ref: NSRect, withMargin margin: CGFloat) {
let screen = ref.screenFrame

let width: CGFloat = {
switch position {
case .horizontal(.left, let w, _): min(
CGFloat(w),
ref.horizontalSpaceLeft - 2 * margin
)
case .horizontal(.right, let w, _): min(
CGFloat(w),
ref.horizontalSpaceRight - 2 * margin
)
case .vertical(_, _, nil): min(
ref.width,
screen.width - 2 * margin
)
case .vertical(_, _, let w?): min(
CGFloat(w),
screen.width - 2 * margin
)
}
}()

let height: CGFloat = {
switch position {
case .horizontal(_, _, nil): ref.height
case .horizontal(_, _, let mh?): max(CGFloat(mh), ref.height)
case .vertical(.bottom, let h, _): min(
CGFloat(h),
ref.verticalSpaceBelow - 2 * margin
)
case .vertical(.top, let h, _): min(
CGFloat(h),
ref.verticalSpaceAbove - 2 * margin
)
}
}()

let x: CGFloat = {
switch position {
case .vertical(_, _, _): ref.minX + (ref.width - width) / 2
case .horizontal(.left, _, _): ref.minX - (width + margin)
case .horizontal(.right, _, _): ref.minX + (ref.width + margin)
}
}()

let y: CGFloat = {
switch position {
case .horizontal(_, _, _): ref.maxY - height
case .vertical(.top, _, _): ref.maxY + margin
case .vertical(.bottom, _, _): ref.minY - (height + margin)
}
}()

self.init(x: x, y: y, width: width, height: height)
}

var screenFrame: NSRect {
NSScreen.screens.first(where: { $0.frame.intersects(self) })!.visibleFrame
}

var verticalSpaceBelow: CGFloat { minY - screenFrame.minY }

var verticalSpaceAbove: CGFloat { screenFrame.maxY - maxY }

var horizontalSpaceRight: CGFloat { screenFrame.maxX - maxX }

var horizontalSpaceLeft: CGFloat { minX - screenFrame.minX }
}

8 changes: 5 additions & 3 deletions AlfredExtraPane/PanePositionCodable.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
extension PanePosition: Codable {
enum CodingKeys: CodingKey { case horizontal, vertical }
enum HorizontalKeys: CodingKey { case placement, width, minHeight }
enum VerticalKeys: CodingKey { case placement, height }
enum VerticalKeys: CodingKey { case placement, height, width }

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
Expand All @@ -18,7 +18,8 @@ extension PanePosition: Codable {
forKey: .placement
)
let height = try nested.decode(Int.self, forKey: .height)
self = .vertical(placement: placement, height: height)
let width = try? nested.decode(Int.self, forKey: .width)
self = .vertical(placement: placement, height: height, width: width)
case .horizontal:
let nested = try container.nestedContainer(
keyedBy: HorizontalKeys.self,
Expand Down Expand Up @@ -50,13 +51,14 @@ extension PanePosition: Codable {
var container = encoder.container(keyedBy: CodingKeys.self)

switch self {
case .vertical(let position, let height):
case .vertical(let position, let height, let width):
var nested = container.nestedContainer(
keyedBy: VerticalKeys.self,
forKey: .vertical
)
try nested.encode(position, forKey: .placement)
try nested.encode(height, forKey: .height)
try nested.encode(width, forKey: .width)
case .horizontal(let position, let width, let minHeight):
var nested = container.nestedContainer(
keyedBy: HorizontalKeys.self,
Expand Down
6 changes: 3 additions & 3 deletions AlfredExtraPaneTests/AlfredExtraPaneTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class AlfredExtraPaneTests: XCTestCase {
"horizontal" : {"placement" : "left", "width" : 300, "minHeight" : null}}
}, {
"alignment" : {
"vertical" : {"placement" : "top", "height" : 100}},
"vertical" : {"placement" : "top", "height" : 100, "width": 25}},
"customJSFilename": "script.js",
"mediaAutoplay": true
}, {
Expand Down Expand Up @@ -45,15 +45,15 @@ final class AlfredExtraPaneTests: XCTestCase {
mediaAutoplay: nil
),
AlfredExtraPane.PaneConfig(
alignment: .vertical(placement: .top, height: 100),
alignment: .vertical(placement: .top, height: 100, width: 25),
customUserAgent: nil,
customCSSFilename: nil,
customJSFilename: "script.js",
staticPaneConfig: nil,
mediaAutoplay: true
),
AlfredExtraPane.PaneConfig(
alignment: .vertical(placement: .bottom, height: 200),
alignment: .vertical(placement: .bottom, height: 200, width: nil),
customUserAgent: nil,
customCSSFilename: nil,
customJSFilename: nil,
Expand Down
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,23 @@ Configurable parameters are:
- `alignment` (required):
- `horizontal`
- `placement`: `left` or `right`
- `width`: width of the pane
- `minHeight`: minimum height of the pane
- `width`: width of the pane. If the width is so large that the
pane doesn't fit on the screen, it is automatically reduced so
that the pane fills the entire horizontal space between the
Alfred window and the edge of the screen.
- `minHeight` (optional): minimum height of the pane. If not
specified, the height of the pane is always same as the height
of the Alfred window.
- `vertical`
- `placement`: `top` or `bottom`
- `height`: height of the pane
- `height`: height of the pane. If the height is so large that the
pane doesn't fit on the screen, it is automatically reduced so
that the pane fills the entire vertical space between the
Alfred window and the edge of the screen.
- `width` (optional): width of the pane. If not specified, the
width of the pane is always same as the width of the Alfred
window. If the width is larger than the screen width, the pane
is reduced so that it fits the screen.
- `customUserAgent` (optional): User-Agent string for HTTP(S) URLs
- `customCSSFilename` (optional): Name of the CSS file to be loaded
in the pane. The file should be in the same directory as the JSON
Expand Down

0 comments on commit dc2fb39

Please sign in to comment.