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