// 16 july 2014 #import "objc_darwin.h" #import "_cgo_export.h" #import #define toNSButton(x) ((NSButton *) (x)) #define toNSTextField(x) ((NSTextField *) (x)) #define toNSView(x) ((NSView *) (x)) #define toNSWindow(x) ((NSWindow *) (x)) #define toNSBox(x) ((NSBox *) (x)) #define toNSTextView(x) ((NSTextView *) (x)) #define toNSProgressIndicator(x) ((NSProgressIndicator *) (x)) @interface goControlDelegate : NSObject { @public void *gocontrol; } @end @implementation goControlDelegate - (IBAction)buttonClicked:(id)sender { buttonClicked(self->gocontrol); } - (IBAction)checkboxToggled:(id)sender { checkboxToggled(self->gocontrol); } - (void)controlTextDidChange:(NSNotification *)note { textfieldChanged(self->gocontrol); } @end id newButton(void) { NSButton *b; b = [[NSButton alloc] initWithFrame:NSZeroRect]; [b setButtonType:NSMomentaryPushInButton]; [b setBordered:YES]; [b setBezelStyle:NSRoundedBezelStyle]; setStandardControlFont((id) b); return (id) b; } void buttonSetDelegate(id button, void *b) { goControlDelegate *d; d = [goControlDelegate new]; d->gocontrol = b; [toNSButton(button) setTarget:d]; [toNSButton(button) setAction:@selector(buttonClicked:)]; } const char *buttonText(id button) { return [[toNSButton(button) title] UTF8String]; } void buttonSetText(id button, char *text) { [toNSButton(button) setTitle:[NSString stringWithUTF8String:text]]; } id newCheckbox(void) { NSButton *c; c = [[NSButton alloc] initWithFrame:NSZeroRect]; [c setButtonType:NSSwitchButton]; [c setBordered:NO]; setStandardControlFont((id) c); return (id) c; } void checkboxSetDelegate(id checkbox, void *b) { goControlDelegate *d; d = [goControlDelegate new]; d->gocontrol = b; [toNSButton(checkbox) setTarget:d]; [toNSButton(checkbox) setAction:@selector(checkboxToggled:)]; } BOOL checkboxChecked(id c) { if ([toNSButton(c) state] == NSOnState) return YES; return NO; } void checkboxSetChecked(id c, BOOL checked) { NSInteger state; state = NSOnState; if (checked == NO) state = NSOffState; [toNSButton(c) setState:state]; } // also good for labels // not static because area_darwin.m uses it id finishNewTextField(id _t, BOOL bordered) { NSTextField *t = toNSTextField(_t); // same for text fields, password fields, and labels setStandardControlFont((id) t); // these three are the same across text fields, password fields, and labels; the only difference is the setBezeled: value, and it's only different on labels // THE ORDER OF THESE CALLS IS IMPORTANT; CHANGE IT AND THE BORDERS WILL DISAPPEAR [t setBordered:NO]; [t setBezelStyle:NSTextFieldSquareBezel]; [t setBezeled:bordered]; // smart quotes and other autocorrect features are handled by the window; see newWindow() in window_darwin.m for details // Interface Builder does this to make the text box behave properly // this disables both word wrap AND ellipsizing in one fell swoop // however, we need to send it to the control's cell, not to the control directly [[t cell] setLineBreakMode:NSLineBreakByClipping]; // Interface Builder also sets this to allow horizontal scrolling // it also sets this for labels, despite those not being scrollable [[t cell] setScrollable:YES]; return (id) t; } id newTextField(void) { NSTextField *t; t = [[NSTextField alloc] initWithFrame:NSZeroRect]; [t setSelectable:YES]; // otherwise the setting is masked by the editable default of YES return finishNewTextField((id) t, YES); } id newPasswordField(void) { NSSecureTextField *t; t = [[NSSecureTextField alloc] initWithFrame:NSZeroRect]; [t setSelectable:YES]; // otherwise the setting is masked by the editable default of YES return finishNewTextField((id) t, YES); } void textfieldSetDelegate(id textfield, void *t) { goControlDelegate *d; d = [goControlDelegate new]; d->gocontrol = t; [toNSTextField(textfield) setDelegate:d]; } // also good for labels const char *textfieldText(id t) { return [[toNSTextField(t) stringValue] UTF8String]; } // also good for labels void textfieldSetText(id t, char *text) { [toNSTextField(t) setStringValue:[NSString stringWithUTF8String:text]]; } id textfieldOpenInvalidPopover(id textfield, char *reason) { id popover; popover = newWarningPopover(reason); warningPopoverShow(popover, textfield); NSBeep(); return (id) popover; } void textfieldCloseInvalidPopover(id popover) { [toNSWindow(popover) close]; // don't release; close does that already } BOOL textfieldEditable(id textfield) { return [toNSTextField(textfield) isEditable]; } void textfieldSetEditable(id textfield, BOOL editable) { [toNSTextField(textfield) setEditable:editable]; } id newLabel(void) { NSTextField *l; l = [[NSTextField alloc] initWithFrame:NSZeroRect]; [l setEditable:NO]; [l setSelectable:NO]; [l setDrawsBackground:NO]; return finishNewTextField((id) l, NO); } id newGroup(id container) { NSBox *group; group = [[NSBox alloc] initWithFrame:NSZeroRect]; [group setBorderType:NSLineBorder]; [group setBoxType:NSBoxPrimary]; [group setTransparent:NO]; // can't use setSmallControlFont() here because the selector is different [group setTitleFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; [group setTitlePosition:NSAtTop]; [group setContentView:toNSView(container)]; return (id) group; } const char *groupText(id group) { return [[toNSBox(group) title] UTF8String]; } void groupSetText(id group, char *text) { [toNSBox(group) setTitle:[NSString stringWithUTF8String:text]]; } id newTextbox(void) { NSTextView *tv; tv = [[NSTextView alloc] initWithFrame:NSZeroRect]; // verified against Interface Builder, except for rich text options [tv setAllowsDocumentBackgroundColorChange:NO]; [tv setBackgroundColor:[NSColor textBackgroundColor]]; [tv setTextColor:[NSColor textColor]]; [tv setAllowsUndo:YES]; [tv setEditable:YES]; [tv setSelectable:YES]; [tv setRichText:NO]; [tv setImportsGraphics:NO]; [tv setBaseWritingDirection:NSWritingDirectionNatural]; // TODO default paragraph format [tv setAllowsImageEditing:NO]; [tv setAutomaticQuoteSubstitutionEnabled:NO]; [tv setAutomaticLinkDetectionEnabled:NO]; [tv setUsesRuler:NO]; [tv setRulerVisible:NO]; [tv setUsesInspectorBar:NO]; [tv setSelectionGranularity:NSSelectByCharacter]; //TODO [tv setInsertionPointColor:[NSColor insertionColor]]; [tv setContinuousSpellCheckingEnabled:NO]; [tv setGrammarCheckingEnabled:NO]; [tv setUsesFontPanel:NO]; [tv setEnabledTextCheckingTypes:0]; [tv setAutomaticDashSubstitutionEnabled:NO]; [tv setAutomaticSpellingCorrectionEnabled:NO]; [tv setAutomaticTextReplacementEnabled:NO]; [tv setSmartInsertDeleteEnabled:NO]; [tv setLayoutOrientation:NSTextLayoutOrientationHorizontal]; // TODO default find panel behavior // now just to be safe; this will do some of the above but whatever disableAutocorrect((id) tv); // this option is complex; just set it to the Interface Builder default [[tv layoutManager] setAllowsNonContiguousLayout:YES]; // this will work because it's the same selector setStandardControlFont((id) tv); return (id) tv; } char *textboxText(id tv) { return [[toNSTextView(tv) string] UTF8String]; } void textboxSetText(id tv, char *text) { [toNSTextView(tv) setString:[NSString stringWithUTF8String:text]]; } id newProgressBar(void) { NSProgressIndicator *pi; pi = [[NSProgressIndicator alloc] initWithFrame:NSZeroRect]; [pi setStyle:NSProgressIndicatorBarStyle]; [pi setControlSize:NSRegularControlSize]; [pi setControlTint:NSDefaultControlTint]; [pi setBezeled:YES]; [pi setDisplayedWhenStopped:YES]; [pi setUsesThreadedAnimation:YES]; [pi setIndeterminate:NO]; [pi setMinValue:0]; [pi setMaxValue:100]; [pi setDoubleValue:0]; return (id) pi; } intmax_t progressbarPercent(id pbar) { return (intmax_t) [toNSProgressIndicator(pbar) doubleValue]; } void progressbarSetPercent(id pbar, intmax_t percent) { [toNSProgressIndicator(pbar) setDoubleValue:((double) percent)]; }