Skip to content

Commit

Permalink
Add support for binding NSControl.isEnabled and similar config proper…
Browse files Browse the repository at this point in the history
…ties
  • Loading branch information
lorentey committed Sep 6, 2017
1 parent 43d55da commit a1283db
Showing 1 changed file with 46 additions and 42 deletions.
88 changes: 46 additions & 42 deletions Sources/NSControl Glue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,25 @@ extension NSControl {
@objc open dynamic override var glue: GlueForNSControl { return _glue() }
}

public func <-- <V: UpdatableValueType>(target: GlueForNSControl.IntValueReceiver, model: V) where V.Value == Int {
target.glue.setModel(model.anyUpdatableValue)
public func <-- <Value, Model: UpdatableValueType>(target: GlueForNSControl.ValueSlot<Value>, model: Model) where Model.Value == Value {
target.glue.setValueModel(model.anyUpdatableValue)
}
public func <-- <V: UpdatableValueType>(target: GlueForNSControl.IntValueReceiver, model: V) where V.Value == Int? {
target.glue.setModel(model.anyUpdatableValue)
public func <-- <Value, V: UpdatableValueType>(target: GlueForNSControl.ValueSlot<Value>, model: V) where V.Value == Value? {
target.glue.setValueModel(model.anyUpdatableValue)
}

public func <-- <V: UpdatableValueType>(target: GlueForNSControl.DoubleValueReceiver, model: V) where V.Value == Double {
target.glue.setModel(model.anyUpdatableValue)
}
public func <-- <V: UpdatableValueType>(target: GlueForNSControl.DoubleValueReceiver, model: V) where V.Value == Double? {
target.glue.setModel(model.anyUpdatableValue)
}

public func <-- <V: UpdatableValueType>(target: GlueForNSControl.StringValueReceiver, model: V) where V.Value == String {
target.glue.setModel(model.anyUpdatableValue)
}
public func <-- <V: UpdatableValueType>(target: GlueForNSControl.StringValueReceiver, model: V) where V.Value == String? {
target.glue.setModel(model.anyUpdatableValue)
}

public func <-- <V: UpdatableValueType>(target: GlueForNSControl.AttributedStringValueReceiver, model: V) where V.Value == NSAttributedString {
target.glue.setModel(model.anyUpdatableValue)
}
public func <-- <V: UpdatableValueType>(target: GlueForNSControl.AttributedStringValueReceiver, model: V) where V.Value == NSAttributedString? {
target.glue.setModel(model.anyUpdatableValue)
public func <-- <Value, Model: ObservableValueType>(target: GlueForNSControl.ConfigSlot<Value>, model: Model) where Model.Value == Value {
target.glue.setConfigSlot(target.keyPath, to: model.anyObservableValue)
}


open class GlueForNSControl: GlueForNSObject {
private var object: NSControl { return owner as! NSControl }
private var modelConnection: Connection? = nil
fileprivate var model: AnyObservableValue<Any?>? = nil {
fileprivate var valueModel: AnyObservableValue<Any?>? = nil {
didSet {
modelConnection?.disconnect()
if let model = model {
if let model = valueModel {
modelConnection = model.values.subscribe { [unowned self] value in
self.object.objectValue = value
}
Expand All @@ -56,41 +40,61 @@ open class GlueForNSControl: GlueForNSObject {
}
}
}
fileprivate var updater: ((Any?) -> Bool)? = nil
fileprivate var valueUpdater: ((Any?) -> Bool)? = nil

fileprivate func setModel<V>(_ model: AnyUpdatableValue<V>) {
self.updater = { value in
fileprivate func setValueModel<V>(_ model: AnyUpdatableValue<V>) {
self.valueUpdater = { value in
guard let v = value as? V else { return false }
model.value = v
return true
}
self.model = model.map { $0 as Any? }
self.valueModel = model.map { $0 as Any? }
}

fileprivate func setModel<V>(_ model: AnyUpdatableValue<V?>) {
self.updater = { value in
fileprivate func setValueModel<V>(_ model: AnyUpdatableValue<V?>) {
self.valueUpdater = { value in
model.value = value as? V
return true
}
self.model = model.map { $0 as Any? }
self.valueModel = model.map { $0 as Any? }
}

@objc func controlAction(_ sender: NSControl) {
if updater?(sender.objectValue) != true {
sender.objectValue = model?.value
if valueUpdater?(sender.objectValue) != true {
sender.objectValue = valueModel?.value
}
}

public struct IntValueReceiver { fileprivate let glue: GlueForNSControl }
public var intValue: IntValueReceiver { return IntValueReceiver(glue: self) }
public struct ValueSlot<Value> {
fileprivate let glue: GlueForNSControl
}

public var intValue: ValueSlot<Int> { return ValueSlot<Int>(glue: self) }
public var doubleValue: ValueSlot<Double> { return ValueSlot(glue: self) }
public var stringValue: ValueSlot<String> { return ValueSlot(glue: self) }
public var attributedStringValue: ValueSlot<NSAttributedString> { return ValueSlot(glue: self) }

public struct DoubleValueReceiver { fileprivate let glue: GlueForNSControl }
public var doubleValue: DoubleValueReceiver { return DoubleValueReceiver(glue: self) }
public struct ConfigSlot<Value> {
fileprivate let glue: GlueForNSControl
fileprivate let keyPath: ReferenceWritableKeyPath<NSControl, Value>
}

var configModels: [AnyKeyPath: Connection] = [:]

public struct StringValueReceiver { fileprivate let glue: GlueForNSControl }
public var stringValue: StringValueReceiver { return StringValueReceiver(glue: self) }
func setConfigSlot<Value>(_ keyPath: ReferenceWritableKeyPath<NSControl, Value>, to model: AnyObservableValue<Value>) {
let connection = model.values.subscribe { [unowned object] value in
object[keyPath: keyPath] = value
_ = object
}
configModels.updateValue(connection, forKey: keyPath)?.disconnect()
}

public struct AttributedStringValueReceiver { fileprivate let glue: GlueForNSControl }
public var attributedStringValue: AttributedStringValueReceiver { return AttributedStringValueReceiver(glue: self) }
public var isEnabled: ConfigSlot<Bool> { return ConfigSlot(glue: self, keyPath: \.isEnabled) }
public var alignment: ConfigSlot<NSTextAlignment> { return ConfigSlot(glue: self, keyPath: \.alignment) }
public var font: ConfigSlot<NSFont?> { return ConfigSlot(glue: self, keyPath: \.font) }
public var lineBreakMode: ConfigSlot<NSParagraphStyle.LineBreakMode> { return ConfigSlot(glue: self, keyPath: \.lineBreakMode) }
public var usesSingleLineMode: ConfigSlot<Bool> { return ConfigSlot(glue: self, keyPath: \.usesSingleLineMode) }
public var formatter: ConfigSlot<Formatter?> { return ConfigSlot(glue: self, keyPath: \.formatter) }
public var baseWritingDirection: ConfigSlot<NSWritingDirection> { return ConfigSlot(glue: self, keyPath: \.baseWritingDirection) }
}
#endif

0 comments on commit a1283db

Please sign in to comment.