|
@@ -0,0 +1,123 @@
|
|
|
+//
|
|
|
+// KMTextWithIconCell.swift
|
|
|
+// PDF Reader Pro
|
|
|
+//
|
|
|
+// Created by lizhe on 2024/2/21.
|
|
|
+//
|
|
|
+
|
|
|
+import Cocoa
|
|
|
+
|
|
|
+let SKTextWithIconStringKey = "string"
|
|
|
+let SKTextWithIconImageKey = "image"
|
|
|
+let BORDER_BETWEEN_EDGE_AND_IMAGE: CGFloat = 2.0
|
|
|
+let BORDER_BETWEEN_IMAGE_AND_TEXT: CGFloat = 2.0
|
|
|
+let IMAGE_OFFSET: CGFloat = 1.0
|
|
|
+
|
|
|
+class KMTextWithIconCell: NSTextFieldCell {
|
|
|
+ private var imageCell: NSImageCell = NSImageCell()
|
|
|
+
|
|
|
+ override init(textCell string: String) {
|
|
|
+ super.init(textCell: string)
|
|
|
+ commonInit()
|
|
|
+ }
|
|
|
+
|
|
|
+ required init(coder: NSCoder) {
|
|
|
+ super.init(coder: coder)
|
|
|
+ commonInit()
|
|
|
+ }
|
|
|
+
|
|
|
+ private func commonInit() {
|
|
|
+ imageCell.imageScaling = .scaleProportionallyUpOrDown
|
|
|
+// if formatter == nil {
|
|
|
+// formatter = DictionaryFormatter(key: SKTextWithIconStringKey)
|
|
|
+// }
|
|
|
+ }
|
|
|
+
|
|
|
+ override func copy(with zone: NSZone? = nil) -> Any {
|
|
|
+ let copy = super.copy(with: zone) as! KMTextWithIconCell
|
|
|
+ copy.imageCell = imageCell.copy() as! NSImageCell
|
|
|
+ return copy
|
|
|
+ }
|
|
|
+
|
|
|
+ override func cellSize(forBounds rect: NSRect) -> NSSize {
|
|
|
+ var cellSize = super.cellSize(forBounds: rect)
|
|
|
+ cellSize.width += cellSize.height - 1 + BORDER_BETWEEN_EDGE_AND_IMAGE + BORDER_BETWEEN_IMAGE_AND_TEXT
|
|
|
+ cellSize.width = min(cellSize.width, rect.width)
|
|
|
+ return cellSize
|
|
|
+ }
|
|
|
+
|
|
|
+ private func textRect(forBounds rect: NSRect) -> NSRect {
|
|
|
+ return KMShrinkRect(rect, NSHeight(rect) - 1 + BORDER_BETWEEN_EDGE_AND_IMAGE + BORDER_BETWEEN_IMAGE_AND_TEXT, .minX)
|
|
|
+ }
|
|
|
+
|
|
|
+ private func iconRect(forBounds rect: NSRect) -> NSRect {
|
|
|
+ return KMSliceRect(KMShrinkRect(rect, BORDER_BETWEEN_EDGE_AND_IMAGE, .minX), NSHeight(rect) - 1, .minX)
|
|
|
+ }
|
|
|
+
|
|
|
+ override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
|
|
|
+ // let super draw the text
|
|
|
+ let textRect = textRect(forBounds: cellFrame)
|
|
|
+ super.drawInterior(withFrame: textRect, in: controlView)
|
|
|
+
|
|
|
+ // Draw the image
|
|
|
+ var imageRect = iconRect(forBounds: cellFrame)
|
|
|
+ imageRect = KMCenterRectVertically(rect: imageRect, height: NSWidth(imageRect), offset: IMAGE_OFFSET, flipped: controlView.isFlipped)
|
|
|
+ imageCell.drawInterior(withFrame: imageRect, in: controlView)
|
|
|
+ }
|
|
|
+
|
|
|
+ override func edit(withFrame cellFrame: NSRect, in controlView: NSView, editor textObj: NSText, delegate anObject: Any?, event: NSEvent?) {
|
|
|
+ super.edit(withFrame: textRect(forBounds: cellFrame), in: controlView, editor: textObj, delegate: anObject, event: event)
|
|
|
+ }
|
|
|
+
|
|
|
+ override func select(withFrame cellFrame: NSRect, in controlView: NSView, editor textObj: NSText, delegate anObject: Any?, start selStart: Int, length selLength: Int) {
|
|
|
+ super.select(withFrame: textRect(forBounds: cellFrame), in: controlView, editor: textObj, delegate: anObject, start: selStart, length: selLength)
|
|
|
+ }
|
|
|
+
|
|
|
+ override func hitTest(for event: NSEvent, in rect: NSRect, of controlView: NSView) -> NSCell.HitResult {
|
|
|
+ let textRect = textRect(forBounds: rect)
|
|
|
+ let mouseLoc = event.location(inPDFListView: controlView)
|
|
|
+ var hit: NSCell.HitResult = []
|
|
|
+ if NSMouseInRect(mouseLoc, textRect, controlView.isFlipped) {
|
|
|
+ hit = super.hitTest(for: event, in: textRect, of: controlView)
|
|
|
+ } else if NSMouseInRect(mouseLoc, iconRect(forBounds: rect), controlView.isFlipped) {
|
|
|
+ hit = .contentArea
|
|
|
+ }
|
|
|
+ return hit
|
|
|
+ }
|
|
|
+
|
|
|
+ override var objectValue: Any? {
|
|
|
+ didSet {
|
|
|
+ if let obj = objectValue as? NSDictionary {
|
|
|
+ imageCell.image = obj[SKTextWithIconImageKey] as? NSImage
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var icon: NSImage? {
|
|
|
+ return imageCell.image
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+extension KMTextWithIconCell {
|
|
|
+ func KMSliceRect(_ rect: NSRect, _ amount: CGFloat, _ edge: NSRectEdge) -> NSRect {
|
|
|
+ var rect = rect
|
|
|
+ var ignored = NSRect.zero
|
|
|
+ NSDivideRect(rect, &rect, &ignored, amount, edge);
|
|
|
+ return rect
|
|
|
+ }
|
|
|
+
|
|
|
+ func KMShrinkRect(_ rect: NSRect, _ amount: CGFloat, _ edge: NSRectEdge) -> NSRect {
|
|
|
+ var rect = rect
|
|
|
+ var ignored = NSRect.zero
|
|
|
+ NSDivideRect(rect, &ignored, &rect, amount, edge);
|
|
|
+ return rect
|
|
|
+ }
|
|
|
+
|
|
|
+ func KMCenterRectVertically(rect: NSRect, height: CGFloat , offset: CGFloat, flipped: Bool) -> NSRect {
|
|
|
+ var rect = rect
|
|
|
+ rect.origin.y += 0.5 * (NSHeight(rect) - height);
|
|
|
+ rect.origin.y = flipped ? ceil(rect.origin.y) - offset : floor(rect.origin.y) + offset;
|
|
|
+ rect.size.height = height;
|
|
|
+ return rect;
|
|
|
+ }
|
|
|
+}
|