Experiment:
[AROS-Contrib.git] / bgui / pageclass.c
blobd9b997793248fc71e0ed2a1d132dc14aaa0af08b
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)
106 STATIC ASM REGFUNC2(PM *, GetMember,
107 REGPARAM(A0, PML *, l),
108 REGPARAM(D0, ULONG, mnum))
110 PM *pm;
111 ULONG num = 0;
113 for (pm = l->pl_First; pm->pm_Next; pm = pm->pm_Next, num++)
115 if (num == mnum)
116 return pm;
118 return NULL;
120 REGFUNC_END
123 * Add members.
125 //STATIC ASM VOID AddMembers( REG(a0) Class *cl, REG(a1) Object *obj, REG(a2) struct TagItem *attr)
126 STATIC ASM REGFUNC3(VOID, AddMembers,
127 REGPARAM(A0, Class *, cl),
128 REGPARAM(A1, Object *, obj),
129 REGPARAM(A2, struct TagItem *, attr))
131 PD *pd = INST_DATA(cl, obj);
132 PM *pm;
133 struct TagItem *tstate = attr, *tag;
136 * Scan attributes.
138 while (tag = NextTagItem(&tstate))
140 switch (tag->ti_Tag)
142 case PAGE_Member:
144 * We do not allow NULL-objects.
146 if (tag->ti_Data)
149 * Allocate PMember structure.
151 if (pm = (PM *)BGUI_AllocPoolMem(sizeof(PM)))
154 * Initialize structure and add it to the list.
156 pm->pm_Object = (Object *)tag->ti_Data;
157 if (pd->pd_Flags & PDF_INVERTED)
158 AddHead((struct List *)&pd->pd_Members, (struct Node *)pm);
159 else
160 AddTail((struct List *)&pd->pd_Members, (struct Node *)pm);
161 } else
163 * Memory error.
165 pd->pd_Flags |= PDF_ADDFAILURE;
166 } else
168 * NULL-object.
170 pd->pd_Flags |= PDF_ADDFAILURE;
171 break;
175 REGFUNC_END
178 * Set members active/deactive.
180 //STATIC ASM VOID DoMembers(REG(a0) PD *pd)
181 STATIC ASM REGFUNC1(VOID, DoMembers,
182 REGPARAM(A0, PD *, pd))
184 PM *pm, *active = pd->pd_Active;
185 BOOL inhibit = pd->pd_Flags & PDF_INHIBIT;
188 * Loop members.
190 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
193 * (De)activate members.
195 AsmDoMethod(pm->pm_Object, BASE_INHIBIT, inhibit || (pm != active));
198 REGFUNC_END
200 /// OM_NEW
202 * Create a shiny new object.
204 METHOD(PageClassNew, struct opSet *, ops)
206 PD *pd;
207 struct TagItem *tags, *tag;
208 ULONG rc;
210 tags = DefTagList(BGUI_PAGE_GADGET, ops->ops_AttrList);
213 * First we let the superclass
214 * get us an object.
216 if (rc = NewSuperObject(cl, obj, tags))
218 pd = INST_DATA(cl, rc);
220 if (tag = FindTagItem(PAGE_NoBufferRP, tags))
222 DoSetMethodNG((Object *)rc, BT_Buffer, !(tag->ti_Data), TAG_DONE);
226 * Initialize the page
227 * member list.
229 NewList((struct List *)&pd->pd_Members);
231 GADGET(rc)->Activation |= GACT_RELVERIFY;
233 if (GetTagData(PAGE_Inverted, FALSE, tags))
234 pd->pd_Flags |= PDF_INVERTED;
237 * Add all page members.
239 AddMembers(cl, (Object *)rc, ops->ops_AttrList);
241 pd->pd_Flags &= ~PDF_INVERTED;
244 * When successfull return the object.
246 if (!(pd->pd_Flags & PDF_ADDFAILURE))
249 * Get the active member.
251 pd->pd_Num = GetTagData(PAGE_Active, 0, tags);
252 pd->pd_Active = GetMember(&pd->pd_Members, pd->pd_Num);
253 DoMembers(pd);
255 else
258 * Otherwise dispose of the page.
260 AsmCoerceMethod(cl, (Object *)rc, OM_DISPOSE);
261 rc = 0;
264 FreeTagItems(tags);
266 return rc;
268 METHOD_END
270 /// OM_SET, OM_UPDATE
272 * Set/update page attributes.
274 METHOD(PageClassSetUpdate, struct opUpdate *, opu)
276 PD *pd = INST_DATA( cl, obj );
277 struct TagItem *attr = opu->opu_AttrList, *tstate = attr, *tag;
278 struct GadgetInfo *gi = opu->opu_GInfo;
279 PM *pm;
280 ULONG data;
281 BOOL vc = FALSE;
284 * First we let the superclass
285 * do it's thing.
287 AsmDoSuperMethodA(cl, obj, (Msg)opu);
289 GADGET(obj)->Activation |= GACT_RELVERIFY;
292 * We do not respond
293 * to interim messages.
295 if ((opu->MethodID == OM_UPDATE) && (opu->opu_Flags & OPUF_INTERIM))
296 return 0;
298 while (tag = NextTagItem(&tstate))
300 data = tag->ti_Data;
301 switch (tag->ti_Tag)
303 case GA_TopBorder:
304 case GA_BottomBorder:
305 case GA_LeftBorder:
306 case GA_RightBorder:
307 case BT_ParentWindow:
308 case BT_ParentView:
309 case BT_TextAttr:
310 case FRM_ThinFrame:
312 * Pass on attribute to the members.
314 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
315 DoSetMethod(pm->pm_Object, gi, tag->ti_Tag, data, TAG_DONE);
316 break;
318 case PAGE_Active:
319 if (pd->pd_Num != data)
321 pd->pd_Num = data;
322 pd->pd_Active = GetMember(&pd->pd_Members, data);
323 DoMembers(pd);
324 vc = TRUE;
326 break;
331 * When a visual change is necessary we re-render.
333 if (vc)
335 DoRenderMethod(obj, gi, GREDRAW_REDRAW);
336 DoNotifyMethod(obj, gi, 0, PAGE_Active, pd->pd_Num, TAG_END);
338 return 1;
340 METHOD_END
342 /// BASE_RENDER
344 * Render the page.
346 METHOD(PageClassRender, struct bmRender *, bmr)
348 PD *pd = INST_DATA(cl, obj);
349 BC *bc = BASE_DATA(obj);
350 struct BaseInfo *bi = bmr->bmr_BInfo;
353 * Render the baseclass.
355 AsmDoSuperMethodA(cl, obj, (Msg)bmr);
358 * Then we go.
360 if (pd->pd_Active)
363 * Setup the active member size.
365 DoSetMethodNG(pd->pd_Active->pm_Object, GA_Left, bc->bc_InnerBox.Left, GA_Top, bc->bc_InnerBox.Top,
366 GA_Width, bc->bc_InnerBox.Width, GA_Height, bc->bc_InnerBox.Height,
367 BT_ParentGroup, obj, TAG_DONE);
369 * Render it.
371 AsmDoMethod(pd->pd_Active->pm_Object, GM_RENDER, bi, bi->bi_RPort, GREDRAW_REDRAW);
373 return 1;
375 METHOD_END
377 /// OM_GET
379 * They want to know something.
381 METHOD(PageClassGet, struct opGet *, opg )
383 PD *pd = INST_DATA(cl, obj);
384 ULONG rc = 1, *store = opg->opg_Storage;
386 switch (opg->opg_AttrID)
388 case PAGE_Active:
389 if (pd->pd_Active) STORE pd->pd_Num;
390 else STORE ~0;
391 break;
393 default:
394 rc = AsmDoSuperMethodA(cl, obj, (Msg)opg);
395 break;
397 return rc;
399 METHOD_END
401 /// OM_DISPOSE
403 * Dispose of all objects added to the page-list
404 * and then dispose of the page itself.
406 METHOD(PageClassDispose, Msg, msg)
408 PD *pd = INST_DATA(cl, obj);
409 PM *pm;
412 * Remove all objects from the list.
414 while (pm = (PM *)RemHead((struct List *)&pd->pd_Members))
417 * Tell the object to
418 * dispose.
420 AsmDoMethod(pm->pm_Object, OM_DISPOSE);
423 * Deallocate the object
424 * it's PM structure.
426 BGUI_FreePoolMem(pm);
430 * Call the super class
431 * to dispose the pageclass object.
433 return AsmDoSuperMethodA(cl, obj, msg);
435 METHOD_END
437 /// BASE_DIMENSIONS
439 * They want to know something about
440 * our dimensions.
442 METHOD(PageClassDimensions, struct bmDimensions *, bmd)
444 PD *pd = INST_DATA(cl, obj);
445 struct BaseInfo *bi = bmd->bmd_BInfo;
446 PM *pm;
447 UWORD mw = 0, w;
448 UWORD mh = 0, h;
450 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
452 w = h = 0;
453 AsmDoMethod(pm->pm_Object, GRM_DIMENSIONS, bi, bi->bi_RPort, &w, &h, 0);
454 if (w > mw) mw = w;
455 if (h > mh) mh = h;
457 return CalcDimensions(cl, obj, bmd, mw, mh);
459 METHOD_END
461 /// GRM_WHICHOBJECT
463 * Get the object under the mouse.
465 METHOD(PageClassWhichObject, struct grmWhichObject *, grwo)
467 PD *pd = INST_DATA(cl, obj);
468 Object *ob = pd->pd_Active->pm_Object;
470 * Current page member a group?
472 if (IsMulti(ob))
474 * Route message.
476 ob = (Object *)AsmDoMethodA(ob, (Msg)grwo);
478 return (ULONG)ob;
480 METHOD_END
482 /// #?_FORWARD
484 * Forward a message to the active page.
486 METHOD(PageClassForward, Msg, msg)
488 PD *pd = INST_DATA(cl, obj);
489 ULONG rc = GMR_NOREUSE;
492 * Do we have an active member?
494 if (pd->pd_Active)
497 * Forward the message to the
498 * active member.
500 rc = AsmDoMethodA(pd->pd_Active->pm_Object, msg);
503 * Take over the active member's GadgetID.
505 GADGET(obj)->GadgetID = GADGET(pd->pd_Active->pm_Object)->GadgetID;
507 return rc;
509 METHOD_END
511 /// #?_ALL
513 * Pass the message to all submembers.
515 METHOD(PageClassAll, Msg, msg)
517 PD *pd = INST_DATA(cl, obj);
518 PM *pm;
519 ULONG rc = 0;
521 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
523 rc += AsmDoMethodA(pm->pm_Object, msg);
525 return rc;
527 METHOD_END
529 /// BASE_INHIBIT
531 * Inhibit an entire page object.
533 METHOD(PageClassInhibit, struct bmInhibit *, bmi)
535 PD *pd = INST_DATA(cl, obj);
536 PM *pm, *active = pd->pd_Active;
537 BOOL inhibit = bmi->bmi_Inhibit;
539 if(!AsmDoSuperMethodA(cl, obj, (Msg)bmi))
540 return(0);
541 if (inhibit) pd->pd_Flags |= PDF_INHIBIT;
542 else pd->pd_Flags &= ~PDF_INHIBIT;
544 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
546 AsmDoMethod(pm->pm_Object, BASE_INHIBIT, inhibit || (pm != active));
549 return 1;
551 METHOD_END
553 /// BASE_IS_MULTI
554 METHOD(PageClassIsMulti, Msg, msg)
556 return TRUE;
558 METHOD_END
562 /// GRM_ADDMEMBER
564 * Add a member to the group.
566 METHOD(PageClassAddMember, struct grmAddMember *, grma)
568 PD *pd = INST_DATA(cl, obj);
569 PM *pm;
571 if(!(pm = (PM *)BGUI_AllocPoolMem(sizeof(PM))))
572 return(FALSE);
573 pm->pm_Object=grma->grma_Member;
574 Forbid();
575 AddTail((struct List *)&pd->pd_Members, (struct Node *)pm);
576 Permit();
578 if(BASE_DATA(obj)->bc_Window)
580 struct TagItem tags[2];
582 tags[0].ti_Tag=BT_Inhibit;
583 tags[0].ti_Data=TRUE;
584 tags[1].ti_Tag=TAG_END;
585 AsmDoMethod(BASE_DATA(obj)->bc_Window, WM_SETUPGADGET,pm->pm_Object,&tags);
589 * Try to re-layout the group.
592 if(GetTagData(LGO_Relayout, TRUE, (struct TagItem *)&grma->grma_Attr)
593 && !RelayoutGroup(obj))
595 Forbid();
596 Remove((struct Node *)pm);
597 Permit();
598 BGUI_FreePoolMem(pm);
599 RelayoutGroup(obj);
601 return FALSE;
603 return TRUE;
605 METHOD_END
608 /// GRM_REMMEMBER
610 * Remove an object from the list.
612 METHOD(PageClassRemMember, struct grmRemMember *, grmr)
614 PD *pd = INST_DATA(cl, obj);
615 PM *pm;
617 if(!grmr->grmr_Member)
618 return(NULL);
619 Forbid();
620 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
622 if(pm->pm_Object==grmr->grmr_Member)
624 if(pm==pd->pd_Active)
625 pd->pd_Active=(pm->pm_Prev->pm_Prev ? pm->pm_Prev : pm->pm_Next);
626 Remove((struct Node *)pm);
627 BGUI_FreePoolMem(pm);
628 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);
629 Permit();
630 RelayoutGroup(obj);
631 return((ULONG)grmr->grmr_Member);
634 Permit();
635 return(NULL);
637 METHOD_END
640 /// GRM_INSERTMEMBER
642 * Insert a member in the group.
644 METHOD(PageClassInsert, struct grmInsertMember *, grmi)
646 PD *pd = INST_DATA(cl, obj);
647 PM *pm,*new_pm;
649 if(!grmi->grmi_Member
650 || !(new_pm = (PM *)BGUI_AllocPoolMem(sizeof(PM))))
651 return(FALSE);
652 new_pm->pm_Object=grmi->grmi_Member;
653 Forbid();
654 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
656 if(pm->pm_Object==grmi->grmi_Pred)
658 Insert((struct List *)&pd->pd_Members,(struct Node *)new_pm,(struct Node *)pm);
659 Permit();
661 if(BASE_DATA(obj)->bc_Window)
663 struct TagItem tags[2];
665 tags[0].ti_Tag=BT_Inhibit;
666 tags[0].ti_Data=TRUE;
667 tags[1].ti_Tag=TAG_END;
668 AsmDoMethod(BASE_DATA(obj)->bc_Window, WM_SETUPGADGET,pm->pm_Object,&tags);
672 * Try to re-layout the group.
674 if(GetTagData(LGO_Relayout, TRUE, (struct TagItem *)&grmi->grmi_Attr)
675 && !RelayoutGroup(obj))
677 Forbid();
678 Remove((struct Node *)new_pm);
679 Permit();
680 BGUI_FreePoolMem(new_pm);
681 RelayoutGroup(obj);
683 return FALSE;
685 return TRUE;
688 Permit();
689 BGUI_FreePoolMem(new_pm);
690 return(FALSE);
692 METHOD_END
695 /// GRM_REPLACEMEMBER
697 * Replace a member in the group.
699 METHOD(PageClassReplace, struct grmReplaceMember *, grrm)
701 PD *pd = INST_DATA(cl, obj);
702 PM *pm;
705 * No NULL-objects.
707 if(!grrm->grrm_MemberA
708 || !grrm->grrm_MemberB)
709 return(FALSE);
710 Forbid();
711 for (pm = pd->pd_Members.pl_First; pm->pm_Next; pm = pm->pm_Next)
713 if(pm->pm_Object==grrm->grrm_MemberA)
715 pm->pm_Object=grrm->grrm_MemberB;
716 Permit();
718 if(BASE_DATA(obj)->bc_Window)
720 struct TagItem tags[2];
722 tags[0].ti_Tag=BT_Inhibit;
723 tags[0].ti_Data=((pd->pd_Flags & PDF_INHIBIT)!=0 || (pm != pd->pd_Active));
724 tags[1].ti_Tag=TAG_END;
725 AsmDoMethod(BASE_DATA(obj)->bc_Window, WM_SETUPGADGET,pm->pm_Object,&tags);
729 * Try to re-layout the group.
731 if(GetTagData(LGO_Relayout, TRUE, (struct TagItem *)&grrm->grrm_Attr)
732 && !RelayoutGroup(obj))
734 Forbid();
735 pm->pm_Object=grrm->grrm_MemberA;
736 Permit();
737 RelayoutGroup(obj);
739 return FALSE;
741 return((ULONG)grrm->grrm_MemberA);
744 Permit();
745 return 0;
747 METHOD_END
749 /// Class initialization.
751 * Function table.
753 STATIC DPFUNC ClassFunc[] = {
754 BASE_RENDER, (FUNCPTR)PageClassRender,
755 BASE_DIMENSIONS, (FUNCPTR)PageClassDimensions,
756 OM_NEW, (FUNCPTR)PageClassNew,
757 OM_SET, (FUNCPTR)PageClassSetUpdate,
758 OM_UPDATE, (FUNCPTR)PageClassSetUpdate,
759 OM_DISPOSE, (FUNCPTR)PageClassDispose,
760 OM_GET, (FUNCPTR)PageClassGet,
761 GM_GOINACTIVE, (FUNCPTR)PageClassForward,
762 GM_GOACTIVE, (FUNCPTR)PageClassForward,
763 GM_HANDLEINPUT, (FUNCPTR)PageClassForward,
764 GM_HITTEST, (FUNCPTR)PageClassForward,
765 GRM_WHICHOBJECT, (FUNCPTR)PageClassWhichObject,
766 BASE_INHIBIT, (FUNCPTR)PageClassInhibit,
767 BASE_MOVEBOUNDS, (FUNCPTR)PageClassForward,
768 BASE_LOCALIZE, (FUNCPTR)PageClassAll,
769 BASE_KEYLABEL, (FUNCPTR)PageClassAll,
770 BASE_FINDKEY, (FUNCPTR)PageClassForward,
771 BASE_SHOWHELP, (FUNCPTR)PageClassForward,
772 BASE_IS_MULTI, (FUNCPTR)PageClassIsMulti,
773 GRM_ADDMEMBER, (FUNCPTR)PageClassAddMember,
774 GRM_REMMEMBER, (FUNCPTR)PageClassRemMember,
775 GRM_INSERTMEMBER, (FUNCPTR)PageClassInsert,
776 GRM_REPLACEMEMBER, (FUNCPTR)PageClassReplace,
777 DF_END, NULL
781 * Simple initialization of the page class.
783 makeproto Class *InitPageClass(void)
785 return BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_BASE_GADGET,
786 CLASS_ObjectSize, sizeof(PD),
787 CLASS_DFTable, ClassFunc,
788 TAG_DONE);