github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/updater/osx/Updater/TextView.m (about) 1 // 2 // TextView.m 3 // Updater 4 // 5 // Created by Gabriel on 2/12/15. 6 // Copyright (c) 2015 Keybase. All rights reserved. 7 // 8 9 #import "TextView.h" 10 11 @interface KBNSTextView : NSTextView 12 @property (weak) TextView *parent; 13 @end 14 15 @interface TextView () <NSTextViewDelegate> 16 @property KBNSTextView *view; 17 @end 18 19 @implementation TextView 20 21 - (instancetype)initWithFrame:(NSRect)frameRect { 22 if ((self = [super initWithFrame:frameRect])) { 23 [self viewInit]; 24 } 25 return self; 26 } 27 28 - (instancetype)initWithCoder:(NSCoder *)coder { 29 if ((self = [super initWithCoder:coder])) { 30 [self viewInit]; 31 } 32 return self; 33 } 34 35 - (void)viewInit { 36 self.identifier = self.className; 37 KBNSTextView *view = [[KBNSTextView alloc] init]; 38 view.parent = self; 39 _view = view; 40 _view.autoresizingMask = NSViewHeightSizable|NSViewWidthSizable; 41 _view.backgroundColor = NSColor.whiteColor; 42 _view.editable = YES; 43 _view.delegate = self; 44 45 [self setDocumentView:_view]; 46 self.hasVerticalScroller = YES; 47 self.verticalScrollElasticity = NSScrollElasticityAllowed; 48 self.autohidesScrollers = YES; 49 } 50 51 // Adding this method and passing to super makes responsive scroll work correctly. 52 // Without this method scrolling using trackpad is slow and chunky. 53 // AppKit checks if this method is being overridden by a subclass, which works around the issue somehow. 54 - (void)scrollWheel:(NSEvent *)event { 55 [super scrollWheel:event]; 56 } 57 58 - (CGSize)sizeThatFits:(CGSize)size { 59 return self.frame.size; 60 } 61 62 - (BOOL)becomeFirstResponder { 63 return [_view becomeFirstResponder]; 64 } 65 66 - (BOOL)resignFirstResponder { 67 return [_view resignFirstResponder]; 68 } 69 70 - (void)setEnabled:(BOOL)enabled { 71 _view.selectable = enabled; 72 _view.editable = enabled; 73 } 74 75 - (NSString *)description { 76 return [NSString stringWithFormat:@"%@ %@", super.description, self.attributedText]; 77 } 78 79 - (NSString *)text { 80 return [_view.textStorage string]; 81 } 82 83 - (void)setText:(NSString *)text { 84 _view.string = text ? text : @""; 85 } 86 87 - (void)setAttributedText:(NSAttributedString *)attributedText { 88 if (!attributedText) attributedText = [[NSAttributedString alloc] initWithString:@""]; 89 NSAssert(_view.textStorage, @"No text storage"); 90 [_view.textStorage setAttributedString:attributedText]; 91 _view.needsDisplay = YES; 92 } 93 94 - (NSAttributedString *)attributedText { 95 return _view.textStorage; 96 } 97 98 - (void)setText:(NSString *)text font:(NSFont *)font color:(NSColor *)color { 99 [self setText:text font:font color:color alignment:NSLeftTextAlignment lineBreakMode:NSLineBreakByWordWrapping]; 100 } 101 102 - (void)setText:(NSString *)text font:(NSFont *)font color:(NSColor *)color alignment:(NSTextAlignment)alignment lineBreakMode:(NSLineBreakMode)lineBreakMode { 103 if (!text) { 104 self.attributedText = nil; 105 return; 106 } 107 NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:text]; 108 109 NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; 110 paragraphStyle.alignment = alignment; 111 paragraphStyle.lineBreakMode = lineBreakMode; 112 113 NSDictionary *attributes = @{NSForegroundColorAttributeName:color, NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle}; 114 [str setAttributes:attributes range:NSMakeRange(0, str.length)]; 115 116 self.attributedText = str; 117 } 118 119 - (BOOL)isEditable { 120 return _view.isEditable; 121 } 122 123 - (void)setEditable:(BOOL)editable { 124 [_view setEditable:editable]; 125 } 126 127 // Returns YES if you should call super paste (use the default paste impl) 128 - (BOOL)onPasted { 129 BOOL paste = YES; 130 if (self.onPaste) paste = self.onPaste(self); 131 [self didChange]; 132 return paste; 133 } 134 135 - (void)didChange { 136 if (self.onChange) self.onChange(self); 137 } 138 139 #pragma mark NSTextViewDelegate 140 141 - (void)textDidChange:(NSNotification *)notification { 142 [self didChange]; 143 } 144 145 @end 146 147 148 @implementation KBNSTextView 149 150 - (void)paste:(id)sender { 151 if ([self.parent onPasted]) [super paste:sender]; 152 } 153 154 @end