A SwiftUI-style declarative NSTouchBar
for AppKit.
NSTouchBar
has an amazing API with incredible flexibility, but I find that it can be too verbose and spread throughout your code with the use of delegates and callbacks for simpler projects and I have trouble keeping tabs on all the individual components. Even moreso if you want to use actions and bindings on the touchbar objects which just increases the amount code required for each touchbar.
Give that I'd written a SwiftUI-style declarative API for NSToolbar
I adapted the API for NSTouchBar
.
I know that I'm late to the game here - but there's still going to be quite a while before a lot of existing apps can migrate upwards to SwiftUI (especially my own small apps).
If you're going pure SwiftUI now for your apps, you should use the touchbar(_:)
ViewModifier.
If you're familiar with SwiftUI syntax you'll feel comfortable with the declaration style.
class ViewController: NSViewController {
@objc dynamic var editbutton_state: NSButton.ControlState = .off
@objc dynamic var canEdit: Bool = false
@objc dynamic var upgradeBackgroundColor: NSColor = .clear
override func makeTouchBar() -> NSTouchBar? {
DSFTouchBar(
baseIdentifier: .init("com.myapp.touchbardemo.documentation"),
customizationIdentifier: .init("com.myapp.touchbardemo.documentation.docodemo")) {
// This button will have the unique identifier 'com.darrenford.dsftouchbar.documentation.edit-document'
DSFTouchBar.Button(.init("edit-document"))
.title("Edit")
.type(.onOff)
.bindState(to: self, withKeyPath: \ViewController.editbutton_state)
.bindBackgroundColor(to: self, withKeyPath: \ViewController.editBackgroundColor)
.action { _ in
Swift.print("Edit button pressed")
}
// This button will have the unique identifier 'com.darrenford.dsftouchbar.documentation.upgrade-document'
DSFTouchBar.Button(.init("upgrade-document"))
.title("Upgrade")
.bindIsEnabled(to: self, withKeyPath: \ViewController.canEdit)
.bindBackgroundColor(to: self, withKeyPath: \ViewController.upgradeBackgroundColor)
.action { _ in
Swift.print("Upgrade button pressed")
}
// This button will have the unique identifier 'com.darrenford.dsftouchbar.documentation.go-document'
DSFTouchBar.Button(.init("go-button"))
.title("Go")
.image(NSImage(named: NSImage.touchBarGoForwardTemplateName))
.imagePosition(.imageRight)
.action { state in
Swift.print("GO!")
}
DSFTouchBar.OtherItemsPlaceholder()
}
.makeTouchBar()
}
}
Type | Description |
---|---|
Button | Add a button to the touchbar |
ColorPicker | Add a color picker control to the touchbar |
Group | Add an item that contains a grouping of other items |
Label | Add a label to the touchbar |
Popover | Add a popover |
ScrollGroup | Add an item that contains a scrollable grouping of other items |
Segmented | Add a segmented control to the touchbar |
SharingServicePicker | Add a button that presents the sharing services when pressed |
Slider | Add a slider control to the touchbar |
View | Add a custom view to the touch bar |
OtherItems | A special "other items proxy", which is used to nest touch bars up the responder chain. Refer to Apple's documentation for more information |
The baseIdentifier for the toolbar provides the 'root' identifier for all of the children. When a toolbar item is added, the identifier provided for the item is appended to the baseIdentifier to make a unique identifier.
This is done to try to reduce the verboseness of specifying a full identifier for each child of the toolbar.
DSFTouchBar(baseIdentifier: .init("com.myapp.touchbardemo")) {
DSFTouchBar.Button(.init("edit-document")) // identifier is 'com.myapp.touchbardemo.edit-document'
}
The customization identifier allows the touchbar to be customized. The identifier is used when storing the configuration for the touchbar to disk.
DSFTouchBar(
baseIdentifier: .init("com.myapp.touchbardemo"),
customizationIdentifier: .init("com.myapp.touchbardemo.settings")) {
DSFTouchBar.Button(.init("edit-document")) // identifier is 'com.myapp.touchbardemo.edit-document'
}
You can find some demos for macOS in the Demos
subfolder
The touchbar will only be shown for a view/control that accepts first responder (ie. acceptsFirstResponder == true for the view)
Check to see that the leafIdentifier
for all controls is unique.
You need to tell your app to enable customize touchbar behaviour.
NSApplication.shared.isAutomaticCustomizeTouchBarMenuItemEnabled = true
You can only customize a touchbar that has a customizationIdentifier
specified for it.
DSFTouchBar(
baseIdentifier: .init("com.myapp.documentation"),
customizationIdentifier: .init("com.myapp.documentation.docodemo")) {
You need to specify a customizationLabel
for each DSFTouchBar item.
DSFTouchBar.Button(.init("edit-document"), customizationLabel: "Edit Document")
Initial release.
MIT. Use it for anything you want! Let me know if you do use it somewhere, I'd love to hear about it.
MIT License
Copyright (c) 2021 Darren Ford
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
link |
Stars: 5 |
Last commit: 2 years ago |
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics