aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl/libui/darwin/radiobuttons.m
blob: 25d773c9720e251b49f26dd1036f995cd55ea9d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// 14 august 2015
#import "uipriv_darwin.h"

// TODO resizing the controlgallery vertically causes the third button to still resize :|

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

// LONGTERM 6 units of spacing between buttons, as suggested by Interface Builder?

@interface radioButtonsDelegate : NSObject {
	uiRadioButtons *libui_r;
}
- (id)initWithR:(uiRadioButtons *)r;
- (IBAction)onClicked:(id)sender;
@end

struct uiRadioButtons {
	uiDarwinControl c;
	NSView *view;
	NSMutableArray *buttons;
	NSMutableArray *constraints;
	NSLayoutConstraint *lastv;
	radioButtonsDelegate *delegate;
	void (*onSelected)(uiRadioButtons *, void *);
	void *onSelectedData;
};

@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

uiDarwinControlAllDefaultsExceptDestroy(uiRadioButtons, view)

static void defaultOnSelected(uiRadioButtons *r, void *data)
{
	// do nothing
}

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
	for (b in r->buttons) {
		[b setTarget:nil];
		[b removeFromSuperview];
	}
	[r->buttons release];
	// destroy the delegate
	[r->delegate release];
	// and destroy ourselves
	[r->view release];
	uiFreeControl(uiControl(r));
}

static NSButton *buttonAt(uiRadioButtons *r, int n)
{
	return (NSButton *) [r->buttons objectAtIndex:n];
}

void uiRadioButtonsAppend(uiRadioButtons *r, const char *text)
{
	NSButton *b, *b2;
	NSLayoutConstraint *constraint;

	b = [[NSButton alloc] initWithFrame:NSZeroRect];
	[b setTitle:toNSString(text)];
	[b setButtonType:NSRadioButton];
	// doesn't seem to have an associated bezel style
	[b setBordered:NO];
	[b setTransparent:NO];
	uiDarwinSetControlFont(b, NSRegularControlSize);
	[b setTranslatesAutoresizingMaskIntoConstraints:NO];

	[b setTarget:r->delegate];
	[b setAction:@selector(onClicked:)];

	[r->buttons addObject:b];
	[r->view addSubview:b];

	// 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];

	// 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];

	// 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];
	}

	// 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];
}

int 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, int 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;
}

uiRadioButtons *uiNewRadioButtons(void)
{
	uiRadioButtons *r;

	uiDarwinNewControl(uiRadioButtons, r);

	r->view = [[NSView alloc] initWithFrame:NSZeroRect];
	r->buttons = [NSMutableArray new];
	r->constraints = [NSMutableArray new];

	r->delegate = [[radioButtonsDelegate alloc] initWithR:r];

	uiRadioButtonsOnSelected(r, defaultOnSelected, NULL);

	return r;
}