123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- //
- // KMCustomViewButton.swift
- // PDF Reader Pro
- //
- // Created by tangchao on 2023/11/2.
- //
- import Cocoa
- @objc enum KMCustomViewButtonType: Int {
- case batchToolbar = 0
- case menuItem
- case normal
- }
- @objc enum KMCustomViewButtonState: Int {
- case normal = 0
- case mouseIn
- case hightLighted
- }
- @objc protocol KMCustomButtonViewPopDataSource: NSObjectProtocol {
- /// pop框有多少行
- func numberOfLine(in button: KMCustomViewButton) -> Int
- /// pop框某行显示的文字
- func string(for button: KMCustomViewButton, index: Int) -> String?
- /// 某行是否需要下划线
- func needInsertSeperateLine(_ button: KMCustomViewButton, index: Int) -> Bool
- /// 某行是否需要选取
- func needHightLightLine(_ button: KMCustomViewButton, index: Int) -> Bool
- }
- @objc protocol KMCustomButtonViewPopDelegate: NSObjectProtocol {
- func customViewButton(_ button: KMCustomViewButton, didSelectIndex index: Int)
- }
- @objcMembers class KMCustomViewButton: NSView {
- /// constraint
- var frontImageLeftConstraint: MASConstraint? //左边图片距离左边约束
- var frontImageTopConstraint: MASConstraint? //左边图片顶部约束
- var titleLeftConstraint: MASConstraint? //标题距离左边约束
- var titleTopConstraint: MASConstraint? //标题顶部约束
- var backImageLeftConstraint: MASConstraint? //右边图片距离左边约束
-
- /// view
- lazy var imageView: NSImageView = {
- let view = NSImageView()
- return view
- }()
- lazy var titleTextField: NSTextField = {
- let view = NSTextField()
- view.isBordered = false
- view.drawsBackground = true
- view.backgroundColor = .clear
- view.isEditable = false
- return view
- }()
- lazy var indicateImageView: NSImageView = {
- let view = NSImageView()
- return view
- }()
- weak var layoutReferenceView: NSView?
-
- /// layer
- var backLayer: CALayer?
-
- /// state
- var isSelected = false {
- didSet {
- if (self.isSelected) {
- self._toolbarButtonSelected(true)
- if let color = self.selectColor {
- self.backLayer?.backgroundColor = color.cgColor
- }
- } else {
- self._toolbarButtonSelected(true)
- self.backLayer?.backgroundColor = .clear
- }
- }
- }
-
- var mouseInColor: NSColor?
- var highLightColor: NSColor?
- var selectColor: NSColor?
-
- /// popover
- var popOver: NSPopover?
-
- var enable = false
-
- /// title Attribute
- var titleAttributeDict: [String : Any]?
-
- weak var dataSource: KMCustomButtonViewPopDataSource? {
- didSet {
- NotificationCenter.default.removeObserver(self)
- NotificationCenter.default.addObserver(self, selector: #selector(_closePop), name: NSNotification.Name("KMCloseCustomViewButtonPopNotification"), object: nil)
- }
- }
- weak var delegate: KMCustomButtonViewPopDelegate?
-
- private var _showMenuFlag = false
-
- private var _type: KMCustomViewButtonType = .batchToolbar
- private var _state: KMCustomViewButtonState = .normal {
- didSet {
- if (self._state == .normal) {
- if (self.isSelected) {
- self.backLayer?.backgroundColor = self.selectColor != nil ? self.selectColor!.cgColor : .clear
- } else {
- self._toolbarButtonSelected(true)
- self.backLayer?.backgroundColor = .clear
- }
- } else if (self._state == .mouseIn) {
- self._toolbarButtonSelected(true)
- if (self.isSelected) {
- self.backLayer?.backgroundColor = self.selectColor != nil ? self.selectColor!.cgColor : (self.mouseInColor ?? NSColor.clear).cgColor
- } else {
- self.backLayer?.backgroundColor = (self.mouseInColor ?? NSColor.clear).cgColor
- }
- } else if (self._state == .hightLighted) {
- if (self.isSelected) {
- self.backLayer?.backgroundColor = self.selectColor != nil ? self.selectColor!.cgColor : (self.highLightColor ?? NSColor.clear).cgColor
- } else {
- self.backLayer?.backgroundColor = (self.highLightColor ?? NSColor.clear).cgColor
- }
- }
-
- if (self.titleAttributeDict != nil) {
- self.titleTextField.textColor = self.titleAttributeDict?["\(self._state.rawValue)"] as? NSColor
- }
- }
- }
-
- private weak var _target: AnyObject?
- private var _action: Selector?
-
- deinit {
- KMPrint("KMCustomViewButton deinit.")
- NotificationCenter.default.removeObserver(self)
- }
-
- /**
- * 初始化方法
- * @param frontImage 头部图片
- * @param backImage 尾部图片
- * @param title 标题
- * @param title 样式
- *
- */
- convenience init(frontImage: NSImage?, backImage: NSImage?, title: String?, type: KMCustomViewButtonType) {
- if frontImage == nil && backImage == nil && title == nil {
- // return
- }
- self.init()
- self.wantsLayer = true
- self.enable = false
-
- self._addTrackingArea()
- self.layoutReferenceView = self
- var leftMargin = 0.0
- if (frontImage != nil) {
- self.addSubview(self.imageView)
- self.imageView.image = frontImage
- leftMargin = 8
- self.imageView.mas_makeConstraints { make in
- self.frontImageLeftConstraint = make?.left.equalTo()(self.layoutReferenceView)?.offset()(leftMargin)
- make?.centerY.top().equalTo()(self.layoutReferenceView)
- self.frontImageTopConstraint = make?.top.equalTo()(self.layoutReferenceView)?.offset()(3)
- }
- self.layoutReferenceView = self.imageView
- }
-
- if (title != nil) {
- self.addSubview(self.titleTextField)
- self.titleTextField.stringValue = title!
- self.titleTextField.font = .systemFont(ofSize: 12)
- self.titleTextField.textColor = KMAppearance.Layout.h0Color()
- self.titleTextField.mas_makeConstraints { make in
- if self.isEqual(to: self.layoutReferenceView) {
- leftMargin = 30
- self.titleLeftConstraint = make?.left.equalTo()(self)?.offset()(leftMargin)
- self.titleTopConstraint = make?.top.equalTo()(self)?.offset()(3)
- make?.centerY.equalTo()(self)
- } else {
- leftMargin = 8
- self.titleLeftConstraint = make?.left.equalTo()(self.imageView.mas_right)?.offset()(leftMargin)
- make?.centerY.equalTo()(self)
- }
- }
- self.layoutReferenceView = self.titleTextField
- }
-
- if (backImage != nil) {
- self.addSubview(self.indicateImageView)
- self.indicateImageView.image = backImage
- self.indicateImageView.mas_makeConstraints { make in
- self.backImageLeftConstraint = make?.left.equalTo()(self.layoutReferenceView?.mas_right)?.offset()(2)
- make?.centerY.equalTo()(self)
- }
- self.layoutReferenceView = self.indicateImageView
- }
-
- self.layoutReferenceView?.mas_makeConstraints({ make in
- make?.right.equalTo()(self)?.offset()(-leftMargin)
- })
- self.configuAppearance(type: type)
- self._type = type
- self._state = .normal
- self.isSelected = false
- }
-
- override func mouseEntered(with event: NSEvent) {
- if (self.enable) {
- super.mouseEntered(with: event)
- self._showPop()
- if (self.dataSource == nil) {
- NotificationCenter.default.post(name: NSNotification.Name("KMCloseCustomViewButtonPopNotification"), object: nil)
- }
- self._state = .mouseIn
- }
- }
-
- // MARK: - Public Methods
-
- /// 设置设置target-action
- func addTarget(_ target: AnyObject?, action: Selector?) {
- self._target = target
- self._action = action
- }
-
- /// 关闭pop
- func closePop() {
- self._closePop()
- }
-
- override func mouseExited(with event: NSEvent) {
- if (self.enable) {
- super.mouseExited(with: event)
- if (self._showMenuFlag) {
- } else {
- self._state = .normal
- }
- }
- }
-
- override func mouseDown(with event: NSEvent) {
- if (self.enable) {
- super.mouseDown(with: event)
- self._state = .hightLighted
- }
- }
-
- override func mouseUp(with event: NSEvent) {
- if (self.enable) {
- super.mouseUp(with: event)
- if (self._showMenuFlag) {
- } else {
- self._state = .normal
- }
- /// 响应事件
- if let data = (self._target as? NSObject)?.responds(to: self._action), data {
- (self._target as? NSObject)?.perform(self._action, with: self)
- }
- }
- }
- }
- // MARK: - Private Methods
- extension KMCustomViewButton {
- private func _toolbarButtonSelected(_ isSelected: Bool) {
- // if (isSelected) {
- // if ([self.titleTextField.stringValue isEqualToString:NSLocalizedString(@"Convert")]) {
- // self.imageView.image = [NSImage imageNamed:@"KMImageNameUXIconBatchConvert"];
- // } else if ([self.titleTextField.stringValue isEqualToString:NSLocalizedString(@"Merge")]) {
- // self.imageView.image = [NSImage imageNamed:@"KMImageNameUXIconBatchMerge"];
- // } else if ([self.titleTextField.stringValue isEqualToString:NSLocalizedString(@"Compress")]) {
- // self.imageView.image = [NSImage imageNamed:@"KMImageNameUXIconBatchOptimize"];
- // } else if ([self.titleTextField.stringValue isEqualToString:NSLocalizedString(@"OCR")]) {
- // self.imageView.image = [NSImage imageNamed:@"KMImageNameUXIconBatchConvertOCR"];
- // } else if ([self.titleTextField.stringValue isEqualToString:NSLocalizedString(@"Security")]) {
- // self.imageView.image = [NSImage imageNamed:@"KMImageNameUXIconBatchSafe"];
- // } else if ([self.titleTextField.stringValue isEqualToString:NSLocalizedString(@"Watermark")]) {
- // self.imageView.image = [NSImage imageNamed:@"KMImageNameUXIconBatchWatermark"];
- // } else if ([self.titleTextField.stringValue isEqualToString:NSLocalizedString(@"Background")]) {
- // self.imageView.image = [NSImage imageNamed:@"KMImageNameUXIconBatchBackground"];
- // } else if ([self.titleTextField.stringValue isEqualToString:NSLocalizedString(@"Header & Footer")]) {
- // self.imageView.image = [NSImage imageNamed:@"KMImageNameUXIconBatchHeaderandfooter"];
- // } else if ([self.titleTextField.stringValue isEqualToString:NSLocalizedString(@"Bates Numbers")]) {
- // self.imageView.image = [NSImage imageNamed:@"KMImageNameUXIconBatchBates"];
- // }
- // } else {
- if self.titleTextField.stringValue == KMLocalizedString("Convert") {
- self.imageView.image = NSImage(named: "KMImageNameUXIconBatchConvertNor")
- } else if self.titleTextField.stringValue == KMLocalizedString("Merge") {
- self.imageView.image = NSImage(named: "KMImageNameUXIconBatchMergeNor")
- } else if self.titleTextField.stringValue == KMLocalizedString("Compress") {
- self.imageView.image = NSImage(named: "KMImageNameUXIconBatchOptimizeNor")
- } else if self.titleTextField.stringValue == KMLocalizedString("OCR") {
- self.imageView.image = NSImage(named: "KMImageNameUXIconBatchConvertOCRNor")
- } else if self.titleTextField.stringValue == KMLocalizedString("Security") {
- self.imageView.image = NSImage(named: "KMImageNameUXIconBatchSafeNor")
- } else if self.titleTextField.stringValue == KMLocalizedString("Watermark") {
- self.imageView.image = NSImage(named: "KMImageNameUXIconBatchWatermarkNor")
- } else if self.titleTextField.stringValue == KMLocalizedString("Background") {
- self.imageView.image = NSImage(named: "KMImageNameUXIconBatchBackgroundNor")
- } else if self.titleTextField.stringValue == KMLocalizedString("Header & Footer") {
- self.imageView.image = NSImage(named: "KMImageNameUXIconBatchHeaderandfooterNor")
- } else if self.titleTextField.stringValue == KMLocalizedString("Bates Numbers") {
- self.imageView.image = NSImage(named: "KMImageNameUXIconBatchBatesNor")
- }
- // }
- }
-
- @objc private func _closePop() {
- self.popOver?.close()
- self._state = .normal
- }
-
- private func _showPop() {
- if (self.delegate == nil || self.dataSource == nil) {
- return
- }
-
- let menuViewController = KMCustomButtonPopMenuViewController()
- menuViewController.delegate = self
- menuViewController.dataSources = self
- if (self.popOver == nil) {
- 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 = self.bounds
- sourcesRect = self.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: KMRectInset(self.bounds, 0, 5), of: self, preferredEdge: .minY)
- }
-
- private func _addTrackingArea() {
- let trackingArea = NSTrackingArea(rect: self.bounds, options: [.mouseEnteredAndExited, .inVisibleRect, .activeAlways,.mouseMoved], owner: self)
- self.addTrackingArea(trackingArea)
- }
- }
- // MARK: - NSPopoverDelegate
- extension KMCustomViewButton: NSPopoverDelegate {
- func popoverDidShow(_ notification: Notification) {
- self._showMenuFlag = true
- }
-
- func popoverDidClose(_ notification: Notification) {
- self._showMenuFlag = false
- self._state = .normal
- }
- }
- // MARK: - KMCustomButtonPopMenuViewControllerDelegate, KMCustomButtonPopMenuViewControllerDataSources
- extension KMCustomViewButton: KMCustomButtonPopMenuViewControllerDelegate, KMCustomButtonPopMenuViewControllerDataSources {
- func customViewButtonPopDidSelectIndex(_ index: Int) {
- if let _ = self.delegate?.customViewButton(self, didSelectIndex: index) {
- self._closePop()
- }
- }
-
- func numberOfLine() -> Int {
- if let data = self.dataSource?.numberOfLine(in: self) {
- return data
- }
- return 0
- }
-
- /// pop框某行显示的文字
- func stringForLine(at index: Int) -> String? {
- if let data = self.dataSource?.string(for: self, index: index) {
- return data
- }
- return nil;
- }
-
- /// 某行是否需要下划线
- func needInsertSeperateLine(at index: Int) -> Bool {
- if let data = self.dataSource?.needInsertSeperateLine(self, index: index) {
- return data
- }
- return false
- }
-
- /// 某行是否需要选取
- func needHightLightLine(at index: Int) -> Bool {
- if let data = self.dataSource?.needHightLightLine(self, index: index) {
- return data
- }
- return false
- }
-
- func imageForLine(at index: Int) -> NSImage? {
- return nil
- }
-
- func itemEnable(at index: Int) -> Bool {
- return true
- }
- }
- // MARK: - Appearance
- extension KMCustomViewButton {
- func configuAppearance(type: KMCustomViewButtonType) {
- if (type == .batchToolbar) {
- self.backLayer = CALayer()
- self.backLayer?.frame = self.layer?.frame ?? NSRect.zero
- self.backLayer?.autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
- self.layer?.addSublayer(self.backLayer!)
- self.backLayer?.cornerRadius = 6.0;
- self.selectColor = KMAppearance.Status.selColor()
- self.highLightColor = KMAppearance.Status.selColor()
- self.mouseInColor = KMAppearance.Status.selColor()
- } else if (type == .menuItem) {
- self.alignCenter(margin: 10)
- self.changeTopMargin(5)
- }
- }
-
- /// 调整按钮左右间距并居中
- func alignCenter(margin: CGFloat) {
- self.changeLeftMargin(margin)
- self.changeRightMargin(margin)
- }
-
- /// 调整顶部间距离
- func changeTopMargin(_ topMargin: CGFloat) {
- let v = self._leftestView()
- if self.imageView.isEqual(to: v) {
- self.imageView.mas_updateConstraints { make in
- make?.top.equalTo()(self)?.offset()(topMargin)
- }
- } else if self.titleTextField.isEqual(to: v) {
- self.titleTextField.mas_updateConstraints { make in
- make?.top.equalTo()(self)?.offset()(topMargin)
- }
- } else if self.indicateImageView.isEqual(to: v) {
-
- }
- }
- /// 调整按钮左边间距
- func changeLeftMargin(_ leftMargin: CGFloat) {
- let v = self._leftestView()
- if self.imageView.isEqual(to: v) {
- self.imageView.mas_updateConstraints { make in
- self.frontImageLeftConstraint = make?.left.equalTo()(self)?.offset()(leftMargin)
- }
- } else if self.titleTextField.isEqual(to: v) {
- self.titleTextField.mas_updateConstraints { make in
- self.titleLeftConstraint = make?.left.equalTo()(self)?.offset()(leftMargin)
- }
- } else if self.indicateImageView.isEqual(to: v) {
- self.indicateImageView.mas_updateConstraints { make in
- self.backImageLeftConstraint = make?.left.equalTo()(self)?.offset()(leftMargin)
- }
- }
- }
- /// 调整按钮右边间距
- func changeRightMargin(_ rightMargin: CGFloat) {
- let v = self._rightestView()
- if self.imageView.isEqual(to: v) {
- self.imageView.mas_updateConstraints { make in
- make?.right.equalTo()(self)?.offset()(-rightMargin)
- }
- } else if self.titleTextField.isEqual(to: v) {
- self.titleTextField.mas_updateConstraints { make in
- make?.right.equalTo()(self)?.offset()(-rightMargin)
- }
- } else if self.indicateImageView.isEqual(to: v) {
- self.indicateImageView.mas_updateConstraints { make in
- make?.right.equalTo()(self)?.offset()(-rightMargin)
- }
- }
- }
-
- private func _leftestView() -> NSView? {
- if self.subviews.contains(self.imageView) {
- return self.imageView
- } else if self.subviews.contains(self.titleTextField) {
- return self.titleTextField
- } else if (self.subviews.contains(self.indicateImageView)) {
- return self.indicateImageView
- }
- return nil
- }
-
- private func _rightestView() -> NSView? {
- if self.subviews.contains(self.indicateImageView) {
- return self.indicateImageView
- } else if self.subviews.contains(self.titleTextField) {
- return self.titleTextField
- } else if self.subviews.contains(self.imageView) {
- return self.imageView
- }
- return nil
- }
- }
|