Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / libs / muimaster / classes / slider.c
blobcc5f30bccc9f7b2033dbf7d54da161a90808ba74
1 /*
2 Copyright 1999, David Le Corfec.
3 Copyright 2002-2006, The AROS Development Team.
4 All rights reserved.
6 $Id$
7 */
9 #include <string.h>
11 #include <clib/alib_protos.h>
12 #include <clib/macros.h>
14 #include <proto/exec.h>
15 #include <proto/intuition.h>
16 #include <proto/graphics.h>
17 #include <proto/utility.h>
18 #include <proto/muimaster.h>
20 /*#define MYDEBUG 1*/
21 #include "debug.h"
23 #include "support.h"
24 #include "mui.h"
25 #include "muimaster_intern.h"
26 #include "prefs.h"
27 #include "imspec.h"
29 extern struct Library *MUIMasterBase;
31 struct MUI_SliderData
33 ULONG flags;
34 struct MUI_EventHandlerNode ehn;
35 struct MUI_ImageSpec_intern *knob_bg;
36 LONG knob_offset; /* current pixel offest for fine algiment */
37 LONG knob_left;
38 LONG knob_top;
39 LONG knob_width;
40 LONG knob_height;
41 LONG knob_click;
42 LONG last_val;
43 LONG max_text_width;
44 LONG state; /* When using mouse */
45 int keep_knob_offset;
47 int same_knop_value; /* 1 if the knob value didn't change in since last call of MUIM_Draw */
51 enum slider_flags {
52 SLIDER_HORIZ = (1<<0),
53 SLIDER_QUIET = (1<<1),
56 #define longget(obj,attr,var) \
57 do \
58 { \
59 IPTR _iptr_var = *(var); \
60 get(obj,attr,&_iptr_var); \
61 *var = (LONG)_iptr_var; \
62 } while(0)
65 Slider.mui/MUIA_Slider_Horiz
66 Slider.mui/MUIA_Slider_Level
67 Slider.mui/MUIA_Slider_Max
68 Slider.mui/MUIA_Slider_Min
69 Slider.mui/MUIA_Slider_Quiet
70 Slider.mui/MUIA_Slider_Reverse d
73 /**************************************************************************
74 OM_NEW
75 **************************************************************************/
76 IPTR Slider__OM_NEW(struct IClass *cl, Object * obj, struct opSet *msg)
78 struct MUI_SliderData *data;
79 struct TagItem *tags, *tag;
80 ULONG flags = SLIDER_HORIZ;
82 for (tags = msg->ops_AttrList; (tag = NextTagItem((const struct TagItem **)&tags));)
84 switch (tag->ti_Tag)
86 case MUIA_Group_Horiz:
87 case MUIA_Slider_Horiz:
88 _handle_bool_tag(flags, tag->ti_Data, SLIDER_HORIZ);
89 break;
90 case MUIA_Slider_Quiet:
91 _handle_bool_tag(flags, tag->ti_Data, SLIDER_QUIET);
92 break;
96 obj = (Object *) DoSuperNewTags
98 cl, obj, NULL,
100 MUIA_Background, MUII_SliderBack,
101 MUIA_Font, MUIV_Font_Knob,
102 MUIA_Frame, MUIV_Frame_Slider,
104 TAG_MORE, (IPTR) msg->ops_AttrList
107 if (!obj)
109 return 0;
112 data = INST_DATA(cl, obj);
113 data->flags = flags;
115 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS;
116 data->ehn.ehn_Priority = 0;
117 data->ehn.ehn_Flags = 0;
118 data->ehn.ehn_Object = obj;
119 data->ehn.ehn_Class = cl;
121 return (IPTR)obj;
124 /**************************************************************************
125 MUIM_Show
126 **************************************************************************/
127 IPTR Slider__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
129 struct MUI_SliderData *data = INST_DATA(cl, obj);
130 struct TagItem *tags, *tag;
132 for (tags = msg->ops_AttrList; (tag = NextTagItem((const struct TagItem **)&tags));)
134 switch (tag->ti_Tag)
136 case MUIA_Numeric_Value:
137 if (!data->keep_knob_offset)
139 /* reset the offset */
140 data->knob_offset = 0;
142 break;
145 return DoSuperMethodA(cl,obj,(Msg)msg);
148 /**************************************************************************
149 MUIM_Setup
150 **************************************************************************/
151 IPTR Slider__MUIM_Setup(struct IClass *cl, Object *obj, struct MUIP_Setup *msg)
153 struct MUI_SliderData *data = INST_DATA(cl, obj);
154 const struct ZuneFrameGfx *knob_frame;
155 LONG min;
156 LONG max;
157 LONG val;
158 LONG width;
159 struct RastPort rp;
161 if (!DoSuperMethodA(cl,obj,(Msg)msg))
162 return FALSE;
164 knob_frame = zune_zframe_get(obj, &muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob]);
165 data->knob_bg = zune_imspec_setup(MUII_SliderKnob, muiRenderInfo(obj));
167 InitRastPort(&rp);
168 SetFont(&rp,_font(obj));
170 width = 0;
172 longget(obj,MUIA_Numeric_Min,&min);
173 longget(obj,MUIA_Numeric_Max,&max);
175 if ((max - min) > MUI_MAXMAX)
177 min = 0;
178 max = MUI_MAXMAX;
181 /* Determine the width of the knob */
182 for (val=min;val<=max;val++)
184 LONG nw;
185 char *buf;
187 buf = (char*)DoMethod(obj,MUIM_Numeric_Stringify,val);
188 nw = TextLength(&rp,buf,strlen(buf));
189 if (nw > width) width = nw;
191 data->max_text_width = width;
192 data->knob_width = width +
193 knob_frame->ileft +
194 knob_frame->iright +
195 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerLeft +
196 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerRight;
198 data->knob_height = _font(obj)->tf_YSize +
199 knob_frame->itop +
200 knob_frame->ibottom +
201 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerTop +
202 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerBottom;
204 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
206 DeinitRastPort(&rp);
208 return TRUE;
211 /**************************************************************************
212 MUIM_Cleanup
213 **************************************************************************/
214 IPTR Slider__MUIM_Cleanup(struct IClass *cl, Object *obj, struct MUIP_Cleanup *msg)
216 struct MUI_SliderData *data = INST_DATA(cl, obj);
218 if (data->knob_bg)
220 zune_imspec_cleanup(data->knob_bg);
221 data->knob_bg = NULL;
223 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
224 return DoSuperMethodA(cl,obj,(Msg)msg);
227 /**************************************************************************
228 MUIM_AskMinMax
229 **************************************************************************/
230 IPTR Slider__MUIM_AskMinMax(struct IClass *cl, Object *obj, struct MUIP_AskMinMax *msg)
232 struct MUI_SliderData *data = INST_DATA(cl, obj);
233 LONG min,max;
235 DoSuperMethodA(cl, obj, (Msg)msg);
237 longget(obj,MUIA_Numeric_Min,&min);
238 longget(obj,MUIA_Numeric_Max,&max);
240 if (data->flags & SLIDER_HORIZ)
242 msg->MinMaxInfo->MinWidth += data->knob_width + 1;
243 msg->MinMaxInfo->MinHeight += data->knob_height;
244 msg->MinMaxInfo->DefWidth += data->knob_width * 4 + 2;
245 msg->MinMaxInfo->DefHeight += data->knob_height;
246 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
247 msg->MinMaxInfo->MaxHeight += data->knob_height;
249 else
251 msg->MinMaxInfo->MinWidth += data->knob_width;
252 msg->MinMaxInfo->MinHeight += data->knob_height + 1;
253 msg->MinMaxInfo->DefWidth += data->knob_width;
254 msg->MinMaxInfo->DefHeight += data->knob_height * 4 + 2;
255 msg->MinMaxInfo->MaxWidth += data->knob_width;
256 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
259 return TRUE;
262 /**************************************************************************
263 MUIM_Show
264 **************************************************************************/
265 IPTR Slider__MUIM_Show(struct IClass *cl, Object *obj, struct MUIP_Show *msg)
267 struct MUI_SliderData *data = INST_DATA(cl, obj);
269 DoSuperMethodA(cl,obj,(Msg)msg);
270 if (data->knob_bg)
271 zune_imspec_show(data->knob_bg, obj);
272 return 1;
275 /**************************************************************************
276 MUIM_Hide
277 **************************************************************************/
278 IPTR Slider__MUIM_Hide(struct IClass *cl, Object *obj,struct MUIP_Hide *msg)
280 struct MUI_SliderData *data = INST_DATA(cl, obj);
282 if (data->knob_bg)
283 zune_imspec_hide(data->knob_bg);
285 /* This may look ugly when window is resized but it is easier than recalculating
286 * the knob offset in Slider_Show */
287 data->knob_offset = 0;
289 return DoSuperMethodA(cl,obj,(Msg)msg);
293 /**************************************************************************
294 MUIM_Draw
295 **************************************************************************/
296 IPTR Slider__MUIM_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
298 struct MUI_SliderData *data = INST_DATA(cl, obj);
299 const struct ZuneFrameGfx *knob_frame;
300 int knob_frame_state;
301 LONG val;
302 char *buf;
303 int width;
305 DoSuperMethodA(cl,obj,(Msg)msg);
307 if (!(msg->flags & (MADF_DRAWOBJECT | MADF_DRAWUPDATE)))
308 return FALSE;
310 if (data->flags & SLIDER_HORIZ)
312 data->knob_top = _mtop(obj);
313 data->knob_left = DoSuperMethod(cl, obj,MUIM_Numeric_ValueToScale, 0, _mwidth(obj) - data->knob_width) + data->knob_offset + _mleft(obj);
315 if (data->knob_left < _mleft(obj)) data->knob_left = _mleft(obj);
316 else
318 if (data->knob_left + data->knob_width > _mright(obj))
319 data->knob_left = _mright(obj) - data->knob_width;
322 else
324 data->knob_top = (_mheight(obj) - data->knob_height - DoSuperMethod(cl, obj,MUIM_Numeric_ValueToScale, 0, _mheight(obj) - data->knob_height)) + data->knob_offset + _mtop(obj);
325 data->knob_left = _mleft(obj);
327 if (data->knob_top < _mtop(obj)) data->knob_top = _mtop(obj);
328 else
330 if (data->knob_top + data->knob_height > _mbottom(obj))
331 data->knob_top = _mbottom(obj) - data->knob_height;
335 DoMethod(obj,MUIM_DrawBackground,_mleft(obj),_mtop(obj),_mwidth(obj),_mheight(obj),0,0,0);
337 zune_imspec_draw(data->knob_bg, muiRenderInfo(obj),
338 data->knob_left, data->knob_top, data->knob_width, data->knob_height,
339 0, 0, 0);
341 knob_frame_state = muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].state;
342 if (data->state)
343 knob_frame_state ^= 1;
344 knob_frame = zune_zframe_get_with_state(obj,
345 &muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob], knob_frame_state);
346 knob_frame->draw(knob_frame->customframe, muiRenderInfo(obj), data->knob_left, data->knob_top, data->knob_width,
347 data->knob_height, data->knob_left, data->knob_top, data->knob_width,
348 data->knob_height);
350 SetFont(_rp(obj),_font(obj));
351 SetABPenDrMd(_rp(obj),_pens(obj)[MPEN_TEXT],_pens(obj)[MPEN_BACKGROUND],JAM1);
352 longget(obj, MUIA_Numeric_Value, &val);
353 buf = (char*)DoMethod(obj,MUIM_Numeric_Stringify,val);
354 width = TextLength(_rp(obj),buf,strlen(buf));
356 Move(_rp(obj),
357 data->knob_left + knob_frame->ileft +
358 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerLeft +
359 (data->max_text_width - width) / 2,
360 data->knob_top + _font(obj)->tf_Baseline + knob_frame->itop +
361 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerTop);
362 Text(_rp(obj), buf, strlen(buf));
364 data->same_knop_value = 0;
365 return TRUE;
368 /**************************************************************************
369 MUIM_HandleEvent
370 **************************************************************************/
371 IPTR Slider__MUIM_HandleEvent(struct IClass *cl, Object *obj, struct MUIP_HandleEvent *msg)
373 struct MUI_SliderData *data = INST_DATA(cl, obj);
375 if (!msg->imsg)
376 return 0;
377 switch (msg->imsg->Class)
379 case IDCMP_MOUSEBUTTONS:
380 if (msg->imsg->Code == SELECTDOWN)
382 if (_isinobject(msg->imsg->MouseX, msg->imsg->MouseY))
384 if (data->flags & SLIDER_HORIZ)
386 data->knob_click = msg->imsg->MouseX - data->knob_left + _mleft(obj);
388 else
390 data->knob_click = msg->imsg->MouseY - data->knob_top + _mtop(obj) ;
391 D(bug("%p: Y=%ld, mtop=%ld mheight=%ld ktop=%ld kheight=%ld knob_click=%ld\n",
392 obj, msg->imsg->MouseY, _mtop(obj), _mheight(obj),
393 data->knob_top, data->knob_height, data->knob_click));
396 if (_between(data->knob_left, msg->imsg->MouseX, data->knob_left + data->knob_width)
397 && _between(data->knob_top, msg->imsg->MouseY, data->knob_top + data->knob_height))
399 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
400 data->ehn.ehn_Events |= IDCMP_MOUSEMOVE;
401 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
402 data->state = 1;
403 MUI_Redraw(obj,MADF_DRAWUPDATE);
405 else if (((data->flags & SLIDER_HORIZ)
406 && msg->imsg->MouseX < data->knob_left)
407 || (!(data->flags & SLIDER_HORIZ)
408 && msg->imsg->MouseY > data->knob_top + data->knob_height))
410 DoSuperMethod(cl, obj, MUIM_Numeric_Decrease, 1);
412 else
414 DoSuperMethod(cl, obj, MUIM_Numeric_Increase, 1);
418 else /* msg->imsg->Code != SELECTDOWN */
420 if (data->state)
422 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
423 data->ehn.ehn_Events &= ~IDCMP_MOUSEMOVE;
424 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
425 data->state = 0;
426 MUI_Redraw(obj,MADF_DRAWUPDATE);
428 } /* if (msg->imsg->Code == SELECTDOWN) */
429 break;
431 case IDCMP_MOUSEMOVE:
433 IPTR oldval;
434 LONG newval;
435 LONG pixel;
436 LONG oldko = data->knob_offset;
438 if (data->flags & SLIDER_HORIZ)
440 newval = DoSuperMethod(cl, obj, MUIM_Numeric_ScaleToValue,
441 0, _mwidth(obj) - data->knob_width,
442 msg->imsg->MouseX - data->knob_click);
444 pixel = DoSuperMethod(cl, obj,MUIM_Numeric_ValueToScaleExt, newval, 0, _mwidth(obj) - data->knob_width) + data->knob_click;
445 if (data->knob_offset < 0) data->knob_offset = 0;
446 data->knob_offset = msg->imsg->MouseX - pixel;
447 data->keep_knob_offset = 1;
448 // D(bug("%ld %ld %ld %ld %ld\n",data->knob_offset, pixel, msg->imsg->MouseX, _mleft(obj), data->knob_click));
450 else
452 LONG scale;
454 scale = _mheight(obj) - data->knob_height + data->knob_click - msg->imsg->MouseY;
455 newval = DoSuperMethod(cl, obj, MUIM_Numeric_ScaleToValue,
456 0, _mheight(obj) - data->knob_height,
457 scale);
458 pixel = (_mheight(obj) - data->knob_height - DoSuperMethod(cl, obj, MUIM_Numeric_ValueToScaleExt, newval, 0, _mheight(obj) - data->knob_height)) + data->knob_click;
459 data->knob_offset = msg->imsg->MouseY - pixel;
460 data->keep_knob_offset = 1;
461 // D(bug("%0lx: Y=%ld scale=%ld val=%ld pixel: %ld koff: %ld\n", obj, msg->imsg->MouseY, scale, newval, pixel, data->knob_offset));
464 get(obj, MUIA_Numeric_Value, &oldval);
465 if ((LONG)oldval != newval)
467 set(obj, MUIA_Numeric_Value, newval);
468 } else if (oldko != data->knob_offset)
470 data->same_knop_value = 1;
471 MUI_Redraw(obj, MADF_DRAWUPDATE);
473 data->keep_knob_offset = 0;
475 break;
478 return 0;
481 BOOPSI_DISPATCHER(IPTR, Slider_Dispatcher, cl, obj, msg)
483 switch (msg->MethodID)
485 case OM_NEW: return Slider__OM_NEW(cl, obj, (struct opSet *)msg);
486 case OM_SET: return Slider__OM_SET(cl, obj, (struct opSet *)msg);
487 case MUIM_Setup: return Slider__MUIM_Setup(cl, obj, (APTR)msg);
488 case MUIM_Cleanup: return Slider__MUIM_Cleanup(cl, obj, (APTR)msg);
489 case MUIM_Show: return Slider__MUIM_Show(cl, obj, (APTR)msg);
490 case MUIM_Hide: return Slider__MUIM_Hide(cl, obj, (APTR)msg);
491 case MUIM_AskMinMax: return Slider__MUIM_AskMinMax(cl, obj, (APTR)msg);
492 case MUIM_Draw: return Slider__MUIM_Draw(cl, obj, (APTR)msg);
493 case MUIM_HandleEvent: return Slider__MUIM_HandleEvent(cl, obj, (APTR)msg);
495 return DoSuperMethodA(cl, obj, msg);
497 BOOPSI_DISPATCHER_END
501 * Class descriptor.
503 const struct __MUIBuiltinClass _MUI_Slider_desc = {
504 MUIC_Slider,
505 MUIC_Numeric,
506 sizeof(struct MUI_SliderData),
507 (void*)Slider_Dispatcher