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...

This commit is contained in:
Pietro Gagliardi 2014-05-28 23:46:33 -04:00
parent e3edc7e0c3
commit 4baa9397e6
4 changed files with 132 additions and 248 deletions

122
combobox_darwin.m Normal file
View File

@ -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 <AppKit/NSArrayController.h>
#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 <AppKit/NSApplication.h>
#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 <AppKit/NSPopUpButton.h>
#import <AppKit/NSComboBox.h>
#import <AppKit/NSArrayController.h>
/*
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]);
}

View File

@ -1,156 +0,0 @@
// 17 may 2014
#include "objc_darwin.h"
#include <AppKit/NSPopUpButton.h>
#include <AppKit/NSComboBox.h>
#include <AppKit/NSArrayController.h>
/*
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]);
}

View File

@ -103,13 +103,6 @@ extern void buttonSetTargetAction(id, id);
extern void buttonSetText(id, id); extern void buttonSetText(id, id);
extern id buttonText(id); extern id buttonText(id);
extern id makeCheckbox(void); 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 void comboboxSelectIndex(id, BOOL, intptr_t);
extern id makeLineEdit(BOOL); extern id makeLineEdit(BOOL);
extern void lineeditSetText(id, id); 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 setProgress(id, intptr_t);
extern void setAreaSize(id, intptr_t, 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 #endif

View File

@ -25,8 +25,6 @@
#import <AppKit/NSFont.h> #import <AppKit/NSFont.h>
#import <AppKit/NSControl.h> #import <AppKit/NSControl.h>
#import <AppKit/NSButton.h> #import <AppKit/NSButton.h>
#import <AppKit/NSPopUpButton.h>
#import <AppKit/NSComboBox.h>
#import <AppKit/NSTextField.h> #import <AppKit/NSTextField.h>
#import <AppKit/NSSecureTextField.h> #import <AppKit/NSSecureTextField.h>
#import <AppKit/NSProgressIndicator.h> #import <AppKit/NSProgressIndicator.h>
@ -39,8 +37,6 @@ extern NSRect dummyRect;
#define toNSView(x) to(NSView, (x)) #define toNSView(x) to(NSView, (x))
#define toNSControl(x) to(NSControl, (x)) #define toNSControl(x) to(NSControl, (x))
#define toNSButton(x) to(NSButton, (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 toNSTextField(x) to(NSTextField, (x))
#define toNSProgressIndicator(x) to(NSProgressIndicator, (x)) #define toNSProgressIndicator(x) to(NSProgressIndicator, (x))
#define toNSScrollView(x) to(NSScrollView, (x)) #define toNSScrollView(x) to(NSScrollView, (x))
@ -143,89 +139,9 @@ id makeCheckbox(void)
return checkbox; 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) void comboboxSelectIndex(id combobox, BOOL editable, intptr_t index)
{ {
NSInteger i; // TODO remove
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];
} }
id makeLineEdit(BOOL password) id makeLineEdit(BOOL password)