minor simplification.
[AROS.git] / workbench / libs / muimaster / classes / slider.c
blob596b62c06ee12dfabaf88acfd42964cb4141ba02
1 /*
2 Copyright © 1999, David Le Corfec.
3 Copyright © 2002-2013, 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;
37 LONG scale_length;
38 LONG knob_length;
39 LONG knob_left;
40 LONG knob_top;
41 LONG knob_width;
42 LONG knob_height;
43 LONG knob_click;
44 UWORD max_text_width;
45 CONST_STRPTR text_buffer;
46 UWORD text_width;
47 UWORD text_length;
51 enum slider_flags
53 SLIDER_HORIZ = (1 << 0),
54 SLIDER_QUIET = (1 << 1),
55 SLIDER_VALIDOFFSET = (1 << 2),
56 SLIDER_VALIDSTRING = (1 << 3),
59 #define longget(obj,attr,var) \
60 do \
61 { \
62 IPTR _iptr_var = *(var); \
63 get(obj,attr,&_iptr_var); \
64 *var = (LONG)_iptr_var; \
65 } while(0)
68 static void CalcKnobDimensions(struct IClass *cl, Object *obj)
70 struct MUI_SliderData *data = INST_DATA(cl, obj);
71 const struct ZuneFrameGfx *knob_frame;
72 LONG min = 0;
73 LONG max = 0;
74 LONG val;
75 LONG width;
76 struct RastPort rp;
78 knob_frame =
79 zune_zframe_get(obj,
80 &muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob]);
82 InitRastPort(&rp);
83 SetFont(&rp, _font(obj));
85 width = 0;
87 longget(obj, MUIA_Numeric_Min, &min);
88 longget(obj, MUIA_Numeric_Max, &max);
90 if ((max - min) > MUI_MAXMAX)
92 min = 0;
93 max = MUI_MAXMAX;
96 /* Determine the width of the knob */
97 for (val = min; val <= max; val++)
99 LONG nw;
100 char *buf;
102 buf = (char *)DoMethod(obj, MUIM_Numeric_Stringify, val);
103 nw = TextLength(&rp, buf, strlen(buf));
104 if (nw > width)
105 width = nw;
107 data->max_text_width = width;
108 data->knob_width = width +
109 knob_frame->ileft +
110 knob_frame->iright +
111 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerLeft +
112 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerRight;
114 data->knob_height = _font(obj)->tf_YSize +
115 knob_frame->itop +
116 knob_frame->ibottom +
117 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerTop +
118 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerBottom;
120 if (data->flags & SLIDER_HORIZ)
121 data->knob_length = data->knob_width;
122 else
123 data->knob_length = data->knob_height;
126 /**************************************************************************
127 OM_NEW
128 **************************************************************************/
129 IPTR Slider__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
131 struct MUI_SliderData *data;
132 struct TagItem *tags, *tag;
133 ULONG flags = SLIDER_HORIZ;
135 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
137 switch (tag->ti_Tag)
139 case MUIA_Slider_Horiz:
140 _handle_bool_tag(flags, tag->ti_Data, SLIDER_HORIZ);
141 break;
142 case MUIA_Slider_Quiet:
143 _handle_bool_tag(flags, tag->ti_Data, SLIDER_QUIET);
144 break;
148 obj = (Object *) DoSuperNewTags
150 cl, obj, NULL,
152 MUIA_Background, MUII_SliderBack,
153 MUIA_Font, MUIV_Font_Knob,
154 MUIA_Frame, MUIV_Frame_Slider,
156 TAG_MORE, (IPTR) msg->ops_AttrList
159 if (!obj)
161 return 0;
164 data = INST_DATA(cl, obj);
165 data->flags = flags;
167 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS;
168 data->ehn.ehn_Priority = 0;
169 data->ehn.ehn_Flags = 0;
170 data->ehn.ehn_Object = obj;
171 data->ehn.ehn_Class = cl;
173 return (IPTR) obj;
176 /**************************************************************************
177 OM_SET
178 **************************************************************************/
179 IPTR Slider__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
181 struct MUI_SliderData *data = INST_DATA(cl, obj);
182 struct TagItem *tags, *tag;
184 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
186 switch (tag->ti_Tag)
188 case MUIA_Slider_Horiz:
189 _handle_bool_tag(data->flags, tag->ti_Data, SLIDER_HORIZ);
190 CalcKnobDimensions(cl, obj);
191 data->flags &= ~(SLIDER_VALIDOFFSET | SLIDER_VALIDSTRING);
192 MUI_Redraw(obj, MADF_DRAWOBJECT);
193 break;
194 case MUIA_Numeric_Value:
195 case MUIA_Numeric_Min:
196 case MUIA_Numeric_Max:
197 case MUIA_Numeric_Format:
198 /* reset the knob position and string */
199 data->flags &= ~(SLIDER_VALIDOFFSET | SLIDER_VALIDSTRING);
200 break;
203 return DoSuperMethodA(cl, obj, (Msg) msg);
206 /**************************************************************************
207 OM_GET
208 **************************************************************************/
209 IPTR Slider__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
211 struct MUI_SliderData *data = INST_DATA(cl, obj);
212 IPTR *store = msg->opg_Storage;
214 switch (msg->opg_AttrID)
216 case MUIA_Slider_Horiz:
217 *store = ((data->flags & SLIDER_HORIZ) != 0);
218 return TRUE;
221 return DoSuperMethodA(cl, obj, (Msg) msg);
224 /**************************************************************************
225 MUIM_Setup
226 **************************************************************************/
227 IPTR Slider__MUIM_Setup(struct IClass *cl, Object *obj,
228 struct MUIP_Setup *msg)
230 struct MUI_SliderData *data = INST_DATA(cl, obj);
232 if (!DoSuperMethodA(cl, obj, (Msg) msg))
233 return FALSE;
235 data->knob_bg = zune_imspec_setup(MUII_SliderKnob, muiRenderInfo(obj));
237 CalcKnobDimensions(cl, obj);
239 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) & data->ehn);
241 return TRUE;
244 /**************************************************************************
245 MUIM_Cleanup
246 **************************************************************************/
247 IPTR Slider__MUIM_Cleanup(struct IClass *cl, Object *obj,
248 struct MUIP_Cleanup *msg)
250 struct MUI_SliderData *data = INST_DATA(cl, obj);
252 if (data->knob_bg)
254 zune_imspec_cleanup(data->knob_bg);
255 data->knob_bg = NULL;
257 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
259 return DoSuperMethodA(cl, obj, (Msg) msg);
262 /**************************************************************************
263 MUIM_AskMinMax
264 **************************************************************************/
265 IPTR Slider__MUIM_AskMinMax(struct IClass *cl, Object *obj,
266 struct MUIP_AskMinMax *msg)
268 struct MUI_SliderData *data = INST_DATA(cl, obj);
269 LONG min = 0, max = 0;
271 DoSuperMethodA(cl, obj, (Msg) msg);
273 longget(obj, MUIA_Numeric_Min, &min);
274 longget(obj, MUIA_Numeric_Max, &max);
276 if (data->flags & SLIDER_HORIZ)
278 msg->MinMaxInfo->MinWidth += data->knob_width + 1;
279 msg->MinMaxInfo->MinHeight += data->knob_height;
280 msg->MinMaxInfo->DefWidth += data->knob_width * 4 + 2;
281 msg->MinMaxInfo->DefHeight += data->knob_height;
282 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
283 msg->MinMaxInfo->MaxHeight += data->knob_height;
285 else
287 msg->MinMaxInfo->MinWidth += data->knob_width;
288 msg->MinMaxInfo->MinHeight += data->knob_height + 1;
289 msg->MinMaxInfo->DefWidth += data->knob_width;
290 msg->MinMaxInfo->DefHeight += data->knob_height * 4 + 2;
291 msg->MinMaxInfo->MaxWidth += data->knob_width;
292 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
295 return TRUE;
298 /**************************************************************************
299 MUIM_Show
300 **************************************************************************/
301 IPTR Slider__MUIM_Show(struct IClass *cl, Object *obj,
302 struct MUIP_Show *msg)
304 struct MUI_SliderData *data = INST_DATA(cl, obj);
306 DoSuperMethodA(cl, obj, (Msg) msg);
307 if (data->knob_bg)
308 zune_imspec_show(data->knob_bg, obj);
309 return 1;
312 /**************************************************************************
313 MUIM_Hide
314 **************************************************************************/
315 IPTR Slider__MUIM_Hide(struct IClass *cl, Object *obj,
316 struct MUIP_Hide *msg)
318 struct MUI_SliderData *data = INST_DATA(cl, obj);
320 if (data->knob_bg)
321 zune_imspec_hide(data->knob_bg);
323 /* This may look ugly when window is resized but it is easier than
324 * recalculating the knob offset in the Show method */
325 data->flags &= ~SLIDER_VALIDOFFSET;
327 return DoSuperMethodA(cl, obj, (Msg) msg);
331 /**************************************************************************
332 MUIM_Draw
333 **************************************************************************/
334 IPTR Slider__MUIM_Draw(struct IClass *cl, Object *obj,
335 struct MUIP_Draw *msg)
337 struct MUI_SliderData *data = INST_DATA(cl, obj);
338 const struct ZuneFrameGfx *knob_frame;
339 UWORD knob_frame_state;
340 LONG val = 0;
342 D(bug("[slider] %s: obj @ 0x%p", __func__, obj);)
344 DoSuperMethodA(cl, obj, (Msg) msg);
346 if (!(msg->flags & (MADF_DRAWOBJECT | MADF_DRAWUPDATE)))
347 return FALSE;
349 D(bug("[slider] %s: %d,%d->%d,%d (%d,%d)", __func__, _mleft(obj), _mtop(obj), _mright(obj), _mbottom(obj), _mwidth(obj), _mheight(obj));)
351 if (data->flags & SLIDER_HORIZ)
352 data->scale_length = _mwidth(obj);
353 else
354 data->scale_length = _mheight(obj);
355 data->scale_length -= data->knob_length;
357 /* Update knob position if not cached */
358 if (!(data->flags & SLIDER_VALIDOFFSET))
360 data->knob_offset =
361 DoMethod(obj, MUIM_Numeric_ValueToScale, 0,
362 data->scale_length);
363 data->flags |= SLIDER_VALIDOFFSET;
366 data->knob_top = _mtop(obj);
367 data->knob_left = _mleft(obj);
368 if (data->flags & SLIDER_HORIZ)
369 data->knob_left += data->knob_offset;
370 else
371 data->knob_top += data->knob_offset;
373 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), _mtop(obj),
374 _mwidth(obj), _mheight(obj), 0, 0, 0);
376 zune_imspec_draw(data->knob_bg, muiRenderInfo(obj),
377 data->knob_left, data->knob_top, data->knob_width,
378 data->knob_height, 0, 0, 0);
380 knob_frame_state =
381 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].state;
382 if (XGET(obj, MUIA_Pressed))
383 knob_frame_state ^= 1;
384 knob_frame = zune_zframe_get_with_state(obj,
385 &muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob],
386 knob_frame_state);
387 knob_frame->draw(knob_frame->customframe, muiRenderInfo(obj),
388 data->knob_left, data->knob_top, data->knob_width,
389 data->knob_height, data->knob_left, data->knob_top,
390 data->knob_width, data->knob_height);
392 if (!(data->flags & SLIDER_QUIET))
394 SetFont(_rp(obj), _font(obj));
395 SetABPenDrMd(_rp(obj), _pens(obj)[MPEN_TEXT],
396 _pens(obj)[MPEN_BACKGROUND], JAM1);
397 if (!(data->flags & SLIDER_VALIDSTRING))
399 longget(obj, MUIA_Numeric_Value, &val);
400 data->text_buffer = (CONST_STRPTR) DoMethod(obj,
401 MUIM_Numeric_Stringify, val);
402 data->text_length = strlen(data->text_buffer);
403 data->text_width =
404 TextLength(_rp(obj), data->text_buffer, data->text_length);
405 data->flags |= SLIDER_VALIDSTRING;
408 Move(_rp(obj),
409 data->knob_left + knob_frame->ileft +
410 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerLeft +
411 (data->max_text_width - data->text_width) / 2,
412 data->knob_top + _font(obj)->tf_Baseline + knob_frame->itop +
413 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerTop);
414 Text(_rp(obj), data->text_buffer, data->text_length);
417 return TRUE;
420 /**************************************************************************
421 MUIM_HandleEvent
422 **************************************************************************/
423 IPTR Slider__MUIM_HandleEvent(struct IClass *cl, Object *obj,
424 struct MUIP_HandleEvent *msg)
426 struct MUI_SliderData *data = INST_DATA(cl, obj);
427 BOOL increase;
429 if (!msg->imsg)
430 return 0;
431 switch (msg->imsg->Class)
433 case IDCMP_MOUSEBUTTONS:
434 if (msg->imsg->Code == SELECTDOWN)
436 if (_isinobject(obj, msg->imsg->MouseX, msg->imsg->MouseY)
437 && (msg->imsg->Qualifier
438 & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) == 0)
440 if (data->flags & SLIDER_HORIZ)
442 data->knob_click =
443 msg->imsg->MouseX - data->knob_offset - _mleft(obj);
445 else
447 data->knob_click =
448 msg->imsg->MouseY - data->knob_offset - _mtop(obj);
451 if (_between(data->knob_left, msg->imsg->MouseX,
452 data->knob_left + data->knob_width)
453 && _between(data->knob_top, msg->imsg->MouseY,
454 data->knob_top + data->knob_height))
456 /* Clicked on knob */
457 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
458 (IPTR) & data->ehn);
459 data->ehn.ehn_Events |= IDCMP_MOUSEMOVE;
460 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
461 (IPTR) & data->ehn);
462 set(obj, MUIA_Pressed, TRUE);
463 MUI_Redraw(obj, MADF_DRAWUPDATE);
465 else
467 /* Clicked on background */
468 if (data->flags & SLIDER_HORIZ)
469 increase = msg->imsg->MouseX > data->knob_left;
470 else
471 increase = msg->imsg->MouseY > data->knob_top;
473 if (XGET(obj, MUIA_Numeric_Reverse))
474 increase = !increase;
476 DoMethod(obj, increase ?
477 MUIM_Numeric_Increase : MUIM_Numeric_Decrease, 1);
481 else
483 if (XGET(obj, MUIA_Pressed))
485 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
486 (IPTR) & data->ehn);
487 data->ehn.ehn_Events &= ~IDCMP_MOUSEMOVE;
488 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
489 (IPTR) & data->ehn);
490 set(obj, MUIA_Pressed, FALSE);
491 MUI_Redraw(obj, MADF_DRAWUPDATE);
494 break;
496 case IDCMP_MOUSEMOVE:
498 IPTR oldval = 0;
499 LONG newval;
500 LONG old_offset = data->knob_offset;
502 if (data->flags & SLIDER_HORIZ)
503 data->knob_offset =
504 msg->imsg->MouseX - data->knob_click - _mleft(obj);
505 else
506 data->knob_offset =
507 msg->imsg->MouseY - data->knob_click - _mtop(obj);
509 /* Ensure knob offset is within range */
510 if (data->knob_offset < 0)
511 data->knob_offset = 0;
512 else if (data->knob_offset > data->scale_length)
513 data->knob_offset = data->scale_length;
515 newval = DoMethod(obj, MUIM_Numeric_ScaleToValue,
516 0, data->scale_length, data->knob_offset);
518 if (data->knob_offset != old_offset)
520 get(obj, MUIA_Numeric_Value, &oldval);
521 if ((LONG) oldval != newval)
523 /* Bypass our own set method so that knob position is not
524 * reset */
525 data->flags &= ~SLIDER_VALIDSTRING;
526 IPTR tag_list[] = {MUIA_Numeric_Value, newval, TAG_END};
527 DoSuperMethod(cl, obj, OM_SET, tag_list, NULL);
529 else
530 MUI_Redraw(obj, MADF_DRAWUPDATE);
533 break;
536 return 0;
539 BOOPSI_DISPATCHER(IPTR, Slider_Dispatcher, cl, obj, msg)
541 switch (msg->MethodID)
543 case OM_NEW:
544 return Slider__OM_NEW(cl, obj, (struct opSet *)msg);
545 case OM_SET:
546 return Slider__OM_SET(cl, obj, (struct opSet *)msg);
547 case OM_GET:
548 return Slider__OM_GET(cl, obj, (struct opGet *)msg);
549 case MUIM_Setup:
550 return Slider__MUIM_Setup(cl, obj, (APTR) msg);
551 case MUIM_Cleanup:
552 return Slider__MUIM_Cleanup(cl, obj, (APTR) msg);
553 case MUIM_Show:
554 return Slider__MUIM_Show(cl, obj, (APTR) msg);
555 case MUIM_Hide:
556 return Slider__MUIM_Hide(cl, obj, (APTR) msg);
557 case MUIM_AskMinMax:
558 return Slider__MUIM_AskMinMax(cl, obj, (APTR) msg);
559 case MUIM_Draw:
560 return Slider__MUIM_Draw(cl, obj, (APTR) msg);
561 case MUIM_HandleEvent:
562 return Slider__MUIM_HandleEvent(cl, obj, (APTR) msg);
564 return DoSuperMethodA(cl, obj, msg);
566 BOOPSI_DISPATCHER_END
569 * Class descriptor.
571 const struct __MUIBuiltinClass _MUI_Slider_desc =
573 MUIC_Slider,
574 MUIC_Numeric,
575 sizeof(struct MUI_SliderData),
576 (void *) Slider_Dispatcher