1 /*
2 * Copyright (c) 2004-2010 Hypertriton, Inc. <http://hypertriton.com/>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23 * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include <agar/core/core.h>
27 #include <agar/gui/toolbar.h>
28 #include <agar/gui/window.h>
29 #include <agar/gui/primitive.h>
30 #include <agar/gui/separator.h>
31
32 AG_Toolbar *
AG_ToolbarNew(void * parent,enum ag_toolbar_type type,int nRows,Uint flags)33 AG_ToolbarNew(void *parent, enum ag_toolbar_type type, int nRows, Uint flags)
34 {
35 AG_Toolbar *bar;
36 int i;
37
38 bar = Malloc(sizeof(AG_Toolbar));
39 AG_ObjectInit(bar, &agToolbarClass);
40 bar->flags |= flags;
41 bar->type = type;
42
43 for (i = 0; i < nRows && i < AG_TOOLBAR_MAX_ROWS; i++) {
44 int bflags = 0;
45
46 if (flags & AG_TOOLBAR_HOMOGENOUS) {
47 bflags = AG_BOX_HOMOGENOUS;
48 }
49 switch (type) {
50 case AG_TOOLBAR_HORIZ:
51 bar->rows[i] = AG_BoxNew(bar, AG_BOX_HORIZ, bflags);
52 break;
53 case AG_TOOLBAR_VERT:
54 bar->rows[i] = AG_BoxNew(bar, AG_BOX_VERT, bflags);
55 break;
56 }
57 if (flags & AG_TOOLBAR_HFILL) { AG_ExpandHoriz(bar->rows[i]); }
58 if (flags & AG_TOOLBAR_VFILL) { AG_ExpandVert(bar->rows[i]); }
59 AG_BoxSetPadding(bar->rows[i], 1);
60 AG_BoxSetSpacing(bar->rows[i], 1);
61 bar->nRows++;
62 }
63 AG_BoxSetPadding(AGBOX(bar), 0);
64 AG_BoxSetSpacing(AGBOX(bar), 1);
65 AG_ObjectAttach(parent, bar);
66 return (bar);
67 }
68
69 static void
Init(void * obj)70 Init(void *obj)
71 {
72 AG_Toolbar *bar = obj;
73
74 WIDGET(bar)->flags |= AG_WIDGET_NOSPACING;
75
76 bar->flags = 0;
77 bar->type = AG_TOOLBAR_HORIZ;
78 bar->nRows = 0;
79 bar->curRow = 0;
80 bar->nButtons = 0;
81 }
82
83 static void
StickyUpdate(AG_Event * event)84 StickyUpdate(AG_Event *event)
85 {
86 AG_Button *selBtn = AG_SELF();
87 AG_Toolbar *bar = AG_PTR(1);
88 AG_Variable *stateb;
89 AG_Button *oBtn;
90 int i;
91
92 AG_ObjectLock(bar);
93 for (i = 0; i < bar->nRows; i++) {
94 OBJECT_FOREACH_CHILD(oBtn, bar->rows[i], ag_button) {
95 int *state;
96
97 stateb = AG_GetVariable(oBtn, "state", &state);
98 if (bar->flags & AG_TOOLBAR_MULTI_STICKY) {
99 *state = !(*state);
100 } else {
101 *state = (oBtn == selBtn);
102 }
103 AG_UnlockVariable(stateb);
104 }
105 }
106 AG_ObjectUnlock(bar);
107 }
108
109 void
AG_ToolbarRow(AG_Toolbar * bar,int row)110 AG_ToolbarRow(AG_Toolbar *bar, int row)
111 {
112 AG_ObjectLock(bar);
113 #ifdef AG_DEBUG
114 if (row < 0 || row >= bar->nRows)
115 AG_FatalError("no such row %d", row);
116 #endif
117 bar->curRow = row;
118 AG_ObjectUnlock(bar);
119 }
120
121 AG_Button *
AG_ToolbarButtonIcon(AG_Toolbar * bar,AG_Surface * icon,int def,void (* handler)(AG_Event *),const char * fmt,...)122 AG_ToolbarButtonIcon(AG_Toolbar *bar, AG_Surface *icon, int def,
123 void (*handler)(AG_Event *), const char *fmt, ...)
124 {
125 AG_Button *bu;
126 AG_Event *ev;
127
128 AG_ObjectLock(bar);
129
130 bu = AG_ButtonNewS(bar->rows[bar->curRow], 0, NULL);
131 AG_ButtonSurface(bu, icon);
132 AG_ButtonSetFocusable(bu, 0);
133 AG_ButtonSetSticky(bu, bar->flags & AG_TOOLBAR_STICKY);
134 AG_SetInt(bu, "state", def);
135 bar->nButtons++;
136
137 ev = AG_SetEvent(bu, "button-pushed", handler, NULL);
138 AG_EVENT_GET_ARGS(ev, fmt);
139
140 if (bar->flags & (AG_TOOLBAR_STICKY|AG_TOOLBAR_MULTI_STICKY)) {
141 AG_AddEvent(bu, "button-pushed", StickyUpdate, "%p", bar);
142 }
143
144 AG_ObjectUnlock(bar);
145 AG_Redraw(bar);
146 return (bu);
147 }
148
149 AG_Button *
AG_ToolbarButton(AG_Toolbar * bar,const char * text,int def,void (* handler)(AG_Event *),const char * fmt,...)150 AG_ToolbarButton(AG_Toolbar *bar, const char *text, int def,
151 void (*handler)(AG_Event *), const char *fmt, ...)
152 {
153 AG_Button *bu;
154 AG_Event *ev;
155
156 AG_ObjectLock(bar);
157
158 bu = AG_ButtonNewS(bar->rows[bar->curRow], 0, text);
159 AG_ButtonSetFocusable(bu, 0);
160 AG_ButtonSetSticky(bu, bar->flags & AG_TOOLBAR_STICKY);
161 AG_SetInt(bu, "state", def);
162 bar->nButtons++;
163
164 ev = AG_SetEvent(bu, "button-pushed", handler, NULL);
165 AG_EVENT_GET_ARGS(ev, fmt);
166
167 if (bar->flags & (AG_TOOLBAR_STICKY|AG_TOOLBAR_MULTI_STICKY)) {
168 AG_AddEvent(bu, "button-pushed", StickyUpdate, "%p", bar);
169 }
170
171 AG_ObjectUnlock(bar);
172 AG_Redraw(bar);
173 return (bu);
174 }
175
176 void
AG_ToolbarSeparator(AG_Toolbar * bar)177 AG_ToolbarSeparator(AG_Toolbar *bar)
178 {
179 AG_ObjectLock(bar);
180 AG_SeparatorNew(bar->rows[bar->curRow],
181 (bar->type == AG_TOOLBAR_HORIZ) ?
182 AG_SEPARATOR_VERT : AG_SEPARATOR_HORIZ);
183 AG_ObjectUnlock(bar);
184 AG_Redraw(bar);
185 }
186
187 void
AG_ToolbarSelect(AG_Toolbar * bar,AG_Button * bSel)188 AG_ToolbarSelect(AG_Toolbar *bar, AG_Button *bSel)
189 {
190 AG_SetInt(bSel, "state", 1);
191 AG_Redraw(bar);
192 }
193
194 void
AG_ToolbarDeselect(AG_Toolbar * bar,AG_Button * bSel)195 AG_ToolbarDeselect(AG_Toolbar *bar, AG_Button *bSel)
196 {
197 AG_SetInt(bSel, "state", 0);
198 AG_Redraw(bar);
199 }
200
201 void
AG_ToolbarSelectOnly(AG_Toolbar * bar,AG_Button * bSel)202 AG_ToolbarSelectOnly(AG_Toolbar *bar, AG_Button *bSel)
203 {
204 AG_Variable *stateb;
205 AG_Button *b;
206 int i, *state;
207
208 AG_ObjectLock(bar);
209 for (i = 0; i < bar->nRows; i++) {
210 OBJECT_FOREACH_CHILD(b, bar->rows[i], ag_button) {
211 stateb = AG_GetVariable(b, "state", &state);
212 *state = (b == bSel);
213 AG_UnlockVariable(stateb);
214 }
215 }
216 AG_ObjectUnlock(bar);
217 AG_Redraw(bar);
218 }
219
220 void
AG_ToolbarSelectAll(AG_Toolbar * bar)221 AG_ToolbarSelectAll(AG_Toolbar *bar)
222 {
223 AG_Variable *stateb;
224 AG_Button *b;
225 int i, *state;
226
227 AG_ObjectLock(bar);
228 for (i = 0; i < bar->nRows; i++) {
229 OBJECT_FOREACH_CHILD(b, bar->rows[i], ag_button) {
230 stateb = AG_GetVariable(b, "state", &state);
231 *state = 1;
232 AG_UnlockVariable(stateb);
233 }
234 }
235 AG_ObjectUnlock(bar);
236 AG_Redraw(bar);
237 }
238
239 void
AG_ToolbarDeselectAll(AG_Toolbar * bar)240 AG_ToolbarDeselectAll(AG_Toolbar *bar)
241 {
242 AG_Variable *stateb;
243 AG_Button *b;
244 int i, *state;
245
246 AG_ObjectLock(bar);
247 for (i = 0; i < bar->nRows; i++) {
248 OBJECT_FOREACH_CHILD(b, bar->rows[i], ag_button) {
249 stateb = AG_GetVariable(b, "state", &state);
250 *state = 0;
251 AG_UnlockVariable(stateb);
252 }
253 }
254 AG_ObjectUnlock(bar);
255 AG_Redraw(bar);
256 }
257
258 static void
SizeRequest(void * p,AG_SizeReq * r)259 SizeRequest(void *p, AG_SizeReq *r)
260 {
261 AG_Toolbar *tbar = p;
262 AG_SizeReq rBar;
263 int i;
264
265 WIDGET_SUPER_OPS(tbar)->size_request(tbar, r);
266
267 rBar = *r;
268 rBar.h = (tbar->type == AG_TOOLBAR_HORIZ) ? r->h/tbar->nRows :
269 r->w/tbar->nRows;
270 for (i = 0; i < tbar->nRows; i++)
271 WIDGET_SUPER_OPS(tbar)->size_request(tbar->rows[i], &rBar);
272 }
273
274 AG_WidgetClass agToolbarClass = {
275 {
276 "Agar(Widget:Box:Toolbar)",
277 sizeof(AG_Toolbar),
278 { 0,0 },
279 Init,
280 NULL, /* free */
281 NULL, /* destroy */
282 NULL, /* load */
283 NULL, /* save */
284 NULL /* edit */
285 },
286 AG_WidgetInheritDraw,
287 SizeRequest,
288 AG_WidgetInheritSizeAllocate
289 };
290