2015-08-14 22:50:38 -05:00
|
|
|
// 14 august 2015
|
|
|
|
#import "uipriv_darwin.h"
|
|
|
|
|
2016-05-21 01:00:08 -05:00
|
|
|
// In the old days you would use a NSMatrix for this; as of OS X 10.8 this was deprecated and now you need just a bunch of NSButtons with the same superview AND same action method.
|
|
|
|
// This is documented on the NSMatrix page, but the rest of the OS X documentation says to still use NSMatrix.
|
|
|
|
// NSMatrix has weird quirks anyway...
|
|
|
|
|
2016-05-28 20:17:54 -05:00
|
|
|
// LONGTERM 6 units of spacing between buttons, as suggested by Interface Builder?
|
2015-08-22 20:39:12 -05:00
|
|
|
|
2016-06-06 19:12:17 -05:00
|
|
|
@interface radioButtonsDelegate : NSObject {
|
|
|
|
uiRadioButtons *libui_r;
|
|
|
|
}
|
|
|
|
- (id)initWithR:(uiRadioButtons *)r;
|
|
|
|
- (IBAction)onClicked:(id)sender;
|
|
|
|
@end
|
|
|
|
|
2015-08-14 22:50:38 -05:00
|
|
|
struct uiRadioButtons {
|
|
|
|
uiDarwinControl c;
|
2016-05-21 01:00:08 -05:00
|
|
|
NSView *view;
|
|
|
|
NSMutableArray *buttons;
|
|
|
|
NSMutableArray *constraints;
|
|
|
|
NSLayoutConstraint *lastv;
|
2016-06-06 19:12:17 -05:00
|
|
|
radioButtonsDelegate *delegate;
|
|
|
|
void (*onSelected)(uiRadioButtons *, void *);
|
|
|
|
void *onSelectedData;
|
2015-08-14 22:50:38 -05:00
|
|
|
};
|
|
|
|
|
2016-06-06 19:12:17 -05:00
|
|
|
@implementation radioButtonsDelegate
|
|
|
|
|
|
|
|
- (id)initWithR:(uiRadioButtons *)r
|
|
|
|
{
|
|
|
|
self = [super init];
|
|
|
|
if (self)
|
|
|
|
self->libui_r = r;
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (IBAction)onClicked:(id)sender
|
|
|
|
{
|
|
|
|
uiRadioButtons *r = self->libui_r;
|
|
|
|
|
|
|
|
(*(r->onSelected))(r, r->onSelectedData);
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2016-05-21 01:00:08 -05:00
|
|
|
uiDarwinControlAllDefaultsExceptDestroy(uiRadioButtons, view)
|
|
|
|
|
2016-06-06 19:12:17 -05:00
|
|
|
static void defaultOnSelected(uiRadioButtons *r, void *data)
|
|
|
|
{
|
|
|
|
// do nothing
|
|
|
|
}
|
|
|
|
|
2016-05-21 01:00:08 -05:00
|
|
|
static void uiRadioButtonsDestroy(uiControl *c)
|
|
|
|
{
|
|
|
|
uiRadioButtons *r = uiRadioButtons(c);
|
|
|
|
NSButton *b;
|
|
|
|
|
|
|
|
// drop the constraints
|
|
|
|
[r->view removeConstraints:r->constraints];
|
|
|
|
[r->constraints release];
|
|
|
|
if (r->lastv != nil)
|
|
|
|
[r->lastv release];
|
|
|
|
// destroy the buttons
|
2016-06-06 19:12:17 -05:00
|
|
|
for (b in r->buttons) {
|
|
|
|
[b setTarget:nil];
|
2016-05-21 01:00:08 -05:00
|
|
|
[b removeFromSuperview];
|
2016-06-06 19:12:17 -05:00
|
|
|
}
|
2016-05-21 01:00:08 -05:00
|
|
|
[r->buttons release];
|
2016-06-06 19:12:17 -05:00
|
|
|
// destroy the delegate
|
|
|
|
[r->delegate release];
|
2016-05-21 01:00:08 -05:00
|
|
|
// and destroy ourselves
|
|
|
|
[r->view release];
|
|
|
|
uiFreeControl(uiControl(r));
|
|
|
|
}
|
2015-08-14 22:50:38 -05:00
|
|
|
|
2016-05-21 01:00:08 -05:00
|
|
|
static NSButton *buttonAt(uiRadioButtons *r, uintmax_t n)
|
2015-08-22 14:12:48 -05:00
|
|
|
{
|
2016-05-21 01:00:08 -05:00
|
|
|
return (NSButton *) [r->buttons objectAtIndex:n];
|
2015-08-22 14:12:48 -05:00
|
|
|
}
|
|
|
|
|
2015-08-14 22:50:38 -05:00
|
|
|
void uiRadioButtonsAppend(uiRadioButtons *r, const char *text)
|
|
|
|
{
|
2016-05-21 01:00:08 -05:00
|
|
|
NSButton *b, *b2;
|
|
|
|
NSLayoutConstraint *constraint;
|
|
|
|
|
|
|
|
b = [[NSButton alloc] initWithFrame:NSZeroRect];
|
|
|
|
[b setTitle:toNSString(text)];
|
|
|
|
[b setButtonType:NSRadioButton];
|
2016-05-28 20:17:54 -05:00
|
|
|
// doesn't seem to have an associated bezel style
|
2016-05-21 01:00:08 -05:00
|
|
|
[b setBordered:NO];
|
2016-05-28 20:17:54 -05:00
|
|
|
[b setTransparent:NO];
|
2016-05-21 01:00:08 -05:00
|
|
|
uiDarwinSetControlFont(b, NSRegularControlSize);
|
|
|
|
[b setTranslatesAutoresizingMaskIntoConstraints:NO];
|
|
|
|
|
2016-06-06 19:12:17 -05:00
|
|
|
[b setTarget:r->delegate];
|
2016-05-21 01:00:08 -05:00
|
|
|
[b setAction:@selector(onClicked:)];
|
|
|
|
|
|
|
|
[r->buttons addObject:b];
|
|
|
|
[r->view addSubview:b];
|
2015-08-22 16:21:27 -05:00
|
|
|
|
2016-05-21 01:00:08 -05:00
|
|
|
// pin horizontally to the edges of the superview
|
|
|
|
constraint = mkConstraint(b, NSLayoutAttributeLeading,
|
|
|
|
NSLayoutRelationEqual,
|
|
|
|
r->view, NSLayoutAttributeLeading,
|
|
|
|
1, 0,
|
|
|
|
@"uiRadioButtons button leading constraint");
|
|
|
|
[r->view addConstraint:constraint];
|
|
|
|
[r->constraints addObject:constraint];
|
|
|
|
constraint = mkConstraint(b, NSLayoutAttributeTrailing,
|
|
|
|
NSLayoutRelationEqual,
|
|
|
|
r->view, NSLayoutAttributeTrailing,
|
|
|
|
1, 0,
|
|
|
|
@"uiRadioButtons button trailing constraint");
|
|
|
|
[r->view addConstraint:constraint];
|
|
|
|
[r->constraints addObject:constraint];
|
2015-08-22 20:39:12 -05:00
|
|
|
|
2016-05-21 01:00:08 -05:00
|
|
|
// if this is the first view, pin it to the top
|
|
|
|
// otherwise pin to the bottom of the last
|
|
|
|
if ([r->buttons count] == 1)
|
|
|
|
constraint = mkConstraint(b, NSLayoutAttributeTop,
|
|
|
|
NSLayoutRelationEqual,
|
|
|
|
r->view, NSLayoutAttributeTop,
|
|
|
|
1, 0,
|
|
|
|
@"uiRadioButtons first button top constraint");
|
|
|
|
else {
|
|
|
|
b2 = buttonAt(r, [r->buttons count] - 2);
|
|
|
|
constraint = mkConstraint(b, NSLayoutAttributeTop,
|
|
|
|
NSLayoutRelationEqual,
|
|
|
|
b2, NSLayoutAttributeBottom,
|
|
|
|
1, 0,
|
|
|
|
@"uiRadioButtons non-first button top constraint");
|
|
|
|
}
|
|
|
|
[r->view addConstraint:constraint];
|
|
|
|
[r->constraints addObject:constraint];
|
2015-08-22 20:39:12 -05:00
|
|
|
|
2016-05-21 01:00:08 -05:00
|
|
|
// if there is a previous bottom constraint, remove it
|
|
|
|
if (r->lastv != nil) {
|
|
|
|
[r->view removeConstraint:r->lastv];
|
|
|
|
[r->constraints removeObject:r->lastv];
|
|
|
|
[r->lastv release];
|
|
|
|
}
|
2015-08-22 20:39:12 -05:00
|
|
|
|
2016-05-21 01:00:08 -05:00
|
|
|
// and make the new bottom constraint
|
|
|
|
r->lastv = mkConstraint(b, NSLayoutAttributeBottom,
|
|
|
|
NSLayoutRelationEqual,
|
|
|
|
r->view, NSLayoutAttributeBottom,
|
|
|
|
1, 0,
|
|
|
|
@"uiRadioButtons last button bottom constraint");
|
|
|
|
[r->view addConstraint:r->lastv];
|
|
|
|
[r->constraints addObject:r->lastv];
|
|
|
|
[r->lastv retain];
|
2015-08-14 22:50:38 -05:00
|
|
|
}
|
|
|
|
|
2016-06-06 19:12:17 -05:00
|
|
|
intmax_t uiRadioButtonsSelected(uiRadioButtons *r)
|
|
|
|
{
|
|
|
|
NSButton *b;
|
|
|
|
NSUInteger i;
|
|
|
|
|
|
|
|
for (i = 0; i < [r->buttons count]; i++) {
|
|
|
|
b = (NSButton *) [r->buttons objectAtIndex:i];
|
|
|
|
if ([b state] == NSOnState)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void uiRadioButtonsSetSelected(uiRadioButtons *r, intmax_t n)
|
|
|
|
{
|
|
|
|
NSButton *b;
|
|
|
|
NSInteger state;
|
|
|
|
|
|
|
|
state = NSOnState;
|
|
|
|
if (n == -1) {
|
|
|
|
n = uiRadioButtonsSelected(r);
|
|
|
|
if (n == -1) // from nothing to nothing; do nothing
|
|
|
|
return;
|
|
|
|
state = NSOffState;
|
|
|
|
}
|
|
|
|
b = (NSButton *) [r->buttons objectAtIndex:n];
|
|
|
|
[b setState:state];
|
|
|
|
}
|
|
|
|
|
|
|
|
void uiRadioButtonsOnSelected(uiRadioButtons *r, void (*f)(uiRadioButtons *, void *), void *data)
|
|
|
|
{
|
|
|
|
r->onSelected = f;
|
|
|
|
r->onSelectedData = data;
|
|
|
|
}
|
|
|
|
|
2015-08-14 22:50:38 -05:00
|
|
|
uiRadioButtons *uiNewRadioButtons(void)
|
|
|
|
{
|
|
|
|
uiRadioButtons *r;
|
|
|
|
|
2016-04-25 10:54:09 -05:00
|
|
|
uiDarwinNewControl(uiRadioButtons, r);
|
2015-08-14 22:50:38 -05:00
|
|
|
|
2016-05-21 01:00:08 -05:00
|
|
|
r->view = [[NSView alloc] initWithFrame:NSZeroRect];
|
|
|
|
r->buttons = [NSMutableArray new];
|
|
|
|
r->constraints = [NSMutableArray new];
|
2015-08-14 22:50:38 -05:00
|
|
|
|
2016-06-06 19:12:17 -05:00
|
|
|
r->delegate = [[radioButtonsDelegate alloc] initWithR:r];
|
|
|
|
|
|
|
|
uiRadioButtonsOnSelected(r, defaultOnSelected, NULL);
|
|
|
|
|
2015-08-14 22:50:38 -05:00
|
|
|
return r;
|
|
|
|
}
|