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