123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576 |
- //
- // KMFontWell.swift
- // PDF Reader Pro
- //
- // Created by tangchao on 2023/11/7.
- //
- import Cocoa
- class KMFontWellCell: NSButtonCell {
- var textColor: NSColor?
- var hasTextColor: Bool = false
-
- private let FONTNAME_KEY = "fontName"
- private let FONTSIZE_KEY = "fontSize"
- private let TEXTCOLOR_KEY = "textColor"
- private let HASTEXTCOLOR_KEY = "hasTextColor"
-
- deinit {
- KMPrint("KMFontWellCell deinit.")
- }
-
- override init(textCell string: String) {
- super.init(textCell: string)
-
- self.commonInit()
- }
-
- required init(coder: NSCoder) {
- super.init(coder: coder)
-
- self.textColor = coder.decodeObject(forKey: TEXTCOLOR_KEY) as? NSColor
- self.hasTextColor = coder.decodeBool(forKey: HASTEXTCOLOR_KEY)
- self.commonInit()
- }
-
- func commonInit() {
- if self.textColor == nil {
- self.textColor = .black
- }
-
- self.bezelStyle = .shadowlessSquare
- self.setButtonType(.pushOnPushOff)
- self.state = .off
- }
-
- override func encode(with coder: NSCoder) {
- super.encode(with: coder)
-
- coder.encodeConditionalObject(self.textColor, forKey: TEXTCOLOR_KEY)
- coder.encode(self.hasTextColor, forKey: HASTEXTCOLOR_KEY)
- }
-
- override func copy(with zone: NSZone? = nil) -> Any {
- let cell = super.copy(with: zone) as? KMFontWellCell
- cell?.textColor = self.textColor?.copy(with: zone) as? NSColor
- cell?.hasTextColor = self.hasTextColor
- return cell as Any
- }
-
- override func drawBezel(withFrame frame: NSRect, in controlView: NSView) {
- KMDrawTextFieldBezel(frame, controlView)
- if (self.state == .on) {
- NSGraphicsContext.saveGraphicsState()
- NSColor.selectedControlColor.setFill()
- frame.fill(using: .plusDarker)
- NSGraphicsContext.restoreGraphicsState()
- }
- if (self.isHighlighted) {
- NSGraphicsContext.saveGraphicsState()
- NSColor(calibratedWhite: 0, alpha: 0.1).setFill()
- frame.frame(withWidth: 1, using: .plusDarker)
- NSGraphicsContext.restoreGraphicsState()
- }
-
- if (self.showsFirstResponder) {
- NSGraphicsContext.saveGraphicsState()
- NSFocusRingPlacement.only.set()
- _ = CGRect.fill(frame)
- NSGraphicsContext.restoreGraphicsState()
- }
- }
-
- override var attributedTitle: NSAttributedString {
- set {
- super.attributedTitle = newValue
- }
- get {
- if (self.hasTextColor) {
- var attrString = super.attributedTitle.mutableCopy() as? NSMutableAttributedString
- attrString?.addAttribute(.foregroundColor, value: self.textColor ?? NSColor.black, range: NSMakeRange(0, attrString?.length ?? 0))
- if let data = self.textColor?.usingColorSpaceName(.calibratedRGB)?.brightnessComponent, data > 0.8 {
- let shade = NSShadow()
- shade.shadowColor = .black
- shade.shadowBlurRadius = 1
- attrString?.addAttribute(.shadow, value: shade, range: NSMakeRange(0, attrString?.length ?? 0))
- }
-
- return attrString!
- } else {
- return super.attributedTitle
- }
- }
- }
- }
- private let SKFontWellWillBecomeActiveNotification = "SKFontWellWillBecomeActiveNotification"
- private let ACTION_KEY = "action"
- private let TARGET_KEY = "target"
- class KMFontWell: NSButton {
- var isActive: Bool {
- get {
- return self.state == .on
- }
- }
- var fontName: String? {
- get {
- return self.font?.fontName
- }
- set {
- if let _fontName = newValue {
- let newFont = NSFont(name: _fontName, size: self.font?.pointSize ?? 12)
- self.font = newFont
- }
- }
- }
- var fontSize: CGFloat {
- get {
- return self.font?.pointSize ?? 12
- }
- set {
- if let _fontName = self.fontName {
- let newFont = NSFont(name: _fontName, size: newValue)
- self.font = newFont
- }
- }
- }
- var textColor: NSColor? {
- get {
- return (self.cell as? KMFontWellCell)?.textColor
- }
- set {
- let didChange = self.textColor?.isEqual(to: newValue) ?? false
- (self.cell as? KMFontWellCell)?.textColor = newValue
- if didChange {
- self.needsDisplay = true
- }
- }
- }
-
- var hasTextColor: Bool {
- get {
- if let data = self.cell as? KMFontWellCell {
- return data.hasTextColor
- }
- return false
- }
- set {
- if self.hasTextColor != newValue {
- (self.cell as? KMFontWellCell)?.hasTextColor = newValue
- self.needsDisplay = true
- }
- }
- }
-
- private var _pri_target: AnyObject?
- private var _pri_action: Selector?
- /*
- @interface SKFontWell : NSButton {
- NSMutableDictionary *bindingInfo;
- }
- - (void)changeFontFromFontManager:(id)sender;
- - (void)changeAttributesFromFontManager:(id)sender;
- */
-
- override class var cellClass: AnyClass? {
- set {
- super.cellClass = newValue
- }
- get {
- return KMFontWellCell.self
- }
- }
-
- deinit {
- // SKENSURE_MAIN_THREAD(
- // [self unbind:FONTNAME_KEY];
- // [self unbind:FONTSIZE_KEY];
- // );
- NotificationCenter.default.removeObserver(self)
- // SKDESTROY(bindingInfo);
- }
-
- override init(frame frameRect: NSRect) {
- super.init(frame: frameRect)
-
- self.commonInit()
- }
-
- required init?(coder: NSCoder) {
- super.init(coder: coder)
-
- let oldCell = self.cell as? NSButtonCell
- if let data = oldCell?.isKind(of: Self.cellClass!), !data {
- let newCell = KMFontWellCell(textCell: "")
- newCell.alignment = oldCell?.alignment ?? .center
- newCell.isEditable = oldCell?.isEditable ?? true
- newCell.target = oldCell?.target
- newCell.action = oldCell?.action
- self.cell = newCell
- }
- action = NSSelectorFromString(coder.decodeObject(forKey: ACTION_KEY) as? String ?? "")
- target = coder.decodeObject(forKey: TARGET_KEY) as AnyObject?
- self.commonInit()
- }
-
- override func encode(with coder: NSCoder) {
- super.encode(with: coder)
-
- if let data = self.action {
- coder.encode(NSStringFromSelector(data), forKey: ACTION_KEY)
- }
- coder.encodeConditionalObject(target, forKey: TARGET_KEY)
- }
-
- func commonInit() {
- if (self.font == nil) {
- self.font = .systemFont(ofSize: 0.0)
- }
- self.isEnabled = true
- self._fontChanged()
- super.action = #selector(_changeActive)
- super.target = self
- // bindingInfo = [[NSMutableDictionary alloc] init];
- // [self registerForDraggedTypes:[NSArray arrayWithObjects:SKNSFontPanelDescriptorsPboardType, SKNSFontPanelFamiliesPboardType, NSPasteboardTypeColor, nil]];
- }
- override func draw(_ dirtyRect: NSRect) {
- super.draw(dirtyRect)
- // Drawing code here.
- }
-
- override func viewWillMove(toWindow newWindow: NSWindow?) {
- self._deactivate()
- super.viewWillMove(toWindow: newWindow)
- }
-
- @objc func fontPickerWillBecomeActive(_ notification: NSNotification) {
- let sender = notification.object
- if self.isEqual(to: sender) == false && self.isActive {
- self._deactivate()
- }
- }
-
- @objc func fontPanelWillClose(_ notification: NSNotification) {
- self._deactivate()
- }
-
- override var font: NSFont? {
- get {
- return super.font
- }
- set {
- let didChange = (self.font?.isEqual(to: newValue) == false)
- super.font = newValue
- if didChange {
- self._fontChanged()
- }
- }
- }
-
- override func activeFontWell() -> KMFontWell? {
- if self.isActive {
- return self
- }
- return super.activeFontWell()
- }
-
- func changeFontFromFontManager(_ sender: AnyObject?) {
- if (self.isActive) {
- if let _fontManager = sender as? NSFontManager {
- if let _font = self.font {
- self.font = _fontManager.convert(_font)
- }
- }
- // [self notifyFontBinding];
- self.sendAction(self._pri_action, to: self._pri_target)
- }
- }
-
- override var target: AnyObject? {
- get {
- return self._pri_target
- }
- set {
- self._pri_target = newValue
- }
- }
-
- override var action: Selector? {
- get {
- return self._pri_action
- }
- set {
- self._pri_action = newValue
- }
- }
-
- /*
-
- #define SKNSFontPanelDescriptorsPboardType @"NSFontPanelDescriptorsPboardType"
- #define SKNSFontPanelFamiliesPboardType @"NSFontPanelFamiliesPboardType"
- #define SKNSFontCollectionFontDescriptors @"NSFontCollectionFontDescriptors"
- #define FONT_KEY @"font"
- static char SKFontWellFontNameObservationContext;
- static char SKFontWellFontSizeObservationContext;
- @interface SKFontWell (SKPrivate)
- - (void)changeActive:(id)sender;
- - (void)fontChanged;
- @end
- @implementation SKFontWell
- + (void)initialize {
- // SKINITIALIZE;
-
- [self exposeBinding:FONTNAME_KEY];
- [self exposeBinding:FONTSIZE_KEY];
- [self exposeBinding:TEXTCOLOR_KEY];
- }
- + (NSSet *)keyPathsForValuesAffectingFontName {
- return [NSSet setWithObjects:FONT_KEY, nil];
- }
- + (NSSet *)keyPathsForValuesAffectingFontSize {
- return [NSSet setWithObjects:FONT_KEY, nil];
- }
- - (Class)valueClassForBinding:(NSString *)binding {
- if ([binding isEqualToString:FONTNAME_KEY])
- return [NSString class];
- else if ([binding isEqualToString:FONTNAME_KEY])
- return [NSNumber class];
- else if ([binding isEqualToString:TEXTCOLOR_KEY])
- return [NSColor class];
- else
- return [super valueClassForBinding:binding];
- }
- - (void)notifyFontBinding {
- NSDictionary *info = [self infoForBinding:FONTNAME_KEY];
- [[info objectForKey:NSObservedObjectKey] setValue:[self fontName] forKeyPath:[info objectForKey:NSObservedKeyPathKey]];
- info = [self infoForBinding:FONTSIZE_KEY];
- [[info objectForKey:NSObservedObjectKey] setValue:[NSNumber numberWithDouble:[self fontSize]] forKeyPath:[info objectForKey:NSObservedKeyPathKey]];
- }
- - (void)notifyTextColorBinding {
- NSDictionary *info = [self infoForBinding:TEXTCOLOR_KEY];
- if (info) {
- id value = [self textColor];
- NSString *transformerName = [[info objectForKey:NSOptionsKey] objectForKey:NSValueTransformerNameBindingOption];
- if (transformerName && [transformerName isEqual:[NSNull null]] == NO) {
- NSValueTransformer *valueTransformer = [NSValueTransformer valueTransformerForName:transformerName];
- value = [valueTransformer reverseTransformedValue:value];
- }
- [[info objectForKey:NSObservedObjectKey] setValue:value forKeyPath:[info objectForKey:NSObservedKeyPathKey]];
- }
- }
- - (void)changeAttributesFromFontManager:(id)sender {
- if ([self isActive] && [self hasTextColor]) {
- [self setTextColor:[[sender convertAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[self textColor], NSForegroundColorAttributeName, nil]] valueForKey:NSForegroundColorAttributeName]];
- [self notifyTextColorBinding];
- [self sendAction:[self action] to:[self target]];
- }
- }
- #pragma mark Accessors
- - (SEL)action { return action; }
- - (void)setAction:(SEL)newAction { action = newAction; }
- - (id)target { return target; }
- - (void)setTarget:(id)newTarget { target = newTarget; }
- #pragma mark Binding support
- - (void)bind:(NSString *)bindingName toObject:(id)observableController withKeyPath:(NSString *)keyPath options:(NSDictionary *)options {
- if ([bindingName isEqualToString:FONTNAME_KEY] || [bindingName isEqualToString:FONTSIZE_KEY]) {
-
- if ([bindingInfo objectForKey:bindingName])
- [self unbind:bindingName];
-
- // NSDictionary *bindingsData = [NSDictionary dictionaryWithObjectsAndKeys:observableController, NSObservedObjectKey, [[keyPath copy] autorelease], NSObservedKeyPathKey, [[options copy] autorelease], NSOptionsKey, nil];
- // [bindingInfo setObject:bindingsData forKey:bindingName];
-
- void *context = NULL;
- if ([bindingName isEqualToString:FONTNAME_KEY])
- context = &SKFontWellFontNameObservationContext;
- else if ([bindingName isEqualToString:FONTSIZE_KEY])
- context = &SKFontWellFontSizeObservationContext;
-
- [observableController addObserver:self forKeyPath:keyPath options:0 context:context];
- [self observeValueForKeyPath:keyPath ofObject:observableController change:nil context:context];
- } else {
- [super bind:bindingName toObject:observableController withKeyPath:keyPath options:options];
- }
- [self setNeedsDisplay:YES];
- }
- - (void)unbind:(NSString *)bindingName {
- if ([bindingName isEqualToString:FONTNAME_KEY] || [bindingName isEqualToString:FONTSIZE_KEY]) {
-
- NSDictionary *info = [self infoForBinding:bindingName];
- [[info objectForKey:NSObservedObjectKey] removeObserver:self forKeyPath:[info objectForKey:NSObservedKeyPathKey]];
- [bindingInfo removeObjectForKey:bindingName];
- } else {
- [super unbind:bindingName];
- }
- [self setNeedsDisplay:YES];
- }
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
- NSString *key = nil;
- if (context == &SKFontWellFontNameObservationContext)
- key = FONTNAME_KEY;
- else if (context == &SKFontWellFontSizeObservationContext)
- key = FONTSIZE_KEY;
-
- if (key) {
- NSDictionary *info = [self infoForBinding:key];
- id value = [[info objectForKey:NSObservedObjectKey] valueForKeyPath:[info objectForKey:NSObservedKeyPathKey]];
- if (NSIsControllerMarker(value) == NO)
- [self setValue:value forKey:key];
- } else {
- [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
- }
- }
- - (NSDictionary *)infoForBinding:(NSString *)bindingName {
- return [bindingInfo objectForKey:bindingName] ?: [super infoForBinding:bindingName];
- }
- #pragma mark NSDraggingDestination protocol
- - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
- if ([self isEnabled] && [sender draggingSource] != self && [[sender draggingPasteboard] availableTypeFromArray:[NSArray arrayWithObjects:SKNSFontPanelDescriptorsPboardType, SKNSFontPanelFamiliesPboardType, ([self hasTextColor] ? NSPasteboardTypeColor : nil), nil]]) {
- [[self cell] setHighlighted:YES];
- [self setKeyboardFocusRingNeedsDisplayInRect:[self bounds]];
- [self setNeedsDisplay:YES];
- return NSDragOperationGeneric;
- } else
- return NSDragOperationNone;
- }
- - (void)draggingExited:(id <NSDraggingInfo>)sender {
- if ([self isEnabled] && [sender draggingSource] != self && [[sender draggingPasteboard] availableTypeFromArray:[NSArray arrayWithObjects:SKNSFontPanelDescriptorsPboardType, SKNSFontPanelFamiliesPboardType, ([self hasTextColor] ? NSPasteboardTypeColor : nil), nil]]) {
- [[self cell] setHighlighted:NO];
- [self setKeyboardFocusRingNeedsDisplayInRect:[self bounds]];
- [self setNeedsDisplay:YES];
- }
- }
- - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender {
- return [self isEnabled] && [sender draggingSource] != self && [[sender draggingPasteboard] availableTypeFromArray:[NSArray arrayWithObjects:SKNSFontPanelDescriptorsPboardType, SKNSFontPanelFamiliesPboardType, ([self hasTextColor] ? NSPasteboardTypeColor : nil), nil]];
- }
- - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender{
- NSPasteboard *pboard = [sender draggingPasteboard];
- NSString *type = [pboard availableTypeFromArray:[NSArray arrayWithObjects:SKNSFontPanelDescriptorsPboardType, SKNSFontPanelFamiliesPboardType, ([self hasTextColor] ? NSPasteboardTypeColor : nil), nil]];
- NSFont *droppedFont = nil;
- NSColor *droppedColor = nil;
-
- @try {
- if ([type isEqualToString:SKNSFontPanelDescriptorsPboardType]) {
- NSData *data = [pboard dataForType:type];
- NSDictionary *dict = [data isKindOfClass:[NSData class]] ? [NSKeyedUnarchiver unarchiveObjectWithData:data] : nil;
- if ([dict isKindOfClass:[NSDictionary class]]) {
- NSArray *fontDescriptors = [dict objectForKey:SKNSFontCollectionFontDescriptors];
- NSFontDescriptor *fontDescriptor = ([fontDescriptors isKindOfClass:[NSArray class]] && [fontDescriptors count]) ? [fontDescriptors objectAtIndex:0] : nil;
- if ([fontDescriptor isKindOfClass:[NSFontDescriptor class]]) {
- NSNumber *size = [[fontDescriptor fontAttributes] objectForKey:NSFontSizeAttribute] ?: [dict objectForKey:NSFontSizeAttribute];
- CGFloat fontSize = [size respondsToSelector:@selector(doubleValue)] ? [size doubleValue] : [self fontSize];
- droppedFont = [NSFont fontWithDescriptor:fontDescriptor size:fontSize];
- }
- }
- } else if ([type isEqualToString:SKNSFontPanelFamiliesPboardType]) {
- NSArray *families = [pboard propertyListForType:type];
- NSString *family = ([families isKindOfClass:[NSArray class]] && [families count]) ? [families objectAtIndex:0] : nil;
- if ([family isKindOfClass:[NSString class]])
- droppedFont = [[NSFontManager sharedFontManager] convertFont:[self font] toFamily:family];
- } else if ([type isEqualToString:NSPasteboardTypeColor]) {
- droppedColor = [NSColor colorFromPasteboard:pboard];
- }
- }
- @catch (id exception) {
- NSLog(@"Ignoring exception %@ when dropping on SKFontWell failed", exception);
- }
-
- if (droppedFont) {
- [self setFont:droppedFont];
- [self notifyFontBinding];
- [self sendAction:[self action] to:[self target]];
- }
- if (droppedColor) {
- [self setTextColor:droppedColor];
- [self notifyTextColorBinding];
- [self sendAction:[self action] to:[self target]];
- }
-
- [[self cell] setHighlighted:NO];
- [self setKeyboardFocusRingNeedsDisplayInRect:[self bounds]];
- [self setNeedsDisplay:YES];
-
- return droppedFont != nil || droppedColor != nil;
- }
- @end
- */
- }
- // MARK: - Private Methods
- extension KMFontWell {
- private func _fontChanged() {
- if self.isActive {
- NSFontManager.shared.setSelectedFont(self.font ?? .systemFont(ofSize: 0), isMultiple: false)
- }
- self.title = String(format: "%@ %.0f", self.font?.displayName ?? "", self.fontSize)
- self.needsDisplay = true
- }
-
- @objc private func _changeActive(_ sender: AnyObject?) {
- if (self.isEnabled) {
- if (self.isActive) {
- self._activate()
- } else {
- self._deactivate()
- }
- }
- }
-
- private func _activate() {
- let nc = NotificationCenter.default
- let fm = NSFontManager.shared
-
- nc.post(name: NSNotification.Name(rawValue: SKFontWellWillBecomeActiveNotification), object: self)
-
- fm.setSelectedFont(self.font ?? .systemFont(ofSize: 0), isMultiple: false)
- fm.orderFrontFontPanel(self)
-
- nc.addObserver(self, selector: #selector(fontPickerWillBecomeActive), name: NSNotification.Name(SKFontWellWillBecomeActiveNotification), object: nil)
- nc.addObserver(self, selector: #selector(fontPanelWillClose), name: NSWindow.willCloseNotification, object: fm.fontPanel(true))
-
- self.state = .on
- self.setKeyboardFocusRingNeedsDisplay(self.bounds)
- self.needsDisplay = true
- }
-
- private func _deactivate() {
- NotificationCenter.default.removeObserver(self)
- self.state = .off
- self.setKeyboardFocusRingNeedsDisplay(self.bounds)
- self.needsDisplay = true
- }
- }
|