Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / libs / muimaster / classes / numeric.c
blob7482b645b6ac745540ce21dde1eec319f9db33d3
1 /*
2 Copyright © 2002-2006, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <stdio.h>
8 #include <clib/alib_protos.h>
9 #include <proto/exec.h>
10 #include <proto/intuition.h>
11 #include <proto/graphics.h>
12 #include <proto/utility.h>
13 #include <proto/muimaster.h>
15 #include "debug.h"
16 #include "mui.h"
17 #include "muimaster_intern.h"
18 #include "support.h"
20 struct MUI_NumericData
22 STRPTR format;
23 LONG defvalue;
24 LONG max;
25 LONG min;
26 LONG value;
27 ULONG flags;
28 struct MUI_EventHandlerNode ehn;
29 char buf[50];
32 enum numeric_flags {
33 NUMERIC_REVERSE = (1<<0),
34 NUMERIC_REVLEFTRIGHT = (1<<1),
35 NUMERIC_REVUPDOWN = (1<<2),
36 NUMERIC_CHECKALLSIZES = (1<<3),
39 extern struct Library *MUIMasterBase;
41 /**************************************************************************
42 OM_NEW
43 **************************************************************************/
44 IPTR Numeric__OM_NEW(struct IClass *cl, Object * obj, struct opSet *msg)
46 struct MUI_NumericData *data;
47 struct TagItem *tags, *tag;
49 BOOL value_set = FALSE;
51 obj = (Object *)DoSuperMethodA(cl, obj, (Msg)msg);
52 if (!obj)
53 return 0;
55 data = INST_DATA(cl, obj);
56 data->format = "%ld";
57 data->max = 100;
58 data->min = 0;
59 data->flags = 0;
61 for (tags = msg->ops_AttrList; (tag = NextTagItem((const struct TagItem **)&tags));)
63 switch (tag->ti_Tag)
65 case MUIA_Numeric_CheckAllSizes:
66 _handle_bool_tag(data->flags, tag->ti_Data, NUMERIC_CHECKALLSIZES);
67 break;
68 case MUIA_Numeric_Default:
69 /* data->defvalue = CLAMP(tag->ti_Data, data->min, data->max); */
70 data->defvalue = tag->ti_Data;
71 break;
72 case MUIA_Numeric_Format:
73 data->format = (STRPTR)tag->ti_Data;
74 break;
75 case MUIA_Numeric_Max:
76 data->max = tag->ti_Data;
77 break;
78 case MUIA_Numeric_Min:
79 data->min = tag->ti_Data;
80 break;
81 case MUIA_Numeric_Reverse:
82 _handle_bool_tag(data->flags, tag->ti_Data, NUMERIC_REVERSE);
83 break;
84 case MUIA_Numeric_RevLeftRight:
85 _handle_bool_tag(data->flags, tag->ti_Data, NUMERIC_REVLEFTRIGHT);
86 break;
87 case MUIA_Numeric_RevUpDown:
88 _handle_bool_tag(data->flags, tag->ti_Data, NUMERIC_REVUPDOWN);
89 break;
90 case MUIA_Numeric_Value:
91 value_set = TRUE;
92 data->value = (LONG)tag->ti_Data;
93 break;
97 data->value = CLAMP(value_set ? data->value : data->defvalue, data->min, data->max);
99 return (IPTR)obj;
102 /**************************************************************************
103 OM_SET
104 **************************************************************************/
105 IPTR Numeric__OM_SET(struct IClass *cl, Object * obj, struct opSet *msg)
107 struct MUI_NumericData *data = INST_DATA(cl, obj);
108 struct TagItem *tags, *tag;
109 LONG oldval, oldmin, oldmax;
110 STRPTR oldfmt;
111 IPTR ret;
112 BOOL values_changed = FALSE;
114 oldval = data->value;
115 oldfmt = data->format;
116 oldmin = data->min;
117 oldmax = data->max;
119 for (tags = msg->ops_AttrList; (tag = NextTagItem((const struct TagItem **)&tags));)
121 switch (tag->ti_Tag)
123 case MUIA_Numeric_CheckAllSizes:
124 _handle_bool_tag(data->flags, tag->ti_Data, NUMERIC_CHECKALLSIZES);
125 break;
126 case MUIA_Numeric_Default:
127 /* data->defvalue = CLAMP(tag->ti_Data, data->min, data->max); */
128 data->defvalue = tag->ti_Data;
129 break;
130 case MUIA_Numeric_Format:
131 data->format = (STRPTR)tag->ti_Data;
132 break;
133 case MUIA_Numeric_Max:
134 data->max = tag->ti_Data;
135 break;
136 case MUIA_Numeric_Min:
137 data->min = tag->ti_Data;
138 break;
139 case MUIA_Numeric_Reverse:
140 _handle_bool_tag(data->flags, tag->ti_Data, NUMERIC_REVERSE);
141 break;
142 case MUIA_Numeric_RevLeftRight:
143 _handle_bool_tag(data->flags, tag->ti_Data, NUMERIC_REVLEFTRIGHT);
144 break;
145 case MUIA_Numeric_RevUpDown:
146 _handle_bool_tag(data->flags, tag->ti_Data, NUMERIC_REVUPDOWN);
147 break;
148 case MUIA_Numeric_Value:
149 tag->ti_Data = CLAMP((LONG)tag->ti_Data, data->min, data->max);
151 if (data->value == (LONG)tag->ti_Data)
152 tag->ti_Tag = TAG_IGNORE;
153 else
154 data->value = (LONG)tag->ti_Data;
156 break;
160 /* If the max, min or format values changed, then the minimum and maximum sizes
161 of the string output by MUIM_Numeric_Strigify maye have changed, so
162 give the subclass a chance to recalculate them and relayout the group
163 accordingly. Basically, the subclass will have to react on changes to
164 these values as well (by setting a notification on them, or by overriding
165 OM_SET) and then recalculate the minimum and maximum sizes for the object. */
166 if (data->format != oldfmt || data->min != oldmin || data->max != oldmax)
168 values_changed = TRUE;
169 DoMethod(_parent(obj), MUIM_Group_InitChange);
170 DoMethod(_parent(obj), MUIM_Group_ExitChange);
174 ret = DoSuperMethodA(cl, obj, (Msg)msg);
176 if (data->value != oldval || values_changed)
178 MUI_Redraw(obj, MADF_DRAWUPDATE);
181 return ret;
184 /**************************************************************************
185 OM_GET
186 **************************************************************************/
187 IPTR Numeric__OM_GET(struct IClass *cl, Object * obj, struct opGet *msg)
189 struct MUI_NumericData *data = INST_DATA(cl, obj);
190 IPTR *store = msg->opg_Storage;
191 ULONG tag = msg->opg_AttrID;
193 switch (tag)
195 case MUIA_Numeric_CheckAllSizes:
196 *store = ((data->flags & NUMERIC_CHECKALLSIZES) != 0);
197 return TRUE;
199 case MUIA_Numeric_Default:
200 *store = data->defvalue;
201 return TRUE;
203 case MUIA_Numeric_Format:
204 *store = (IPTR)data->format;
205 return TRUE;
207 case MUIA_Numeric_Max:
208 *store = data->max;
209 return TRUE;
211 case MUIA_Numeric_Min:
212 *store = data->min;
213 return TRUE;
215 case MUIA_Numeric_Reverse:
216 *store = ((data->flags & NUMERIC_REVERSE) != 0);
217 return TRUE;
219 case MUIA_Numeric_RevLeftRight:
220 *store = ((data->flags & NUMERIC_REVLEFTRIGHT) != 0);
221 return TRUE;
223 case MUIA_Numeric_RevUpDown:
224 *store = ((data->flags & NUMERIC_REVUPDOWN) != 0);
225 return TRUE;
227 case MUIA_Numeric_Value:
228 *store = data->value;
229 return TRUE;
232 return DoSuperMethodA(cl, obj, (Msg)msg);
235 /**************************************************************************
236 MUIM_Setup
237 **************************************************************************/
238 IPTR Numeric__MUIM_Setup(struct IClass *cl, Object *obj, struct MUIP_Setup *msg)
240 struct MUI_NumericData *data = INST_DATA(cl, obj);
242 if (!DoSuperMethodA(cl,obj,(Msg)msg))
243 return FALSE;
245 data->ehn.ehn_Events = IDCMP_RAWKEY;
246 data->ehn.ehn_Priority = 0;
247 data->ehn.ehn_Flags = 0;
248 data->ehn.ehn_Object = obj;
249 data->ehn.ehn_Class = cl;
250 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)(&data->ehn));
252 return TRUE;
255 /**************************************************************************
256 MUIM_Cleanup
257 **************************************************************************/
258 IPTR Numeric__MUIM_Cleanup(struct IClass *cl, Object *obj, struct MUIP_Cleanup *msg)
260 struct MUI_NumericData *data = INST_DATA(cl, obj);
262 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)(&data->ehn));
263 return DoSuperMethodA(cl,obj,(Msg)msg);
266 /**************************************************************************
267 MUIM_HandleEvent
268 **************************************************************************/
269 IPTR Numeric__MUIM_HandleEvent(struct IClass *cl, Object *obj, struct MUIP_HandleEvent *msg)
271 struct MUI_NumericData *data = INST_DATA(cl, obj);
273 if (msg->muikey != MUIKEY_NONE)
275 LONG step;
277 if (data->max - data->min < 10)
278 step = 1;
279 else
280 step = 10;
282 switch(msg->muikey)
284 case MUIKEY_PRESS:
285 return MUI_EventHandlerRC_Eat;
287 case MUIKEY_TOGGLE:
288 DoMethod(obj, MUIM_Numeric_SetDefault);
289 return MUI_EventHandlerRC_Eat;
291 case MUIKEY_RELEASE:
292 return MUI_EventHandlerRC_Eat;
294 case MUIKEY_BOTTOM:
295 case MUIKEY_LINEEND:
296 if (data->flags & NUMERIC_REVUPDOWN)
297 set(obj, MUIA_Numeric_Value, data->min);
298 else
299 set(obj, MUIA_Numeric_Value, data->max);
300 return MUI_EventHandlerRC_Eat;
302 case MUIKEY_TOP:
303 case MUIKEY_LINESTART:
304 if (data->flags & NUMERIC_REVUPDOWN)
305 set(obj, MUIA_Numeric_Value, data->max);
306 else
307 set(obj, MUIA_Numeric_Value, data->min);
308 return MUI_EventHandlerRC_Eat;
310 case MUIKEY_LEFT:
311 if (data->flags & NUMERIC_REVLEFTRIGHT)
312 DoMethod(obj, MUIM_Numeric_Increase, 1);
313 else
314 DoMethod(obj, MUIM_Numeric_Decrease, 1);
315 return MUI_EventHandlerRC_Eat;
317 case MUIKEY_RIGHT:
318 if (data->flags & NUMERIC_REVLEFTRIGHT)
319 DoMethod(obj, MUIM_Numeric_Decrease, 1);
320 else
321 DoMethod(obj, MUIM_Numeric_Increase, 1);
322 return MUI_EventHandlerRC_Eat;
324 case MUIKEY_UP:
325 if (data->flags & NUMERIC_REVUPDOWN)
326 DoMethod(obj, MUIM_Numeric_Increase, 1);
327 else
328 DoMethod(obj, MUIM_Numeric_Decrease, 1);
329 return MUI_EventHandlerRC_Eat;
331 case MUIKEY_DOWN:
332 if (data->flags & NUMERIC_REVUPDOWN)
333 DoMethod(obj, MUIM_Numeric_Decrease, 1);
334 else
335 DoMethod(obj, MUIM_Numeric_Increase, 1);
336 return MUI_EventHandlerRC_Eat;
338 case MUIKEY_PAGEDOWN:
339 case MUIKEY_WORDRIGHT:
340 if (data->flags & NUMERIC_REVUPDOWN)
341 DoMethod(obj, MUIM_Numeric_Decrease, step);
342 else
343 DoMethod(obj, MUIM_Numeric_Increase, step);
344 return MUI_EventHandlerRC_Eat;
346 case MUIKEY_PAGEUP:
347 case MUIKEY_WORDLEFT:
348 if (data->flags & NUMERIC_REVUPDOWN)
349 DoMethod(obj, MUIM_Numeric_Increase, step);
350 else
351 DoMethod(obj, MUIM_Numeric_Decrease, step);
352 return MUI_EventHandlerRC_Eat;
354 default:
355 return 0;
359 return 0;
363 /**************************************************************************
364 MUIM_Numeric_Decrease
365 **************************************************************************/
366 IPTR Numeric__MUIM_Decrease(struct IClass *cl, Object * obj, struct MUIP_Numeric_Decrease *msg)
368 struct MUI_NumericData *data = INST_DATA(cl, obj);
369 LONG newval = CLAMP(data->value - msg->amount, data->min, data->max);
370 if (newval != data->value) set(obj,MUIA_Numeric_Value, newval);
371 return 1;
374 /**************************************************************************
375 MUIM_Numeric_Increase
376 **************************************************************************/
377 IPTR Numeric__MUIM_Increase(struct IClass *cl, Object * obj, struct MUIP_Numeric_Increase *msg)
379 struct MUI_NumericData *data = INST_DATA(cl, obj);
380 LONG newval = CLAMP(data->value + msg->amount, data->min, data->max);
382 if (newval != data->value) set(obj,MUIA_Numeric_Value, newval);
383 return 1;
387 /**************************************************************************
388 MUIM_Numeric_ScaleToValue
389 **************************************************************************/
390 IPTR Numeric__MUIM_ScaleToValue(struct IClass *cl, Object * obj, struct MUIP_Numeric_ScaleToValue *msg)
392 struct MUI_NumericData *data = INST_DATA(cl, obj);
393 LONG min, max;
394 LONG val;
395 LONG d;
397 min = (data->flags & NUMERIC_REVERSE) ? data->max : data->min;
398 max = (data->flags & NUMERIC_REVERSE) ? data->min : data->max;
400 val = CLAMP(msg->scale - msg->scalemin, msg->scalemin, msg->scalemax);
401 d = msg->scalemax - msg->scalemin;
403 #warning FIXME: watch out for overflow here.
404 val = val * (max - min);
406 if (d)
407 val /= d;
409 val += min;
411 return val;
414 /**************************************************************************
415 MUIM_Numeric_SetDefault
416 **************************************************************************/
417 IPTR Numeric__MUIM_SetDefault(struct IClass *cl, Object * obj, Msg msg)
419 struct MUI_NumericData *data = INST_DATA(cl, obj);
421 set(obj, MUIA_Numeric_Value, CLAMP(data->defvalue, data->min, data->max));
423 return 0;
426 /**************************************************************************
427 MUIM_Numeric_Stringify
428 **************************************************************************/
429 IPTR Numeric__MUIM_Stringify(struct IClass *cl, Object * obj, struct MUIP_Numeric_Stringify *msg)
431 struct MUI_NumericData *data = INST_DATA(cl, obj);
433 /* TODO: use RawDoFmt() and buffer overrun */
434 snprintf(data->buf, 49, data->format, msg->value);
435 data->buf[49] = 0;
437 return (IPTR)data->buf;
440 /**************************************************************************
441 MUIM_Numeric_ValueToScale
442 **************************************************************************/
443 IPTR Numeric__MUIM_ValueToScale(struct IClass *cl, Object * obj, struct MUIP_Numeric_ValueToScale *msg)
445 LONG val;
446 struct MUI_NumericData *data = INST_DATA(cl, obj);
447 LONG min, max;
449 min = (data->flags & NUMERIC_REVERSE) ? msg->scalemax : msg->scalemin;
450 max = (data->flags & NUMERIC_REVERSE) ? msg->scalemin : msg->scalemax;
452 if (data->max != data->min)
454 val = min + ((data->value - data->min) * (max - min) + (data->max - data->min)/2) / (data->max - data->min);
456 else
458 val = min;
461 val = CLAMP(val, min, max);
463 return val;
466 /**************************************************************************
467 MUIM_Numeric_ValueToScaleExt
468 **************************************************************************/
469 IPTR Numeric__MUIM_ValueToScaleExt(struct IClass *cl, Object * obj, struct MUIP_Numeric_ValueToScaleExt *msg)
471 LONG scale;
472 LONG value;
473 struct MUI_NumericData *data = INST_DATA(cl, obj);
474 LONG min, max;
476 value = CLAMP(msg->value,data->min,data->max);
477 min = (data->flags & NUMERIC_REVERSE) ? msg->scalemax : msg->scalemin;
478 max = (data->flags & NUMERIC_REVERSE) ? msg->scalemin : msg->scalemax;
480 if (data->max != data->min)
482 scale = min + ((value - data->min) * (max - min) + (data->max - data->min)/2) / (data->max - data->min);
484 else
486 scale = min;
489 scale = CLAMP(scale, min, max);
491 return scale;
494 /**************************************************************************
495 MUIM_Export - to export an objects "contents" to a dataspace object.
496 **************************************************************************/
497 IPTR Numeric__MUIM_Export(struct IClass *cl, Object *obj, struct MUIP_Export *msg)
499 struct MUI_NumericData *data = INST_DATA(cl, obj);
500 ULONG id;
502 if ((id = muiNotifyData(obj)->mnd_ObjectID))
504 LONG value = data->value;
505 DoMethod(msg->dataspace, MUIM_Dataspace_Add,
506 (IPTR) &value,
507 sizeof(value),
508 (IPTR) id);
510 return 0;
513 /**************************************************************************
514 MUIM_Import - to import an objects "contents" from a dataspace object.
515 **************************************************************************/
516 IPTR Numeric__MUIM_Import(struct IClass *cl, Object *obj, struct MUIP_Import *msg)
518 ULONG id;
519 LONG *s;
521 if ((id = muiNotifyData(obj)->mnd_ObjectID))
523 if ((s = (LONG*) DoMethod(msg->dataspace, MUIM_Dataspace_Find, (IPTR) id)))
525 set(obj, MUIA_Numeric_Value, *s);
528 return 0;
532 BOOPSI_DISPATCHER(IPTR, Numeric_Dispatcher, cl, obj, msg)
534 switch (msg->MethodID)
536 case OM_NEW: return Numeric__OM_NEW(cl, obj, (APTR)msg);
537 case OM_SET: return Numeric__OM_SET(cl, obj, (APTR)msg);
538 case OM_GET: return Numeric__OM_GET(cl, obj, (APTR)msg);
540 case MUIM_Setup: return Numeric__MUIM_Setup(cl, obj, (APTR)msg);
541 case MUIM_Cleanup: return Numeric__MUIM_Cleanup(cl, obj, (APTR)msg);
542 case MUIM_HandleEvent: return Numeric__MUIM_HandleEvent(cl, obj, (APTR)msg);
543 case MUIM_Numeric_Decrease: return Numeric__MUIM_Decrease(cl, obj, (APTR)msg);
544 case MUIM_Numeric_Increase: return Numeric__MUIM_Increase(cl, obj, (APTR)msg);
545 case MUIM_Numeric_ScaleToValue: return Numeric__MUIM_ScaleToValue(cl, obj, (APTR)msg);
546 case MUIM_Numeric_SetDefault: return Numeric__MUIM_SetDefault(cl, obj, (APTR)msg);
547 case MUIM_Numeric_Stringify: return Numeric__MUIM_Stringify(cl, obj, (APTR)msg);
548 case MUIM_Numeric_ValueToScale: return Numeric__MUIM_ValueToScale(cl, obj, (APTR)msg);
549 case MUIM_Numeric_ValueToScaleExt: return Numeric__MUIM_ValueToScaleExt(cl, obj, (APTR)msg);
550 case MUIM_Export: return Numeric__MUIM_Export(cl, obj, (APTR)msg);
551 case MUIM_Import: return Numeric__MUIM_Import(cl, obj, (APTR)msg);
554 return DoSuperMethodA(cl, obj, msg);
556 BOOPSI_DISPATCHER_END
560 * Class descriptor.
562 const struct __MUIBuiltinClass _MUI_Numeric_desc = {
563 MUIC_Numeric,
564 MUIC_Area,
565 sizeof(struct MUI_NumericData),
566 (void*)Numeric_Dispatcher