tangled
alpha
login
or
join now
jonmsterling.com
/
AquaKit
4
fork
atom
A collection of user interface components and drawing routines for building tasteful apps using AppKit.
appkit
swift
aqua
ui
mac
4
fork
atom
overview
issues
1
pulls
pipelines
Working on window bottom bar
jonmsterling.com
1 month ago
6ed916c8
fb165347
+79
-34
8 changed files
expand all
collapse all
unified
split
Sources
AquaKit
Controls and Views
AquaSplitViewResizeHandle.swift
SplitViewResizeCoordinator.swift
Scroll Views
AquaScroller.swift
Source Lists
SourceListBottomBarViewController.swift
Windows
AquaTitlebarBackgroundView.swift
AquaTrafficLightButton.swift
AquaWindow.swift
AquaWindowBottomBarViewController.swift
+18
-19
Sources/AquaKit/Controls and Views/AquaResizeHandle.swift
Sources/AquaKit/Controls and Views/AquaSplitViewResizeHandle.swift
···
1
1
import AppKit
2
2
3
3
-
open class AquaResizeHandle: NSControl {
3
3
+
open class AquaSplitViewResizeHandle: NSControl {
4
4
public struct Drag {
5
5
public var initialLocation: NSPoint = .zero
6
6
-
public var delta: CGFloat = 0
6
6
+
public var finalLocation: NSPoint = .zero
7
7
}
8
8
9
9
override open var mouseDownCanMoveWindow: Bool { false }
···
34
34
35
35
public required init?(coder: NSCoder) {
36
36
fatalError("init(coder:) has not been implemented")
37
37
-
}
38
38
-
39
39
-
override open func draw(_ dirtyRect: NSRect) {
40
40
-
let path = NSBezierPath()
41
41
-
let bounds = bounds.insetBy(dx: 4, dy: 0)
42
42
-
path.move(to: NSPoint(x: bounds.minX, y: bounds.minY))
43
43
-
path.line(to: NSPoint(x: bounds.minX, y: bounds.maxY))
44
44
-
path.move(to: NSPoint(x: bounds.midX, y: bounds.minY))
45
45
-
path.line(to: NSPoint(x: bounds.midX, y: bounds.maxY))
46
46
-
path.move(to: NSPoint(x: bounds.maxX, y: bounds.minY))
47
47
-
path.line(to: NSPoint(x: bounds.maxX, y: bounds.maxY))
48
48
-
path.lineWidth = 1
49
49
-
50
50
-
NSColor.aquaSeparatorColor.setStroke()
51
51
-
path.stroke()
52
37
}
53
38
54
39
override open func mouseDown(with event: NSEvent) {
···
57
42
58
43
override open func mouseDragged(with event: NSEvent) {
59
44
guard var drag = activeDrag else { return }
60
60
-
let location = convert(event.locationInWindow, from: nil)
61
61
-
drag.delta = location.x - drag.initialLocation.x
45
45
+
drag.finalLocation = convert(event.locationInWindow, from: nil)
62
46
activeDrag = drag
63
47
sendAction(action, to: target)
64
48
}
···
69
53
70
54
override open func acceptsFirstMouse(for event: NSEvent?) -> Bool {
71
55
true
56
56
+
}
57
57
+
58
58
+
override open func draw(_ dirtyRect: NSRect) {
59
59
+
let path = NSBezierPath()
60
60
+
let bounds = bounds.insetBy(dx: 4, dy: 0)
61
61
+
path.move(to: NSPoint(x: bounds.minX, y: bounds.minY))
62
62
+
path.line(to: NSPoint(x: bounds.minX, y: bounds.maxY))
63
63
+
path.move(to: NSPoint(x: bounds.midX, y: bounds.minY))
64
64
+
path.line(to: NSPoint(x: bounds.midX, y: bounds.maxY))
65
65
+
path.move(to: NSPoint(x: bounds.maxX, y: bounds.minY))
66
66
+
path.line(to: NSPoint(x: bounds.maxX, y: bounds.maxY))
67
67
+
path.lineWidth = 1
68
68
+
69
69
+
NSColor.aquaSeparatorColor.setStroke()
70
70
+
path.stroke()
72
71
}
73
72
}
+3
-2
Sources/AquaKit/Controls and Views/SplitViewResizeCoordinator.swift
···
9
9
}
10
10
11
11
@MainActor
12
12
-
@objc public func resize(_ sender: AquaResizeHandle) {
12
12
+
@objc public func resize(_ sender: AquaSplitViewResizeHandle) {
13
13
guard let drag = sender.activeDrag else { return }
14
14
let subview = splitView.arrangedSubviews[dividerIndex]
15
15
let currentPosition = splitView.isVertical ? subview.frame.maxX : subview.frame.maxY
16
16
-
splitView.setPosition(currentPosition + drag.delta, ofDividerAt: dividerIndex)
16
16
+
let delta = drag.finalLocation.x - drag.initialLocation.x
17
17
+
splitView.setPosition(currentPosition + delta, ofDividerAt: dividerIndex)
17
18
}
18
19
}
+4
Sources/AquaKit/Scroll Views/AquaScroller.swift
···
139
139
} else {
140
140
baseColor = NSColor.graphiteColor.highlight(withLevel: 0.5)!
141
141
}
142
142
+
143
143
+
if effectiveAppearance.isDarkAqua {
144
144
+
baseColor = baseColor.blended(withFraction: 0.3, of: .graphiteColor.shadow(withLevel: 0.8)!)!
145
145
+
}
142
146
143
147
do {
144
148
NSGraphicsContext.saveGraphicsState()
+4
-8
Sources/AquaKit/Source Lists/SourceListBottomBarViewController.swift
···
1
1
import AppKit
2
2
3
3
open class SourceListBottomBarViewController: NSSplitViewItemAccessoryViewController {
4
4
-
public let resizeHandle = AquaResizeHandle()
4
4
+
public let resizeHandle = AquaSplitViewResizeHandle()
5
5
6
6
public override init(nibName nibNameOrNil: NSNib.Name?, bundle nibBundleOrNil: Bundle?) {
7
7
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
···
56
56
gradient?.draw(in: bounds, angle: 270)
57
57
NSGraphicsContext.restoreGraphicsState()
58
58
59
59
-
let borderPath = NSBezierPath()
60
60
-
borderPath.move(to: NSPoint(x: bounds.minX, y: bounds.maxY))
61
61
-
borderPath.line(to: NSPoint(x: bounds.maxX, y: bounds.maxY))
62
62
-
borderPath.lineWidth = 1
63
63
-
NSColor.aquaSeparatorColor.setStroke()
64
64
-
borderPath.stroke()
59
59
+
NSColor.aquaSeparatorColor.setFill()
60
60
+
NSBezierPath.fill(NSRect(x: bounds.minX, y: bounds.maxY - 1, width: bounds.width, height: 1))
65
61
}
66
62
}
67
63
···
82
78
])
83
79
84
80
automaticallyAppliesContentInsets = false
85
85
-
view.heightAnchor.constraint(equalToConstant: 30).isActive = true
81
81
+
view.heightAnchor.constraint(equalToConstant: AquaWindow.bottomBarThickness).isActive = true
86
82
}
87
83
}
+2
-2
Sources/AquaKit/Windows/AquaTitlebarBackgroundView.swift
···
10
10
fatalError("init(coder:) has not been implemented")
11
11
}
12
12
13
13
-
private var gradient: NSGradient? {
13
13
+
static var gradient: NSGradient! {
14
14
let color1 = NSColor(light: #colorLiteral(red: 0.9262896776, green: 0.9262896776, blue: 0.9262896776, alpha: 1), dark: .underPageBackgroundColor.highlight(withLevel: 0.3)!.withAlphaComponent(0.2))
15
15
let color2 = NSColor(light: #colorLiteral(red: 0.8432617784, green: 0.8432616591, blue: 0.8432617784, alpha: 1), dark: .underPageBackgroundColor.withAlphaComponent(0.2))
16
16
return NSGradient(colors: [color1, color2])!
···
25
25
}
26
26
27
27
override open func draw(_ dirtyRect: NSRect) {
28
28
-
gradient!.draw(in: bounds, angle: 270)
28
28
+
Self.gradient.draw(in: bounds, angle: 270)
29
29
30
30
NSColor.aquaSeparatorColor.setStroke()
31
31
dividerPath.stroke()
+6
-3
Sources/AquaKit/Windows/AquaTrafficLightButton.swift
···
65
65
66
66
override open func draw(_ dirtyRect: NSRect) {
67
67
NSGraphicsContext.saveGraphicsState()
68
68
-
68
68
+
69
69
var color = kind.baseColor
70
70
if NSColor.controlAccentColor.isGrayscale {
71
71
color = .graphiteColor
···
120
120
121
121
color.shadow(withLevel: 0.7)!.setStroke()
122
122
ellipse.stroke()
123
123
-
123
123
+
124
124
NSGraphicsContext.restoreGraphicsState()
125
125
}
126
126
···
163
163
case .zoom: #colorLiteral(red: 0.5023847222, green: 0.7764200568, blue: 0.07384926826, alpha: 1)
164
164
}
165
165
166
166
-
return NSColor(light: unblended, dark: unblended.blended(withFraction: 0.5, of: .black)!)
166
166
+
return NSColor(
167
167
+
light: unblended,
168
168
+
dark: unblended.blended(withFraction: 0.6, of: .graphiteColor.shadow(withLevel: 0.9)!)!
169
169
+
)
167
170
}
168
171
}
+2
Sources/AquaKit/Windows/AquaWindow.swift
···
1
1
import AppKit
2
2
3
3
open class AquaWindow: NSWindow {
4
4
+
public static var bottomBarThickness: CGFloat { 30.0 }
5
5
+
4
6
private var _showsToolbarButton: Bool = false
5
7
override open var showsToolbarButton: Bool {
6
8
get { _showsToolbarButton }
+40
Sources/AquaKit/Windows/AquaWindowBottomBarViewController.swift
···
1
1
+
import AppKit
2
2
+
3
3
+
open class AquaWindowBottomBarViewController: ContainerViewController {
4
4
+
class View: NSView {
5
5
+
override init(frame frameRect: NSRect) {
6
6
+
super.init(frame: frameRect)
7
7
+
addSubview(WindowStateSentinelView())
8
8
+
}
9
9
+
10
10
+
required init?(coder: NSCoder) {
11
11
+
fatalError("init(coder:) has not been implemented")
12
12
+
}
13
13
+
14
14
+
private var dividerPath: NSBezierPath {
15
15
+
let dividerPath = NSBezierPath()
16
16
+
dividerPath.move(to: NSPoint(x: bounds.minX, y: bounds.maxY))
17
17
+
dividerPath.line(to: NSPoint(x: bounds.maxX, y: bounds.maxY))
18
18
+
dividerPath.lineWidth = 1
19
19
+
return dividerPath
20
20
+
}
21
21
+
22
22
+
override open func draw(_ dirtyRect: NSRect) {
23
23
+
AquaTitlebarBackgroundView.gradient.draw(in: bounds, angle: 270)
24
24
+
25
25
+
if let window, !window.isKeyWindow {
26
26
+
NSColor.pinstripes.setFill()
27
27
+
bounds.fill()
28
28
+
}
29
29
+
30
30
+
NSColor.aquaSeparatorColor.setFill()
31
31
+
NSBezierPath.fill(NSRect(x: bounds.minX, y: bounds.maxY - 1, width: bounds.width, height: 1))
32
32
+
33
33
+
// TODO: using NSColor.aquaSeparatorColor, draw a window resize handle with four diagonal lines in the style of Mac OS X, in the lower-right corner.
34
34
+
}
35
35
+
}
36
36
+
37
37
+
open override func loadView() {
38
38
+
view = View()
39
39
+
}
40
40
+
}