fix remapping behavior. Remapping is only necessary if we are rendering on the workbe...
[AROS-Contrib.git] / bgui / mxclass.c
bloba01a0824d3629eafd304945cae536f160f069579
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 ULONG 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 struct TagItem id2act[] = {
78 { GA_UserData, MX_Active, },
79 { GA_Selected, TAG_IGNORE, },
80 { TAG_END, 0 },
84 * Module prototypes.
87 ///
88 /// AddMXObjects()
90 * Add MX objects.
92 STATIC ASM BOOL AddMXObjects(REG(a0) Object *target, REG(a1) MD *md)
94 UBYTE **labels = md->md_LabelStrings;
95 ULONG i = 0;
96 ULONG id = md->md_LabelStringsID;
97 BOOL rc = FALSE, tab;
98 struct TagItem tags[16], *t = &tags[0];
100 static const struct TagItem tags_fix[] = {
101 { LGO_FixMinWidth, TRUE },
102 { LGO_FixMinHeight, TRUE },
103 { TAG_DONE },
106 t->ti_Tag = GA_ToggleSelect; t->ti_Data = TRUE; t++;
107 t->ti_Tag = GA_ID; t->ti_Data = GADGET(target)->GadgetID; t++;
108 t->ti_Tag = GA_Disabled; t->ti_Data = GADGET(target)->Flags & GFLG_DISABLED; t++;
109 t->ti_Tag = LAB_SelectedDriPen; t->ti_Data = TEXTPEN; t++;
111 switch (md->md_Type)
113 case MXTYPE_RADIOBUTTON:
114 t->ti_Tag = LAB_Place; t->ti_Data = md->md_Place; t++;
116 tab = FALSE;
117 break;
119 case MXTYPE_TAB_TOP:
120 t->ti_Tag = FRM_Type; t->ti_Data = FRTYPE_TAB_TOP; t++;
121 goto common_tab;
123 case MXTYPE_TAB_BOTTOM:
124 t->ti_Tag = FRM_Type; t->ti_Data = FRTYPE_TAB_BOTTOM; t++;
125 goto common_tab;
127 case MXTYPE_TAB_LEFT:
128 t->ti_Tag = FRM_Type; t->ti_Data = FRTYPE_TAB_LEFT; t++;
129 goto common_tab;
131 case MXTYPE_TAB_RIGHT:
132 t->ti_Tag = FRM_Type; t->ti_Data = FRTYPE_TAB_RIGHT; t++;
134 common_tab:
135 t->ti_Tag = BUTTON_SelectOnly; t->ti_Data = TRUE; t++;
136 t->ti_Tag = LAB_Place; t->ti_Data = PLACE_IN; t++;
137 t->ti_Tag = LAB_SelectedStyle; t->ti_Data = FSF_BOLD; t++;
138 t->ti_Tag = LAB_TextAttr; t->ti_Data = (IPTR)md->md_TabsFont; t++;
139 t->ti_Tag = md->md_BackFill[0]; t->ti_Data = md->md_BackFill[1]; t++;
141 tab = TRUE;
142 break;
144 default:
145 return FALSE;
147 t->ti_Tag = TAG_DONE;
148 t++;
151 * Allocate an array to hold the object pointers.
153 if ((md->md_Objects = (Object **)BGUI_AllocPoolMem((md->md_MaxLabel + 1) * sizeof(Object *))))
156 * Loop through all labels.
158 while (*labels)
161 * Create a toggle object.
163 if ((md->md_Objects[i] = BGUI_NewObject(tab ? BGUI_BUTTON_GADGET : BGUI_RADIOBUTTON_GADGET,
164 LAB_Label, *labels,
165 LAB_LabelID, id,
166 GA_UserData, i,
167 GA_Selected, (i == md->md_ActiveLabel),
168 TAG_MORE, tags)))
171 * Add it to the parent group.
173 if (AsmDoMethod(target, GRM_ADDMEMBER, md->md_Objects[i], tab ? TAG_DONE : TAG_MORE, &tags_fix))
175 if (AsmDoMethod(md->md_Objects[i], BASE_ADDMAP, target, id2act))
177 i++;
178 labels++;
179 if (id) id++;
181 else
182 goto addmapError;
184 else
186 addmapError:
188 * Adding failed.
190 DisposeObject(md->md_Objects[i]);
191 goto addError;
193 } else
194 goto addError;
196 rc = TRUE;
198 addError:
200 return rc;
204 /// OM_NEW
206 * Create a shiny new object.
208 STATIC METHOD(MXClassNew, struct opSet *, ops)
210 MD *md;
211 IPTR rc, data;
212 struct TagItem *tstate;
213 struct TagItem *tags = ops->ops_AttrList, *tag;
214 int type = MXTYPE_RADIOBUTTON;
217 * No labels? No gadget!
219 if (!FindTagItem(MX_Labels, tags))
220 return 0;
222 tags = DefTagList(BGUI_MX_GADGET, tags);
224 if (GetTagData(MX_TabsObject, FALSE, tags))
226 if (GetTagData(MX_TabsUpsideDown, FALSE, tags))
227 type = MXTYPE_TAB_BOTTOM;
228 else
229 type = MXTYPE_TAB_TOP;
231 type = GetTagData(MX_Type, type, tags);
234 * Let the superclass setup an object for us.
236 if ((rc = NewSuperObject(cl, obj, tags)))
239 * Initialize instance data.
241 md = INST_DATA(cl, rc);
242 md->md_Type = type;
243 md->md_BackFill[0] = TAG_IGNORE;
244 md->md_Place = PLACE_RIGHT;
246 tstate = tags;
247 while ((tag = NextTagItem(&tstate)))
249 data = tag->ti_Data;
250 switch (tag->ti_Tag)
252 case MX_Spacing:
254 * If we are a regular mx object we need a default spacing.
256 if (type == MXTYPE_RADIOBUTTON)
257 DoSuperSetMethodNG(cl, (Object *)rc, GROUP_Spacing, data, TAG_DONE);
258 break;
260 case MX_LabelPlace:
262 * Only PLACE_LEFT & PLACE_RIGHT are supported.
264 if ((md->md_Place == PLACE_LEFT) || (md->md_Place == PLACE_RIGHT))
265 md->md_Place = data;
266 break;
268 case MX_Labels:
269 md->md_LabelStrings = (UBYTE **)data;
270 break;
272 case MX_LabelsID:
273 md->md_LabelStringsID = data;
274 break;
276 case MX_TabsTextAttr:
277 md->md_TabsFont = (struct TextAttr *)data;
278 break;
280 case MX_TabsBackFill:
281 md->md_BackFill[0] = FRM_BackFill;
282 md->md_BackFill[1] = data;
283 break;
285 case MX_TabsBackPen:
286 md->md_BackFill[0] = FRM_BackPen;
287 md->md_BackFill[1] = data;
288 break;
290 case MX_TabsBackDriPen:
291 md->md_BackFill[0] = FRM_BackDriPen;
292 md->md_BackFill[1] = data;
293 break;
295 case MX_TabsBackFillHook:
296 md->md_BackFill[0] = FRM_BackFillHook;
297 md->md_BackFill[1] = data;
298 break;
300 case MX_TabsFillPattern:
301 md->md_BackFill[0] = FRM_FillPattern;
302 md->md_BackFill[1] = data;
303 break;
308 * Count the number of labels.
310 md->md_MaxLabel = CountLabels(md->md_LabelStrings);
313 * Sanity check.
315 if (md->md_ActiveLabel > md->md_MaxLabel)
317 if (type) md->md_ActiveLabel = 0;
318 else md->md_ActiveLabel = md->md_MaxLabel;
321 if (AddMXObjects((Object *)rc, md))
323 AsmCoerceMethod(cl, (Object *)rc, OM_SET, tags, NULL);
325 else
328 * Oops, something screwed up.
330 AsmCoerceMethod(cl, (Object *)rc, OM_DISPOSE);
331 rc = 0;
334 FreeTagItems(tags);
336 return rc;
338 METHOD_END
340 /// OM_SET, OM_UPDATE
342 * Change the object attributes.
344 STATIC METHOD(MXClassSetUpdate, struct opUpdate *, opu)
346 MD *md = INST_DATA(cl, obj);
347 struct GadgetInfo *gi = opu->opu_GInfo;
348 struct TagItem *tstate = opu->opu_AttrList;
349 struct TagItem *tag, ttag[2];
350 struct opSet set;
351 ULONG data, i;
353 set.MethodID = OM_SET;
354 set.ops_AttrList = ttag;
355 set.ops_GInfo = gi;
356 ttag[1].ti_Tag = TAG_DONE;
359 * First let the superclass do its thing.
361 AsmDoSuperMethodA(cl, obj, (Msg)opu);
364 * Make sure that we are GACT_IMMEDIATE.
366 GADGET(obj)->Activation |= GACT_IMMEDIATE;
367 GADGET(obj)->Activation &= ~GACT_RELVERIFY;
370 * Font?
372 if (FindTagItem(BT_TextAttr, tstate) && md->md_TabsFont)
374 for (i = 0; i <= md->md_MaxLabel; i++)
375 DoSetMethodNG(md->md_Objects[i], BT_TextAttr, md->md_TabsFont, TAG_END);
378 while ((tag = NextTagItem(&tstate)))
380 data = tag->ti_Data;
381 switch (tag->ti_Tag)
383 case GA_ID:
384 case GA_Disabled:
385 case BT_HelpFile:
386 case BT_HelpNode:
387 case BT_HelpLine:
388 case BT_HelpText:
389 case BT_HelpTextID:
390 case BT_HelpHook:
391 *ttag = *tag;
392 for (i = 0; i <= md->md_MaxLabel; i++)
394 AsmDoMethodA(md->md_Objects[i], (Msg)&set);
396 break;
398 case MX_DisableButton:
399 case MX_EnableButton:
400 if ((data >= 0) && (data <= md->md_MaxLabel))
401 DoSetMethod(md->md_Objects[data], gi, GA_Disabled, (tag->ti_Tag == MX_DisableButton), TAG_DONE);
402 break;
404 case MX_Active:
406 * Sanity check.
408 if (data > md->md_MaxLabel)
410 if (md->md_Type) data = 0;
411 else data = md->md_MaxLabel;
413 if (data != md->md_ActiveLabel)
416 * De-select the previous active object if
417 * it's different from the current active one.
419 DoSetMethod(md->md_Objects[md->md_ActiveLabel], gi, GA_Selected, FALSE, TAG_DONE);
420 DoSetMethod(md->md_Objects[data], gi, GA_Selected, TRUE, TAG_DONE);
421 DoNotifyMethod(obj, gi, 0, GA_ID, GADGET(obj)->GadgetID, MX_Active, data, TAG_DONE);
422 md->md_ActiveLabel = data;
424 break;
427 return 1;
429 METHOD_END
431 /// OM_GET
433 * Get an attribute.
435 STATIC METHOD(MXClassGet, struct opGet *, opg)
437 MD *md = INST_DATA(cl, obj);
438 ULONG rc = 1;
440 switch (opg->opg_AttrID)
442 case MX_Active:
443 *opg->opg_Storage = md->md_ActiveLabel;
444 break;
446 default:
447 rc = AsmDoSuperMethodA(cl, obj, (Msg)opg);
448 break;
450 return rc;
452 METHOD_END
454 /// OM_DISPOSE
456 * Dispose of the object.
458 STATIC METHOD(MXClassDispose, Msg, msg)
460 MD *md = INST_DATA(cl, obj);
462 if (md->md_Objects)
463 BGUI_FreePoolMem(md->md_Objects);
465 return AsmDoSuperMethodA(cl, obj, msg);
467 METHOD_END
469 /// WM_KEYACTIVE
471 * Key activation.
473 STATIC METHOD(MXClassKeyActive, struct wmKeyInput *, wmki)
475 MD *md = INST_DATA(cl, obj);
476 UWORD qual = wmki->wmki_IEvent->ie_Qualifier;
477 ULONG num = md->md_ActiveLabel;
478 ULONG max = md->md_MaxLabel;
479 int old, dir;
482 * Shifted activation?
484 dir = (qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) ? -1 : 1;
487 * Scan through the button list for the
488 * next or previous enabled button.
490 old = num;
491 do {
492 num += dir;
493 if (num < 0) num = max;
494 if (num > max) num = 0;
495 if (!(GADGET(md->md_Objects[num])->Flags & GFLG_DISABLED)) break;
497 while (num != old);
500 * Setup the new button.
502 if (num != md->md_ActiveLabel)
503 DoSetMethod(obj, wmki->wmki_GInfo, MX_Active, num, TAG_END);
506 * Return the ID.
508 *(wmki->wmki_ID) = GADGET(obj)->GadgetID;
510 return WMKF_VERIFY;
512 METHOD_END
514 /// Class initialization.
516 * Class function table.
518 STATIC DPFUNC ClassFunc[] = {
519 { OM_NEW, MXClassNew, },
520 { OM_SET, MXClassSetUpdate, },
521 { OM_UPDATE, MXClassSetUpdate, },
522 { OM_GET, MXClassGet, },
523 { OM_DISPOSE, MXClassDispose, },
524 { WM_KEYACTIVE, MXClassKeyActive, },
525 { DF_END, NULL },
529 * Initialize the mx class.
531 makeproto Class *InitMxClass(void)
533 return BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_GROUP_GADGET,
534 CLASS_ObjectSize, sizeof(MD),
535 CLASS_DFTable, ClassFunc,
536 TAG_DONE);