// // KMToolbarItemView.swift // PDF Reader Pro // // Created by tangchao on 2023/10/24. // import Cocoa enum KMToolbarItemViewSelectBackgroundType: Int { case none = 0 case imageBox } class KMToolbarClickButton: NSButton { weak var clickObject: AnyObject? } extension NSControl.ImagePosition { static let imageExpandLeft: NSControl.ImagePosition = .init(rawValue: 100) ?? .imageLeft } private let KMPopOverClosedByWindowNotificationName = "KMPopOverClosedByWindowNotification" extension KMToolbarItemView { public static let popOverClosedNotificationName = Notification.Name(KMPopOverClosedByWindowNotificationName) } @objcMembers class KMToolbarItemView: NSView { var menuFormRepresentation: NSMenuItem? private var _itemIdentifier: String? var itemIdentifier: String? { get { return self._itemIdentifier } } var pdfView : CPDFListView = CPDFListView() lazy var clickButton: KMToolbarClickButton = { let view = KMToolbarClickButton() view.bezelStyle = .regularSquare view.isBordered = false view.imagePosition = .imageOnly view.clickObject = self return view }() var isSelected = false { didSet { if self.itemIdentifier != KMToolbarDividerItemIdentifier { if (isSelected) { if(self.image != nil && self.alternateImage != nil) { if let data = self.selectedImage { self.imageViewBtn.image = data } else { if let data = self.alternateImage { self.imageViewBtn.image = data } } } if (self.nameBtn.superview != nil) { self.nameBtn.setTitleColor(color: Self.fetchTextSelectedColor()) } if(self.needExpandAction) { self.needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownSel") } } else { if (self.needExpandAction) { self.needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownNor") } if let data = self.image { self.imageViewBtn.image = data } if (self.nameBtn.superview != nil) { self.nameBtn.setTitleColor(color: Self.fetchTextNormalColor()) } } self._updateSelectBackground() } } } var unEnabled = false { didSet { self.clickButton.isEnabled = !self.unEnabled self.nameBtn.isEnabled = !self.unEnabled self.imageViewBtn.isEnabled = !self.unEnabled self.needExpandButton.isEnabled = !self.unEnabled if let data = self.customizeView { self.subviewsdEnable(view: data, isEnable: !self.unEnabled) } } } var isShowCustomToolTip = false { didSet { if (self.isShowCustomToolTip) { self.clickButton.toolTip = "" } } } var boxImagePosition: NSControl.ImagePosition = .imageLeft { didSet { self._layoutView() self.itemWidth = self._calculateWidth() } } var image: NSImage? { didSet { self.imageViewBtn.image = self.image } } var selectedImage: NSImage? var alternateImage: NSImage? var titleName: String? { didSet { self.nameBtn.title = self.titleName ?? " " self.nameBtn.setTitleColor(color: Self.fetchTextNormalColor()) self.itemWidth = self._calculateWidth() } } weak var target: AnyObject? { didSet { self.clickButton.target = self.target } } var btnAction: Selector? { didSet { self.clickButton.action = self.btnAction } } var needExpandAction = false { didSet { self.itemWidth = self._calculateWidth() } } var btnTag = 0 { didSet { self.clickButton.tag = self.btnTag } } var customizeView: NSView? { didSet { self._layoutView() self.itemWidth = self._calculateWidth() } } // var isShowPrompt: Bool { // // } private var promptView_: NSView? var promptView: NSView? { get { return self.promptView_ } } private var promptIdentifier_: String? var promptIdentifier: String? { get { return self.promptIdentifier_ } set { if self.promptIdentifier_ != newValue { self.promptIdentifier_ = newValue if let data = KMDataManager.ud_object(forKey: newValue ?? "") as? Bool { self.isShowPrompt = !data } else { self.isShowPrompt = true } } } } private var isShowPrompt_: Bool = false var isShowPrompt: Bool { get { return self.isShowPrompt_ } set { self.isShowPrompt_ = newValue self.promptView?.isHidden = !newValue } } var normalBackgroundColor: NSColor = .clear var selectedBackgroundColor: NSColor = KMAppearance.Status.selColor() var selectBackgroundType: KMToolbarItemViewSelectBackgroundType = .none var itemWidth: CGFloat = 0 var itemHeight: CGFloat = 0 var isPopToolTip = false private var area_: NSTrackingArea? static let kDividerWidth: CGFloat = 8 static let kHSpace: CGFloat = 4 static let kExpandWidth: CGFloat = 8 static let kRightMargin: CGFloat = 4 static let kImageAboveMinWidth: CGFloat = 32 lazy var imageViewBox: NSBox = { let view = NSBox() view.borderWidth = 0 view.contentViewMargins = NSSize.zero view.boxType = .custom view.borderColor = .clear view.cornerRadius = 7.0 return view }() lazy var imageViewBtn: NSButton = { let view = NSButton() view.bezelStyle = .regularSquare view.isBordered = false view.imagePosition = .imageOnly return view }() var nameBtn: NSButton = { let view = NSButton() view.bezelStyle = .regularSquare view.isBordered = false view.imagePosition = .imageOnly view.title = "" return view }() private var needExpandButton: NSButton = { let view = NSButton() view.bezelStyle = .regularSquare view.isBordered = false view.imagePosition = .imageOnly view.image = NSImage(named: "KMImageNameUXIconBtnTriDownNor") return view }() private var _popOver: NSPopover? var popOver: NSPopover? { get { return self._popOver } set { if self._popOver == nil || self._popOver!.isEqual(to: newValue) == false { self._popOver = newValue if (newValue != nil) { self.layer?.backgroundColor = Self.selectedBackgroundColor.cgColor } else { self._updateSelectBackground() } } } } private var _menuViewController: KMCustomButtonPopMenuViewController? private var _kNormalImage: NSImage? private var _originalHelpTip: String? deinit { if (self.area_ != nil) { self.removeTrackingArea(self.area_!) self.area_ = nil } NotificationCenter.default.removeObserver(self) } class var textFont: NSFont { get { .systemFont(ofSize: 12) } } // class var textNormalColor: NSColor { // get { // KMAppearance.titleColor() // } // } class func fetchTextNormalColor() -> NSColor { return KMAppearance.titleColor() } class func fetchTextSelectedColor() -> NSColor { return KMAppearance.titleColor() } class var selectedBackgroundColor: NSColor { get { return KMAppearance.Status.selColor() } } class var normalBackgroundColor: NSColor { get { return .clear } } convenience init(itemIdentifier: String) { self.init() self._itemIdentifier = itemIdentifier self.boxImagePosition = .imageLeft self.wantsLayer = true self.layer?.cornerRadius = 5 self.layer?.masksToBounds = true self.nameBtn.font = Self.textFont let promptV = NSView() self.promptView_ = promptV self.addSubview(promptV) promptV.wantsLayer = true promptV.layer?.cornerRadius = 3 promptV.layer?.backgroundColor = NSColor(red: 1, green: 56/255.0, blue: 25/255.0, alpha: 1).cgColor self.isShowPrompt = false self._addTrackingArea() NotificationCenter.default.addObserver(self, selector: #selector(_windowClosedPop), name: KMToolbarItemView.popOverClosedNotificationName, object: nil) } convenience init(itemIdentifier: String, postition imagePositionImagePosition: NSControl.ImagePosition, withPopMenu popMenuViewController: KMCustomButtonPopMenuViewController?) { self.init() self.boxImagePosition = imagePositionImagePosition self._menuViewController = popMenuViewController self._itemIdentifier = itemIdentifier self.wantsLayer = true self.layer?.cornerRadius = 4 self.layer?.masksToBounds = true self.nameBtn.font = Self.textFont let promptV = NSView() self.promptView_ = promptV self.addSubview(promptV) promptV.wantsLayer = true promptV.layer?.cornerRadius = 3 promptV.layer?.backgroundColor = NSColor(red: 1, green: 56/255.0, blue: 25/255.0, alpha: 1).cgColor self.isShowPrompt = false self._addTrackingArea() self._layoutView() if (popMenuViewController != nil) { NotificationCenter.default.addObserver(self, selector: #selector(_windowClosedPop), name: KMToolbarItemView.popOverClosedNotificationName, object: nil) } } override func draw(_ dirtyRect: NSRect) { if (self.itemIdentifier == KMToolbarDividerItemIdentifier) { let context = NSGraphicsContext.current?.cgContext KMContextSaveGState(context) KMContextTranslateCTM(context, CGRectGetWidth(dirtyRect)/2.0, CGRectGetHeight(dirtyRect)/2.0-10) KMContextMoveToPoint(context, 0, 0) KMContextAddLineToPoint(context, 0, 20) KMContextSetStrokeColorWithColor(context, NSColor(red: 0, green: 0, blue: 0, alpha: 0.1).cgColor) KMContextStrokePath(context) KMContextRestoreGState(context) } } override var toolTip: String? { get { return self._originalHelpTip } set { self.clickButton.toolTip = newValue ?? "" self._originalHelpTip = self.clickButton.toolTip if(self.isShowCustomToolTip) { self.clickButton.toolTip = "" } } } override func updateTrackingAreas() { super.updateTrackingAreas() let areaBound = NSRect(x: 0, y: 5, width: self.bounds.size.width, height: self.bounds.size.height) if let _area = self.area_, _area.rect.isEmpty == false { if (_area.rect.equalTo(areaBound)) { return } } if (self.area_ != nil) { self.removeTrackingArea(self.area_!) self.area_ = nil } // inVisibleRect activeInKeyWindow self.area_ = NSTrackingArea(rect: areaBound, options: [.mouseEnteredAndExited,.mouseMoved, .activeAlways], owner: self) self.addTrackingArea(self.area_!) } override func mouseEntered(with event: NSEvent) { super.mouseEntered(with: event) guard let _window = self.window else { return } if (!_window.isKeyWindow) { return } if (self.itemIdentifier == KMToolbarDividerItemIdentifier || self.customizeView != nil || self.image == nil) { return } if self.unEnabled { return } if (!self.isSelected) { if self.selectBackgroundType == .none { self.layer?.backgroundColor = Self.selectedBackgroundColor.cgColor } else { self.imageViewBox.fillColor = Self.selectedBackgroundColor } if(self.image != nil && self.alternateImage != nil) { self._kNormalImage = self.image self.imageViewBtn.image = self.alternateImage if(self.nameBtn.superview != nil) { self.nameBtn.setTitleColor(color: Self.fetchTextNormalColor()) } } } if self.isPopToolTip { self._showPopTip(self) }else { if (self.needExpandAction) { // KMImageNameUXIconBtnTriDownSel self.needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownNor") self._showPop(self) }else if (self.isShowCustomToolTip) { self.perform(#selector(_showHUDHint), with: nil, afterDelay: 0.1) } } } override func mouseExited(with event: NSEvent) { super.mouseExited(with: event) if (!self.isSelected && !self.needExpandAction) { if self.selectBackgroundType == .none { self.layer?.backgroundColor = self.normalBackgroundColor.cgColor } else { self.imageViewBox.fillColor = self.normalBackgroundColor } if(self.image != nil && self.alternateImage != nil) { self.imageViewBtn.image = self._kNormalImage ?? self.image! } } if(self.needExpandAction && !self.isSelected) { if self.selectBackgroundType == .none { self.layer?.backgroundColor = self.normalBackgroundColor.cgColor } else { self.imageViewBox.fillColor = self.normalBackgroundColor } if(self.image != nil && self.alternateImage != nil) { self.imageViewBtn.image = self._kNormalImage ?? self.image! } self.needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownNor") } guard let _window = self.window else { return } if (!_window.isKeyWindow) { return } if(self.nameBtn.superview != nil && !self.isSelected) { self.nameBtn.setTitleColor(color: Self.fetchTextNormalColor()) } if self.isPopToolTip { NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(_showHUDHint), object: nil) self._closePop() }else{ if (self.isShowCustomToolTip && !self.needExpandAction) { NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(_showHUDHint), object: nil) self._closePop() } } } public func calculateWidth() -> CGFloat { let iWidth = self._calculateWidth() return iWidth } private func _updateSelectBackground() { if self.selectBackgroundType == .none { if self.isSelected { self.layer?.backgroundColor = Self.selectedBackgroundColor.cgColor } else { self.layer?.backgroundColor = self.normalBackgroundColor.cgColor } } else if self.selectBackgroundType == .imageBox { if self.isSelected { self.imageViewBox.fillColor = Self.selectedBackgroundColor } else { self.imageViewBox.fillColor = self.normalBackgroundColor self.layer?.backgroundColor = self.normalBackgroundColor.cgColor } } } override func updateLayer() { super.updateLayer() // // self.wantsLayer = true // self.layer?.backgroundColor = KMAppearance.Layout.l_2Color().cgColor } } // MARK: - Private Methods extension KMToolbarItemView { private func _addTrackingArea() { // let trackingArea = NSTrackingArea(rect: self.bounds, options: [.mouseEnteredAndExited, .inVisibleRect, .activeInKeyWindow], owner: self) // self.addTrackingArea(trackingArea) } private func _showPop(_ sender: NSView) { if (self._popOver != nil) { return } let menuViewController = KMCustomButtonPopMenuViewController() menuViewController.delegate = self menuViewController.dataSources = self self.popOver = NSPopover() self.popOver?.delegate = self self.popOver?.contentViewController = menuViewController self.popOver?.animates = false self.popOver?.behavior = .semitransient self.popOver?.contentSize = menuViewController.view.frame.size var sourcesRect = sender.bounds sourcesRect = sender.convert(sourcesRect, to: nil) sourcesRect.origin.y -= 20 sourcesRect.size.height += 20 self.window?.popover = self.popOver self.window?.sourcesRect = sourcesRect self.popOver?.show(relativeTo: CGRectInset(self.bounds, 0, 5), of: self, preferredEdge: .minY) } func _showPopTip(_ sender: NSView) { if (self._popOver != nil) { return } var sourcesRect = sender.bounds sourcesRect = sender.convert(sourcesRect, to: nil) sourcesRect.origin.y -= 20 sourcesRect.size.height += 20 // self.window?.popover = self.popOver // self.window?.sourcesRect = sourcesRect let popViewController = KMToolbarItemPopViewController() self.popOver = NSPopover() self.popOver?.contentViewController = popViewController self.popOver?.animates = false self.popOver?.behavior = .semitransient self.popOver?.contentSize = popViewController.view.frame.size popViewController.updateWithHelpTip(helpTip: self.toolTip ?? "") // self.window?.popover = self.popOver // self.window?.sourcesRect = sourcesRect self.popOver?.show(relativeTo: CGRectInset(self.bounds, 0, 5), of: self, preferredEdge: .minY) } private func _closePop() { self.popOver?.close() self.popOver = nil } @objc private func _showHUDHint() { // KMToolbarItemPopViewController *popViewController = [[[KMToolbarItemPopViewController alloc] init] autorelease]; // self.popOver = [[[NSPopover alloc] init] autorelease]; // self.popOver.contentViewController = popViewController; // self.popOver.animates = NO; // self.popOver.behavior = NSPopoverBehaviorSemitransient; // self.popOver.backgroundColor = [KMAppearance KMBluegrey01Color]; // // self.popOver.contentSize = popViewController.view.frame.size; // [popViewController updateWithHelpTip:self.originalHelpTip]; // [self.popOver showRelativeToRect:self.bounds ofView:self preferredEdge:NSRectEdgeMinY]; } @objc private func _windowClosedPop(sender: Notification) { if let data = self._popOver?.isEqual(to: sender.object), data { self.popOver = nil } } private func _layoutView() { if self.nameBtn.superview != nil { self.nameBtn.removeFromSuperview() } if self.imageViewBox.superview != nil { self.imageViewBox.removeFromSuperview() } if self.imageViewBtn.superview != nil { self.imageViewBtn.removeFromSuperview() } if let view = self.promptView, view.superview != nil { view.removeFromSuperview() } if let view = self.customizeView { if view.superview != nil { view.removeFromSuperview() } let iWidth = NSWidth(view.bounds) self.addSubview(view) view.km_add_leading_constraint() view.km_add_trailing_constraint() view.km_add_centerY_constraint() view.km_add_width_constraint(constant: iWidth) view.km_add_height_constraint(constant: NSHeight(view.bounds)) self.itemHeight = NSHeight(view.bounds) return } else if (self.itemIdentifier == KMToolbarDividerItemIdentifier) { self.addSubview(self.imageViewBox) self.imageViewBox.km_add_inset_constraint(inset: NSEdgeInsetsZero) self.imageViewBox.km_add_width_constraint(constant: Self.kDividerWidth) self.itemHeight = 40 return } let offset = Self.kRightMargin let offsetY: CGFloat = 2.0 let offsetX = Self.kHSpace if self.boxImagePosition == .imageOnly { let iWidth = (self.imageViewBtn.image?.size ?? .zero).width + offsetX * 2 self.addSubview(self.imageViewBox) self.imageViewBox.km_add_inset_constraint() self.imageViewBox.contentView?.addSubview(self.imageViewBtn) self.imageViewBtn.km_add_inset_constraint(equalTo: self.imageViewBox, inset: NSEdgeInsets(top: offsetY, left: 0, bottom: offsetY, right: 0)) self.itemHeight = 24 } else if (self.boxImagePosition == .imageLeft) { self.addSubview(self.imageViewBox) self.imageViewBox.km_add_leading_constraint() self.imageViewBox.km_add_top_constraint() self.imageViewBox.km_add_bottom_constraint() self.imageViewBox.contentView?.addSubview(self.imageViewBtn) self.imageViewBtn.km_add_inset_constraint(equalTo: self.imageViewBox, inset: NSEdgeInsets(top: offsetY, left: 2*offsetX-2, bottom: offsetY, right: 2)) self.addSubview(self.nameBtn) self.nameBtn.km_add_centerY_constraint() self.nameBtn.km_add_leading_constraint(equalTo: self.imageViewBox, attribute: .trailing) if (self.needExpandAction) { self.nameBtn.km_add_right_constraint(constant: -2*offsetX-Self.kExpandWidth) } else { self.nameBtn.km_add_right_constraint(constant: -2*offsetX) } if(self.needExpandAction) { self.needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownNor") self.addSubview(self.needExpandButton) self.needExpandButton.km_add_centerY_constraint() self.needExpandButton.km_add_width_constraint(constant: Self.kExpandWidth) self.needExpandButton.km_add_right_constraint(constant: -offset) } self.layer?.cornerRadius = 6 self.itemHeight = 24 } else if (self.boxImagePosition == .imageExpandLeft) { self.addSubview(self.imageViewBox) self.imageViewBox.km_add_leading_constraint() self.imageViewBox.km_add_top_constraint() self.imageViewBox.km_add_bottom_constraint() self.imageViewBox.contentView?.addSubview(self.imageViewBtn) self.imageViewBtn.km_add_inset_constraint(equalTo: self.imageViewBox, inset: NSEdgeInsets(top: offsetY, left: offsetX, bottom: offsetY, right: 0)) self.needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownNor") self.addSubview(self.needExpandButton) self.needExpandButton.km_add_centerY_constraint() self.needExpandButton.km_add_width_constraint(constant: Self.kExpandWidth) self.needExpandButton.km_add_right_constraint(constant: -offset) self.addSubview(self.nameBtn) self.nameBtn.km_add_centerY_constraint() self.nameBtn.km_add_leading_constraint(equalTo: self.imageViewBox, attribute: .trailing) self.nameBtn.km_add_trailing_constraint(equalTo: self.needExpandButton, attribute: .leading) self.itemHeight = 24 } else if (self.boxImagePosition == .imageAbove) { self.addSubview(self.nameBtn) self.nameBtn.alignment = .center self.nameBtn.mas_makeConstraints { make in make?.left.right().equalTo()(0) make?.width.greaterThanOrEqualTo()(Self.kImageAboveMinWidth) make?.bottom.equalTo()(self.mas_bottom)?.offset()(0) } // self.nameBtn.km_add_leading_constraint() // self.nameBtn.km_add_trailing_constraint() // self.nameBtn.km_add_bottom_constraint() self.addSubview(self.imageViewBox) self.imageViewBox.km_add_top_constraint() self.imageViewBox.km_add_width_constraint(constant: Self.kImageAboveMinWidth) self.imageViewBox.km_add_centerX_constraint() self.imageViewBox.km_add_bottom_constraint(equalTo: self.nameBtn, attribute: .top, constant: 0) self.imageViewBox.contentView?.addSubview(self.imageViewBtn) self.imageViewBtn.km_add_inset_constraint(inset: .init(top: 0.5, left: offset, bottom: 0, right: offset)) self.itemHeight = 40 } self.imageViewBox.borderWidth = 1.0 self.addSubview(self.clickButton) self.clickButton.km_add_inset_constraint() if let view = self.promptView { self.addSubview(view) } } private func _calculateWidth() -> CGFloat { if let v = self.customizeView { return NSWidth(v.bounds) } else if self.itemIdentifier == KMToolbarDividerItemIdentifier { return Self.kDividerWidth } else { if self.boxImagePosition == .imageOnly { return (self.imageViewBtn.image?.size ?? .zero).width + Self.kHSpace * 2 } else if self.boxImagePosition == .imageLeft { // Compress 98 = 28(4+20+4) + 62 + 8(4+4) var iWidth = (self.imageViewBtn.image?.size.width ?? 0) + Self.kHSpace * 2 self.nameBtn.sizeToFit() iWidth += self.nameBtn.frame.size.width iWidth += (2 * Self.kHSpace) if self.needExpandAction { iWidth += 8 } return iWidth } else if self.boxImagePosition == .imageExpandLeft { // Security 87 var iWidth = (self.imageViewBtn.image?.size.width ?? 0) + Self.kHSpace self.nameBtn.sizeToFit() iWidth += self.nameBtn.frame.size.width iWidth += Self.kExpandWidth iWidth += Self.kRightMargin return iWidth } else if self.boxImagePosition == .imageAbove { // Panel 33 self.nameBtn.sizeToFit() let iWidth = NSWidth(self.nameBtn.bounds) return max(Self.kImageAboveMinWidth, iWidth) } } return 0 } override func layout() { super.layout() if let view = self.promptView, view.superview != nil { let wh: CGFloat = 6 let y: CGFloat = 3 view.frame = NSMakeRect(NSWidth(self.bounds)-wh, NSHeight(self.bounds)-wh-y, wh, wh) } } } extension KMToolbarItemView: NSPopoverDelegate { func popoverDidClose(_ notification: Notification) { if let data = self.popOver?.isEqual(to: notification.object), data { self._closePop() } } } extension KMToolbarItemView: KMCustomButtonPopMenuViewControllerDelegate, KMCustomButtonPopMenuViewControllerDataSources { func customViewButtonPopDidSelectIndex(_ index: Int) { self._closePop() // if (self.itemIdentifier == KMToolbarPageEditPageRangeItemIdentifier) { if let items = self.menuFormRepresentation?.submenu?.items { let item = items[index] _ = item.target?.perform(item.action, with: item) } // } } func numberOfLine() -> Int { // if (self.itemIdentifier == KMToolbarPageEditPageRangeItemIdentifier) { if let items = self.menuFormRepresentation?.submenu?.items { return items.count } // } return 0 } func stringForLine(at index: Int) -> String? { // if (self.itemIdentifier == KMToolbarPageEditPageRangeItemIdentifier) { if let items = self.menuFormRepresentation?.submenu?.items { return items[index].title } // } return nil } func needInsertSeperateLine(at index: Int) -> Bool { if let items = self.menuFormRepresentation?.submenu?.items { return items[index].isSeparatorItem } return false } func needHightLightLine(at index: Int) -> Bool { return false } func imageForLine(at index: Int) -> NSImage? { if let items = self.menuFormRepresentation?.submenu?.items { return items[index].image } return nil } func itemEnable(at index: Int) -> Bool { if self.itemIdentifier == KMToolbarToolFormAlignIdentifier { if index <= 6 { if self.pdfView.activeAnnotations.count >= 2 { return true } } else { if self.pdfView.activeAnnotations.count >= 3 { return true } } return false } return true } } extension KMToolbarItemView { func subviewsdEnable(view: NSView, isEnable: Bool) { if let data = view as? NSButton { data.isEnabled = isEnable } if let data = (view as? NSTextField) { data.isEnabled = isEnable } for subview in view.subviews { if subview.subviews.count != 0 { self.subviewsdEnable(view: subview, isEnable: isEnable) } if let data = subview as? NSButton { data.isEnabled = isEnable } if let data = (subview as? NSTextField) { data.isEnabled = isEnable } } } }