1 /*
2 * Copyright (c) 2007-2012 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 #ifdef __NetBSD__
27 #define _NETBSD_SOURCE
28 #endif
29
30 #include <agar/core/core.h>
31 #include <agar/gui/numerical.h>
32 #include <agar/gui/primitive.h>
33
34 #include <string.h>
35
36 #include <agar/config/_mk_have_strtold.h>
37 #include <agar/config/_mk_have_strtoll.h>
38 #if defined(_MK_HAVE_STRTOLD_H) || defined(_MK_HAVE_STRTOLL_H)
39 # define _XOPEN_SOURCE 600
40 # include <stdlib.h>
41 #endif
42
43 static void UnitSelected(AG_Event *);
44
45 AG_Numerical *
AG_NumericalNew(void * parent,Uint flags,const char * unit,const char * fmt,...)46 AG_NumericalNew(void *parent, Uint flags, const char *unit, const char *fmt,
47 ...)
48 {
49 char s[AG_LABEL_MAX];
50 va_list ap;
51
52 if (fmt != NULL) {
53 va_start(ap, fmt);
54 Vsnprintf(s, sizeof(s), fmt, ap);
55 va_end(ap);
56 return AG_NumericalNewS(parent, flags, unit, s);
57 } else {
58 return AG_NumericalNewS(parent, flags, unit, NULL);
59 }
60 }
61
62 AG_Numerical *
AG_NumericalNewS(void * parent,Uint flags,const char * unit,const char * label)63 AG_NumericalNewS(void *parent, Uint flags, const char *unit, const char *label)
64 {
65 AG_Numerical *num;
66
67 num = Malloc(sizeof(AG_Numerical));
68 AG_ObjectInit(num, &agNumericalClass);
69
70 if (flags & AG_NUMERICAL_HFILL) { AG_ExpandHoriz(num); }
71 if (flags & AG_NUMERICAL_VFILL) { AG_ExpandVert(num); }
72 if (label != NULL) {
73 AG_TextboxSetLabelS(num->input, label);
74 }
75 if (unit != NULL) {
76 num->units = AG_UComboNew(num, 0);
77 AG_SetEvent(num->units, "ucombo-selected",
78 UnitSelected, "%p", num);
79 AG_NumericalSetUnitSystem(num, unit);
80 AG_WidgetSetFocusable(num->units, 0);
81 }
82
83 AG_ObjectAttach(parent, num);
84 return (num);
85 }
86
87 AG_Numerical *
AG_NumericalNewDbl(void * parent,Uint flags,const char * unit,const char * label,double * v)88 AG_NumericalNewDbl(void *parent, Uint flags, const char *unit, const char *label, double *v)
89 {
90 AG_Numerical *num;
91 num = AG_NumericalNewS(parent, flags, unit, label);
92 AG_BindDouble(num, "value", v);
93 return (num);
94 }
95 AG_Numerical *
AG_NumericalNewDblR(void * parent,Uint flags,const char * unit,const char * label,double * v,double min,double max)96 AG_NumericalNewDblR(void *parent, Uint flags, const char *unit, const char *label, double *v, double min, double max)
97 {
98 AG_Numerical *num;
99 num = AG_NumericalNewS(parent, flags, unit, label);
100 AG_BindDouble(num, "value", v);
101 AG_SetDouble(num, "min", min);
102 AG_SetDouble(num, "max", max);
103 return (num);
104 }
105
106 #ifdef HAVE_LONG_DOUBLE
107 AG_Numerical *
AG_NumericalNewLdbl(void * parent,Uint flags,const char * unit,const char * label,long double * v)108 AG_NumericalNewLdbl(void *parent, Uint flags, const char *unit, const char *label, long double *v)
109 {
110 AG_Numerical *num;
111 num = AG_NumericalNewS(parent, flags, unit, label);
112 AG_BindLongDouble(num, "value", v);
113 return (num);
114 }
115 AG_Numerical *
AG_NumericalNewLdblR(void * parent,Uint flags,const char * unit,const char * label,long double * v,long double min,long double max)116 AG_NumericalNewLdblR(void *parent, Uint flags, const char *unit, const char *label, long double *v, long double min, long double max)
117 {
118 AG_Numerical *num;
119 num = AG_NumericalNewS(parent, flags, unit, label);
120 AG_BindLongDouble(num, "value", v);
121 AG_SetLongDouble(num, "min", min);
122 AG_SetLongDouble(num, "max", max);
123 return (num);
124 }
125 #endif /* HAVE_LONG_DOUBLE */
126
127 AG_Numerical *
AG_NumericalNewFlt(void * parent,Uint flags,const char * unit,const char * label,float * v)128 AG_NumericalNewFlt(void *parent, Uint flags, const char *unit, const char *label, float *v)
129 {
130 AG_Numerical *num;
131 num = AG_NumericalNewS(parent, flags, unit, label);
132 AG_BindFloat(num, "value", v);
133 return (num);
134 }
135 AG_Numerical *
AG_NumericalNewFltR(void * parent,Uint flags,const char * unit,const char * label,float * v,float min,float max)136 AG_NumericalNewFltR(void *parent, Uint flags, const char *unit, const char *label, float *v, float min, float max)
137 {
138 AG_Numerical *num;
139 num = AG_NumericalNewS(parent, flags, unit, label);
140 AG_BindFloat(num, "value", v);
141 AG_SetFloat(num, "min", min);
142 AG_SetFloat(num, "max", max);
143 return (num);
144 }
145
146 AG_Numerical *
AG_NumericalNewInt(void * parent,Uint flags,const char * unit,const char * label,int * v)147 AG_NumericalNewInt(void *parent, Uint flags, const char *unit, const char *label, int *v)
148 {
149 AG_Numerical *num;
150 num = AG_NumericalNewS(parent, flags, unit, label);
151 AG_BindInt(num, "value", v);
152 return (num);
153 }
154 AG_Numerical *
AG_NumericalNewIntR(void * parent,Uint flags,const char * unit,const char * label,int * v,int min,int max)155 AG_NumericalNewIntR(void *parent, Uint flags, const char *unit, const char *label, int *v, int min, int max)
156 {
157 AG_Numerical *num;
158 num = AG_NumericalNewS(parent, flags, unit, label);
159 AG_BindInt(num, "value", v);
160 AG_SetInt(num, "min", min);
161 AG_SetInt(num, "max", max);
162 return (num);
163 }
164 AG_Numerical *
AG_NumericalNewUint(void * parent,Uint flags,const char * unit,const char * label,Uint * v)165 AG_NumericalNewUint(void *parent, Uint flags, const char *unit, const char *label, Uint *v)
166 {
167 AG_Numerical *num;
168 num = AG_NumericalNewS(parent, flags, unit, label);
169 AG_BindUint(num, "value", v);
170 return (num);
171 }
172 AG_Numerical *
AG_NumericalNewUintR(void * parent,Uint flags,const char * unit,const char * label,Uint * v,Uint min,Uint max)173 AG_NumericalNewUintR(void *parent, Uint flags, const char *unit, const char *label, Uint *v, Uint min, Uint max)
174 {
175 AG_Numerical *num;
176 num = AG_NumericalNewS(parent, flags, unit, label);
177 AG_BindUint(num, "value", v);
178 AG_SetUint(num, "min", min);
179 AG_SetUint(num, "max", max);
180 return (num);
181 }
182
183 #ifdef AG_LEGACY
184
185 AG_Numerical *
AG_NumericalNewUint8(void * parent,Uint flags,const char * unit,const char * label,Uint8 * v)186 AG_NumericalNewUint8(void *parent, Uint flags, const char *unit, const char *label, Uint8 *v)
187 {
188 AG_Numerical *num;
189 num = AG_NumericalNewS(parent, flags, unit, label);
190 AG_BindUint8(num, "value", v);
191 return (num);
192 }
193 AG_Numerical *
AG_NumericalNewUint8R(void * parent,Uint flags,const char * unit,const char * label,Uint8 * v,Uint8 min,Uint8 max)194 AG_NumericalNewUint8R(void *parent, Uint flags, const char *unit, const char *label, Uint8 *v, Uint8 min, Uint8 max)
195 {
196 AG_Numerical *num;
197 num = AG_NumericalNewS(parent, flags, unit, label);
198 AG_BindUint8(num, "value", v);
199 AG_SetUint8(num, "min", min);
200 AG_SetUint8(num, "max", max);
201 return (num);
202 }
203 AG_Numerical *
AG_NumericalNewSint8(void * parent,Uint flags,const char * unit,const char * label,Sint8 * v)204 AG_NumericalNewSint8(void *parent, Uint flags, const char *unit, const char *label, Sint8 *v)
205 {
206 AG_Numerical *num;
207 num = AG_NumericalNewS(parent, flags, unit, label);
208 AG_BindSint8(num, "value", v);
209 return (num);
210 }
211 AG_Numerical *
AG_NumericalNewSint8R(void * parent,Uint flags,const char * unit,const char * label,Sint8 * v,Sint8 min,Sint8 max)212 AG_NumericalNewSint8R(void *parent, Uint flags, const char *unit, const char *label, Sint8 *v, Sint8 min, Sint8 max)
213 {
214 AG_Numerical *num;
215 num = AG_NumericalNewS(parent, flags, unit, label);
216 AG_BindSint8(num, "value", v);
217 AG_SetSint8(num, "min", min);
218 AG_SetSint8(num, "max", max);
219 return (num);
220 }
221 AG_Numerical *
AG_NumericalNewUint16(void * parent,Uint flags,const char * unit,const char * label,Uint16 * v)222 AG_NumericalNewUint16(void *parent, Uint flags, const char *unit, const char *label, Uint16 *v)
223 {
224 AG_Numerical *num;
225 num = AG_NumericalNewS(parent, flags, unit, label);
226 AG_BindUint16(num, "value", v);
227 return (num);
228 }
229 AG_Numerical *
AG_NumericalNewUint16R(void * parent,Uint flags,const char * unit,const char * label,Uint16 * v,Uint16 min,Uint16 max)230 AG_NumericalNewUint16R(void *parent, Uint flags, const char *unit, const char *label, Uint16 *v, Uint16 min, Uint16 max)
231 {
232 AG_Numerical *num;
233 num = AG_NumericalNewS(parent, flags, unit, label);
234 AG_BindUint16(num, "value", v);
235 AG_SetUint16(num, "min", min);
236 AG_SetUint16(num, "max", max);
237 return (num);
238 }
239 AG_Numerical *
AG_NumericalNewSint16(void * parent,Uint flags,const char * unit,const char * label,Sint16 * v)240 AG_NumericalNewSint16(void *parent, Uint flags, const char *unit, const char *label, Sint16 *v)
241 {
242 AG_Numerical *num;
243 num = AG_NumericalNewS(parent, flags, unit, label);
244 AG_BindSint16(num, "value", v);
245 return (num);
246 }
247 AG_Numerical *
AG_NumericalNewSint16R(void * parent,Uint flags,const char * unit,const char * label,Sint16 * v,Sint16 min,Sint16 max)248 AG_NumericalNewSint16R(void *parent, Uint flags, const char *unit, const char *label, Sint16 *v, Sint16 min, Sint16 max)
249 {
250 AG_Numerical *num;
251 num = AG_NumericalNewS(parent, flags, unit, label);
252 AG_BindSint16(num, "value", v);
253 AG_SetSint16(num, "min", min);
254 AG_SetSint16(num, "max", max);
255 return (num);
256 }
257 AG_Numerical *
AG_NumericalNewUint32(void * parent,Uint flags,const char * unit,const char * label,Uint32 * v)258 AG_NumericalNewUint32(void *parent, Uint flags, const char *unit, const char *label, Uint32 *v)
259 {
260 AG_Numerical *num;
261 num = AG_NumericalNewS(parent, flags, unit, label);
262 AG_BindUint32(num, "value", v);
263 return (num);
264 }
265 AG_Numerical *
AG_NumericalNewUint32R(void * parent,Uint flags,const char * unit,const char * label,Uint32 * v,Uint32 min,Uint32 max)266 AG_NumericalNewUint32R(void *parent, Uint flags, const char *unit, const char *label, Uint32 *v, Uint32 min, Uint32 max)
267 {
268 AG_Numerical *num;
269 num = AG_NumericalNewS(parent, flags, unit, label);
270 AG_BindUint32(num, "value", v);
271 AG_SetUint32(num, "min", min);
272 AG_SetUint32(num, "max", max);
273 return (num);
274 }
275 AG_Numerical *
AG_NumericalNewSint32(void * parent,Uint flags,const char * unit,const char * label,Sint32 * v)276 AG_NumericalNewSint32(void *parent, Uint flags, const char *unit, const char *label, Sint32 *v)
277 {
278 AG_Numerical *num;
279 num = AG_NumericalNewS(parent, flags, unit, label);
280 AG_BindSint32(num, "value", v);
281 return (num);
282 }
283 AG_Numerical *
AG_NumericalNewSint32R(void * parent,Uint flags,const char * unit,const char * label,Sint32 * v,Sint32 min,Sint32 max)284 AG_NumericalNewSint32R(void *parent, Uint flags, const char *unit, const char *label, Sint32 *v, Sint32 min, Sint32 max)
285 {
286 AG_Numerical *num;
287 num = AG_NumericalNewS(parent, flags, unit, label);
288 AG_BindSint32(num, "value", v);
289 AG_SetSint32(num, "min", min);
290 AG_SetSint32(num, "max", max);
291 return (num);
292 }
293 #endif /* AG_LEGACY */
294
295 static Uint32
UpdateTimeout(AG_Timer * to,AG_Event * event)296 UpdateTimeout(AG_Timer *to, AG_Event *event)
297 {
298 AG_Numerical *num = AG_SELF();
299
300 if (!AG_WidgetIsFocused(num)) {
301 AG_NumericalUpdate(num);
302 }
303 return (to->ival);
304 }
305
306 #undef SET_DEF
307 #define SET_DEF(fn,dmin,dmax,dinc) { \
308 if (!AG_Defined(num, "min")) { fn(num, "min", dmin); } \
309 if (!AG_Defined(num, "max")) { fn(num, "max", dmax); } \
310 if (!AG_Defined(num, "inc")) { fn(num, "inc", dinc); } \
311 }
312 static void
OnShow(AG_Event * event)313 OnShow(AG_Event *event)
314 {
315 AG_Numerical *num = AG_SELF();
316 AG_Variable *V;
317
318 if ((num->flags & AG_NUMERICAL_EXCL) == 0) {
319 AG_AddTimer(num, &num->updateTo, 250, UpdateTimeout, NULL);
320 }
321 if ((V = AG_GetVariableLocked(num, "value")) == NULL) {
322 if (num->flags & AG_NUMERICAL_INT) {
323 V = AG_SetInt(num, "value", 0);
324 } else {
325 V = AG_SetDouble(num, "value", 0.0);
326 }
327 if (V == NULL) {
328 return;
329 }
330 AG_LockVariable(V);
331 }
332 switch (AG_VARIABLE_TYPE(V)) {
333 case AG_VARIABLE_FLOAT: SET_DEF(AG_SetFloat, -AG_FLT_MAX, AG_FLT_MAX, 0.1f); break;
334 case AG_VARIABLE_DOUBLE: SET_DEF(AG_SetDouble, -AG_DBL_MAX, AG_DBL_MAX, 0.1); break;
335 #ifdef HAVE_LONG_DOUBLE
336 case AG_VARIABLE_LONG_DOUBLE: SET_DEF(AG_SetLongDouble, -AG_LDBL_MAX, AG_LDBL_MAX, 0.1l); break;
337 #endif
338 case AG_VARIABLE_INT: SET_DEF(AG_SetInt, AG_INT_MIN+1, AG_INT_MAX-1, 1); break;
339 case AG_VARIABLE_UINT: SET_DEF(AG_SetUint, 0U, AG_UINT_MAX-1, 1U); break;
340 case AG_VARIABLE_UINT8: SET_DEF(AG_SetUint8, 0U, 0xffU, 1U); break;
341 case AG_VARIABLE_SINT8: SET_DEF(AG_SetSint8, -0x7f, 0x7f, 1); break;
342 case AG_VARIABLE_UINT16: SET_DEF(AG_SetUint16, 0U, 0xffffU, 1U); break;
343 case AG_VARIABLE_SINT16: SET_DEF(AG_SetSint16, -0x7fff, 0x7fff, 1); break;
344 case AG_VARIABLE_UINT32: SET_DEF(AG_SetUint32, 0UL, 0xffffffffUL, 1UL); break;
345 case AG_VARIABLE_SINT32: SET_DEF(AG_SetSint32, -0x7fffffffL, 0x7fffffffL, 1L); break;
346 #ifdef HAVE_64BIT
347 case AG_VARIABLE_UINT64: SET_DEF(AG_SetUint64, 0ULL, 0xffffffffffffffffULL, 1ULL); break;
348 case AG_VARIABLE_SINT64: SET_DEF(AG_SetSint64, -0x7fffffffffffffffLL, 0x7fffffffffffffffLL, 1LL); break;
349 #endif
350 default: break;
351 }
352 switch (AG_VARIABLE_TYPE(V)) {
353 case AG_VARIABLE_FLOAT:
354 case AG_VARIABLE_DOUBLE:
355 case AG_VARIABLE_LONG_DOUBLE:
356 AG_TextboxSetFltOnly(num->input, 1);
357 break;
358 default:
359 AG_TextboxSetIntOnly(num->input, 1);
360 break;
361 }
362 AG_UnlockVariable(V);
363 AG_NumericalUpdate(num);
364 }
365
366 static void
KeyDown(AG_Event * event)367 KeyDown(AG_Event *event)
368 {
369 AG_Numerical *num = AG_SELF();
370 int keysym = AG_INT(1);
371
372 switch (keysym) {
373 case AG_KEY_UP:
374 AG_NumericalIncrement(num);
375 break;
376 case AG_KEY_DOWN:
377 AG_NumericalDecrement(num);
378 break;
379 default:
380 break;
381 }
382 }
383
384 /*
385 * Update the numerical value from the textbox.
386 */
387 #define SET_NUM(TYPE,expr) { \
388 TYPE val = (TYPE)(expr); \
389 *(TYPE *)value = val < *(TYPE *)min ? *(TYPE *)min : \
390 val > *(TYPE *)max ? *(TYPE *)max : val; \
391 }
392 static void
UpdateFromText(AG_Event * event)393 UpdateFromText(AG_Event *event)
394 {
395 AG_Numerical *num = AG_PTR(1);
396 int unfocus = AG_INT(2);
397 AG_Variable *valueb, *minb, *maxb;
398 void *value, *min, *max;
399
400 valueb = AG_GetVariable(num, "value", &value);
401 minb = AG_GetVariable(num, "min", &min);
402 maxb = AG_GetVariable(num, "max", &max);
403
404 switch (AG_VARIABLE_TYPE(valueb)) {
405 case AG_VARIABLE_FLOAT:
406 SET_NUM(float, AG_Unit2Base(strtod(num->inTxt,NULL),num->unit));
407 break;
408 case AG_VARIABLE_DOUBLE:
409 SET_NUM(double, AG_Unit2Base(strtod(num->inTxt,NULL),num->unit));
410 break;
411 #ifdef HAVE_LONG_DOUBLE
412 case AG_VARIABLE_LONG_DOUBLE:
413 # ifdef _MK_HAVE_STRTOLD
414 SET_NUM(long double, AG_Unit2BaseLDBL(strtold(num->inTxt,NULL),num->unit));
415 # else
416 SET_NUM(long double, AG_Unit2BaseLDBL((long double)strtod(num->inTxt,NULL),num->unit));
417 # endif
418 break;
419 #endif
420 case AG_VARIABLE_INT: SET_NUM(int, strtol(num->inTxt,NULL,10)); break;
421 case AG_VARIABLE_UINT: SET_NUM(Uint, strtoul(num->inTxt,NULL,10)); break;
422 case AG_VARIABLE_UINT8: SET_NUM(Uint8, strtoul(num->inTxt,NULL,10)); break;
423 case AG_VARIABLE_SINT8: SET_NUM(Sint8, strtol(num->inTxt,NULL,10)); break;
424 case AG_VARIABLE_UINT16: SET_NUM(Uint16, strtoul(num->inTxt,NULL,10)); break;
425 case AG_VARIABLE_SINT16: SET_NUM(Sint16, strtol(num->inTxt,NULL,10)); break;
426 case AG_VARIABLE_UINT32: SET_NUM(Uint32, strtoul(num->inTxt,NULL,10)); break;
427 case AG_VARIABLE_SINT32: SET_NUM(Sint32, strtol(num->inTxt,NULL,10)); break;
428 #ifdef HAVE_64BIT
429 case AG_VARIABLE_UINT64:
430 # ifdef _MK_HAVE_STRTOLL
431 SET_NUM(Uint64, strtoull(num->inTxt,NULL,10));
432 # else
433 SET_NUM(Uint64, strtoul(num->inTxt,NULL,10));
434 # endif
435 break;
436 case AG_VARIABLE_SINT64:
437 # ifdef _MK_HAVE_STRTOLL
438 SET_NUM(Sint64, strtoll(num->inTxt,NULL,10));
439 # else
440 SET_NUM(Sint64, strtol(num->inTxt,NULL,10));
441 # endif
442 break;
443 #endif
444 default:
445 break;
446 }
447
448 AG_PostEvent(NULL, num, "numerical-changed", NULL);
449
450 AG_UnlockVariable(valueb);
451 AG_UnlockVariable(minb);
452 AG_UnlockVariable(maxb);
453
454 if (unfocus) {
455 AG_WidgetUnfocus(num->input);
456 }
457 AG_PostEvent(NULL, num, "numerical-return", NULL);
458 }
459 #undef SET_NUM
460
461 static void
IncrementValue(AG_Event * event)462 IncrementValue(AG_Event *event)
463 {
464 AG_Numerical *num = AG_PTR(1);
465 AG_NumericalIncrement(num);
466 }
467 static void
DecrementValue(AG_Event * event)468 DecrementValue(AG_Event *event)
469 {
470 AG_Numerical *num = AG_PTR(1);
471 AG_NumericalDecrement(num);
472 }
473
474 static void
UpdateUnitSelector(AG_Numerical * num)475 UpdateUnitSelector(AG_Numerical *num)
476 {
477 AG_ButtonTextS(num->units->button, AG_UnitAbbr(num->unit));
478 if (WIDGET(num)->window != NULL &&
479 WIDGET(num)->window->visible)
480 AG_NumericalUpdate(num);
481 }
482
483 static void
UnitSelected(AG_Event * event)484 UnitSelected(AG_Event *event)
485 {
486 AG_Numerical *num = AG_PTR(1);
487 AG_TlistItem *ti = AG_PTR(2);
488
489 AG_ObjectLock(num);
490 num->unit = (const AG_Unit *)ti->p1;
491 UpdateUnitSelector(num);
492 AG_ObjectUnlock(num);
493 }
494
495 int
AG_NumericalSetUnitSystem(AG_Numerical * num,const char * unit_key)496 AG_NumericalSetUnitSystem(AG_Numerical *num, const char *unit_key)
497 {
498 const AG_Unit *unit = NULL;
499 const AG_Unit *ugroup = NULL;
500 int found = 0, i;
501 int w, h, nUnits = 0;
502
503 AG_ObjectLock(num);
504
505 for (i = 0; i < agnUnitGroups; i++) {
506 ugroup = agUnitGroups[i];
507 for (unit = &ugroup[0]; unit->key != NULL; unit++) {
508 if (strcmp(unit->key, unit_key) == 0) {
509 found++;
510 break;
511 }
512 }
513 if (found)
514 break;
515 }
516 if (!found) {
517 AG_SetError(_("No such unit: %s"), unit_key);
518 AG_ObjectUnlock(num);
519 return (-1);
520 }
521 num->unit = unit;
522 UpdateUnitSelector(num);
523
524 num->wUnitSel = 0;
525 num->hUnitSel = 0;
526 num->wPreUnit = 0;
527
528 AG_ObjectLock(num->units->list);
529 AG_TlistDeselectAll(num->units->list);
530 AG_TlistBegin(num->units->list);
531 for (unit = &ugroup[0]; unit->key != NULL; unit++) {
532 AG_TlistItem *it;
533
534 AG_TextSize(AG_UnitAbbr(unit), &w, &h);
535 if (w > num->wUnitSel) { num->wUnitSel = w; }
536 if (h > num->hUnitSel) { num->hUnitSel = h; }
537
538 AG_TextSize(unit->name, &w, NULL);
539 if (w > num->wPreUnit) { num->wPreUnit = w; }
540
541 it = AG_TlistAddPtr(num->units->list, NULL, _(unit->name),
542 (void *)unit);
543 if (unit == num->unit)
544 it->selected++;
545
546 nUnits++;
547 }
548 AG_TlistEnd(num->units->list);
549 AG_TlistSizeHintLargest(num->units->list, 5);
550 AG_ObjectUnlock(num->units->list);
551
552 if (num->wPreUnit > 0) { num->wPreUnit += 8; }
553 AG_UComboSizeHintPixels(num->units, num->wPreUnit,
554 nUnits<6 ? (nUnits + 1) : 6);
555
556 AG_WidgetUpdate(num);
557 AG_ObjectUnlock(num);
558 return (0);
559 }
560
561 /* Update the input text from the binding value. */
562 void
AG_NumericalUpdate(AG_Numerical * num)563 AG_NumericalUpdate(AG_Numerical *num)
564 {
565 char s[64];
566 AG_Variable *valueb;
567 void *value;
568
569 valueb = AG_GetVariable(num, "value", &value);
570 switch (AG_VARIABLE_TYPE(valueb)) {
571 case AG_VARIABLE_DOUBLE:
572 Snprintf(s, sizeof(s), num->format,
573 AG_Base2Unit(*(double *)value, num->unit));
574 break;
575 case AG_VARIABLE_FLOAT:
576 Snprintf(s, sizeof(s), num->format,
577 AG_Base2Unit(*(float *)value, num->unit));
578 break;
579 case AG_VARIABLE_INT: StrlcpyInt(s, *(int *)value, sizeof(s)); break;
580 case AG_VARIABLE_UINT: StrlcpyUint(s, *(Uint *)value, sizeof(s)); break;
581 case AG_VARIABLE_UINT8: StrlcpyUint(s, *(Uint8 *)value, sizeof(s)); break;
582 case AG_VARIABLE_SINT8: StrlcpyInt(s, *(Sint8 *)value, sizeof(s)); break;
583 case AG_VARIABLE_UINT16: StrlcpyUint(s, *(Uint16 *)value, sizeof(s)); break;
584 case AG_VARIABLE_SINT16: StrlcpyInt(s, *(Sint16 *)value, sizeof(s)); break;
585 case AG_VARIABLE_UINT32: Snprintf(s, sizeof(s), "%lu", (unsigned long)*(Uint32 *)value); break;
586 case AG_VARIABLE_SINT32: Snprintf(s, sizeof(s), "%ld", (long)*(Sint32 *)value); break;
587 #ifdef HAVE_64BIT
588 case AG_VARIABLE_UINT64: Snprintf(s, sizeof(s), "%llu", (unsigned long long)*(Uint64 *)value); break;
589 case AG_VARIABLE_SINT64: Snprintf(s, sizeof(s), "%lld", (long long)*(Sint64 *)value); break;
590 #endif
591 default: break;
592 }
593 if (strcmp(num->inTxt, s) != 0) {
594 AG_TextboxSetString(num->input, s);
595 }
596 AG_UnlockVariable(valueb);
597 }
598
599 static void
Init(void * obj)600 Init(void *obj)
601 {
602 AG_Numerical *num = obj;
603
604 WIDGET(num)->flags |= AG_WIDGET_FOCUSABLE|
605 AG_WIDGET_TABLE_EMBEDDABLE;
606
607 num->flags = 0;
608 num->writeable = 1;
609 num->wUnitSel = 0;
610 num->hUnitSel = 0;
611 num->inTxt[0] = '\0';
612 Strlcpy(num->format, "%.02f", sizeof(num->format));
613 AG_InitTimer(&num->updateTo, "update", 0);
614
615 num->input = AG_TextboxNewS(num, AG_TEXTBOX_EXCL, NULL);
616 AG_TextboxBindASCII(num->input, num->inTxt, sizeof(num->inTxt));
617 AG_TextboxSizeHint(num->input, "8888.88");
618
619 num->unit = AG_FindUnit("identity");
620 num->units = NULL;
621
622 num->incbu = AG_ButtonNewS(num, AG_BUTTON_REPEAT, _("+"));
623 AG_ButtonSetPadding(num->incbu, 0,0,0,0);
624 AG_LabelSetPadding(num->incbu->lbl, 0,0,0,0);
625 AG_WidgetSetFocusable(num->incbu, 0);
626
627 num->decbu = AG_ButtonNewS(num, AG_BUTTON_REPEAT, _("-"));
628 AG_ButtonSetPadding(num->decbu, 0,0,0,0);
629 AG_LabelSetPadding(num->decbu->lbl, 0,0,0,0);
630 AG_WidgetSetFocusable(num->decbu, 0);
631
632 AG_AddEvent(num, "widget-shown", OnShow, NULL);
633 AG_SetEvent(num, "key-down", KeyDown, NULL);
634 AG_SetEvent(num->incbu, "button-pushed", IncrementValue, "%p", num);
635 AG_SetEvent(num->decbu, "button-pushed", DecrementValue, "%p", num);
636 AG_SetEvent(num->input, "textbox-return", UpdateFromText, "%p,%i", num, 1);
637 AG_SetEvent(num->input, "textbox-changed", UpdateFromText, "%p,%i", num, 0);
638 AG_WidgetForwardFocus(num, num->input);
639 }
640
641 void
AG_NumericalSizeHint(AG_Numerical * num,const char * text)642 AG_NumericalSizeHint(AG_Numerical *num, const char *text)
643 {
644 AG_ObjectLock(num);
645 AG_TextboxSizeHint(num->input, text);
646 AG_ObjectUnlock(num);
647 }
648
649 static void
SizeRequest(void * obj,AG_SizeReq * r)650 SizeRequest(void *obj, AG_SizeReq *r)
651 {
652 AG_Numerical *num = obj;
653 AG_SizeReq rChld, rInc, rDec;
654
655 AG_WidgetSizeReq(num->input, &rChld);
656 r->w = rChld.w + num->wUnitSel + 4;
657 r->h = MAX(rChld.h, num->hUnitSel);
658
659 AG_WidgetSizeReq(num->incbu, &rInc);
660 AG_WidgetSizeReq(num->decbu, &rDec);
661 r->w += MAX(rInc.w, rDec.w) + 4;
662 }
663
664 static int
SizeAllocate(void * obj,const AG_SizeAlloc * a)665 SizeAllocate(void *obj, const AG_SizeAlloc *a)
666 {
667 AG_Numerical *num = obj;
668 AG_SizeAlloc aChld;
669 int szBtn = a->h/2;
670 int wUnitSel = num->wUnitSel + 4;
671 int hUnitSel = num->hUnitSel;
672
673 if (a->h < 4 || a->w < szBtn+4)
674 return (-1);
675
676 if (num->units != NULL) {
677 if (wUnitSel > a->w - szBtn-4) {
678 wUnitSel = a->w - szBtn-4;
679 }
680 if (hUnitSel > a->h) {
681 hUnitSel = a->h;
682 }
683 } else {
684 wUnitSel = 0;
685 hUnitSel = 0;
686 }
687
688 /* Size input textbox */
689 aChld.x = 0;
690 aChld.y = 0;
691 aChld.w = a->w - wUnitSel - szBtn - 4;
692 aChld.h = a->h;
693 AG_WidgetSizeAlloc(num->input, &aChld);
694 aChld.x += aChld.w + 2;
695
696 /* Size unit selector */
697 if (num->units != NULL) {
698 aChld.w = wUnitSel;
699 aChld.h = a->h;
700 AG_WidgetSizeAlloc(num->units, &aChld);
701 aChld.x += aChld.w + 2;
702 }
703
704 /* Size increment buttons */
705 aChld.w = szBtn;
706 aChld.h = szBtn;
707 AG_WidgetSizeAlloc(num->incbu, &aChld);
708 aChld.y += aChld.h;
709 if (aChld.h*2 < a->h) {
710 aChld.h++;
711 }
712 AG_WidgetSizeAlloc(num->decbu, &aChld);
713 return (0);
714 }
715
716 static void
Draw(void * obj)717 Draw(void *obj)
718 {
719 AG_Numerical *num = obj;
720
721 AG_WidgetDraw(num->input);
722 if (num->units != NULL) { AG_WidgetDraw(num->units); }
723 AG_WidgetDraw(num->incbu);
724 AG_WidgetDraw(num->decbu);
725 }
726
727 /*
728 * Type-independent increment operation.
729 */
730 #undef ADD_INT
731 #define ADD_INT(TYPE) { \
732 TYPE v = *(TYPE *)value; \
733 if ((v + *(TYPE *)inc) < *(TYPE *)min) { v = *(TYPE *)min; } \
734 else if ((v + *(TYPE *)inc) > *(TYPE *)max) { v = *(TYPE *)max; } \
735 else { v += *(TYPE *)inc; } \
736 *(TYPE *)value = v; \
737 }
738 #undef ADD_REAL
739 #define ADD_REAL(TYPE) { \
740 TYPE v = AG_Base2Unit((double)*(TYPE *)value, num->unit); \
741 if ((v + *(TYPE *)inc) < *(TYPE *)min) { v = *(TYPE *)min; } \
742 else if ((v + *(TYPE *)inc) > *(TYPE *)max) { v = *(TYPE *)max; } \
743 else { v += *(TYPE *)inc; } \
744 *(TYPE *)value = AG_Unit2Base((double)v, num->unit); \
745 }
746 #undef ADD_LDBL
747 #define ADD_LDBL(TYPE) { \
748 TYPE v; \
749 v = AG_Base2UnitLDBL(*(TYPE *)value, num->unit); \
750 if ((v + *(TYPE *)inc) < *(TYPE *)min) { v = *(TYPE *)min; } \
751 else if ((v + *(TYPE *)inc) > *(TYPE *)max) { v = *(TYPE *)max; } \
752 else { v += *(TYPE *)inc; } \
753 *(TYPE *)value = AG_Unit2BaseLDBL((long double)v, num->unit); \
754 }
755 void
AG_NumericalIncrement(AG_Numerical * num)756 AG_NumericalIncrement(AG_Numerical *num)
757 {
758 AG_Variable *valueb, *minb, *maxb, *incb;
759 void *value, *min, *max, *inc;
760
761 AG_ObjectLock(num);
762 valueb = AG_GetVariable(num, "value", &value);
763 minb = AG_GetVariable(num, "min", &min);
764 maxb = AG_GetVariable(num, "max", &max);
765 incb = AG_GetVariable(num, "inc", &inc);
766
767 switch (AG_VARIABLE_TYPE(valueb)) {
768 case AG_VARIABLE_FLOAT: ADD_REAL(float); break;
769 case AG_VARIABLE_DOUBLE: ADD_REAL(double); break;
770 #ifdef HAVE_LONG_DOUBLE
771 case AG_VARIABLE_LONG_DOUBLE: ADD_LDBL(long double); break;
772 #endif
773 case AG_VARIABLE_INT: ADD_INT(int); break;
774 case AG_VARIABLE_UINT: ADD_INT(Uint); break;
775 case AG_VARIABLE_UINT8: ADD_INT(Uint8); break;
776 case AG_VARIABLE_SINT8: ADD_INT(Sint8); break;
777 case AG_VARIABLE_UINT16: ADD_INT(Uint16); break;
778 case AG_VARIABLE_SINT16: ADD_INT(Sint16); break;
779 case AG_VARIABLE_UINT32: ADD_INT(Uint32); break;
780 case AG_VARIABLE_SINT32: ADD_INT(Sint32); break;
781 #ifdef HAVE_64BIT
782 case AG_VARIABLE_UINT64: ADD_INT(Uint64); break;
783 case AG_VARIABLE_SINT64: ADD_INT(Sint64); break;
784 #endif
785 default: break;
786 }
787
788 AG_PostEvent(NULL, num, "numerical-changed", NULL);
789
790 AG_UnlockVariable(valueb);
791 AG_UnlockVariable(minb);
792 AG_UnlockVariable(maxb);
793 AG_UnlockVariable(incb);
794
795 AG_NumericalUpdate(num);
796 AG_ObjectUnlock(num);
797 }
798 #undef ADD_INT
799 #undef ADD_REAL
800 #undef ADD_LDBL
801
802 /*
803 * Type-independent decrement operation.
804 */
805 #undef SUB_INT
806 #define SUB_INT(TYPE) { \
807 TYPE v = *(TYPE *)value; \
808 if ((v - *(TYPE *)inc) < *(TYPE *)min) { v = *(TYPE *)min; } \
809 else if ((v - *(TYPE *)inc) > *(TYPE *)max) { v = *(TYPE *)max; } \
810 else { v -= *(TYPE *)inc; } \
811 *(TYPE *)value = v; \
812 }
813 #undef SUB_REAL
814 #define SUB_REAL(TYPE) { \
815 TYPE v = AG_Base2Unit((double)*(TYPE *)value, num->unit); \
816 if ((v - *(TYPE *)inc) < *(TYPE *)min) { v = *(TYPE *)min; } \
817 else if ((v - *(TYPE *)inc) > *(TYPE *)max) { v = *(TYPE *)max; } \
818 else { v -= *(TYPE *)inc; } \
819 *(TYPE *)value = AG_Unit2Base((double)v, num->unit); \
820 }
821 #undef SUB_LDBL
822 #define SUB_LDBL(TYPE) { \
823 TYPE v = AG_Base2UnitLDBL((long double)*(TYPE *)value, num->unit); \
824 if ((v - *(TYPE *)inc) < *(TYPE *)min) { v = *(TYPE *)min; } \
825 else if ((v - *(TYPE *)inc) > *(TYPE *)max) { v = *(TYPE *)max; } \
826 else { v -= *(TYPE *)inc; } \
827 *(TYPE *)value = AG_Unit2BaseLDBL((long double)v, num->unit); \
828 }
829 void
AG_NumericalDecrement(AG_Numerical * num)830 AG_NumericalDecrement(AG_Numerical *num)
831 {
832 AG_Variable *valueb, *minb, *maxb, *incb;
833 void *value, *min, *max, *inc;
834
835 AG_ObjectLock(num);
836 valueb = AG_GetVariable(num, "value", &value);
837 minb = AG_GetVariable(num, "min", &min);
838 maxb = AG_GetVariable(num, "max", &max);
839 incb = AG_GetVariable(num, "inc", &inc);
840
841 switch (AG_VARIABLE_TYPE(valueb)) {
842 case AG_VARIABLE_FLOAT: SUB_REAL(float); break;
843 case AG_VARIABLE_DOUBLE: SUB_REAL(double); break;
844 #ifdef HAVE_LONG_DOUBLE
845 case AG_VARIABLE_LONG_DOUBLE: SUB_LDBL(long double); break;
846 #endif
847 case AG_VARIABLE_INT: SUB_INT(int); break;
848 case AG_VARIABLE_UINT: SUB_INT(Uint); break;
849 case AG_VARIABLE_UINT8: SUB_INT(Uint8); break;
850 case AG_VARIABLE_SINT8: SUB_INT(Sint8); break;
851 case AG_VARIABLE_UINT16: SUB_INT(Uint16); break;
852 case AG_VARIABLE_SINT16: SUB_INT(Sint16); break;
853 case AG_VARIABLE_UINT32: SUB_INT(Uint32); break;
854 case AG_VARIABLE_SINT32: SUB_INT(Sint32); break;
855 #ifdef HAVE_64BIT
856 case AG_VARIABLE_UINT64: SUB_INT(Uint64); break;
857 case AG_VARIABLE_SINT64: SUB_INT(Sint64); break;
858 #endif
859 default: break;
860 }
861 AG_PostEvent(NULL, num, "numerical-changed", NULL);
862
863 AG_UnlockVariable(valueb);
864 AG_UnlockVariable(minb);
865 AG_UnlockVariable(maxb);
866 AG_UnlockVariable(incb);
867
868 AG_NumericalUpdate(num);
869 AG_ObjectUnlock(num);
870 }
871 #undef SUB_INT
872 #undef SUB_REAL
873 #undef SUB_LDBL
874
875 void
AG_NumericalSetPrecision(AG_Numerical * num,const char * mode,int precision)876 AG_NumericalSetPrecision(AG_Numerical *num, const char *mode,
877 int precision)
878 {
879 AG_ObjectLock(num);
880 num->format[0] = '%';
881 num->format[1] = '.';
882 num->format[2] = '\0';
883 StrlcatInt(num->format, precision, sizeof(num->format));
884 Strlcat(num->format, mode, sizeof(num->format));
885 AG_NumericalUpdate(num);
886 AG_ObjectUnlock(num);
887 }
888
889 void
AG_NumericalSelectUnit(AG_Numerical * num,const char * uname)890 AG_NumericalSelectUnit(AG_Numerical *num, const char *uname)
891 {
892 AG_TlistItem *it;
893
894 AG_ObjectLock(num);
895 AG_ObjectLock(num->units->list);
896 AG_TlistDeselectAll(num->units->list);
897 TAILQ_FOREACH(it, &num->units->list->items, items) {
898 const AG_Unit *unit = it->p1;
899
900 if (strcmp(unit->key, uname) == 0) {
901 it->selected++;
902 num->unit = unit;
903 UpdateUnitSelector(num);
904 break;
905 }
906 }
907 AG_ObjectUnlock(num->units->list);
908 AG_ObjectUnlock(num);
909 }
910
911 void
AG_NumericalSetWriteable(AG_Numerical * num,int writeable)912 AG_NumericalSetWriteable(AG_Numerical *num, int writeable)
913 {
914 AG_ObjectLock(num);
915 num->writeable = writeable;
916 if (writeable) {
917 AG_WidgetEnable(num->incbu);
918 AG_WidgetEnable(num->decbu);
919 AG_WidgetEnable(num->input);
920 } else {
921 AG_WidgetDisable(num->incbu);
922 AG_WidgetDisable(num->decbu);
923 AG_WidgetDisable(num->input);
924 }
925 AG_ObjectUnlock(num);
926 }
927
928 /* Convert the bound value to a float. */
929 float
AG_NumericalGetFlt(AG_Numerical * num)930 AG_NumericalGetFlt(AG_Numerical *num)
931 {
932 AG_Variable *bValue;
933 void *value;
934
935 bValue = AG_GetVariable(num, "value", &value);
936 switch (AG_VARIABLE_TYPE(bValue)) {
937 case AG_VARIABLE_FLOAT: return *(float *)value;
938 case AG_VARIABLE_DOUBLE: return (float)(*(double *)value);
939 #ifdef HAVE_LONG_DOUBLE
940 case AG_VARIABLE_LONG_DOUBLE: return (float)(*(long double *)value);
941 #endif
942 case AG_VARIABLE_INT: return (float)(*(int *)value);
943 case AG_VARIABLE_UINT: return (float)(*(Uint *)value);
944 case AG_VARIABLE_UINT8: return (float)(*(Uint8 *)value);
945 case AG_VARIABLE_UINT16: return (float)(*(Uint16 *)value);
946 case AG_VARIABLE_UINT32: return (float)(*(Uint32 *)value);
947 case AG_VARIABLE_SINT8: return (float)(*(Sint8 *)value);
948 case AG_VARIABLE_SINT16: return (float)(*(Sint16 *)value);
949 case AG_VARIABLE_SINT32: return (float)(*(Sint32 *)value);
950 #ifdef HAVE_64BIT
951 case AG_VARIABLE_UINT64: return (float)(*(Uint64 *)value);
952 case AG_VARIABLE_SINT64: return (float)(*(Sint64 *)value);
953 #endif
954 default: return (0.0f);
955 }
956 }
957
958 /* Convert the bound value to a double. */
959 double
AG_NumericalGetDbl(AG_Numerical * num)960 AG_NumericalGetDbl(AG_Numerical *num)
961 {
962 AG_Variable *bValue;
963 void *value;
964
965 bValue = AG_GetVariable(num, "value", &value);
966 switch (AG_VARIABLE_TYPE(bValue)) {
967 case AG_VARIABLE_FLOAT: return (double)(*(float *)value);
968 case AG_VARIABLE_DOUBLE: return *(double *)value;
969 #ifdef HAVE_LONG_DOUBLE
970 case AG_VARIABLE_LONG_DOUBLE: return (double)(*(long double *)value);
971 #endif
972 case AG_VARIABLE_INT: return (double)(*(int *)value);
973 case AG_VARIABLE_UINT: return (double)(*(Uint *)value);
974 case AG_VARIABLE_UINT8: return (double)(*(Uint8 *)value);
975 case AG_VARIABLE_UINT16: return (double)(*(Uint16 *)value);
976 case AG_VARIABLE_UINT32: return (double)(*(Uint32 *)value);
977 case AG_VARIABLE_SINT8: return (double)(*(Sint8 *)value);
978 case AG_VARIABLE_SINT16: return (double)(*(Sint16 *)value);
979 case AG_VARIABLE_SINT32: return (double)(*(Sint32 *)value);
980 #ifdef HAVE_64BIT
981 case AG_VARIABLE_UINT64: return (double)(*(Uint64 *)value);
982 case AG_VARIABLE_SINT64: return (double)(*(Sint64 *)value);
983 #endif
984 default: return (0.0);
985 }
986 }
987
988 #ifdef HAVE_LONG_DOUBLE
989 /* Convert the bound value to a long double. */
990 long double
AG_NumericalGetLdbl(AG_Numerical * num)991 AG_NumericalGetLdbl(AG_Numerical *num)
992 {
993 AG_Variable *bValue;
994 void *value;
995
996 bValue = AG_GetVariable(num, "value", &value);
997 switch (AG_VARIABLE_TYPE(bValue)) {
998 case AG_VARIABLE_FLOAT: return (long double)(*(float *)value);
999 case AG_VARIABLE_DOUBLE: return (long double)(*(double *)value);
1000 case AG_VARIABLE_LONG_DOUBLE: return *(long double *)value;
1001 case AG_VARIABLE_INT: return (long double)(*(int *)value);
1002 case AG_VARIABLE_UINT: return (long double)(*(Uint *)value);
1003 case AG_VARIABLE_UINT8: return (long double)(*(Uint8 *)value);
1004 case AG_VARIABLE_UINT16: return (long double)(*(Uint16 *)value);
1005 case AG_VARIABLE_UINT32: return (long double)(*(Uint32 *)value);
1006 case AG_VARIABLE_SINT8: return (long double)(*(Sint8 *)value);
1007 case AG_VARIABLE_SINT16: return (long double)(*(Sint16 *)value);
1008 case AG_VARIABLE_SINT32: return (long double)(*(Sint32 *)value);
1009 #ifdef HAVE_64BIT
1010 case AG_VARIABLE_UINT64: return (long double)(*(Uint64 *)value);
1011 case AG_VARIABLE_SINT64: return (long double)(*(Sint64 *)value);
1012 #endif
1013 default: return (0.0L);
1014 }
1015 }
1016 #endif /* HAVE_LONG_DOUBLE */
1017
1018 /* Convert the bound value to a natural integer. */
1019 int
AG_NumericalGetInt(AG_Numerical * num)1020 AG_NumericalGetInt(AG_Numerical *num)
1021 {
1022 AG_Variable *bValue;
1023 void *value;
1024
1025 bValue = AG_GetVariable(num, "value", &value);
1026 switch (AG_VARIABLE_TYPE(bValue)) {
1027 case AG_VARIABLE_FLOAT: return (int)(*(float *)value);
1028 case AG_VARIABLE_DOUBLE: return (int)(*(double *)value);
1029 #ifdef HAVE_LONG_DOUBLE
1030 case AG_VARIABLE_LONG_DOUBLE: return (int)(*(long double *)value);
1031 #endif
1032 case AG_VARIABLE_INT: return *(int *)value;
1033 case AG_VARIABLE_UINT: return (int)(*(Uint *)value);
1034 case AG_VARIABLE_UINT8: return (int)(*(Uint8 *)value);
1035 case AG_VARIABLE_UINT16: return (int)(*(Uint16 *)value);
1036 case AG_VARIABLE_UINT32: return (int)(*(Uint32 *)value);
1037 case AG_VARIABLE_SINT8: return (int)(*(Sint8 *)value);
1038 case AG_VARIABLE_SINT16: return (int)(*(Sint16 *)value);
1039 case AG_VARIABLE_SINT32: return (int)(*(Sint32 *)value);
1040 #ifdef HAVE_64BIT
1041 case AG_VARIABLE_UINT64: return (int)(*(Uint64 *)value);
1042 case AG_VARIABLE_SINT64: return (int)(*(Sint64 *)value);
1043 #endif
1044 default: return (0);
1045 }
1046 }
1047
1048 /* Convert the bound value to a 32-bit integer. */
1049 Uint32
AG_NumericalGetUint32(AG_Numerical * num)1050 AG_NumericalGetUint32(AG_Numerical *num)
1051 {
1052 AG_Variable *bValue;
1053 void *value;
1054
1055 bValue = AG_GetVariable(num, "value", &value);
1056 switch (AG_VARIABLE_TYPE(bValue)) {
1057 case AG_VARIABLE_FLOAT: return (Uint32)(*(float *)value);
1058 case AG_VARIABLE_DOUBLE: return (Uint32)(*(double *)value);
1059 #ifdef HAVE_LONG_DOUBLE
1060 case AG_VARIABLE_LONG_DOUBLE: return (Uint32)(*(long double *)value);
1061 #endif
1062 case AG_VARIABLE_INT: return (Uint32)(*(int *)value);
1063 case AG_VARIABLE_UINT: return (Uint32)(*(Uint *)value);
1064 case AG_VARIABLE_UINT8: return (Uint32)(*(Uint8 *)value);
1065 case AG_VARIABLE_UINT16: return (Uint32)(*(Uint16 *)value);
1066 case AG_VARIABLE_UINT32: return *(Uint32 *)value;
1067 case AG_VARIABLE_SINT8: return (Uint32)(*(Sint8 *)value);
1068 case AG_VARIABLE_SINT16: return (Uint32)(*(Sint16 *)value);
1069 case AG_VARIABLE_SINT32: return (Uint32)(*(Sint32 *)value);
1070 #ifdef HAVE_64BIT
1071 case AG_VARIABLE_UINT64: return (Uint32)(*(Uint64 *)value);
1072 case AG_VARIABLE_SINT64: return (Uint32)(*(Sint64 *)value);
1073 #endif
1074 default: return (0UL);
1075 }
1076 }
1077
1078 #ifdef HAVE_64BIT
1079 /* Convert the bound value to a 64-bit integer. */
1080 Uint64
AG_NumericalGetUint64(AG_Numerical * num)1081 AG_NumericalGetUint64(AG_Numerical *num)
1082 {
1083 AG_Variable *bValue;
1084 void *value;
1085
1086 bValue = AG_GetVariable(num, "value", &value);
1087 switch (AG_VARIABLE_TYPE(bValue)) {
1088 case AG_VARIABLE_FLOAT: return (Uint64)(*(float *)value);
1089 case AG_VARIABLE_DOUBLE: return (Uint64)(*(double *)value);
1090 #ifdef HAVE_LONG_DOUBLE
1091 case AG_VARIABLE_LONG_DOUBLE: return (Uint64)(*(long double *)value);
1092 #endif
1093 case AG_VARIABLE_INT: return (Uint64)(*(int *)value);
1094 case AG_VARIABLE_UINT: return (Uint64)(*(Uint *)value);
1095 case AG_VARIABLE_UINT8: return (Uint64)(*(Uint8 *)value);
1096 case AG_VARIABLE_UINT16: return (Uint64)(*(Uint16 *)value);
1097 case AG_VARIABLE_UINT32: return (Uint64)(*(Uint32 *)value);
1098 case AG_VARIABLE_UINT64: return *(Uint64 *)value;
1099 case AG_VARIABLE_SINT8: return (Uint64)(*(Sint8 *)value);
1100 case AG_VARIABLE_SINT16: return (Uint64)(*(Sint16 *)value);
1101 case AG_VARIABLE_SINT32: return (Uint64)(*(Sint32 *)value);
1102 case AG_VARIABLE_SINT64: return (Uint64)(*(Sint64 *)value);
1103 default: return (0ULL);
1104 }
1105 }
1106 #endif /* HAVE_64BIT */
1107
1108 #ifdef AG_LEGACY
1109 void
AG_NumericalSetIncrement(AG_Numerical * num,double inc)1110 AG_NumericalSetIncrement(AG_Numerical *num, double inc)
1111 {
1112 AG_Variable *V;
1113
1114 AG_ObjectLock(num);
1115
1116 if ((V = AG_GetVariableLocked(num, "value")) == NULL) {
1117 goto out;
1118 }
1119 switch (AG_VARIABLE_TYPE(V)) {
1120 case AG_VARIABLE_INT: AG_SetInt(num, "inc", (int)inc); break;
1121 case AG_VARIABLE_UINT: AG_SetUint(num, "inc", (Uint)inc); break;
1122 case AG_VARIABLE_UINT8: AG_SetUint8(num, "inc", (Uint8)inc); break;
1123 case AG_VARIABLE_SINT8: AG_SetSint8(num, "inc", (Sint8)inc); break;
1124 case AG_VARIABLE_UINT16: AG_SetUint16(num, "inc", (Uint16)inc); break;
1125 case AG_VARIABLE_SINT16: AG_SetSint16(num, "inc", (Sint16)inc); break;
1126 case AG_VARIABLE_UINT32: AG_SetUint32(num, "inc", (Uint32)inc); break;
1127 case AG_VARIABLE_SINT32: AG_SetSint32(num, "inc", (Sint32)inc); break;
1128 #ifdef HAVE_64BIT
1129 case AG_VARIABLE_UINT64: AG_SetUint64(num, "inc", (Uint64)inc); break;
1130 case AG_VARIABLE_SINT64: AG_SetSint64(num, "inc", (Sint64)inc); break;
1131 #endif
1132 case AG_VARIABLE_FLOAT: AG_SetFloat(num, "inc", (float)inc); break;
1133 case AG_VARIABLE_DOUBLE: AG_SetDouble(num, "inc", inc); break;
1134 #ifdef HAVE_LONG_DOUBLE
1135 case AG_VARIABLE_LONG_DOUBLE: AG_SetLongDouble(num, "inc", (long double)inc); break;
1136 #endif
1137 default: break;
1138 }
1139 AG_UnlockVariable(V);
1140 out:
1141 AG_ObjectUnlock(num);
1142 }
1143 void
AG_NumericalSetRangeInt(AG_Numerical * num,int min,int max)1144 AG_NumericalSetRangeInt(AG_Numerical *num, int min, int max)
1145 {
1146 AG_SetInt(num, "min", min);
1147 AG_SetInt(num, "max", max);
1148 }
1149 void
AG_NumericalSetRangeFlt(AG_Numerical * num,float min,float max)1150 AG_NumericalSetRangeFlt(AG_Numerical *num, float min, float max)
1151 {
1152 AG_SetFloat(num, "min", min);
1153 AG_SetFloat(num, "max", max);
1154 }
1155 void
AG_NumericalSetRangeDbl(AG_Numerical * num,double min,double max)1156 AG_NumericalSetRangeDbl(AG_Numerical *num, double min, double max)
1157 {
1158 AG_SetDouble(num, "min", min);
1159 AG_SetDouble(num, "max", max);
1160 }
AG_NumericalSetMin(AG_Numerical * num,double min)1161 void AG_NumericalSetMin(AG_Numerical *num, double min)
1162 {
1163 AG_SetDouble(num, "min", min);
1164 }
AG_NumericalSetMax(AG_Numerical * num,double max)1165 void AG_NumericalSetMax(AG_Numerical *num, double max)
1166 {
1167 AG_SetDouble(num, "max", max);
1168 }
1169 #endif /* AG_LEGACY */
1170
1171 AG_WidgetClass agNumericalClass = {
1172 {
1173 "Agar(Widget:Numerical)",
1174 sizeof(AG_Numerical),
1175 { 0,0 },
1176 Init,
1177 NULL, /* free */
1178 NULL, /* destroy */
1179 NULL, /* load */
1180 NULL, /* save */
1181 NULL /* edit */
1182 },
1183 Draw,
1184 SizeRequest,
1185 SizeAllocate
1186 };
1187
1188