2 ** $Id: ListBoxClass.c,v 1.3 1999/01/30 13:25:03 bernie Exp $
4 ** Copyright (C) 1997,98,99 Bernardo Innocenti (<bernardo.innocenti@usa.net>)
5 ** All rights reserved.
7 ** Use 4 chars wide TABs to read this file
9 ** GadTools-like `boopsi' ListView group class
12 #define USE_BUILTIN_MATH
13 #define INTUI_V36_NAMES_ONLY
14 #define INTUITION_IOBSOLETE_H
16 #define CLIB_ALIB_PROTOS_H /* Avoid dupe defines of boopsi funcs */
18 #include <exec/types.h>
19 #include <exec/memory.h>
20 #include <intuition/intuition.h>
21 #include <intuition/intuitionbase.h>
22 #include <intuition/classes.h>
23 #include <intuition/gadgetclass.h>
24 #include <intuition/icclass.h>
25 #include <intuition/imageclass.h>
27 #include <proto/exec.h>
28 #include <proto/intuition.h>
29 #include <proto/utility.h>
35 #define LV_GADTOOLS_STUFF
36 #include <gadgets/ListBoxClass.h>
38 #include <CompilerSpecific.h>
39 #include <DebugMacros.h>
40 #include <BoopsiStubs.h>
41 #include <BoopsiLib.h>
47 #define VSLIDER_WIDTH 18
48 #define HSLIDER_HEIGHT 18
51 /* Per-object instance data */
54 /* struct Gadget *ThisGadget; (not used) */
60 Object *LVToVSliderIC;
61 Object *LVToHSliderIC;
63 Object *Model; /* The ic object that makes our children talk to each other */
64 Object *Frame; /* The frame to put around the child objects */
67 LONG FrameWidth, FrameHeight;
69 /* These two have the same meaning, but we keep both updated
70 * because the Rectangle structure (MinX, MinY, MaxX, MaxY)
71 * is more handy in some cases, while the IBox structure
72 * (Left/Top/Width/Height) is best for other cases.
75 struct Rectangle GRect;
79 /* Global class data */
82 Class *SliderBarGClass;
83 struct ClassLibrary *SliderBarBase;
88 #define SLIDERBARGCLASS_PTR ( ((struct LBClassData *)(cl->cl_UserData))->SliderBarGClass )
92 extern Class *ListViewClass;
95 /* Local function prototypes */
96 static void LB_GMLayout (Class *cl, struct Gadget *g, struct gpLayout *msg);
97 static ULONG LB_OMSet (Class *cl, struct Gadget *g, struct opUpdate *msg);
98 static ULONG LB_OMGet (Class *cl, struct Gadget *g, struct opGet *msg);
99 static ULONG LB_OMNew (Class *cl, struct Gadget *g, struct opSet *msg);
100 static void LB_OMDispose (Class *cl, struct Gadget *g, Msg msg);
102 static void CreateVSlider (Class *cl, struct Gadget *g, struct LBData *lb, struct DrawInfo *dri);
103 static void CreateHSlider (Class *cl, struct Gadget *g, struct LBData *lb, struct DrawInfo *dri);
104 static void DeleteVSlider (struct Gadget *g, struct LBData *lb);
105 static void DeleteHSlider (struct Gadget *g, struct LBData *lb);
110 /* Attribute translations for object interconnections */
112 static LONG MapLVToHSlider[] =
114 LVA_PixelLeft, PGA_Top,
115 LVA_PixelWidth, PGA_Total,
116 LVA_PixelHVisible, PGA_Visible,
120 static LONG MapHSliderToLV[] =
122 PGA_Top, LVA_PixelLeft,
126 static LONG MapLVToVSlider[] =
128 LVA_PixelTop, PGA_Top,
129 LVA_PixelHeight, PGA_Total,
130 LVA_PixelVVisible, PGA_Visible,
134 static LONG MapVSliderToLV[] =
136 PGA_Top, LVA_PixelTop,
142 static ULONG HOOKCALL LBDispatcher(
144 REG(a2, struct Gadget *g),
149 ASSERT_VALID_PTR(msg)
151 switch (msg->MethodID)
154 /* This method is only supported on V39 and above */
155 LB_GMLayout(cl, g, (struct gpLayout *)msg);
160 return LB_OMSet(cl, g, (struct opUpdate *)msg);
163 return LB_OMGet(cl, g, (struct opGet *)msg);
166 return LB_OMNew(cl, g, (struct opSet *)msg);
169 LB_OMDispose(cl, g, msg);
173 /* Unsupported method: let our superclass's dispatcher take
174 * a look at it. This includes all gadget methods sent
175 * by Intuition: GM_RENDER, GM_HANDLEINPUT, GM_GOACTIVE and
176 * GM_GOINACTIVE. These methods are automatically forwarded
177 * to our child gadgets by the groupgclass.
179 DB2 (DBPRINTF("ListBoxClass: passing unknown method 0x%lx to superclass\n", msg->MethodID);)
180 return DoSuperMethodA (cl, (Object *)g, msg);
186 static void LB_GMLayout(Class *cl, struct Gadget *g, struct gpLayout *msg)
188 struct LBData *lb = (struct LBData *) INST_DATA(cl, (Object *)g);
190 DB(DBPRINTF("ListBoxClass: GM_LAYOUT\n");)
194 /* Collect new gadget size */
195 GetGadgetBox(msg->gpl_GInfo, (struct ExtGadget *)g, &lv->GBox);
196 IBoxToRect(&lv->GBox, &lv->GRect);
199 /* Size our children accordingly */
200 SetAttrs(lb->ListView,
201 GA_Left, lb->GBox.Left + lb->FrameWidth / 2,
202 GA_Top, lb->GBox.Top + lb->FrameHeight / 2,
203 GA_Width, lb->GBox.Width - lb->FrameWidth - VSLIDER_WIDTH,
204 GA_Height, lb->GBox.Height - lb->FrameHeight - HSLIDER_HEIGHT,
208 SetAttrs(lb->VSlider,
209 GA_Left, lb->GRect.MaxX - VSLIDER_WIDTH + 1,
210 GA_Top, lb->GBox.Top,
211 GA_Width, VSLIDER_WIDTH,
212 GA_Height, lb->GBox.Height,
216 /* NOTE: it seems that the groupgclass does not forward GM_LAYOUT
217 * to its children, so we must handle this here.
219 DoMethodA(lb->ListView, (Msg)msg);
220 if (lb->VSlider) DoMethodA(lb->VSlider, (Msg)msg);
225 static ULONG LB_OMSet(Class *cl, struct Gadget *g, struct opUpdate *msg)
227 struct LBData *lb = (struct LBData *) INST_DATA(cl, (Object *)g);
229 DB2(DBPRINTF("ListBoxClass: OM_SET\n");)
233 /* Forward attributes to our listview */
234 DoMethodA (lb->ListView, (Msg)msg);
236 /* Also forward to our superclass */
237 return DoSuperMethodA (cl, (Object *)g, (Msg) msg);
242 static ULONG LB_OMGet(Class *cl, struct Gadget *g, struct opGet *msg)
244 struct LBData *lb = (struct LBData *) INST_DATA(cl, (Object *)g);
246 DB2(DBPRINTF("ListBoxClass: OM_GET\n");)
249 /* Forward this method to our listview */
250 return DoMethodA(lb->ListView, (Msg)msg);
255 static ULONG LB_OMNew(Class *cl, struct Gadget *g, struct opSet *msg)
258 struct DrawInfo *dri;
261 DB2(DBPRINTF("ListBoxClass: OM_NEW\n");)
263 if (g = (struct Gadget *)DoSuperMethodA(cl, (Object *)g, (Msg)msg))
265 /* Set the GMORE_SCROLLRASTER flag */
266 if (g->Flags & GFLG_EXTENDED)
268 DB(DBPRINTF("ListBoxClass: OM_NEW: Setting GMORE_SCROLLRASTER\n");)
269 ((struct ExtGadget *)g)->MoreFlags |= GMORE_SCROLLRASTER;
272 lb = (struct LBData *) INST_DATA(cl, (Object *)g);
276 /* Clear the object instance */
277 memset(lb, 0, sizeof (struct LBData));
280 /* Store a pointer to this object (a Gadget) in the class private
281 * instance. This way we can avoid passing it along to all functions.
283 /* lb->ThisGadget = g; (not used) */
287 dri = (struct DrawInfo *) GetTagData(GA_DrawInfo, NULL, msg->ops_AttrList);
290 /* Create a frame to put around us */
291 if (lb->Frame = NewObject(NULL, FRAMEICLASS,
293 IA_FrameType, FRAME_BUTTON,
296 struct IBox FrameBox, ContentsBox = { 0, 0, 0, 0 };
298 /* Ask the frame about its nominal frame width and height */
299 DoMethod((Object *)lb->Frame, IM_FRAMEBOX, &ContentsBox, &FrameBox, dri, 0);
301 /* Remember it later */
302 lb->FrameWidth = FrameBox.Width;
303 lb->FrameHeight = FrameBox.Height;
306 /* Create a model object. This will be the core of the boopsi attributes
307 * network used by the sub-objects to talk each other. We pass our
308 * initalization tags to the model so it will pick up the correct
309 * ICA_TARGET and ICA_MAP, if specified with NewObject().
311 if (lb->Model = NewObjectA(NULL, MODELCLASS, NULL))
313 /* Create the ListView and pass all creation time attributes to it.
314 * Note that any GA_#? attributes are also passed to the listview,
315 * so it will have the same size of its container.
317 if (lb->ListView = NewObject(ListViewClass, NULL,
319 TAG_MORE, msg->ops_AttrList))
321 /* From now on, the groupgclass will dispose this object for us */
322 DoMethod((Object *)g, OM_ADDMEMBER, lb->ListView);
324 /* Connect Model to ListView */
328 if (icobject = NewObject(NULL, ICCLASS,
329 ICA_TARGET, lb->ListView,
331 if (!DoMethod(lb->Model, OM_ADDMEMBER, icobject))
332 DisposeObject(icobject);
335 /* Connect ListView to Model */
336 SetAttrs(lb->ListView,
337 ICA_TARGET, lb->Model,
341 CreateVSlider(cl, g, lb, dri);
342 CreateHSlider(cl, g, lb, dri);
344 /* Set the gadget width and height because the groupgclass
345 * always forces them to 0 on creation.
350 if (tag = FindTagItem(GA_RelWidth, msg->ops_AttrList))
352 GA_RelWidth, tag->ti_Data,
356 GA_Width, GetTagData(GA_Width, g->Width, msg->ops_AttrList),
359 if (tag = FindTagItem(GA_RelHeight, msg->ops_AttrList))
361 GA_RelHeight, tag->ti_Data,
365 GA_Height, GetTagData (GA_Height, g->Height, msg->ops_AttrList),
368 DB2(DBPRINTF("ListBoxClass: OM_NEW: size set to L=%ld T=%ld W=%ld H=%ld\n",
369 g->LeftEdge, g->TopEdge, g->Width, g->Height);)
372 /* TODO: Handle creation-time attributes */
374 return (ULONG)g; /* Return newly created istance */
379 /* Dispose object without disturbing the dispatchers of our sub-classes, if any */
380 CoerceMethod(cl, (Object *)g, OM_DISPOSE);
388 static void LB_OMDispose(Class *cl, struct Gadget *g, Msg msg)
390 struct LBData *lb = (struct LBData *) INST_DATA(cl, (Object *)g);
392 DB(DBPRINTF("ListBoxClass: OM_DISPOSE\n");)
396 DeleteHSlider(g, lb);
397 DeleteVSlider(g, lb);
399 /* Dispose the child objects that aren't freed automatically by the modelclass.
400 * Note that here we are disposing the Frame before we dispose the gadgets that
401 * may be still using it. Everything will go well unless those classes will
402 * access the frame within their OM_DISPOSE methods (very silly).
404 DisposeObject(lb->Model);
405 DisposeObject(lb->Frame);
407 /* Our superclass will cleanup everything else now */
408 DoSuperMethodA(cl, (Object *)g, (Msg) msg);
410 /* From now on, our instance data is no longer available */
415 static void CreateVSlider(Class *cl, struct Gadget *g, struct LBData *lb, struct DrawInfo *dri)
417 if (lb->VSlider = NewObject(SLIDERBARGCLASS_PTR, NULL,
418 GA_ID, g->GadgetID, /* Same as our ID */
420 GA_LabelImage, lb->Frame,
421 PGA_Freedom, FREEVERT,
423 PGA_Borderless, TRUE,
424 LAYOUTA_Orientation, LORIENT_VERT,
425 ICA_TARGET, lb->Model,
426 ICA_MAP, MapVSliderToLV,
429 /* From now on, the groupgclass will dispose this object for us */
430 DoMethod((Object *)g, OM_ADDMEMBER, lb->VSlider);
432 /* Connect Model to ListView */
434 ICA_TARGET, lb->ListView,
437 /* Connect VSlider to Model */
438 if (lb->LVToVSliderIC = NewObject(NULL, ICCLASS,
439 ICA_TARGET, lb->VSlider,
440 ICA_MAP, MapLVToVSlider,
442 if (!DoMethod(lb->Model, OM_ADDMEMBER, lb->LVToVSliderIC))
443 DisposeObject(lb->LVToVSliderIC);
449 static void CreateHSlider(Class *cl, struct Gadget *g, struct LBData *lb, struct DrawInfo *dri)
455 static void DeleteVSlider(struct Gadget *g, struct LBData *lb)
457 if (lb->LVToVSliderIC)
459 ASSERT_VALID_PTR(lb->LVToVSliderIC)
460 ASSERT_VALID_PTR(lb->Model)
462 DoMethod (lb->Model, OM_REMMEMBER, lb->LVToVSliderIC);
463 DisposeObject (lb->LVToVSliderIC);
464 lb->LVToVSliderIC = NULL;
469 ASSERT_VALID_PTR(lb->VSlider)
471 DoMethod ((Object *)g, OM_REMMEMBER, lb->VSlider);
472 DisposeObject (lb->VSlider);
479 static void DeleteHSlider(struct Gadget *g, struct LBData *lb)
486 Class *MakeListBoxClass(void)
489 struct LBClassData *classdata;
491 if (class = MakeClass(NULL, GROUPGCLASS, NULL, sizeof (struct LBData), 0))
493 class->cl_Dispatcher.h_Entry = (ULONG (*)()) LBDispatcher;
495 /* Allocate storage for global class data */
496 if (classdata = AllocMem(sizeof (struct LBClassData), MEMF_PUBLIC | MEMF_CLEAR))
498 class->cl_UserData = (ULONG) classdata;
500 if (classdata->SliderBarBase = (struct ClassLibrary *)
501 OpenLibrary("gadgets/sliderbar.gadget", 0))
503 classdata->SliderBarGClass = classdata->SliderBarBase->cl_Class;
504 ASSERT_VALID_PTR(classdata->SliderBarGClass);
510 FreeListBoxClass(class);
518 BOOL FreeListBoxClass(Class *class)
520 struct LBClassData *classdata;
524 ASSERT_VALID_PTR(class)
526 classdata = (struct LBClassData *)class->cl_UserData;
528 /* Try to remove the class */
529 if (FreeClass(class))
533 ASSERT_VALID_PTR(classdata)
534 ASSERT_VALID_PTR_OR_NULL(classdata->SliderBarBase)
536 /* Cleanup global class data */
538 /* NULL is safe in CloseLibrary() since V36 */
539 CloseLibrary((struct Library *)classdata->SliderBarBase);
540 FreeMem(classdata, sizeof (struct LBClassData));