revert between 56095 -> 55830 in arch
[AROS.git] / workbench / classes / gadgets / arospalette / paletteclass.c
blob91172ec768bee92bed90e262806756cead207891
1 /*
2 Copyright © 1995-2005, The AROS Development Team. All rights reserved.
3 $Id$
5 AROS Palette gadget for use in gadtools.
6 */
8 #define USE_BOOPSI_STUBS
9 #include <proto/utility.h>
10 #include <proto/intuition.h>
11 #include <proto/graphics.h>
12 #include <intuition/classes.h>
13 #include <intuition/classusr.h>
14 #include <intuition/cghooks.h>
15 #include <intuition/gadgetclass.h>
16 #include <utility/tagitem.h>
17 #include <gadgets/arospalette.h>
18 #include <aros/asmcall.h>
19 #include <stdlib.h> /* abs() */
20 #include "arospalette_intern.h"
22 #define SDEBUG 0
23 #define DEBUG 0
24 #include <aros/debug.h>
26 #define AROSPaletteBase ((struct PaletteBase_intern *)(cl->cl_UserData))
28 #include <clib/boopsistubs.h>
31 STATIC IPTR _OM_SET(Class *cl, Object *o, struct opSet *msg, BOOL render)
33 struct TagItem *tag, *tstate;
34 IPTR retval = (IPTR)0;
35 struct PaletteData *data = INST_DATA(cl, o);
37 BOOL labelplace_set = FALSE, relayout = FALSE;
38 BOOL colortag_found = FALSE, numcolorstag_found = FALSE;
40 EnterFunc(bug("Palette::Set()\n"));
42 for (tstate = msg->ops_AttrList; (tag = NextTagItem(&tstate)); )
44 IPTR tidata = tag->ti_Data;
47 switch (tag->ti_Tag)
49 case AROSA_Palette_Depth: /* [ISU] */
50 /* NumColors tag overrides Depth tag! */
51 if (!numcolorstag_found)
53 data->pd_NumColors = (1 << ((UBYTE)tidata));
55 D(bug("Depth initialized to %d\n", tidata));
56 relayout = TRUE;
57 retval++;
59 break;
61 case AROSA_Palette_Color: /* [IS] */
62 colortag_found = TRUE;
64 data->pd_OldColor = data->pd_Color;
65 data->pd_Color = (UBYTE)tidata;
66 D(bug("Color set to %d\n", tidata));
67 retval++;
68 break;
70 case AROSA_Palette_ColorOffset: /* [I] */
71 data->pd_ColorOffset = (UBYTE)tidata;
72 D(bug("ColorOffset initialized to %d\n", tidata));
73 retval++;
74 break;
76 case AROSA_Palette_IndicatorWidth: /* [I] */
77 data->pd_IndWidth = (UWORD)tidata;
78 D(bug("Indicatorwidth set to %d\n", tidata));
80 /* If palette has an indictor on left, GA_LabelPlace
81 ** defaults to GV_LabelPlace_Left
83 if (!labelplace_set)
84 data->pd_LabelPlace = GV_LabelPlace_Left;
85 break;
87 case AROSA_Palette_IndicatorHeight: /* [I] */
88 data->pd_IndHeight = (UWORD)tidata;
89 D(bug("Indicatorheight set to %d\n", tidata));
90 break;
92 case GA_LabelPlace: /* [I] */
93 data->pd_LabelPlace = (LONG)tidata;
94 D(bug("Labelplace set to %d\n", tidata));
96 labelplace_set = TRUE;
97 break;
99 case GA_TextAttr: /* [I] */
100 data->pd_TAttr = (struct TextAttr *)tidata;
101 D(bug("TextAttr set to %s %d\n",
102 data->pd_TAttr->ta_Name, data->pd_TAttr->ta_YSize));
103 break;
105 case AROSA_Palette_ColorTable:
106 data->pd_ColorTable = (UBYTE *)tidata;
107 break;
109 case AROSA_Palette_NumColors:
110 numcolorstag_found = TRUE;
112 data->pd_NumColors = (UWORD)tidata;
113 relayout = TRUE;
114 break;
116 } /* switch (tag->ti_Tag) */
118 } /* for (each attr in attrlist) */
120 if (colortag_found)
122 /* convert pen number to index */
124 if (data->pd_ColorTable)
126 WORD i;
128 /* convert pen number to index number */
129 for(i = 0; i < data->pd_NumColors; i++)
131 if (data->pd_ColorTable[i] == data->pd_Color)
133 data->pd_Color = i;
134 break;
138 } else {
139 data->pd_Color -= data->pd_ColorOffset;
142 } /* if (colortag_found) */
144 if (relayout)
146 /* Check if the old selected fits into the new depth */
147 if (data->pd_Color > data->pd_NumColors - 1)
149 data->pd_Color = 0;
150 data->pd_OldColor = 0; /* So that UpdateActiveColor() don't get confused */
153 /* Relayout the gadget */
154 DoMethod(o, GM_LAYOUT, (IPTR)msg->ops_GInfo, FALSE);
157 if ( render )
159 struct GadgetInfo *gi = ((struct opSet *)msg)->ops_GInfo;
161 if (gi)
163 struct RastPort *rp = ObtainGIRPort(gi);
165 if (rp)
167 DoMethod(o,
168 GM_RENDER,
169 (IPTR)gi,
170 (IPTR)rp,
171 FindTagItem(GA_Disabled, ((struct opSet *)msg)->ops_AttrList) ? GREDRAW_REDRAW : GREDRAW_UPDATE
174 ReleaseGIRPort(rp);
179 ReturnPtr ("Palette::Set", IPTR, retval);
182 /************************
183 ** Palette::Update() **
184 ************************/
185 IPTR AROSPalette__OM_UPDATE(Class *cl, Object *o, struct opSet *msg)
187 IPTR retval = DoSuperMethodA(cl, o, msg);
188 /* Only rerender when we are not subclassed */
189 return retval + _OM_SET(cl, o, msg, cl == OCLASS(o));
192 /*********************
193 ** Palette::Set() **
194 *********************/
195 IPTR AROSPalette__OM_SET(Class *cl, Object *o, struct opSet *msg)
197 IPTR retval = DoSuperMethodA(cl, o, msg);
198 /* Always rerender for the OM_SET method */
199 return retval + _OM_SET(cl, o, msg, TRUE);
202 /*********************
203 ** Palette::New() **
204 *********************/
205 Object *AROSPalette__OM_NEW(Class *cl, Object *o, struct opSet *msg)
207 struct opSet ops, *p_ops = &ops;
208 struct TagItem tags[] =
210 {GA_RelSpecial, TRUE},
211 {TAG_MORE, 0}
214 EnterFunc(bug("Palette::New()\n"));
216 tags[1].ti_Data = (IPTR)msg->ops_AttrList;
218 ops.MethodID = OM_NEW;
219 ops.ops_GInfo = NULL;
220 ops.ops_AttrList = &tags[0];
222 o = (Object *)DoSuperMethodA(cl, o, (Msg)p_ops);
223 if (o)
225 struct PaletteData *data = INST_DATA(cl, o);
227 /* Set some defaults */
228 data->pd_NumColors = 2;
229 data->pd_ColorTable = NULL;
230 data->pd_Color = 0;
231 data->pd_OldColor = 0 ; /* = data->pd_OldColor */
232 data->pd_ColorOffset = 0;
233 data->pd_IndWidth = 0;
234 data->pd_IndHeight = 0;
235 data->pd_LabelPlace = GV_LabelPlace_Above;
238 _OM_SET(cl, o, msg, FALSE);
242 ReturnPtr ("Palette::New", Object *, o);
245 /*********************
246 ** Palette::Get() **
247 *********************/
248 IPTR AROSPalette__OM_GET(Class *cl, Object *o, struct opGet *msg)
250 struct PaletteData *data = INST_DATA(cl, o);
251 IPTR retval = 1UL;
253 switch(msg->opg_AttrID)
255 case AROSA_Palette_Color:
256 *msg->opg_Storage = (IPTR)GetPalettePen(data, data->pd_Color);
257 break;
259 case AROSA_Palette_ColorOffset:
260 *msg->opg_Storage = (IPTR)data->pd_ColorOffset;
261 break;
263 case AROSA_Palette_ColorTable:
264 *msg->opg_Storage = (IPTR)data->pd_ColorTable;
265 break;
267 default:
268 retval = DoSuperMethodA(cl, o, (Msg)msg);
269 break;
272 return retval;
275 /************************
276 ** Palette::Render() **
277 ************************/
278 VOID AROSPalette__GM_RENDER(Class *cl, Object *o, struct gpRender *msg)
280 struct PaletteData *data = INST_DATA(cl, o);
282 struct DrawInfo *dri = msg->gpr_GInfo->gi_DrInfo;
283 struct RastPort *rp;
284 struct IBox *gbox = &(data->pd_GadgetBox);
286 EnterFunc(bug("Palette::Render()\n"));
288 rp = msg->gpr_RPort;
291 switch (msg->gpr_Redraw)
293 case GREDRAW_REDRAW:
294 D(bug("Doing total redraw\n"));
296 /* Render gadget label in correct position */
297 RenderLabel((struct Gadget *)o, gbox, rp,
298 data->pd_LabelPlace, AROSPaletteBase);
300 RenderFrame(data, rp, gbox, dri, FALSE, FALSE, AROSPaletteBase);
302 RenderPalette(data, rp, AROSPaletteBase);
304 /* Render frame aroun ibox */
305 if (data->pd_IndWidth || data->pd_IndHeight)
307 RenderFrame(data, rp, &(data->pd_IndicatorBox), dri, TRUE, TRUE, AROSPaletteBase);
310 case GREDRAW_UPDATE:
311 D(bug("Doing redraw update\n"));
313 UpdateActiveColor(data, dri, rp, AROSPaletteBase);
315 if (data->pd_IndWidth || data->pd_IndHeight)
317 struct IBox *ibox = &(data->pd_IndicatorBox);
318 SetAPen(rp, GetPalettePen(data, data->pd_Color));
320 D(bug("Drawing indocator at: (%d, %d, %d, %d)\n",
321 ibox->Left, ibox->Top,
322 ibox->Left + ibox->Width, ibox->Top + ibox->Height));
324 RectFill(msg->gpr_RPort,
325 ibox->Left + VBORDER + VSPACING,
326 ibox->Top + HBORDER + HSPACING,
327 ibox->Left + ibox->Width - 1 - VBORDER - VSPACING,
328 ibox->Top + ibox->Height - 1 - HBORDER - HSPACING);
331 break;
334 } /* switch (redraw method) */
336 if (EG(o)->Flags & GFLG_DISABLED)
338 DrawDisabledPattern(rp, gbox, dri->dri_Pens[SHADOWPEN], AROSPaletteBase);
341 ReturnVoid("Palette::Render");
344 /*************************
345 ** Palette::Dispose() **
346 *************************/
347 VOID AROSPalette__OM_DISPOSE(Class *cl, Object *o, Msg msg)
349 struct PaletteData *data = INST_DATA(cl, o);
351 if (data->pd_Frame) DisposeObject(data->pd_Frame);
353 DoSuperMethodA(cl, o, msg);
356 /*************************
357 ** Palette::HitTest() **
358 *************************/
359 IPTR AROSPalette__GM_HITTEST(Class *cl, Object *o, struct gpHitTest *msg)
361 WORD x, y;
363 IPTR retval = 0UL;
364 struct PaletteData *data = INST_DATA(cl, o);
366 EnterFunc(bug("Palette::HitTest()\n"));
368 /* One might think that this method is not necessary to implement,
369 ** but here is an example to show the opposite:
370 ** Consider a 16 color palette with 8 rows and 2 cols.
371 ** Gadget is 87 pix. heigh. Each row will then be 10 pix hight + 7 pix
372 ** of "nowhere". To prevent anything from happening when this area is
373 ** clicked, we rule it out here.
376 x = msg->gpht_Mouse.X + data->pd_GadgetBox.Left;
377 y = msg->gpht_Mouse.Y + data->pd_GadgetBox.Top;
379 if ( (x > data->pd_PaletteBox.Left)
380 && (x < data->pd_PaletteBox.Left + data->pd_PaletteBox.Width - 1)
381 && (y > data->pd_PaletteBox.Top)
382 && (y < data->pd_PaletteBox.Top + data->pd_PaletteBox.Height - 1)
385 retval = GMR_GADGETHIT;
388 ReturnInt ("Palette::HitTest", IPTR, retval);
391 /************************
392 ** Palette::GoActive **
393 ************************/
394 IPTR AROSPalette__GM_GOACTIVE(Class *cl, Object *o, struct gpInput *msg)
396 IPTR retval = 0UL;
397 struct PaletteData *data = INST_DATA(cl, o);
399 EnterFunc(bug("Palette::GoActive()\n"));
400 if (EG(o)->Flags & GFLG_DISABLED)
402 retval = GMR_NOREUSE;
404 else
406 if (msg->gpi_IEvent)
408 UBYTE clicked_color;
410 /* Set temporary active to the old active */
411 data->pd_ColorBackup = data->pd_Color;
413 clicked_color = ComputeColor(data,
414 msg->gpi_Mouse.X + data->pd_GadgetBox.Left,
415 msg->gpi_Mouse.Y + data->pd_GadgetBox.Top);
417 if (clicked_color != data->pd_Color)
419 struct RastPort *rp;
421 data->pd_Color = clicked_color;
423 if ((rp = ObtainGIRPort(msg->gpi_GInfo)))
425 DoMethod(o, GM_RENDER, (IPTR)msg->gpi_GInfo, (IPTR)rp, GREDRAW_UPDATE);
427 ReleaseGIRPort(rp);
431 retval = GMR_MEACTIVE;
432 } /* if (gadget activated is a result of user input) */
434 else
435 retval = GMR_NOREUSE;
436 } /* if (gadget isn't disabled) */
438 ReturnInt("Palette::GoActive", IPTR, retval);
443 /*****************************
444 ** Palette::HandleInput() **
445 *****************************/
446 IPTR AROSPalette__GM_HANDLEINPUT(Class *cl, Object *o, struct gpInput *msg)
448 struct PaletteData *data = INST_DATA(cl, o);
449 IPTR retval = 0UL;
450 struct InputEvent *ie = msg->gpi_IEvent;
452 EnterFunc(bug("Palette::HandleInput\n"));
454 retval = GMR_MEACTIVE;
456 if (ie->ie_Class == IECLASS_RAWMOUSE)
458 WORD x = msg->gpi_Mouse.X + data->pd_GadgetBox.Left;
459 WORD y = msg->gpi_Mouse.Y + data->pd_GadgetBox.Top;
461 if (x <= data->pd_PaletteBox.Left) x = data->pd_PaletteBox.Left + 1;
462 if (y <= data->pd_PaletteBox.Top) y = data->pd_PaletteBox.Top + 1;
463 if (x >= data->pd_PaletteBox.Left + data->pd_PaletteBox.Width - 1)
464 x = data->pd_PaletteBox.Left + data->pd_PaletteBox.Width - 2;
465 if (y >= data->pd_PaletteBox.Top + data->pd_PaletteBox.Height - 1)
466 y = data->pd_PaletteBox.Top + data->pd_PaletteBox.Height - 2;
468 switch (ie->ie_Code)
470 case SELECTUP: {
471 /* If the button was released outside the gadget, then
472 ** go back to old state --> no longer: stegerg
475 D(bug("IECLASS_RAWMOUSE: SELECTUP\n"));
477 #if 0
478 if (!InsidePalette(data, x, y))
480 struct RastPort *rp;
482 /* Left released outside of gadget area, go back
483 ** to old state
485 data->pd_Color = data->pd_ColorBackup;
486 D(bug("Left released outside gadget\n"));
488 if ((rp = ObtainGIRPort(msg->gpi_GInfo)))
490 DoMethod(o, GM_RENDER, msg->gpi_GInfo, rp, GREDRAW_UPDATE);
492 ReleaseGIRPort(rp);
495 else
497 #endif
499 D(bug("Left released inside gadget, color=%d\n", GetPalettePen(data, data->pd_Color)));
500 *(msg->gpi_Termination) = GetPalettePen(data, data->pd_Color);
501 retval = GMR_VERIFY;
503 #if 0
505 #endif
507 retval |= GMR_NOREUSE;
508 } break;
510 case IECODE_NOBUTTON: {
512 UBYTE over_color;
514 D(bug("IECLASS_POINTERPOS\n"));
516 if (InsidePalette(data, x, y))
519 over_color = ComputeColor(data, x, y);
521 if (over_color != data->pd_Color)
523 struct RastPort *rp;
525 data->pd_Color = over_color;
526 if ((rp = ObtainGIRPort(msg->gpi_GInfo)))
528 DoMethod(o, GM_RENDER, (IPTR)msg->gpi_GInfo, (IPTR)rp, GREDRAW_UPDATE);
530 ReleaseGIRPort(rp);
532 } /* if (mouse is over a different color) */
534 } /* if (mouse is over gadget) */
536 retval = GMR_MEACTIVE;
538 } break;
541 case MENUUP: {
543 /* Right released on gadget, go back to old state */
545 struct RastPort *rp;
547 data->pd_Color = data->pd_ColorBackup;
548 D(bug("Right mouse pushed \n"));
550 if ((rp = ObtainGIRPort(msg->gpi_GInfo)))
552 DoMethod(o, GM_RENDER, (IPTR)msg->gpi_GInfo, (IPTR)rp, GREDRAW_UPDATE);
554 ReleaseGIRPort(rp);
557 retval = GMR_NOREUSE;
558 } break;
560 } /* switch (ie->ie_Code) */
562 } /* if (mouse event) */
564 ReturnInt("Palette::HandleInput", IPTR, retval);
567 /************************
568 ** Palette::Layout() **
569 ************************/
570 VOID AROSPalette__GM_LAYOUT(Class *cl, Object *o, struct gpLayout *msg)
573 /* The palette gadget has been resized and we need to update our layout */
575 struct PaletteData *data = INST_DATA(cl, o);
576 struct IBox *gbox = &(data->pd_GadgetBox),
577 *pbox = &(data->pd_PaletteBox),
578 *indbox = &(data->pd_IndicatorBox);
581 UWORD cols, rows;
583 WORD factor1, factor2, ratio;
584 UWORD fault, smallest_so_far;
586 UWORD *largest, *smallest;
588 WORD leftover_width, leftover_height;
590 EnterFunc(bug("Palette::Layout()\n"));
592 if (!msg->gpl_GInfo)
593 ReturnVoid("Palette::Layout"); /* We MUST have a GInfo to get screen aspect ratio */
595 /* Delete the old gadget box */
596 if (!msg->gpl_Initial)
599 struct RastPort *rp;
601 if ((rp = ObtainGIRPort(msg->gpl_GInfo)))
603 SetAPen(rp, msg->gpl_GInfo->gi_DrInfo->dri_Pens[BACKGROUNDPEN]);
604 D(bug("Clearing area (%d, %d, %d, %d)\n",
605 gbox->Left, gbox->Top, gbox->Left + gbox->Width, gbox->Top + gbox->Height));
606 RectFill(rp, gbox->Left, gbox->Top,
607 gbox->Left + gbox->Width - 1, gbox->Top + gbox->Height - 1);
609 ReleaseGIRPort(rp);
613 /* get the IBox surrounding the whole palette */
614 GetGadgetIBox(o, msg->gpl_GInfo, gbox);
615 D(bug("Got palette ibox: (%d, %d, %d, %d)\n",
616 gbox->Left, gbox->Top, gbox->Width, gbox->Height));
618 /* Get the palette box */
619 pbox->Left = gbox->Left + VBORDER + VSPACING;
620 pbox->Top = gbox->Top + HBORDER + HSPACING;
621 pbox->Width = gbox->Width - VBORDER * 2 - VSPACING * 2;
622 pbox->Height = gbox->Height - HBORDER * 2 - HSPACING * 2;
625 /* If we have an indicator box then account for this */
626 if (data->pd_IndHeight)
628 indbox->Top = pbox->Top;
629 indbox->Left = pbox->Left;
630 indbox->Width = pbox->Width;
631 indbox->Height = data->pd_IndHeight;
633 pbox->Height -= (indbox->Height + HSPACING * 2);
634 pbox->Top += (data->pd_IndHeight + HSPACING * 2);
636 else if (data->pd_IndWidth)
638 indbox->Left = pbox->Left;
639 indbox->Top = pbox->Top;
640 indbox->Width = data->pd_IndWidth;
641 indbox->Height = pbox->Height;
643 pbox->Width -= (indbox->Width + VSPACING * 2);
644 pbox->Left += (data->pd_IndWidth + VSPACING * 2);
648 /* Compute initial aspect ratio */
649 if (pbox->Width > pbox->Height)
651 cols = pbox->Width / pbox->Height;
652 rows = 1;
653 largest = &cols;
654 smallest = &rows;
656 else
658 rows = pbox->Height / pbox->Width;
659 cols = 1;
660 largest = &rows;
661 smallest = &cols;
664 D(bug("Biggest aspect: %d\n", *largest));
666 ratio = *largest;
668 smallest_so_far = 0xFFFF;
670 factor1 = 1 << Colors2Depth(data->pd_NumColors);
671 factor2 = 1;
673 while (factor1 >= factor2)
676 D(bug("trying aspect %dx%d\n", factor1, factor2));
678 fault = abs(ratio - (factor1 / factor2));
679 D(bug("Fault: %d, smallest fault so far: %d\n", fault, smallest_so_far));
681 if (fault < smallest_so_far)
683 *largest = factor1;
684 *smallest = factor2;
686 smallest_so_far = fault;
689 factor1 >>= 1;
690 factor2 <<= 1;
694 data->pd_NumCols = (UBYTE)cols;
695 data->pd_NumRows = (UBYTE)rows;
697 data->pd_ColWidth = pbox->Width / data->pd_NumCols;
698 data->pd_RowHeight = pbox->Height / data->pd_NumRows;
700 D(bug("cols=%d, rows=%d\n", data->pd_NumCols, data->pd_NumRows));
701 D(bug("colwidth=%d, rowheight=%d\n", data->pd_ColWidth, data->pd_RowHeight));
703 /* Adjust the pbox's and indbox's height according to leftovers */
705 leftover_width = pbox->Width % data->pd_NumCols;
706 leftover_height = pbox->Height % data->pd_NumRows;
708 pbox->Width -= leftover_width;
709 pbox->Height -= leftover_height;
711 if (data->pd_IndHeight)
712 indbox->Width -= leftover_width;
713 else if (data->pd_IndWidth)
714 indbox->Height -= leftover_height;
716 ReturnVoid("Palette::Layout");