Updated to latest source.
[AROS-Contrib.git] / bgui / mxclass.c
blob6b9fbd4d6ae2a0afb9fa1a0a7a9099e091a5c58a
1 /*
2 * @(#) $Header$
4 * BGUI library
5 * mxclass.c
7 * (C) Copyright 1998 Manuel Lemos.
8 * (C) Copyright 1996-1997 Ian J. Einman.
9 * (C) Copyright 1993-1996 Jaba Development.
10 * (C) Copyright 1993-1996 Jan van den Baard.
11 * All Rights Reserved.
13 * $Log$
14 * Revision 42.5 2004/06/16 20:16:48 verhaegs
15 * Use METHODPROTO, METHOD_END and REGFUNCPROTOn where needed.
17 * Revision 42.4 2003/01/18 19:10:00 chodorowski
18 * Instead of using the _AROS or __AROS preprocessor symbols, use __AROS__.
20 * Revision 42.3 2000/05/29 00:40:24 bergers
21 * Update to compile with AROS now. Should also still compile with SASC etc since I only made changes that test the define __AROS__. The compilation is still very noisy but it does the trick for the main directory. Maybe members of the BGUI team should also have a look at the compiler warnings because some could also cause problems on other systems... (Comparison always TRUE due to datatype (or something like that)). And please compile it on an Amiga to see whether it still works... Thanks.
23 * Revision 42.2 2000/05/15 19:27:02 stegerg
24 * another hundreds of REG() macro replacements in func headers/protos.
26 * Revision 42.1 2000/05/14 23:32:48 stegerg
27 * changed over 200 function headers which all use register
28 * parameters (oh boy ...), because the simple REG() macro
29 * doesn't work with AROS. And there are still hundreds
30 * of headers left to be fixed :(
32 * Many of these functions would also work with stack
33 * params, but since i have fixed every single one
34 * I encountered up to now, I guess will have to do
35 * the same for the rest.
37 * Revision 42.0 2000/05/09 22:09:48 mlemos
38 * Bumped to revision 42.0 before handing BGUI to AROS team
40 * Revision 41.11 2000/05/09 19:54:49 mlemos
41 * Merged with the branch Manuel_Lemos_fixes.
43 * Revision 41.10.2.1 1998/11/22 00:31:42 mlemos
44 * Made the radio buttons notifications map GA_Selected into TAG_IGNORE to not
45 * set the MX class group selected attribute.
47 * Revision 41.10 1998/02/25 21:12:45 mlemos
48 * Bumping to 41.10
50 * Revision 1.1 1998/02/25 17:09:16 mlemos
51 * Ian sources
56 #include "include/classdefs.h"
58 /// Class definitions.
60 * Object instance data.
62 typedef struct {
63 UBYTE **md_LabelStrings; /* MX button labels. */
64 ULONG md_LabelStringsID; /* Starting string ID label. */
65 LONG md_ActiveLabel; /* Currently active selection. */
66 ULONG md_MaxLabel; /* Number of available labels. */
67 ULONG md_Place; /* Place of the labels. */
68 Object **md_Objects; /* MX buttons. */
69 struct TextAttr *md_TabsFont; /* Font for the buttons. */
70 UWORD md_Type; /* MX Type. */
71 ULONG md_BackFill[2]; /* Back fill tag. */
72 } MD;
75 * Notification map.
77 STATIC ULONG id2act[] = {
78 GA_UserData, MX_Active,
79 GA_Selected, TAG_IGNORE,
80 TAG_END
84 * Module prototypes.
86 METHODPROTO(MXClassSetUpdate, struct opUpdate *, );
87 ///
88 /// AddMXObjects()
90 * Add MX objects.
92 //STATIC ASM BOOL AddMXObjects(REG(a0) Object *target, REG(a1) MD *md)
93 STATIC ASM REGFUNC2(BOOL, AddMXObjects,
94 REGPARAM(A0, Object *, target),
95 REGPARAM(A1, MD *, md))
97 UBYTE **labels = md->md_LabelStrings;
98 UWORD i = 0;
99 ULONG id = md->md_LabelStringsID;
100 BOOL rc = FALSE, tab;
101 ULONG tags[32], *t = tags;
103 static ULONG tags_fix[] = { LGO_FixMinWidth, TRUE, LGO_FixMinHeight, TRUE, TAG_DONE };
105 *t++ = GA_ToggleSelect; *t++ = TRUE;
106 *t++ = GA_ID; *t++ = GADGET(target)->GadgetID;
107 *t++ = GA_Disabled; *t++ = GADGET(target)->Flags & GFLG_DISABLED;
108 *t++ = LAB_SelectedDriPen; *t++ = TEXTPEN;
110 switch (md->md_Type)
112 case MXTYPE_RADIOBUTTON:
113 *t++ = LAB_Place; *t++ = md->md_Place;
115 tab = FALSE;
116 break;
118 case MXTYPE_TAB_TOP:
119 *t++ = FRM_Type; *t++ = FRTYPE_TAB_TOP;
120 goto common_tab;
122 case MXTYPE_TAB_BOTTOM:
123 *t++ = FRM_Type; *t++ = FRTYPE_TAB_BOTTOM;
124 goto common_tab;
126 case MXTYPE_TAB_LEFT:
127 *t++ = FRM_Type; *t++ = FRTYPE_TAB_LEFT;
128 goto common_tab;
130 case MXTYPE_TAB_RIGHT:
131 *t++ = FRM_Type; *t++ = FRTYPE_TAB_RIGHT;
133 common_tab:
134 *t++ = BUTTON_SelectOnly; *t++ = TRUE;
135 *t++ = LAB_Place; *t++ = PLACE_IN;
136 *t++ = LAB_SelectedStyle; *t++ = FSF_BOLD;
137 *t++ = LAB_TextAttr; *t++ = (ULONG)md->md_TabsFont;
138 *t++ = md->md_BackFill[0]; *t++ = md->md_BackFill[1];
140 tab = TRUE;
141 break;
143 default:
144 return FALSE;
146 *t++ = TAG_DONE;
149 * Allocate an array to hold the object pointers.
151 if (md->md_Objects = (Object **)BGUI_AllocPoolMem((md->md_MaxLabel + 1) * sizeof(Object *)))
154 * Loop through all labels.
156 while (*labels)
159 * Create a toggle object.
161 if (md->md_Objects[i] = BGUI_NewObject(tab ? BGUI_BUTTON_GADGET : BGUI_RADIOBUTTON_GADGET,
162 LAB_Label, *labels,
163 LAB_LabelID, id,
164 GA_UserData, i,
165 GA_Selected, (i == md->md_ActiveLabel),
166 TAG_MORE, tags))
169 * Add it to the parent group.
171 if (AsmDoMethod(target, GRM_ADDMEMBER, md->md_Objects[i], tab ? TAG_DONE : TAG_MORE, &tags_fix))
173 if (AsmDoMethod(md->md_Objects[i], BASE_ADDMAP, target, id2act))
175 i++;
176 labels++;
177 if (id) id++;
179 else
180 goto addmapError;
182 else
184 addmapError:
186 * Adding failed.
188 DisposeObject(md->md_Objects[i]);
189 goto addError;
191 } else
192 goto addError;
194 rc = TRUE;
196 addError:
198 return rc;
200 REGFUNC_END
202 /// OM_NEW
204 * Create a shiny new object.
206 METHOD(MXClassNew, struct opSet *, ops)
208 MD *md;
209 struct TagItem *tstate, *tags = ops->ops_AttrList, *tag;
210 ULONG rc, data;
211 int type = MXTYPE_RADIOBUTTON;
214 * No labels? No gadget!
216 if (!FindTagItem(MX_Labels, tags))
217 return NULL;
219 tags = DefTagList(BGUI_MX_GADGET, tags);
221 if (GetTagData(MX_TabsObject, FALSE, tags))
223 if (GetTagData(MX_TabsUpsideDown, FALSE, tags))
224 type = MXTYPE_TAB_BOTTOM;
225 else
226 type = MXTYPE_TAB_TOP;
228 type = GetTagData(MX_Type, type, tags);
231 * Let the superclass setup an object for us.
233 if (rc = NewSuperObject(cl, obj, tags))
236 * Initialize instance data.
238 md = INST_DATA(cl, rc);
239 md->md_Type = type;
240 md->md_BackFill[0] = TAG_IGNORE;
241 md->md_Place = PLACE_RIGHT;
243 tstate = tags;
244 while (tag = NextTagItem(&tstate))
246 data = tag->ti_Data;
247 switch (tag->ti_Tag)
249 case MX_Spacing:
251 * If we are a regular mx object we need a default spacing.
253 if (type == MXTYPE_RADIOBUTTON)
254 DoSuperSetMethodNG(cl, (Object *)rc, GROUP_Spacing, data, TAG_DONE);
255 break;
257 case MX_LabelPlace:
259 * Only PLACE_LEFT & PLACE_RIGHT are supported.
261 if ((md->md_Place == PLACE_LEFT) || (md->md_Place == PLACE_RIGHT))
262 md->md_Place = data;
263 break;
265 case MX_Labels:
266 md->md_LabelStrings = (UBYTE **)data;
267 break;
269 case MX_LabelsID:
270 md->md_LabelStringsID = data;
271 break;
273 case MX_TabsTextAttr:
274 md->md_TabsFont = (struct TextAttr *)data;
275 break;
277 case MX_TabsBackFill:
278 md->md_BackFill[0] = FRM_BackFill;
279 md->md_BackFill[1] = data;
280 break;
282 case MX_TabsBackPen:
283 md->md_BackFill[0] = FRM_BackPen;
284 md->md_BackFill[1] = data;
285 break;
287 case MX_TabsBackDriPen:
288 md->md_BackFill[0] = FRM_BackDriPen;
289 md->md_BackFill[1] = data;
290 break;
292 case MX_TabsBackFillHook:
293 md->md_BackFill[0] = FRM_BackFillHook;
294 md->md_BackFill[1] = data;
295 break;
297 case MX_TabsFillPattern:
298 md->md_BackFill[0] = FRM_FillPattern;
299 md->md_BackFill[1] = data;
300 break;
305 * Count the number of labels.
307 md->md_MaxLabel = CountLabels(md->md_LabelStrings);
310 * Sanity check.
312 if (md->md_ActiveLabel < 0)
314 if (type) md->md_ActiveLabel = md->md_MaxLabel;
315 else md->md_ActiveLabel = 0;
317 if (md->md_ActiveLabel > md->md_MaxLabel)
319 if (type) md->md_ActiveLabel = 0;
320 else md->md_ActiveLabel = md->md_MaxLabel;
323 if (AddMXObjects((Object *)rc, md))
325 AsmCoerceMethod(cl, (Object *)rc, OM_SET, tags, NULL);
327 else
330 * Oops, something screwed up.
332 AsmCoerceMethod(cl, (Object *)rc, OM_DISPOSE);
333 rc = 0;
336 FreeTagItems(tags);
338 return rc;
340 METHOD_END
342 /// OM_SET, OM_UPDATE
344 * Change the object attributes.
346 METHOD(MXClassSetUpdate, struct opUpdate *, opu)
348 MD *md = INST_DATA(cl, obj);
349 struct GadgetInfo *gi = opu->opu_GInfo;
350 struct TagItem *tstate = opu->opu_AttrList, *tag, ttag[2];
351 struct opSet set;
352 ULONG data, i;
354 set.MethodID = OM_SET;
355 set.ops_AttrList = ttag;
356 set.ops_GInfo = gi;
357 ttag[1].ti_Tag = TAG_DONE;
360 * First let the superclass do its thing.
362 AsmDoSuperMethodA(cl, obj, (Msg)opu);
365 * Make sure that we are GACT_IMMEDIATE.
367 GADGET(obj)->Activation |= GACT_IMMEDIATE;
368 GADGET(obj)->Activation &= ~GACT_RELVERIFY;
371 * Font?
373 if (FindTagItem(BT_TextAttr, tstate) && md->md_TabsFont)
375 for (i = 0; i <= md->md_MaxLabel; i++)
376 DoSetMethodNG(md->md_Objects[i], BT_TextAttr, md->md_TabsFont, TAG_END);
379 while (tag = NextTagItem(&tstate))
381 data = tag->ti_Data;
382 switch (tag->ti_Tag)
384 case GA_ID:
385 case GA_Disabled:
386 case BT_HelpFile:
387 case BT_HelpNode:
388 case BT_HelpLine:
389 case BT_HelpText:
390 case BT_HelpTextID:
391 case BT_HelpHook:
392 *ttag = *tag;
393 for (i = 0; i <= md->md_MaxLabel; i++)
395 AsmDoMethodA(md->md_Objects[i], (Msg)&set);
397 break;
399 case MX_DisableButton:
400 case MX_EnableButton:
401 if ((data >= 0) && (data <= md->md_MaxLabel))
402 DoSetMethod(md->md_Objects[data], gi, GA_Disabled, (tag->ti_Tag == MX_DisableButton), TAG_DONE);
403 break;
405 case MX_Active:
407 * Sanity check.
409 if ((int)data < 0)
411 if (md->md_Type) data = md->md_MaxLabel;
412 else data = 0;
414 if (data > md->md_MaxLabel)
416 if (md->md_Type) data = 0;
417 else data = md->md_MaxLabel;
419 if (data != md->md_ActiveLabel)
422 * De-select the previous active object if
423 * it's different from the current active one.
425 DoSetMethod(md->md_Objects[md->md_ActiveLabel], gi, GA_Selected, FALSE, TAG_DONE);
426 DoSetMethod(md->md_Objects[data], gi, GA_Selected, TRUE, TAG_DONE);
427 DoNotifyMethod(obj, gi, 0, GA_ID, GADGET(obj)->GadgetID, MX_Active, data, TAG_DONE);
428 md->md_ActiveLabel = data;
430 break;
433 return 1;
435 METHOD_END
437 /// OM_GET
439 * Get an attribute.
441 METHOD(MXClassGet, struct opGet *, opg)
443 MD *md = INST_DATA(cl, obj);
444 ULONG rc = 1;
446 switch (opg->opg_AttrID)
448 case MX_Active:
449 *opg->opg_Storage = md->md_ActiveLabel;
450 break;
452 default:
453 rc = AsmDoSuperMethodA(cl, obj, (Msg)opg);
454 break;
456 return rc;
458 METHOD_END
460 /// OM_DISPOSE
462 * Dispose of the object.
464 METHOD(MXClassDispose, Msg, msg)
466 MD *md = INST_DATA(cl, obj);
468 if (md->md_Objects)
469 BGUI_FreePoolMem(md->md_Objects);
471 return AsmDoSuperMethodA(cl, obj, msg);
473 METHOD_END
475 /// WM_KEYACTIVE
477 * Key activation.
479 METHOD(MXClassKeyActive, struct wmKeyInput *, wmki)
481 MD *md = INST_DATA(cl, obj);
482 UWORD qual = wmki->wmki_IEvent->ie_Qualifier;
483 int num = md->md_ActiveLabel;
484 int max = md->md_MaxLabel;
485 int old, dir;
488 * Shifted activation?
490 dir = (qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) ? -1 : 1;
493 * Scan through the button list for the
494 * next or previous enabled button.
496 old = num;
497 do {
498 num += dir;
499 if (num < 0) num = max;
500 if (num > max) num = 0;
501 if (!(GADGET(md->md_Objects[num])->Flags & GFLG_DISABLED)) break;
503 while (num != old);
506 * Setup the new button.
508 if (num != md->md_ActiveLabel)
509 DoSetMethod(obj, wmki->wmki_GInfo, MX_Active, num, TAG_END);
512 * Return the ID.
514 *(wmki->wmki_ID) = GADGET(obj)->GadgetID;
516 return WMKF_VERIFY;
518 METHOD_END
520 /// Class initialization.
522 * Class function table.
524 STATIC DPFUNC ClassFunc[] = {
525 OM_NEW, (FUNCPTR)MXClassNew,
526 OM_SET, (FUNCPTR)MXClassSetUpdate,
527 OM_UPDATE, (FUNCPTR)MXClassSetUpdate,
528 OM_GET, (FUNCPTR)MXClassGet,
529 OM_DISPOSE, (FUNCPTR)MXClassDispose,
530 WM_KEYACTIVE, (FUNCPTR)MXClassKeyActive,
531 DF_END, NULL
535 * Initialize the mx class.
537 makeproto Class *InitMxClass(void)
539 return BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_GROUP_GADGET,
540 CLASS_ObjectSize, sizeof(MD),
541 CLASS_DFTable, ClassFunc,
542 TAG_DONE);