revert between 56095 -> 55830 in arch
[AROS.git] / workbench / libs / muimaster / classes / slider.c
blobc3ec69dc7d949464c8807566147483f6da6aac4c
1 /*
2 Copyright © 1999, David Le Corfec.
3 Copyright © 2002-2018, 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\n", __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)\n", __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 IPTR result = 0;
428 BOOL increase;
430 if (!msg->imsg)
431 return 0;
432 switch (msg->imsg->Class)
434 case IDCMP_MOUSEBUTTONS:
435 if (msg->imsg->Code == SELECTDOWN)
437 if (_isinobject(obj, msg->imsg->MouseX, msg->imsg->MouseY)
438 && (msg->imsg->Qualifier
439 & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) == 0)
441 if (data->flags & SLIDER_HORIZ)
443 data->knob_click =
444 msg->imsg->MouseX - data->knob_offset - _mleft(obj);
446 else
448 data->knob_click =
449 msg->imsg->MouseY - data->knob_offset - _mtop(obj);
452 if (_between(data->knob_left, msg->imsg->MouseX,
453 data->knob_left + data->knob_width)
454 && _between(data->knob_top, msg->imsg->MouseY,
455 data->knob_top + data->knob_height))
457 /* Clicked on knob */
458 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
459 (IPTR) & data->ehn);
460 data->ehn.ehn_Events |= IDCMP_MOUSEMOVE;
461 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
462 (IPTR) & data->ehn);
463 set(obj, MUIA_Pressed, TRUE);
464 MUI_Redraw(obj, MADF_DRAWUPDATE);
466 else
468 /* Clicked on background */
469 if (data->flags & SLIDER_HORIZ)
470 increase = msg->imsg->MouseX > data->knob_left;
471 else
472 increase = msg->imsg->MouseY > data->knob_top;
474 if (XGET(obj, MUIA_Numeric_Reverse))
475 increase = !increase;
477 DoMethod(obj, increase ?
478 MUIM_Numeric_Increase : MUIM_Numeric_Decrease, 1);
480 result = MUI_EventHandlerRC_Eat;
483 else
485 if (XGET(obj, MUIA_Pressed))
487 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
488 (IPTR) & data->ehn);
489 data->ehn.ehn_Events &= ~IDCMP_MOUSEMOVE;
490 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
491 (IPTR) & data->ehn);
492 set(obj, MUIA_Pressed, FALSE);
493 MUI_Redraw(obj, MADF_DRAWUPDATE);
494 result = MUI_EventHandlerRC_Eat;
497 break;
499 case IDCMP_MOUSEMOVE:
501 IPTR oldval = 0;
502 LONG newval;
503 LONG old_offset = data->knob_offset;
505 if (data->flags & SLIDER_HORIZ)
506 data->knob_offset =
507 msg->imsg->MouseX - data->knob_click - _mleft(obj);
508 else
509 data->knob_offset =
510 msg->imsg->MouseY - data->knob_click - _mtop(obj);
512 /* Ensure knob offset is within range */
513 if (data->knob_offset < 0)
514 data->knob_offset = 0;
515 else if (data->knob_offset > data->scale_length)
516 data->knob_offset = data->scale_length;
518 newval = DoMethod(obj, MUIM_Numeric_ScaleToValue,
519 0, data->scale_length, data->knob_offset);
521 if (data->knob_offset != old_offset)
523 get(obj, MUIA_Numeric_Value, &oldval);
524 if ((LONG) oldval != newval)
526 /* Bypass our own set method so that knob position is not
527 * reset */
528 struct TagItem superSetTags[] =
530 { MUIA_Numeric_Value, newval },
531 { TAG_DONE, 0 }
533 struct opSet superSet =
535 .MethodID = OM_SET,
536 .ops_AttrList = superSetTags,
537 .ops_GInfo = NULL
539 data->flags &= ~SLIDER_VALIDSTRING;
540 DoSuperMethodA(cl, obj, (Msg)&superSet);
542 else
543 MUI_Redraw(obj, MADF_DRAWUPDATE);
544 result = MUI_EventHandlerRC_Eat;
547 break;
550 return result;
553 BOOPSI_DISPATCHER(IPTR, Slider_Dispatcher, cl, obj, msg)
555 switch (msg->MethodID)
557 case OM_NEW:
558 return Slider__OM_NEW(cl, obj, (struct opSet *)msg);
559 case OM_SET:
560 return Slider__OM_SET(cl, obj, (struct opSet *)msg);
561 case OM_GET:
562 return Slider__OM_GET(cl, obj, (struct opGet *)msg);
563 case MUIM_Setup:
564 return Slider__MUIM_Setup(cl, obj, (APTR) msg);
565 case MUIM_Cleanup:
566 return Slider__MUIM_Cleanup(cl, obj, (APTR) msg);
567 case MUIM_Show:
568 return Slider__MUIM_Show(cl, obj, (APTR) msg);
569 case MUIM_Hide:
570 return Slider__MUIM_Hide(cl, obj, (APTR) msg);
571 case MUIM_AskMinMax:
572 return Slider__MUIM_AskMinMax(cl, obj, (APTR) msg);
573 case MUIM_Draw:
574 return Slider__MUIM_Draw(cl, obj, (APTR) msg);
575 case MUIM_HandleEvent:
576 return Slider__MUIM_HandleEvent(cl, obj, (APTR) msg);
578 return DoSuperMethodA(cl, obj, msg);
580 BOOPSI_DISPATCHER_END
583 * Class descriptor.
585 const struct __MUIBuiltinClass _MUI_Slider_desc =
587 MUIC_Slider,
588 MUIC_Numeric,
589 sizeof(struct MUI_SliderData),
590 (void *) Slider_Dispatcher