// // KMToolbarItemView.swift // PDF Master // // Created by tangchao on 2023/10/24. // import Cocoa class KMToolbarClickButton: NSButton { weak var clickObject: AnyObject? } extension NSControl.ImagePosition { static let imageExpandLeft: NSControl.ImagePosition = .init(rawValue: 100)! } 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 } } lazy var clickButton: KMToolbarClickButton = { let _clickButton = KMToolbarClickButton() _clickButton.bezelStyle = .regularSquare _clickButton.isBordered = false _clickButton.imagePosition = .imageOnly _clickButton.clickObject = self return _clickButton }() var isSelected = false { didSet { if self.itemIdentifier != KMToolbarDividerItemIdentifier { if (isSelected) { if (isMainTool) { // self.layer?.backgroundColor = self.normalBackgroundColor.cgColor self.imageViewBox.fillColor = self.normalBackgroundColor self.nameBtn.setTitleColor(color: KMAppearance.titleColor(), font: .SFProTextSemiboldFont(14)) self.linView.isHidden = false return } // self.layer?.backgroundColor = self.selectedBackgroundColor.cgColor self.imageViewBox.fillColor = self.selectedBackgroundColor if(self.image != nil && self.alternateImage != nil) { if (self.selectedImage != nil) { self.imageViewBtn.image = self.selectedImage! } else { self.imageViewBtn.image = self.alternateImage! } } if (self.nameBtn.superview != nil) { self.nameBtn.setTitleColor(color: KMAppearance.titleColor()) } if(self.needExpandAction) { self.needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownSel") } } else { if (isMainTool) { // self.layer?.backgroundColor = self.normalBackgroundColor.cgColor self.imageViewBox.fillColor = self.normalBackgroundColor self.nameBtn.setTitleColor(color: NSColor(red: 97.0/255.0, green: 100.0/255.0, blue: 105.0/255.0, alpha: 1.0),font: .SFProTextRegularFont(14)) self.linView.isHidden = true return } // self.layer?.backgroundColor = self.normalBackgroundColor.cgColor self.imageViewBox.fillColor = self.normalBackgroundColor if (self.needExpandAction) { self.needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownNor") } if (self.image != nil) { self.imageViewBtn.image = self.image! } if (self.nameBtn.superview != nil) { self.nameBtn.setTitleColor(color: KMAppearance.titleColor()) } } } } } var unEnabled = false { didSet { self.clickButton.isEnabled = !self.unEnabled self.nameBtn.isEnabled = !self.unEnabled self.imageViewBtn.isEnabled = !self.unEnabled self.needExpandButton.isEnabled = !self.unEnabled } } var isShowCustomToolTip = false { didSet { if (self.isShowCustomToolTip) { self.clickButton.toolTip = "" } } } var boxImagePosition: NSControl.ImagePosition = .imageLeft { didSet { self._layoutView() } } 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: KMAppearance.titleColor()) } } weak var target: AnyObject? { didSet { self.clickButton.target = self.target } } var btnAction: Selector? { didSet { self.clickButton.action = self.btnAction } } var needExpandAction = false var btnTag = 0 { didSet { self.clickButton.tag = self.btnTag } } var customizeView: NSView? { didSet { self._layoutView() } } var isMainTool = false { didSet { if (isMainTool) { self.nameBtn.setTitleColor(color: NSColor(red: 97.0/255.0, green: 100.0/255.0, blue: 105.0/255.0, alpha: 1), font: .SFProTextRegularFont(14)) } else { self.nameBtn.setTitleColor(color: KMAppearance.titleColor()) } self._layoutView() } } var linView: NSView = { let _linView = NSView() _linView.wantsLayer = true _linView.layer?.backgroundColor = NSColor(red: 23/255.0, green: 112/255.0, blue: 244/255.0, alpha: 1).cgColor _linView.layer?.cornerRadius = 2 return _linView }() var normalBackgroundColor: NSColor = .clear var selectedBackgroundColor: NSColor = KMAppearance.Status.selColor() var imageViewBox: NSBox = { let _imageViewBox = NSBox() _imageViewBox.borderWidth = 0 _imageViewBox.contentViewMargins = NSZeroSize _imageViewBox.boxType = .custom return _imageViewBox }() private lazy var imageViewBtn: NSButton = { let _imageViewBtn = NSButton() _imageViewBtn.bezelStyle = .regularSquare _imageViewBtn.isBordered = false _imageViewBtn.imagePosition = .imageOnly return _imageViewBtn }() private var nameBtn: NSButton = { let _nameBtn = NSButton() _nameBtn.bezelStyle = .regularSquare _nameBtn.isBordered = false _nameBtn.imagePosition = .imageOnly _nameBtn.font = .systemFont(ofSize: 12) _nameBtn.title = "" return _nameBtn }() private var needExpandButton: NSButton = { let _needExpandButton = NSButton() _needExpandButton.bezelStyle = .regularSquare _needExpandButton.isBordered = false _needExpandButton.imagePosition = .imageOnly _needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownNor") return _needExpandButton }() private var _popOver: NSPopover? var popOver: NSPopover? { get { return self._popOver } set { if self._popOver?.isEqual(to: newValue) == false { self._popOver = newValue if (newValue != nil) { self.layer?.backgroundColor = self.selectedBackgroundColor.cgColor } else { if (self.isSelected) { self.layer?.backgroundColor = self.selectedBackgroundColor.cgColor }else { self.layer?.backgroundColor = self.normalBackgroundColor.cgColor } } } } } private var _menuViewController: KMCustomButtonPopMenuViewController? private var _kNormalImage: NSImage? private var _originalHelpTip: String? deinit { Swift.debugPrint("KMToolbarItemView deinit") NotificationCenter.default.removeObserver(self) } convenience init(itemIdentifier: String) { self.init() self._itemIdentifier = itemIdentifier self.boxImagePosition = .imageLeft self.wantsLayer = true self.layer?.cornerRadius = 5 self.layer?.masksToBounds = true // self.normalBackgroundColor = .clear // self.selectedBackgroundColor = NSColor(red: 223.0/255.0, green: 225.0/255.0, blue: 229.0/255.0, alpha: 1) 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.normalBackgroundColor = .clear // self.selectedBackgroundColor = NSColor(red: 223.0/255.0, green: 225.0/255.0, blue: 229.0/255.0, alpha: 1) 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 = "" } } } // MARK: - Private Methods private func _addTrackingArea() { let trackingArea = NSTrackingArea(rect: self.bounds, options: [.mouseEnteredAndExited, .inVisibleRect, .activeInKeyWindow], owner: self) self.addTrackingArea(trackingArea) } 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.isSelected) { // self.layer?.backgroundColor = self.selectedBackgroundColor.cgColor 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: KMAppearance.titleColor()) } } } if (self.needExpandAction) { self.needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownSel") // [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) { // self.layer?.backgroundColor = self.normalBackgroundColor.cgColor self.imageViewBox.fillColor = self.normalBackgroundColor if(self.image != nil && self.alternateImage != nil) { self.imageViewBtn.image = self._kNormalImage ?? self.image! } } if(self.needExpandAction && !self.isSelected) { self.layer?.backgroundColor = self.normalBackgroundColor.cgColor 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.isMainTool) { self.nameBtn.setTitleColor(color: KMAppearance.titleColor()) } if (self.isShowCustomToolTip && !self.needExpandAction) { NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(_showHUDHint), object: nil) self._closePop() } } @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 _closePop() { self.popOver?.close() self.popOver = nil } private func _layoutView() { let offset = 4.0 let offsetY = 2.0 let offsetX = 4.0 if self.nameBtn.superview != nil { self.nameBtn.removeFromSuperview() } if self.linView.superview != nil { self.linView.removeFromSuperview() } if self.imageViewBox.superview != nil { self.imageViewBox.removeFromSuperview() } if self.imageViewBtn.superview != nil { self.imageViewBtn.removeFromSuperview() } if self.customizeView != nil { if self.customizeView?.superview != nil { self.customizeView?.removeFromSuperview() } self.addSubview(self.customizeView!) self.customizeView?.mas_makeConstraints({ make in make?.left.right().equalTo()(0) make?.centerY.equalTo()(0) make?.width.offset()(self.customizeView!.frame.size.width) make?.height.offset()(self.customizeView!.frame.size.height) }) return } if self.boxImagePosition == .imageOnly && self.itemIdentifier != KMToolbarDividerItemIdentifier { self.addSubview(self.imageViewBox) self.imageViewBox.mas_makeConstraints { make in make?.left.right().top().bottom().equalTo()(0) } self.imageViewBox.contentView?.addSubview(self.imageViewBtn) self.imageViewBtn.mas_makeConstraints { make in make?.left.equalTo()(self.imageViewBox.mas_left)?.offset()(offsetX) make?.top.equalTo()(self.imageViewBox.mas_top)?.offset()(offsetY) make?.bottom.equalTo()(self.imageViewBox.mas_bottom)?.offset()(-offsetY) make?.right.equalTo()(self.imageViewBox.mas_right)?.offset()(-offsetX) } } else if (self.boxImagePosition == .imageLeft) { self.addSubview(self.imageViewBox) self.imageViewBox.mas_makeConstraints { make in make?.left.top().bottom().equalTo()(0) } self.imageViewBox.contentView?.addSubview(self.imageViewBtn) self.imageViewBtn.mas_makeConstraints { make in make?.left.equalTo()(self.imageViewBox.mas_left)?.offset()(2 * offsetX) make?.top.equalTo()(self.imageViewBox.mas_top)?.offset()(offsetY) make?.bottom.equalTo()(self.imageViewBox.mas_bottom)?.offset()(-offsetY) make?.right.equalTo()(0) } self.addSubview(self.nameBtn) self.nameBtn.mas_makeConstraints { make in make?.centerY.equalTo()(0) make?.left.equalTo()(self.imageViewBox.mas_right)?.offset()(0) if (self.needExpandAction) { make?.right.equalTo()(self.mas_right)?.offset()(-2*offsetX-8) } else { make?.right.equalTo()(self.mas_right)?.offset()(-2*offsetX) } } if(self.needExpandAction) { self.needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownNor") self.addSubview(self.needExpandButton) self.needExpandButton.mas_makeConstraints { make in make?.centerY.equalTo()(0) make?.width.height().equalTo()(8) make?.right.equalTo()(self.mas_right)?.offset()(-offset) } } self.layer?.cornerRadius = 6 } else if (self.boxImagePosition == .imageExpandLeft) { self.addSubview(self.imageViewBox) self.imageViewBox.mas_makeConstraints { make in make?.left.top().bottom().equalTo()(0) } self.imageViewBox.contentView?.addSubview(self.imageViewBtn) self.imageViewBtn.mas_makeConstraints { make in make?.left.equalTo()(self.imageViewBox.mas_left)?.offset()(offsetX) make?.top.equalTo()(self.imageViewBox.mas_top)?.offset()(offsetY) make?.bottom.equalTo()(self.imageViewBox.mas_bottom)?.offset()(-offsetY) make?.right.equalTo()(0) } self.needExpandButton.image = NSImage(named: "KMImageNameUXIconBtnTriDownNor") self.addSubview(self.needExpandButton) self.needExpandButton.mas_makeConstraints { make in make?.centerY.equalTo()(0) make?.width.height().equalTo()(8) make?.right.equalTo()(self.mas_right)?.offset()(-offset) } self.addSubview(self.nameBtn) self.nameBtn.mas_makeConstraints { make in make?.centerY.equalTo()(0) make?.left.equalTo()(self.imageViewBox.mas_right)?.offset()(0) make?.right.equalTo()(self.needExpandButton.mas_left)?.offset()(0) } } 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()(32) make?.bottom.equalTo()(self.mas_bottom)?.offset()(0) } self.addSubview(self.imageViewBox) self.imageViewBox.mas_makeConstraints { make in make?.top.equalTo()(0) make?.width.equalTo()(32) make?.centerX.equalTo()(0) make?.bottom.equalTo()(nameBtn.mas_top)?.offset()(0) } self.imageViewBox.contentView?.addSubview(self.imageViewBtn) self.imageViewBtn.mas_makeConstraints { make in make?.left.equalTo()(offset) make?.right.equalTo()(-offset) make?.top.equalTo()(0) make?.bottom.equalTo()(0) } } else { if (self.itemIdentifier == KMToolbarDividerItemIdentifier) { self.addSubview(self.imageViewBox) self.imageViewBox.mas_makeConstraints { make in make?.top.equalTo()(0) make?.width.equalTo()(8) make?.left.equalTo()(0) make?.right.equalTo()(0) make?.bottom.equalTo()(self.mas_bottom)?.offset()(0) } } } if self.nameBtn.superview != nil && self.isMainTool { self.addSubview(self.linView) self.linView.mas_makeConstraints { make in make?.width.offset()(32) make?.height.offset()(3) make?.centerX.equalTo()(self.mas_centerX) make?.bottom.equalTo()(self.mas_bottom)?.offset()(0) } self.nameBtn.font = .systemFont(ofSize: 14) self.linView.isHidden = true } else { self.nameBtn.font = .systemFont(ofSize: 12) } if self.itemIdentifier != KMToolbarDividerItemIdentifier { self.imageViewBox.borderColor = .clear self.imageViewBox.borderWidth = 1.0 self.imageViewBox.cornerRadius = 7.0 self.addSubview(self.clickButton) self.clickButton.mas_makeConstraints { make in make?.left.right().top().bottom().equalTo()(0) } } } }