Bringing ChocolateCaste-0.7 into the main branch.
[AROS-Contrib.git] / bgui / pageclass.c
blobcf86017be8d2c14bb84f0bf18b67335eefe0c70d
1 /*
2 * @(#) $Header$
4 * BGUI library
5 * pageclass.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.3 2004/06/16 20:16:48 verhaegs
15 * Use METHODPROTO, METHOD_END and REGFUNCPROTOn where needed.
17 * Revision 42.2 2000/05/15 19:27:02 stegerg
18 * another hundreds of REG() macro replacements in func headers/protos.
20 * Revision 42.1 2000/05/14 23:32:48 stegerg
21 * changed over 200 function headers which all use register
22 * parameters (oh boy ...), because the simple REG() macro
23 * doesn't work with AROS. And there are still hundreds
24 * of headers left to be fixed :(
26 * Many of these functions would also work with stack
27 * params, but since i have fixed every single one
28 * I encountered up to now, I guess will have to do
29 * the same for the rest.
31 * Revision 42.0 2000/05/09 22:09:50 mlemos
32 * Bumped to revision 42.0 before handing BGUI to AROS team
34 * Revision 41.11 2000/05/09 19:54:51 mlemos
35 * Merged with the branch Manuel_Lemos_fixes.
37 * Revision 41.10.2.4 1999/08/30 04:57:39 mlemos
38 * Made the methods that change group members on-fly setup the gadget
39 * attributes using the window WINDOW_SETUPGADGET method.
41 * Revision 41.10.2.3 1999/08/30 00:22:54 mlemos
42 * Made the BASE_INHIBIT method call the superclass to set the base object
43 * inhibit flag.
44 * Made an added, inserted or replaced page member object be inhibited if it
45 * is not active or the page object is inhibited.
46 * Adjusted the active page number and node pointer when removing a page
47 * member.
49 * Revision 41.10.2.2 1999/08/29 18:58:49 mlemos
50 * Added support to the LGO_Relayout attribute to be able to not relayout a
51 * when calling GRM_ADDMEMBER, GRM_INSERTMEMBER, GRM_REPLACEMEMBER.
53 * Revision 41.10.2.1 1999/08/29 17:08:39 mlemos
54 * Added the implementation of the methods GRM_ADDMEMBER, GRM_REMMEMBER,
55 * GRM_INSERTMEMBER, GRM_REPLACEMEMBER.
57 * Revision 41.10 1998/02/25 21:12:47 mlemos
58 * Bumping to 41.10
60 * Revision 1.1 1998/02/25 17:09:20 mlemos
61 * Ian sources
66 /// Class definitions.
68 #include "include/classdefs.h"
71 * Page members are tied together
72 * using these structures.
74 typedef struct PMember {
75 struct PMember *pm_Next; /* next member */
76 struct PMember *pm_Prev; /* previous member */
77 Object *pm_Object; /* the member */
78 } PM;
80 typedef struct {
81 PM *pl_First; /* first memeber */
82 PM *pl_EndMark; /* end-of-list marker */
83 PM *pl_Last; /* last member */
84 } PML;
87 * Object instance data.
89 typedef struct {
90 ULONG pd_Flags; /* see below */
91 PML pd_Members; /* list of members */
92 PM *pd_Active; /* points to the active member */
93 ULONG pd_Num; /* member number. */
94 } PD;
96 #define PDF_ADDFAILURE (1<<0) /* create time failure */
97 #define PDF_INVERTED (1<<1) /* AddHead() */
98 #define PDF_INHIBIT (1<<2) /* Inhibited? */
103 * Get the member 'num'.
105 STATIC ASM PM *GetMember(REG(a0) PML *l, REG(d0) ULONG mnum)
107 PM *pm;
108 ULONG num = 0;
110 for (pm = l->pl_First; pm->pm_Next; pm = pm->pm_Next, num++)
112 if (num == mnum)
113 return pm;
115 return NULL;
119 * Add members.
121 STATIC ASM VOID AddMembers( REG(a0) Class *cl, REG(a1) Object *obj, REG(a2) struct TagItem *attr)
123 PD *pd = INST_DATA(cl, obj);
124 PM *pm;
125 struct TagItem *tstate = attr;
126 struct TagItem *tag;
129 * Scan attributes.
131 while ((tag = NextTagItem(&tstate)))
133 switch (tag->ti_Tag)
135 case PAGE_Member:
137 * We do not allow NULL-objects.
139 if (tag->ti_Data)
142 * Allocate PMember structure.
144 if ((pm = (PM *)BGUI_AllocPoolMem(sizeof(PM))))
147 * Initialize structure and add it to the list.
149 pm->pm_Object = (Object *)tag->ti_Data;
150 if (pd->pd_Flags & PDF_INVERTED)
151 AddHead((struct List *)&pd->pd_Members, (struct Node *)pm);
152 else
153 AddTail((struct List *)&pd->pd_Members, (struct Node *)pm);
154 } else
156 * Memory error.
158 pd->pd_Flags |= PDF_ADDFAILURE;
159 } else
161 * NULL-object.
163 pd->pd_Flags |= PDF_ADDFAILURE;
164 break;
170 * Set members active/deactive.
172 STATIC ASM VOID DoMembers(REG(a0) PD *pd)
174 PM *pm, *active = pd->pd_Active;
175 BOOL inhibit = pd->pd_Flags & PDF_INHIBIT;
178 * Loop members.
180 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
183 * (De)activate members.
185 AsmDoMethod(pm->pm_Object, BASE_INHIBIT, inhibit || (pm != active));
189 /// OM_NEW
191 * Create a shiny new object.
193 METHOD(PageClassNew, struct opSet *, ops)
195 PD *pd;
196 struct TagItem *tags, *tag;
197 IPTR rc;
199 tags = DefTagList(BGUI_PAGE_GADGET, ops->ops_AttrList);
202 * First we let the superclass
203 * get us an object.
205 if ((rc = NewSuperObject(cl, obj, tags)))
207 pd = INST_DATA(cl, rc);
209 if ((tag = FindTagItem(PAGE_NoBufferRP, tags)))
211 DoSetMethodNG((Object *)rc, BT_Buffer, !(tag->ti_Data), TAG_DONE);
215 * Initialize the page
216 * member list.
218 NewList((struct List *)&pd->pd_Members);
220 GADGET(rc)->Activation |= GACT_RELVERIFY;
222 if (GetTagData(PAGE_Inverted, FALSE, tags))
223 pd->pd_Flags |= PDF_INVERTED;
226 * Add all page members.
228 AddMembers(cl, (Object *)rc, ops->ops_AttrList);
230 pd->pd_Flags &= ~PDF_INVERTED;
233 * When successfull return the object.
235 if (!(pd->pd_Flags & PDF_ADDFAILURE))
238 * Get the active member.
240 pd->pd_Num = GetTagData(PAGE_Active, 0, tags);
241 pd->pd_Active = GetMember(&pd->pd_Members, pd->pd_Num);
242 DoMembers(pd);
244 else
247 * Otherwise dispose of the page.
249 AsmCoerceMethod(cl, (Object *)rc, OM_DISPOSE);
250 rc = 0;
253 FreeTagItems(tags);
255 return rc;
257 METHOD_END
259 /// OM_SET, OM_UPDATE
261 * Set/update page attributes.
263 METHOD(PageClassSetUpdate, struct opUpdate *, opu)
265 PD *pd = INST_DATA( cl, obj );
266 struct TagItem *attr = opu->opu_AttrList, *tag;
267 struct TagItem *tstate = attr;
268 struct GadgetInfo *gi = opu->opu_GInfo;
269 PM *pm;
270 ULONG data;
271 BOOL vc = FALSE;
274 * First we let the superclass
275 * do it's thing.
277 AsmDoSuperMethodA(cl, obj, (Msg)opu);
279 GADGET(obj)->Activation |= GACT_RELVERIFY;
282 * We do not respond
283 * to interim messages.
285 if ((opu->MethodID == OM_UPDATE) && (opu->opu_Flags & OPUF_INTERIM))
286 return 0;
288 while ((tag = NextTagItem(&tstate)))
290 data = tag->ti_Data;
291 switch (tag->ti_Tag)
293 case GA_TopBorder:
294 case GA_BottomBorder:
295 case GA_LeftBorder:
296 case GA_RightBorder:
297 case BT_ParentWindow:
298 case BT_ParentView:
299 case BT_TextAttr:
300 case FRM_ThinFrame:
302 * Pass on attribute to the members.
304 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
305 DoSetMethod(pm->pm_Object, gi, tag->ti_Tag, data, TAG_DONE);
306 break;
308 case PAGE_Active:
309 if (pd->pd_Num != data)
311 pd->pd_Num = data;
312 pd->pd_Active = GetMember(&pd->pd_Members, data);
313 DoMembers(pd);
314 vc = TRUE;
316 break;
321 * When a visual change is necessary we re-render.
323 if (vc)
325 DoRenderMethod(obj, gi, GREDRAW_REDRAW);
326 DoNotifyMethod(obj, gi, 0, PAGE_Active, pd->pd_Num, TAG_END);
328 return 1;
330 METHOD_END
332 /// BASE_RENDER
334 * Render the page.
336 METHOD(PageClassRender, struct bmRender *, bmr)
338 PD *pd = INST_DATA(cl, obj);
339 BC *bc = BASE_DATA(obj);
340 struct BaseInfo *bi = bmr->bmr_BInfo;
343 * Render the baseclass.
345 AsmDoSuperMethodA(cl, obj, (Msg)bmr);
348 * Then we go.
350 if (pd->pd_Active)
353 * Setup the active member size.
355 DoSetMethodNG(pd->pd_Active->pm_Object, GA_Left, bc->bc_InnerBox.Left, GA_Top, bc->bc_InnerBox.Top,
356 GA_Width, bc->bc_InnerBox.Width, GA_Height, bc->bc_InnerBox.Height,
357 BT_ParentGroup, obj, TAG_DONE);
359 * Render it.
361 AsmDoMethod(pd->pd_Active->pm_Object, GM_RENDER, bi, bi->bi_RPort, GREDRAW_REDRAW);
363 return 1;
365 METHOD_END
367 /// OM_GET
369 * They want to know something.
371 METHOD(PageClassGet, struct opGet *, opg )
373 PD *pd = INST_DATA(cl, obj);
374 ULONG rc = 1;
375 IPTR *store = opg->opg_Storage;
377 switch (opg->opg_AttrID)
379 case PAGE_Active:
380 if (pd->pd_Active) STORE pd->pd_Num;
381 else STORE ~0;
382 break;
384 default:
385 rc = AsmDoSuperMethodA(cl, obj, (Msg)opg);
386 break;
388 return rc;
390 METHOD_END
392 /// OM_DISPOSE
394 * Dispose of all objects added to the page-list
395 * and then dispose of the page itself.
397 METHOD(PageClassDispose, Msg, msg)
399 PD *pd = INST_DATA(cl, obj);
400 PM *pm;
403 * Remove all objects from the list.
405 while ((pm = (PM *)RemHead((struct List *)&pd->pd_Members)))
408 * Tell the object to
409 * dispose.
411 AsmDoMethod(pm->pm_Object, OM_DISPOSE);
414 * Deallocate the object
415 * it's PM structure.
417 BGUI_FreePoolMem(pm);
421 * Call the super class
422 * to dispose the pageclass object.
424 return AsmDoSuperMethodA(cl, obj, msg);
426 METHOD_END
428 /// BASE_DIMENSIONS
430 * They want to know something about
431 * our dimensions.
433 METHOD(PageClassDimensions, struct bmDimensions *, bmd)
435 PD *pd = INST_DATA(cl, obj);
436 struct BaseInfo *bi = bmd->bmd_BInfo;
437 PM *pm;
438 UWORD mw = 0, w;
439 UWORD mh = 0, h;
441 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
443 w = h = 0;
444 AsmDoMethod(pm->pm_Object, GRM_DIMENSIONS, bi, bi->bi_RPort, &w, &h, 0);
445 if (w > mw) mw = w;
446 if (h > mh) mh = h;
448 return CalcDimensions(cl, obj, bmd, mw, mh);
450 METHOD_END
452 /// GRM_WHICHOBJECT
454 * Get the object under the mouse.
456 METHOD(PageClassWhichObject, struct grmWhichObject *, grwo)
458 PD *pd = INST_DATA(cl, obj);
459 Object *ob = pd->pd_Active->pm_Object;
461 * Current page member a group?
463 if (IsMulti(ob))
465 * Route message.
467 ob = (Object *)AsmDoMethodA(ob, (Msg)grwo);
469 return (IPTR)ob;
471 METHOD_END
473 /// #?_FORWARD
475 * Forward a message to the active page.
477 METHOD(PageClassForward, Msg, msg)
479 PD *pd = INST_DATA(cl, obj);
480 ULONG rc = GMR_NOREUSE;
483 * Do we have an active member?
485 if (pd->pd_Active)
488 * Forward the message to the
489 * active member.
491 rc = AsmDoMethodA(pd->pd_Active->pm_Object, msg);
494 * Take over the active member's GadgetID.
496 GADGET(obj)->GadgetID = GADGET(pd->pd_Active->pm_Object)->GadgetID;
498 return rc;
500 METHOD_END
502 /// #?_ALL
504 * Pass the message to all submembers.
506 METHOD(PageClassAll, Msg, msg)
508 PD *pd = INST_DATA(cl, obj);
509 PM *pm;
510 ULONG rc = 0;
512 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
514 rc += AsmDoMethodA(pm->pm_Object, msg);
516 return rc;
518 METHOD_END
520 /// BASE_INHIBIT
522 * Inhibit an entire page object.
524 METHOD(PageClassInhibit, struct bmInhibit *, bmi)
526 PD *pd = INST_DATA(cl, obj);
527 PM *pm, *active = pd->pd_Active;
528 BOOL inhibit = bmi->bmi_Inhibit;
530 if(!AsmDoSuperMethodA(cl, obj, (Msg)bmi))
531 return(0);
532 if (inhibit) pd->pd_Flags |= PDF_INHIBIT;
533 else pd->pd_Flags &= ~PDF_INHIBIT;
535 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
537 AsmDoMethod(pm->pm_Object, BASE_INHIBIT, inhibit || (pm != active));
540 return 1;
542 METHOD_END
544 /// BASE_IS_MULTI
545 METHOD(PageClassIsMulti, Msg, msg)
547 return TRUE;
549 METHOD_END
553 /// GRM_ADDMEMBER
555 * Add a member to the group.
557 METHOD(PageClassAddMember, struct grmAddMember *, grma)
559 PD *pd = INST_DATA(cl, obj);
560 PM *pm;
562 if(!(pm = (PM *)BGUI_AllocPoolMem(sizeof(PM))))
563 return(FALSE);
564 pm->pm_Object=grma->grma_Member;
565 Forbid();
566 AddTail((struct List *)&pd->pd_Members, (struct Node *)pm);
567 Permit();
569 if(BASE_DATA(obj)->bc_Window)
571 struct TagItem tags[2];
573 tags[0].ti_Tag=BT_Inhibit;
574 tags[0].ti_Data=TRUE;
575 tags[1].ti_Tag=TAG_END;
576 AsmDoMethod(BASE_DATA(obj)->bc_Window, WM_SETUPGADGET,pm->pm_Object,&tags);
580 * Try to re-layout the group.
583 if(GetTagData(LGO_Relayout, TRUE, (struct TagItem *)&grma->grma_Attr)
584 && !RelayoutGroup(obj))
586 Forbid();
587 Remove((struct Node *)pm);
588 Permit();
589 BGUI_FreePoolMem(pm);
590 RelayoutGroup(obj);
592 return FALSE;
594 return TRUE;
596 METHOD_END
599 /// GRM_REMMEMBER
601 * Remove an object from the list.
603 METHOD(PageClassRemMember, struct grmRemMember *, grmr)
605 PD *pd = INST_DATA(cl, obj);
606 PM *pm;
608 if(!grmr->grmr_Member)
609 return (IPTR)NULL;
610 Forbid();
611 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
613 if(pm->pm_Object==grmr->grmr_Member)
615 if(pm==pd->pd_Active)
616 pd->pd_Active=(pm->pm_Prev->pm_Prev ? pm->pm_Prev : pm->pm_Next);
617 Remove((struct Node *)pm);
618 BGUI_FreePoolMem(pm);
619 for(pd->pd_Num=0,pm=pd->pd_Members.pl_First;pm->pm_Next && pm!=pd->pd_Active;pd->pd_Num++,pm=pm->pm_Next);
620 Permit();
621 RelayoutGroup(obj);
622 return((IPTR)grmr->grmr_Member);
625 Permit();
626 return (IPTR)NULL;
628 METHOD_END
631 /// GRM_INSERTMEMBER
633 * Insert a member in the group.
635 METHOD(PageClassInsert, struct grmInsertMember *, grmi)
637 PD *pd = INST_DATA(cl, obj);
638 PM *pm,*new_pm;
640 if(!grmi->grmi_Member
641 || !(new_pm = (PM *)BGUI_AllocPoolMem(sizeof(PM))))
642 return(FALSE);
643 new_pm->pm_Object=grmi->grmi_Member;
644 Forbid();
645 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
647 if(pm->pm_Object==grmi->grmi_Pred)
649 Insert((struct List *)&pd->pd_Members,(struct Node *)new_pm,(struct Node *)pm);
650 Permit();
652 if(BASE_DATA(obj)->bc_Window)
654 struct TagItem tags[2];
656 tags[0].ti_Tag=BT_Inhibit;
657 tags[0].ti_Data=TRUE;
658 tags[1].ti_Tag=TAG_END;
659 AsmDoMethod(BASE_DATA(obj)->bc_Window, WM_SETUPGADGET,pm->pm_Object,&tags);
663 * Try to re-layout the group.
665 if(GetTagData(LGO_Relayout, TRUE, (struct TagItem *)&grmi->grmi_Attr)
666 && !RelayoutGroup(obj))
668 Forbid();
669 Remove((struct Node *)new_pm);
670 Permit();
671 BGUI_FreePoolMem(new_pm);
672 RelayoutGroup(obj);
674 return FALSE;
676 return TRUE;
679 Permit();
680 BGUI_FreePoolMem(new_pm);
681 return(FALSE);
683 METHOD_END
686 /// GRM_REPLACEMEMBER
688 * Replace a member in the group.
690 METHOD(PageClassReplace, struct grmReplaceMember *, grrm)
692 PD *pd = INST_DATA(cl, obj);
693 PM *pm;
696 * No NULL-objects.
698 if(!grrm->grrm_MemberA
699 || !grrm->grrm_MemberB)
700 return(FALSE);
701 Forbid();
702 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
704 if(pm->pm_Object==grrm->grrm_MemberA)
706 pm->pm_Object=grrm->grrm_MemberB;
707 Permit();
709 if(BASE_DATA(obj)->bc_Window)
711 struct TagItem tags[2];
713 tags[0].ti_Tag=BT_Inhibit;
714 tags[0].ti_Data=((pd->pd_Flags & PDF_INHIBIT)!=0 || (pm != pd->pd_Active));
715 tags[1].ti_Tag=TAG_END;
716 AsmDoMethod(BASE_DATA(obj)->bc_Window, WM_SETUPGADGET,pm->pm_Object,&tags);
720 * Try to re-layout the group.
722 if(GetTagData(LGO_Relayout, TRUE, (struct TagItem *)&grrm->grrm_Attr)
723 && !RelayoutGroup(obj))
725 Forbid();
726 pm->pm_Object=grrm->grrm_MemberA;
727 Permit();
728 RelayoutGroup(obj);
730 return FALSE;
732 return((IPTR)grrm->grrm_MemberA);
735 Permit();
736 return 0;
738 METHOD_END
740 /// Class initialization.
742 * Function table.
744 STATIC DPFUNC ClassFunc[] = {
745 { BASE_RENDER, PageClassRender },
746 { BASE_DIMENSIONS, PageClassDimensions },
747 { OM_NEW, PageClassNew },
748 { OM_SET, PageClassSetUpdate },
749 { OM_UPDATE, PageClassSetUpdate },
750 { OM_DISPOSE, PageClassDispose },
751 { OM_GET, PageClassGet },
752 { GM_GOINACTIVE, PageClassForward },
753 { GM_GOACTIVE, PageClassForward },
754 { GM_HANDLEINPUT, PageClassForward },
755 { GM_HITTEST, PageClassForward },
756 { GRM_WHICHOBJECT, PageClassWhichObject },
757 { BASE_INHIBIT, PageClassInhibit },
758 { BASE_MOVEBOUNDS, PageClassForward },
759 { BASE_LOCALIZE, PageClassAll },
760 { BASE_KEYLABEL, PageClassAll },
761 { BASE_FINDKEY, PageClassForward },
762 { BASE_SHOWHELP, PageClassForward },
763 { BASE_IS_MULTI, PageClassIsMulti },
764 { GRM_ADDMEMBER, PageClassAddMember },
765 { GRM_REMMEMBER, PageClassRemMember },
766 { GRM_INSERTMEMBER, PageClassInsert },
767 { GRM_REPLACEMEMBER, PageClassReplace },
768 { DF_END },
772 * Simple initialization of the page class.
774 makeproto Class *InitPageClass(void)
776 return BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_BASE_GADGET,
777 CLASS_ObjectSize, sizeof(PD),
778 CLASS_DFTable, ClassFunc,
779 TAG_DONE);