Tabs to spaces, more consistent formatting.
[AROS.git] / workbench / libs / muimaster / classes / slider.c
blob727cde2f427bc4a5390ad9d52eaf8e9e114217f1
1 /*
2 Copyright © 1999, David Le Corfec.
3 Copyright © 2002-2011, 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 alignment */
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
48 * since last call of MUIM_Draw */
52 enum slider_flags
54 SLIDER_HORIZ = (1 << 0),
55 SLIDER_QUIET = (1 << 1),
58 #define longget(obj,attr,var) \
59 do \
60 { \
61 IPTR _iptr_var = *(var); \
62 get(obj,attr,&_iptr_var); \
63 *var = (LONG)_iptr_var; \
64 } while(0)
67 Slider.mui/MUIA_Slider_Horiz
68 Slider.mui/MUIA_Slider_Level
69 Slider.mui/MUIA_Slider_Max
70 Slider.mui/MUIA_Slider_Min
71 Slider.mui/MUIA_Slider_Quiet
72 Slider.mui/MUIA_Slider_Reverse d
75 /**************************************************************************
76 OM_NEW
77 **************************************************************************/
78 IPTR Slider__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
80 struct MUI_SliderData *data;
81 struct TagItem *tags, *tag;
82 ULONG flags = SLIDER_HORIZ;
84 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
86 switch (tag->ti_Tag)
88 case MUIA_Group_Horiz:
89 case MUIA_Slider_Horiz:
90 _handle_bool_tag(flags, tag->ti_Data, SLIDER_HORIZ);
91 break;
92 case MUIA_Slider_Quiet:
93 _handle_bool_tag(flags, tag->ti_Data, SLIDER_QUIET);
94 break;
98 obj = (Object *) DoSuperNewTags
100 cl, obj, NULL,
102 MUIA_Background, MUII_SliderBack,
103 MUIA_Font, MUIV_Font_Knob,
104 MUIA_Frame, MUIV_Frame_Slider,
106 TAG_MORE, (IPTR) msg->ops_AttrList
109 if (!obj)
111 return 0;
114 data = INST_DATA(cl, obj);
115 data->flags = flags;
117 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS;
118 data->ehn.ehn_Priority = 0;
119 data->ehn.ehn_Flags = 0;
120 data->ehn.ehn_Object = obj;
121 data->ehn.ehn_Class = cl;
123 return (IPTR) obj;
126 /**************************************************************************
127 MUIM_Show
128 **************************************************************************/
129 IPTR Slider__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
131 struct MUI_SliderData *data = INST_DATA(cl, obj);
132 struct TagItem *tags, *tag;
134 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
136 switch (tag->ti_Tag)
138 case MUIA_Numeric_Value:
139 if (!data->keep_knob_offset)
141 /* reset the offset */
142 data->knob_offset = 0;
144 break;
147 return DoSuperMethodA(cl, obj, (Msg) msg);
150 /**************************************************************************
151 MUIM_Setup
152 **************************************************************************/
153 IPTR Slider__MUIM_Setup(struct IClass *cl, Object *obj,
154 struct MUIP_Setup *msg)
156 struct MUI_SliderData *data = INST_DATA(cl, obj);
157 const struct ZuneFrameGfx *knob_frame;
158 LONG min = 0;
159 LONG max = 0;
160 LONG val;
161 LONG width;
162 struct RastPort rp;
164 if (!DoSuperMethodA(cl, obj, (Msg) msg))
165 return FALSE;
167 knob_frame =
168 zune_zframe_get(obj,
169 &muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob]);
170 data->knob_bg = zune_imspec_setup(MUII_SliderKnob, muiRenderInfo(obj));
172 InitRastPort(&rp);
173 SetFont(&rp, _font(obj));
175 width = 0;
177 longget(obj, MUIA_Numeric_Min, &min);
178 longget(obj, MUIA_Numeric_Max, &max);
180 if ((max - min) > MUI_MAXMAX)
182 min = 0;
183 max = MUI_MAXMAX;
186 /* Determine the width of the knob */
187 for (val = min; val <= max; val++)
189 LONG nw;
190 char *buf;
192 buf = (char *)DoMethod(obj, MUIM_Numeric_Stringify, val);
193 nw = TextLength(&rp, buf, strlen(buf));
194 if (nw > width)
195 width = nw;
197 data->max_text_width = width;
198 data->knob_width = width +
199 knob_frame->ileft +
200 knob_frame->iright +
201 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerLeft +
202 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerRight;
204 data->knob_height = _font(obj)->tf_YSize +
205 knob_frame->itop +
206 knob_frame->ibottom +
207 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerTop +
208 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].innerBottom;
210 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) & data->ehn);
212 return TRUE;
215 /**************************************************************************
216 MUIM_Cleanup
217 **************************************************************************/
218 IPTR Slider__MUIM_Cleanup(struct IClass *cl, Object *obj,
219 struct MUIP_Cleanup *msg)
221 struct MUI_SliderData *data = INST_DATA(cl, obj);
223 if (data->knob_bg)
225 zune_imspec_cleanup(data->knob_bg);
226 data->knob_bg = NULL;
228 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
229 return DoSuperMethodA(cl, obj, (Msg) msg);
232 /**************************************************************************
233 MUIM_AskMinMax
234 **************************************************************************/
235 IPTR Slider__MUIM_AskMinMax(struct IClass *cl, Object *obj,
236 struct MUIP_AskMinMax *msg)
238 struct MUI_SliderData *data = INST_DATA(cl, obj);
239 LONG min = 0, max = 0;
241 DoSuperMethodA(cl, obj, (Msg) msg);
243 longget(obj, MUIA_Numeric_Min, &min);
244 longget(obj, MUIA_Numeric_Max, &max);
246 if (data->flags & SLIDER_HORIZ)
248 msg->MinMaxInfo->MinWidth += data->knob_width + 1;
249 msg->MinMaxInfo->MinHeight += data->knob_height;
250 msg->MinMaxInfo->DefWidth += data->knob_width * 4 + 2;
251 msg->MinMaxInfo->DefHeight += data->knob_height;
252 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
253 msg->MinMaxInfo->MaxHeight += data->knob_height;
255 else
257 msg->MinMaxInfo->MinWidth += data->knob_width;
258 msg->MinMaxInfo->MinHeight += data->knob_height + 1;
259 msg->MinMaxInfo->DefWidth += data->knob_width;
260 msg->MinMaxInfo->DefHeight += data->knob_height * 4 + 2;
261 msg->MinMaxInfo->MaxWidth += data->knob_width;
262 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
265 return TRUE;
268 /**************************************************************************
269 MUIM_Show
270 **************************************************************************/
271 IPTR Slider__MUIM_Show(struct IClass *cl, Object *obj,
272 struct MUIP_Show *msg)
274 struct MUI_SliderData *data = INST_DATA(cl, obj);
276 DoSuperMethodA(cl, obj, (Msg) msg);
277 if (data->knob_bg)
278 zune_imspec_show(data->knob_bg, obj);
279 return 1;
282 /**************************************************************************
283 MUIM_Hide
284 **************************************************************************/
285 IPTR Slider__MUIM_Hide(struct IClass *cl, Object *obj,
286 struct MUIP_Hide *msg)
288 struct MUI_SliderData *data = INST_DATA(cl, obj);
290 if (data->knob_bg)
291 zune_imspec_hide(data->knob_bg);
293 /* This may look ugly when window is resized but it is easier than
294 * recalculating the knob offset in Slider_Show */
295 data->knob_offset = 0;
297 return DoSuperMethodA(cl, obj, (Msg) msg);
301 /**************************************************************************
302 MUIM_Draw
303 **************************************************************************/
304 IPTR Slider__MUIM_Draw(struct IClass *cl, Object *obj,
305 struct MUIP_Draw *msg)
307 struct MUI_SliderData *data = INST_DATA(cl, obj);
308 const struct ZuneFrameGfx *knob_frame;
309 int knob_frame_state;
310 LONG val = 0;
311 char *buf;
312 int width;
314 DoSuperMethodA(cl, obj, (Msg) msg);
316 if (!(msg->flags & (MADF_DRAWOBJECT | MADF_DRAWUPDATE)))
317 return FALSE;
319 if (data->flags & SLIDER_HORIZ)
321 data->knob_top = _mtop(obj);
322 data->knob_left =
323 DoSuperMethod(cl, obj, MUIM_Numeric_ValueToScale, 0,
324 _mwidth(obj) - data->knob_width) + data->knob_offset +
325 _mleft(obj);
327 if (data->knob_left < _mleft(obj))
328 data->knob_left = _mleft(obj);
329 else
331 if (data->knob_left + data->knob_width > _mright(obj))
332 data->knob_left = _mright(obj) - data->knob_width;
335 else
337 data->knob_top =
338 (_mheight(obj) - data->knob_height - DoSuperMethod(cl, obj,
339 MUIM_Numeric_ValueToScale, 0,
340 _mheight(obj) - data->knob_height)) + data->knob_offset +
341 _mtop(obj);
342 data->knob_left = _mleft(obj);
344 if (data->knob_top < _mtop(obj))
345 data->knob_top = _mtop(obj);
346 else
348 if (data->knob_top + data->knob_height > _mbottom(obj))
349 data->knob_top = _mbottom(obj) - data->knob_height;
353 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), _mtop(obj),
354 _mwidth(obj), _mheight(obj), 0, 0, 0);
356 zune_imspec_draw(data->knob_bg, muiRenderInfo(obj),
357 data->knob_left, data->knob_top, data->knob_width,
358 data->knob_height, 0, 0, 0);
360 knob_frame_state =
361 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].state;
362 if (data->state)
363 knob_frame_state ^= 1;
364 knob_frame = zune_zframe_get_with_state(obj,
365 &muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob],
366 knob_frame_state);
367 knob_frame->draw(knob_frame->customframe, muiRenderInfo(obj),
368 data->knob_left, data->knob_top, data->knob_width,
369 data->knob_height, data->knob_left, data->knob_top,
370 data->knob_width, data->knob_height);
372 if (!(data->flags & SLIDER_QUIET))
374 SetFont(_rp(obj), _font(obj));
375 SetABPenDrMd(_rp(obj), _pens(obj)[MPEN_TEXT],
376 _pens(obj)[MPEN_BACKGROUND], JAM1);
377 longget(obj, MUIA_Numeric_Value, &val);
378 buf = (char *)DoMethod(obj, MUIM_Numeric_Stringify, val);
379 width = TextLength(_rp(obj), buf, strlen(buf));
381 Move(_rp(obj),
382 data->knob_left + knob_frame->ileft +
383 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].
384 innerLeft + (data->max_text_width - width) / 2,
385 data->knob_top + _font(obj)->tf_Baseline + knob_frame->itop +
386 muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Knob].
387 innerTop);
388 Text(_rp(obj), buf, strlen(buf));
391 data->same_knop_value = 0;
392 return TRUE;
395 /**************************************************************************
396 MUIM_HandleEvent
397 **************************************************************************/
398 IPTR Slider__MUIM_HandleEvent(struct IClass *cl, Object *obj,
399 struct MUIP_HandleEvent *msg)
401 struct MUI_SliderData *data = INST_DATA(cl, obj);
403 if (!msg->imsg)
404 return 0;
405 switch (msg->imsg->Class)
407 case IDCMP_MOUSEBUTTONS:
408 if (msg->imsg->Code == SELECTDOWN)
410 if (_isinobject(msg->imsg->MouseX, msg->imsg->MouseY))
412 if (data->flags & SLIDER_HORIZ)
414 data->knob_click =
415 msg->imsg->MouseX - data->knob_left + _mleft(obj);
417 else
419 data->knob_click =
420 msg->imsg->MouseY - data->knob_top + _mtop(obj);
421 D(bug("%p: Y=%ld, mtop=%ld mheight=%ld ktop=%ld "
422 "kheight=%ld knob_click=%ld\n",
423 obj, msg->imsg->MouseY, _mtop(obj),
424 _mheight(obj), data->knob_top,
425 data->knob_height, data->knob_click));
428 if (_between(data->knob_left, msg->imsg->MouseX,
429 data->knob_left + data->knob_width)
430 && _between(data->knob_top, msg->imsg->MouseY,
431 data->knob_top + data->knob_height))
433 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
434 (IPTR) & data->ehn);
435 data->ehn.ehn_Events |= IDCMP_MOUSEMOVE;
436 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
437 (IPTR) & data->ehn);
438 data->state = 1;
439 MUI_Redraw(obj, MADF_DRAWUPDATE);
441 else if (((data->flags & SLIDER_HORIZ)
442 && msg->imsg->MouseX < data->knob_left)
443 || (!(data->flags & SLIDER_HORIZ)
444 && msg->imsg->MouseY >
445 data->knob_top + data->knob_height))
447 DoSuperMethod(cl, obj, MUIM_Numeric_Decrease, 1);
449 else
451 DoSuperMethod(cl, obj, MUIM_Numeric_Increase, 1);
455 else
457 if (data->state)
459 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
460 (IPTR) & data->ehn);
461 data->ehn.ehn_Events &= ~IDCMP_MOUSEMOVE;
462 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
463 (IPTR) & data->ehn);
464 data->state = 0;
465 MUI_Redraw(obj, MADF_DRAWUPDATE);
468 break;
470 case IDCMP_MOUSEMOVE:
472 IPTR oldval = 0;
473 LONG newval;
474 LONG pixel;
475 LONG oldko = data->knob_offset;
477 if (data->flags & SLIDER_HORIZ)
479 newval = DoSuperMethod(cl, obj, MUIM_Numeric_ScaleToValue,
480 0, _mwidth(obj) - data->knob_width,
481 msg->imsg->MouseX - data->knob_click);
483 pixel =
484 DoSuperMethod(cl, obj, MUIM_Numeric_ValueToScaleExt,
485 newval, 0,
486 _mwidth(obj) - data->knob_width) + data->knob_click;
487 if (data->knob_offset < 0)
488 data->knob_offset = 0;
489 data->knob_offset = msg->imsg->MouseX - pixel;
490 data->keep_knob_offset = 1;
491 // D(bug("%ld %ld %ld %ld %ld\n", data->knob_offset, pixel,
492 // msg->imsg->MouseX, _mleft(obj), data->knob_click));
494 else
496 LONG scale;
498 scale =
499 _mheight(obj) - data->knob_height + data->knob_click -
500 msg->imsg->MouseY;
501 newval =
502 DoSuperMethod(cl, obj, MUIM_Numeric_ScaleToValue, 0,
503 _mheight(obj) - data->knob_height, scale);
504 pixel =
505 (_mheight(obj) - data->knob_height - DoSuperMethod(cl,
506 obj, MUIM_Numeric_ValueToScaleExt, newval, 0,
507 _mheight(obj) - data->knob_height)) +
508 data->knob_click;
509 data->knob_offset = msg->imsg->MouseY - pixel;
510 data->keep_knob_offset = 1;
511 // D(bug("%0lx: Y=%ld scale=%ld val=%ld pixel: %ld koff: %ld\n",
512 // obj, msg->imsg->MouseY, scale, newval, pixel,
513 // data->knob_offset));
516 get(obj, MUIA_Numeric_Value, &oldval);
517 if ((LONG) oldval != newval)
519 set(obj, MUIA_Numeric_Value, newval);
521 else if (oldko != data->knob_offset)
523 data->same_knop_value = 1;
524 MUI_Redraw(obj, MADF_DRAWUPDATE);
526 data->keep_knob_offset = 0;
528 break;
531 return 0;
534 BOOPSI_DISPATCHER(IPTR, Slider_Dispatcher, cl, obj, msg)
536 switch (msg->MethodID)
538 case OM_NEW:
539 return Slider__OM_NEW(cl, obj, (struct opSet *)msg);
540 case OM_SET:
541 return Slider__OM_SET(cl, obj, (struct opSet *)msg);
542 case MUIM_Setup:
543 return Slider__MUIM_Setup(cl, obj, (APTR) msg);
544 case MUIM_Cleanup:
545 return Slider__MUIM_Cleanup(cl, obj, (APTR) msg);
546 case MUIM_Show:
547 return Slider__MUIM_Show(cl, obj, (APTR) msg);
548 case MUIM_Hide:
549 return Slider__MUIM_Hide(cl, obj, (APTR) msg);
550 case MUIM_AskMinMax:
551 return Slider__MUIM_AskMinMax(cl, obj, (APTR) msg);
552 case MUIM_Draw:
553 return Slider__MUIM_Draw(cl, obj, (APTR) msg);
554 case MUIM_HandleEvent:
555 return Slider__MUIM_HandleEvent(cl, obj, (APTR) msg);
557 return DoSuperMethodA(cl, obj, msg);
559 BOOPSI_DISPATCHER_END
562 * Class descriptor.
564 const struct __MUIBuiltinClass _MUI_Slider_desc =
566 MUIC_Slider,
567 MUIC_Numeric,
568 sizeof(struct MUI_SliderData),
569 (void *) Slider_Dispatcher