Tabs to spaces, more consistent formatting.
[AROS.git] / workbench / libs / muimaster / classes / knob.c
blob8c5ba85cf2dd429763053a6d00a25b290fb90a08
1 /*
2 Copyright © 2002-2003, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define MUIMASTER_YES_INLINE_STDARG
8 #include <exec/memory.h>
9 #include <clib/alib_protos.h>
10 #include <proto/exec.h>
11 #include <proto/dos.h>
12 #include <proto/intuition.h>
13 #include <proto/graphics.h>
14 #include <proto/utility.h>
15 #include <proto/muimaster.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <math.h>
21 #include "mui.h"
22 #include "muimaster_intern.h"
23 #include "support.h"
24 #include "support_classes.h"
25 #include "prefs.h"
26 #include "debug.h"
27 #include "knob_private.h"
29 extern struct Library *MUIMasterBase;
31 #define OUTERFRAME_X 2
32 #define OUTERFRAME_Y 2
33 #define OUTERFRAME_W (OUTERFRAME_X * 2)
34 #define OUTERFRAME_H (OUTERFRAME_Y * 2)
36 #define INNERFRAME_X 2
37 #define INNERFRAME_Y 2
38 #define INNERFRAME_W (INNERFRAME_X * 2)
39 #define INNERFRAME_H (INNERFRAME_Y * 2)
41 #define BORDERSIZE_X 2
42 #define BORDERSIZE_Y 2
43 #define BORDERSIZE_W (BORDERSIZE_X * 2)
44 #define BORDERSIZE_H (BORDERSIZE_Y * 2)
46 #define KNOB_LABEL_SPACING 2
48 #define KNOB_WIDTH 25
49 #define KNOB_HEIGHT 25
51 #define LABEL_HEIGHT 8
53 #define TOTAL_WIDTH OUTERFRAME_W + BORDERSIZE_W + KNOB_WIDTH
54 #define TOTAL_HEIGHT OUTERFRAME_H + BORDERSIZE_H + INNERFRAME_H \
55 + KNOB_HEIGHT + KNOB_LABEL_SPACING + LABEL_HEIGHT
58 /* 0 halfshine */
59 /* 1 halfshadow */
60 /* 2 shadow */
61 /* 3 shine */
63 #define RLE_REP(count, val) (((count - 1) << 4) | val)
65 static const UBYTE knob_rle[] = /* hand-encoded, BTW ;-) */
67 RLE_REP(8,0), RLE_REP(9,1), RLE_REP(8,0),
68 RLE_REP(6,0), RLE_REP(2,1), RLE_REP(9,2), RLE_REP(2,1), RLE_REP(6,0),
69 RLE_REP(5,0), 1, RLE_REP(2,2), RLE_REP(9,3), RLE_REP(2,2), 1, RLE_REP(5,0),
70 RLE_REP(4,0), 1, 2, RLE_REP(13,3), 2, 1, RLE_REP(4,0),
71 RLE_REP(3,0), 1, 2, RLE_REP(3,3), RLE_REP(9,0), RLE_REP(3,3), 2, 3, RLE_REP(3,0),
72 RLE_REP(2,0), 1, 2, RLE_REP(2,3), RLE_REP(13,0), 3, 1, 2, 3, RLE_REP(2,0),
73 0, 1, 2, RLE_REP(2,3), RLE_REP(15,0), RLE_REP(2,1), 2, 3, 0,
74 0, 1, 2, RLE_REP(2,3), RLE_REP(15,0), RLE_REP(2,1), 2, 3, 0,
75 1, 2, RLE_REP(2,3), 0, RLE_REP(16,0), RLE_REP(2,1), 2, 3,
76 1, 2, RLE_REP(2,3), 0, RLE_REP(16,0), RLE_REP(2,1), 2, 3,
77 1, 2, RLE_REP(2,3), 0, RLE_REP(16,0), RLE_REP(2,1), 2, 3,
78 1, 2, RLE_REP(2,3), 0, RLE_REP(16,0), RLE_REP(2,1), 2, 3,
79 1, 2, RLE_REP(2,3), 0, RLE_REP(16,0), RLE_REP(2,1), 2, 3,
80 1, 2, RLE_REP(2,3), 0, RLE_REP(16,0), RLE_REP(2,1), 2, 3,
81 1, 2, RLE_REP(2,3), 0, RLE_REP(16,0), RLE_REP(2,1), 2, 3,
82 1, 2, RLE_REP(2,3), 0, RLE_REP(16,0), RLE_REP(2,1), 2, 3,
83 1, 2, RLE_REP(2,3), 0, RLE_REP(16,0), RLE_REP(2,1), 2, 3,
84 0, 1, 2, RLE_REP(2,3), RLE_REP(15,0), RLE_REP(2,1), 2, 3, 0,
85 0, 1, 2, RLE_REP(2,3), RLE_REP(15,0), RLE_REP(2,1), 2, 3, 0,
86 RLE_REP(2,0), 1, 2, RLE_REP(2,3), RLE_REP(13,0), RLE_REP(2,1), 2, 3, RLE_REP(2,0),
87 RLE_REP(3,0), 1, 2, RLE_REP(3,1), RLE_REP(9,0), RLE_REP(3,1), 2, 3, RLE_REP(3,0),
88 RLE_REP(4,0), 3, 2, RLE_REP(13,1), 2, 3, RLE_REP(4,0),
89 RLE_REP(5,0), 3, RLE_REP(2,2), RLE_REP(9,1), RLE_REP(2,2), 3, RLE_REP(5,0),
90 RLE_REP(6,0), RLE_REP(2,3), RLE_REP(9,2), RLE_REP(2,3), RLE_REP(6,0),
91 RLE_REP(8,0), RLE_REP(9,3), RLE_REP(8,0),
95 IPTR Knob__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
97 obj = (Object *) DoSuperNewTags
98 (cl, obj, NULL,
99 MUIA_FillArea, FALSE, TAG_MORE, (IPTR) msg->ops_AttrList);
101 if (obj)
103 struct Knob_DATA *data = INST_DATA(cl, obj);
105 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS;
106 data->ehn.ehn_Priority = 0;
107 data->ehn.ehn_Flags = 0;
108 data->ehn.ehn_Object = obj;
109 data->ehn.ehn_Class = cl;
113 return (IPTR) obj;
116 IPTR Knob__MUIM_Setup(struct IClass *cl, Object *obj,
117 struct MUIP_Setup *msg)
119 //struct RastPort rp;
120 IPTR retval;
122 retval = DoSuperMethodA(cl, obj, (Msg) msg);
123 if (retval)
125 struct Knob_DATA *data = INST_DATA(cl, obj);
126 #if 0
127 InitRastPort(&rp);
128 SetFont(&rp, _font(obj));
130 DeinitRastPort(&rp);
131 #endif
133 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
134 (IPTR) & data->ehn);
138 return retval;
141 IPTR Knob__MUIM_Cleanup(struct IClass *cl, Object *obj,
142 struct MUIP_Cleanup *msg)
144 struct Knob_DATA *data = INST_DATA(cl, obj);
146 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
148 return DoSuperMethodA(cl, obj, (Msg) msg);
151 /**************************************************************************
152 MUIM_AskMinMax
153 **************************************************************************/
154 IPTR Knob__MUIM_AskMinMax(struct IClass *cl, Object *obj,
155 struct MUIP_AskMinMax *msg)
157 //struct Knob_DATA *data = INST_DATA(cl, obj);
159 DoSuperMethodA(cl, obj, (Msg) msg);
161 msg->MinMaxInfo->MinWidth += TOTAL_WIDTH;
162 msg->MinMaxInfo->MinHeight += TOTAL_HEIGHT;
163 msg->MinMaxInfo->DefWidth += TOTAL_WIDTH;
164 msg->MinMaxInfo->DefHeight += TOTAL_HEIGHT;
165 msg->MinMaxInfo->MaxWidth += TOTAL_WIDTH;
166 msg->MinMaxInfo->MaxHeight += TOTAL_HEIGHT;
168 return TRUE;
171 static void DrawNeedle(Object *obj, struct RastPort *rp, LONG x1, LONG y1,
172 LONG x2, LONG y2, double angle, BOOL clear)
174 LONG cx = (x1 + x2) / 2;
175 LONG cy = (y1 + y2) / 2;
176 LONG rx = cx - x1 - 4;
177 LONG ry = cy - y1 - 4;
178 LONG a, b;
180 SetDrMd(rp, JAM1);
182 if ((angle < 0.0) | (angle > 270.0))
183 angle = 0.0;
184 angle = 270.0 - 45.0 - angle;
186 a = cx + (LONG) (cos(angle * 3.14159265358979323846 / 180.0) * rx);
187 b = cy - (LONG) (sin(angle * 3.14159265358979323846 / 180.0) * ry);
189 if (clear)
191 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
192 RectFill(rp, a - 1, b - 1, a + 1, b + 1);
194 else
196 SetAPen(rp, _pens(obj)[MPEN_SHADOW]);
197 Move(rp, a, b - 1);
198 Draw(rp, a - 1, b);
199 SetAPen(rp, _pens(obj)[MPEN_HALFSHADOW]);
200 Move(rp, a - 1, b - 1);
201 Draw(rp, a, b);
202 SetAPen(rp, _pens(obj)[MPEN_SHINE]);
203 Move(rp, a + 1, b);
204 Draw(rp, a, b + 1);
205 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
206 WritePixel(rp, a + 1, b - 1);
207 WritePixel(rp, a + 1, b + 1);
208 WritePixel(rp, a - 1, b + 1);
214 /**************************************************************************
215 MUIM_Draw
216 **************************************************************************/
217 IPTR Knob__MUIM_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
219 struct Knob_DATA *data = INST_DATA(cl, obj);
220 struct RastPort *rp;
221 WORD x1, y1, x2, y2;
223 DoSuperMethodA(cl, obj, (Msg) msg);
225 if (!(msg->flags & (MADF_DRAWOBJECT | MADF_DRAWUPDATE)))
226 return FALSE;
228 x1 = _mleft(obj);
229 y1 = _mtop(obj);
230 x2 = _mright(obj);
231 y2 = _mbottom(obj);
233 rp = _rp(obj);
235 if (msg->flags & MADF_DRAWOBJECT)
237 /* Transparent edges */
239 DoMethod(obj, MUIM_DrawParentBackground, x1, y1, 2, 1, x1, y1, 0);
240 DoMethod(obj, MUIM_DrawParentBackground, x1, y1 + 1, 1, 1, x1,
241 y1 + 1, 0);
243 DoMethod(obj, MUIM_DrawParentBackground, x2 - 1, y1, 2, 1, x2 - 1,
244 y1, 0);
245 DoMethod(obj, MUIM_DrawParentBackground, x2, y1 + 1, 1, 1, x2,
246 y1 + 1, 0);
248 DoMethod(obj, MUIM_DrawParentBackground, x1, y2, 2, 1, x1, y2, 0);
249 DoMethod(obj, MUIM_DrawParentBackground, x1, y2 - 1, 1, 1, x1,
250 y2 - 1, 0);
252 DoMethod(obj, MUIM_DrawParentBackground, x2 - 1, y2, 2, 1, x2 - 1,
253 y2, 0);
254 DoMethod(obj, MUIM_DrawParentBackground, x2, y2 - 1, 1, 1, x2,
255 y2 - 1, 0);
257 /* Outer frame */
259 SetABPenDrMd(rp, _pens(obj)[MPEN_SHINE], 0, JAM1);
260 Move(rp, x1 + 1, y2 - 1);
261 Draw(rp, x1, y2 - 2);
262 Draw(rp, x1, y1 + 2);
263 Draw(rp, x1 + 2, y1);
264 Draw(rp, x2 - 2, y1);
265 Draw(rp, x2 - 1, y1 + 1);
267 SetAPen(rp, _pens(obj)[MPEN_SHADOW]);
268 Move(rp, x2, y1 + 2);
269 Draw(rp, x2, y2 - 2);
270 Draw(rp, x2 - 2, y2);
271 Draw(rp, x1 + 2, y2);
273 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
274 Move(rp, x1 + 1, y2 - 2);
275 Draw(rp, x1 + 1, y1 + 2);
276 Draw(rp, x1 + 2, y1 + 1);
277 Draw(rp, x2 - 2, y1 + 1);
279 SetAPen(rp, _pens(obj)[MPEN_HALFSHADOW]);
280 Move(rp, x2 - 1, y1 + 2);
281 Draw(rp, x2 - 1, y2 - 2);
282 Draw(rp, x2 - 2, y2 - 1);
283 Draw(rp, x1 + 2, y2 - 1);
285 /* Border */
287 x1 += OUTERFRAME_X;
288 x2 -= OUTERFRAME_X;
289 y1 += OUTERFRAME_X;
290 y2 -= OUTERFRAME_Y;
292 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
293 RectFill(rp, x1, y1, x2, y1 + BORDERSIZE_Y - 1);
294 RectFill(rp, x1, y1 + BORDERSIZE_Y, x1 + BORDERSIZE_X - 1, y2);
295 RectFill(rp, x1 + BORDERSIZE_X - 1, y2 - BORDERSIZE_Y + 1, x2, y2);
296 RectFill(rp, x2 - BORDERSIZE_X + 1, y1 + BORDERSIZE_Y, x2,
297 y2 - BORDERSIZE_Y);
299 /* Inner Frame */
301 x1 += BORDERSIZE_X;
302 x2 -= BORDERSIZE_X;
303 y1 += BORDERSIZE_Y;
304 y2 = y1 + KNOB_HEIGHT - 1;
306 /* Knob bg */
309 static const UBYTE pen_mapping[] = {
310 MPEN_HALFSHINE, MPEN_HALFSHADOW, MPEN_SHADOW, MPEN_SHINE
312 const UBYTE *rleptr;
313 UBYTE rle;
314 WORD x = 0, y = 0, count;
316 for (rleptr = knob_rle;;)
318 rle = *rleptr++;
319 count = (rle >> 4) + 1;
320 SetAPen(_rp(obj), _pens(obj)[pen_mapping[rle & 15]]);
321 RectFill(_rp(obj), x1 + x, y1 + y, x1 + x + count - 1,
322 y1 + y);
323 x += count;
324 if (x >= KNOB_WIDTH)
326 x = 0;
327 y++;
328 if (y >= KNOB_HEIGHT)
329 break;
334 /* Knob-Label spacing */
336 y1 = y2 + 1;
338 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
339 RectFill(rp, x1, y1, x2, y1 + KNOB_LABEL_SPACING - 1);
341 /* Label Frame */
343 y1 += KNOB_LABEL_SPACING;
344 y2 = _mbottom(obj) - OUTERFRAME_Y - BORDERSIZE_Y;
346 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
347 Move(rp, x1, y1);
348 Draw(rp, x1 + 1, y1);
349 Draw(rp, x1, y1 + 1);
350 Move(rp, x2, y1);
351 Draw(rp, x2 - 1, y1);
352 Draw(rp, x2, y1 + 1);
353 Move(rp, x1, y2);
354 Draw(rp, x1 + 1, y2);
355 Draw(rp, x1, y2 - 1);
356 Move(rp, x2, y2);
357 Draw(rp, x2 - 1, y2);
358 Draw(rp, x2, y2 - 1);
360 SetAPen(rp, _pens(obj)[MPEN_HALFSHADOW]);
361 Move(rp, x1 + 1, y2 - 1);
362 Draw(rp, x1, y2 - 2);
363 Draw(rp, x1, y1 + 2);
364 Draw(rp, x1 + 2, y1);
365 Draw(rp, x2 - 2, y1);
366 Draw(rp, x2 - 1, y1 + 1);
368 SetAPen(rp, _pens(obj)[MPEN_SHINE]);
369 Move(rp, x2, y1 + 2);
370 Draw(rp, x2, y2 - 2);
371 Draw(rp, x2 - 2, y2);
372 Draw(rp, x1 + 2, y2);
374 SetAPen(rp, _pens(obj)[MPEN_SHADOW]);
375 RectFill(rp, x1 + 1, y1 + 2, x1 + 1, y2 - 2);
376 RectFill(rp, x2 - 1, y1 + 2, x2 - 1, y2 - 2);
377 RectFill(rp, x1 + 2, y1 + 1, x2 - 2, y1 + 1);
378 RectFill(rp, x1 + 2, y2 - 1, x2 - 2, y2 - 1);
380 /* Label Bg */
382 RectFill(rp, x1 + 2, y1 + 2, x2 - 2, y2 - 2);
386 x1 = _mleft(obj) + OUTERFRAME_X + BORDERSIZE_X;
387 x2 = _mright(obj) - OUTERFRAME_X - BORDERSIZE_X;
388 y1 = _mtop(obj) + OUTERFRAME_Y + BORDERSIZE_Y;
389 y2 = y1 + KNOB_HEIGHT - 1;
391 if (msg->flags & MADF_DRAWUPDATE)
393 DrawNeedle(obj, rp, x1, y1, x2, y2, data->prevangle, TRUE);
396 data->prevangle =
397 (double)DoMethod(obj, MUIM_Numeric_ValueToScale, 0, 270);
399 DrawNeedle(obj, rp, x1, y1, x2, y2, data->prevangle, FALSE);
401 return TRUE;
404 /**************************************************************************
405 MUIM_HandleEvent
406 **************************************************************************/
407 IPTR Knob__MUIM_HandleEvent(struct IClass *cl, Object *obj,
408 struct MUIP_HandleEvent *msg)
410 struct Knob_DATA *data = INST_DATA(cl, obj);
412 if (!msg->imsg)
414 return 0;
417 switch (msg->imsg->Class)
419 case IDCMP_MOUSEBUTTONS:
420 switch (msg->imsg->Code)
422 case SELECTDOWN:
423 if (_between(_left(obj), msg->imsg->MouseX, _right(obj)) &&
424 _between(_top(obj), msg->imsg->MouseY, _bottom(obj)))
426 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
427 (IPTR) & data->ehn);
428 data->ehn.ehn_Events |= IDCMP_MOUSEMOVE;
429 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
430 (IPTR) & data->ehn);
433 break;
435 case SELECTUP:
436 case MENUUP:
437 case MIDDLEUP:
438 default:
439 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
440 (IPTR) & data->ehn);
441 data->ehn.ehn_Events &= ~IDCMP_MOUSEMOVE;
442 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
443 (IPTR) & data->ehn);
444 break;
447 } /* switch(msg->imsg->Code) */
448 break;
450 case IDCMP_MOUSEMOVE:
452 double angle;
453 WORD x1, y1, x2, y2, cx, cy, dx, dy;
454 IPTR val;
456 x1 = _mleft(obj) + OUTERFRAME_X + BORDERSIZE_X;
457 x2 = _mright(obj) - OUTERFRAME_X - BORDERSIZE_X;
458 y1 = _mtop(obj) + OUTERFRAME_Y + BORDERSIZE_Y;
459 y2 = y1 + KNOB_HEIGHT - 1;
460 cx = (x1 + x2) / 2;
461 cy = (y1 + y2) / 2;
462 dx = msg->imsg->MouseX - cx;
463 dy = cy - msg->imsg->MouseY;
465 angle =
466 180.0 - 45.0 + 180.0 * atan2((double)dx,
467 (double)dy) / 3.14159265358979323846;
468 if (angle < 0.0)
469 angle = 0.0;
470 else if (angle > 270.0)
471 angle = 270.0;
473 val =
474 DoMethod(obj, MUIM_Numeric_ScaleToValue, 0, 270,
475 (LONG) angle);
476 set(obj, MUIA_Numeric_Value, val);
479 break;
481 } /* switch(msg->imsg->Class) */
483 return 0;
486 #if ZUNE_BUILTIN_KNOB
487 BOOPSI_DISPATCHER(IPTR, Knob_Dispatcher, cl, obj, msg)
489 switch (msg->MethodID)
491 case OM_NEW:
492 return Knob__OM_NEW(cl, obj, (struct opSet *)msg);
493 case MUIM_Setup:
494 return Knob__MUIM_Setup(cl, obj, (struct MUIP_Setup *)msg);
495 case MUIM_Cleanup:
496 return Knob__MUIM_Cleanup(cl, obj, (struct MUIP_Cleanup *)msg);
497 case MUIM_AskMinMax:
498 return Knob__MUIM_AskMinMax(cl, obj, (struct MUIP_AskMinMax *)msg);
499 case MUIM_Draw:
500 return Knob__MUIM_Draw(cl, obj, (struct MUIP_Draw *)msg);
501 case MUIM_HandleEvent:
502 return Knob__MUIM_HandleEvent(cl, obj,
503 (struct MUIP_HandleEvent *)msg);
504 default:
505 return DoSuperMethodA(cl, obj, msg);
508 BOOPSI_DISPATCHER_END
510 const struct __MUIBuiltinClass _MUI_Knob_desc =
512 MUIC_Knob,
513 MUIC_Numeric,
514 sizeof(struct Knob_DATA),
515 (void *) Knob_Dispatcher
517 #endif /* ZUNE_BUILTIN_KNOB */