Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / libs / muimaster / classes / knob.c
blob64341edc74d7f67282b86b9978d173a1e4824ece
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 + KNOB_HEIGHT + KNOB_LABEL_SPACING + LABEL_HEIGHT
57 /* 0 halfshine */
58 /* 1 halfshadow */
59 /* 2 shadow */
60 /* 3 shine */
62 #define RLE_REP(count, val) (((count - 1) << 4) | val)
64 static const UBYTE knob_rle[] = /* hand-encoded, BTW ;-) */
66 RLE_REP(8,0), RLE_REP(9,1), RLE_REP(8,0),
67 RLE_REP(6,0), RLE_REP(2,1), RLE_REP(9,2), RLE_REP(2,1), RLE_REP(6,0),
68 RLE_REP(5,0), 1, RLE_REP(2,2), RLE_REP(9,3), RLE_REP(2,2), 1, RLE_REP(5,0),
69 RLE_REP(4,0), 1, 2, RLE_REP(13,3), 2, 1, RLE_REP(4,0),
70 RLE_REP(3,0), 1, 2, RLE_REP(3,3), RLE_REP(9,0), RLE_REP(3,3), 2, 3, RLE_REP(3,0),
71 RLE_REP(2,0), 1, 2, RLE_REP(2,3), RLE_REP(13,0), 3, 1, 2, 3, RLE_REP(2,0),
72 0, 1, 2, RLE_REP(2,3), RLE_REP(15,0), RLE_REP(2,1), 2, 3, 0,
73 0, 1, 2, RLE_REP(2,3), RLE_REP(15,0), RLE_REP(2,1), 2, 3, 0,
74 1, 2, RLE_REP(2,3), 0, RLE_REP(16,0), RLE_REP(2,1), 2, 3,
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 0, 1, 2, RLE_REP(2,3), RLE_REP(15,0), RLE_REP(2,1), 2, 3, 0,
84 0, 1, 2, RLE_REP(2,3), RLE_REP(15,0), RLE_REP(2,1), 2, 3, 0,
85 RLE_REP(2,0), 1, 2, RLE_REP(2,3), RLE_REP(13,0), RLE_REP(2,1), 2, 3, RLE_REP(2,0),
86 RLE_REP(3,0), 1, 2, RLE_REP(3,1), RLE_REP(9,0), RLE_REP(3,1), 2, 3, RLE_REP(3,0),
87 RLE_REP(4,0), 3, 2, RLE_REP(13,1), 2, 3, RLE_REP(4,0),
88 RLE_REP(5,0), 3, RLE_REP(2,2), RLE_REP(9,1), RLE_REP(2,2), 3, RLE_REP(5,0),
89 RLE_REP(6,0), RLE_REP(2,3), RLE_REP(9,2), RLE_REP(2,3), RLE_REP(6,0),
90 RLE_REP(8,0), RLE_REP(9,3), RLE_REP(8,0),
94 IPTR Knob__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
96 obj = (Object *)DoSuperNewTags
98 cl, obj, NULL,
99 MUIA_FillArea, FALSE,
100 TAG_MORE, (IPTR) msg->ops_AttrList
103 if (obj)
105 struct Knob_DATA *data = INST_DATA(cl, obj);
107 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS;
108 data->ehn.ehn_Priority = 0;
109 data->ehn.ehn_Flags = 0;
110 data->ehn.ehn_Object = obj;
111 data->ehn.ehn_Class = cl;
115 return (IPTR)obj;
118 IPTR Knob__MUIM_Setup(struct IClass *cl, Object *obj, struct MUIP_Setup *msg)
120 //struct RastPort rp;
121 IPTR retval;
123 retval = DoSuperMethodA(cl, obj, (Msg)msg);
124 if (retval)
126 struct Knob_DATA *data = INST_DATA(cl, obj);
127 #if 0
128 InitRastPort(&rp);
129 SetFont(&rp,_font(obj));
131 DeinitRastPort(&rp);
132 #endif
134 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
138 return retval;
141 IPTR Knob__MUIM_Cleanup(struct IClass *cl, Object *obj, struct MUIP_Cleanup *msg)
143 struct Knob_DATA *data = INST_DATA(cl, obj);
145 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
147 return DoSuperMethodA(cl, obj, (Msg)msg);
150 /**************************************************************************
151 MUIM_AskMinMax
152 **************************************************************************/
153 IPTR Knob__MUIM_AskMinMax(struct IClass *cl, Object *obj, struct MUIP_AskMinMax *msg)
155 //struct Knob_DATA *data = INST_DATA(cl, obj);
157 DoSuperMethodA(cl, obj, (Msg)msg);
159 msg->MinMaxInfo->MinWidth += TOTAL_WIDTH;
160 msg->MinMaxInfo->MinHeight += TOTAL_HEIGHT;
161 msg->MinMaxInfo->DefWidth += TOTAL_WIDTH;
162 msg->MinMaxInfo->DefHeight += TOTAL_HEIGHT;
163 msg->MinMaxInfo->MaxWidth += TOTAL_WIDTH;
164 msg->MinMaxInfo->MaxHeight += TOTAL_HEIGHT;
166 return TRUE;
169 static void DrawNeedle(Object *obj, struct RastPort *rp, LONG x1, LONG y1,
170 LONG x2, LONG y2, double angle, BOOL clear)
172 LONG cx = (x1 + x2) / 2;
173 LONG cy = (y1 + y2) / 2;
174 LONG rx = cx - x1 - 4;
175 LONG ry = cy - y1 - 4;
176 LONG a, b;
178 SetDrMd(rp, JAM1);
180 if ((angle < 0.0) | (angle > 270.0)) angle = 0.0;
181 angle = 270.0 - 45.0 - angle;
183 a = cx + (LONG)(cos(angle * 3.14159265358979323846 / 180.0) * rx);
184 b = cy - (LONG)(sin(angle * 3.14159265358979323846 / 180.0) * ry);
186 if (clear)
188 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
189 RectFill(rp, a - 1, b - 1, a + 1, b + 1);
191 else
193 SetAPen(rp, _pens(obj)[MPEN_SHADOW]);
194 Move(rp, a, b - 1); Draw(rp, a - 1, b);
195 SetAPen(rp, _pens(obj)[MPEN_HALFSHADOW]);
196 Move(rp, a - 1, b - 1); Draw(rp, a, b);
197 SetAPen(rp, _pens(obj)[MPEN_SHINE]);
198 Move(rp, a + 1, b); Draw(rp, a, b + 1);
199 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
200 WritePixel(rp, a + 1, b - 1);
201 WritePixel(rp, a + 1, b + 1);
202 WritePixel(rp, a - 1, b + 1);
208 /**************************************************************************
209 MUIM_Draw
210 **************************************************************************/
211 IPTR Knob__MUIM_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
213 struct Knob_DATA *data = INST_DATA(cl, obj);
214 struct RastPort *rp;
215 WORD x1, y1, x2, y2;
217 DoSuperMethodA(cl,obj,(Msg)msg);
219 if (!(msg->flags & (MADF_DRAWOBJECT | MADF_DRAWUPDATE)))
220 return FALSE;
222 x1 = _mleft(obj);
223 y1 = _mtop(obj);
224 x2 = _mright(obj);
225 y2 = _mbottom(obj);
227 rp = _rp(obj);
229 if (msg->flags & MADF_DRAWOBJECT)
231 /* Transparent edges */
233 DoMethod(obj, MUIM_DrawParentBackground, x1, y1, 2, 1, x1, y1, 0);
234 DoMethod(obj, MUIM_DrawParentBackground, x1, y1 + 1, 1, 1, x1, y1 + 1, 0);
236 DoMethod(obj, MUIM_DrawParentBackground, x2 - 1, y1, 2, 1, x2 - 1, y1, 0);
237 DoMethod(obj, MUIM_DrawParentBackground, x2, y1 + 1, 1, 1, x2, y1 + 1, 0);
239 DoMethod(obj, MUIM_DrawParentBackground, x1, y2, 2, 1, x1, y2, 0);
240 DoMethod(obj, MUIM_DrawParentBackground, x1, y2 - 1, 1, 1, x1, y2 - 1, 0);
242 DoMethod(obj, MUIM_DrawParentBackground, x2 - 1, y2, 2, 1, x2 - 1, y2, 0);
243 DoMethod(obj, MUIM_DrawParentBackground, x2, y2 - 1, 1, 1, x2, y2 - 1, 0);
245 /* Outer frame */
247 SetABPenDrMd(rp, _pens(obj)[MPEN_SHINE], 0, JAM1);
248 Move(rp, x1 + 1, y2 - 1);
249 Draw(rp, x1, y2 - 2);
250 Draw(rp, x1, y1 + 2);
251 Draw(rp, x1 + 2, y1);
252 Draw(rp, x2 - 2, y1);
253 Draw(rp, x2 - 1, y1 + 1);
255 SetAPen(rp, _pens(obj)[MPEN_SHADOW]);
256 Move(rp, x2, y1 + 2);
257 Draw(rp, x2, y2 - 2);
258 Draw(rp, x2 - 2, y2);
259 Draw(rp, x1 + 2, y2);
261 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
262 Move(rp, x1 + 1, y2 - 2);
263 Draw(rp, x1 + 1, y1 + 2);
264 Draw(rp, x1 + 2, y1 + 1);
265 Draw(rp, x2 - 2, y1 + 1);
267 SetAPen(rp, _pens(obj)[MPEN_HALFSHADOW]);
268 Move(rp, x2 - 1, y1 + 2);
269 Draw(rp, x2 - 1, y2 - 2);
270 Draw(rp, x2 - 2, y2 - 1);
271 Draw(rp, x1 + 2, y2 - 1);
273 /* Border */
275 x1 += OUTERFRAME_X; x2 -= OUTERFRAME_X;
276 y1 += OUTERFRAME_X; y2 -= OUTERFRAME_Y;
278 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
279 RectFill(rp, x1, y1, x2, y1 + BORDERSIZE_Y - 1);
280 RectFill(rp, x1, y1 + BORDERSIZE_Y, x1 + BORDERSIZE_X - 1, y2);
281 RectFill(rp, x1 + BORDERSIZE_X - 1, y2 - BORDERSIZE_Y + 1, x2, y2);
282 RectFill(rp, x2 - BORDERSIZE_X + 1, y1 + BORDERSIZE_Y, x2, y2 - BORDERSIZE_Y);
284 /* Inner Frame */
286 x1 += BORDERSIZE_X; x2 -= BORDERSIZE_X;
287 y1 += BORDERSIZE_Y; y2 = y1 + KNOB_HEIGHT -1;
289 /* Knob bg */
292 static const UBYTE pen_mapping[] =
294 MPEN_HALFSHINE, MPEN_HALFSHADOW, MPEN_SHADOW, MPEN_SHINE
296 const UBYTE *rleptr;
297 UBYTE rle;
298 WORD x = 0, y = 0, count;
300 for(rleptr = knob_rle; ;)
302 rle = *rleptr++;
303 count = (rle >> 4) + 1;
304 SetAPen(_rp(obj), _pens(obj)[pen_mapping[rle & 15]]);
305 RectFill(_rp(obj), x1 + x, y1 + y, x1 + x + count - 1, y1 + y);
306 x += count;
307 if (x >= KNOB_WIDTH)
309 x = 0;
310 y++;
311 if (y >= KNOB_HEIGHT) break;
316 /* Knob-Label spacing */
318 y1 = y2 + 1;
320 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
321 RectFill(rp, x1, y1, x2, y1 + KNOB_LABEL_SPACING - 1);
323 /* Label Frame */
325 y1 += KNOB_LABEL_SPACING;
326 y2 = _mbottom(obj) - OUTERFRAME_Y - BORDERSIZE_Y;
328 SetAPen(rp, _pens(obj)[MPEN_HALFSHINE]);
329 Move(rp, x1, y1); Draw(rp, x1 + 1, y1); Draw(rp, x1, y1 + 1);
330 Move(rp, x2, y1); Draw(rp, x2 - 1, y1); Draw(rp, x2, y1 + 1);
331 Move(rp, x1, y2); Draw(rp, x1 + 1, y2); Draw(rp, x1, y2 - 1);
332 Move(rp, x2, y2); Draw(rp, x2 - 1, y2); Draw(rp, x2, y2 - 1);
334 SetAPen(rp, _pens(obj)[MPEN_HALFSHADOW]);
335 Move(rp, x1 + 1, y2 - 1);
336 Draw(rp, x1, y2 - 2);
337 Draw(rp, x1, y1 + 2);
338 Draw(rp, x1 + 2, y1);
339 Draw(rp, x2 - 2, y1);
340 Draw(rp, x2 - 1, y1 + 1);
342 SetAPen(rp, _pens(obj)[MPEN_SHINE]);
343 Move(rp, x2, y1 + 2);
344 Draw(rp, x2, y2 - 2);
345 Draw(rp, x2 - 2, y2);
346 Draw(rp, x1 + 2, y2);
348 SetAPen(rp, _pens(obj)[MPEN_SHADOW]);
349 RectFill(rp, x1 + 1, y1 + 2, x1 + 1, y2 - 2);
350 RectFill(rp, x2 - 1, y1 + 2, x2 - 1, y2 - 2);
351 RectFill(rp, x1 + 2, y1 + 1, x2 - 2, y1 + 1);
352 RectFill(rp, x1 + 2, y2 - 1, x2 - 2, y2 - 1);
354 /* Label Bg */
356 RectFill(rp, x1 + 2, y1 +2, x2 - 2, y2 - 2);
360 x1 = _mleft(obj) + OUTERFRAME_X + BORDERSIZE_X;
361 x2 = _mright(obj) - OUTERFRAME_X - BORDERSIZE_X;
362 y1 = _mtop(obj) + OUTERFRAME_Y + BORDERSIZE_Y;
363 y2 = y1 + KNOB_HEIGHT - 1;
365 if (msg->flags & MADF_DRAWUPDATE)
367 DrawNeedle(obj, rp, x1, y1, x2, y2, data->prevangle, TRUE);
370 data->prevangle = (double)DoMethod(obj, MUIM_Numeric_ValueToScale, 0, 270);
372 DrawNeedle(obj, rp, x1, y1, x2, y2, data->prevangle, FALSE);
374 return TRUE;
377 /**************************************************************************
378 MUIM_HandleEvent
379 **************************************************************************/
380 IPTR Knob__MUIM_HandleEvent(struct IClass *cl, Object *obj, struct MUIP_HandleEvent *msg)
382 struct Knob_DATA *data = INST_DATA(cl, obj);
384 if (!msg->imsg)
386 return 0;
389 switch(msg->imsg->Class)
391 case IDCMP_MOUSEBUTTONS:
392 switch(msg->imsg->Code)
394 case SELECTDOWN:
395 if (_between(_left(obj), msg->imsg->MouseX, _right(obj)) &&
396 _between(_top(obj), msg->imsg->MouseY, _bottom(obj)))
398 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
399 data->ehn.ehn_Events |= IDCMP_MOUSEMOVE;
400 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
403 break;
405 case SELECTUP:
406 case MENUUP:
407 case MIDDLEUP:
408 default:
409 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
410 data->ehn.ehn_Events &= ~IDCMP_MOUSEMOVE;
411 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
412 break;
415 } /* switch(msg->imsg->Code) */
416 break;
418 case IDCMP_MOUSEMOVE:
420 double angle;
421 WORD x1, y1, x2, y2, cx, cy, dx, dy;
422 IPTR val;
424 x1 = _mleft(obj) + OUTERFRAME_X + BORDERSIZE_X;
425 x2 = _mright(obj) - OUTERFRAME_X - BORDERSIZE_X;
426 y1 = _mtop(obj) + OUTERFRAME_Y + BORDERSIZE_Y;
427 y2 = y1 + KNOB_HEIGHT - 1;
428 cx = (x1 + x2) / 2;
429 cy = (y1 + y2) / 2;
430 dx = msg->imsg->MouseX - cx;
431 dy = cy - msg->imsg->MouseY;
433 angle = 180.0 - 45.0 + 180.0 * atan2((double)dx, (double)dy) / 3.14159265358979323846;
434 if (angle < 0.0) angle = 0.0; else if (angle > 270.0) angle = 270.0;
436 val = DoMethod(obj, MUIM_Numeric_ScaleToValue, 0, 270, (LONG)angle);
437 set(obj, MUIA_Numeric_Value, val);
440 break;
442 } /* switch(msg->imsg->Class) */
444 return 0;
447 #if ZUNE_BUILTIN_KNOB
448 BOOPSI_DISPATCHER(IPTR, Knob_Dispatcher, cl, obj, msg)
450 switch (msg->MethodID)
452 case OM_NEW: return Knob__OM_NEW(cl, obj, (struct opSet *)msg);
453 case MUIM_Setup: return Knob__MUIM_Setup(cl, obj, (struct MUIP_Setup *)msg);
454 case MUIM_Cleanup: return Knob__MUIM_Cleanup(cl, obj, (struct MUIP_Cleanup *)msg);
455 case MUIM_AskMinMax: return Knob__MUIM_AskMinMax(cl, obj, (struct MUIP_AskMinMax *)msg);
456 case MUIM_Draw: return Knob__MUIM_Draw(cl, obj, (struct MUIP_Draw *)msg);
457 case MUIM_HandleEvent: return Knob__MUIM_HandleEvent(cl, obj, (struct MUIP_HandleEvent *)msg);
458 default: return DoSuperMethodA(cl, obj, msg);
461 BOOPSI_DISPATCHER_END
463 const struct __MUIBuiltinClass _MUI_Knob_desc =
465 MUIC_Knob,
466 MUIC_Numeric,
467 sizeof(struct Knob_DATA),
468 (void*)Knob_Dispatcher
470 #endif /* ZUNE_BUILTIN_KNOB */