2 ** $Id: SliderBarGClass.c,v 1.1 1999/02/07 14:24:43 bernie Exp $
4 ** Copyright (C) 1999 Bernardo Innocenti
5 ** All rights reserved.
7 ** Use 4 chars wide TABs to read this file
9 ** "sliderbargclass", a GadTools like slider with scroll buttons.
10 ** See the header file "SliderBarGClass.h" for class documentation.
13 /* Supported class flavours:
16 * Build a class library if this option is set or
17 * a static linker object otherwise.
20 * Call AddClass() to show this class globally if set,
21 * make a private class otherwise.
23 #define FLAVOUR_CLASSLIB (1<<0)
24 #define FLAVOUR_PUBCLASS (1<<1)
26 #define CLASS_FLAVOUR (FLAVOUR_CLASSLIB | FLAVOUR_PUBCLASS)
28 /* Definitions for system headers */
29 #define USE_BUILTIN_MATH
30 #define INTUI_V36_NAMES_ONLY
31 #define INTUITION_IOBSOLETE_H
33 #define CLIB_ALIB_PROTOS_H /* Avoid dupe defines of boopsi funcs */
35 #include <exec/types.h>
36 #include <exec/memory.h>
37 #include <utility/tagitem.h>
38 #include <intuition/intuition.h>
39 #include <intuition/classes.h>
40 #include <intuition/classusr.h>
41 #include <intuition/gadgetclass.h>
42 #include <intuition/imageclass.h>
43 #include <intuition/icclass.h>
45 #include <proto/exec.h>
46 #include <proto/intuition.h>
47 #include <proto/utility.h>
49 #include <CompilerSpecific.h>
50 #include <DebugMacros.h>
51 #include <DiagnosticMacros.h>
52 #include <BoopsiStubs.h>
54 #include <images/VectorGlyphIClass.h>
55 #include <gadgets/SmartGroupGClass.h>
56 #include <gadgets/ScrollButtonClass.h>
57 #include "FrPropGClass.h"
58 #include "SliderBarGClass.h"
65 #define BUTTON_WIDTH 16
66 #define BUTTON_HEIGHT 16
68 /* Local function prototypes */
70 INLINE void GetGadgetBox (struct GadgetInfo *ginfo, struct Gadget *g, struct IBox *box);
72 static ULONG HOOKCALL SliderBarDispatcher (
74 REG(a2, struct Gadget *g),
77 static void SB_GMLayout (Class *cl, struct Gadget *g, struct gpLayout *msg);
78 static ULONG SB_OMNew (Class *cl, struct Gadget *g, struct opSet *msg);
79 static void SB_OMDispose(Class *cl, struct Gadget *g, Msg msg);
80 static ULONG SB_OMGet (Class *cl, struct Gadget *g, struct opGet *msg);
81 static ULONG SB_OMSet (Class *cl, struct Gadget *g, struct opUpdate *msg);
85 /* Per-object instance data */
89 Object *Prop, *DecButton, *IncButton;
91 /* VectorGlyph images for the buttons */
92 Object *IncImage, *DecImage;
94 /* Copy of prop attributes */
95 LONG Top, Total, Visible;
97 /* Slider orientation: can be LORIENT_VERT or LORIENT_HORIZ */
103 /* Global class data */
106 /* Boopsi frame to put around our children */
109 /* Classes we are using */
110 Class *SmartGroupGClass;
111 Class *FrScrollButtonClass;
113 Class *VectorGlyphIClass;
114 struct ClassLibrary *VectorGlyphBase;
118 #if (CLASS_FLAVOUR & FLAVOUR_CLASSLIB)
120 /* Class library support functions */
121 struct ClassLibrary * HOOKCALL _UserLibInit (REG(a6, struct ClassLibrary *mybase));
122 struct ClassLibrary * HOOKCALL _UserLibCleanup (REG(a6, struct ClassLibrary *mybase));
123 Class * HOOKCALL _GetEngine (REG(a6, struct ClassLibrary *mybase));
126 const UBYTE LibName[] = "sliderbar.gadget";
127 const UBYTE LibVer[] = { '$', 'V', 'E', 'R', ':', ' ' };
128 const UBYTE LibId[] = "sliderbar.gadget 1.0 (30.1.99) © 1999 Bernardo Innocenti\n";
130 /* Workaround a bug in StormC header file <proto/utility.h> */
132 #define UTILITYBASETYPE struct Library
134 #define UTILITYBASETYPE struct UtilityBase
137 /* Library bases - also used by the FrScrollButtonClass and the FrPropGClass */
138 struct ExecBase *SysBase = NULL;
139 struct IntuitionBase *IntuitionBase = NULL;
140 UTILITYBASETYPE *UtilityBase = NULL;
144 /* Static variables */
146 static LONG MapPropToSB[] =
148 PGA_Top, SBA_InternalTop,
153 static LONG MapButtonToSB[] =
161 INLINE void GetGadgetBox (struct GadgetInfo *ginfo, struct Gadget *g, struct IBox *box)
163 /* Gets the actual IBox where a gadget exists in a window.
164 * The special cases it handles are all the REL#? (relative positioning flags).
166 * This function returns the gadget size in the provided IBox structure,
167 * computing the values from the coordinates of the gadget and the window
168 * inside which it lives.
172 ASSERT_VALID_PTR(ginfo)
173 ASSERT_VALID_PTR(box)
175 box->Left = g->LeftEdge;
176 if (g->Flags & GFLG_RELRIGHT)
177 box->Left += ginfo->gi_Domain.Width - 1;
179 box->Top = g->TopEdge;
180 if (g->Flags & GFLG_RELBOTTOM)
181 box->Top += ginfo->gi_Domain.Height - 1;
183 box->Width = g->Width;
184 if (g->Flags & GFLG_RELWIDTH)
185 box->Width += ginfo->gi_Domain.Width;
187 box->Height = g->Height;
188 if (g->Flags & GFLG_RELHEIGHT)
189 box->Height += ginfo->gi_Domain.Height;
194 static void SB_GMLayout (Class *cl, struct Gadget *g, struct gpLayout *msg)
196 struct SBData *sb = (struct SBData *) INST_DATA (cl, (Object *)g);
197 struct SBClassData *classdata = (struct SBClassData *)cl->cl_UserData;
198 struct IBox gbox, framebox, contentsbox = { 0, 0, 0, 0 };
200 DB2 (kprintf ("SliderBarClass: GM_LAYOUT\n");)
202 ASSERT_VALID_PTR(classdata)
205 /* Collect new group size */
206 GetGadgetBox (msg->gpl_GInfo, g, &gbox);
208 /* Query the frame on its nominal width and height */
209 DoMethod (classdata->Frame, IM_FRAMEBOX, &contentsbox, &framebox,
210 msg->gpl_GInfo->gi_DrInfo, 0);
212 /* Size our children accordingly */
214 if (sb->Orientation == LORIENT_VERT)
217 GA_Left, gbox.Left + framebox.Width / 2,
218 GA_Top, gbox.Top + framebox.Height / 2,
219 GA_Width, gbox.Width - framebox.Width,
220 GA_Height, gbox.Height - framebox.Height - BUTTON_HEIGHT * 2,
224 SetAttrs (sb->DecButton,
226 GA_Top, gbox.Top + gbox.Height - BUTTON_HEIGHT * 2,
227 GA_Width, gbox.Width,
228 GA_Height, BUTTON_HEIGHT,
232 SetAttrs (sb->IncButton,
234 GA_Top, gbox.Top + gbox.Height - BUTTON_HEIGHT,
235 GA_Width, gbox.Width,
236 GA_Height, BUTTON_HEIGHT,
239 else /* LORIENT_HORIZ */
242 GA_Left, gbox.Left + framebox.Width / 2,
243 GA_Top, gbox.Top + framebox.Height / 2,
244 GA_Width, gbox.Width - framebox.Width - BUTTON_WIDTH * 2,
245 GA_Height, gbox.Height - framebox.Height,
249 SetAttrs (sb->DecButton,
250 GA_Left, gbox.Left + gbox.Width - BUTTON_WIDTH * 2,
252 GA_Width, BUTTON_WIDTH,
253 GA_Height, gbox.Height,
257 SetAttrs (sb->IncButton,
258 GA_Left, gbox.Left + gbox.Width - BUTTON_WIDTH,
260 GA_Width, BUTTON_WIDTH,
261 GA_Height, gbox.Height,
265 DoSuperMethodA (cl, (Object *)g, (Msg)msg);
270 static ULONG SB_OMNew (Class *cl, struct Gadget *g, struct opSet *msg)
273 struct SBClassData *classdata;
275 DB2 (DBPRINTF ("SliderBarGClass: OM_NEW\n");)
277 if (g = (struct Gadget *)DoSuperMethodA (cl, (Object *)g, (Msg)msg))
279 classdata = (struct SBClassData *)cl->cl_UserData;
280 sb = (struct SBData *) INST_DATA (cl, (Object *)g);
282 ASSERT_VALID_PTR(classdata)
285 /* Initialize the object instance */
286 sb->DecButton = NULL;
287 sb->IncButton = NULL;
290 sb->Orientation = GetTagData (LAYOUTA_Orientation, LORIENT_HORIZ, msg->ops_AttrList);
291 sb->Top = GetTagData (PGA_Top, 0, msg->ops_AttrList);
292 sb->Total = GetTagData (PGA_Total, 0, msg->ops_AttrList);
293 sb->Visible = GetTagData (PGA_Visible, 0, msg->ops_AttrList);
295 if (sb->Prop = NewObject (classdata->FrPropGClass, NULL,
296 GA_ID, g->GadgetID, /* Same as our ID */
297 GA_LabelImage, classdata->Frame,
298 PGA_Freedom, (sb->Orientation == LORIENT_VERT) ? FREEVERT : FREEHORIZ,
300 PGA_Borderless, TRUE,
302 PGA_Total, sb->Total,
303 PGA_Visible, sb->Visible,
304 ICA_TARGET, g, /* target on us */
305 ICA_MAP, MapPropToSB,
308 /* From now on, the groupgclass will dispose this object for us */
309 DoMethod ((Object *)g, OM_ADDMEMBER, sb->Prop);
311 /* Don't bother checking for failure here:
312 * the images are not mission-critical.
314 sb->DecImage = NewObject (classdata->VectorGlyphIClass, NULL,
315 SYSIA_Which, (sb->Orientation == LORIENT_VERT) ? VG_UPARROW : VG_LEFTARROW,
318 if (sb->DecButton = NewObject (classdata->FrScrollButtonClass, NULL,
320 GA_LabelImage, sb->DecImage,
321 GA_Image, classdata->Frame,
322 ICA_TARGET, g, /* target on us */
323 ICA_MAP, MapButtonToSB,
326 /* From now on, the groupgclass will dispose this object for us */
327 DoMethod ((Object *)g, OM_ADDMEMBER, sb->DecButton);
330 /* Don't bother checking for failure here:
331 * the images are not mission-critical.
333 sb->IncImage = NewObject (classdata->VectorGlyphIClass, NULL,
334 SYSIA_Which, (sb->Orientation == LORIENT_VERT) ? VG_DOWNARROW : VG_RIGHTARROW,
337 if (sb->IncButton = NewObject (classdata->FrScrollButtonClass, NULL,
339 GA_LabelImage, sb->IncImage,
340 GA_Image, classdata->Frame,
341 ICA_TARGET, g, /* target on us */
342 ICA_MAP, MapButtonToSB,
345 /* From now on, the groupgclass will dispose this object for us */
346 DoMethod ((Object *)g, OM_ADDMEMBER, sb->IncButton);
349 return (ULONG)g; /* Return newly created instance */
352 /* Commit suicide without disturbing the dispatchers of our subclasses */
353 CoerceMethod (cl, (Object *)g, OM_DISPOSE);
361 static void SB_OMDispose (Class *cl, struct Gadget *g, Msg msg)
363 struct SBData *sb = (struct SBData *) INST_DATA (cl, (Object *)g);
365 /* The groupgclass will dispose all our children for us */
367 DisposeObject (sb->IncImage);
368 DisposeObject (sb->DecImage);
370 /* Our superclass will cleanup everything else now */
371 DoSuperMethodA (cl, (Object *)g, msg);
373 /* From now on, our instance data is no longer available */
377 static ULONG SB_OMSet (Class *cl, struct Gadget *g, struct opUpdate *msg)
379 struct SBData *sb = INST_DATA (cl, g);
380 struct TagItem *ti, *tstate = msg->opu_AttrList;
381 ULONG action = 0; /* see flag definitions below */
385 ASSERT_VALID_PTR_OR_NULL(tstate)
387 DB2 (DBPRINTF ((msg->MethodID == OM_SET) ?
388 "SliderBarGClass: OM_SET\n" :
389 "SliderBarGClass: OM_UPDATE\n");)
392 /* Definitions for the ations to be taken right after
393 * scanning the attributes list in OM_SET/OM_UPDATE.
394 * For speed reasons we pack them together in a single variable,
395 * so we can set and test multiple flags in once.
397 #define ACTIONF_DO_SUPER_METHOD (1<<0)
398 #define ACTIONF_NOTIFY_TOP (1<<1)
399 #define ACTIONF_NOTIFY_ALL (1<<2)
400 #define ACTIONF_UPDATE_CHILD (1<<3)
403 while (ti = NextTagItem (&tstate))
407 if (msg->MethodID == OM_SET)
409 DB2 (DBPRINTF (" GA_ID, %ld\n", ti->ti_Data);)
411 /* Avoid forwarding all taglists to superclass because of GA_ID */
412 g->GadgetID = ti->ti_Data;
417 if (sb->Top != ti->ti_Data)
419 sb->Top = ti->ti_Data;
420 action |= ACTIONF_NOTIFY_TOP | ACTIONF_UPDATE_CHILD;
425 if (sb->Total != ti->ti_Data)
427 sb->Total = ti->ti_Data;
428 action |= ACTIONF_NOTIFY_ALL | ACTIONF_UPDATE_CHILD;
433 if (sb->Visible != ti->ti_Data)
435 sb->Visible = ti->ti_Data;
436 action |= ACTIONF_NOTIFY_ALL | ACTIONF_UPDATE_CHILD;
440 case SBA_InternalTop:
441 /* Prop gadget updating us */
442 if (sb->Top != ti->ti_Data)
444 sb->Top = ti->ti_Data;
445 action |= ACTIONF_NOTIFY_TOP;
451 LONG newtop = sb->Top + (LONG)((WORD)ti->ti_Data);
453 /* Clip result to allowable values */
454 if (newtop < 0) newtop = 0;
455 if (newtop > sb->Total - sb->Visible) newtop = sb->Total - sb->Visible;
457 if (newtop != sb->Top)
460 action |= ACTIONF_NOTIFY_TOP | ACTIONF_UPDATE_CHILD;
467 action |= ACTIONF_DO_SUPER_METHOD;
471 /* Forward method to our superclass dispatcher, only if needed */
472 if (action & ACTIONF_DO_SUPER_METHOD)
474 DB2 (DBPRINTF ("SliderBarGClass: Forwarding OM_SET/OM_UPDATE to superclass\n"));
475 result = (DoSuperMethodA (cl, (Object *)g, (Msg) msg));
480 if (action & ACTIONF_UPDATE_CHILD)
482 if (action & ACTIONF_NOTIFY_ALL)
484 DB2 (DBPRINTF ("SliderBarGClass: Update child ALL\n"));
486 UpdateAttrs (sb->Prop, msg->opu_GInfo,
487 (msg->MethodID == OM_UPDATE) ? msg->opu_Flags : 0,
489 PGA_Total, sb->Total,
490 PGA_Visible, sb->Visible,
495 DB2 (DBPRINTF ("SliderBarGClass: Update child PGA_Top (%ld)\n", sb->Top));
497 UpdateAttrs (sb->Prop, msg->opu_GInfo,
498 (msg->MethodID == OM_UPDATE) ? msg->opu_Flags : 0,
504 if (action & ACTIONF_NOTIFY_ALL)
506 DB2 (DBPRINTF ("SliderBarGClass: Notify target ALL\n"));
508 NotifyAttrs ((Object *)g, msg->opu_GInfo,
509 (msg->MethodID == OM_UPDATE) ? msg->opu_Flags : 0,
511 PGA_Total, sb->Total,
512 PGA_Visible, sb->Visible,
516 else if (action & ACTIONF_NOTIFY_TOP)
518 DB2 (DBPRINTF ("SliderBarGClass: Notify target TOP\n"));
520 NotifyAttrs ((Object *)g, msg->opu_GInfo,
521 (msg->MethodID == OM_UPDATE) ? msg->opu_Flags : 0,
531 static ULONG SB_OMGet (Class *cl, struct Gadget *g, struct opGet *msg)
533 struct SBData *sb = INST_DATA (cl, g);
536 ASSERT_VALID_PTR(msg->opg_Storage)
538 DB2 (DBPRINTF ("ScrollBarGClass: OM_GET\n");)
541 switch (msg->opg_AttrID)
544 *msg->opg_Storage = (ULONG) sb->Top;
548 *msg->opg_Storage = (ULONG) sb->Total;
552 *msg->opg_Storage = (ULONG) sb->Visible;
561 static ULONG HOOKCALL SliderBarDispatcher (
563 REG(a2, struct Gadget *g),
566 /* SliderBar class dispatcher - Handles all boopsi messages. */
570 ASSERT_VALID_PTR(msg)
573 switch (msg->MethodID)
576 /* This method is only supported on V39 and above */
577 SB_GMLayout (cl, g, (struct gpLayout *)msg);
582 return SB_OMSet (cl, g, (struct opUpdate *)msg);
585 return SB_OMGet (cl, g, (struct opGet *)msg);
588 return SB_OMNew (cl, g, (struct opSet *)msg);
591 SB_OMDispose (cl, g, msg);
595 /* Unsupported method: let our superclass's dispatcher take
596 * a look at it. This includes all gadget methods sent
597 * by Intuition: GM_HITTEST, GM_RENDER, GM_HANDLEINPUT,
598 * GM_GOACTIVE and GM_GOINACTIVE. All these methods are
599 * automatically forwarded to our children by our superclass.
601 DB2 (DBPRINTF ("SliderBarGClass: passing unknown method 0x%lx to superclass\n",
603 return DoSuperMethodA (cl, (Object *)g, msg);
609 Class *MakeSliderBarGClass (void)
612 struct SBClassData *classdata;
615 if (!(smartgrp = MakeSmartGroupGClass()))
618 if (class = MakeClass (
619 #if (CLASS_FLAVOUR & FLAVOUR_PUBCLASS)
624 NULL, smartgrp, sizeof (struct SBData), 0))
626 class->cl_Dispatcher.h_Entry = (ULONG (*)()) SliderBarDispatcher;
628 /* Allocate storage for global class data */
629 if (classdata = AllocMem (sizeof (struct SBClassData), MEMF_PUBLIC | MEMF_CLEAR))
631 class->cl_UserData = (ULONG) classdata;
633 classdata->SmartGroupGClass = smartgrp;
635 classdata->FrScrollButtonClass = MakeFrScrollButtonClass();
636 ASSERT_VALID_PTR (classdata->FrScrollButtonClass);
638 classdata->FrPropGClass = MakeFrPropGClass();
639 ASSERT_VALID_PTR (classdata->FrPropGClass);
641 if (classdata->VectorGlyphBase = (struct ClassLibrary *)
642 OpenLibrary ("images/vectorglyph.image", 0))
644 classdata->VectorGlyphIClass = classdata->VectorGlyphBase->cl_Class;
645 ASSERT_VALID_PTR (classdata->VectorGlyphIClass);
647 if (classdata->Frame = NewObject (NULL, FRAMEICLASS,
649 IA_FrameType, FRAME_BUTTON,
652 #if (CLASS_FLAVOUR & FLAVOUR_PUBCLASS)
660 static struct EasyStruct OpenClassES =
662 sizeof (struct EasyStruct),
664 #if (CLASS_FLAVOUR & FLAVOUR_CLASSLIB)
669 "Couldn't open images/vectorglyph.image",
673 /* Report an error */
674 EasyRequestArgs (NULL, &OpenClassES, NULL, NULL);
678 FreeSliderBarGClass (class);
685 BOOL FreeSliderBarGClass (Class *class)
687 struct SBClassData *classdata;
691 ASSERT_VALID_PTR(class)
693 classdata = (struct SBClassData *)class->cl_UserData;
695 /* Try to remove the class */
696 if (FreeClass (class))
700 ASSERT_VALID_PTR(classdata)
701 ASSERT_VALID_PTR_OR_NULL(classdata->Frame);
702 ASSERT_VALID_PTR_OR_NULL(classdata->VectorGlyphBase)
703 ASSERT_VALID_PTR_OR_NULL(classdata->FrScrollButtonClass)
704 ASSERT_VALID_PTR_OR_NULL(classdata->FrPropGClass)
705 ASSERT_VALID_PTR_OR_NULL(classdata->SmartGroupGClass)
707 /* Cleanup global class data.
709 * NOTE: NULL is safe in DisposeObject() and CloseLibrary() since V36
711 DisposeObject(classdata->Frame);
712 CloseLibrary ((struct Library *)classdata->VectorGlyphBase);
713 FreeFrScrollButtonClass (classdata->FrScrollButtonClass);
714 FreeFrPropGClass (classdata->FrPropGClass);
715 FreeSmartGroupGClass (classdata->SmartGroupGClass);
716 FreeMem (classdata, sizeof (struct SBClassData));
727 #if (CLASS_FLAVOUR & FLAVOUR_CLASSLIB)
729 * Class library support functions
732 struct ClassLibrary * HOOKCALL _UserLibInit (REG(a6, struct ClassLibrary *mybase))
734 SysBase = *((struct ExecBase **)4); /* Initialize SysBase */
736 IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 39);
737 UtilityBase = (UTILITYBASETYPE *) OpenLibrary ("utility.library", 39);
739 if (!(IntuitionBase && UtilityBase))
741 _UserLibCleanup (mybase);
745 if (mybase->cl_Class = MakeSliderBarGClass ())
751 _UserLibCleanup (mybase);
756 struct ClassLibrary * HOOKCALL _UserLibCleanup (REG(a6, struct ClassLibrary *mybase))
758 if (mybase->cl_Class)
759 if (!FreeSliderBarGClass (mybase->cl_Class))
762 CloseLibrary ((struct Library *)UtilityBase);
763 CloseLibrary ((struct Library *)IntuitionBase);
768 Class * HOOKCALL _GetEngine (REG(a6, struct ClassLibrary *mybase))
770 return (mybase->cl_Class);
773 #endif /* (CLASS_FLAVOUR & FLAVOUR_CLASSLIB) */