2 ** $Id: ScrollButtonClass.c,v 1.1 1999/02/07 14:24:43 bernie Exp $
4 ** Copyright (C) 1998,99 Bernardo Innocenti
6 ** Use 4 chars wide TABs to read this file
8 ** The ScrollButtonClass is a simple subclass of the buttongclass
9 ** specialized for scroll buttons. See ScrollButtonClass.h for a detailed
13 #define USE_BUILTIN_MATH
14 #define INTUI_V36_NAMES_ONLY
16 #define CLIB_ALIB_PROTOS_H /* Avoid dupe defs of boopsi funcs */
19 #include <intuition/gadgetclass.h>
20 #include <intuition/imageclass.h>
21 #include <proto/exec.h>
22 #include <proto/intuition.h>
23 #include <proto/utility.h>
25 #include <gadgets/ScrollButtonClass.h>
27 #include <CompilerSpecific.h>
28 #include <DebugMacros.h>
29 #include <DiagnosticMacros.h>
30 #include <BoopsiStubs.h>
31 #include <BoopsiLib.h>
39 /* Per object instance data */
40 struct ScrollButtonData
42 /* The number of ticks we still have to wait
43 * before sending any notification.
47 struct IBox GBox; /* Our gadget bounds */
48 struct IBox FrameBox; /* Frame size and position */
50 BOOL LayoutDone; /* Need to recalculate above info? */
55 /* Local function prototypes */
57 static ULONG SB_GMGoActive (Class *cl, struct Gadget *g, struct gpInput *gpi);
58 static ULONG SB_GMHandleInput(Class *cl, struct Gadget *g, struct gpInput *gpi);
59 static void SB_GMRender (Class *cl, struct Gadget *g, struct gpRender *gpr);
60 static void SB_GMLayout (Class *cl, struct Gadget *g, struct gpLayout *gpl);
61 static ULONG SB_OMSet (Class *cl, struct Gadget *g, struct opUpdate *msg);
63 static ULONG HOOKCALL ScrollButtonDispatcher(
65 REG(a2, struct Gadget *g),
70 #if (CLASS_FLAVOUR & FLAVOUR_CLASSLIB)
72 /* Class library support functions */
73 struct ClassLibrary * HOOKCALL _UserLibInit (REG(a6, struct ClassLibrary *mybase));
74 struct ClassLibrary * HOOKCALL _UserLibCleanup (REG(a6, struct ClassLibrary *mybase));
75 Class * HOOKCALL _GetEngine (REG(a6, struct ClassLibrary *mybase));
78 const UBYTE LibName[] = "scrollbutton.gadget";
79 const UBYTE LibVer[] = { '$', 'V', 'E', 'R', ':', ' ' };
80 const UBYTE LibId[] = "scrollbutton.gadget 1.0 (19.3.2000) © 1997-2000 Bernardo Innocenti\n";
82 /* Workaround a bug in StormC header file <proto/utility.h> */
84 #define UTILITYBASETYPE struct Library
86 #define UTILITYBASETYPE struct UtilityBase
90 struct ExecBase *SysBase = NULL;
91 struct IntuitionBase *IntuitionBase = NULL;
92 UTILITYBASETYPE *UtilityBase = NULL;
97 static ULONG SB_GMGoActive(Class *cl, struct Gadget *g, struct gpInput *gpi)
99 struct ScrollButtonData *bd = (struct ScrollButtonData *) INST_DATA(cl, g);
101 DB2(DBPRINTF("ScrollButton: GM_GOACTIVE\n");)
104 /* May define an attribute to make delay configurable */
107 /* Notify our target that we have initially hit. */
108 NotifyAttrs((Object *)g, gpi->gpi_GInfo, 0,
112 /* Send more input */
118 static ULONG SB_GMHandleInput(Class *cl, struct Gadget *g, struct gpInput *gpi)
120 struct ScrollButtonData *bd = (struct ScrollButtonData *) INST_DATA(cl, g);
122 ULONG retval = GMR_MEACTIVE;
125 DB2 (DBPRINTF ("ScrollButton: GM_HANDLEINPUT\n");)
128 /* This also works with classic (non-boopsi) images. */
129 if (PointInImage((gpi->gpi_Mouse.X << 16) + (gpi->gpi_Mouse.Y), g->GadgetRender))
132 selected = GFLG_SELECTED;
135 if (gpi->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE && gpi->gpi_IEvent->ie_Code == SELECTUP)
137 /* Gadgetup, time to go */
138 retval = GMR_NOREUSE;
139 /* Unselect the gadget on our way out... */
142 else if (gpi->gpi_IEvent->ie_Class == IECLASS_TIMER)
144 /* We got a tick. Decrement counter, and if 0, send notify. */
149 /* Notify our target that we are still being hit */
150 NotifyAttrs ((Object *)g, gpi->gpi_GInfo, 0,
155 if ((g->Flags & GFLG_SELECTED) != selected)
157 /* Update changes in gadget render */
158 g->Flags ^= GFLG_SELECTED;
159 if (rp = ObtainGIRPort (gpi->gpi_GInfo))
161 DoMethod((Object *) g, GM_RENDER, gpi->gpi_GInfo, rp, GREDRAW_UPDATE);
170 static void SB_GMRender(Class *cl, struct Gadget *g, struct gpRender *gpr)
172 struct ScrollButtonData *bd = (struct ScrollButtonData *) INST_DATA(cl, g);
173 struct impDraw impdraw;
175 DB2(DBPRINTF("ScrollButton: GM_RENDER\n");)
179 SB_GMLayout(cl, g, (struct gpLayout *)gpr);
181 impdraw.MethodID = IM_DRAWFRAME;
182 impdraw.imp_RPort = gpr->gpr_RPort;
183 impdraw.imp_DrInfo = gpr->gpr_GInfo->gi_DrInfo;
185 /* Check if we are living inside an inactive window border */
186 if ((g->Activation & (GACT_RIGHTBORDER | GACT_LEFTBORDER | GACT_TOPBORDER | GACT_BOTTOMBORDER)) &&
187 gpr->gpr_GInfo->gi_Window &&
188 (!(gpr->gpr_GInfo->gi_Window->Flags & WFLG_WINDOWACTIVE)))
190 impdraw.imp_State = (g->Flags & GFLG_SELECTED) ?
191 IDS_INACTIVESELECTED :
192 ((g->Flags & GFLG_DISABLED) ? IDS_INACTIVEDISABLED : IDS_INACTIVENORMAL );
196 impdraw.imp_State = (g->Flags & GFLG_SELECTED) ?
197 ((g->Flags & GFLG_DISABLED) ? IDS_SELECTEDDISABLED : IDS_SELECTED ) :
198 ((g->Flags & GFLG_DISABLED) ? IDS_DISABLED : IDS_NORMAL );
201 /* Check whether our label image is valid and can be sent a boopsi message */
202 if ((g->Flags & GFLG_LABELIMAGE) && g->GadgetText &&
203 (((struct Image *)g->GadgetText)->Depth == CUSTOMIMAGEDEPTH))
205 impdraw.imp_Offset.X = bd->GBox.Left - bd->FrameBox.Left;
206 impdraw.imp_Offset.Y = bd->GBox.Top - bd->FrameBox.Top;
207 impdraw.imp_Dimensions.Width = bd->GBox.Width - bd->FrameBox.Width;
208 impdraw.imp_Dimensions.Height = bd->GBox.Height - bd->FrameBox.Height;
210 DoMethodA((Object *)g->GadgetText, (Msg)&impdraw);
213 /* Check whether our framing image is valid and can be sent a boopsi message */
214 if ((g->Flags & GFLG_GADGIMAGE) && g->GadgetRender &&
215 (((struct Image *)g->GadgetRender)->Depth == CUSTOMIMAGEDEPTH))
217 impdraw.imp_Offset.X = bd->GBox.Left;
218 impdraw.imp_Offset.Y = bd->GBox.Top;
219 impdraw.imp_Dimensions.Width = bd->GBox.Width;
220 impdraw.imp_Dimensions.Height = bd->GBox.Height;
222 DoMethodA((Object *)g->GadgetRender, (Msg)&impdraw);
228 static void SB_GMLayout(Class *cl, struct Gadget *g, struct gpLayout *gpl)
230 struct ScrollButtonData *bd = (struct ScrollButtonData *) INST_DATA(cl, g);
232 DB2(DBPRINTF("ScrollButton: GM_LAYOUT\n");)
235 /* Compute new button size */
236 GetGadgetBox(gpl->gpl_GInfo, g, &bd->GBox);
238 /* Check if our framing image is valid and can be sent a boopsi message */
239 if ((g->Flags & GFLG_GADGIMAGE) && g->GadgetRender &&
240 (((struct Image *)g->GadgetRender)->Depth == CUSTOMIMAGEDEPTH))
242 struct IBox fakecontents = { 0, 0, 0, 0 };
244 /* Ask the frame what is its size */
245 DoMethod((Object *)g->GadgetRender, IM_FRAMEBOX,
246 &fakecontents, &bd->FrameBox, gpl->gpl_GInfo->gi_DrInfo, 0);
249 bd->LayoutDone = TRUE;
254 static ULONG SB_OMSet (Class *cl, struct Gadget *g, struct opUpdate *msg)
256 struct ScrollButtonData *bd = (struct ScrollButtonData *) INST_DATA(cl, g);
257 struct TagItem *ti, *tstate = msg->opu_AttrList;
259 DB1(DBPRINTF("ScrollButton: OM_SET\n");)
261 ASSERT_VALID_PTR(tstate)
263 while (ti = NextTagItem(&tstate))
265 /* Check for any of GA_Width, GA_RelWidth, GA_Height, GA_RelHeight.
266 * This test assumes that the values of these tags are consecutive
267 * and will break whenever their definitions are changed.
269 if ((ti->ti_Tag >= GA_Width) && (ti->ti_Tag <= GA_RelHeight))
270 bd->LayoutDone = FALSE;
273 /* The superclass handles everything else */
274 return (DoSuperMethodA(cl, (Object *)g, (Msg) msg));
279 static ULONG HOOKCALL ScrollButtonDispatcher(
281 REG(a2, struct Gadget *g),
284 /* ScrollButton Class Dispatcher entrypoint.
285 * Handle boopsi messages.
288 switch (msg->MethodID)
291 return SB_GMGoActive(cl, g, (struct gpInput *)msg);
294 return SB_GMHandleInput(cl, g, (struct gpInput *)msg);
297 SB_GMRender(cl, g, (struct gpRender *)msg);
301 SB_GMLayout(cl, g, (struct gpLayout *)msg);
306 return SB_OMSet(cl, g, (struct opUpdate *)msg);
309 /* Super class handles everything else */
310 return (DoSuperMethodA(cl, (Object *)g, msg));
316 Class *MakeScrollButtonClass (void)
320 if (class = MakeClass(NULL, BUTTONGCLASS, NULL, sizeof(struct ScrollButtonData), 0))
321 class->cl_Dispatcher.h_Entry = (ULONG (*)()) ScrollButtonDispatcher;
326 Class *MakeFrScrollButtonClass (void)
330 if (class = MakeClass (NULL, FRBUTTONCLASS, NULL, sizeof(struct ScrollButtonData), 0))
331 class->cl_Dispatcher.h_Entry = (ULONG (*)()) ScrollButtonDispatcher;
336 BOOL FreeScrollButtonClass (Class *cl)
338 return (FreeClass(cl));
343 #if (CLASS_FLAVOUR & FLAVOUR_CLASSLIB)
345 * Class library support functions
348 struct ClassLibrary * HOOKCALL _UserLibInit(REG(a6, struct ClassLibrary *mybase))
350 /* Initialize SysBase */
351 SysBase = *((struct ExecBase **)4UL);
353 if (!((UtilityBase = (UTILITYBASETYPE *) OpenLibrary("utility.library", 39)) &&
354 (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 39))))
356 _UserLibCleanup(mybase);
360 if (!(mybase->cl_Class = MakeScrollButtonClass()))
362 _UserLibCleanup(mybase);
366 AddClass(mybase->cl_Class);
370 struct ClassLibrary * HOOKCALL _UserLibCleanup(REG(a6, struct ClassLibrary *mybase))
372 if (mybase->cl_Class)
373 if (!FreeScrollButtonClass(mybase->cl_Class))
376 CloseLibrary((struct Library *)IntuitionBase);
377 CloseLibrary((struct Library *)UtilityBase);
382 Class * HOOKCALL _GetEngine(REG(a6, struct ClassLibrary *mybase))
384 return mybase->cl_Class;
387 #endif /* (CLASS_FLAVOUR & FLAVOUR_CLASSLIB) */