// 8 december 2015 #import "uipriv_darwin.h" // NSTextView has no intrinsic content size by default, which wreaks havoc on a pure-Auto Layout system // we'll have to take over to get it to work // see also http://stackoverflow.com/questions/24210153/nstextview-not-properly-resizing-with-auto-layout and http://stackoverflow.com/questions/11237622/using-autolayout-with-expanding-nstextviews @interface intrinsicSizeTextView : NSTextView @end @implementation intrinsicSizeTextView - (NSSize)intrinsicContentSize { NSTextContainer *textContainer; NSLayoutManager *layoutManager; NSRect rect; textContainer = [self textContainer]; layoutManager = [self layoutManager]; [layoutManager ensureLayoutForTextContainer:textContainer]; rect = [layoutManager usedRectForTextContainer:textContainer]; return rect.size; } - (void)didChangeText { [super didChangeText]; [self invalidateIntrinsicContentSize]; } // TODO this doesn't call the above? // TODO this also isn't perfect; play around with cpp-multithread - (void)setString:(NSString *)str { [super setString:str]; [self didChangeText]; } @end struct uiMultilineEntry { uiDarwinControl c; NSScrollView *sv; intrinsicSizeTextView *tv; void (*onChanged)(uiMultilineEntry *, void *); void *onChangedData; struct scrollViewConstraints constraints; }; // TODO events // TODO destroy uiDarwinControlAllDefaults(uiMultilineEntry, sv) static void defaultOnChanged(uiMultilineEntry *e, void *data) { // do nothing } char *uiMultilineEntryText(uiMultilineEntry *e) { return uiDarwinNSStringToText([e->tv string]); } void uiMultilineEntrySetText(uiMultilineEntry *e, const char *text) { // TODO does this send a changed signal? [e->tv setString:toNSString(text)]; } // TODO scroll to end? void uiMultilineEntryAppend(uiMultilineEntry *e, const char *text) { // TODO better way? NSString *str; // TODO does this send a changed signal? str = [e->tv string]; str = [str stringByAppendingString:toNSString(text)]; [e->tv setString:str]; } void uiMultilineEntryOnChanged(uiMultilineEntry *e, void (*f)(uiMultilineEntry *e, void *data), void *data) { e->onChanged = f; e->onChangedData = data; } int uiMultilineEntryReadOnly(uiMultilineEntry *e) { return [e->tv isEditable] == NO; } void uiMultilineEntrySetReadOnly(uiMultilineEntry *e, int readonly) { BOOL editable; editable = YES; if (readonly) editable = NO; [e->tv setEditable:editable]; } uiMultilineEntry *uiNewMultilineEntry(void) { uiMultilineEntry *e; NSFont *font; uiDarwinNewControl(uiMultilineEntry, e); e->sv = [[NSScrollView alloc] initWithFrame:NSZeroRect]; // TODO verify against Interface Builder [e->sv setHasHorizontalScroller:NO]; [e->sv setHasVerticalScroller:YES]; [e->sv setAutohidesScrollers:YES]; [e->sv setBorderType:NSBezelBorder]; e->tv = [[intrinsicSizeTextView alloc] initWithFrame:NSZeroRect]; // verified against Interface Builder, except for rich text options [e->tv setAllowsDocumentBackgroundColorChange:NO]; [e->tv setBackgroundColor:[NSColor textBackgroundColor]]; [e->tv setTextColor:[NSColor textColor]]; [e->tv setAllowsUndo:YES]; [e->tv setEditable:YES]; [e->tv setSelectable:YES]; [e->tv setRichText:NO]; [e->tv setImportsGraphics:NO]; [e->tv setBaseWritingDirection:NSWritingDirectionNatural]; // TODO default paragraph format [e->tv setAllowsImageEditing:NO]; [e->tv setAutomaticQuoteSubstitutionEnabled:NO]; [e->tv setAutomaticLinkDetectionEnabled:NO]; [e->tv setUsesRuler:NO]; [e->tv setRulerVisible:NO]; [e->tv setUsesInspectorBar:NO]; [e->tv setSelectionGranularity:NSSelectByCharacter]; //TODO [e->tv setInsertionPointColor:[NSColor insertionColor]]; [e->tv setContinuousSpellCheckingEnabled:NO]; [e->tv setGrammarCheckingEnabled:NO]; [e->tv setUsesFontPanel:NO]; [e->tv setEnabledTextCheckingTypes:0]; [e->tv setAutomaticDashSubstitutionEnabled:NO]; [e->tv setAutomaticSpellingCorrectionEnabled:NO]; [e->tv setAutomaticTextReplacementEnabled:NO]; [e->tv setSmartInsertDeleteEnabled:NO]; [e->tv setLayoutOrientation:NSTextLayoutOrientationHorizontal]; // TODO default find panel behavior // now just to be safe; this will do some of the above but whatever disableAutocorrect(e->tv); // this option is complex; just set it to the Interface Builder default [[e->tv layoutManager] setAllowsNonContiguousLayout:YES]; // don't use uiDarwinSetControlFont() directly; we have to do a little extra work to set the font font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; [e->tv setTypingAttributes:[NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]]; // e->tv font from Interface Builder is nil, but setFont:nil throws an exception // let's just set it to the standard control font anyway, just to be safe [e->tv setFont:font]; [e->sv setDocumentView:e->tv]; [e->tv setTranslatesAutoresizingMaskIntoConstraints:NO]; scrollViewConstraintsEstablish(&(e->constraints), e->sv, @"uiMultilineEntry"); // needed to allow horizontal shrinking // TODO what about vertical text? [e->tv setContentCompressionResistancePriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal]; //TODO:void printinfo(NSScrollView *sv, NSTextView *tv); //printinfo(e->sv, e->tv); uiMultilineEntryOnChanged(e, defaultOnChanged, NULL); return e; } // TODO #if 0 NSMutableString *s; static void add(const char *fmt, ...) { va_list ap; NSString *fmts; NSString *a; va_start(ap, fmt); fmts = [NSString stringWithUTF8String:fmt]; a = [[NSString alloc] initWithFormat:fmts arguments:ap]; [s appendString:a]; [s appendString:@"\n"]; va_end(ap); } static NSString *edgeInsetsStr(NSEdgeInsets i) { return [NSString stringWithFormat:@"left:%g top:%g right:%g bottom:%g", i.left, i.top, i.right, i.bottom]; } void printinfo(NSScrollView *sv, NSTextView *tv) { s = [NSMutableString new]; #define self _s struct { NSScrollView *sv; NSTextView *tv; } _s; _s.sv = sv; _s.tv = tv; add("NSScrollView"); add(" backgroundColor %@", [self.sv backgroundColor]); add(" drawsBackground %d", [self.sv drawsBackground]); add(" borderType %d", [self.sv borderType]); add(" documentCursor %@", [self.sv documentCursor]); add(" hasHorizontalScroller %d", [self.sv hasHorizontalScroller]); add(" hasVerticalScroller %d", [self.sv hasVerticalScroller]); add(" autohidesScrollers %d", [self.sv autohidesScrollers]); add(" hasHorizontalRuler %d", [self.sv hasHorizontalRuler]); add(" hasVerticalRuler %d", [self.sv hasVerticalRuler]); add(" rulersVisible %d", [self.sv rulersVisible]); add(" automaticallyAdjustsContentInsets %d", [self.sv automaticallyAdjustsContentInsets]); add(" contentInsets %@", edgeInsetsStr([self.sv contentInsets])); add(" scrollerInsets %@", edgeInsetsStr([self.sv scrollerInsets])); add(" scrollerKnobStyle %d", [self.sv scrollerKnobStyle]); add(" scrollerStyle %d", [self.sv scrollerStyle]); add(" lineScroll %g", [self.sv lineScroll]); add(" horizontalLineScroll %g", [self.sv horizontalLineScroll]); add(" verticalLineScroll %g", [self.sv verticalLineScroll]); add(" pageScroll %g", [self.sv pageScroll]); add(" horizontalPageScroll %g", [self.sv horizontalPageScroll]); add(" verticalPageScroll %g", [self.sv verticalPageScroll]); add(" scrollsDynamically %d", [self.sv scrollsDynamically]); add(" findBarPosition %d", [self.sv findBarPosition]); add(" usesPredominantAxisScrolling %d", [self.sv usesPredominantAxisScrolling]); add(" horizontalScrollElasticity %d", [self.sv horizontalScrollElasticity]); add(" verticalScrollElasticity %d", [self.sv verticalScrollElasticity]); add(" allowsMagnification %d", [self.sv allowsMagnification]); add(" magnification %g", [self.sv magnification]); add(" maxMagnification %g", [self.sv maxMagnification]); add(" minMagnification %g", [self.sv minMagnification]); add(""); add("NSTextView"); add(" textContainerInset %@", NSStringFromSize([self.tv textContainerInset])); add(" textContainerOrigin %@", NSStringFromPoint([self.tv textContainerOrigin])); add(" backgroundColor %@", [self.tv backgroundColor]); add(" drawsBackground %d", [self.tv drawsBackground]); add(" allowsDocumentBackgroundColorChange %d", [self.tv allowsDocumentBackgroundColorChange]); add(" allowedInputSourceLocales %@", [self.tv allowedInputSourceLocales]); add(" allowsUndo %d", [self.tv allowsUndo]); add(" isEditable %d", [self.tv isEditable]); add(" isSelectable %d", [self.tv isSelectable]); add(" isFieldEditor %d", [self.tv isFieldEditor]); add(" isRichText %d", [self.tv isRichText]); add(" importsGraphics %d", [self.tv importsGraphics]); add(" defaultParagraphStyle %@", [self.tv defaultParagraphStyle]); add(" allowsImageEditing %d", [self.tv allowsImageEditing]); add(" isAutomaticQuoteSubstitutionEnabled %d", [self.tv isAutomaticQuoteSubstitutionEnabled]); add(" isAutomaticLinkDetectionEnabled %d", [self.tv isAutomaticLinkDetectionEnabled]); add(" displaysLinkToolTips %d", [self.tv displaysLinkToolTips]); add(" usesRuler %d", [self.tv usesRuler]); add(" isRulerVisible %d", [self.tv isRulerVisible]); add(" usesInspectorBar %d", [self.tv usesInspectorBar]); add(" selectionAffinity %d", [self.tv selectionAffinity]); add(" selectionGranularity %d", [self.tv selectionGranularity]); add(" insertionPointColor %@", [self.tv insertionPointColor]); add(" selectedTextAttributes %@", [self.tv selectedTextAttributes]); add(" markedTextAttributes %@", [self.tv markedTextAttributes]); add(" linkTextAttributes %@", [self.tv linkTextAttributes]); add(" typingAttributes %@", [self.tv typingAttributes]); add(" smartInsertDeleteEnabled %d", [self.tv smartInsertDeleteEnabled]); add(" isContinuousSpellCheckingEnabled %d", [self.tv isContinuousSpellCheckingEnabled]); add(" isGrammarCheckingEnabled %d", [self.tv isGrammarCheckingEnabled]); add(" acceptsGlyphInfo %d", [self.tv acceptsGlyphInfo]); add(" usesFontPanel %d", [self.tv usesFontPanel]); add(" usesFindPanel %d", [self.tv usesFindPanel]); add(" enabledTextCheckingTypes %d", [self.tv enabledTextCheckingTypes]); add(" isAutomaticDashSubstitutionEnabled %d", [self.tv isAutomaticDashSubstitutionEnabled]); add(" isAutomaticDataDetectionEnabled %d", [self.tv isAutomaticDataDetectionEnabled]); add(" isAutomaticSpellingCorrectionEnabled %d", [self.tv isAutomaticSpellingCorrectionEnabled]); add(" isAutomaticTextReplacementEnabled %d", [self.tv isAutomaticTextReplacementEnabled]); add(" usesFindBar %d", [self.tv usesFindBar]); add(" isIncrementalSearchingEnabled %d", [self.tv isIncrementalSearchingEnabled]); add(" NSText:"); add(" font %@", [self.tv font]); add(" textColor %@", [self.tv textColor]); add(" baseWritingDirection %d", [self.tv baseWritingDirection]); add(" maxSize %@", NSStringFromSize([self.tv maxSize])); add(" minSize %@", NSStringFromSize([self.tv minSize])); add(" isVerticallyResizable %d", [self.tv isVerticallyResizable]); add(" isHorizontallyResizable %d", [self.tv isHorizontallyResizable]); #undef self fprintf(stdout, "%s", [s UTF8String]); } #endif