├── .gitignore ├── BurntCocoaUITests ├── BurntCocoaUITests-Bridging-Header.h ├── Info.plist └── MainTests.swift ├── BurntCocoaUI.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved ├── xcshareddata │ └── xcschemes │ │ └── BurntCocoaUI.xcscheme └── project.pbxproj ├── BurntCocoaUI ├── UIControlAssistant.swift ├── NSResponder.swift ├── NSEvent.swift ├── BurntCocoaUI.h ├── Target.swift ├── UIChoiceRepresentative.swift ├── Info.plist ├── Renderers.swift ├── PlaceholderMenuItemAssistant.swift ├── MenuAssistant.swift ├── PopUpButtonAssistant.swift ├── Field.swift ├── MenuItemsAssistant.swift └── SegmentedControlAssistant.swift ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | BurntCocoaUI.xcodeproj/xcuserdata 2 | xcuserdata 3 | -------------------------------------------------------------------------------- /BurntCocoaUITests/BurntCocoaUITests-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /BurntCocoaUI.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BurntCocoaUI.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /BurntCocoaUI/UIControlAssistant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIControlAssistant.swift 3 | // BurntCocoaUI 4 | // 5 | // Created by Patrick Smith on 25/04/2016. 6 | // Copyright © 2016 Burnt Caramel. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | protocol UIControlAssistant { 13 | associatedtype Value : Hashable 14 | associatedtype Control : NSView 15 | 16 | var control: Control { get } 17 | 18 | var controlRenderer: (Value?) -> Control { get } 19 | } 20 | -------------------------------------------------------------------------------- /BurntCocoaUI/NSResponder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSResponder.swift 3 | // BurntCocoaUI 4 | // 5 | // Created by Patrick Smith on 22/04/2016. 6 | // Copyright © 2016 Burnt Caramel. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | extension NSResponder { 13 | public var nextResponderChain: AnySequence { 14 | var currentNextResponder = nextResponder 15 | return AnySequence(AnyIterator { 16 | defer { 17 | currentNextResponder = currentNextResponder?.nextResponder 18 | } 19 | 20 | return currentNextResponder 21 | }) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BurntCocoaUI/NSEvent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSEvent.swift 3 | // BurntCocoaUI 4 | // 5 | // Created by Patrick Smith on 6/09/2015. 6 | // Copyright (c) 2015 Burnt Caramel. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | extension NSEvent { 13 | public var burnt_firstCharacter: Character? { 14 | if let charactersIgnoringModifiers = charactersIgnoringModifiers { 15 | return charactersIgnoringModifiers[charactersIgnoringModifiers.startIndex] 16 | } 17 | 18 | return nil 19 | } 20 | 21 | public var burnt_isSpaceKey: Bool { 22 | return burnt_firstCharacter == " " 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /BurntCocoaUI/BurntCocoaUI.h: -------------------------------------------------------------------------------- 1 | // 2 | // BurntCocoaUI.h 3 | // BurntCocoaUI 4 | // 5 | // Created by Patrick Smith on 4/05/2015. 6 | // Copyright (c) 2015 Burnt Caramel. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for BurntCocoaUI. 12 | FOUNDATION_EXPORT double BurntCocoaUIVersionNumber; 13 | 14 | //! Project version string for BurntCocoaUI. 15 | FOUNDATION_EXPORT const unsigned char BurntCocoaUIVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /BurntCocoaUI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "CwlCatchException", 6 | "repositoryURL": "https://github.com/mattgallagher/CwlCatchException.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "f809deb30dc5c9d9b78c872e553261a61177721a", 10 | "version": "2.0.0" 11 | } 12 | }, 13 | { 14 | "package": "CwlPreconditionTesting", 15 | "repositoryURL": "https://github.com/mattgallagher/CwlPreconditionTesting.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "02b7a39a99c4da27abe03cab2053a9034379639f", 19 | "version": "2.0.0" 20 | } 21 | } 22 | ] 23 | }, 24 | "version": 1 25 | } 26 | -------------------------------------------------------------------------------- /BurntCocoaUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /BurntCocoaUI/Target.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Target.swift 3 | // BurntCocoaUI 4 | // 5 | // Created by Patrick Smith on 27/04/2016. 6 | // Copyright © 2016 Burnt Caramel. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | public class Target : NSObject { 12 | fileprivate var onPerform: (_ sender: AnyObject?) -> () 13 | 14 | public init(onPerform: @escaping (_ sender: AnyObject?) -> ()) { 15 | self.onPerform = onPerform 16 | } 17 | 18 | @objc public func performed(_ sender: AnyObject?) { 19 | onPerform(sender) 20 | } 21 | 22 | public var action: Selector = #selector(Target.performed(_:)) 23 | } 24 | 25 | 26 | extension NSControl { 27 | public func setActionHandler(_ onPerform: @escaping (_ sender: AnyObject?) -> ()) -> Target { 28 | let target = Target(onPerform: onPerform) 29 | self.target = target 30 | self.action = target.action 31 | 32 | return target 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /BurntCocoaUI/UIChoiceRepresentative.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIChoiceRepresentative.swift 3 | // BurntCocoaUI 4 | // 5 | // Created by Patrick Smith on 15/05/2015. 6 | // Copyright (c) 2015 Burnt Caramel. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | /** 13 | What each UI item (menu item, segmented item) is represented with. Recommended to be used on an enum. This can either be a model enum directly using an extension, or you can use an independent enum with the model value inside. 14 | */ 15 | public protocol UIChoiceRepresentative { 16 | var title: String { get } 17 | 18 | associatedtype UniqueIdentifier : Hashable 19 | var uniqueIdentifier: UniqueIdentifier { get } 20 | } 21 | 22 | 23 | extension UIChoiceRepresentative where UniqueIdentifier == Self { 24 | var uniqueIdentifier: UniqueIdentifier { 25 | return self 26 | } 27 | } 28 | 29 | 30 | public protocol UIChoiceEnumerable { 31 | static var allChoices: [Self] { get } 32 | } 33 | -------------------------------------------------------------------------------- /BurntCocoaUI/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.5 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2015 Burnt Caramel. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Patrick Smith 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /BurntCocoaUI/Renderers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Renderers.swift 3 | // BurntCocoaUI 4 | // 5 | // Created by Patrick Smith on 27/04/2016. 6 | // Copyright © 2016 Burnt Caramel. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | public func textFieldRenderer 13 | 14 | (onChange: @escaping (String) -> ()) 15 | -> (String?) -> TextField 16 | { 17 | let textField = TextField() 18 | textField.cell?.sendsActionOnEndEditing = true 19 | 20 | let target = textField.setActionHandler { _ in 21 | onChange(textField.stringValue) 22 | } 23 | 24 | return { stringValue in 25 | withExtendedLifetime(target) { 26 | textField.stringValue = stringValue ?? "" 27 | } 28 | return textField 29 | } 30 | } 31 | 32 | public func checkboxRenderer 33 |