2 Copyright © 1995-2005, The AROS Development Team. All rights reserved.
5 AROS Palette gadget for use in gadtools.
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"
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
;
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
));
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
));
70 case AROSA_Palette_ColorOffset
: /* [I] */
71 data
->pd_ColorOffset
= (UBYTE
)tidata
;
72 D(bug("ColorOffset initialized to %d\n", tidata
));
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
84 data
->pd_LabelPlace
= GV_LabelPlace_Left
;
87 case AROSA_Palette_IndicatorHeight
: /* [I] */
88 data
->pd_IndHeight
= (UWORD
)tidata
;
89 D(bug("Indicatorheight set to %d\n", tidata
));
92 case GA_LabelPlace
: /* [I] */
93 data
->pd_LabelPlace
= (LONG
)tidata
;
94 D(bug("Labelplace set to %d\n", tidata
));
96 labelplace_set
= TRUE
;
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
));
105 case AROSA_Palette_ColorTable
:
106 data
->pd_ColorTable
= (UBYTE
*)tidata
;
109 case AROSA_Palette_NumColors
:
110 numcolorstag_found
= TRUE
;
112 data
->pd_NumColors
= (UWORD
)tidata
;
116 } /* switch (tag->ti_Tag) */
118 } /* for (each attr in attrlist) */
122 /* convert pen number to index */
124 if (data
->pd_ColorTable
)
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
)
139 data
->pd_Color
-= data
->pd_ColorOffset
;
142 } /* if (colortag_found) */
146 /* Check if the old selected fits into the new depth */
147 if (data
->pd_Color
> data
->pd_NumColors
- 1)
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
);
159 struct GadgetInfo
*gi
= ((struct opSet
*)msg
)->ops_GInfo
;
163 struct RastPort
*rp
= ObtainGIRPort(gi
);
171 FindTagItem(GA_Disabled
, ((struct opSet
*)msg
)->ops_AttrList
) ? GREDRAW_REDRAW
: GREDRAW_UPDATE
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 /*********************
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 /*********************
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
},
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
);
225 struct PaletteData
*data
= INST_DATA(cl
, o
);
227 /* Set some defaults */
228 data
->pd_NumColors
= 2;
229 data
->pd_ColorTable
= NULL
;
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 /*********************
247 *********************/
248 IPTR
AROSPalette__OM_GET(Class
*cl
, Object
*o
, struct opGet
*msg
)
250 struct PaletteData
*data
= INST_DATA(cl
, o
);
253 switch(msg
->opg_AttrID
)
255 case AROSA_Palette_Color
:
256 *msg
->opg_Storage
= (IPTR
)GetPalettePen(data
, data
->pd_Color
);
259 case AROSA_Palette_ColorOffset
:
260 *msg
->opg_Storage
= (IPTR
)data
->pd_ColorOffset
;
263 case AROSA_Palette_ColorTable
:
264 *msg
->opg_Storage
= (IPTR
)data
->pd_ColorTable
;
268 retval
= DoSuperMethodA(cl
, o
, (Msg
)msg
);
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
;
284 struct IBox
*gbox
= &(data
->pd_GadgetBox
);
286 EnterFunc(bug("Palette::Render()\n"));
291 switch (msg
->gpr_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
);
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
);
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
)
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
)
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
;
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
)
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
);
431 retval
= GMR_MEACTIVE
;
432 } /* if (gadget activated is a result of user input) */
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
);
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;
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"));
478 if (!InsidePalette(data
, x
, y
))
482 /* Left released outside of gadget area, go back
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
);
499 D(bug("Left released inside gadget, color=%d\n", GetPalettePen(data
, data
->pd_Color
)));
500 *(msg
->gpi_Termination
) = GetPalettePen(data
, data
->pd_Color
);
507 retval
|= GMR_NOREUSE
;
510 case IECODE_NOBUTTON
: {
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
)
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
);
532 } /* if (mouse is over a different color) */
534 } /* if (mouse is over gadget) */
536 retval
= GMR_MEACTIVE
;
543 /* Right released on gadget, go back to old state */
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
);
557 retval
= GMR_NOREUSE
;
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
);
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"));
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
)
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);
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
;
658 rows
= pbox
->Height
/ pbox
->Width
;
664 D(bug("Biggest aspect: %d\n", *largest
));
668 smallest_so_far
= 0xFFFF;
670 factor1
= 1 << Colors2Depth(data
->pd_NumColors
);
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
)
686 smallest_so_far
= fault
;
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");