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.
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
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
84 * Revision 1.1 1998/02/25 17:08:29 mlemos
92 #include "include/classdefs.h"
94 /// Class definitions.
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. */
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 STATIC IPTR ASM
SetGroupNodeAttrs(REG(a0
) Class
*cl
, REG(a2
) Object
*obj
, REG(a1
) struct opSet
*ops
)
128 MD
*md
= INST_DATA(cl
, obj
);
130 struct TagItem
*tstate
= ops
->ops_AttrList
;
132 BOOL relayout
= FALSE
;
135 * Scan LGO attributes.
137 while ((tag
= NextTagItem(&tstate
)))
143 md
->md_Bounds
.Left
= data
;
147 md
->md_Bounds
.Top
= data
;
151 md
->md_Bounds
.Width
= data
;
155 md
->md_Bounds
.Height
= data
;
159 md
->md_Object
= (Object
*)data
;
163 md
->md_Group
= (Object
*)data
;
166 case LGO_SpaceObject
:
167 md
->md_Object
= BGUI_NewObjectA(BGUI_SPACING_OBJECT
, NULL
);
168 md
->md_Weight
= data
;
169 md
->md_Flags
|= MDF_SPACING
;
173 if (data
< 1) data
= 1;
174 if (md
->md_Weight
!= data
)
176 md
->md_Weight
= data
;
182 md
->md_FixedWidth
= (WORD
)data
;
186 md
->md_FixedHeight
= (WORD
)data
;
189 case LGO_FixMinWidth
:
190 md
->md_FixedWidth
= data
? 0 : -1;
193 case LGO_FixMinHeight
:
194 md
->md_FixedHeight
= data
? 0 : -1;
199 md
->md_Flags
|= MDF_NO_NO_ALIGN
;
204 md
->md_Flags
|= MDF_NO_ALIGN
;
208 if ((md
->md_AspectX
!= ((data
>>16) & 0xffff)) &&
209 (md
->md_AspectY
!= ((data
>> 0) & 0xffff)))
211 md
->md_AspectX
= (data
>>16) & 0xffff;
212 md
->md_AspectY
= (data
>> 0) & 0xffff;
220 if (md
->md_Flags
& MDF_HIDDEN
)
222 md
->md_Flags
&= ~MDF_HIDDEN
;
228 if (!(md
->md_Flags
& MDF_HIDDEN
))
230 md
->md_Flags
|= MDF_HIDDEN
;
237 if (relayout
&& md
->md_Group
) RelayoutGroup(md
->md_Group
);
245 * Create a shiny new object.
247 METHOD(GroupNodeClassNew
, struct opSet
*, ops
)
253 * First we let the superclass
256 if ((rc
= AsmDoSuperMethodA(cl
, obj
, (Msg
)ops
)))
258 md
= INST_DATA(cl
, rc
);
259 md
->md_Weight
= DEFAULT_WEIGHT
;
260 md
->md_FixedWidth
= -1;
261 md
->md_FixedHeight
= -1;
264 * Setup user attributes.
266 SetGroupNodeAttrs(cl
, (Object
*)rc
, ops
);
268 if (md
->md_Object
&& md
->md_Group
)
270 DoSetMethodNG(md
->md_Object
, BT_GroupMember
, rc
,
271 BT_ParentGroup
, md
->md_Group
,
272 BT_ParentWindow
, BASE_DATA(md
->md_Group
)->bc_Window
,
278 AsmCoerceMethod(cl
, (Object
*)rc
, OM_DISPOSE
);
286 * Change one or more of the object
289 METHOD(GroupNodeClassSet
, struct opSet
*, ops
)
291 AsmDoSuperMethodA(cl
, obj
, (Msg
)ops
);
293 return SetGroupNodeAttrs(cl
, obj
, ops
);
299 * Give one of the attributes.
301 METHOD(GroupNodeClassGet
, struct opGet
*, opg
)
303 MD
*md
= INST_DATA(cl
, obj
);
305 IPTR
*store
= opg
->opg_Storage
;
307 switch (opg
->opg_AttrID
)
310 STORE md
->md_MinWidth
;
313 STORE md
->md_MinHeight
;
316 STORE md
->md_MaxWidth
;
319 STORE md
->md_MaxHeight
;
322 STORE md
->md_NomWidth
;
325 STORE md
->md_NomHeight
;
331 rc
= AsmDoSuperMethodA(cl
, obj
, (Msg
)opg
);
342 METHOD(GroupNodeClassRemove
, Msg
, msg
)
344 MD
*md
= INST_DATA(cl
, obj
);
347 DoSetMethodNG(md
->md_Object
, BT_ParentWindow
, NULL
, BT_ParentGroup
, NULL
, BT_GroupMember
, NULL
, TAG_DONE
);
349 return AsmDoSuperMethodA(cl
, obj
, msg
);
354 /// Class initialization.
358 STATIC DPFUNC ClassFuncNode
[] = {
359 { OM_NEW
, GroupNodeClassNew
},
360 { OM_SET
, GroupNodeClassSet
},
361 { OM_GET
, GroupNodeClassGet
},
362 { RM_REMOVE
, GroupNodeClassRemove
},
366 static Class
*GMClass
= NULL
;
367 #define MEMBER_DATA(m) ((MD *)INST_DATA(GMClass, ((Object *)m)))
370 * Simple class initialization.
372 makeproto Class
*InitGroupNodeClass(void)
374 return GMClass
= BGUI_MakeClass(CLASS_SuperClassBGUI
, BGUI_ROOT_OBJECT
,
375 CLASS_ObjectSize
, sizeof(MD
),
376 CLASS_DFTable
, ClassFuncNode
,
382 /// Class definitions.
395 * Object instance data.
398 struct SignalSemaphore gd_Lock
; /* Semaphore for safety purposes. */
399 Object
**gd_MD
; /* Array of object pointers. */
400 struct MinList gd_Members
; /* Group members. */
401 UWORD gd_NumMembers
; /* Number of members. */
402 UWORD gd_Rows
; /* Rows in HGroup. */
403 UWORD gd_Columns
; /* Columns in VGroup. */
404 UBYTE gd_HAlign
; /* Horizontal alignment. */
405 UBYTE gd_VAlign
; /* Vertical alignment. */
406 UWORD gd_SpaceX
; /* Inner-object spacing. */
407 UWORD gd_SpaceY
; /* Inner-object spacing. */
408 TD
*gd_RD
, *gd_CD
; /* Row and column descriptors. */
409 Object
*gd_Active
; /* Active member. */
410 UBYTE gd_Flags
; /* See below. */
411 UBYTE gd_Style
; /* Style. */
414 #define GDF_ADD_FAILURE (1<<0) /* Error flag. */
415 #define GDF_HAS_TITLE (1<<1) /* Group is framed with a title. */
416 #define GDF_IS_MASTER (1<<2) /* This is the master group. */
417 #define GDF_EQUAL_MINWIDTH (1<<3) /* All objects have the same min width. */
418 #define GDF_EQUAL_MINHEIGHT (1<<4) /* All objects have the same min height.*/
419 #define GDF_BUFFER (1<<5) /* Buffer rendering. */
424 STATIC ASM MD
*NextGroupNode(REG(a0
) GD
*gd
, REG(a1
) Object
**node
, REG(d0
) ULONG flags
)
431 if (*node
) next
= (Object
*)AsmDoMethod(*node
, RM_NEXT
);
432 else next
= ListHeadObject((struct List
*)&gd
->gd_Members
);
434 if (!(*node
= next
)) return NULL
;
436 md
= MEMBER_DATA(next
);
438 } while (md
->md_Flags
& flags
);
445 STATIC ASM Object
*GroupNode(REG(a0
) GD
*gd
, REG(d0
) int i
, REG(d1
) int j
)
447 switch (gd
->gd_Style
)
449 case GRSTYLE_HORIZONTAL
:
450 j
= (i
* gd
->gd_Columns
) + j
;
452 case GRSTYLE_VERTICAL
:
453 j
= (j
* gd
->gd_Rows
) + i
;
459 if (j
< gd
->gd_NumMembers
) return gd
->gd_MD
[j
];
467 static UWORD
VSpace(UWORD space
)
471 case (UWORD
)GRSPACE_NARROW
:
472 return (UWORD
)GetTagData(GROUP_DefVSpaceNarrow
, 2, BGUI_GetDefaultTags(BGUI_GROUP_GADGET
));
473 case (UWORD
)GRSPACE_NORMAL
:
474 return (UWORD
)GetTagData(GROUP_DefVSpaceNormal
, 4, BGUI_GetDefaultTags(BGUI_GROUP_GADGET
));
475 case (UWORD
)GRSPACE_WIDE
:
476 return (UWORD
)GetTagData(GROUP_DefVSpaceWide
, 8, BGUI_GetDefaultTags(BGUI_GROUP_GADGET
));
480 static UWORD
HSpace(UWORD space
)
484 case (UWORD
)GRSPACE_NARROW
:
485 return (UWORD
)GetTagData(GROUP_DefHSpaceNarrow
, 2, BGUI_GetDefaultTags(BGUI_GROUP_GADGET
));
486 case (UWORD
)GRSPACE_NORMAL
:
487 return (UWORD
)GetTagData(GROUP_DefHSpaceNormal
, 4, BGUI_GetDefaultTags(BGUI_GROUP_GADGET
));
488 case (UWORD
)GRSPACE_WIDE
:
489 return (UWORD
)GetTagData(GROUP_DefHSpaceWide
, 8, BGUI_GetDefaultTags(BGUI_GROUP_GADGET
));
496 STATIC ASM Object
*FindObNode(REG(a0
) GD
*gd
, REG(a1
) Object
*find
)
504 * Try to locate the object.
506 while ((md
= NextGroupNode(gd
, &m
, 0)))
511 if (md
->md_Object
== find
) return m
;
520 METHOD(GroupClassNewMember
, struct opSet
*, ops
)
522 return (IPTR
)BGUI_NewObjectA(BGUI_GROUP_NODE
, ops
->ops_AttrList
);
528 * Allocate and initialize a member structure.
530 STATIC Object
*NewGroupMember(Object
*obj
, Object
*member
, struct TagItem
*attrs
)
532 struct TagItem tags
[3], *t
= tags
;
534 t
->ti_Tag
= LGO_Group
; t
->ti_Data
= (IPTR
)obj
; t
++;
535 t
->ti_Tag
= LGO_Object
; t
->ti_Data
= (IPTR
)member
; t
++;
536 t
->ti_Tag
= TAG_MORE
; t
->ti_Data
= (IPTR
)attrs
;
538 return (Object
*)AsmDoMethod(obj
, GROUPM_NEWMEMBER
, tags
, NULL
);
543 * Add a spacing object.
545 STATIC Object
*NewSpaceObject(Object
*obj
, ULONG weight
)
547 struct TagItem tags
[3], *t
= tags
;
549 t
->ti_Tag
= LGO_Group
; t
->ti_Data
= (IPTR
)obj
; t
++;
550 t
->ti_Tag
= LGO_SpaceObject
; t
->ti_Data
= (IPTR
)weight
; t
++;
551 t
->ti_Tag
= TAG_DONE
;
553 return (Object
*)AsmDoMethod(obj
, GROUPM_NEWMEMBER
, tags
, NULL
);
558 * Pass an attribute on to the members.
560 STATIC ASM
void PassAttr(REG(a0
) GD
*gd
, REG(a1
) struct TagItem
*tag
, REG(a2
) struct GadgetInfo
*gi
)
567 T
[0].ti_Tag
= tag
->ti_Tag
;
568 T
[0].ti_Data
= tag
->ti_Data
;
569 T
[1].ti_Tag
= TAG_DONE
;
571 ops
.MethodID
= OM_SET
;
572 ops
.ops_AttrList
= T
;
576 while ((md
= NextGroupNode(gd
, &m
, MDF_HIDDEN
| MDF_SPACING
)))
577 AsmDoMethodA(md
->md_Object
, (Msg
)&ops
);
581 * Set one or more attributes.
583 IPTR ASM
GroupSetAttrs(REG(a0
) Class
*cl
, REG(a2
) Object
*obj
, REG(a1
) struct opSet
*ops
)
585 GD
*gd
= INST_DATA(cl
, obj
);
586 BC
*bc
= BASE_DATA(obj
);
587 struct TagItem
*tstate
= ops
->ops_AttrList
, *tag
;
589 struct GadgetInfo
*gi
= ops
->ops_GInfo
;
592 * Make sure we stay with the correct activation flags.
594 GADGET(obj
)->Activation
|= GACT_RELVERIFY
;
599 while ((tag
= BGUI_NextTagItem(&tstate
)))
605 if (data
) gd
->gd_Flags
|= GDF_HAS_TITLE
;
606 else gd
->gd_Flags
&= ~GDF_HAS_TITLE
;
610 if (data
== FRTYPE_DEFAULT
)
612 data
= GetTagData(FRM_DefaultType
, FRTYPE_NEXT
, BGUI_GetDefaultTags(BGUI_GROUP_GADGET
));
613 DoSetMethodNG(bc
->bc_Frame
, FRM_Type
, data
, TAG_DONE
);
618 case GA_BottomBorder
:
622 case BT_ParentWindow
:
626 PassAttr(gd
, tag
, gi
);
633 if (data
) gd
->gd_Flags
|= GDF_IS_MASTER
;
634 else gd
->gd_Flags
&= ~GDF_IS_MASTER
;
638 gd
->gd_SpaceX
= gd
->gd_SpaceY
= data
;
641 case GROUP_HorizSpacing
:
642 gd
->gd_SpaceX
= data
;
645 case GROUP_VertSpacing
:
646 gd
->gd_SpaceY
= data
;
654 gd
->gd_Columns
= data
;
661 case GROUP_HorizAlign
:
662 gd
->gd_HAlign
= data
;
665 case GROUP_VertAlign
:
666 gd
->gd_VAlign
= data
;
669 case GROUP_EqualWidth
:
670 if (data
) gd
->gd_Flags
|= GDF_EQUAL_MINWIDTH
;
671 else gd
->gd_Flags
&= ~GDF_EQUAL_MINWIDTH
;
674 case GROUP_EqualHeight
:
675 if (data
) gd
->gd_Flags
|= GDF_EQUAL_MINHEIGHT
;
676 else gd
->gd_Flags
&= ~GDF_EQUAL_MINHEIGHT
;
687 case GROUP_BackDriPen
:
688 attr
= FRM_BackDriPen
;
692 DoSuperSetMethodNG(cl
, obj
, bc
->bc_Frame
? TAG_IGNORE
: FRM_Type
, FRTYPE_NONE
, attr
, data
, TAG_DONE
);
702 * Create a new object.
704 METHOD(GroupClassNew
, struct opSet
*, ops
)
707 struct TagItem
*tags
= ops
->ops_AttrList
, *tstate
, *tag
;
712 struct Node
*n1
, *n2
;
713 int l
= 0, r
= 0, t
= 0, b
= 0;
716 * Let the superclass make an object.
718 if ((rc
= NewSuperObject(cl
, obj
, tags
)))
721 * Obtain instance data.
723 gd
= INST_DATA(cl
, rc
);
726 * Initialize member list and other data.
728 NewList((struct List
*)&gd
->gd_Members
);
729 InitSemaphore(&gd
->gd_Lock
);
735 * Initialize the rest of the instance data.
737 while ((tag
= BGUI_NextTagItem(&tstate
)))
744 l
= r
= t
= b
= data
;
747 case GROUP_HorizOffset
:
751 case GROUP_VertOffset
:
755 case GROUP_LeftOffset
:
759 case GROUP_TopOffset
:
763 case GROUP_RightOffset
:
767 case GROUP_BottomOffset
:
775 case GROUP_SpaceObject
:
776 if ((m
= NewSpaceObject((Object
*)rc
, data
)))
778 AsmDoMethod(m
, RM_ADDTAIL
, &gd
->gd_Members
);
781 gd
->gd_Flags
|= GDF_ADD_FAILURE
;
787 if ((m
= NewGroupMember((Object
*)rc
, (Object
*)data
, tag
+ 1)))
789 AsmDoMethod(m
, RM_ADDTAIL
, &gd
->gd_Members
);
793 * Dispose of the member.
795 AsmDoMethod((Object
*)data
, OM_DISPOSE
);
800 gd
->gd_Flags
|= GDF_ADD_FAILURE
;
807 struct List
*membList
= (struct List
*)&gd
->gd_Members
;
808 n1
= membList
->lh_Head
;
810 while ((n2
= n1
->ln_Succ
)->ln_Succ
)
813 AddHead(membList
, n2
);
820 if (!(gd
->gd_Flags
& GDF_ADD_FAILURE
))
822 if (GADGET(rc
)->Activation
& GACT_TOPBORDER
) l
++;
824 DoSuperSetMethodNG(cl
, (Object
*)rc
, BT_LeftOffset
, HSpace(l
), BT_RightOffset
, HSpace(r
),
825 BT_TopOffset
, VSpace(t
), BT_BottomOffset
, VSpace(b
), TAG_DONE
);
827 GroupSetAttrs(cl
, (Object
*)rc
, ops
);
832 * Noop... dump the object.
834 AsmCoerceMethod(cl
, (Object
*)rc
, OM_DISPOSE
);
844 * Set one or more attributes.
846 METHOD(GroupClassSet
, struct opSet
*, ops
)
849 * First we let the superclass have a go at it.
851 AsmDoSuperMethodA(cl
, obj
, (Msg
)ops
);
853 return GroupSetAttrs(cl
, obj
, ops
);
858 METHOD(GroupClassGet
, struct opGet
*, opg
)
860 GD
*gd
= INST_DATA(cl
, obj
);
862 IPTR
*store
= opg
->opg_Storage
;
864 switch (opg
->opg_AttrID
)
871 STORE gd
->gd_Columns
;
874 case GROUP_HorizSpacing
:
878 case GROUP_VertSpacing
:
882 case GROUP_HorizAlign
:
886 case GROUP_VertAlign
:
894 case GROUP_NumMembers
:
895 STORE gd
->gd_NumMembers
;
903 rc
= AsmDoSuperMethodA(cl
, obj
, (Msg
)opg
);
910 static Object
**ObtainMembers(Object
*obj
,GD
*gd
,BOOL
*got_members_list
)
914 if (!(gd
->gd_MD
= (Object
**)AsmDoMethod(obj
, GROUPM_OBTAINMEMBERS
, GROMF_WAIT
|GROMF_VISIBLE
, &gd
->gd_NumMembers
)))
916 *got_members_list
=TRUE
;
919 *got_members_list
=FALSE
;
923 static VOID
ReleaseMembers(Object
*obj
,GD
*gd
,BOOL got_members_list
)
927 AsmDoMethod(obj
, GROUPM_RELEASEMEMBERS
, gd
->gd_MD
);
938 METHOD(GroupClassLayout
, struct bmLayout
*, bml
)
940 GD
*gd
= INST_DATA(cl
, obj
);
941 BC
*bc
= BASE_DATA(obj
);
945 BOOL changed
,got_members_list
;
946 ULONG totalweight
, totalsize
, tw
, th
;
948 int r
, c
, size
, last
;
949 int x
, y
, dx
, dy
, w
, h
;
952 * Layout the baseclass.
954 AsmDoSuperMethodA(cl
, obj
, (Msg
)bml
);
956 if (!(bml
->bml_Flags
& BLF_CUSTOM_GROUP
))
958 w
= bc
->bc_InnerBox
.Width
- (HSpace(gd
->gd_SpaceX
) * (gd
->gd_Columns
- 1));
959 h
= bc
->bc_InnerBox
.Height
- (VSpace(gd
->gd_SpaceY
) * (gd
->gd_Rows
- 1));
961 if(ObtainMembers(obj
,gd
,&got_members_list
)==NULL
)
963 if (!gd
->gd_NumMembers
)
965 ReleaseMembers(obj
,gd
,got_members_list
);
970 * Set starting values.
973 for (c
= 0, td
= gd
->gd_CD
; c
< gd
->gd_Columns
; c
++, td
++)
975 tw
+= (td
->td_Size
= td
->td_Nom
);
982 * First loop to get total weight.
986 for (c
= 0, td
= gd
->gd_CD
; c
< gd
->gd_Columns
; c
++, td
++)
988 if (td
->td_Size
< td
->td_Max
)
989 totalweight
+= td
->td_Weight
;
991 totalsize
-= td
->td_Size
;
994 if ((totalweight
== 0) || (totalsize
<= 0)) break;
997 * Loop to get all scaled sizes.
1000 for (c
= 0, td
= gd
->gd_CD
; c
< gd
->gd_Columns
; c
++, td
++)
1002 if (td
->td_Size
< td
->td_Max
)
1004 size
= ScaleWeight(totalsize
, totalweight
, td
->td_Weight
);
1005 td
->td_Size
= range(size
, td
->td_Min
, td
->td_Max
);
1009 * Keep track of the total size.
1013 if (tw
== last
) break;
1018 * Constantly adjust the size of objects which where scaled larger
1019 * than their minimum size when the total scaled size was larger than
1020 * the area the objects must fit in.
1025 for (c
= 0, td
= gd
->gd_CD
; c
< gd
->gd_Columns
; c
++, td
++)
1028 * Was the size bigger than the minimum size?
1030 if (td
->td_Size
> td
->td_Min
)
1042 if (!changed
) break;
1046 * Set starting values.
1049 for (r
= 0, td
= gd
->gd_RD
; r
< gd
->gd_Rows
; r
++, td
++)
1051 th
+= (td
->td_Size
= td
->td_Nom
);
1058 * First loop to get total weight.
1063 for (r
= 0, td
= gd
->gd_RD
; r
< gd
->gd_Rows
; r
++, td
++)
1065 if (td
->td_Size
< td
->td_Max
)
1066 totalweight
+= td
->td_Weight
;
1068 totalsize
-= td
->td_Size
;
1071 if ((totalweight
== 0) || (totalsize
<= 0)) break;
1074 * Loop to get all scaled sizes.
1077 for (r
= 0, td
= gd
->gd_RD
; r
< gd
->gd_Rows
; r
++, td
++)
1079 if (td
->td_Size
< td
->td_Max
)
1081 size
= ScaleWeight(totalsize
, totalweight
, td
->td_Weight
);
1082 td
->td_Size
= range(size
, td
->td_Min
, td
->td_Max
);
1086 * Keep track of the total size.
1090 if (th
== last
) break;
1095 * Constantly adjust the size of objects which where scaled larger
1096 * than their minimum size when the total scaled size was larger than
1097 * the area the objects must fit in.
1102 for (r
= 0, td
= gd
->gd_RD
; r
< gd
->gd_Rows
; r
++, td
++)
1105 * Was the size bigger than the minimum size?
1107 if (td
->td_Size
> td
->td_Min
)
1119 if (!changed
) break;
1123 * Scan through the members.
1125 x
= bc
->bc_InnerBox
.Left
;
1127 for (c
= 0, cd
= gd
->gd_CD
; c
< gd
->gd_Columns
; c
++, cd
++)
1129 y
= bc
->bc_InnerBox
.Top
;
1131 for (r
= 0, rd
= gd
->gd_RD
; r
< gd
->gd_Rows
; r
++, rd
++)
1133 if ((m
= GroupNode(gd
, r
, c
)))
1135 md
= MEMBER_DATA(m
);
1137 md
->md_Bounds
.Width
= range(cd
->td_Size
- md
->md_HBLeft
, md
->md_MinWidth
, md
->md_MaxWidth
);
1138 md
->md_Bounds
.Height
= range(rd
->td_Size
, md
->md_MinHeight
, md
->md_MaxHeight
);
1140 switch (md
->md_HAlign
? md
->md_HAlign
: gd
->gd_HAlign
)
1146 case GRALIGN_CENTER
:
1147 dx
= max(0, cd
->td_Size
- md
->md_Bounds
.Width
) >> 1;
1150 dx
= max(0, cd
->td_Size
- md
->md_Bounds
.Width
);
1154 switch (md
->md_VAlign
? md
->md_VAlign
: gd
->gd_VAlign
)
1160 case GRALIGN_CENTER
:
1161 dy
= max(0, rd
->td_Size
- md
->md_Bounds
.Height
) >> 1;
1163 case GRALIGN_BOTTOM
:
1164 dy
= max(0, rd
->td_Size
- md
->md_Bounds
.Height
);
1168 md
->md_Bounds
.Left
= x
+ dx
;
1169 md
->md_Bounds
.Top
= y
+ dy
;
1171 y
+= rd
->td_Size
+ VSpace(gd
->gd_SpaceY
);
1173 x
+= cd
->td_Size
+ HSpace(gd
->gd_SpaceX
);
1175 ReleaseMembers(obj
,gd
,got_members_list
);
1186 struct Message sr_Message
;
1188 struct GadgetInfo
*sr_GInfo
;
1189 struct RastPort
*sr_RPort
;
1192 VOID SAVEDS
subrender_task(void)
1194 struct Process
*proc
= (struct Process
*)FindTask(NULL
);
1195 struct SubRender
*sr
;
1197 WaitPort(&proc
->pr_MsgPort
);
1198 sr
= (struct SubRender
*)GetMsg(&proc
->pr_MsgPort
);
1200 AsmDoMethod(sr
->sr_Object
, GM_RENDER
, sr
->sr_GInfo
, sr
->sr_RPort
, GREDRAW_REDRAW
);
1202 ReplyMsg((struct Message
*)sr
);
1208 METHOD(GroupClassRender
, struct bmRender
*, bmr
)
1210 GD
*gd
= INST_DATA(cl
, obj
);
1211 BC
*bc
= BASE_DATA(obj
);
1214 struct BaseInfo
*bi
= bmr
->bmr_BInfo
;
1215 struct RastPort
*rp
= bi
->bi_RPort
;
1216 struct Process
*proc
;
1217 struct MsgPort
*msgport
= NULL
;
1218 struct SubRender
*sr
;
1220 BOOL subrender
= FALSE
; // no multitasking yet
1221 int render_count
= 0;
1223 if (gd
->gd_Flags
& GDF_IS_MASTER
)
1227 BSetDPenA(bi
, BACKGROUNDPEN
);
1228 BBoxFillA(bi
, &bc
->bc_OuterBox
);
1232 WW(kprintf("***GroupClassRender*** obj = %x\n", obj
));
1235 * Render the baseclass.
1237 AsmDoSuperMethodA(cl
, obj
, (Msg
)bmr
);
1240 * Top-border group hack...
1242 if (GADGET(obj
)->Activation
& GACT_TOPBORDER
)
1244 BSetDPenA(bi
, SHADOWPEN
);
1245 Move(rp
, bc
->bc_OuterBox
.Left
, bc
->bc_OuterBox
.Top
+ 1);
1246 Draw(rp
, bc
->bc_OuterBox
.Left
, bc
->bc_OuterBox
.Top
+ bc
->bc_OuterBox
.Height
- 1);
1251 msgport
= CreateMsgPort();
1252 if (!msgport
) subrender
= FALSE
;
1256 while ((md
= NextGroupNode(gd
, &m
, MDF_HIDDEN
| MDF_SPACING
)))
1259 * Setup object position/dimensions and render it.
1261 SetGadgetBounds(md
->md_Object
, &md
->md_Bounds
);
1267 if ((sr
= BGUI_AllocPoolMem(sizeof(struct SubRender
))))
1269 proc
= CreateNewProcTags(NP_Entry
, subrender_task
, NP_Name
, "BGUI Render", TAG_DONE
);
1271 if (!proc
) BGUI_FreePoolMem(sr
);
1279 sr
->sr_Message
.mn_ReplyPort
= msgport
;
1280 sr
->sr_Message
.mn_Length
= sizeof(struct SubRender
);
1281 sr
->sr_Object
= md
->md_Object
;
1282 sr
->sr_GInfo
= (struct GadgetInfo
*)bi
;
1285 PutMsg(&proc
->pr_MsgPort
, &sr
->sr_Message
);
1289 AsmDoMethod(md
->md_Object
, GM_RENDER
, bi
, rp
, GREDRAW_REDRAW
);
1295 * Wait for all subtasks to finish.
1297 while (render_count
)
1300 while ((sr
= (struct SubRender
*)GetMsg(msgport
)))
1302 BGUI_FreePoolMem(sr
);
1306 DeleteMsgPort(msgport
);
1314 * Pass on the hittest message.
1316 METHOD(GroupClassHitTest
, struct gpHitTest
*, gph
)
1318 GD
*gd
= INST_DATA(cl
, obj
);
1324 * See if a member was "hit".
1327 while ((md
= NextGroupNode(gd
, &m
, MDF_HIDDEN
| MDF_SPACING
)))
1332 if ((rc
= ForwardMsg(obj
, md
->md_Object
, (Msg
)gph
)) == GMR_GADGETHIT
)
1335 * Make it the active one.
1337 gd
->gd_Active
= md
->md_Object
;
1343 * Safety precautions.
1345 gd
->gd_Active
= NULL
;
1351 /// GM_GOACTIVE, GM_HANDLEINPUT
1353 * Forward a GM_GOACTIVE or GM_HANDLEINPUT message.
1355 METHOD(GroupClassActiveInput
, struct gpInput
*, gpi
)
1357 GD
*gd
= INST_DATA(cl
, obj
);
1358 ULONG rc
= GMR_NOREUSE
;
1361 * Do we have an active member?
1366 * Tell'm its active.
1368 if (gpi
->MethodID
== GM_GOACTIVE
)
1369 DoSetMethodNG(gd
->gd_Active
, BT_IsActive
, TRUE
, TAG_END
);
1371 rc
= ForwardMsg(obj
, gd
->gd_Active
, (Msg
)gpi
);
1376 DoSuperSetMethodNG(cl
, obj
, GA_ID
, GADGET(gd
->gd_Active
)->GadgetID
, TAG_DONE
);
1384 * Forward the GM_GOINACTIVE message.
1386 METHOD(GroupClassInActive
, Msg
, msg
)
1388 GD
*gd
= INST_DATA(cl
, obj
);
1392 * Inactivate the active member.
1396 rc
= AsmDoMethodA(gd
->gd_Active
, msg
);
1398 * Tell 'm its in-active.
1400 DoSetMethodNG(gd
->gd_Active
, BT_IsActive
, FALSE
, TAG_END
);
1401 gd
->gd_Active
= NULL
;
1409 * Dispose of the group and all
1412 METHOD(GroupClassDispose
, Msg
, msg
)
1414 GD
*gd
= INST_DATA(cl
, obj
);
1419 * Remove and dispose of all members.
1421 while ((m
= ListHeadObject((struct List
*)&gd
->gd_Members
)))
1423 md
= MEMBER_DATA(m
);
1429 AsmDoMethod(m
, OM_DISPOSE
);
1432 * Dispose of the member.
1434 AsmDoMethod(o
, OM_DISPOSE
);
1437 if (gd
->gd_RD
) BGUI_FreePoolMem(gd
->gd_RD
);
1438 if (gd
->gd_CD
) BGUI_FreePoolMem(gd
->gd_CD
);
1441 * Leave the rest up to the superclass.
1443 return AsmDoSuperMethodA(cl
, obj
, msg
);
1449 * Add a member to the group.
1451 METHOD(GroupClassAddMember
, struct grmAddMember
*, grma
)
1453 GD
*gd
= INST_DATA(cl
, obj
);
1457 * Allocate and initialize node.
1459 if ((m
= NewGroupMember(obj
, grma
->grma_Member
, (struct TagItem
*)&grma
->grma_Attr
)))
1462 * Add it to the list.
1464 AsmDoMethod(m
, RM_ADDTAIL
, &gd
->gd_Members
);
1466 WW(kprintf("** GroupClassAddMember\n"));
1467 WW(if(BASE_DATA(obj
)->bc_Window
) kprintf("** GroupClassAddMember: sending WM_SETUPGADGET to window\n"));
1469 if(BASE_DATA(obj
)->bc_Window
)
1470 AsmDoMethod(BASE_DATA(obj
)->bc_Window
, WM_SETUPGADGET
, grma
->grma_Member
, NULL
);
1473 * Try to re-layout the group.
1475 WW(kprintf("** GroupClassAddMember: calling relayoutgroup: LGO_Relayout = %d\n",GetTagData(LGO_Relayout
, TRUE
, (struct TagItem
*)&grma
->grma_Attr
)));
1477 if(GetTagData(LGO_Relayout
, TRUE
, (struct TagItem
*)&grma
->grma_Attr
)
1478 && !RelayoutGroup(obj
))
1480 WW(kprintf("** GroupClassAddMember: relayoutgroup failed. returning FALSE\n"));
1486 WW(kprintf("** GroupClassAddMember: everything done. returning TRUE\n"));
1494 /// GRM_INSERTMEMBER
1496 * Insert a member in the group.
1498 METHOD(GroupClassInsert
, struct grmInsertMember
*, grmi
)
1500 GD
*gd
= INST_DATA(cl
, obj
);
1506 if (!grmi
->grmi_Member
)
1510 * Allocate and initialize node.
1512 if ((m
= NewGroupMember(obj
, grmi
->grmi_Member
, (struct TagItem
*)&grmi
->grmi_Attr
)))
1514 AsmDoMethod(m
, RM_INSERT
, &gd
->gd_Members
, FindObNode(gd
, grmi
->grmi_Pred
));
1516 if(BASE_DATA(obj
)->bc_Window
)
1517 AsmDoMethod(BASE_DATA(obj
)->bc_Window
, WM_SETUPGADGET
, grmi
->grmi_Member
, NULL
);
1520 * Try to re-layout the group.
1522 if(GetTagData(LGO_Relayout
, TRUE
, (struct TagItem
*)&grmi
->grmi_Attr
)
1523 && !RelayoutGroup(obj
))
1536 /// GRM_REPLACEMEMBER
1538 * Replace a member in the group.
1540 METHOD(GroupClassReplace
, struct grmReplaceMember
*, grrm
)
1542 GD
*gd
= INST_DATA(cl
, obj
);
1548 if (!grrm
->grrm_MemberA
|| !grrm
->grrm_MemberB
)
1552 * Allocate and initialize node.
1554 if ((m
= NewGroupMember(obj
, grrm
->grrm_MemberB
, (struct TagItem
*)&grrm
->grrm_Attr
)))
1557 * Find member to replace.
1559 if ((old
= FindObNode(gd
, grrm
->grrm_MemberA
)))
1561 AsmDoMethod(m
, RM_INSERT
, &gd
->gd_Members
, old
);
1562 AsmDoMethod(old
, RM_REMOVE
);
1564 if(BASE_DATA(obj
)->bc_Window
)
1565 AsmDoMethod(BASE_DATA(obj
)->bc_Window
, WM_SETUPGADGET
, grrm
->grrm_MemberB
, NULL
);
1568 * Try to re-layout the group.
1570 if(GetTagData(LGO_Relayout
, TRUE
, (struct TagItem
*)&grrm
->grrm_Attr
)
1571 && !RelayoutGroup(obj
))
1573 AsmDoMethod(old
, RM_INSERT
, &gd
->gd_Members
);
1581 * Deallocate replaced node.
1588 return (IPTR
)grrm
->grrm_MemberA
;
1597 * Remove an object from the list.
1599 METHOD(GroupClassRemMember
, struct grmRemMember
*, grmr
)
1601 GD
*gd
= INST_DATA(cl
, obj
);
1604 if ((m
= FindObNode(gd
, grmr
->grmr_Member
)))
1607 * Remove and dealocate it.
1612 * Relayout the group.
1616 return (IPTR
)grmr
->grmr_Member
;
1622 /// GROUPM_OBTAINMEMBERS
1624 METHOD(GroupClassObtainMembers
, struct gmObtainMembers
*, gmom
)
1626 GD
*gd
= INST_DATA(cl
, obj
);
1630 ULONG flags
= gmom
->gmom_Flags
;
1632 if (flags
& GROMF_WAIT
)
1634 if (flags
& GROMF_EXCLUSIVE
)
1636 ObtainSemaphore(&gd
->gd_Lock
);
1640 ObtainSemaphoreShared(&gd
->gd_Lock
);
1645 if (flags
& GROMF_EXCLUSIVE
)
1647 n
= AttemptSemaphore(&gd
->gd_Lock
);
1651 n
= AttemptSemaphoreShared(&gd
->gd_Lock
);
1658 while ((md
= NextGroupNode(gd
, &m
, (flags
& GROMF_VISIBLE
) ? MDF_HIDDEN
: 0)))
1661 o
= BGUI_AllocPoolMem(sizeof(Object
*) * (n
+ 2));
1665 ReleaseSemaphore(&gd
->gd_Lock
);
1669 *o
++ = obj
; // Marker for safety.
1672 while ((md
= NextGroupNode(gd
, &m
, (flags
& GROMF_VISIBLE
) ? MDF_HIDDEN
: 0)))
1674 if (flags
& GROMF_OBJECTS
)
1675 *o
++ = md
->md_Object
;
1680 if (gmom
->gmom_Number
) *(gmom
->gmom_Number
) = n
;
1681 return (IPTR
)(o
- n
);
1685 /// GROUPM_RELEASEMEMBERS
1687 METHOD(GroupClassReleaseMembers
, struct gmReleaseMembers
*, gmrm
)
1689 GD
*gd
= INST_DATA(cl
, obj
);
1690 Object
**o
= gmrm
->gmrm_Array
- 1;
1693 if (*o
== obj
) // Check for safety marker.
1695 if (gd
->gd_Lock
.ss_Owner
== FindTask(NULL
))
1697 rc
= gd
->gd_Lock
.ss_NestCount
- 1;
1699 ReleaseSemaphore(&gd
->gd_Lock
);
1701 BGUI_FreePoolMem(o
);
1705 D(bug("*** Attempt to free an invalid group members list\n"));
1707 return (ULONG
)rc
; // rc < 0 = failure, rc = 0 is freed, rc > 0 still locked.
1713 makeproto ASM ULONG
RelayoutGroup(REG(a0
) Object
*obj
)
1715 BC
*bc
= BASE_DATA(obj
);
1716 struct Window
*w
= NULL
;
1717 struct bmRelayout bmr
;
1720 WW(kprintf("** GroupClass_RelayoutGrop\n"));
1724 WW(kprintf("** GroupClass_RelayoutGrop: has bc->bc_Window\n"));
1725 Get_Attr(bc
->bc_Window
, WINDOW_Window
, (IPTR
*)&w
);
1729 bmr
.MethodID
= BASE_RELAYOUT
;
1730 bmr
.bmr_GInfo
= NULL
;
1731 bmr
.bmr_RPort
= w
->RPort
;
1732 WW(kprintf("** GroupClass_RelayoutGrop: has WINDOW_Window --> sending BASE_RELAYOUT to obj\n"));
1734 rc
= BGUI_DoGadgetMethodA(obj
, w
, NULL
, (Msg
)&bmr
);
1741 /// MemberDimensions
1743 * Calculate the minimum size of a group.
1745 STATIC ASM BOOL
MemberDimensions(REG(a0
) Class
*cl
, REG(a2
) Object
*obj
, REG(a1
) struct bmDimensions
*bmd
)
1747 GD
*gd
= INST_DATA(cl
, obj
);
1751 ULONG minw
, minh
, nomw
, nomh
, maxw
, maxh
;
1752 ULONG tmin
, tmax
, tnom
;
1754 BOOL got_members_list
;
1756 if(ObtainMembers(obj
,gd
,&got_members_list
)==NULL
)
1758 if (gd
->gd_NumMembers
)
1760 if (gd
->gd_Style
== GRSTYLE_HORIZONTAL
)
1762 gd
->gd_Rows
= range(gd
->gd_Rows
, 1, gd
->gd_NumMembers
);
1763 gd
->gd_Columns
= (gd
->gd_NumMembers
+ (gd
->gd_Rows
- 1)) / gd
->gd_Rows
;
1766 if (gd
->gd_Style
== GRSTYLE_VERTICAL
)
1768 gd
->gd_Columns
= range(gd
->gd_Columns
, 1, gd
->gd_NumMembers
);
1769 gd
->gd_Rows
= (gd
->gd_NumMembers
+ (gd
->gd_Columns
- 1)) / gd
->gd_Columns
;
1772 if (gd
->gd_RD
) BGUI_FreePoolMem(gd
->gd_RD
);
1773 if (gd
->gd_CD
) BGUI_FreePoolMem(gd
->gd_CD
);
1775 gd
->gd_RD
= BGUI_AllocPoolMem(sizeof(TD
) * gd
->gd_Rows
);
1776 gd
->gd_CD
= BGUI_AllocPoolMem(sizeof(TD
) * gd
->gd_Columns
);
1778 if (!(gd
->gd_RD
&& gd
->gd_CD
)) return FALSE
;
1781 * Scan through the members.
1783 for (c
= 0, td
= gd
->gd_CD
; c
< gd
->gd_Columns
; c
++, td
++)
1785 td
->td_PreAlign
= 0;
1787 for (r
= 0; r
< gd
->gd_Rows
; r
++)
1789 if ((m
= GroupNode(gd
, r
, c
)))
1791 md
= MEMBER_DATA(m
);
1794 * Find out how much we must adjust for alignment.
1796 AsmDoMethod(md
->md_Object
, BASE_LEFTEXT
, bmd
->bmd_BInfo
->bi_RPort
, &md
->md_HBLeft
);
1800 if (!(md
->md_Flags
& MDF_NO_NO_ALIGN
))
1801 md
->md_Flags
|= MDF_NO_ALIGN
;
1805 if (md
->md_HBLeft
> td
->td_PreAlign
) td
->td_PreAlign
= md
->md_HBLeft
;
1814 for (r
= 0; r
< gd
->gd_Rows
; r
++)
1816 if ((m
= GroupNode(gd
, r
, c
)))
1818 md
= MEMBER_DATA(m
);
1820 if (!(md
->md_Flags
& MDF_NO_ALIGN
))
1822 md
->md_HBLeft
= td
->td_PreAlign
- md
->md_HBLeft
;
1829 if (r
== 0) td
->td_Weight
= md
->md_Weight
;
1832 * Adjust the minimum width with the maximum extention.
1834 tmin
= max(tmin
, md
->md_MinWidth
+ md
->md_HBLeft
);
1835 tnom
= max(tnom
, md
->md_NomWidth
+ md
->md_HBLeft
);
1836 tmax
= max(tmax
, md
->md_MaxWidth
);
1842 td
->td_Nom
= range(tnom
, tmin
, tmax
);
1846 * Scan through the members.
1848 for (r
= 0, td
= gd
->gd_RD
; r
< gd
->gd_Rows
; r
++, td
++)
1854 for (c
= 0; c
< gd
->gd_Columns
; c
++)
1856 if ((m
= GroupNode(gd
, r
, c
)))
1858 md
= MEMBER_DATA(m
);
1860 if (c
== 0) td
->td_Weight
= md
->md_Weight
;
1862 tmin
= max(tmin
, md
->md_MinHeight
);
1863 tnom
= max(tnom
, md
->md_NomHeight
);
1864 tmax
= max(tmax
, md
->md_MaxHeight
);
1870 td
->td_Nom
= range(tnom
, tmin
, tmax
);
1873 minw
= nomw
= HSpace(gd
->gd_SpaceX
) * (gd
->gd_Columns
- 1);
1874 minh
= nomh
= VSpace(gd
->gd_SpaceY
) * (gd
->gd_Rows
- 1);
1877 for (r
= 0, td
= gd
->gd_RD
; r
< gd
->gd_Rows
; r
++, td
++)
1884 for (c
= 0, td
= gd
->gd_CD
; c
< gd
->gd_Columns
; c
++, td
++)
1898 maxw
= maxh
= 0xFFFF;
1901 ReleaseMembers(obj
,gd
,got_members_list
);
1903 minw
= max(minw
, 1);
1904 minh
= max(minh
, 1);
1906 maxw
= range(maxw
, minw
, 0xFFFF);
1907 maxh
= range(maxh
, minh
, 0xFFFF);
1909 nomw
= range(nomw
, minw
, maxw
);
1910 nomh
= range(nomh
, minh
, maxh
);
1912 bmd
->bmd_Extent
->be_Min
.Width
+= minw
;
1913 bmd
->bmd_Extent
->be_Min
.Height
+= minh
;
1914 bmd
->bmd_Extent
->be_Nom
.Width
+= nomw
;
1915 bmd
->bmd_Extent
->be_Nom
.Height
+= nomh
;
1916 bmd
->bmd_Extent
->be_Max
.Width
= maxw
;
1917 bmd
->bmd_Extent
->be_Max
.Height
= maxh
;
1924 * They want our dimensions info.
1926 METHOD(GroupClassDimensions
, struct bmDimensions
*, bmd
)
1928 GD
*gd
= INST_DATA(cl
, obj
);
1929 /* BC *bc = BASE_DATA(obj); */
1932 struct grmDimensions dim
;
1933 UWORD mw
= 0, mh
= 0, minw
, minh
, maxw
, maxh
, nomw
, nomh
;
1936 dim
.MethodID
= GRM_DIMENSIONS
;
1937 dim
.grmd_GInfo
= (struct GadgetInfo
*)bmd
->bmd_BInfo
;
1938 dim
.grmd_RPort
= bmd
->bmd_BInfo
->bi_RPort
;
1939 dim
.grmd_Flags
= bmd
->bmd_Flags
| GDIMF_MAXIMUM
|GDIMF_NOMINAL
;
1940 dim
.grmd_MinSize
.Width
= &minw
;
1941 dim
.grmd_MinSize
.Height
= &minh
;
1942 dim
.grmd_MaxSize
.Width
= &maxw
;
1943 dim
.grmd_MaxSize
.Height
= &maxh
;
1944 dim
.grmd_NomSize
.Width
= &nomw
;
1945 dim
.grmd_NomSize
.Height
= &nomh
;
1948 * Browse through the members.
1951 while ((md
= NextGroupNode(gd
, &m
, MDF_HIDDEN
)))
1953 if (md
->md_Flags
& MDF_SPACING
)
1955 md
->md_MinWidth
= 0;
1956 md
->md_MinHeight
= 0;
1957 md
->md_NomWidth
= 0;
1958 md
->md_NomHeight
= 0;
1959 md
->md_MaxWidth
= 0xFFFF;
1960 md
->md_MaxHeight
= 0xFFFF;
1967 AsmDoMethodA(md
->md_Object
, (Msg
)&dim
);
1970 * Make sure the fixed sizes are not smaller than allowed.
1972 if (md
->md_FixedWidth
>= 0)
1974 maxw
= minw
= nomw
= range(md
->md_FixedWidth
, minw
, maxw
);
1976 if (md
->md_FixedHeight
>= 0)
1978 maxh
= minh
= nomh
= range(md
->md_FixedHeight
, minh
, maxh
);
1980 if (minw
> mw
) mw
= minw
;
1981 if (minh
> mh
) mh
= minh
;
1983 md
->md_MinWidth
= minw
;
1984 md
->md_MinHeight
= minh
;
1985 md
->md_MaxWidth
= max(minw
, maxw
);
1986 md
->md_MaxHeight
= max(minh
, maxh
);
1987 md
->md_NomWidth
= range(nomw
, minw
, maxw
);
1988 md
->md_NomHeight
= range(nomh
, minh
, maxh
);
1993 while ((md
= NextGroupNode(gd
, &m
, MDF_HIDDEN
)))
1996 * Set equal width/height.
1998 if (gd
->gd_Flags
& GDF_EQUAL_MINWIDTH
) md
->md_MinWidth
= mw
;
1999 if (gd
->gd_Flags
& GDF_EQUAL_MINHEIGHT
) md
->md_MinHeight
= mh
;
2002 if ((rc
= AsmDoSuperMethodA(cl
, obj
, (Msg
)bmd
)))
2005 * Calculate constraints.
2007 if (!(bmd
->bmd_Flags
& BDF_CUSTOM_GROUP
))
2008 rc
= MemberDimensions(cl
, obj
, bmd
);
2015 METHOD(GroupClassDimensionsX
, struct grmDimensions
*, dim
)
2017 GD
*gd
= INST_DATA(cl
, obj
);
2019 BOOL got_members_list
;
2021 if(ObtainMembers(obj
,gd
,&got_members_list
)==NULL
)
2023 rc
=AsmDoSuperMethodA(cl
, obj
, (Msg
)dim
);
2024 ReleaseMembers(obj
,gd
,got_members_list
);
2032 * Pass on the help message.
2034 METHOD(GroupClassHelp
, struct bmShowHelp
*, bsh
)
2036 GD
*gd
= INST_DATA(cl
, obj
);
2039 ULONG rc
= BMHELP_NOT_ME
;
2042 while ((md
= NextGroupNode(gd
, &m
, MDF_HIDDEN
| MDF_SPACING
)) && (rc
== BMHELP_NOT_ME
))
2047 rc
= AsmDoMethodA(md
->md_Object
, (Msg
)bsh
);
2053 /// GRM_ADDSPACEMEMBER
2055 * Add a spacing object.
2057 METHOD(GroupClassAddSpaceMember
, struct grmAddSpaceMember
*, grms
)
2059 GD
*gd
= INST_DATA(cl
, obj
);
2062 if ((m
= NewSpaceObject(obj
, grms
->grms_Weight
)))
2064 AsmDoMethod(m
, RM_ADDTAIL
, &gd
->gd_Members
);
2073 * Route a BASE_LEFTEXT method.
2075 METHOD(GroupClassLeftExt
, struct bmLeftExt
*, le
)
2077 GD
*gd
= INST_DATA(cl
, obj
);
2078 BC
*bc
= BASE_DATA(obj
);
2082 * Do we have a label or frame? If so we
2083 * take the left-extention of this object.
2087 return AsmDoSuperMethodA(cl
, obj
, (Msg
)le
);
2092 Get_Attr(bc
->bc_Frame
, FRM_Type
, &rc
);
2093 if (rc
!= FRTYPE_NONE
)
2095 return AsmDoSuperMethodA(cl
, obj
, (Msg
)le
);
2100 * Get the biggest in the first column.
2103 *(le
->bmle_Extention
) = gd
->gd_CD
[0].td_PreAlign
;
2106 *(le
->bmle_Extention
)=0;
2115 * Which object is under the mouse?
2117 METHOD(GroupClassWhichObject
, struct grmWhichObject
*, grwo
)
2119 GD
*gd
= INST_DATA(cl
, obj
);
2127 * Pick up the coords.
2129 x
= grwo
->grwo_Coords
.X
;
2130 y
= grwo
->grwo_Coords
.Y
;
2133 * See if the coords are over a member.
2136 while ((md
= NextGroupNode(gd
, &m
, MDF_HIDDEN
| MDF_SPACING
)))
2139 * If this is a group/page we pass on the method.
2141 if (IsMulti(md
->md_Object
))
2143 if ((rc
= AsmDoMethodA(md
->md_Object
, (Msg
)grwo
)))
2148 * Get hitbox bounds.
2150 ibox
= GADGETBOX(md
->md_Object
);
2155 if (x
>= ibox
->Left
&& x
< (ibox
->Left
+ ibox
->Width
) &&
2156 y
>= ibox
->Top
&& y
< (ibox
->Top
+ ibox
->Height
))
2160 return (IPTR
)md
->md_Object
;
2169 * Which object has the proper key?
2171 METHOD(GroupClassFindKey
, struct bmFindKey
*, bmfk
)
2173 GD
*gd
= INST_DATA(cl
, obj
);
2178 if ((rc
= AsmDoSuperMethodA(cl
, obj
, (Msg
)bmfk
)))
2182 while ((md
= NextGroupNode(gd
, &m
, MDF_HIDDEN
| MDF_SPACING
)))
2184 if ((rc
= AsmDoMethodA(md
->md_Object
, (Msg
)bmfk
)))
2193 * Attach keys from labels.
2195 METHOD(GroupClassAll
, Msg
, msg
)
2197 GD
*gd
= INST_DATA(cl
, obj
);
2202 rc
= AsmDoSuperMethodA(cl
, obj
, msg
);
2205 while ((md
= NextGroupNode(gd
, &m
, MDF_HIDDEN
)))
2207 rc
+= AsmDoMethodA(md
->md_Object
, msg
);
2214 METHOD(GroupClassIsMulti
, Msg
, msg
)
2220 /// Class initialization.
2222 * Class function table.
2224 STATIC DPFUNC ClassFunc
[] = {
2225 { BASE_RENDER
, GroupClassRender
},
2226 { BASE_LAYOUT
, GroupClassLayout
},
2227 { BASE_DIMENSIONS
, GroupClassDimensions
},
2228 { GRM_DIMENSIONS
, GroupClassDimensionsX
},
2230 { OM_NEW
, GroupClassNew
},
2231 { OM_SET
, GroupClassSet
},
2232 { OM_GET
, GroupClassGet
},
2233 { OM_DISPOSE
, GroupClassDispose
},
2234 { GM_GOACTIVE
, GroupClassActiveInput
},
2235 { GM_HANDLEINPUT
, GroupClassActiveInput
},
2236 { GM_GOINACTIVE
, GroupClassInActive
},
2237 { GM_HITTEST
, GroupClassHitTest
},
2239 { GROUPM_OBTAINMEMBERS
, GroupClassObtainMembers
},
2240 { GROUPM_RELEASEMEMBERS
, GroupClassReleaseMembers
},
2241 { GROUPM_NEWMEMBER
, GroupClassNewMember
},
2242 { GRM_ADDMEMBER
, GroupClassAddMember
},
2243 { GRM_REMMEMBER
, GroupClassRemMember
},
2244 { GRM_ADDSPACEMEMBER
, GroupClassAddSpaceMember
},
2245 { GRM_INSERTMEMBER
, GroupClassInsert
},
2246 { GRM_REPLACEMEMBER
, GroupClassReplace
},
2247 { GRM_WHICHOBJECT
, GroupClassWhichObject
},
2248 { BASE_MOVEBOUNDS
, GroupClassAll
},
2249 { BASE_FINDKEY
, GroupClassFindKey
},
2250 { BASE_KEYLABEL
, GroupClassAll
},
2251 { BASE_LOCALIZE
, GroupClassAll
},
2252 { BASE_SHOWHELP
, GroupClassHelp
},
2253 { BASE_LEFTEXT
, GroupClassLeftExt
},
2254 { BASE_INHIBIT
, GroupClassAll
},
2255 { BASE_IS_MULTI
, GroupClassIsMulti
},
2261 * Simple class initialization.
2263 makeproto Class
*InitGroupClass(void)
2265 return BGUI_MakeClass(CLASS_SuperClassBGUI
, BGUI_BASE_GADGET
,
2266 CLASS_ObjectSize
, sizeof(GD
),
2267 CLASS_DFTable
, ClassFunc
,