Replaced System by SYS because on "native" the volume name of the system partition...
[AROS-Contrib.git] / bgui / groupclass.c
blobb4cf6bf7675bf4270155aef733a11fe9dd2d118b
1 /*
2 * @(#) $Header$
4 * BGUI library
5 * groupclass.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.4 2004/06/16 20:16:48 verhaegs
15 * Use METHODPROTO, METHOD_END and REGFUNCPROTOn where needed.
17 * Revision 42.3 2000/08/10 17:52:47 stegerg
18 * temp fix for relayout refresh bug which only happens in AROS. temp. solved
19 * by doing a RefreshGList in windowclass.c/WindowClassRelease method.
21 * Revision 42.2 2000/05/15 19:27:01 stegerg
22 * another hundreds of REG() macro replacements in func headers/protos.
24 * Revision 42.1 2000/05/14 23:32:47 stegerg
25 * changed over 200 function headers which all use register
26 * parameters (oh boy ...), because the simple REG() macro
27 * doesn't work with AROS. And there are still hundreds
28 * of headers left to be fixed :(
30 * Many of these functions would also work with stack
31 * params, but since i have fixed every single one
32 * I encountered up to now, I guess will have to do
33 * the same for the rest.
35 * Revision 42.0 2000/05/09 22:09:07 mlemos
36 * Bumped to revision 42.0 before handing BGUI to AROS team
38 * Revision 41.11 2000/05/09 19:54:22 mlemos
39 * Merged with the branch Manuel_Lemos_fixes.
41 * Revision 41.10.2.11 1999/08/30 04:57:41 mlemos
42 * Made the methods that change group members on-fly setup the gadget
43 * attributes using the window WINDOW_SETUPGADGET method.
45 * Revision 41.10.2.10 1999/08/29 20:21:59 mlemos
46 * Renamed the GRM_RELAYOUT to BASE_RELAYOUT.
48 * Revision 41.10.2.9 1999/08/29 18:58:51 mlemos
49 * Added support to the LGO_Relayout attribute to be able to not relayout a
50 * when calling GRM_ADDMEMBER, GRM_INSERTMEMBER, GRM_REPLACEMEMBER.
52 * Revision 41.10.2.8 1998/10/14 04:07:55 mlemos
53 * Fixed the computation of group members minimum, maximum and nominam sizes.
55 * Revision 41.10.2.7 1998/07/05 19:19:26 mlemos
56 * Fixed bug of Group node instance data pointer be passed instead of the
57 * object pointer.
59 * Revision 41.10.2.6 1998/03/02 01:31:21 mlemos
60 * Fixed members list memory leak when group has no members.
61 * Added functions to obtain and release the members list.
63 * Revision 41.10.2.5 1998/03/02 00:22:18 mlemos
64 * Fixed extention determination when a group is empty.
66 * Revision 41.10.2.4 1998/03/01 17:36:48 mlemos
67 * Fixed memory leaks from group member list allocations.
68 * Prevented nest calls to retrieve copies of the group members list.
70 * Revision 41.10.2.3 1998/02/28 02:44:06 mlemos
71 * Made GRM_DIMENSIONS method obtain the group members list.
73 * Revision 41.10.2.2 1998/02/26 22:37:53 mlemos
74 * Commented out unused variables.
75 * Added casts to GadgetInfo structure where BaseInfo is passed.
76 * Fixed Group Node Class RM_REMOVE call.
78 * Revision 41.10.2.1 1998/02/26 17:45:40 mlemos
79 * Added support for getting a group node object
81 * Revision 41.10 1998/02/25 21:12:11 mlemos
82 * Bumping to 41.10
84 * Revision 1.1 1998/02/25 17:08:29 mlemos
85 * Ian sources
90 #define WW(x)
92 #include "include/classdefs.h"
94 /// Class definitions.
96 * Group member node.
98 typedef struct {
99 Object *md_Object; /* The object itself. */
100 struct IBox md_Bounds; /* Bounds relative to group. */
101 ULONG md_Weight; /* The object weight. */
102 WORD md_FixedWidth; /* Fixed width. */
103 WORD md_FixedHeight; /* Fixed height. */
104 UWORD md_AspectX, md_AspectY; /* Fixed Aspect ratio. */
105 UWORD md_MinWidth, md_MinHeight; /* Minimum width and height. */
106 UWORD md_MaxWidth, md_MaxHeight; /* Maximum width and height. */
107 UWORD md_NomWidth, md_NomHeight; /* Nominal width and height. */
108 UWORD md_HBLeft; /* Hit-box leftedge. */
109 UWORD md_ScaledSize; /* Scaled size. */
110 UWORD md_Flags; /* See below. */
111 UBYTE md_HAlign, md_VAlign; /* Alignment. */
112 Object *md_Group; /* The group we are in. */
113 } MD;
115 #define MDF_FIXEDWIDTH (1<<0) /* Fix width. */
116 #define MDF_FIXEDHEIGHT (1<<1) /* Fix height. */
117 #define MDF_SPACING (1<<2) /* This is a spacing object. */
118 #define MDF_NO_ALIGN (1<<3) /* Object must not be aligned. */
119 #define MDF_RESERVED (1<<4) /* Reserved bit. */
120 #define MDF_NO_NO_ALIGN (1<<5) /* Force alignment. */
121 #define MDF_HIDDEN (1<<6) /* Member hidden? */
124 /// SetGroupNodeAttrs
126 METHOD(SetGroupNodeAttrs, struct opSet *, ops)
128 MD *md = INST_DATA(cl, obj);
129 struct TagItem *tstate = ops->ops_AttrList, *tag;
130 ULONG data;
131 BOOL relayout = FALSE;
134 * Scan LGO attributes.
136 while (tag = NextTagItem(&tstate))
138 data = tag->ti_Data;
139 switch (tag->ti_Tag)
141 case LGO_Left:
142 md->md_Bounds.Left = data;
143 break;
145 case LGO_Top:
146 md->md_Bounds.Top = data;
147 break;
149 case LGO_Width:
150 md->md_Bounds.Width = data;
151 break;
153 case LGO_Height:
154 md->md_Bounds.Height = data;
155 break;
157 case LGO_Object:
158 md->md_Object = (Object *)data;
159 break;
161 case LGO_Group:
162 md->md_Group = (Object *)data;
163 break;
165 case LGO_SpaceObject:
166 md->md_Object = BGUI_NewObjectA(BGUI_SPACING_OBJECT, NULL);
167 md->md_Weight = data;
168 md->md_Flags |= MDF_SPACING;
169 break;
171 case LGO_Weight:
172 if (data < 1) data = 1;
173 if (md->md_Weight != data)
175 md->md_Weight = data;
176 relayout = TRUE;
178 break;
180 case LGO_FixWidth:
181 md->md_FixedWidth = (WORD)data;
182 break;
184 case LGO_FixHeight:
185 md->md_FixedHeight = (WORD)data;
186 break;
188 case LGO_FixMinWidth:
189 md->md_FixedWidth = data ? 0 : -1;
190 break;
192 case LGO_FixMinHeight:
193 md->md_FixedHeight = data ? 0 : -1;
194 break;
196 case LGO_Align:
197 if (data)
198 md->md_Flags |= MDF_NO_NO_ALIGN;
199 break;
201 case LGO_NoAlign:
202 if (data)
203 md->md_Flags |= MDF_NO_ALIGN;
204 break;
206 case LGO_FixAspect:
207 if (*(ULONG *)&md->md_AspectX != data)
209 *(ULONG *)&md->md_AspectX = data;
210 relayout = TRUE;
212 break;
214 case LGO_Visible:
215 if (data)
217 if (md->md_Flags & MDF_HIDDEN)
219 md->md_Flags &= ~MDF_HIDDEN;
220 relayout = TRUE;
223 else
225 if (!(md->md_Flags & MDF_HIDDEN))
227 md->md_Flags |= MDF_HIDDEN;
228 relayout = TRUE;
231 break;
234 if (relayout && md->md_Group) RelayoutGroup(md->md_Group);
236 return 1;
238 METHOD_END
241 /// OM_NEW
243 * Create a shiny new object.
245 METHOD(GroupNodeClassNew, struct opSet *, ops)
247 MD *md;
248 ULONG rc;
251 * First we let the superclass
252 * create the object.
254 if (rc = AsmDoSuperMethodA(cl, obj, (Msg)ops))
256 md = INST_DATA(cl, rc);
257 md->md_Weight = DEFAULT_WEIGHT;
258 md->md_FixedWidth = -1;
259 md->md_FixedHeight = -1;
262 * Setup user attributes.
264 SetGroupNodeAttrs(cl, (Object *)rc, ops);
266 if (md->md_Object && md->md_Group)
268 DoSetMethodNG(md->md_Object, BT_GroupMember, rc,
269 BT_ParentGroup, md->md_Group,
270 BT_ParentWindow, BASE_DATA(md->md_Group)->bc_Window,
271 TAG_DONE);
273 return rc;
276 AsmCoerceMethod(cl, (Object *)rc, OM_DISPOSE);
278 return NULL;
280 METHOD_END
282 /// OM_SET
284 * Change one or more of the object
285 * it's attributes.
287 METHOD(GroupNodeClassSet, struct opSet *, ops)
289 AsmDoSuperMethodA(cl, obj, (Msg)ops);
291 return SetGroupNodeAttrs(cl, obj, ops);
293 METHOD_END
295 /// OM_GET
297 * Give one of the attributes.
299 METHOD(GroupNodeClassGet, struct opGet *, opg)
301 MD *md = INST_DATA(cl, obj);
302 ULONG rc = 1, *store = opg->opg_Storage;
304 switch (opg->opg_AttrID)
306 case LGO_MinWidth:
307 STORE md->md_MinWidth;
308 break;
309 case LGO_MinHeight:
310 STORE md->md_MinHeight;
311 break;
312 case LGO_MaxWidth:
313 STORE md->md_MaxWidth;
314 break;
315 case LGO_MaxHeight:
316 STORE md->md_MaxHeight;
317 break;
318 case LGO_NomWidth:
319 STORE md->md_NomWidth;
320 break;
321 case LGO_NomHeight:
322 STORE md->md_NomHeight;
323 break;
324 case LGO_Object:
325 STORE md->md_Object;
326 break;
327 default:
328 rc = AsmDoSuperMethodA(cl, obj, (Msg)opg);
329 break;
331 return rc;
333 METHOD_END
335 /// RM_REMOVE
337 * Remove node.
339 METHOD(GroupNodeClassRemove, Msg, msg)
341 MD *md = INST_DATA(cl, obj);
343 if (md->md_Object)
344 DoSetMethodNG(md->md_Object, BT_ParentWindow, NULL, BT_ParentGroup, NULL, BT_GroupMember, NULL, TAG_DONE);
346 return AsmDoSuperMethodA(cl, obj, msg);
348 METHOD_END
351 /// Class initialization.
353 * Function table.
355 STATIC DPFUNC ClassFuncNode[] = {
356 OM_NEW, (FUNCPTR)GroupNodeClassNew,
357 OM_SET, (FUNCPTR)GroupNodeClassSet,
358 OM_GET, (FUNCPTR)GroupNodeClassGet,
359 RM_REMOVE, (FUNCPTR)GroupNodeClassRemove,
360 DF_END, NULL
363 static Class *GMClass = NULL;
364 #define MEMBER_DATA(m) ((MD *)INST_DATA(GMClass, ((Object *)m)))
367 * Simple class initialization.
369 makeproto Class *InitGroupNodeClass(void)
371 return GMClass = BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_ROOT_OBJECT,
372 CLASS_ObjectSize, sizeof(MD),
373 CLASS_DFTable, ClassFuncNode,
374 TAG_DONE);
379 /// Class definitions.
381 typedef struct {
382 UWORD td_Min;
383 UWORD td_Nom;
384 UWORD td_Max;
385 UWORD td_Size;
386 UWORD td_Weight;
387 UWORD td_PreAlign;
388 UWORD td_PostAlign;
389 } TD;
392 * Object instance data.
394 typedef struct {
395 struct SignalSemaphore gd_Lock; /* Semaphore for safety purposes. */
396 Object **gd_MD; /* Array of object pointers. */
397 struct MinList gd_Members; /* Group members. */
398 UWORD gd_NumMembers; /* Number of members. */
399 UWORD gd_Rows; /* Rows in HGroup. */
400 UWORD gd_Columns; /* Columns in VGroup. */
401 UBYTE gd_HAlign; /* Horizontal alignment. */
402 UBYTE gd_VAlign; /* Vertical alignment. */
403 UWORD gd_SpaceX; /* Inner-object spacing. */
404 UWORD gd_SpaceY; /* Inner-object spacing. */
405 TD *gd_RD, *gd_CD; /* Row and column descriptors. */
406 Object *gd_Active; /* Active member. */
407 UBYTE gd_Flags; /* See below. */
408 UBYTE gd_Style; /* Style. */
409 } GD;
411 #define GDF_ADD_FAILURE (1<<0) /* Error flag. */
412 #define GDF_HAS_TITLE (1<<1) /* Group is framed with a title. */
413 #define GDF_IS_MASTER (1<<2) /* This is the master group. */
414 #define GDF_EQUAL_MINWIDTH (1<<3) /* All objects have the same min width. */
415 #define GDF_EQUAL_MINHEIGHT (1<<4) /* All objects have the same min height.*/
416 #define GDF_BUFFER (1<<5) /* Buffer rendering. */
419 /// NextGroupNode
421 //static ASM MD *NextGroupNode(REG(a0) GD *gd, REG(a1) Object **node, REG(d0) ULONG flags)
422 static ASM REGFUNC3(MD *, NextGroupNode,
423 REGPARAM(A0, GD *, gd),
424 REGPARAM(A1, Object **, node),
425 REGPARAM(D0, ULONG, flags))
427 Object *next;
428 MD *md;
432 if (*node) next = (Object *)AsmDoMethod(*node, RM_NEXT);
433 else next = ListHeadObject((struct List *)&gd->gd_Members);
435 if (!(*node = next)) return NULL;
437 md = MEMBER_DATA(next);
439 } while (md->md_Flags & flags);
441 return md;
443 REGFUNC_END
445 /// GroupNode
447 //STATIC ASM Object *GroupNode(REG(a0) GD *gd, REG(d0) int i, REG(d1) int j)
448 STATIC ASM REGFUNC3(Object *, GroupNode,
449 REGPARAM(A0, GD *, gd),
450 REGPARAM(D0, int, i),
451 REGPARAM(D1, int, j))
453 switch (gd->gd_Style)
455 case GRSTYLE_HORIZONTAL:
456 j = (i * gd->gd_Columns) + j;
457 break;
458 case GRSTYLE_VERTICAL:
459 j = (j * gd->gd_Rows) + i;
460 break;
461 default:
462 return NULL;
465 if (j < gd->gd_NumMembers) return gd->gd_MD[j];
467 return NULL;
469 REGFUNC_END
471 /// VSpace, HSpace
473 static UWORD VSpace(UWORD space)
475 switch (space)
477 case (UWORD)GRSPACE_NARROW:
478 return (UWORD)GetTagData(GROUP_DefVSpaceNarrow, 2, BGUI_GetDefaultTags(BGUI_GROUP_GADGET));
479 case (UWORD)GRSPACE_NORMAL:
480 return (UWORD)GetTagData(GROUP_DefVSpaceNormal, 4, BGUI_GetDefaultTags(BGUI_GROUP_GADGET));
481 case (UWORD)GRSPACE_WIDE:
482 return (UWORD)GetTagData(GROUP_DefVSpaceWide, 8, BGUI_GetDefaultTags(BGUI_GROUP_GADGET));
484 return space;
486 static UWORD HSpace(UWORD space)
488 switch (space)
490 case (UWORD)GRSPACE_NARROW:
491 return (UWORD)GetTagData(GROUP_DefHSpaceNarrow, 2, BGUI_GetDefaultTags(BGUI_GROUP_GADGET));
492 case (UWORD)GRSPACE_NORMAL:
493 return (UWORD)GetTagData(GROUP_DefHSpaceNormal, 4, BGUI_GetDefaultTags(BGUI_GROUP_GADGET));
494 case (UWORD)GRSPACE_WIDE:
495 return (UWORD)GetTagData(GROUP_DefHSpaceWide, 8, BGUI_GetDefaultTags(BGUI_GROUP_GADGET));
497 return space;
500 /// FindObNode
502 //STATIC ASM Object *FindObNode(REG(a0) GD *gd, REG(a1) Object *find)
503 STATIC ASM REGFUNC2(Object *, FindObNode,
504 REGPARAM(A0, GD *, gd),
505 REGPARAM(A1, Object *, find))
507 Object *m = NULL;
508 MD *md;
510 if (find)
513 * Try to locate the object.
515 while (md = NextGroupNode(gd, &m, 0))
518 * Is this the one?
520 if (md->md_Object == find) return m;
523 return NULL;
525 REGFUNC_END
528 /// GROUPM_NEWMEMBER
530 METHOD(GroupClassNewMember, struct opSet *, ops)
532 return (ULONG)BGUI_NewObjectA(BGUI_GROUP_NODE, ops->ops_AttrList);
534 METHOD_END
536 /// NewGroupMember
538 * Allocate and initialize a member structure.
540 STATIC Object *NewGroupMember(Object *obj, Object *member, struct TagItem *attrs)
542 ULONG tags[6], *t = tags;
544 *t++ = LGO_Group; *t++ = (ULONG)obj;
545 *t++ = LGO_Object; *t++ = (ULONG)member;
546 *t++ = TAG_MORE; *t++ = (ULONG)attrs;
548 return (Object *)AsmDoMethod(obj, GROUPM_NEWMEMBER, tags, NULL);
551 /// NewSpaceObject
553 * Add a spacing object.
555 STATIC Object *NewSpaceObject(Object *obj, ULONG weight)
557 ULONG tags[6], *t = tags;
559 *t++ = LGO_Group; *t++ = (ULONG)obj;
560 *t++ = LGO_SpaceObject; *t++ = (ULONG)weight;
561 *t++ = TAG_DONE;
563 return (Object *)AsmDoMethod(obj, GROUPM_NEWMEMBER, tags, NULL);
566 /// GroupSetAttrs
568 * Pass an attribute on to the members.
570 //STATIC ASM void PassAttr(REG(a0) GD *gd, REG(a1) struct TagItem *tag, REG(a2) struct GadgetInfo *gi)
571 STATIC ASM REGFUNC3(void, PassAttr,
572 REGPARAM(A0, GD *, gd),
573 REGPARAM(A1, struct TagItem *, tag),
574 REGPARAM(A2, struct GadgetInfo *, gi))
576 Object *m;
577 MD *md;
578 struct opSet ops;
579 struct TagItem T[2];
581 T[0].ti_Tag = tag->ti_Tag;
582 T[0].ti_Data = tag->ti_Data;
583 T[1].ti_Tag = TAG_DONE;
585 ops.MethodID = OM_SET;
586 ops.ops_AttrList = T;
587 ops.ops_GInfo = gi;
589 m = NULL;
590 while (md = NextGroupNode(gd, &m, MDF_HIDDEN | MDF_SPACING))
591 AsmDoMethodA(md->md_Object, (Msg)&ops);
593 REGFUNC_END
596 * Set one or more attributes.
598 METHOD(GroupSetAttrs, struct opSet *, ops)
600 GD *gd = INST_DATA(cl, obj);
601 BC *bc = BASE_DATA(obj);
602 struct TagItem *tstate = ops->ops_AttrList, *tag;
603 ULONG data, attr;
604 struct GadgetInfo *gi = ops->ops_GInfo;
607 * Make sure we stay with the correct activation flags.
609 GADGET(obj)->Activation |= GACT_RELVERIFY;
612 * Pass on some tags.
614 while (tag = BGUI_NextTagItem(&tstate))
616 data = tag->ti_Data;
617 switch (tag->ti_Tag)
619 case FRM_Title:
620 if (data) gd->gd_Flags |= GDF_HAS_TITLE;
621 else gd->gd_Flags &= ~GDF_HAS_TITLE;
622 break;
624 case FRM_Type:
625 if (data == FRTYPE_DEFAULT)
627 data = GetTagData(FRM_DefaultType, FRTYPE_NEXT, BGUI_GetDefaultTags(BGUI_GROUP_GADGET));
628 DoSetMethodNG(bc->bc_Frame, FRM_Type, data, TAG_DONE);
630 break;
632 case GA_TopBorder:
633 case GA_BottomBorder:
634 case GA_LeftBorder:
635 case GA_RightBorder:
636 case BT_TextAttr:
637 case BT_ParentWindow:
638 case BT_ParentView:
639 case GA_Disabled:
640 case FRM_ThinFrame:
641 PassAttr(gd, tag, gi);
642 break;
644 case GROUP_IsMaster:
646 * Master group?
648 if (data) gd->gd_Flags |= GDF_IS_MASTER;
649 else gd->gd_Flags &= ~GDF_IS_MASTER;
650 break;
652 case GROUP_Spacing:
653 gd->gd_SpaceX = gd->gd_SpaceY = data;
654 break;
656 case GROUP_HorizSpacing:
657 gd->gd_SpaceX = data;
658 break;
660 case GROUP_VertSpacing:
661 gd->gd_SpaceY = data;
662 break;
664 case GROUP_Rows:
665 gd->gd_Rows = data;
666 break;
668 case GROUP_Columns:
669 gd->gd_Columns = data;
670 break;
672 case GROUP_Style:
673 gd->gd_Style = data;
674 break;
676 case GROUP_HorizAlign:
677 gd->gd_HAlign = data;
678 break;
680 case GROUP_VertAlign:
681 gd->gd_VAlign = data;
682 break;
684 case GROUP_EqualWidth:
685 if (data) gd->gd_Flags |= GDF_EQUAL_MINWIDTH;
686 else gd->gd_Flags &= ~GDF_EQUAL_MINWIDTH;
687 break;
689 case GROUP_EqualHeight:
690 if (data) gd->gd_Flags |= GDF_EQUAL_MINHEIGHT;
691 else gd->gd_Flags &= ~GDF_EQUAL_MINHEIGHT;
692 break;
694 case GROUP_BackFill:
695 attr = FRM_BackFill;
696 goto frame_attr;
698 case GROUP_BackPen:
699 attr = FRM_BackPen;
700 goto frame_attr;
702 case GROUP_BackDriPen:
703 attr = FRM_BackDriPen;
704 goto frame_attr;
706 frame_attr:
707 DoSuperSetMethodNG(cl, obj, bc->bc_Frame ? TAG_IGNORE : FRM_Type, FRTYPE_NONE, attr, data, TAG_DONE);
708 break;
711 return 1;
713 METHOD_END
716 /// OM_NEW
718 * Create a new object.
720 METHOD(GroupClassNew, struct opSet *, ops)
722 GD *gd;
723 struct TagItem *tags = ops->ops_AttrList, *tstate, *tag;
724 ULONG rc;
725 ULONG data;
726 BOOL invert = FALSE;
727 Object *m;
728 struct Node *n1, *n2;
729 int l = 0, r = 0, t = 0, b = 0;
732 * Let the superclass make an object.
734 if (rc = NewSuperObject(cl, obj, tags))
737 * Obtain instance data.
739 gd = INST_DATA(cl, rc);
742 * Initialize member list and other data.
744 NewList((struct List *)&gd->gd_Members);
745 InitSemaphore(&gd->gd_Lock);
746 gd->gd_MD=NULL;
747 gd->gd_NumMembers=0;
749 tstate = tags;
751 * Initialize the rest of the instance data.
753 while (tag = BGUI_NextTagItem(&tstate))
755 data = tag->ti_Data;
757 switch (tag->ti_Tag)
759 case GROUP_Offset:
760 l = r = t = b = data;
761 break;
763 case GROUP_HorizOffset:
764 l = r = data;
765 break;
767 case GROUP_VertOffset:
768 t = b = data;
769 break;
771 case GROUP_LeftOffset:
772 l = data;
773 break;
775 case GROUP_TopOffset:
776 t = data;
777 break;
779 case GROUP_RightOffset:
780 r = data;
781 break;
783 case GROUP_BottomOffset:
784 b = data;
785 break;
787 case GROUP_Inverted:
788 invert = data;
789 break;
791 case GROUP_SpaceObject:
792 if (m = NewSpaceObject((Object *)rc, data))
794 AsmDoMethod(m, RM_ADDTAIL, &gd->gd_Members);
795 break;
797 gd->gd_Flags |= GDF_ADD_FAILURE;
798 break;
800 case GROUP_Member:
801 if (data)
803 if (m = NewGroupMember((Object *)rc, (Object *)data, tag + 1))
805 AsmDoMethod(m, RM_ADDTAIL, &gd->gd_Members);
806 break;
809 * Dispose of the member.
811 AsmDoMethod((Object *)data, OM_DISPOSE);
814 * Set error flag.
816 gd->gd_Flags |= GDF_ADD_FAILURE;
817 break;
821 if (invert)
823 n1 = ((struct List *)&gd->gd_Members)->lh_Head;
825 while ((n2 = n1->ln_Succ)->ln_Succ)
827 Remove(n2);
828 AddHead((struct List *)&gd->gd_Members, n2);
833 * All OK?
835 if (!(gd->gd_Flags & GDF_ADD_FAILURE))
837 if (GADGET(rc)->Activation & GACT_TOPBORDER) l++;
839 DoSuperSetMethodNG(cl, (Object *)rc, BT_LeftOffset, HSpace(l), BT_RightOffset, HSpace(r),
840 BT_TopOffset, VSpace(t), BT_BottomOffset, VSpace(b), TAG_DONE);
842 GroupSetAttrs(cl, (Object *)rc, ops);
844 else
847 * Noop... dump the object.
849 AsmCoerceMethod(cl, (Object *)rc, OM_DISPOSE);
850 rc = 0;
853 return rc;
855 METHOD_END
857 /// OM_SET
859 * Set one or more attributes.
861 METHOD(GroupClassSet, struct opSet *, ops)
864 * First we let the superclass have a go at it.
866 AsmDoSuperMethodA(cl, obj, (Msg)ops);
868 return GroupSetAttrs(cl, obj, ops);
870 METHOD_END
872 /// OM_GET
873 METHOD(GroupClassGet, struct opGet *, opg)
875 GD *gd = INST_DATA(cl, obj);
876 ULONG rc = 1, *store = opg->opg_Storage;
878 switch (opg->opg_AttrID)
880 case GROUP_Rows:
881 STORE gd->gd_Rows;
882 break;
884 case GROUP_Columns:
885 STORE gd->gd_Columns;
886 break;
888 case GROUP_HorizSpacing:
889 STORE gd->gd_SpaceX;
890 break;
892 case GROUP_VertSpacing:
893 STORE gd->gd_SpaceY;
894 break;
896 case GROUP_HorizAlign:
897 STORE gd->gd_HAlign;
898 break;
900 case GROUP_VertAlign:
901 STORE gd->gd_VAlign;
902 break;
904 case GROUP_Members:
905 STORE gd->gd_MD;
906 break;
908 case GROUP_NumMembers:
909 STORE gd->gd_NumMembers;
910 break;
912 case GROUP_Style:
913 STORE gd->gd_Style;
914 break;
916 default:
917 rc = AsmDoSuperMethodA(cl, obj, (Msg)opg);
918 break;
920 return rc;
922 METHOD_END
924 static Object **ObtainMembers(Object *obj,GD *gd,BOOL *got_members_list)
926 if(gd->gd_MD==NULL)
928 if (!(gd->gd_MD = (Object **)AsmDoMethod(obj, GROUPM_OBTAINMEMBERS, GROMF_WAIT|GROMF_VISIBLE, &gd->gd_NumMembers)))
929 return 0;
930 *got_members_list=TRUE;
932 else
933 *got_members_list=FALSE;
934 return(gd->gd_MD);
937 static VOID ReleaseMembers(Object *obj,GD *gd,BOOL got_members_list)
939 if(got_members_list)
941 AsmDoMethod(obj, GROUPM_RELEASEMEMBERS, gd->gd_MD);
942 gd->gd_MD=NULL;
943 gd->gd_NumMembers=0;
948 /// BASE_LAYOUT
950 * Layout the group.
952 METHOD(GroupClassLayout, struct bmLayout *, bml)
954 GD *gd = INST_DATA(cl, obj);
955 BC *bc = BASE_DATA(obj);
956 Object *m;
957 MD *md;
958 TD *td, *cd, *rd;
959 BOOL changed,got_members_list;
960 ULONG totalweight, totalsize, tw, th;
961 /* UBYTE align; */
962 int r, c, size, last;
963 int x, y, dx, dy, w, h;
966 * Layout the baseclass.
968 AsmDoSuperMethodA(cl, obj, (Msg)bml);
970 if (!(bml->bml_Flags & BLF_CUSTOM_GROUP))
972 w = bc->bc_InnerBox.Width - (HSpace(gd->gd_SpaceX) * (gd->gd_Columns - 1));
973 h = bc->bc_InnerBox.Height - (VSpace(gd->gd_SpaceY) * (gd->gd_Rows - 1));
975 if(ObtainMembers(obj,gd,&got_members_list)==NULL)
976 return(0);
977 if (!gd->gd_NumMembers)
979 ReleaseMembers(obj,gd,got_members_list);
980 return 1;
984 * Set starting values.
986 tw = 0;
987 for (c = 0, td = gd->gd_CD; c < gd->gd_Columns; c++, td++)
989 tw += (td->td_Size = td->td_Nom);
992 last = 0;
996 * First loop to get total weight.
998 totalweight = 0;
999 totalsize = w;
1000 for (c = 0, td = gd->gd_CD; c < gd->gd_Columns; c++, td++)
1002 if (td->td_Size < td->td_Max)
1003 totalweight += td->td_Weight;
1004 else
1005 totalsize -= td->td_Size;
1008 if ((totalweight == 0) || (totalsize <= 0)) break;
1011 * Loop to get all scaled sizes.
1013 tw = 0;
1014 for (c = 0, td = gd->gd_CD; c < gd->gd_Columns; c++, td++)
1016 if (td->td_Size < td->td_Max)
1018 size = ScaleWeight(totalsize, totalweight, td->td_Weight);
1019 td->td_Size = range(size, td->td_Min, td->td_Max);
1023 * Keep track of the total size.
1025 tw += td->td_Size;
1027 if (tw == last) break;
1028 last = tw;
1029 } while (tw < w);
1032 * Constantly adjust the size of objects which where scaled larger
1033 * than their minimum size when the total scaled size was larger than
1034 * the area the objects must fit in.
1036 while (tw > w)
1038 changed = FALSE;
1039 for (c = 0, td = gd->gd_CD; c < gd->gd_Columns; c++, td++)
1042 * Was the size bigger than the minimum size?
1044 if (td->td_Size > td->td_Min)
1046 changed = TRUE;
1047 td->td_Size--;
1048 tw--;
1052 * Are we done yet?
1054 if (tw <= w) break;
1056 if (!changed) break;
1060 * Set starting values.
1062 th = 0;
1063 for (r = 0, td = gd->gd_RD; r < gd->gd_Rows; r++, td++)
1065 th += (td->td_Size = td->td_Nom);
1068 last = 0;
1072 * First loop to get total weight.
1074 totalweight = 0;
1075 totalsize = h;
1077 for (r = 0, td = gd->gd_RD; r < gd->gd_Rows; r++, td++)
1079 if (td->td_Size < td->td_Max)
1080 totalweight += td->td_Weight;
1081 else
1082 totalsize -= td->td_Size;
1085 if ((totalweight == 0) || (totalsize <= 0)) break;
1088 * Loop to get all scaled sizes.
1090 th = 0;
1091 for (r = 0, td = gd->gd_RD; r < gd->gd_Rows; r++, td++)
1093 if (td->td_Size < td->td_Max)
1095 size = ScaleWeight(totalsize, totalweight, td->td_Weight);
1096 td->td_Size = range(size, td->td_Min, td->td_Max);
1100 * Keep track of the total size.
1102 th += td->td_Size;
1104 if (th == last) break;
1105 last = th;
1106 } while (th < h);
1109 * Constantly adjust the size of objects which where scaled larger
1110 * than their minimum size when the total scaled size was larger than
1111 * the area the objects must fit in.
1113 while (th > h)
1115 changed = FALSE;
1116 for (r = 0, td = gd->gd_RD; r < gd->gd_Rows; r++, td++)
1119 * Was the size bigger than the minimum size?
1121 if (td->td_Size > td->td_Min)
1123 changed = TRUE;
1124 td->td_Size--;
1125 th--;
1129 * Are we done yet?
1131 if (th <= h) break;
1133 if (!changed) break;
1137 * Scan through the members.
1139 x = bc->bc_InnerBox.Left;
1141 for (c = 0, cd = gd->gd_CD; c < gd->gd_Columns; c++, cd++)
1143 y = bc->bc_InnerBox.Top;
1145 for (r = 0, rd = gd->gd_RD; r < gd->gd_Rows; r++, rd++)
1147 if (m = GroupNode(gd, r, c))
1149 md = MEMBER_DATA(m);
1151 md->md_Bounds.Width = range(cd->td_Size - md->md_HBLeft, md->md_MinWidth, md->md_MaxWidth);
1152 md->md_Bounds.Height = range(rd->td_Size, md->md_MinHeight, md->md_MaxHeight);
1154 switch (md->md_HAlign ? md->md_HAlign : gd->gd_HAlign)
1156 default:
1157 case GRALIGN_LEFT:
1158 dx = md->md_HBLeft;
1159 break;
1160 case GRALIGN_CENTER:
1161 dx = max(0, cd->td_Size - md->md_Bounds.Width) >> 1;
1162 break;
1163 case GRALIGN_RIGHT:
1164 dx = max(0, cd->td_Size - md->md_Bounds.Width);
1165 break;
1168 switch (md->md_VAlign ? md->md_VAlign : gd->gd_VAlign)
1170 default:
1171 case GRALIGN_TOP:
1172 dy = 0;
1173 break;
1174 case GRALIGN_CENTER:
1175 dy = max(0, rd->td_Size - md->md_Bounds.Height) >> 1;
1176 break;
1177 case GRALIGN_BOTTOM:
1178 dy = max(0, rd->td_Size - md->md_Bounds.Height);
1179 break;
1182 md->md_Bounds.Left = x + dx;
1183 md->md_Bounds.Top = y + dy;
1185 y += rd->td_Size + VSpace(gd->gd_SpaceY);
1187 x += cd->td_Size + HSpace(gd->gd_SpaceX);
1189 ReleaseMembers(obj,gd,got_members_list);
1192 return 1;
1194 METHOD_END
1196 /// BASE_RENDER
1198 struct SubRender
1200 struct Message sr_Message;
1201 Object *sr_Object;
1202 struct GadgetInfo *sr_GInfo;
1203 struct RastPort *sr_RPort;
1206 VOID SAVEDS subrender_task(void)
1208 struct Process *proc = (struct Process *)FindTask(NULL);
1209 struct SubRender *sr;
1211 WaitPort(&proc->pr_MsgPort);
1212 sr = (struct SubRender *)GetMsg(&proc->pr_MsgPort);
1214 AsmDoMethod(sr->sr_Object, GM_RENDER, sr->sr_GInfo, sr->sr_RPort, GREDRAW_REDRAW);
1216 ReplyMsg((struct Message *)sr);
1220 * Render the group.
1222 METHOD(GroupClassRender, struct bmRender *, bmr)
1224 GD *gd = INST_DATA(cl, obj);
1225 BC *bc = BASE_DATA(obj);
1226 Object *m;
1227 MD *md;
1228 struct BaseInfo *bi = bmr->bmr_BInfo;
1229 struct RastPort *rp = bi->bi_RPort;
1230 struct Process *proc;
1231 struct MsgPort *msgport = NULL;
1232 struct SubRender *sr;
1233 /* ULONG rc = 0; */
1234 BOOL subrender = FALSE; // no multitasking yet
1235 int render_count = 0;
1237 if (gd->gd_Flags & GDF_IS_MASTER)
1239 if (!bc->bc_Frame)
1241 BSetDPenA(bi, BACKGROUNDPEN);
1242 BBoxFillA(bi, &bc->bc_OuterBox);
1246 WW(kprintf("***GroupClassRender*** obj = %x\n", obj));
1249 * Render the baseclass.
1251 AsmDoSuperMethodA(cl, obj, (Msg)bmr);
1254 * Top-border group hack...
1256 if (GADGET(obj)->Activation & GACT_TOPBORDER)
1258 BSetDPenA(bi, SHADOWPEN);
1259 Move(rp, bc->bc_OuterBox.Left, bc->bc_OuterBox.Top + 1);
1260 Draw(rp, bc->bc_OuterBox.Left, bc->bc_OuterBox.Top + bc->bc_OuterBox.Height - 1);
1263 if (subrender)
1265 msgport = CreateMsgPort();
1266 if (!msgport) subrender = FALSE;
1269 m = NULL;
1270 while (md = NextGroupNode(gd, &m, MDF_HIDDEN | MDF_SPACING))
1273 * Setup object position/dimensions and render it.
1275 SetGadgetBounds(md->md_Object, &md->md_Bounds);
1277 proc = NULL;
1279 if (subrender)
1281 if (sr = BGUI_AllocPoolMem(sizeof(struct SubRender)))
1283 proc = CreateNewProcTags(NP_Entry, subrender_task, NP_Name, "BGUI Render", TAG_DONE);
1285 if (!proc) BGUI_FreePoolMem(sr);
1289 if (proc)
1291 render_count++;
1293 sr->sr_Message.mn_ReplyPort = msgport;
1294 sr->sr_Message.mn_Length = sizeof(struct SubRender);
1295 sr->sr_Object = md->md_Object;
1296 sr->sr_GInfo = (struct GadgetInfo *)bi;
1297 sr->sr_RPort = rp;
1299 PutMsg(&proc->pr_MsgPort, &sr->sr_Message);
1301 else
1303 AsmDoMethod(md->md_Object, GM_RENDER, bi, rp, GREDRAW_REDRAW);
1306 if (subrender)
1309 * Wait for all subtasks to finish.
1311 while (render_count)
1313 WaitPort(msgport);
1314 while (sr = (struct SubRender *)GetMsg(msgport))
1316 BGUI_FreePoolMem(sr);
1317 render_count--;
1320 DeleteMsgPort(msgport);
1322 return 1;
1324 METHOD_END
1326 /// GM_HITTEST
1328 * Pass on the hittest message.
1330 METHOD(GroupClassHitTest, struct gpHitTest *, gph)
1332 GD *gd = INST_DATA(cl, obj);
1333 Object *m;
1334 MD *md;
1335 ULONG rc;
1338 * See if a member was "hit".
1340 m = NULL;
1341 while (md = NextGroupNode(gd, &m, MDF_HIDDEN | MDF_SPACING))
1344 * This member hit?
1346 if ((rc = ForwardMsg(obj, md->md_Object, (Msg)gph)) == GMR_GADGETHIT)
1349 * Make it the active one.
1351 gd->gd_Active = md->md_Object;
1352 return rc;
1357 * Safety precautions.
1359 gd->gd_Active = NULL;
1361 return 0;
1363 METHOD_END
1365 /// GM_GOACTIVE, GM_HANDLEINPUT
1367 * Forward a GM_GOACTIVE or GM_HANDLEINPUT message.
1369 METHOD(GroupClassActiveInput, struct gpInput *, gpi)
1371 GD *gd = INST_DATA(cl, obj);
1372 ULONG rc = GMR_NOREUSE;
1375 * Do we have an active member?
1377 if (gd->gd_Active)
1380 * Tell'm its active.
1382 if (gpi->MethodID == GM_GOACTIVE)
1383 DoSetMethodNG(gd->gd_Active, BT_IsActive, TRUE, TAG_END);
1385 rc = ForwardMsg(obj, gd->gd_Active, (Msg)gpi);
1388 * Clone the ID.
1390 DoSuperSetMethodNG(cl, obj, GA_ID, GADGET(gd->gd_Active)->GadgetID, TAG_DONE);
1392 return rc;
1394 METHOD_END
1396 /// GM_GOINACTIVE
1398 * Forward the GM_GOINACTIVE message.
1400 METHOD(GroupClassInActive, Msg, msg)
1402 GD *gd = INST_DATA(cl, obj);
1403 ULONG rc = 0;
1406 * Inactivate the active member.
1408 if (gd->gd_Active)
1410 rc = AsmDoMethodA(gd->gd_Active, msg);
1412 * Tell 'm its in-active.
1414 DoSetMethodNG(gd->gd_Active, BT_IsActive, FALSE, TAG_END);
1415 gd->gd_Active = NULL;
1417 return rc;
1419 METHOD_END
1421 /// OM_DISPOSE
1423 * Dispose of the group and all
1424 * it's members.
1426 METHOD(GroupClassDispose, Msg, msg)
1428 GD *gd = INST_DATA(cl, obj);
1429 Object *m, *o;
1430 MD *md;
1433 * Remove and dispose of all members.
1435 while (m = ListHeadObject((struct List *)&gd->gd_Members))
1437 md = MEMBER_DATA(m);
1438 o = md->md_Object;
1441 * Free the node.
1443 AsmDoMethod(m, OM_DISPOSE);
1446 * Dispose of the member.
1448 AsmDoMethod(o, OM_DISPOSE);
1451 if (gd->gd_RD) BGUI_FreePoolMem(gd->gd_RD);
1452 if (gd->gd_CD) BGUI_FreePoolMem(gd->gd_CD);
1455 * Leave the rest up to the superclass.
1457 return AsmDoSuperMethodA(cl, obj, msg);
1459 METHOD_END
1461 /// GRM_ADDMEMBER
1463 * Add a member to the group.
1465 METHOD(GroupClassAddMember, struct grmAddMember *, grma)
1467 GD *gd = INST_DATA(cl, obj);
1468 Object *m;
1471 * Allocate and initialize node.
1473 if (m = NewGroupMember(obj, grma->grma_Member, (struct TagItem *)&grma->grma_Attr))
1476 * Add it to the list.
1478 AsmDoMethod(m, RM_ADDTAIL, &gd->gd_Members);
1480 WW(kprintf("** GroupClassAddMember\n"));
1481 WW(if(BASE_DATA(obj)->bc_Window) kprintf("** GroupClassAddMember: sending WM_SETUPGADGET to window\n"));
1483 if(BASE_DATA(obj)->bc_Window)
1484 AsmDoMethod(BASE_DATA(obj)->bc_Window, WM_SETUPGADGET, grma->grma_Member, NULL);
1487 * Try to re-layout the group.
1489 WW(kprintf("** GroupClassAddMember: calling relayoutgroup: LGO_Relayout = %d\n",GetTagData(LGO_Relayout, TRUE, (struct TagItem *)&grma->grma_Attr)));
1491 if(GetTagData(LGO_Relayout, TRUE, (struct TagItem *)&grma->grma_Attr)
1492 && !RelayoutGroup(obj))
1494 WW(kprintf("** GroupClassAddMember: relayoutgroup failed. returning FALSE\n"));
1495 DisposeObject(m);
1496 RelayoutGroup(obj);
1498 return FALSE;
1500 WW(kprintf("** GroupClassAddMember: everything done. returning TRUE\n"));
1502 return TRUE;
1504 return FALSE;
1506 METHOD_END
1508 /// GRM_INSERTMEMBER
1510 * Insert a member in the group.
1512 METHOD(GroupClassInsert, struct grmInsertMember *, grmi)
1514 GD *gd = INST_DATA(cl, obj);
1515 Object *m;
1518 * No NULL-objects.
1520 if (!grmi->grmi_Member)
1521 return FALSE;
1524 * Allocate and initialize node.
1526 if (m = NewGroupMember(obj, grmi->grmi_Member, (struct TagItem *)&grmi->grmi_Attr))
1528 AsmDoMethod(m, RM_INSERT, &gd->gd_Members, FindObNode(gd, grmi->grmi_Pred));
1530 if(BASE_DATA(obj)->bc_Window)
1531 AsmDoMethod(BASE_DATA(obj)->bc_Window, WM_SETUPGADGET, grmi->grmi_Member, NULL);
1534 * Try to re-layout the group.
1536 if(GetTagData(LGO_Relayout, TRUE, (struct TagItem *)&grmi->grmi_Attr)
1537 && !RelayoutGroup(obj))
1539 DisposeObject(m);
1540 RelayoutGroup(obj);
1542 return FALSE;
1544 return TRUE;
1546 return FALSE;
1548 METHOD_END
1550 /// GRM_REPLACEMEMBER
1552 * Replace a member in the group.
1554 METHOD(GroupClassReplace, struct grmReplaceMember *, grrm)
1556 GD *gd = INST_DATA(cl, obj);
1557 Object *m, *old;
1560 * No NULL-objects.
1562 if (!grrm->grrm_MemberA || !grrm->grrm_MemberB)
1563 return 0;
1566 * Allocate and initialize node.
1568 if (m = NewGroupMember(obj, grrm->grrm_MemberB, (struct TagItem *)&grrm->grrm_Attr))
1571 * Find member to replace.
1573 if (old = FindObNode(gd, grrm->grrm_MemberA))
1575 AsmDoMethod(m, RM_INSERT, &gd->gd_Members, old);
1576 AsmDoMethod(old, RM_REMOVE);
1578 if(BASE_DATA(obj)->bc_Window)
1579 AsmDoMethod(BASE_DATA(obj)->bc_Window, WM_SETUPGADGET, grrm->grrm_MemberB, NULL);
1582 * Try to re-layout the group.
1584 if(GetTagData(LGO_Relayout, TRUE, (struct TagItem *)&grrm->grrm_Attr)
1585 && !RelayoutGroup(obj))
1587 AsmDoMethod(old, RM_INSERT, &gd->gd_Members);
1588 DisposeObject(m);
1589 RelayoutGroup(obj);
1591 return 0;
1595 * Deallocate replaced node.
1597 DisposeObject(old);
1600 * Set return code.
1602 return (ULONG)grrm->grrm_MemberA;
1605 return 0;
1607 METHOD_END
1609 /// GRM_REMMEMBER
1611 * Remove an object from the list.
1613 METHOD(GroupClassRemMember, struct grmRemMember *, grmr)
1615 GD *gd = INST_DATA(cl, obj);
1616 Object *m;
1618 if (m = FindObNode(gd, grmr->grmr_Member))
1621 * Remove and dealocate it.
1623 DisposeObject(m);
1626 * Relayout the group.
1628 RelayoutGroup(obj);
1630 return (ULONG)grmr->grmr_Member;
1632 return NULL;
1634 METHOD_END
1636 /// GROUPM_OBTAINMEMBERS
1638 METHOD(GroupClassObtainMembers, struct gmObtainMembers *, gmom)
1640 GD *gd = INST_DATA(cl, obj);
1641 MD *md;
1642 Object **o, *m;
1643 int n;
1644 ULONG flags = gmom->gmom_Flags;
1646 if (flags & GROMF_WAIT)
1648 if (flags & GROMF_EXCLUSIVE)
1650 ObtainSemaphore(&gd->gd_Lock);
1652 else
1654 ObtainSemaphoreShared(&gd->gd_Lock);
1657 else
1659 if (flags & GROMF_EXCLUSIVE)
1661 n = AttemptSemaphore(&gd->gd_Lock);
1663 else
1665 n = AttemptSemaphoreShared(&gd->gd_Lock);
1667 if (!n) return 0;
1670 n = 0;
1671 m = NULL;
1672 while (md = NextGroupNode(gd, &m, (flags & GROMF_VISIBLE) ? MDF_HIDDEN : 0))
1673 n++;
1675 o = BGUI_AllocPoolMem(sizeof(Object *) * (n + 2));
1677 if (!o)
1679 ReleaseSemaphore(&gd->gd_Lock);
1680 return 0;
1683 *o++ = obj; // Marker for safety.
1685 m = NULL;
1686 while (md = NextGroupNode(gd, &m, (flags & GROMF_VISIBLE) ? MDF_HIDDEN : 0))
1688 if (flags & GROMF_OBJECTS)
1689 *o++ = md->md_Object;
1690 else
1691 *o++ = m;
1694 if (gmom->gmom_Number) *(gmom->gmom_Number) = n;
1695 return (ULONG)(o - n);
1697 METHOD_END
1699 /// GROUPM_RELEASEMEMBERS
1701 METHOD(GroupClassReleaseMembers, struct gmReleaseMembers *, gmrm)
1703 GD *gd = INST_DATA(cl, obj);
1704 Object **o = gmrm->gmrm_Array - 1;
1705 int rc = -1;
1707 if (*o == obj) // Check for safety marker.
1709 if (gd->gd_Lock.ss_Owner == FindTask(NULL))
1711 rc = gd->gd_Lock.ss_NestCount - 1;
1713 ReleaseSemaphore(&gd->gd_Lock);
1715 BGUI_FreePoolMem(o);
1717 #ifdef DEBUG_BGUI
1718 else
1719 D(bug("*** Attempt to free an invalid group members list\n"));
1720 #endif
1721 return (ULONG)rc; // rc < 0 = failure, rc = 0 is freed, rc > 0 still locked.
1723 METHOD_END
1725 /// RelayoutGroup
1727 //makeproto ASM ULONG RelayoutGroup(REG(a0) Object *obj)
1728 makeproto ASM REGFUNC1(ULONG, RelayoutGroup,
1729 REGPARAM(A0, Object *, obj))
1731 BC *bc = BASE_DATA(obj);
1732 struct Window *w = NULL;
1733 struct bmRelayout bmr;
1734 ULONG rc = 1;
1736 WW(kprintf("** GroupClass_RelayoutGrop\n"));
1738 if (bc->bc_Window)
1740 WW(kprintf("** GroupClass_RelayoutGrop: has bc->bc_Window\n"));
1741 Get_Attr(bc->bc_Window, WINDOW_Window, (ULONG *)&w);
1743 if (w)
1745 bmr.MethodID = BASE_RELAYOUT;
1746 bmr.bmr_GInfo = NULL;
1747 bmr.bmr_RPort = w->RPort;
1748 WW(kprintf("** GroupClass_RelayoutGrop: has WINDOW_Window --> sending BASE_RELAYOUT to obj\n"));
1750 rc = BGUI_DoGadgetMethodA(obj, w, NULL, (Msg)&bmr);
1753 return rc;
1755 REGFUNC_END
1758 /// MemberDimensions
1760 * Calculate the minimum size of a group.
1762 METHOD(MemberDimensions, struct bmDimensions *, bmd)
1764 GD *gd = INST_DATA(cl, obj);
1765 Object *m;
1766 MD *md;
1767 TD *td;
1768 ULONG minw, minh, nomw, nomh, maxw, maxh;
1769 ULONG tmin, tmax, tnom;
1770 int r, c;
1771 BOOL got_members_list;
1773 if(ObtainMembers(obj,gd,&got_members_list)==NULL)
1774 return(0);
1775 if (gd->gd_NumMembers)
1777 if (gd->gd_Style == GRSTYLE_HORIZONTAL)
1779 gd->gd_Rows = range(gd->gd_Rows, 1, gd->gd_NumMembers);
1780 gd->gd_Columns = (gd->gd_NumMembers + (gd->gd_Rows - 1)) / gd->gd_Rows;
1783 if (gd->gd_Style == GRSTYLE_VERTICAL)
1785 gd->gd_Columns = range(gd->gd_Columns, 1, gd->gd_NumMembers);
1786 gd->gd_Rows = (gd->gd_NumMembers + (gd->gd_Columns - 1)) / gd->gd_Columns;
1789 if (gd->gd_RD) BGUI_FreePoolMem(gd->gd_RD);
1790 if (gd->gd_CD) BGUI_FreePoolMem(gd->gd_CD);
1792 gd->gd_RD = BGUI_AllocPoolMem(sizeof(TD) * gd->gd_Rows);
1793 gd->gd_CD = BGUI_AllocPoolMem(sizeof(TD) * gd->gd_Columns);
1795 if (!(gd->gd_RD && gd->gd_CD)) return 0;
1798 * Scan through the members.
1800 for (c = 0, td = gd->gd_CD; c < gd->gd_Columns; c++, td++)
1802 td->td_PreAlign = 0;
1804 for (r = 0; r < gd->gd_Rows; r++)
1806 if (m = GroupNode(gd, r, c))
1808 md = MEMBER_DATA(m);
1811 * Find out how much we must adjust for alignment.
1813 AsmDoMethod(md->md_Object, BASE_LEFTEXT, bmd->bmd_BInfo->bi_RPort, &md->md_HBLeft);
1815 if (!md->md_HBLeft)
1817 if (!(md->md_Flags & MDF_NO_NO_ALIGN))
1818 md->md_Flags |= MDF_NO_ALIGN;
1820 else
1822 if (md->md_HBLeft > td->td_PreAlign) td->td_PreAlign = md->md_HBLeft;
1827 tmin = 0;
1828 tnom = 0;
1829 tmax = 0;
1831 for (r = 0; r < gd->gd_Rows; r++)
1833 if (m = GroupNode(gd, r, c))
1835 md = MEMBER_DATA(m);
1837 if (!(md->md_Flags & MDF_NO_ALIGN))
1839 md->md_HBLeft = td->td_PreAlign - md->md_HBLeft;
1841 else
1843 md->md_HBLeft = 0;
1846 if (r == 0) td->td_Weight = md->md_Weight;
1849 * Adjust the minimum width with the maximum extention.
1851 tmin = max(tmin, md->md_MinWidth + md->md_HBLeft);
1852 tnom = max(tnom, md->md_NomWidth + md->md_HBLeft);
1853 tmax = max(tmax, md->md_MaxWidth);
1857 td->td_Min = tmin;
1858 td->td_Max = tmax;
1859 td->td_Nom = range(tnom, tmin, tmax);
1863 * Scan through the members.
1865 for (r = 0, td = gd->gd_RD; r < gd->gd_Rows; r++, td++)
1867 tmin = 0;
1868 tnom = 0;
1869 tmax = 0;
1871 for (c = 0; c < gd->gd_Columns; c++)
1873 if (m = GroupNode(gd, r, c))
1875 md = MEMBER_DATA(m);
1877 if (c == 0) td->td_Weight = md->md_Weight;
1879 tmin = max(tmin, md->md_MinHeight);
1880 tnom = max(tnom, md->md_NomHeight);
1881 tmax = max(tmax, md->md_MaxHeight);
1885 td->td_Min = tmin;
1886 td->td_Max = tmax;
1887 td->td_Nom = range(tnom, tmin, tmax);
1890 minw = nomw = HSpace(gd->gd_SpaceX) * (gd->gd_Columns - 1);
1891 minh = nomh = VSpace(gd->gd_SpaceY) * (gd->gd_Rows - 1);
1892 maxw = maxh = 0;
1894 for (r = 0, td = gd->gd_RD; r < gd->gd_Rows; r++, td++)
1896 minh += td->td_Min;
1897 nomh += td->td_Nom;
1898 maxh += td->td_Max;
1901 for (c = 0, td = gd->gd_CD; c < gd->gd_Columns; c++, td++)
1903 minw += td->td_Min;
1904 nomw += td->td_Nom;
1905 maxw += td->td_Max;
1908 else
1911 * No members.
1913 minw = minh = 0;
1914 nomw = nomh = 0;
1915 maxw = maxh = 0xFFFF;
1918 ReleaseMembers(obj,gd,got_members_list);
1920 minw = max(minw, 1);
1921 minh = max(minh, 1);
1923 maxw = range(maxw, minw, 0xFFFF);
1924 maxh = range(maxh, minh, 0xFFFF);
1926 nomw = range(nomw, minw, maxw);
1927 nomh = range(nomh, minh, maxh);
1929 bmd->bmd_Extent->be_Min.Width += minw;
1930 bmd->bmd_Extent->be_Min.Height += minh;
1931 bmd->bmd_Extent->be_Nom.Width += nomw;
1932 bmd->bmd_Extent->be_Nom.Height += nomh;
1933 bmd->bmd_Extent->be_Max.Width = maxw;
1934 bmd->bmd_Extent->be_Max.Height = maxh;
1936 return 1;
1938 METHOD_END
1940 /// BASE_DIMENSIONS
1942 * They want our dimensions info.
1944 METHOD(GroupClassDimensions, struct bmDimensions *, bmd)
1946 GD *gd = INST_DATA(cl, obj);
1947 /* BC *bc = BASE_DATA(obj); */
1948 Object *m;
1949 MD *md;
1950 struct grmDimensions dim;
1951 UWORD mw = 0, mh = 0, minw, minh, maxw, maxh, nomw, nomh;
1952 ULONG rc;
1954 dim.MethodID = GRM_DIMENSIONS;
1955 dim.grmd_GInfo = (struct GadgetInfo *)bmd->bmd_BInfo;
1956 dim.grmd_RPort = bmd->bmd_BInfo->bi_RPort;
1957 dim.grmd_Flags = bmd->bmd_Flags | GDIMF_MAXIMUM|GDIMF_NOMINAL;
1958 dim.grmd_MinSize.Width = &minw;
1959 dim.grmd_MinSize.Height = &minh;
1960 dim.grmd_MaxSize.Width = &maxw;
1961 dim.grmd_MaxSize.Height = &maxh;
1962 dim.grmd_NomSize.Width = &nomw;
1963 dim.grmd_NomSize.Height = &nomh;
1966 * Browse through the members.
1968 m = NULL;
1969 while (md = NextGroupNode(gd, &m, MDF_HIDDEN))
1971 if (md->md_Flags & MDF_SPACING)
1973 md->md_MinWidth = 0;
1974 md->md_MinHeight = 0;
1975 md->md_NomWidth = 0;
1976 md->md_NomHeight = 0;
1977 md->md_MaxWidth = 0xFFFF;
1978 md->md_MaxHeight = 0xFFFF;
1980 else
1983 * Ask dimensions.
1985 AsmDoMethodA(md->md_Object, (Msg)&dim);
1988 * Make sure the fixed sizes are not smaller than allowed.
1990 if (md->md_FixedWidth >= 0)
1992 maxw = minw = nomw = range(md->md_FixedWidth, minw, maxw);
1994 if (md->md_FixedHeight >= 0)
1996 maxh = minh = nomh = range(md->md_FixedHeight, minh, maxh);
1998 if (minw > mw) mw = minw;
1999 if (minh > mh) mh = minh;
2001 md->md_MinWidth = minw;
2002 md->md_MinHeight = minh;
2003 md->md_MaxWidth = max(minw, maxw);
2004 md->md_MaxHeight = max(minh, maxh);
2005 md->md_NomWidth = range(nomw, minw, maxw);
2006 md->md_NomHeight = range(nomh, minh, maxh);
2010 m = NULL;
2011 while (md = NextGroupNode(gd, &m, MDF_HIDDEN))
2014 * Set equal width/height.
2016 if (gd->gd_Flags & GDF_EQUAL_MINWIDTH) md->md_MinWidth = mw;
2017 if (gd->gd_Flags & GDF_EQUAL_MINHEIGHT) md->md_MinHeight = mh;
2020 if (rc = AsmDoSuperMethodA(cl, obj, (Msg)bmd))
2023 * Calculate constraints.
2025 if (!(bmd->bmd_Flags & BDF_CUSTOM_GROUP))
2026 rc = MemberDimensions(cl, obj, bmd);
2028 return rc;
2030 METHOD_END
2032 /// GRM_DIMENSIONS
2033 METHOD(GroupClassDimensionsX, struct grmDimensions *, dim)
2035 GD *gd = INST_DATA(cl, obj);
2036 ULONG rc=0;
2037 BOOL got_members_list;
2039 if(ObtainMembers(obj,gd,&got_members_list)==NULL)
2040 return(0);
2041 rc=AsmDoSuperMethodA(cl, obj, (Msg)dim);
2042 ReleaseMembers(obj,gd,got_members_list);
2043 return(rc);
2045 METHOD_END
2048 /// BASE_SHOWHELP
2050 * Pass on the help message.
2052 METHOD(GroupClassHelp, struct bmShowHelp *, bsh)
2054 GD *gd = INST_DATA(cl, obj);
2055 Object *m;
2056 MD *md;
2057 ULONG rc = BMHELP_NOT_ME;
2059 m = NULL;
2060 while ((md = NextGroupNode(gd, &m, MDF_HIDDEN | MDF_SPACING)) && (rc == BMHELP_NOT_ME))
2063 * Is this the one?
2065 rc = AsmDoMethodA(md->md_Object, (Msg)bsh);
2067 return rc;
2069 METHOD_END
2071 /// GRM_ADDSPACEMEMBER
2073 * Add a spacing object.
2075 METHOD(GroupClassAddSpaceMember, struct grmAddSpaceMember *, grms)
2077 GD *gd = INST_DATA(cl, obj);
2078 Object *m;
2080 if (m = NewSpaceObject(obj, grms->grms_Weight))
2082 AsmDoMethod(m, RM_ADDTAIL, &gd->gd_Members);
2083 return TRUE;
2085 return FALSE;
2087 METHOD_END
2089 /// BASE_LEFTEXT
2091 * Route a BASE_LEFTEXT method.
2093 METHOD(GroupClassLeftExt, struct bmLeftExt *, le)
2095 GD *gd = INST_DATA(cl, obj);
2096 BC *bc = BASE_DATA(obj);
2097 ULONG rc;
2100 * Do we have a label or frame? If so we
2101 * take the left-extention of this object.
2103 if (bc->bc_Label)
2105 return AsmDoSuperMethodA(cl, obj, (Msg)le);
2108 if (bc->bc_Frame)
2110 Get_Attr(bc->bc_Frame, FRM_Type, &rc);
2111 if (rc != FRTYPE_NONE)
2113 return AsmDoSuperMethodA(cl, obj, (Msg)le);
2118 * Get the biggest in the first column.
2120 if(gd->gd_CD)
2121 *(le->bmle_Extention) = gd->gd_CD[0].td_PreAlign;
2122 else
2124 *(le->bmle_Extention)=0;
2127 return 1;
2129 METHOD_END
2131 /// GRM_WHICHOBJECT
2133 * Which object is under the mouse?
2135 METHOD(GroupClassWhichObject, struct grmWhichObject *, grwo)
2137 GD *gd = INST_DATA(cl, obj);
2138 struct IBox *ibox;
2139 Object *m;
2140 MD *md;
2141 WORD x, y;
2142 ULONG rc;
2145 * Pick up the coords.
2147 x = grwo->grwo_Coords.X;
2148 y = grwo->grwo_Coords.Y;
2151 * See if the coords are over a member.
2153 m = NULL;
2154 while (md = NextGroupNode(gd, &m, MDF_HIDDEN | MDF_SPACING))
2157 * If this is a group/page we pass on the method.
2159 if (IsMulti(md->md_Object))
2161 if (rc = AsmDoMethodA(md->md_Object, (Msg)grwo))
2162 return rc;
2166 * Get hitbox bounds.
2168 ibox = GADGETBOX(md->md_Object);
2171 * Over this object?
2173 if (x >= ibox->Left && x < (ibox->Left + ibox->Width ) &&
2174 y >= ibox->Top && y < (ibox->Top + ibox->Height))
2176 * Yes.
2178 return (ULONG)md->md_Object;
2181 return NULL;
2183 METHOD_END
2185 /// BASE_FINDKEY
2187 * Which object has the proper key?
2189 METHOD(GroupClassFindKey, struct bmFindKey *, bmfk)
2191 GD *gd = INST_DATA(cl, obj);
2192 Object *m;
2193 MD *md;
2194 ULONG rc;
2196 if (rc = AsmDoSuperMethodA(cl, obj, (Msg)bmfk))
2197 return rc;
2199 m = NULL;
2200 while (md = NextGroupNode(gd, &m, MDF_HIDDEN | MDF_SPACING))
2202 if (rc = AsmDoMethodA(md->md_Object, (Msg)bmfk))
2203 return rc;
2205 return NULL;
2207 METHOD_END
2209 /// #?
2211 * Attach keys from labels.
2213 METHOD(GroupClassAll, Msg, msg)
2215 GD *gd = INST_DATA(cl, obj);
2216 Object *m;
2217 MD *md;
2218 ULONG rc;
2220 rc = AsmDoSuperMethodA(cl, obj, msg);
2222 m = NULL;
2223 while (md = NextGroupNode(gd, &m, MDF_HIDDEN))
2225 rc += AsmDoMethodA(md->md_Object, msg);
2227 return rc;
2229 METHOD_END
2231 /// BASE_IS_MULTI
2232 METHOD(GroupClassIsMulti, Msg, msg)
2234 return TRUE;
2236 METHOD_END
2238 /// Class initialization.
2240 * Class function table.
2242 STATIC DPFUNC ClassFunc[] = {
2243 BASE_RENDER, (FUNCPTR)GroupClassRender,
2244 BASE_LAYOUT, (FUNCPTR)GroupClassLayout,
2245 BASE_DIMENSIONS, (FUNCPTR)GroupClassDimensions,
2246 GRM_DIMENSIONS, (FUNCPTR)GroupClassDimensionsX,
2248 OM_NEW, (FUNCPTR)GroupClassNew,
2249 OM_SET, (FUNCPTR)GroupClassSet,
2250 OM_GET, (FUNCPTR)GroupClassGet,
2251 OM_DISPOSE, (FUNCPTR)GroupClassDispose,
2252 GM_GOACTIVE, (FUNCPTR)GroupClassActiveInput,
2253 GM_HANDLEINPUT, (FUNCPTR)GroupClassActiveInput,
2254 GM_GOINACTIVE, (FUNCPTR)GroupClassInActive,
2255 GM_HITTEST, (FUNCPTR)GroupClassHitTest,
2257 GROUPM_OBTAINMEMBERS, (FUNCPTR)GroupClassObtainMembers,
2258 GROUPM_RELEASEMEMBERS, (FUNCPTR)GroupClassReleaseMembers,
2259 GROUPM_NEWMEMBER, (FUNCPTR)GroupClassNewMember,
2260 GRM_ADDMEMBER, (FUNCPTR)GroupClassAddMember,
2261 GRM_REMMEMBER, (FUNCPTR)GroupClassRemMember,
2262 GRM_ADDSPACEMEMBER, (FUNCPTR)GroupClassAddSpaceMember,
2263 GRM_INSERTMEMBER, (FUNCPTR)GroupClassInsert,
2264 GRM_REPLACEMEMBER, (FUNCPTR)GroupClassReplace,
2265 GRM_WHICHOBJECT, (FUNCPTR)GroupClassWhichObject,
2266 BASE_MOVEBOUNDS, (FUNCPTR)GroupClassAll,
2267 BASE_FINDKEY, (FUNCPTR)GroupClassFindKey,
2268 BASE_KEYLABEL, (FUNCPTR)GroupClassAll,
2269 BASE_LOCALIZE, (FUNCPTR)GroupClassAll,
2270 BASE_SHOWHELP, (FUNCPTR)GroupClassHelp,
2271 BASE_LEFTEXT, (FUNCPTR)GroupClassLeftExt,
2272 BASE_INHIBIT, (FUNCPTR)GroupClassAll,
2273 BASE_IS_MULTI, (FUNCPTR)GroupClassIsMulti,
2275 DF_END, NULL
2279 * Simple class initialization.
2281 makeproto Class *InitGroupClass(void)
2283 return BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_BASE_GADGET,
2284 CLASS_ObjectSize, sizeof(GD),
2285 CLASS_DFTable, ClassFunc,
2286 TAG_DONE);