Initial commit
[amiga/OpenBoopsi.git] / gadgets / SliderBar / SliderBarGClass.c
1 /*
2 **      $Id: SliderBarGClass.c,v 1.1 1999/02/07 14:24:43 bernie Exp $
3 **
4 **      Copyright (C) 1999 Bernardo Innocenti
5 **      All rights reserved.
6 **
7 **      Use 4 chars wide TABs to read this file
8 **
9 **      "sliderbargclass", a GadTools like slider with scroll buttons.
10 **      See the header file "SliderBarGClass.h" for class documentation.
11 */
12
13 /* Supported class flavours:
14  *
15  * FLAVOUR_CLASSLIB
16  *      Build a class library if this option is set or
17  *      a static linker object otherwise.
18  *
19  * FLAVOUR_PUBCLASS
20  *      Call AddClass() to show this class globally if set,
21  *      make a private class otherwise.
22  */
23 #define FLAVOUR_CLASSLIB        (1<<0)
24 #define FLAVOUR_PUBCLASS        (1<<1)
25
26 #define CLASS_FLAVOUR (FLAVOUR_CLASSLIB | FLAVOUR_PUBCLASS)
27
28 /* Definitions for system headers */
29 #define USE_BUILTIN_MATH
30 #define INTUI_V36_NAMES_ONLY
31 #define INTUITION_IOBSOLETE_H
32 #define __USE_SYSBASE
33 #define  CLIB_ALIB_PROTOS_H             /* Avoid dupe defines of boopsi funcs */
34
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>
44
45 #include <proto/exec.h>
46 #include <proto/intuition.h>
47 #include <proto/utility.h>
48
49 #include <CompilerSpecific.h>
50 #include <DebugMacros.h>
51 #include <DiagnosticMacros.h>
52 #include <BoopsiStubs.h>
53
54 #include <images/VectorGlyphIClass.h>
55 #include <gadgets/SmartGroupGClass.h>
56 #include <gadgets/ScrollButtonClass.h>
57 #include "FrPropGClass.h"
58 #include "SliderBarGClass.h"
59
60 #ifdef __STORM__
61         #pragma header
62 #endif
63
64
65 #define BUTTON_WIDTH    16
66 #define BUTTON_HEIGHT   16
67
68 /* Local function prototypes */
69
70 INLINE void GetGadgetBox (struct GadgetInfo *ginfo, struct Gadget *g, struct IBox *box);
71
72 static ULONG HOOKCALL SliderBarDispatcher (
73         REG(a0, Class *cl),
74         REG(a2, struct Gadget *g),
75         REG(a1, Msg msg));
76
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);
82
83
84
85 /* Per-object instance data */
86 struct SBData
87 {
88         /* Children */
89         Object *Prop, *DecButton, *IncButton;
90
91         /* VectorGlyph images for the buttons */
92         Object *IncImage, *DecImage;
93
94         /* Copy of prop attributes */
95         LONG    Top, Total, Visible;
96
97         /* Slider orientation: can be LORIENT_VERT or LORIENT_HORIZ */
98         ULONG   Orientation;
99 };
100
101
102
103 /* Global class data */
104 struct SBClassData
105 {
106         /* Boopsi frame to put around our children */
107         Object                          *Frame;
108
109         /* Classes we are using */
110         Class                           *SmartGroupGClass;
111         Class                           *FrScrollButtonClass;
112         Class                           *FrPropGClass;
113         Class                           *VectorGlyphIClass;
114         struct ClassLibrary     *VectorGlyphBase;
115 };
116
117
118 #if (CLASS_FLAVOUR & FLAVOUR_CLASSLIB)
119
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));
124
125         /* Library data */
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";
129
130         /* Workaround a bug in StormC header file <proto/utility.h> */
131         #ifdef __STORM__
132                 #define UTILITYBASETYPE struct Library
133         #else
134                 #define UTILITYBASETYPE struct UtilityBase
135         #endif
136
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;
141 #endif
142
143
144 /* Static variables */
145
146 static LONG MapPropToSB[] =
147 {
148         PGA_Top,        SBA_InternalTop,
149         TAG_DONE
150 };
151
152
153 static LONG MapButtonToSB[] =
154 {
155         GA_ID,          SBA_Adjust,
156         TAG_DONE
157 };
158
159
160
161 INLINE void GetGadgetBox (struct GadgetInfo *ginfo, struct Gadget *g, struct IBox *box)
162
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).
165  *
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.
169  */
170 {
171         ASSERT_VALID_PTR(g)
172         ASSERT_VALID_PTR(ginfo)
173         ASSERT_VALID_PTR(box)
174
175         box->Left = g->LeftEdge;
176         if (g->Flags & GFLG_RELRIGHT)
177                 box->Left += ginfo->gi_Domain.Width - 1;
178
179         box->Top = g->TopEdge;
180         if (g->Flags & GFLG_RELBOTTOM)
181                 box->Top += ginfo->gi_Domain.Height - 1;
182
183         box->Width = g->Width;
184         if (g->Flags & GFLG_RELWIDTH)
185                 box->Width += ginfo->gi_Domain.Width;
186
187         box->Height = g->Height;
188         if (g->Flags & GFLG_RELHEIGHT)
189                 box->Height += ginfo->gi_Domain.Height;
190 }
191
192
193
194 static void SB_GMLayout (Class *cl, struct Gadget *g, struct gpLayout *msg)
195 {
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 };
199
200         DB2 (kprintf ("SliderBarClass: GM_LAYOUT\n");)
201         ASSERT_VALID_PTR(sb)
202         ASSERT_VALID_PTR(classdata)
203
204
205         /* Collect new group size */
206         GetGadgetBox (msg->gpl_GInfo, g, &gbox);
207
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);
211
212         /* Size our children accordingly */
213
214         if (sb->Orientation == LORIENT_VERT)
215         {
216                 SetAttrs (sb->Prop,
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,
221                         TAG_DONE);
222
223                 if (sb->DecButton)
224                         SetAttrs (sb->DecButton,
225                                 GA_Left,        gbox.Left,
226                                 GA_Top,         gbox.Top + gbox.Height - BUTTON_HEIGHT * 2,
227                                 GA_Width,       gbox.Width,
228                                 GA_Height,      BUTTON_HEIGHT,
229                                 TAG_DONE);
230
231                 if (sb->IncButton)
232                         SetAttrs (sb->IncButton,
233                                 GA_Left,        gbox.Left,
234                                 GA_Top,         gbox.Top + gbox.Height - BUTTON_HEIGHT,
235                                 GA_Width,       gbox.Width,
236                                 GA_Height,      BUTTON_HEIGHT,
237                                 TAG_DONE);
238         }
239         else /* LORIENT_HORIZ */
240         {
241                 SetAttrs (sb->Prop,
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,
246                         TAG_DONE);
247
248                 if (sb->DecButton)
249                         SetAttrs (sb->DecButton,
250                                 GA_Left,        gbox.Left + gbox.Width - BUTTON_WIDTH * 2,
251                                 GA_Top,         gbox.Top,
252                                 GA_Width,       BUTTON_WIDTH,
253                                 GA_Height,      gbox.Height,
254                                 TAG_DONE);
255
256                 if (sb->IncButton)
257                         SetAttrs (sb->IncButton,
258                                 GA_Left,        gbox.Left + gbox.Width - BUTTON_WIDTH,
259                                 GA_Top,         gbox.Top,
260                                 GA_Width,       BUTTON_WIDTH,
261                                 GA_Height,      gbox.Height,
262                                 TAG_DONE);
263         }
264
265         DoSuperMethodA (cl, (Object *)g, (Msg)msg);
266 }
267
268
269
270 static ULONG SB_OMNew (Class *cl, struct Gadget *g, struct opSet *msg)
271 {
272         struct SBData           *sb;
273         struct SBClassData      *classdata;
274
275         DB2 (DBPRINTF ("SliderBarGClass: OM_NEW\n");)
276
277         if (g = (struct Gadget *)DoSuperMethodA (cl, (Object *)g, (Msg)msg))
278         {
279                 classdata = (struct SBClassData *)cl->cl_UserData;
280                 sb = (struct SBData *) INST_DATA (cl, (Object *)g);
281                 ASSERT_VALID_PTR(sb)
282                 ASSERT_VALID_PTR(classdata)
283
284
285                 /* Initialize the object instance */
286                 sb->DecButton = NULL;
287                 sb->IncButton = NULL;
288                 sb->IncImage = NULL;
289                 sb->DecImage = 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);
294
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,
299                         PGA_NewLook,    TRUE,
300                         PGA_Borderless, TRUE,
301                         PGA_Top,                sb->Top,
302                         PGA_Total,              sb->Total,
303                         PGA_Visible,    sb->Visible,
304                         ICA_TARGET,             g,      /* target on us */
305                         ICA_MAP,                MapPropToSB,
306                         TAG_DONE))
307                 {
308                         /* From now on, the groupgclass will dispose this object for us */
309                         DoMethod ((Object *)g, OM_ADDMEMBER, sb->Prop);
310
311                         /* Don't bother checking for failure here:
312                          * the images are not mission-critical.
313                          */
314                         sb->DecImage = NewObject (classdata->VectorGlyphIClass, NULL,
315                                 SYSIA_Which, (sb->Orientation == LORIENT_VERT) ? VG_UPARROW : VG_LEFTARROW,
316                                 TAG_DONE);
317
318                         if (sb->DecButton = NewObject (classdata->FrScrollButtonClass, NULL,
319                                 GA_ID,                  -1,
320                                 GA_LabelImage,  sb->DecImage,
321                                 GA_Image,               classdata->Frame,
322                                 ICA_TARGET,             g, /* target on us */
323                                 ICA_MAP,                MapButtonToSB,
324                                 TAG_DONE))
325                         {
326                                 /* From now on, the groupgclass will dispose this object for us */
327                                 DoMethod ((Object *)g, OM_ADDMEMBER, sb->DecButton);
328                         }
329
330                         /* Don't bother checking for failure here:
331                          * the images are not mission-critical.
332                          */
333                         sb->IncImage = NewObject (classdata->VectorGlyphIClass, NULL,
334                                 SYSIA_Which, (sb->Orientation == LORIENT_VERT) ? VG_DOWNARROW : VG_RIGHTARROW,
335                                 TAG_DONE);
336
337                         if (sb->IncButton = NewObject (classdata->FrScrollButtonClass, NULL,
338                                 GA_ID,                  +1,
339                                 GA_LabelImage,  sb->IncImage,
340                                 GA_Image,               classdata->Frame,
341                                 ICA_TARGET,             g, /* target on us */
342                                 ICA_MAP,                MapButtonToSB,
343                                 TAG_DONE))
344                         {
345                                 /* From now on, the groupgclass will dispose this object for us */
346                                 DoMethod ((Object *)g, OM_ADDMEMBER, sb->IncButton);
347                         }
348
349                         return (ULONG)g;        /* Return newly created instance */
350                 }
351
352                 /* Commit suicide without disturbing the dispatchers of our subclasses */
353                 CoerceMethod (cl, (Object *)g, OM_DISPOSE);
354         }
355
356         return 0;       /* Fail */
357 }
358
359
360
361 static void SB_OMDispose (Class *cl, struct Gadget *g, Msg msg)
362 {
363         struct SBData *sb = (struct SBData *) INST_DATA (cl, (Object *)g);
364
365         /* The groupgclass will dispose all our children for us */
366
367         DisposeObject (sb->IncImage);
368         DisposeObject (sb->DecImage);
369
370         /* Our superclass will cleanup everything else now */
371         DoSuperMethodA (cl, (Object *)g, msg);
372
373         /* From now on, our instance data is no longer available */
374 }
375
376
377 static ULONG SB_OMSet (Class *cl, struct Gadget *g, struct opUpdate *msg)
378 {
379         struct SBData   *sb = INST_DATA (cl, g);
380         struct TagItem  *ti, *tstate = msg->opu_AttrList;
381         ULONG action = 0;       /* see flag definitions below */
382         ULONG result;
383
384         ASSERT_VALID_PTR(sb)
385         ASSERT_VALID_PTR_OR_NULL(tstate)
386
387         DB2 (DBPRINTF ((msg->MethodID == OM_SET) ?
388                 "SliderBarGClass: OM_SET\n" :
389                 "SliderBarGClass: OM_UPDATE\n");)
390
391
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.
396          */
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)
401
402
403         while (ti = NextTagItem (&tstate))
404                 switch (ti->ti_Tag)
405                 {
406                         case GA_ID:
407                                 if (msg->MethodID == OM_SET)
408                                 {
409                                         DB2 (DBPRINTF ("  GA_ID, %ld\n", ti->ti_Data);)
410
411                                         /* Avoid forwarding all taglists to superclass because of GA_ID */
412                                         g->GadgetID = ti->ti_Data;
413                                 }
414                                 break;
415
416                         case PGA_Top:
417                                 if (sb->Top != ti->ti_Data)
418                                 {
419                                         sb->Top = ti->ti_Data;
420                                         action |= ACTIONF_NOTIFY_TOP | ACTIONF_UPDATE_CHILD;
421                                 }
422                                 break;
423
424                         case PGA_Total:
425                                 if (sb->Total != ti->ti_Data)
426                                 {
427                                         sb->Total = ti->ti_Data;
428                                         action |= ACTIONF_NOTIFY_ALL | ACTIONF_UPDATE_CHILD;
429                                 }
430                                 break;
431
432                         case PGA_Visible:
433                                 if (sb->Visible != ti->ti_Data)
434                                 {
435                                         sb->Visible = ti->ti_Data;
436                                         action |= ACTIONF_NOTIFY_ALL | ACTIONF_UPDATE_CHILD;
437                                 }
438                                 break;
439
440                         case SBA_InternalTop:
441                                 /* Prop gadget updating us */
442                                 if (sb->Top != ti->ti_Data)
443                                 {
444                                         sb->Top = ti->ti_Data;
445                                         action |= ACTIONF_NOTIFY_TOP;
446                                 }
447                                 break;
448
449                         case SBA_Adjust:
450                         {
451                                 LONG newtop = sb->Top + (LONG)((WORD)ti->ti_Data);
452
453                                 /* Clip result to allowable values */
454                                 if (newtop < 0) newtop = 0;
455                                 if (newtop > sb->Total - sb->Visible) newtop = sb->Total - sb->Visible;
456
457                                 if (newtop != sb->Top)
458                                 {
459                                         sb->Top = newtop;
460                                         action |= ACTIONF_NOTIFY_TOP | ACTIONF_UPDATE_CHILD;
461                                 }
462
463                                 break;
464                         }
465
466                         default:
467                                 action |= ACTIONF_DO_SUPER_METHOD;
468                                 break;
469                 }
470
471         /* Forward method to our superclass dispatcher, only if needed */
472         if (action & ACTIONF_DO_SUPER_METHOD)
473         {
474                 DB2 (DBPRINTF ("SliderBarGClass:   Forwarding OM_SET/OM_UPDATE to superclass\n"));
475                 result = (DoSuperMethodA (cl, (Object *)g, (Msg) msg));
476         }
477         else
478                 result = TRUE;
479
480         if (action & ACTIONF_UPDATE_CHILD)
481         {
482                 if (action & ACTIONF_NOTIFY_ALL)
483                 {
484                         DB2 (DBPRINTF ("SliderBarGClass:   Update child ALL\n"));
485
486                         UpdateAttrs (sb->Prop, msg->opu_GInfo,
487                                 (msg->MethodID == OM_UPDATE) ? msg->opu_Flags : 0,
488                                 PGA_Top,                sb->Top,
489                                 PGA_Total,              sb->Total,
490                                 PGA_Visible,    sb->Visible,
491                                 TAG_DONE);
492                 }
493                 else /* Top only */
494                 {
495                         DB2 (DBPRINTF ("SliderBarGClass:   Update child PGA_Top (%ld)\n", sb->Top));
496
497                         UpdateAttrs (sb->Prop, msg->opu_GInfo,
498                                 (msg->MethodID == OM_UPDATE) ? msg->opu_Flags : 0,
499                                 PGA_Top,                sb->Top,
500                                 TAG_DONE);
501                 }
502         }
503
504         if (action & ACTIONF_NOTIFY_ALL)
505         {
506                 DB2 (DBPRINTF ("SliderBarGClass:   Notify target ALL\n"));
507
508                 NotifyAttrs ((Object *)g, msg->opu_GInfo,
509                         (msg->MethodID == OM_UPDATE) ? msg->opu_Flags : 0,
510                         PGA_Top,                sb->Top,
511                         PGA_Total,              sb->Total,
512                         PGA_Visible,    sb->Visible,
513                         GA_ID,                  g->GadgetID,
514                         TAG_DONE);
515         }
516         else if (action & ACTIONF_NOTIFY_TOP)
517         {
518                 DB2 (DBPRINTF ("SliderBarGClass:   Notify target TOP\n"));
519
520                 NotifyAttrs ((Object *)g, msg->opu_GInfo,
521                         (msg->MethodID == OM_UPDATE) ? msg->opu_Flags : 0,
522                         PGA_Top,                sb->Top,
523                         GA_ID,                  g->GadgetID,
524                         TAG_DONE);
525         }
526
527         return result;
528 }
529
530
531 static ULONG SB_OMGet (Class *cl, struct Gadget *g, struct opGet *msg)
532 {
533         struct SBData *sb = INST_DATA (cl, g);
534
535         ASSERT_VALID_PTR(sb)
536         ASSERT_VALID_PTR(msg->opg_Storage)
537
538         DB2 (DBPRINTF ("ScrollBarGClass: OM_GET\n");)
539
540
541         switch (msg->opg_AttrID)
542         {
543                 case PGA_Top:
544                         *msg->opg_Storage = (ULONG) sb->Top;
545                         return TRUE;
546
547                 case PGA_Total:
548                         *msg->opg_Storage = (ULONG) sb->Total;
549                         return TRUE;
550
551                 case PGA_Visible:
552                         *msg->opg_Storage = (ULONG) sb->Visible;
553                         return TRUE;
554
555                 default:
556                         return FALSE;
557         }
558 }
559
560
561 static ULONG HOOKCALL SliderBarDispatcher (
562         REG(a0, Class *cl),
563         REG(a2, struct Gadget *g),
564         REG(a1, Msg msg))
565
566 /* SliderBar class dispatcher - Handles all boopsi messages. */
567 {
568         ASSERT_VALID_PTR(cl)
569         ASSERT_VALID_PTR(g)
570         ASSERT_VALID_PTR(msg)
571
572
573         switch (msg->MethodID)
574         {
575                 case GM_LAYOUT:
576                         /* This method is only supported on V39 and above */
577                         SB_GMLayout (cl, g, (struct gpLayout *)msg);
578                         return TRUE;
579
580                 case OM_SET:
581                 case OM_UPDATE:
582                         return SB_OMSet (cl, g, (struct opUpdate *)msg);
583
584                 case OM_GET:
585                         return SB_OMGet (cl, g, (struct opGet *)msg);
586
587                 case OM_NEW:
588                         return SB_OMNew (cl, g, (struct opSet *)msg);
589
590                 case OM_DISPOSE:
591                         SB_OMDispose (cl, g, msg);
592                         return TRUE;
593
594                 default:
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.
600                          */
601                         DB2 (DBPRINTF ("SliderBarGClass: passing unknown method 0x%lx to superclass\n",
602                                 msg->MethodID);)
603                         return DoSuperMethodA (cl, (Object *)g, msg);
604         }
605 }
606
607
608
609 Class *MakeSliderBarGClass (void)
610 {
611         Class *class;
612         struct SBClassData *classdata;
613         Class *smartgrp;
614
615         if (!(smartgrp = MakeSmartGroupGClass()))
616                 return NULL;
617
618         if (class = MakeClass (
619 #if (CLASS_FLAVOUR & FLAVOUR_PUBCLASS)
620                 SLIDERBARGCLASS,
621 #else
622                 NULL,
623 #endif
624                 NULL, smartgrp, sizeof (struct SBData), 0))
625         {
626                 class->cl_Dispatcher.h_Entry = (ULONG (*)()) SliderBarDispatcher;
627
628                 /* Allocate storage for global class data */
629                 if (classdata = AllocMem (sizeof (struct SBClassData), MEMF_PUBLIC | MEMF_CLEAR))
630                 {
631                         class->cl_UserData = (ULONG) classdata;
632
633                         classdata->SmartGroupGClass = smartgrp;
634
635                         classdata->FrScrollButtonClass = MakeFrScrollButtonClass();
636                         ASSERT_VALID_PTR (classdata->FrScrollButtonClass);
637
638                         classdata->FrPropGClass = MakeFrPropGClass();
639                         ASSERT_VALID_PTR (classdata->FrPropGClass);
640
641                         if (classdata->VectorGlyphBase = (struct ClassLibrary *)
642                                 OpenLibrary ("images/vectorglyph.image", 0))
643                         {
644                                 classdata->VectorGlyphIClass = classdata->VectorGlyphBase->cl_Class;
645                                 ASSERT_VALID_PTR (classdata->VectorGlyphIClass);
646
647                                 if (classdata->Frame = NewObject (NULL, FRAMEICLASS,
648                                         IA_EdgesOnly,   TRUE,
649                                         IA_FrameType,   FRAME_BUTTON,
650                                         TAG_DONE))
651                                 {
652 #if (CLASS_FLAVOUR & FLAVOUR_PUBCLASS)
653                                         AddClass (class);
654 #endif
655                                         return class;
656                                 }
657                         }
658                         else
659                         {
660                                 static struct EasyStruct OpenClassES =
661                                 {
662                                         sizeof (struct EasyStruct),
663                                         0,
664 #if (CLASS_FLAVOUR & FLAVOUR_CLASSLIB)
665                                         LibName,
666 #else
667                                         "sliderbar.gadget",
668 #endif
669                                         "Couldn't open images/vectorglyph.image",
670                                         "Ok"
671                                 };
672
673                                 /* Report an error */
674                                 EasyRequestArgs (NULL, &OpenClassES, NULL, NULL);
675                         }
676                 }
677
678                 FreeSliderBarGClass (class);
679         }
680
681         return NULL;
682 }
683
684
685 BOOL FreeSliderBarGClass (Class *class)
686 {
687         struct SBClassData *classdata;
688
689         if (class)
690         {
691                 ASSERT_VALID_PTR(class)
692
693                 classdata = (struct SBClassData *)class->cl_UserData;
694
695                 /* Try to remove the class */
696                 if (FreeClass (class))
697                 {
698                         if (classdata)
699                         {
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)
706
707                                 /* Cleanup global class data.
708                                  *
709                                  * NOTE: NULL is safe in DisposeObject() and CloseLibrary() since V36
710                                  */
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));
717                         }
718                         return TRUE;
719                 }
720                 return FALSE;
721         }
722         return TRUE;
723 }
724
725
726
727 #if (CLASS_FLAVOUR & FLAVOUR_CLASSLIB)
728 /*
729  * Class library support functions
730  */
731
732 struct ClassLibrary * HOOKCALL _UserLibInit (REG(a6, struct ClassLibrary *mybase))
733 {
734         SysBase = *((struct ExecBase **)4);     /* Initialize SysBase */
735
736         IntuitionBase   = (struct IntuitionBase *) OpenLibrary ("intuition.library", 39);
737         UtilityBase             = (UTILITYBASETYPE *) OpenLibrary ("utility.library", 39);
738
739         if (!(IntuitionBase && UtilityBase))
740         {
741                 _UserLibCleanup (mybase);
742                 return NULL;
743         }
744
745         if (mybase->cl_Class = MakeSliderBarGClass ())
746         {
747                 return mybase;
748         }
749         else
750         {
751                 _UserLibCleanup (mybase);
752                 return NULL;
753         }
754 }
755
756 struct ClassLibrary * HOOKCALL _UserLibCleanup (REG(a6, struct ClassLibrary *mybase))
757 {
758         if (mybase->cl_Class)
759                 if (!FreeSliderBarGClass (mybase->cl_Class))
760                         return NULL;
761
762         CloseLibrary ((struct Library *)UtilityBase);
763         CloseLibrary ((struct Library *)IntuitionBase);
764
765         return mybase;
766 }
767
768 Class * HOOKCALL _GetEngine (REG(a6, struct ClassLibrary *mybase))
769 {
770         return (mybase->cl_Class);
771 }
772
773 #endif /* (CLASS_FLAVOUR & FLAVOUR_CLASSLIB) */