From 4baa9397e6546e78e07b24bb8bbab785417e0378 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 28 May 2014 23:46:33 -0400 Subject: [PATCH] Merged back combobox_darwin.m, rewrote it to use boundListboxArray() instead of creating a whole new object, and implemented what appears to be a fix for NSPopUpButton selection. Will delete the unneeded select(-1) code later and test again... --- combobox_darwin.m | 122 ++++++++++++++++++++++++++ experiments/combobox_darwin.m | 156 ---------------------------------- objc_darwin.h | 16 ++-- sysdata_darwin.m | 86 +------------------ 4 files changed, 132 insertions(+), 248 deletions(-) create mode 100644 combobox_darwin.m delete mode 100644 experiments/combobox_darwin.m diff --git a/combobox_darwin.m b/combobox_darwin.m new file mode 100644 index 0000000..5c88b07 --- /dev/null +++ b/combobox_darwin.m @@ -0,0 +1,122 @@ +// 17 may 2014 + +#include "objc_darwin.h" + +// see delegateuitask_darwin.m +// in this case, NSPopUpButton.h and NSComboBox.h includes NSApplication.h +#import + +#ifdef MAC_OS_X_VERSION_10_7 +#undef MAC_OS_X_VERSION_MIN_REQUIRED +#undef MAC_OS_X_VERSION_MAX_ALLOWED +#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_7 +#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_7 +#endif +#import +#undef MAC_OS_X_VERSION_MIN_REQUIRED +#undef MAC_OS_X_VERSION_MAX_ALLOWED +#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6 +#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_6 + +#import +#import +#import + +/* +Cocoa doesn't have combo boxes in the sense that other systems do. NSPopUpButton is not editable and technically behaves like a menu on a menubar. NSComboBox is editable and is the more traditional combo box, but the edit field and list are even more separated than they are on other platforms. + +Unfortunately, their default internal storage mechanisms exhibit the automatic selection behavior I DON'T want, so we're going to have to do that ourselves. + +The NSArrayController we use in our Listboxes already behaves the way we want. Consequently, you'll notice a bunch of functions here call functions in listbox_darwin.m. How convenient =P (TODO separate into objc_darwin.m?) + +TODO should we use NSComboBox's dataSource feature? +*/ + +extern NSRect dummyRect; + +#define to(T, x) ((T *) (x)) +#define toNSPopUpButton(x) to(NSPopUpButton, (x)) +#define toNSComboBox(x) to(NSComboBox, (x)) + +#define toNSInteger(x) ((NSInteger) (x)) +#define fromNSInteger(x) ((intptr_t) (x)) + +#define COMBOBOXKEY @"cbitem" +static NSString *comboboxKey = COMBOBOXKEY; +static NSString *comboboxBinding = @"contentValues"; +static NSString *comboboxKeyPath = @"arrangedObjects." COMBOBOXKEY; + +id makeCombobox(BOOL editable) +{ + NSArrayController *ac; + + ac = makeListboxArray(); +#define BIND bind:comboboxBinding toObject:ac withKeyPath:comboboxKeyPath options:nil +// for NSPopUpButton, we need a little extra work to make it respect the NSArrayController's selection behavior properties +// thanks to stevesliva (http://stackoverflow.com/questions/23715275/cocoa-how-do-i-suppress-nspopupbutton-automatic-selection-synchronization-nsar) +// TODO where in the docs does it say that NSArrayController has a keyPath of selectionIndex? it's not in the Cocoa Bindings Reference +#define BINDSEL bind:@"selectedIndex" toObject:ac withKeyPath:@"selectionIndex" options:nil + + if (!editable) { + NSPopUpButton *pb; + + pb = [[NSPopUpButton alloc] + initWithFrame:dummyRect + pullsDown:NO]; + [pb BIND]; + [pb BINDSEL]; + return pb; + } + + NSComboBox *cb; + + cb = [[NSComboBox alloc] + initWithFrame:dummyRect]; + [cb setUsesDataSource:NO]; + [cb BIND]; + // no need to bind selection + return cb; +} + +id comboboxText(id c, BOOL editable) +{ + if (!editable) + return [toNSPopUpButton(c) titleOfSelectedItem]; + return [toNSComboBox(c) stringValue]; +} + +void comboboxAppend(id c, BOOL editable, id str) +{ + id ac; + + ac = boundListboxArray(c, comboboxBinding); + listboxArrayAppend(ac, toListboxItem(comboboxKey, str)); +} + +void comboboxInsertBefore(id c, BOOL editable, id str, intptr_t before) +{ + id ac; + + ac = boundListboxArray(c, comboboxBinding); + listboxArrayInsertBefore(ac, toListboxItem(comboboxKey, str), before); +} + +intptr_t comboboxSelectedIndex(id c) +{ + // both satisfy the selector + return fromNSInteger([toNSPopUpButton(c) indexOfSelectedItem]); +} + +void comboboxDelete(id c, intptr_t index) +{ + id ac; + + ac = boundListboxArray(c, comboboxBinding); + listboxArrayDelete(ac, index); +} + +intptr_t comboboxLen(id c) +{ + // both satisfy the selector + return fromNSInteger([toNSPopUpButton(c) numberOfItems]); +} diff --git a/experiments/combobox_darwin.m b/experiments/combobox_darwin.m deleted file mode 100644 index da9b658..0000000 --- a/experiments/combobox_darwin.m +++ /dev/null @@ -1,156 +0,0 @@ -// 17 may 2014 - -#include "objc_darwin.h" -#include -#include -#include - -/* -Cocoa doesn't have combo boxes in the sense that other systems do. NSPopUpButton is not editable and technically behaves like a menu on a menubar. NSComboBox is editable and is the more traditional combo box, but the edit field and list are even more separated than they are on other platforms. - -Unfortunately, their default internal storage mechanisms exhibit the automatic selection behavior I DON'T want, so we're going to have to do that ourselves. - -You will notice that a bunch of functions here call functions in listbox_darwin.m. How convenient =P -*/ - -@interface combobox : NSObject { -@public - NSPopUpButton *pb; - NSComboBox *cb; - NSArrayController *ac; -} -// and these are so we can use a combobox like a reegular control -- (void)setHidden:(BOOL)hidden; -- (void)setFont:(NSFont *)font; -- (void)setFrame:(NSRect)r; -- (NSRect)frame; -- (void)sizeToFit; -@end - -@implementation combobox - -#define OVERRIDE(sig, msg) \ - sig \ - { \ - if (pb != nil) { \ - [pb msg]; \ - return; \ - } \ - [cb msg]; \ - } - -OVERRIDE(- (void)setHidden:(BOOL)hidden, setHidden:hidden) -OVERRIDE(- (void)setFont:(NSFont *)font, setFont:font) -OVERRIDE(- (void)setFrame:(NSRect)r, setFrame:r) - -- (NSRect)frame -{ - if (pb != nil) - return [pb frame]; - return [cb frame]; -} - -OVERRIDE(- (void)sizeToFit, sizeToFit) - -@end - -extern NSRect dummyRect; - -#define to(T, x) ((T *) (x)) -#define tocombobox(x) to(combobox, (x)) - -#define toNSInteger(x) ((NSInteger) (x)) -#define fromNSInteger(x) ((intptr_t) (x)) - -#define COMBOBOXKEY @"cbitem" -static NSString *comboboxKey = COMBOBOXKEY; -static NSString *comboboxKeyPath = @"arrangedObjects." COMBOBOXKEY; - -id makeCombobox(BOOL editable) -{ - combobox *c; - - c = [combobox new]; - c->pb = nil; - c->cb = nil; - c->ac = makeListboxArray(); -#define BIND bind:@"contentValues" toObject:c->ac withKeyPath:comboboxKeyPath options:nil - if (!editable) { - c->pb = [[NSPopUpButton alloc] - initWithFrame:dummyRect - pullsDown:NO]; - [c->pb BIND]; - } else { - c->cb = [[NSComboBox alloc] - initWithFrame:dummyRect]; - [c->cb setUsesDataSource:NO]; - [c->cb BIND]; - } - return c; -} - -void addCombobox(id parentWindow, id cbox) -{ - combobox *c; - - c = tocombobox(cbox); - if (c->pb != nil) { - addControl(parentWindow, c->pb); - return; - } - addControl(parentWindow, c->cb); -} - -id comboboxText(id cbox, BOOL editable) -{ - combobox *c; - - c = tocombobox(cbox); - if (!editable) - return [c->pb titleOfSelectedItem]; - return [c->cb stringValue]; -} - -void comboboxAppend(id cbox, BOOL editable, id str) -{ - combobox *c; - - c = tocombobox(cbox); - listboxArrayAppend(c->ac, toListboxItem(comboboxKey, str)); -} - -void comboboxInsertBefore(id cbox, BOOL editable, id str, intptr_t before) -{ - combobox *c; - - c = tocombobox(cbox); - listboxArrayInsertBefore(c->ac, toListboxItem(comboboxKey, str), before); -} - -intptr_t comboboxSelectedIndex(id cbox) -{ - combobox *c; - - c = tocombobox(cbox); - if (c->pb != nil) - return fromNSInteger([c->pb indexOfSelectedItem]); - return fromNSInteger([c->cb indexOfSelectedItem]); -} - -void comboboxDelete(id cbox, intptr_t index) -{ - combobox *c; - - c = tocombobox(cbox); - listboxArrayDelete(c->ac, index); -} - -intptr_t comboboxLen(id cbox) -{ - combobox *c; - - c = tocombobox(cbox); - if (c->pb != nil) - return fromNSInteger([c->pb numberOfItems]); - return fromNSInteger([c->cb numberOfItems]); -} diff --git a/objc_darwin.h b/objc_darwin.h index 4b084ee..dca3faa 100644 --- a/objc_darwin.h +++ b/objc_darwin.h @@ -103,13 +103,6 @@ extern void buttonSetTargetAction(id, id); extern void buttonSetText(id, id); extern id buttonText(id); extern id makeCheckbox(void); -extern id makeCombobox(BOOL); -extern id comboboxText(id, BOOL); -extern void comboboxAppend(id, BOOL, id); -extern void comboboxInsertBefore(id, BOOL, id, intptr_t); -extern intptr_t comboboxSelectedIndex(id); -extern void comboboxDelete(id, intptr_t); -extern intptr_t comboboxLen(id); extern void comboboxSelectIndex(id, BOOL, intptr_t); extern id makeLineEdit(BOOL); extern void lineeditSetText(id, id); @@ -122,4 +115,13 @@ extern void windowSetContentSize(id, intptr_t, intptr_t); extern void setProgress(id, intptr_t); extern void setAreaSize(id, intptr_t, intptr_t); +/* combobox_darwin.m */ +extern id makeCombobox(BOOL); +extern id comboboxText(id, BOOL); +extern void comboboxAppend(id, BOOL, id); +extern void comboboxInsertBefore(id, BOOL, id, intptr_t); +extern intptr_t comboboxSelectedIndex(id); +extern void comboboxDelete(id, intptr_t); +extern intptr_t comboboxLen(id); + #endif diff --git a/sysdata_darwin.m b/sysdata_darwin.m index 207cee8..e4ad6f6 100644 --- a/sysdata_darwin.m +++ b/sysdata_darwin.m @@ -25,8 +25,6 @@ #import #import #import -#import -#import #import #import #import @@ -39,8 +37,6 @@ extern NSRect dummyRect; #define toNSView(x) to(NSView, (x)) #define toNSControl(x) to(NSControl, (x)) #define toNSButton(x) to(NSButton, (x)) -#define toNSPopUpButton(x) to(NSPopUpButton, (x)) -#define toNSComboBox(x) to(NSComboBox, (x)) #define toNSTextField(x) to(NSTextField, (x)) #define toNSProgressIndicator(x) to(NSProgressIndicator, (x)) #define toNSScrollView(x) to(NSScrollView, (x)) @@ -143,89 +139,9 @@ id makeCheckbox(void) return checkbox; } -id makeCombobox(BOOL editable) -{ - if (!editable) { - NSPopUpButton *combobox; - - combobox = [[NSPopUpButton alloc] - initWithFrame:dummyRect - pullsDown:NO]; - return combobox; - } - - NSComboBox *combobox; - - combobox = [[NSComboBox alloc] - initWithFrame:dummyRect]; - [combobox setUsesDataSource:NO]; - return combobox; -} - -id comboboxText(id combobox, BOOL editable) -{ - if (!editable) - return [toNSPopUpButton(combobox) titleOfSelectedItem]; - return [toNSComboBox(combobox) stringValue]; -} - -void comboboxAppend(id combobox, BOOL editable, id str) -{ - if (!editable) { - [toNSPopUpButton(combobox) addItemWithTitle:str]; - return; - } - [toNSComboBox(combobox) addItemWithObjectValue:str]; -} - -void comboboxInsertBefore(id combobox, BOOL editable, id str, intptr_t before) -{ - if (!editable) { - [toNSPopUpButton(combobox) insertItemWithTitle:str atIndex:toNSInteger(before)]; - return; - } - [toNSComboBox(combobox) insertItemWithObjectValue:str atIndex:toNSInteger(before)]; -} - -intptr_t comboboxSelectedIndex(id combobox) -{ - // works the same for both NSPopUpButton and NSComboBox - return fromNSInteger([toNSPopUpButton(combobox) indexOfSelectedItem]); -} - -void comboboxDelete(id combobox, intptr_t index) -{ - // works the same for both NSPopUpButton and NSComboBox - [toNSPopUpButton(combobox) removeItemAtIndex:toNSInteger(index)]; -} - -intptr_t comboboxLen(id combobox) -{ - // works the same for both NSPopUpButton and NSComboBox - return fromNSInteger([toNSPopUpButton(combobox) numberOfItems]); -} - void comboboxSelectIndex(id combobox, BOOL editable, intptr_t index) { - NSInteger i; - NSInteger selected; - NSComboBox *c; - - i = toNSInteger(index); - // NSPopUpButton documents -1 as deselecting, so we can just use selectItemAtindex: directly - if (!editable) { - [toNSPopUpButton(combobox) selectItemAtIndex:i]; - return; - } - // NSComboBox, on the other hand, does not, so to be safe, we do things the long way - c = toNSComboBox(combobox); - if (i == -1) { // deselect - selected = [c indexOfSelectedItem]; - if (selected != -1) - [c deselectItemAtIndex:selected]; - return; - } - [c selectItemAtIndex:i]; + // TODO remove } id makeLineEdit(BOOL password)