2 Copyright © 1999, David Le Corfec.
3 Copyright © 2002-2017, The AROS Development Team.
9 #include <exec/types.h>
11 #include <clib/alib_protos.h>
12 #include <proto/exec.h>
13 #include <proto/intuition.h>
14 #include <proto/utility.h>
15 #include <proto/graphics.h>
16 #include <proto/muimaster.h>
18 extern struct Library
*MUIMasterBase
;
20 #include "muimaster_intern.h"
25 /* #define MYDEBUG 1 */
28 #define ROUND(x) ((int)(x + 0.5))
29 #define IS_HIDDEN(obj) (! (_flags(obj) & MADF_SHOWME) \
30 || (_flags(obj) & MADF_BORDERGADGET))
32 /* Attributes filtered out in OM_SET, before OM_SET gets passed to children.
33 Tested with MUI under UAE/AOS.
45 MUIA_ContextMenuTrigger
62 /* Private attribute/method definitions */
63 #define MUIM_Group_Insert (MUIB_MUI|0x00424d34) /* MUI: V20 */
64 struct MUIP_Group_Insert
66 STACKED ULONG MethodID
;
71 #define MUIA_Group_ChildCount 0x80420322 /* MUI: V20 isg LONG */
85 struct Hook
*layout_hook
;
89 struct layout2d_elem
*row_infos
;
90 struct layout2d_elem
*col_infos
;
95 ULONG num_visible_children
; /* for horiz/vert group only */
96 ULONG horiz_weight_sum
;
97 ULONG vert_weight_sum
;
98 ULONG samesize_maxmin_horiz
;
99 ULONG samesize_maxmin_vert
;
100 ULONG update
; /* for MUI_Redraw() 1 - do not redraw the frame
101 * 2 - the virtual pos has changed */
102 struct MUI_EventHandlerNode ehn
;
103 LONG virt_offx
, virt_offy
; /* diplay offsets */
104 LONG old_virt_offx
, old_virt_offy
; /* Saved virtual positions,
105 * used for update == 2 */
106 LONG virt_mwidth
, virt_mheight
; /* The complete width */
107 LONG saved_minwidth
, saved_minheight
;
108 LONG dont_forward_get
; /* Set temporarily to 1 so that the get method
109 * is not forwarded */
110 LONG dont_forward_methods
; /* Set temporarily to 1, meaning that the
111 * methods are not forwarded to the group's
113 /* MUI4 group with tabs */
118 * The MUI4 feature of group with tabs is implemented based on behaviour of
119 * one application. What this application codes suggest it seems that passing
120 * MUIV_Frame_Register together with MUIA_Group_PageMode, TRUE activates this
122 * In such mode, the first passed group is used to register tab "titles" and
123 * is always visible. The selection of object in this group selects the
124 * matching (by position) group to be displayed
127 #define GROUP_HORIZ (1<<1)
128 #define GROUP_SAME_WIDTH (1<<2)
129 #define GROUP_SAME_HEIGHT (1<<3)
130 #define GROUP_CHANGING (1<<4)
131 #define GROUP_PAGEMODE (1<<5)
132 #define GROUP_VIRTUAL (1<<6)
133 #define GROUP_HSPACING (1<<7)
134 #define GROUP_VSPACING (1<<8)
135 #define GROUP_CHANGED (1<<9)
138 /* During minmax calculations objects with a weight of 0 shall
139 be treated like they had identical min/def/max size, ie. fixed size.
141 During layout objects with 0 weight must be treated like fixed-sized
142 too, but for hgroups only in x direction, and for vgroups only in
143 y direction. I think ... */
145 #define w0_defwidth(x) (_hweight(x) ? _defwidth(x) : _minwidth(x))
146 #define w0_maxwidth(x) (_hweight(x) ? _maxwidth(x) : _minwidth(x))
148 #define w0_defheight(x) (_vweight(x) ? _defheight(x) : _minheight(x))
149 #define w0_maxheight(x) (_vweight(x) ? _maxheight(x) : _minheight(x))
151 static const int __version
= 1;
152 static const int __revision
= 1;
154 IPTR
Group__MUIM_Show(struct IClass
*cl
, Object
*obj
,
155 struct MUIP_Show
*msg
);
156 IPTR
Group__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
157 struct MUIP_Hide
*msg
);
159 /*****************************************************************************/
160 /*****************************************************************************/
163 static ULONG
Group_DispatchMsg(struct IClass
*cl
, Object
*obj
, Msg msg
);
165 static void change_active_page(struct IClass
*cl
, Object
*obj
, LONG page
)
167 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
168 LONG newpage
, num_children
= data
->num_children
;
170 if (!(data
->flags
& GROUP_PAGEMODE
))
173 if (data
->titlegroup
!= NULL
)
178 case MUIV_Group_ActivePage_First
:
181 case MUIV_Group_ActivePage_Last
:
182 newpage
= num_children
- 1;
184 case MUIV_Group_ActivePage_Prev
:
185 newpage
= data
->active_page
- 1;
187 newpage
= num_children
- 1;
189 case MUIV_Group_ActivePage_Next
:
190 case MUIV_Group_ActivePage_Advance
:
191 newpage
= (data
->active_page
+ 1) % num_children
;
198 if (newpage
!= data
->active_page
)
200 if (_flags(obj
) & MADF_CANDRAW
)
201 Group__MUIM_Hide(cl
, obj
, NULL
);
203 data
->active_page
= newpage
;
205 if (_flags(obj
) & MADF_CANDRAW
)
207 DoMethod(obj
, MUIM_Layout
);
208 Group__MUIM_Show(cl
, obj
, NULL
);
210 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
213 if (data
->titlegroup
)
214 set(data
->titlegroup
, MUIA_Group_ActivePage
, newpage
);
218 /**************************************************************************
219 Returns the number of visible children. Visible children are all children
220 that have MADF_SHOWME and not MADF_BORDERGADGET set.
221 **************************************************************************/
222 static int Group_GetNumVisibleChildren(struct MUI_GroupData
*data
,
223 struct MinList
*children
)
225 int num_visible_children
= data
->num_children
;
229 /* As there can be invisible children we have to subtract those from
230 * the total number of children */
231 cstate
= (Object
*) children
->mlh_Head
;
232 while ((child
= NextObject(&cstate
)))
234 if (IS_HIDDEN(child
))
235 num_visible_children
--;
237 return num_visible_children
;
240 /**************************************************************************
241 Handles insertion of objects - works based on fact that IDs of all methods
242 that use it are the same for Group and Family and that struct share obj at
244 **************************************************************************/
245 struct MUIP_StructWithObj
247 STACKED ULONG MethodID
;
251 static IPTR
Group__MUIM_AddObject(struct IClass
*cl
, Object
*obj
, Msg msg
)
253 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
254 struct MUIP_StructWithObj
*msgint
= (struct MUIP_StructWithObj
*)msg
;
256 DoMethodA(data
->family
, (Msg
) msg
);
257 data
->num_children
++;
258 if ((data
->flags
& GROUP_CHANGING
) != 0)
259 data
->flags
|= GROUP_CHANGED
;
261 /* if we are in an application tree, propagate pointers */
262 if (muiNotifyData(obj
)->mnd_GlobalInfo
)
264 /* Only children of groups can have parents */
266 if ((_flags(obj
) & MADF_INVIRTUALGROUP
)
267 || (data
->flags
& GROUP_VIRTUAL
))
269 _flags(msgint
->obj
) |= MADF_INVIRTUALGROUP
;
272 DoMethod(msgint
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
275 /* Ensure new children are disabled if their parent is */
276 if (XGET(obj
, MUIA_Disabled
))
277 nnset(obj
, MUIA_Disabled
, TRUE
);
279 /* Some apps (Odyssey) expect _parent() will work before group tree is
280 * added to application tree */
281 muiNotifyData(msgint
->obj
)->mnd_ParentObject
= obj
;
283 if (_flags(obj
) & MADF_SETUP
)
285 DoSetupMethod(msgint
->obj
, muiRenderInfo(obj
));
287 /* if (_flags(obj) & MADF_CANDRAW) */
288 /* DoShowMethod(msg->opam_Object); */
293 /**************************************************************************
295 **************************************************************************/
296 IPTR
Group__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
298 struct MUI_GroupData
*data
;
299 struct TagItem
*tags
, *tag
;
300 BOOL bad_children
= FALSE
;
301 IPTR disabled
= FALSE
;
302 IPTR frame
= MUIV_Frame_None
;
304 D(bug("[group.mui] OM_NEW, object 0x%p\n", obj
));
306 obj
= (Object
*) DoSuperMethodA(cl
, obj
, (Msg
) msg
);
310 /* Initial local instance data */
311 data
= INST_DATA(cl
, obj
);
313 data
->family
= MUI_NewObjectA(MUIC_Family
, NULL
);
316 CoerceMethod(cl
, obj
, OM_DISPOSE
);
320 data
->horiz_spacing
= -1;
321 data
->vert_spacing
= -1;
324 data
->active_page
= 0;
325 get(obj
, MUIA_Frame
, &frame
);
327 /* parse initial taglist */
328 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
332 case MUIA_Group_Child
:
333 D(bug("[group.mui] Adding child 0x%p\n", tag
->ti_Data
));
336 DoMethod(obj
, OM_ADDMEMBER
, tag
->ti_Data
);
337 /* Set first child as group title */
338 if ((frame
== MUIV_Frame_Register
)
339 && (data
->titlegroup
== NULL
))
340 data
->titlegroup
= (Object
*) tag
->ti_Data
;
346 case MUIA_Group_ActivePage
:
347 change_active_page(cl
, obj
, (LONG
) tag
->ti_Data
);
350 case MUIA_Group_Columns
:
351 data
->columns
= (tag
->ti_Data
) > 1 ? tag
->ti_Data
: 1;
355 case MUIA_Group_Horiz
:
356 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_HORIZ
);
359 case MUIA_Group_HorizSpacing
:
360 data
->flags
|= GROUP_HSPACING
;
361 data
->horiz_spacing
= tag
->ti_Data
;
364 case MUIA_Group_LayoutHook
:
365 data
->layout_hook
= (struct Hook
*)tag
->ti_Data
;
368 case MUIA_Group_PageMode
:
369 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_PAGEMODE
);
372 case MUIA_Group_Rows
:
373 data
->rows
= MAX((ULONG
) tag
->ti_Data
, 1);
377 case MUIA_Group_SameHeight
:
378 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_HEIGHT
);
381 case MUIA_Group_SameSize
:
382 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_HEIGHT
);
383 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_WIDTH
);
386 case MUIA_Group_SameWidth
:
387 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_WIDTH
);
390 case MUIA_Group_Spacing
:
391 data
->flags
|= (GROUP_HSPACING
| GROUP_VSPACING
);
392 data
->horiz_spacing
= tag
->ti_Data
;
393 data
->vert_spacing
= tag
->ti_Data
;
396 case MUIA_Group_VertSpacing
:
397 data
->flags
|= GROUP_VSPACING
;
398 data
->vert_spacing
= tag
->ti_Data
;
401 case MUIA_Group_Virtual
:
402 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_VIRTUAL
);
409 CoerceMethod(cl
, obj
, OM_DISPOSE
);
413 /* D(bug("Group_New(0x%lx)\n",obj)); */
415 if (data
->flags
& GROUP_VIRTUAL
)
417 /* This is used by MUI_Render() to determine if group is virtual.
418 * It then installs a clip region.
419 * Also MUI_Layout() uses this. Probably for speed up reason */
420 _flags(obj
) |= MADF_ISVIRTUALGROUP
;
423 /* will forward MUIA_Disabled to children */
424 get(obj
, MUIA_Disabled
, &disabled
);
427 set(obj
, MUIA_Disabled
, TRUE
);
430 /* This is only used for virtual groups */
431 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
; /* Will be filled on demand */
432 data
->ehn
.ehn_Priority
= 10; /* Will hear the click before all
433 * other normal objects */
434 data
->ehn
.ehn_Flags
= 0;
435 data
->ehn
.ehn_Object
= obj
;
436 data
->ehn
.ehn_Class
= cl
;
440 /**************************************************************************
442 **************************************************************************/
443 IPTR
Group__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
445 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
447 if (data
->row_infos
!= NULL
)
448 mui_free(data
->row_infos
);
449 if (data
->col_infos
!= NULL
)
450 mui_free(data
->col_infos
);
451 if (data
->family
!= NULL
)
452 MUI_DisposeObject(data
->family
);
453 return DoSuperMethodA(cl
, obj
, msg
);
456 /**************************************************************************
458 **************************************************************************/
459 IPTR
Group__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
461 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
462 struct TagItem
*tags
= msg
->ops_AttrList
;
465 BOOL need_recalc
= FALSE
;
468 int virt_offx
= data
->virt_offx
, virt_offy
= data
->virt_offy
;
470 /* There are many ways to find out what tag items provided by set()
471 ** we do know. The best way should be using NextTagItem() and simply
472 ** browsing through the list.
475 /* Parse group attributes before calling DoSuperMethodA(),
476 ** otherwise if an app for example sets up a notification
477 ** on MUIA_Group_ActivePage which calls a hook, and then
478 ** the hook function calls get(obj, MUIA_Group_ActivePage),
479 ** it would get returned the old active page instead of the new
483 while ((tag
= NextTagItem(&tags
)) != NULL
)
487 case MUIA_Group_Columns
:
488 data
->columns
= MAX((ULONG
) tag
->ti_Data
, 1);
492 case MUIA_Group_ActivePage
:
493 change_active_page(cl
, obj
, (LONG
) tag
->ti_Data
);
495 case MUIA_Group_Forward
:
496 forward
= tag
->ti_Data
;
498 case MUIA_Group_HorizSpacing
:
499 data
->flags
|= GROUP_HSPACING
;
500 data
->horiz_spacing
= tag
->ti_Data
;
502 case MUIA_Group_Rows
:
503 data
->rows
= MAX((ULONG
) tag
->ti_Data
, 1);
507 case MUIA_Group_Spacing
:
508 data
->flags
|= (GROUP_HSPACING
| GROUP_VSPACING
);
509 data
->horiz_spacing
= tag
->ti_Data
;
510 data
->vert_spacing
= tag
->ti_Data
;
512 case MUIA_Group_VertSpacing
:
513 data
->flags
|= GROUP_VSPACING
;
514 data
->vert_spacing
= tag
->ti_Data
;
516 case MUIA_Virtgroup_Left
:
517 //kprintf("set virtgroup_left: %d\n", tag->ti_Data);
518 virt_offx
= tag
->ti_Data
;
521 case MUIA_Group_LayoutHook
:
523 [ach] Seems like MUI supports setting this attribute after
524 initialization, even though the documentation states
525 otherwise. At least some programs use it...
527 data
->layout_hook
= (struct Hook
*)tag
->ti_Data
;
530 case MUIA_Virtgroup_Top
:
531 //kprintf("set virtgroup_top: %d\n", tag->ti_Data);
532 virt_offy
= tag
->ti_Data
;
538 if (muiRenderInfo(obj
) && need_recalc
)
539 DoMethod(_win(obj
), MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
541 retval
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
543 /* seems to be the documented behaviour, however it should be slow! */
547 /* Attributes which are to be filtered out, so that they are ignored
548 when OM_SET is passed to group's children */
550 tags
= msg
->ops_AttrList
;
551 while ((tag
= NextTagItem(&tags
)) != NULL
)
560 case MUIA_ContextMenu
:
561 case MUIA_ContextMenuTrigger
:
562 case MUIA_ControlChar
:
563 case MUIA_CycleChain
:
566 case MUIA_Group_ActivePage
:
568 case MUIA_FrameTitle
:
569 case MUIA_HorizWeight
:
573 case MUIA_VertWeight
:
575 case MUIA_Virtgroup_Left
:
576 case MUIA_Virtgroup_Top
:
577 case MUIA_AppMessage
:
579 tag
->ti_Tag
= TAG_IGNORE
;
582 /* D(bug("Group_Set(%p) MUIA_Selected forwarded\n", obj)); */
583 /* tag->ti_Tag = TAG_IGNORE; */
588 Group_DispatchMsg(cl
, obj
, (Msg
) msg
);
592 if (virt_offx
!= data
->virt_offx
|| virt_offy
!= data
->virt_offy
)
594 if (_flags(obj
) & MADF_CANDRAW
)
595 Group__MUIM_Hide(cl
, obj
, NULL
);
596 data
->virt_offx
= virt_offx
;
597 data
->virt_offy
= virt_offy
;
598 /* Relayout ourselves. This will also relayout all the children */
599 DoMethod(obj
, MUIM_Layout
);
600 if (_flags(obj
) & MADF_CANDRAW
)
601 Group__MUIM_Show(cl
, obj
, NULL
);
603 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
610 /**************************************************************************
612 **************************************************************************/
613 IPTR
Group__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
615 /* small macro to simplify return value storage */
616 #define STORE *(msg->opg_Storage)
618 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
620 switch (msg
->opg_AttrID
)
628 case MUIA_Group_ActivePage
:
629 STORE
= data
->active_page
;
631 case MUIA_Group_ChildList
:
632 return GetAttr(MUIA_Family_List
, data
->family
, msg
->opg_Storage
);
633 case MUIA_Group_Horiz
:
634 STORE
= (data
->flags
& GROUP_HORIZ
);
636 case MUIA_Group_HorizSpacing
:
637 STORE
= data
->horiz_spacing
;
639 case MUIA_Group_VertSpacing
:
640 STORE
= data
->vert_spacing
;
642 case MUIA_Group_ChildCount
:
643 STORE
= data
->num_children
;
645 case MUIA_Virtgroup_Left
:
646 STORE
= data
->virt_offx
;
648 case MUIA_Virtgroup_Top
:
649 STORE
= data
->virt_offy
;
651 case MUIA_Virtgroup_Width
:
652 STORE
= data
->virt_mwidth
;
654 case MUIA_Virtgroup_Height
:
655 STORE
= data
->virt_mheight
;
657 case MUIA_Virtgroup_MinWidth
:
658 STORE
= data
->saved_minwidth
;
660 case MUIA_Virtgroup_MinHeight
:
661 STORE
= data
->saved_minheight
;
665 /* our handler didn't understand the attribute, we simply pass
666 ** it to our superclass now
668 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
671 /* seems to be the documented behaviour, however it should be slow! */
672 if (!data
->dont_forward_get
&& !data
->dont_forward_methods
)
676 struct MinList
*ChildList
= NULL
;
678 get(data
->family
, MUIA_Family_List
, &(ChildList
));
679 cstate
= (Object
*) ChildList
->mlh_Head
;
680 while ((child
= NextObject(&cstate
)))
681 if (DoMethodA(child
, (Msg
) msg
))
689 /**************************************************************************
691 **************************************************************************/
692 IPTR
Group__MUIM_AddTail(struct IClass
*cl
, Object
*obj
,
693 struct MUIP_Group_AddTail
*msg
)
695 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
698 /**************************************************************************
700 **************************************************************************/
701 IPTR
Group__MUIM_AddHead(struct IClass
*cl
, Object
*obj
,
702 struct MUIP_Group_AddHead
*msg
)
704 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
707 /**************************************************************************
709 **************************************************************************/
710 IPTR
Group__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
711 struct MUIP_Group_Insert
*msg
)
713 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
716 /**************************************************************************
718 **************************************************************************/
719 IPTR
Group__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
720 struct MUIP_Group_Remove
*msg
)
722 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
724 if (_flags(obj
) & MADF_CANDRAW
)
725 DoHideMethod(msg
->obj
);
726 if (_flags(obj
) & MADF_SETUP
)
727 DoMethod(msg
->obj
, MUIM_Cleanup
);
728 if (muiNotifyData(obj
)->mnd_GlobalInfo
)
730 DoMethod(msg
->obj
, MUIM_DisconnectParent
);
731 muiNotifyData(msg
->obj
)->mnd_ParentObject
= NULL
;
733 _flags(msg
->obj
) &= ~MADF_INVIRTUALGROUP
;
736 if ((data
->flags
& GROUP_CHANGING
) != 0)
737 data
->flags
|= GROUP_CHANGED
;
738 data
->num_children
--;
739 DoMethodA(data
->family
, (Msg
) msg
);
744 /**************************************************************************
746 **************************************************************************/
747 IPTR
Group__MUIM_Family_GetChild(struct IClass
*cl
, Object
*obj
,
748 struct MUIP_Group_Remove
*msg
)
750 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
752 return DoMethodA(data
->family
, (APTR
) msg
);
755 /**************************************************************************
757 **************************************************************************/
758 IPTR
Group__MUIM_ConnectParent(struct IClass
*cl
, Object
*obj
,
759 struct MUIP_ConnectParent
*msg
)
761 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
764 struct MinList
*ChildList
= NULL
;
766 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
768 get(data
->family
, MUIA_Family_List
, &(ChildList
));
769 cstate
= (Object
*) ChildList
->mlh_Head
;
770 while ((child
= NextObject(&cstate
)))
772 if ((_flags(obj
) & MADF_INVIRTUALGROUP
)
773 || (data
->flags
& GROUP_VIRTUAL
))
775 _flags(child
) |= MADF_INVIRTUALGROUP
;
778 /* Only children of groups can have parents */
779 muiNotifyData(child
)->mnd_ParentObject
= obj
;
781 DoMethod(child
, MUIM_ConnectParent
, (IPTR
) obj
);
786 /**************************************************************************
787 MUIM_DisconnectParent
788 **************************************************************************/
789 IPTR
Group__MUIM_DisconnectParent(struct IClass
*cl
, Object
*obj
,
790 struct MUIP_ConnectParent
*msg
)
792 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
795 struct MinList
*ChildList
= NULL
;
797 get(data
->family
, MUIA_Family_List
, &(ChildList
));
798 cstate
= (Object
*) ChildList
->mlh_Head
;
799 while ((child
= NextObject(&cstate
)))
801 DoMethodA(child
, (Msg
) msg
);
802 muiNotifyData(child
)->mnd_ParentObject
= NULL
;
803 _flags(child
) &= ~MADF_INVIRTUALGROUP
;
805 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
810 * Put group in exchange state
812 IPTR
Group__MUIM_InitChange(struct IClass
*cl
, Object
*obj
,
813 struct MUIP_Group_InitChange
*msg
)
815 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
817 data
->flags
&= ~GROUP_CHANGED
;
818 data
->flags
|= GROUP_CHANGING
;
824 * Will recalculate display after dynamic adding/removing
826 IPTR
Group__MUIM_ExitChange(struct IClass
*cl
, Object
*obj
,
827 struct MUIP_Group_ExitChange
*msg
)
829 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
831 data
->flags
&= ~GROUP_CHANGING
;
834 /* Code is invalid. ExitChange needs to re-layout each time (tested
835 * with MUI 3.8 and MUI 4.0 on m68k).
836 * This is temporary change until proper implementaion is in place. */
837 if (data
->flags
& GROUP_CHANGED
)
840 data
->flags
&= ~GROUP_CHANGED
;
842 if ((_flags(obj
) & MADF_SETUP
) && _win(obj
))
844 Object
*win
= _win(obj
);
845 Object
*parent
= obj
;
847 /* CHECKME: Don't call RecalcDisplay if one of our parents is
848 in GROUP_CHANGING state to prevent crash with Zune prefs
849 program NListtree page because NList/NListtree when
850 killing tree images in MUIM_Cleanup uses InitChange/
851 ExitChange. Zune prefs program uses InitChange/ExitChange
852 when switching page -> nesting -> mess. */
854 while ((parent
= _parent(parent
)))
856 struct MUI_GroupData
*pdata
= INST_DATA(cl
, parent
);
861 if (pdata
->flags
& GROUP_CHANGING
)
868 DoMethod(win
, MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
877 * Will recalculate display after dynamic adding/removing
879 IPTR
Group__MUIM_ExitChange2(struct IClass
*cl
, Object
*obj
,
880 struct MUIP_Group_ExitChange2
*msg
)
882 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
884 if (data
->flags
& GROUP_CHANGING
)
886 data
->flags
&= ~(GROUP_CHANGING
| GROUP_CHANGED
);
888 if ((_flags(obj
) & MADF_SETUP
) && _win(obj
))
890 Object
*win
= _win(obj
);
891 Object
*parent
= obj
;
893 /* CHECKME: Don't call RecalcDisplay if one of our parents is
894 in GROUP_CHANGING state to prevent crash with Zune prefs
895 program NListtree page because NList/NListtree when
896 killing tree images in MUIM_Cleanup uses InitChange/
897 ExitChange. Zune prefs program uses InitChange/ExitChange
898 when switching page -> nesting -> mess. */
900 while ((parent
= _parent(parent
)))
902 struct MUI_GroupData
*pdata
= INST_DATA(cl
, parent
);
907 if (pdata
->flags
& GROUP_CHANGING
)
914 DoMethod(win
, MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
925 IPTR
Group__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
926 struct MUIP_Group_Sort
*msg
)
928 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
931 msg
->MethodID
= MUIM_Family_Sort
;
933 DoMethodA(data
->family
, (APTR
) msg
);
935 /* restore original message */
936 msg
->MethodID
= MUIM_Group_Sort
;
940 /**************************************************************************
941 MUIM_Group_DoMethodNoForward
943 Executes the given method but does not forward it to the children
944 **************************************************************************/
945 IPTR
Group__MUIM_DoMethodNoForward(struct IClass
*cl
, Object
*obj
,
946 struct MUIP_Group_DoMethodNoForward
*msg
)
948 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
950 data
->dont_forward_methods
= 1; /* disable forwarding */
951 rc
= DoMethodA(obj
, (Msg
) & msg
->DoMethodID
);
952 /* Probably doesn't work correctly on AROS? */
954 data
->dont_forward_methods
= 0;
959 * Propagate a method to group children.
961 static ULONG
Group_DispatchMsg(struct IClass
*cl
, Object
*obj
, Msg msg
)
963 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
966 struct MinList
*ChildList
= NULL
;
968 if (data
->dont_forward_methods
)
971 get(data
->family
, MUIA_Family_List
, &(ChildList
));
972 cstate
= (Object
*) ChildList
->mlh_Head
;
973 while ((child
= NextObject(&cstate
)))
975 DoMethodA(child
, (Msg
) msg
);
981 /**************************************************************************
983 **************************************************************************/
984 IPTR
Group__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
985 struct MUIP_Setup
*msg
)
987 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
992 struct MinList
*ChildList
= NULL
;
994 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
997 ASSERT_VALID_PTR(muiGlobalInfo(obj
));
999 if (!(data
->flags
& GROUP_HSPACING
))
1000 data
->horiz_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_hspacing
;
1001 if (!(data
->flags
& GROUP_VSPACING
))
1002 data
->vert_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_vspacing
;
1003 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1004 cstate
= cstate_copy
= (Object
*) ChildList
->mlh_Head
;
1005 while ((child
= NextObject(&cstate
)))
1007 #if 0 /* SHOWME affects only show/hide */
1008 if (!(_flags(child
) & MADF_SHOWME
))
1012 if (!DoSetupMethod(child
, msg
->RenderInfo
))
1014 /* Send MUIM_Cleanup to all objects that received MUIM_Setup.
1016 childFailed
= child
;
1017 cstate
= cstate_copy
;
1018 while ((child
= NextObject(&cstate
)) && (child
!= childFailed
))
1020 #if 0 /* SHOWME affects only show/hide */
1021 if (!(_flags(child
) & MADF_SHOWME
))
1024 DoMethod(child
, MUIM_Cleanup
);
1030 if (data
->flags
& GROUP_VIRTUAL
)
1032 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
1033 (IPTR
) & data
->ehn
);
1040 /**************************************************************************
1042 **************************************************************************/
1043 IPTR
Group__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
, Msg msg
)
1045 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1048 struct MinList
*ChildList
= NULL
;
1050 if (data
->flags
& GROUP_VIRTUAL
)
1052 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
1053 (IPTR
) & data
->ehn
);
1056 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1057 cstate
= (Object
*) ChildList
->mlh_Head
;
1058 while ((child
= NextObject(&cstate
)))
1060 #if 0 /* SHOWME affects only show/hide */
1061 if (!(_flags(child
) & MADF_SHOWME
))
1064 DoMethodA(child
, (Msg
) msg
);
1066 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1069 static struct Region
*group_children_clip_region(struct IClass
*cl
,
1072 struct Region
*region
= NULL
;
1074 region
= NewRegion();
1077 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1078 struct Rectangle rect
;
1080 struct MinList
*ChildList
= NULL
;
1084 rect
.MinX
= _left(obj
);
1085 rect
.MinY
= _top(obj
);
1086 rect
.MaxX
= _right(obj
);
1087 rect
.MaxY
= _bottom(obj
);
1089 OrRectRegion(region
, &rect
);
1090 get(data
->family
, MUIA_Family_List
, &ChildList
);
1091 cstate
= (Object
*) ChildList
->mlh_Head
;
1092 while ((child
= NextObject(&cstate
)))
1094 if (child
!= data
->titlegroup
)
1097 if ((data
->flags
& GROUP_PAGEMODE
) && (page
!= data
->active_page
)
1098 && (child
!= data
->titlegroup
))
1101 if ((muiAreaData(child
)->mad_Flags
& MADF_CANDRAW
)
1102 && (_width(child
) > 0) && (_height(child
) > 0))
1104 rect
.MinX
= MAX(_left(child
), _mleft(obj
));
1105 rect
.MinY
= MAX(_top(child
), _mtop(obj
));
1106 rect
.MaxX
= MIN(_right(child
), _mright(obj
));
1107 rect
.MaxY
= MIN(_bottom(child
), _mbottom(obj
));
1109 if ((rect
.MaxX
>= rect
.MinX
) && (rect
.MaxY
>= rect
.MinY
))
1111 ClearRectRegion(region
, &rect
);
1120 /**************************************************************************
1121 MUIM_Draw - draw the group
1122 **************************************************************************/
1123 IPTR
Group__MUIM_Draw(struct IClass
*cl
, Object
*obj
,
1124 struct MUIP_Draw
*msg
)
1126 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1129 struct MinList
*ChildList
= NULL
;
1130 struct Rectangle group_rect
; /* child_rect; */
1132 struct Region
*region
= NULL
;
1133 APTR clip
= (APTR
) - 1;
1135 if (data
->flags
& GROUP_CHANGING
)
1138 if (muiGlobalInfo(obj
)->mgi_Prefs
->window_redraw
1139 == WINDOW_REDRAW_WITHOUT_CLEAR
)
1141 struct Region
*r
= group_children_clip_region(cl
, obj
);
1144 c
= MUI_AddClipRegion(muiRenderInfo(obj
), r
);
1146 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1149 MUI_RemoveClipRegion(muiRenderInfo(obj
), c
);
1153 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1156 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1)
1158 struct Region
*r
= NULL
;
1161 if (muiGlobalInfo(obj
)->mgi_Prefs
->window_redraw
1162 == WINDOW_REDRAW_WITHOUT_CLEAR
)
1163 r
= group_children_clip_region(cl
, obj
);
1166 c
= MUI_AddClipRegion(muiRenderInfo(obj
), r
);
1169 * update is set when changing active page of a page group
1170 * need to redraw background ourself
1172 DoMethod(obj
, MUIM_DrawBackground
,
1173 _mleft(obj
), _mtop(obj
), _mwidth(obj
), _mheight(obj
),
1174 _mleft(obj
), _mtop(obj
), 0);
1177 MUI_RemoveClipRegion(muiRenderInfo(obj
), c
);
1181 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2)
1183 LONG left
, top
, right
, bottom
;
1184 LONG diff_virt_offx
= data
->virt_offx
- data
->old_virt_offx
;
1185 LONG diff_virt_offy
= data
->virt_offy
- data
->old_virt_offy
;
1186 struct Rectangle rect
;
1187 struct Rectangle
*clip_rect
= &muiRenderInfo(obj
)->mri_ClipRect
;
1191 if (!diff_virt_offx
&& !diff_virt_offy
)
1196 /* sba: I don't know how MUI handle this but ScrollRasterBF() made problems when scrolling
1197 ** a (partly visible) virtual groups in a virtual group, because e.g. _mtop() is then
1198 ** smaller than the region. ScrollRasterBF() on AmigaOS then marks the complete region
1199 ** as damaged. Using ScrollWindowRaster() solved that problem but it flickers then.
1200 ** To avoid this we prevent that the scroll area is out of the region bounds.
1201 ** The region bounds are setted in MUI_Redraw() but should probably should go in the
1202 ** MUI's clip functions
1205 left
= MAX(_mleft(obj
), clip_rect
->MinX
);
1206 top
= MAX(_mtop(obj
), clip_rect
->MinY
);
1207 right
= MIN(_mright(obj
), clip_rect
->MaxX
);
1208 bottom
= MIN(_mbottom(obj
), clip_rect
->MaxY
);
1211 ** ScrollRasterBF(_rp(obj), diff_virt_offx, diff_virt_offy, _mleft(obj), _mtop(obj), _mright(obj),_mbottom(obj));
1214 ScrollWindowRaster(_window(obj
), diff_virt_offx
, diff_virt_offy
,
1215 left
, top
, right
, bottom
);
1217 if ((region
= NewRegion()))
1224 if (diff_virt_offx
> 0)
1226 rect
.MinX
= right
- diff_virt_offx
+ 1;
1227 if (rect
.MinX
< left
)
1234 rect
.MaxX
= left
- diff_virt_offx
- 1;
1235 if (rect
.MaxX
> right
)
1239 if (rect
.MinX
<= rect
.MaxX
)
1241 DoMethod(obj
, MUIM_DrawBackground
,
1242 rect
.MinX
, rect
.MinY
,
1243 rect
.MaxX
- rect
.MinX
+ 1,
1244 rect
.MaxY
- rect
.MinY
+ 1,
1245 rect
.MinX
, rect
.MinY
, 0);
1247 OrRectRegion(region
, &rect
);
1256 if (diff_virt_offy
> 0)
1258 rect
.MinY
= bottom
- diff_virt_offy
+ 1;
1259 if (rect
.MinY
< top
)
1266 rect
.MaxY
= top
- diff_virt_offy
- 1;
1267 if (rect
.MaxY
> bottom
)
1270 if (rect
.MinY
<= rect
.MaxY
)
1272 DoMethod(obj
, MUIM_DrawBackground
,
1273 rect
.MinX
, rect
.MinY
,
1274 rect
.MaxX
- rect
.MinX
+ 1,
1275 rect
.MaxY
- rect
.MinY
+ 1,
1276 rect
.MinX
, rect
.MinY
, 0);
1278 OrRectRegion(region
, &rect
);
1286 if (!(msg
->flags
& MADF_DRAWOBJECT
)
1287 && !(msg
->flags
& MADF_DRAWALL
))
1292 if (data
->flags
& GROUP_VIRTUAL
&& !region
)
1294 /* Not really needed if MUI Draws all the objects, maybe that's
1295 * what DRAWALL is for??? */
1296 if ((region
= NewRegion()))
1298 struct Rectangle rect
;
1299 rect
.MinX
= _mleft(obj
);
1300 rect
.MinY
= _mtop(obj
);
1301 rect
.MaxX
= _mright(obj
);
1302 rect
.MaxY
= _mbottom(obj
);
1303 OrRectRegion(region
, &rect
);
1307 /* Add clipping region if we have one */
1309 clip
= MUI_AddClipRegion(muiRenderInfo(obj
), region
);
1311 group_rect
= muiRenderInfo(obj
)->mri_ClipRect
;
1313 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1314 cstate
= (Object
*) ChildList
->mlh_Head
;
1315 while ((child
= NextObject(&cstate
)))
1317 if (!(_flags(child
) & MADF_SHOWME
))
1320 if (child
!= data
->titlegroup
)
1323 if ((data
->flags
& GROUP_PAGEMODE
) && ((page
!= data
->active_page
)
1324 && (child
!= data
->titlegroup
)))
1329 if ((data
->flags
& GROUP_PAGEMODE
) && (child
== data
->titlegroup
)
1330 && (msg
->flags
& MADF_DRAWUPDATE
) && (data
->update
== 1))
1332 /* Do not issue a re-draw to title group during page switch.
1333 * The group will re-draw itself due to setting of
1334 * MUIA_Group_ActivePage attribute.
1339 MUI_Redraw(child
, MADF_DRAWOBJECT
);
1340 muiRenderInfo(obj
)->mri_ClipRect
= group_rect
;
1343 if (data
->flags
& GROUP_VIRTUAL
&& region
&& clip
!= (APTR
) - 1)
1345 MUI_RemoveClipRegion(muiRenderInfo(obj
), clip
);
1348 data
->old_virt_offx
= data
->virt_offx
;
1349 data
->old_virt_offy
= data
->virt_offy
;
1356 #define END_MINMAX() \
1357 tmp.MaxHeight = MAX(tmp.MaxHeight, tmp.MinHeight); \
1358 tmp.MaxWidth = MAX(tmp.MaxWidth, tmp.MinWidth); \
1359 tmp.DefHeight = CLAMP(tmp.DefHeight, tmp.MinHeight, tmp.MaxHeight); \
1360 tmp.DefWidth = CLAMP(tmp.DefWidth, tmp.MinWidth, tmp.MaxWidth); \
1361 msg->MinMaxInfo->MinWidth += tmp.MinWidth; \
1362 msg->MinMaxInfo->MinHeight += tmp.MinHeight; \
1363 msg->MinMaxInfo->MaxWidth += tmp.MaxWidth; \
1364 msg->MinMaxInfo->MaxHeight += tmp.MaxHeight; \
1365 msg->MinMaxInfo->DefWidth += tmp.DefWidth; \
1366 msg->MinMaxInfo->DefHeight += tmp.DefHeight;
1369 * MinMax calculation function. When this is called,
1370 * the children of your group have already been asked
1371 * about their min/max dimension so you can use their
1372 * dimensions to calculate yours.
1375 * - Init minwidth and maxwidth with size needed for total child spacing.
1376 * - 1st pass to find maximum minimum width, to set minwidth of each child
1377 * if they should have the same width (for a row of buttons ...)
1378 * - Adjust minwidth w/o making object bigger than their max size.
1380 static void group_minmax_horiz(struct IClass
*cl
, Object
*obj
,
1381 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1383 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1386 struct MUI_MinMax tmp
;
1387 WORD maxminwidth
= 0;
1388 BOOL found_nonzero_vweight
= FALSE
;
1392 tmp
.MaxHeight
= MUI_MAXMAX
;
1393 if (data
->num_visible_children
> 0)
1395 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1396 (data
->num_visible_children
- 1) * data
->horiz_spacing
;
1400 tmp
.MinWidth
= tmp
.DefWidth
= 0;
1401 tmp
.MaxWidth
= MUI_MAXMAX
;
1404 if (data
->flags
& GROUP_SAME_WIDTH
)
1406 cstate
= (Object
*) children
->mlh_Head
;
1407 while ((child
= NextObject(&cstate
)))
1409 if (IS_HIDDEN(child
))
1411 maxminwidth
= MAX(maxminwidth
, _minwidth(child
));
1415 data
->samesize_maxmin_horiz
= maxminwidth
;
1416 /* D(bug("group_minmax_horiz(%p) : maxminwidth=%d\n", obj, maxminwidth)); */
1418 data
->horiz_weight_sum
= 0;
1419 cstate
= (Object
*) children
->mlh_Head
;
1420 while ((child
= NextObject(&cstate
)))
1424 if (IS_HIDDEN(child
))
1426 if (data
->flags
& GROUP_SAME_WIDTH
)
1428 minwidth
= MAX(maxminwidth
, _minwidth(child
));
1429 minwidth
= MIN(minwidth
, _maxwidth(child
));
1432 minwidth
= _minwidth(child
);
1433 tmp
.MinWidth
+= minwidth
;
1434 tmp
.DefWidth
+= w0_defwidth(child
);
1435 tmp
.MaxWidth
+= w0_maxwidth(child
);
1436 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, MUI_MAXMAX
);
1437 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1438 tmp
.DefHeight
= MAX(tmp
.DefHeight
, _defheight(child
));
1440 if all children have null weight then maxheight=minheight
1441 if all but some children have null weights, the maxheight
1442 is the min of all maxheights
1444 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, _maxheight(child
));
1445 data
->horiz_weight_sum
+= _hweight(child
);
1446 if (_vweight(child
) > 0)
1448 found_nonzero_vweight
= TRUE
;
1451 if (!found_nonzero_vweight
)
1453 tmp
.MaxHeight
= tmp
.MinHeight
;
1456 //if (data->flags & GROUP_VIRTUAL)
1458 //kprintf("# min %d x %d def %d x %d max %d x %d\n",
1459 // tmp.MinWidth, tmp.MinHeight,
1460 // tmp.DefWidth, tmp.DefHeight,
1461 // tmp.MaxWidth, tmp.MaxHeight);
1467 /* minmax calculation for vertical groups (see group_minmax_horiz)
1469 static void group_minmax_vert(struct IClass
*cl
, Object
*obj
,
1470 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1472 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1475 struct MUI_MinMax tmp
;
1476 WORD maxminheight
= 0;
1477 BOOL found_nonzero_hweight
= FALSE
;
1481 tmp
.MaxWidth
= MUI_MAXMAX
;
1482 if (data
->num_visible_children
> 0)
1484 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1485 (data
->num_visible_children
- 1) * data
->vert_spacing
;
1489 tmp
.MinHeight
= tmp
.DefHeight
= 0;
1490 tmp
.MaxHeight
= MUI_MAXMAX
;
1493 if (data
->flags
& GROUP_SAME_HEIGHT
)
1495 cstate
= (Object
*) children
->mlh_Head
;
1496 while ((child
= NextObject(&cstate
)))
1498 if (IS_HIDDEN(child
))
1500 maxminheight
= MAX(maxminheight
, _minheight(child
));
1504 data
->samesize_maxmin_vert
= maxminheight
;
1505 data
->vert_weight_sum
= 0;
1506 cstate
= (Object
*) children
->mlh_Head
;
1507 while ((child
= NextObject(&cstate
)))
1509 if (IS_HIDDEN(child
))
1512 if (data
->flags
& GROUP_SAME_HEIGHT
)
1513 _minheight(child
) = MIN(maxminheight
, w0_maxheight(child
));
1514 tmp
.MinHeight
+= _minheight(child
);
1515 tmp
.DefHeight
+= w0_defheight(child
);
1516 tmp
.MaxHeight
+= w0_maxheight(child
);
1517 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, MUI_MAXMAX
);
1518 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1519 tmp
.DefWidth
= MAX(tmp
.DefWidth
, _defwidth(child
));
1520 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, _maxwidth(child
));
1521 data
->vert_weight_sum
+= _vweight(child
);
1522 if (_hweight(child
) > 0)
1524 found_nonzero_hweight
= TRUE
;
1527 if (!found_nonzero_hweight
)
1529 tmp
.MaxWidth
= tmp
.MinWidth
;
1537 minmax_2d_rows_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1538 struct MUI_MinMax
*req
, WORD maxmin_height
, WORD maxdef_height
)
1544 /* do not rewind after the while, to process line by line */
1545 cstate
= (Object
*) children
->mlh_Head
;
1547 for (i
= 0; i
< data
->rows
; i
++)
1549 /* calculate min and max height of this row */
1550 int min_h
= 0, def_h
= 0, max_h
= MUI_MAXMAX
;
1551 BOOL found_nonzero_vweight
= FALSE
;
1553 data
->row_infos
[i
].weight
= 0;
1556 while ((child
= NextObject(&cstate
)))
1558 if (IS_HIDDEN(child
))
1560 if (data
->flags
& GROUP_SAME_HEIGHT
)
1562 _minheight(child
) = MIN(maxmin_height
, w0_maxheight(child
));
1563 _defheight(child
) = MIN(maxdef_height
, w0_maxheight(child
));
1565 min_h
= MAX(min_h
, _minheight(child
));
1566 def_h
= MAX(def_h
, w0_defheight(child
));
1567 max_h
= MIN(max_h
, _maxheight(child
));
1568 if (_vweight(child
) > 0)
1570 found_nonzero_vweight
= TRUE
;
1571 data
->row_infos
[i
].weight
+= _vweight(child
);
1574 if ((j
% data
->columns
) == 0)
1577 if (!found_nonzero_vweight
)
1580 max_h
= MAX(max_h
, min_h
);
1581 /* D(bug("row %d : min_h=%d max_h=%d\n", i, min_h, max_h)); */
1583 data
->row_infos
[i
].min
= min_h
;
1584 data
->row_infos
[i
].max
= max_h
;
1585 data
->vert_weight_sum
+= data
->row_infos
[i
].weight
;
1587 req
->MinHeight
+= min_h
;
1588 req
->DefHeight
+= def_h
;
1589 req
->MaxHeight
+= max_h
;
1590 if (req
->MaxHeight
> MUI_MAXMAX
)
1591 req
->MaxHeight
= MUI_MAXMAX
;
1597 minmax_2d_columns_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1598 struct MUI_MinMax
*req
, WORD maxmin_width
, WORD maxdef_width
)
1604 for (i
= 0; i
< data
->columns
; i
++)
1606 /* calculate min and max width of this column */
1607 int min_w
= 0, def_w
= 0, max_w
= MUI_MAXMAX
;
1608 BOOL found_nonzero_hweight
= FALSE
;
1610 data
->col_infos
[i
].weight
= 0;
1613 /* process all children to get children on a column */
1614 cstate
= (Object
*) children
->mlh_Head
;
1615 while ((child
= NextObject(&cstate
)))
1617 if (IS_HIDDEN(child
))
1620 if (((j
- 1) % data
->columns
) != i
)
1622 if (data
->flags
& GROUP_SAME_WIDTH
)
1624 _minwidth(child
) = MIN(maxmin_width
, w0_maxwidth(child
));
1625 _defwidth(child
) = MIN(maxdef_width
, w0_maxwidth(child
));
1627 min_w
= MAX(min_w
, _minwidth(child
));
1628 def_w
= MAX(def_w
, w0_defwidth(child
));
1630 /* this handles the case of null weight children, which limit
1631 * the max size if they're alone, but not if they are with
1632 * non-null weight obj
1634 max_w
= MIN(max_w
, _maxwidth(child
));
1635 if (_hweight(child
) > 0)
1637 found_nonzero_hweight
= TRUE
;
1638 data
->col_infos
[i
].weight
+= _hweight(child
);
1641 if (!found_nonzero_hweight
)
1644 max_w
= MAX(max_w
, min_w
);
1645 /* D(bug("col %d : min_w=%d max_w=%d\n", i, min_w, max_w)); */
1647 data
->col_infos
[i
].min
= min_w
;
1648 data
->col_infos
[i
].max
= max_w
;
1649 data
->horiz_weight_sum
+= data
->col_infos
[i
].weight
;
1651 req
->MinWidth
+= min_w
;
1652 req
->DefWidth
+= def_w
;
1653 req
->MaxWidth
+= max_w
;
1654 if (req
->MaxWidth
> MUI_MAXMAX
)
1655 req
->MaxWidth
= MUI_MAXMAX
;
1660 group_minmax_2d(struct IClass
*cl
, Object
*obj
,
1661 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1663 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1666 struct MUI_MinMax tmp
;
1674 if (data
->num_children
% data
->rows
)
1677 data
->rows
= data
->num_children
;
1680 data
->columns
= data
->num_children
/ data
->rows
;
1684 if (data
->num_children
% data
->columns
)
1687 data
->columns
= data
->num_children
;
1690 data
->rows
= data
->num_children
/ data
->columns
;
1693 if (data
->columns
< 1)
1698 if (data
->row_infos
!= NULL
)
1699 mui_free(data
->row_infos
);
1701 data
->row_infos
= mui_alloc(data
->rows
* sizeof(struct layout2d_elem
));
1702 if (NULL
== data
->row_infos
)
1705 if (data
->col_infos
!= NULL
)
1706 mui_free(data
->col_infos
);
1709 mui_alloc(data
->columns
* sizeof(struct layout2d_elem
));
1710 if (NULL
== data
->col_infos
)
1713 data
->horiz_weight_sum
= 0;
1714 data
->vert_weight_sum
= 0;
1716 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1717 (data
->rows
- 1) * data
->vert_spacing
;
1718 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1719 (data
->columns
- 1) * data
->horiz_spacing
;
1720 /* get minimum dims if same dims for all children are needed */
1726 if ((data
->flags
& GROUP_SAME_WIDTH
)
1727 || (data
->flags
& GROUP_SAME_HEIGHT
))
1729 cstate
= (Object
*) children
->mlh_Head
;
1730 while ((child
= NextObject(&cstate
)))
1732 if (!(_flags(child
) & MADF_SHOWME
))
1734 maxmin_width
= MAX(maxmin_width
, _minwidth(child
));
1735 maxmin_height
= MAX(maxmin_height
, _minheight(child
));
1736 maxdef_width
= MAX(maxdef_width
, w0_defwidth(child
));
1737 maxdef_height
= MAX(maxdef_height
, w0_defheight(child
));
1739 /* g_print("2d group: mminw=%d mminh=%d\n", */
1740 /* maxmin_width, maxmin_height); */
1742 if (data
->flags
& GROUP_SAME_HEIGHT
)
1743 data
->samesize_maxmin_vert
= maxmin_height
;
1745 data
->samesize_maxmin_vert
= 0;
1747 if (data
->flags
& GROUP_SAME_WIDTH
)
1748 data
->samesize_maxmin_horiz
= maxmin_width
;
1750 data
->samesize_maxmin_horiz
= 0;
1752 minmax_2d_rows_pass(data
, children
, &tmp
, maxmin_height
, maxdef_height
);
1753 minmax_2d_columns_pass(data
, children
, &tmp
, maxmin_width
,
1761 group_minmax_pagemode(struct IClass
*cl
, Object
*obj
,
1762 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1766 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1767 struct MUI_MinMax tmp
= { 0, 0, MUI_MAXMAX
, MUI_MAXMAX
, 0, 0 };
1769 cstate
= (Object
*) children
->mlh_Head
;
1771 D(bug("minmax_pagemode(%lx)\n", obj
, tmp
.DefWidth
));
1773 while ((child
= NextObject(&cstate
)))
1775 if (!(_flags(child
) & MADF_SHOWME
))
1778 if (child
== data
->titlegroup
)
1781 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1782 D(bug("minmax_pagemode(%p) minh child = %d tmpmin=%d\n", obj
,
1783 _minheight(child
), tmp
.MinHeight
));
1784 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1785 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, w0_maxheight(child
));
1786 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, w0_maxwidth(child
));
1787 tmp
.DefHeight
= MAX(tmp
.DefHeight
,
1788 ((w0_defheight(child
) <
1789 MUI_MAXMAX
) ? w0_defheight(child
) : tmp
.DefHeight
));
1792 ((w0_defwidth(child
) <
1793 MUI_MAXMAX
) ? w0_defwidth(child
) : tmp
.DefWidth
));
1794 D(bug("minmax_pagemode(%lx) defw = %ld\n", obj
, tmp
.DefWidth
));
1797 if (data
->titlegroup
)
1799 tmp
.MinHeight
+= _minheight(data
->titlegroup
);
1800 tmp
.MaxHeight
+= w0_maxheight(data
->titlegroup
);
1801 tmp
.DefHeight
+= w0_defheight(data
->titlegroup
);
1807 /**************************************************************************
1808 MUIM_AskMinMax : ask children about min/max sizes, then
1809 either call a hook, or the builtin method, to calculate our minmax
1810 **************************************************************************/
1811 IPTR
Group__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1812 struct MUIP_AskMinMax
*msg
)
1814 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1815 struct MUI_LayoutMsg lm
;
1816 struct MUIP_AskMinMax childMsg
;
1817 struct MUI_MinMax childMinMax
;
1820 LONG super_minwidth
, super_minheight
;
1823 * let our superclass first fill in its size with frame, inner spc etc ...
1825 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1826 super_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1827 super_minheight
= msg
->MinMaxInfo
->MinHeight
;
1832 childMsg
.MethodID
= msg
->MethodID
;
1833 childMsg
.MinMaxInfo
= &childMinMax
;
1834 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
1836 cstate
= (Object
*) lm
.lm_Children
->mlh_Head
;
1838 while ((child
= NextObject(&cstate
)))
1840 if (!(_flags(child
) & MADF_SHOWME
))
1841 /* BORDERGADGETs should handle this itself */
1844 DoMethodA(child
, (Msg
) & childMsg
);
1845 /* D(bug("*** group %lx, child %lx min=%ld,%ld\n", */
1846 /* obj, child, childMinMax.MinWidth, childMinMax.MinHeight)); */
1847 __area_finish_minmax(child
, childMsg
.MinMaxInfo
);
1851 * Use children infos to calculate group size
1853 if (data
->flags
& GROUP_PAGEMODE
)
1855 D(bug("minmax_pagemode(%p) minh initial = %d\n", obj
,
1856 msg
->MinMaxInfo
->MinHeight
));
1857 group_minmax_pagemode(cl
, obj
, lm
.lm_Children
, msg
);
1858 D(bug("minmax_pagemode(%p) minh = %d\n", obj
,
1859 msg
->MinMaxInfo
->MinHeight
));
1861 else if (data
->layout_hook
)
1863 lm
.lm_Type
= MUILM_MINMAX
;
1864 CallHookPkt(data
->layout_hook
, obj
, &lm
);
1866 if (lm
.lm_MinMax
.MaxHeight
< lm
.lm_MinMax
.MinHeight
)
1867 lm
.lm_MinMax
.MaxHeight
= lm
.lm_MinMax
.MinHeight
;
1868 if (lm
.lm_MinMax
.DefHeight
< lm
.lm_MinMax
.MinHeight
)
1869 lm
.lm_MinMax
.DefHeight
= lm
.lm_MinMax
.MinHeight
;
1870 if (lm
.lm_MinMax
.MaxWidth
< lm
.lm_MinMax
.MinWidth
)
1871 lm
.lm_MinMax
.MaxWidth
= lm
.lm_MinMax
.MinWidth
;
1872 if (lm
.lm_MinMax
.DefWidth
< lm
.lm_MinMax
.MinWidth
)
1873 lm
.lm_MinMax
.DefWidth
= lm
.lm_MinMax
.MinWidth
;
1875 //kprintf("### min %d x %d def %d x %d max %d x %d\n",
1876 // msg->MinMaxInfo->MinWidth,
1877 // msg->MinMaxInfo->MinHeight,
1878 // msg->MinMaxInfo->DefWidth,
1879 // msg->MinMaxInfo->DefHeight,
1880 // msg->MinMaxInfo->MaxWidth,
1881 // msg->MinMaxInfo->MaxHeight);
1883 msg
->MinMaxInfo
->MinWidth
+= lm
.lm_MinMax
.MinWidth
;
1884 msg
->MinMaxInfo
->MinHeight
+= lm
.lm_MinMax
.MinHeight
;
1885 msg
->MinMaxInfo
->MaxWidth
+= lm
.lm_MinMax
.MaxWidth
;
1886 if (msg
->MinMaxInfo
->MaxWidth
> MUI_MAXMAX
)
1887 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1888 msg
->MinMaxInfo
->MaxHeight
+= lm
.lm_MinMax
.MaxHeight
;
1889 if (msg
->MinMaxInfo
->MaxHeight
> MUI_MAXMAX
)
1890 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1891 msg
->MinMaxInfo
->DefWidth
+= lm
.lm_MinMax
.DefWidth
;
1892 msg
->MinMaxInfo
->DefHeight
+= lm
.lm_MinMax
.DefHeight
;
1894 //kprintf("#### min %d x %d def %d x %d max %d x %d\n",
1895 // msg->MinMaxInfo->MinWidth,
1896 // msg->MinMaxInfo->MinHeight,
1897 // msg->MinMaxInfo->DefWidth,
1898 // msg->MinMaxInfo->DefHeight,
1899 // msg->MinMaxInfo->MaxWidth,
1900 // msg->MinMaxInfo->MaxHeight);
1905 if ((data
->rows
== 1) && (data
->columns
== 1))
1907 data
->num_visible_children
=
1908 Group_GetNumVisibleChildren(data
, lm
.lm_Children
);
1909 if (data
->flags
& GROUP_HORIZ
)
1910 group_minmax_horiz(cl
, obj
, lm
.lm_Children
, msg
);
1912 group_minmax_vert(cl
, obj
, lm
.lm_Children
, msg
);
1916 group_minmax_2d(cl
, obj
, lm
.lm_Children
, msg
);
1920 if (data
->flags
& GROUP_VIRTUAL
)
1922 data
->saved_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1923 data
->saved_minheight
= msg
->MinMaxInfo
->MinHeight
;
1924 msg
->MinMaxInfo
->MinWidth
= super_minwidth
+ 2;
1925 msg
->MinMaxInfo
->MinHeight
= super_minheight
+ 2;
1927 //kprintf("## min %d x %d def %d x %d max %d x %d\n",
1928 // msg->MinMaxInfo->MinWidth,
1929 // msg->MinMaxInfo->MinHeight,
1930 // msg->MinMaxInfo->DefWidth,
1931 // msg->MinMaxInfo->DefHeight,
1932 // msg->MinMaxInfo->MaxWidth,
1933 // msg->MinMaxInfo->MaxHeight);
1942 // enforce minmax constraint, but also update total growable/shrinkable weights
1943 // while we're at it
1944 static void Layout1D_minmax_constraint(WORD
*sizep
, WORD minsize
,
1945 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
1946 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
, WORD samesize
)
1948 WORD size
= *sizep
, remain
= *remainp
,
1949 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
1950 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
1952 /* D(bug("L1D_minmax_c size=%d min=%d max=%d w=%d ss=%d\n", */
1953 /* size, minsize, maxsize, */
1954 /* weight, samesize)); */
1956 if ((samesize
> 0) && (weight
== 0))
1958 remain
+= size
- samesize
;
1964 if (size
<= minsize
) // too little
1966 remain
+= size
- minsize
;
1969 if (size
== maxsize
)
1972 else if (size
>= maxsize
) // too big
1974 remain
+= size
- maxsize
;
1979 if (!((samesize
> 0) && (weight
== 0)))
1982 weightgrow
+= weight
;
1984 weightshrink
+= weight
;
1989 *sizegrowp
= sizegrow
;
1990 *sizeshrinkp
= sizeshrink
;
1991 *weightgrowp
= weightgrow
;
1992 *weightshrinkp
= weightshrink
;
1996 // redistribute excess size to growable child, or reduce size of a shrinkable
1998 static void Layout1D_redistribution(WORD
*sizep
, WORD minsize
,
1999 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
2000 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
)
2002 WORD size
= *sizep
, remain
= *remainp
,
2003 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
2004 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
2009 if ((remain
> 0) && (size
< maxsize
))
2013 newsize
= (sizegrow
* weight
+ weightgrow
/ 2) / weightgrow
;
2015 /* D(bug("newsize=%ld == size_growa=%ld * w=%ld / weight_grow=%d\n", */
2016 /* newsize, sizegrow, weight, weightgrow)); */
2018 /* take care of off-by-1 errors that may toggle remainder sign
2019 * by ensuring convergence to 0
2021 if (remain
- newsize
+ size
< 0)
2023 /* D(bug("adding remainder=%d => size = %d\n", */
2024 /* remain, size + remain)); */
2030 remain
-= newsize
- size
;
2033 weightgrow
-= weight
;
2036 else if ((remain
< 0) && (size
> minsize
))
2040 newsize
= (sizeshrink
* weight
+ weightshrink
/ 2) / weightshrink
;
2042 /* D(bug("newsize=%ld == size_shrinkables=%ld * w=%ld " */
2043 /* "/ weight_shrinkables=%d\n", */
2044 /* newsize, sizeshrink, weight, weightshrink)); */
2046 if (remain
- newsize
+ size
> 0)
2048 /* D(bug("adding remainder=%d => size = %d\n", */
2049 /* remain, size + remain)); */
2055 remain
-= newsize
- size
;
2058 weightshrink
-= weight
;
2064 *sizegrowp
= sizegrow
;
2065 *sizeshrinkp
= sizeshrink
;
2066 *weightgrowp
= weightgrow
;
2067 *weightshrinkp
= weightshrink
;
2071 // 2 passes at most, less on average (0.5 or 1.5), each does
2072 // - a minmax clamping, evenutally adding to a remainder
2073 // (remainder = missing (underflow) or remaining (overflow) space compared
2074 // to ideal sizes where children fill the whole group)
2075 // - a redistribution of the remainder, by growing (pos. remainder) or
2076 // shrinking (neg. remainder) children able to support it.
2078 // Occasionnaly the first time the redistribution is done, the minmax
2079 // constraint can be broken, thus the extra pass to check and eventually
2080 // redistribute. The second redistribution never breaks minmax constraint
2081 // (there should be a mathematical proof, but feel free to prove me wrong
2083 static void Layout1D_minmax_constraints_and_redistrib(struct MinList
2084 *children
, WORD total_size
, WORD remainder
, WORD samesize
,
2091 for (i
= 0; i
< 2; i
++)
2093 WORD size_growables
= total_size
;
2094 WORD size_shrinkables
= total_size
;
2095 ULONG weight_growables
= 0;
2096 ULONG weight_shrinkables
= 0;
2098 /* D(bug("start : rem=%ld, A=%ld, size_growables=%ld, " */
2099 /* "size_shrinkables=%ld\n", */
2100 /* remainder, total_size, size_growables, size_shrinkables)); */
2102 // minmax constraints
2103 cstate
= (Object
*) children
->mlh_Head
;
2104 while ((child
= NextObject(&cstate
)))
2106 /* WORD old_size; */
2108 if (IS_HIDDEN(child
))
2113 /* old_size = _width(child); */
2115 Layout1D_minmax_constraint(&_width(child
), _minwidth(child
),
2116 _maxwidth(child
), &remainder
, &size_growables
,
2117 &size_shrinkables
, &weight_growables
,
2118 &weight_shrinkables
, _hweight(child
), samesize
);
2120 /* D(bug("loop1 on %p : width=%d was %d, rem=%d, A=%d, " */
2121 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2122 /* child, _width(child), old_size, remainder, total_size, */
2123 /* size_growables, size_shrinkables, _hweight(child), */
2124 /* _minwidth(child), _maxwidth(child))); */
2126 else // ! group_horiz
2128 /* old_size = _height(child); */
2130 Layout1D_minmax_constraint(&_height(child
),
2131 _minheight(child
), _maxheight(child
), &remainder
,
2132 &size_growables
, &size_shrinkables
, &weight_growables
,
2133 &weight_shrinkables
, _vweight(child
), samesize
);
2135 /* D(bug("loop1 on %p : h=%ld was %d, rem=%d, A=%d, " */
2136 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2137 /* child, _height(child), old_size, remainder, total_size,*/
2138 /* size_growables, size_shrinkables, _vweight(child), */
2139 /* _minheight(child), _maxheight(child))); */
2140 } // if (group_horiz)
2141 } // while child, minmax constraints
2147 /* D(bug("mid : rem=%d, A=%d, size_grow=%d, size_shrink=%d, " */
2148 /* "wg=%ld, ws=%ld\n", remainder, total_size, size_growables, */
2149 /* size_shrinkables, weight_growables, weight_shrinkables)); */
2151 // distribute remaining space to possible candidates
2152 cstate
= (Object
*) children
->mlh_Head
;
2153 while (((child
= NextObject(&cstate
)) != NULL
) && (remainder
!= 0))
2155 /* WORD old_size; */
2157 if (IS_HIDDEN(child
))
2162 /* old_size = _width(child); */
2164 Layout1D_redistribution(&_width(child
), _minwidth(child
),
2165 _maxwidth(child
), &remainder
, &size_growables
,
2166 &size_shrinkables
, &weight_growables
,
2167 &weight_shrinkables
, _hweight(child
));
2169 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2170 /* "size_grow=%d, size_shrink=%d\n", child, */
2171 /* _width(child), old_size, remainder, total_size, */
2172 /* size_growables, size_shrinkables)); */
2174 else // ! group_horiz
2176 /* old_size = _height(child); */
2178 Layout1D_redistribution(&_height(child
), _minheight(child
),
2179 _maxheight(child
), &remainder
, &size_growables
,
2180 &size_shrinkables
, &weight_growables
,
2181 &weight_shrinkables
, _vweight(child
));
2183 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2184 /* "size_grow=%d, size_shrink=%d\n", child, */
2185 /* _height(child), old_size, remainder, total_size, */
2186 /* size_growables, size_shrinkables)); */
2187 } // if (group_horiz)
2189 } // while child, redistribution
2191 /* if (remainder != 0) */
2193 /* D(bug("end : rem=%ld, A=%ld, size_grow=%ld, size_shrink=%ld\n", */
2194 /* remainder, total_size, size_growables, size_shrinkables)); */
2196 // dont break here if remainder == 0, some minmax constraints
2197 // may not be respected
2200 // to easily spot layout bugs, nothing like a (division by zero) exception
2201 /* if (remainder != 0) */
2203 /* ASSERT(remainder != 0); */
2204 /* D(bug("gonna crash, remainder = %d\n", remainder)); */
2205 /* remainder /= 0; */
2210 static void Layout1D_weight_constraint(WORD
*total_sizep
,
2211 WORD
*total_init_sizep
,
2212 ULONG
*total_weightp
, WORD
*sizep
, UWORD weight
, WORD minsize
)
2214 if (*total_weightp
> 0)
2215 *sizep
= (*total_sizep
* weight
+ *total_weightp
/ 2)
2220 *total_weightp
-= weight
;
2221 *total_sizep
-= *sizep
;
2222 *total_init_sizep
+= *sizep
;
2226 static void group_layout_vert(struct IClass
*cl
, Object
*obj
,
2227 struct MinList
*children
)
2229 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2233 WORD remainder
; /* must converge to 0 to successfully end layout */
2235 WORD total_size_backup
;
2236 WORD total_init_size
; /* total size of the ideally sized children */
2243 //kprintf("group_layout_vert: virtoff = %d,%d\n",
2244 // data->virt_offx, data->virt_offy);
2246 if (data
->flags
& GROUP_VIRTUAL
)
2249 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2250 _maxwidth(obj
) - _subwidth(obj
));
2251 data
->virt_mheight
=
2252 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2253 _maxheight(obj
) - _subheight(obj
));
2255 layout_width
= data
->virt_mwidth
;
2256 layout_height
= data
->virt_mheight
;
2260 layout_width
= _mwidth(obj
);
2261 layout_height
= _mheight(obj
);
2264 total_weight
= data
->vert_weight_sum
;
2265 total_init_size
= 0;
2267 layout_height
- (data
->num_visible_children
-
2268 1) * data
->vert_spacing
;
2269 total_size_backup
= total_size
;
2271 /* D(bug("\nvert layout for %p, A=%d W=%ld\n", */
2272 /* obj, total_size, total_weight)); */
2274 // weight constraints
2275 // calculate ideal size for each object, and total ideal size
2276 cstate
= (Object
*) children
->mlh_Head
;
2277 while ((child
= NextObject(&cstate
)))
2279 if (IS_HIDDEN(child
))
2282 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2283 &total_weight
, &_height(child
), _vweight(child
),
2285 /* D(bug("child %p : ideal=%d w=%ld\n", */
2286 /* child, _height(child), _vweight(child))); */
2287 } // while child, weight constraints
2289 total_size
= total_size_backup
;
2290 remainder
= total_size
- total_init_size
;
2292 if (data
->flags
& GROUP_VIRTUAL
)
2294 /* This is also true for non virtual groups, but if this would be the
2295 ** case then there is a bug in the layout function
2301 Layout1D_minmax_constraints_and_redistrib(children
,
2304 (data
->flags
& GROUP_SAME_HEIGHT
) ? data
->samesize_maxmin_vert
: 0,
2308 cstate
= (Object
*) children
->mlh_Head
;
2309 while ((child
= NextObject(&cstate
)))
2311 if (IS_HIDDEN(child
))
2314 width
= MIN(_maxwidth(child
), layout_width
);
2315 width
= MAX(width
, _minwidth(child
));
2316 left
= (layout_width
- width
) / 2;
2318 /* D(bug("child %p -> layout %d x %d\n", */
2319 /* child, width, _height(child))); */
2320 if (!MUI_Layout(child
, left
, top
, width
, _height(child
), 0))
2322 top
+= data
->vert_spacing
+ _height(child
);
2328 static void group_layout_horiz(struct IClass
*cl
, Object
*obj
,
2329 struct MinList
*children
)
2331 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2335 WORD remainder
; /* must converge to 0 to successfully end layout */
2337 WORD total_size_backup
;
2338 WORD total_init_size
; /* total size of the ideally sized children */
2345 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2346 // data->virt_offx, data->virt_offy);
2348 if (data
->flags
& GROUP_VIRTUAL
)
2351 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2352 _maxwidth(obj
) - _subwidth(obj
));
2353 data
->virt_mheight
=
2354 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2355 _maxheight(obj
) - _subheight(obj
));
2357 layout_width
= data
->virt_mwidth
;
2358 layout_height
= data
->virt_mheight
;
2360 //kprintf("group_layout_horiz: layoutsize %d x %d "
2361 // " virtsize %d x %d msize %d x %d\n",
2362 // layout_width, layout_height, data->virt_mwidth,
2363 // data->virt_mheight,
2364 // _mwidth(obj), _mheight(obj));
2368 layout_width
= _mwidth(obj
);
2369 layout_height
= _mheight(obj
);
2372 total_weight
= data
->horiz_weight_sum
;
2373 total_init_size
= 0;
2375 layout_width
- (data
->num_visible_children
-
2376 1) * data
->horiz_spacing
;
2377 total_size_backup
= total_size
;
2379 /* D(bug("\nhoriz layout for %p, A=%d W=%ld\n", */
2380 /* obj, total_size, total_weight)); */
2382 // weight constraints
2383 // calculate ideal size for each object, and total ideal size
2384 cstate
= (Object
*) children
->mlh_Head
;
2385 while ((child
= NextObject(&cstate
)))
2387 if (IS_HIDDEN(child
))
2390 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2391 &total_weight
, &_width(child
), _hweight(child
),
2393 /* D(bug("child %p : ideal=%d w=%ld\n", */
2394 /* child, _width(child), _hweight(child))); */
2395 } // while child, weight constraints
2397 total_size
= total_size_backup
;
2398 if (data
->horiz_weight_sum
> 0)
2399 remainder
= total_size
- total_init_size
;
2403 if (data
->flags
& GROUP_VIRTUAL
)
2405 /* This is also true for non virtual groups, but if this would be the
2406 ** case then there is a bug in the layout function
2412 Layout1D_minmax_constraints_and_redistrib(children
,
2415 (data
->flags
& GROUP_SAME_WIDTH
) ? data
->samesize_maxmin_horiz
: 0,
2419 cstate
= (Object
*) children
->mlh_Head
;
2420 while ((child
= NextObject(&cstate
)))
2422 if (IS_HIDDEN(child
))
2425 height
= MIN(_maxheight(child
), layout_height
);
2426 height
= MAX(height
, _minheight(child
));
2427 top
= (layout_height
- height
) / 2;
2429 /* D(bug("child %p -> layout %d x %d\n", */
2430 /* child, _width(child), height)); */
2431 if (!MUI_Layout(child
, left
, top
, _width(child
), height
, 0))
2433 left
+= data
->horiz_spacing
+ _width(child
);
2439 static void Layout2D_weight_constraint(struct MUI_GroupData
*data
,
2440 struct layout2d_elem
*row_infos
,
2441 struct layout2d_elem
*col_infos
,
2442 WORD total_size_height
, WORD total_size_width
,
2443 WORD
*total_init_height
, WORD
*total_init_width
)
2446 ULONG total_weight_vert
= data
->vert_weight_sum
;
2447 ULONG total_weight_horiz
= data
->horiz_weight_sum
;
2449 *total_init_height
= 0;
2450 *total_init_width
= 0;
2452 /* calc row heights */
2453 for (i
= 0; i
< data
->rows
; i
++)
2455 if (total_weight_vert
> 0)
2457 (total_size_height
* row_infos
[i
].weight
+
2458 total_weight_vert
/ 2) / total_weight_vert
;
2460 row_infos
[i
].dim
= row_infos
[i
].min
;
2462 /* D(bug("l2 row %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2463 /* i, row_infos[i].dim, */
2464 /* row_infos[i].weight, total_size_height, total_weight_vert)); */
2466 total_weight_vert
-= row_infos
[i
].weight
;
2467 total_size_height
-= row_infos
[i
].dim
;
2468 *total_init_height
+= row_infos
[i
].dim
;
2471 /* calc columns widths */
2472 for (i
= 0; i
< data
->columns
; i
++)
2474 if (total_weight_horiz
)
2476 (total_size_width
* col_infos
[i
].weight
+
2477 total_weight_horiz
/ 2) / total_weight_horiz
;
2479 col_infos
[i
].dim
= col_infos
[i
].min
;
2481 /* D(bug("l2 col %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2482 /* i, col_infos[i].dim, */
2483 /* col_infos[i].weight, total_size_width, total_weight_horiz)); */
2485 total_weight_horiz
-= col_infos
[i
].weight
;
2486 total_size_width
-= col_infos
[i
].dim
;
2487 *total_init_width
+= col_infos
[i
].dim
;
2493 static void Layout2D_minmax_constraints_and_redistrib(struct layout2d_elem
2494 *infos
, WORD nitems
, WORD total_size
, WORD samesize
, WORD remainder
)
2498 /* D(bug("L2D mc&r n=%d A=%d ss=%d rem=%d\n", */
2499 /* nitems, total_size, samesize, remainder)); */
2501 for (j
= 0; j
< 2; j
++)
2503 WORD size_growables
= total_size
;
2504 WORD size_shrinkables
= total_size
;
2505 ULONG weight_growables
= 0;
2506 ULONG weight_shrinkables
= 0;
2507 /* WORD old_size; */
2510 // minmax constraints
2511 for (i
= 0; i
< nitems
; i
++)
2513 /* old_size = infos[i].dim; */
2515 /* D(bug("bef loop1 on %d : size=%d, rem=%d, A=%d, " */
2516 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2517 /* i, infos[i].dim, remainder, total_size, */
2518 /* size_growables, size_shrinkables, infos[i].weight, */
2519 /* infos[i].min, infos[i].max)); */
2521 Layout1D_minmax_constraint(&infos
[i
].dim
, infos
[i
].min
,
2522 infos
[i
].max
, &remainder
, &size_growables
,
2523 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2524 infos
[i
].weight
, samesize
);
2526 /* D(bug("loop1 on %d : size=%d was %d, rem=%d, A=%d, " */
2527 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2528 /* i, infos[i].dim, old_size, remainder, total_size, */
2529 /* size_growables, size_shrinkables, infos[i].weight, */
2530 /* infos[i].min, infos[i].max)); */
2536 for (i
= 0; i
< nitems
; i
++)
2538 /* old_size = infos[i].dim; */
2540 /* D(bug("bef loop2 on %d : size=%d, rem=%d, A=%d, " */
2541 /* "size_grow=%d, size_shrink=%d\n", i, */
2542 /* infos[i].dim, remainder, total_size, */
2543 /* size_growables, size_shrinkables)); */
2545 Layout1D_redistribution(&infos
[i
].dim
, infos
[i
].min
,
2546 infos
[i
].max
, &remainder
, &size_growables
,
2547 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2550 /* D(bug("loop2 on %d : size=%d was %d, rem=%d, A=%d, " */
2551 /* "size_grow=%d, size_shrink=%d\n", i, */
2552 /* infos[i].dim, old_size, remainder, total_size, */
2553 /* size_growables, size_shrinkables)); */
2559 layout_2d_distribute_space(struct MUI_GroupData
*data
,
2560 struct layout2d_elem
*row_infos
,
2561 struct layout2d_elem
*col_infos
,
2562 struct MinList
*children
, LONG left_start
, LONG top_start
)
2573 * pass 2 : distribute space
2575 cstate
= (Object
*) children
->mlh_Head
;
2578 for (i
= 0; i
< data
->rows
; i
++)
2580 /* left start for child layout in this row */
2583 /* max height for children in this row */
2584 row_height
= row_infos
[i
].dim
;
2586 /* for each column */
2587 while ((child
= NextObject(&cstate
)))
2594 if (IS_HIDDEN(child
))
2596 /* max width for children in this column */
2597 col_width
= col_infos
[j
].dim
;
2599 /* center child if col width is bigger than child maxwidth */
2600 cwidth
= MIN(_maxwidth(child
), col_width
);
2601 cwidth
= MAX(cwidth
, _minwidth(child
));
2602 cleft
= left
+ (col_width
- cwidth
) / 2;
2604 /* center child if row height is bigger than child maxheight */
2605 cheight
= MIN(_maxheight(child
), row_height
);
2606 cheight
= MAX(cheight
, _minheight(child
));
2607 ctop
= top
+ (row_height
- cheight
) / 2;
2609 /* g_print("layout %d %d %d %d\n", cleft, ctop, cwidth, cheight); */
2610 /* D(bug("2DL/child %p -> layout %d x %d\n", */
2611 /* child, cwidth, cheight)); */
2612 if (!MUI_Layout(child
, cleft
, ctop
, cwidth
, cheight
, 0))
2615 left
+= data
->horiz_spacing
+ col_width
;
2618 if ((j
% data
->columns
) == 0)
2622 top
+= data
->vert_spacing
+ row_height
;
2629 * all children in the same row have the same maximum height
2630 * all children in the same column have the same maximum height
2631 * if a child maximum size is smaller than the biggest minimum size,
2632 * the chid will be centered in the remaining space.
2634 * for each row, determine its height allocation
2635 * weight ? the vertical weight of a row, if no fixed-height child
2636 * in the row, is the sum of all vertical weights of children
2637 * all row members will have the same height
2639 * for each column, determine its width allocation
2640 * all column members will have the same width
2642 /* Write a proper hook function */
2644 group_layout_2d(struct IClass
*cl
, Object
*obj
, struct MinList
*children
)
2646 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2647 WORD left_start
= 0;
2649 WORD total_size_height
=
2650 _mheight(obj
) - (data
->rows
- 1) * data
->vert_spacing
;
2651 WORD total_size_width
=
2652 _mwidth(obj
) - (data
->columns
- 1) * data
->horiz_spacing
;
2653 WORD total_init_height
;
2654 WORD total_init_width
;
2655 WORD remainder_height
;
2656 WORD remainder_width
;
2660 if (data
->rows
== 0 || data
->columns
== 0)
2662 if (data
->num_children
% data
->rows
2663 || data
->num_children
% data
->columns
)
2665 if (data
->row_infos
== NULL
|| data
->col_infos
== NULL
)
2668 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2669 // data->virt_offx, data->virt_offy);
2671 if (data
->flags
& GROUP_VIRTUAL
)
2674 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2675 _maxwidth(obj
) - _subwidth(obj
));
2676 data
->virt_mheight
=
2677 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2678 _maxheight(obj
) - _subheight(obj
));
2680 layout_width
= data
->virt_mwidth
;
2681 layout_height
= data
->virt_mheight
;
2685 layout_width
= _mwidth(obj
);
2686 layout_height
= _mheight(obj
);
2690 layout_height
- (data
->rows
- 1) * data
->vert_spacing
;
2692 layout_width
- (data
->columns
- 1) * data
->horiz_spacing
;
2696 // weight constraints
2697 Layout2D_weight_constraint(data
, data
->row_infos
, data
->col_infos
,
2698 total_size_height
, total_size_width
,
2699 &total_init_height
, &total_init_width
);
2701 remainder_height
= total_size_height
- total_init_height
;
2702 remainder_width
= total_size_width
- total_init_width
;
2704 Layout2D_minmax_constraints_and_redistrib(data
->row_infos
,
2705 data
->rows
, total_size_height
,
2706 /* (data->flags & GROUP_SAME_HEIGHT) ? data->samesize_maxmin_vert : 0, */
2707 0, remainder_height
);
2709 Layout2D_minmax_constraints_and_redistrib(data
->col_infos
,
2710 data
->columns
, total_size_width
,
2711 /* (data->flags & GROUP_SAME_WIDTH) ? data->samesize_maxmin_horiz : 0, */
2712 0, remainder_width
);
2714 layout_2d_distribute_space(data
, data
->row_infos
, data
->col_infos
,
2715 children
, left_start
, top_start
);
2719 /* Write a proper hook function */
2720 static void group_layout_pagemode(struct IClass
*cl
, Object
*obj
,
2721 struct MinList
*children
)
2723 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2728 int w
, h
, yoffset
= 0;
2730 if (data
->flags
& GROUP_VIRTUAL
)
2733 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2734 _maxwidth(obj
) - _subwidth(obj
));
2735 data
->virt_mheight
=
2736 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2737 _maxheight(obj
) - _subheight(obj
));
2739 layout_width
= data
->virt_mwidth
;
2740 layout_height
= data
->virt_mheight
;
2744 layout_width
= _mwidth(obj
);
2745 layout_height
= _mheight(obj
);
2748 if (data
->titlegroup
)
2750 yoffset
= _minheight(data
->titlegroup
);
2751 layout_height
-= yoffset
;
2754 cstate
= (Object
*) children
->mlh_Head
;
2755 while ((child
= NextObject(&cstate
)))
2757 w
= MIN(layout_width
, _maxwidth(child
));
2758 h
= MIN(layout_height
, _maxheight(child
));
2760 if (child
== data
->titlegroup
)
2762 MUI_Layout(child
, (layout_width
- w
) / 2, 0, w
, yoffset
, 0);
2766 D(bug("PM/child %p -> layout %d x %d\n", child
, w
, h
));
2767 MUI_Layout(child
, (layout_width
- w
) / 2,
2768 yoffset
+ (layout_height
- h
) / 2, w
, h
, 0);
2774 /**************************************************************************
2776 Either use a given layout hook, or the builtin method.
2777 **************************************************************************/
2778 IPTR
Group__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
2779 struct MUIP_Layout
*msg
)
2781 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2782 struct MUI_LayoutMsg lm
= { 0 };
2784 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
2785 if (data
->flags
& GROUP_PAGEMODE
)
2787 group_layout_pagemode(cl
, obj
, lm
.lm_Children
);
2789 else if (data
->layout_hook
)
2791 lm
.lm_Type
= MUILM_LAYOUT
;
2792 lm
.lm_Layout
.Width
= _mwidth(obj
);
2793 lm
.lm_Layout
.Height
= _mheight(obj
);
2795 CallHookPkt(data
->layout_hook
, obj
, &lm
);
2797 if (data
->flags
& GROUP_VIRTUAL
)
2799 data
->virt_mwidth
= lm
.lm_Layout
.Width
;
2800 data
->virt_mheight
= lm
.lm_Layout
.Height
;
2805 if ((data
->rows
== 1) && (data
->columns
== 1))
2807 if (data
->flags
& GROUP_HORIZ
)
2808 group_layout_horiz(cl
, obj
, lm
.lm_Children
);
2810 group_layout_vert(cl
, obj
, lm
.lm_Children
);
2813 group_layout_2d(cl
, obj
, lm
.lm_Children
);
2816 if (data
->flags
& GROUP_VIRTUAL
)
2818 WORD new_virt_offx
, new_virt_offy
;
2820 new_virt_offx
= data
->virt_offx
;
2821 new_virt_offy
= data
->virt_offy
;
2823 if (new_virt_offx
+ _mwidth(obj
) > data
->virt_mwidth
)
2825 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
2827 if (new_virt_offx
< 0)
2830 if (new_virt_offy
+ _mheight(obj
) > data
->virt_mheight
)
2832 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
2834 if (new_virt_offy
< 0)
2837 if (new_virt_offx
!= data
->virt_offx
)
2839 nfset(obj
, MUIA_Virtgroup_Left
, new_virt_offx
);
2842 if (new_virt_offy
!= data
->virt_offy
)
2844 nfset(obj
, MUIA_Virtgroup_Top
, new_virt_offy
);
2852 /**************************************************************************
2854 **************************************************************************/
2855 IPTR
Group__MUIM_Show(struct IClass
*cl
, Object
*obj
,
2856 struct MUIP_Show
*msg
)
2858 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2861 struct MinList
*ChildList
= NULL
;
2863 /* If msg is NULL, we won't want that the super method actually gets
2866 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2868 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2869 cstate
= (Object
*) ChildList
->mlh_Head
;
2871 if (data
->flags
& GROUP_PAGEMODE
)
2874 while ((child
= NextObject(&cstate
)))
2876 if (child
== data
->titlegroup
)
2878 DoShowMethod(child
);
2879 continue; /* Title group is not counted as page */
2882 if (page
== data
->active_page
)
2884 DoShowMethod(child
);
2892 while ((child
= NextObject(&cstate
)))
2894 if (!(data
->flags
& GROUP_VIRTUAL
) ||
2895 IsObjectVisible(child
, MUIMasterBase
))
2897 if (_flags(child
) & MADF_SHOWME
)
2898 DoShowMethod(child
);
2905 /**************************************************************************
2907 **************************************************************************/
2908 IPTR
Group__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
2909 struct MUIP_Hide
*msg
)
2911 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2914 struct MinList
*ChildList
= NULL
;
2916 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2917 cstate
= (Object
*) ChildList
->mlh_Head
;
2919 if (data
->flags
& GROUP_PAGEMODE
)
2922 while ((child
= NextObject(&cstate
)))
2924 if (child
== data
->titlegroup
)
2926 DoHideMethod(child
);
2927 continue; /* Title group is not counted as page */
2930 if (page
== data
->active_page
)
2932 DoHideMethod(child
);
2940 while ((child
= NextObject(&cstate
)))
2942 if (_flags(child
) & MADF_CANDRAW
)
2943 DoHideMethod(child
);
2947 /* If msg is NULL, we won't want that the super method actually gets
2950 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2955 * MUIM_FindUData : tests if the MUIA_UserData of the object
2956 * contains the given <udata> and returns the object pointer in this case.
2958 IPTR
Group__MUIM_FindUData(struct IClass
*cl
, Object
*obj
,
2959 struct MUIP_FindUData
*msg
)
2961 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2963 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2966 return DoMethodA(data
->family
, (Msg
) msg
);
2971 * MUIM_GetUData : This method tests if the MUIA_UserData of the object
2972 * contains the given <udata> and gets <attr> to <storage> for itself
2975 IPTR
Group__MUIM_GetUData(struct IClass
*cl
, Object
*obj
,
2976 struct MUIP_GetUData
*msg
)
2978 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2980 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2982 get(obj
, msg
->attr
, msg
->storage
);
2986 return DoMethodA(data
->family
, (Msg
) msg
);
2991 * MUIM_SetUData : This method tests if the MUIA_UserData of the object
2992 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2994 IPTR
Group__MUIM_SetUData(struct IClass
*cl
, Object
*obj
,
2995 struct MUIP_SetUData
*msg
)
2997 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2999 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
3000 set(obj
, msg
->attr
, msg
->val
);
3002 DoMethodA(data
->family
, (Msg
) msg
);
3008 * MUIM_SetUDataOnce : This method tests if the MUIA_UserData of the object
3009 * contains the given <udata> and sets <attr> to <val> for itself in this case.
3010 * Stop after the first udata found.
3012 IPTR
Group__MUIM_SetUDataOnce(struct IClass
*cl
, Object
*obj
,
3013 struct MUIP_SetUData
*msg
)
3015 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3017 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
3019 set(obj
, msg
->attr
, msg
->val
);
3022 return DoMethodA(data
->family
, (Msg
) msg
);
3025 /**************************************************************************
3026 MUIM_DragQueryExtented
3027 **************************************************************************/
3028 IPTR
Group__MUIM_DragQueryExtended(struct IClass
*cl
, Object
*obj
,
3029 struct MUIP_DragQueryExtended
*msg
)
3031 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3035 struct MinList
*ChildList
= NULL
;
3037 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3038 cstate
= (Object
*) ChildList
->mlh_Head
;
3039 while ((child
= NextObject(&cstate
)))
3041 if (!(_flags(child
) & MADF_CANDRAW
))
3044 if ((found_obj
= (Object
*) DoMethodA(child
, (Msg
) msg
)))
3045 return (IPTR
) found_obj
;
3047 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3050 /**************************************************************************
3052 **************************************************************************/
3053 IPTR
Group__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
3054 struct MUIP_HandleEvent
*msg
)
3056 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3058 /* check this, otherwise a superclass who has IDCMP_MOUSEBUTTONS
3059 eventhandler might call DoSuperMethod, and this function gets
3060 called even when he have not added any eventhandler */
3062 if ((data
->flags
& GROUP_VIRTUAL
) && msg
->imsg
)
3064 switch (msg
->imsg
->Class
)
3066 case IDCMP_MOUSEBUTTONS
:
3067 /* For virtual groups */
3068 if (msg
->imsg
->Code
== SELECTDOWN
)
3070 if (_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
3071 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
3074 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3075 (IPTR
) & data
->ehn
);
3076 data
->ehn
.ehn_Events
|= IDCMP_INTUITICKS
;
3077 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3078 (IPTR
) & data
->ehn
);
3083 if (data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
)
3085 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3086 (IPTR
) & data
->ehn
);
3087 data
->ehn
.ehn_Events
&= ~IDCMP_INTUITICKS
;
3088 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3089 (IPTR
) & data
->ehn
);
3094 case IDCMP_INTUITICKS
:
3095 if (!(data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
))
3098 if (!(_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
3099 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
3102 LONG new_virt_offx
= data
->virt_offx
;
3103 LONG new_virt_offy
= data
->virt_offy
;
3105 if (msg
->imsg
->MouseX
< _mleft(obj
))
3108 if (new_virt_offx
>= 4)
3113 else if (msg
->imsg
->MouseX
> _mright(obj
))
3117 if (new_virt_offx
> data
->virt_mwidth
- _mwidth(obj
))
3118 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
3119 if (new_virt_offx
< 0)
3123 if (msg
->imsg
->MouseY
< _mtop(obj
))
3126 if (new_virt_offy
>= 4)
3131 else if (msg
->imsg
->MouseY
> _mbottom(obj
))
3135 if (new_virt_offy
> data
->virt_mheight
- _mheight(obj
))
3136 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
3137 if (new_virt_offy
< 0)
3141 if (new_virt_offx
!= data
->virt_offx
3142 || new_virt_offy
!= data
->virt_offy
)
3145 MUIA_Virtgroup_Left
, new_virt_offx
,
3146 MUIA_Virtgroup_Top
, new_virt_offy
,
3147 MUIA_Group_Forward
, FALSE
, TAG_DONE
);
3157 /**************************************************************************
3159 **************************************************************************/
3160 IPTR
Group__MUIM_DrawBackground(struct IClass
*cl
, Object
*obj
,
3161 struct MUIP_DrawBackground
*msg
)
3163 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3165 if (data
->flags
& GROUP_VIRTUAL
)
3167 struct MUIP_DrawBackground msg2
= *msg
;
3169 msg2
.xoffset
+= data
->virt_offx
;
3170 msg2
.yoffset
+= data
->virt_offy
;
3172 return DoSuperMethodA(cl
, obj
, (Msg
) & msg2
);
3175 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3178 /**************************************************************************
3180 Find the given object or return NULL
3181 **************************************************************************/
3182 IPTR
Group__MUIM_FindAreaObject(struct IClass
*cl
, Object
*obj
,
3183 struct MUIP_FindAreaObject
*msg
)
3185 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3188 struct MinList
*ChildList
= NULL
;
3191 if (msg
->obj
== obj
)
3194 // it's one of my children ?
3195 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3196 cstate
= (Object
*) ChildList
->mlh_Head
;
3197 while ((child
= NextObject(&cstate
)))
3199 if (msg
->obj
== child
)
3200 return (IPTR
) child
;
3203 // let the children find it
3204 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3205 cstate
= (Object
*) ChildList
->mlh_Head
;
3206 while ((child
= NextObject(&cstate
)))
3208 Object
*res
= (Object
*) DoMethodA(child
, (Msg
) msg
);
3216 /**************************************************************************
3217 MUIM_Export : to export an object's "contents" to a dataspace object.
3218 **************************************************************************/
3219 static IPTR
Group__MUIM_Export(struct IClass
*cl
, Object
*obj
,
3220 struct MUIP_Export
*msg
)
3222 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3225 struct MinList
*ChildList
= NULL
;
3227 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3231 cstate
= (Object
*) ChildList
->mlh_Head
;
3232 while ((child
= NextObject(&cstate
)))
3234 DoMethodA(child
, (Msg
) msg
);
3241 /**************************************************************************
3242 MUIM_Import : to import an object's "contents" from a dataspace object.
3243 **************************************************************************/
3244 static IPTR
Group__MUIM_Import(struct IClass
*cl
, Object
*obj
,
3245 struct MUIP_Import
*msg
)
3247 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3250 struct MinList
*ChildList
= NULL
;
3252 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3256 cstate
= (Object
*) ChildList
->mlh_Head
;
3257 while ((child
= NextObject(&cstate
)))
3259 DoMethodA(child
, (Msg
) msg
);
3265 /**************************************************************************
3266 MUIM_Notify - disabled now because previous Zune versions had a OM_GET
3267 check in MUIM_Notify which is no longer the case
3268 **************************************************************************/
3270 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3271 struct MUIP_Notify
*msg
)
3273 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3276 struct MinList
*ChildList
;
3278 /* Try at first if understand the message our self
3279 ** We disable the forwarding of the OM_GET message
3280 ** as the MUIM_Notify otherwise would "think" that
3281 ** the group class actually understands the attribute
3282 ** although a child does this only
3284 data
->dont_forward_get
= 1;
3285 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
3287 data
->dont_forward_get
= 0;
3291 /* We ourselves didn't understand the notify tag so we try the
3293 data
->dont_forward_get
= 0;
3295 get(data
->family
, MUIA_Family_List
, (IPTR
*) & (ChildList
));
3296 cstate
= (Object
*) ChildList
->mlh_Head
;
3297 while ((child
= NextObject(&cstate
)))
3299 if (DoMethodA(child
, (Msg
) msg
))
3307 /* Notes about Group_Notify() and echo notification problem:
3308 It was discovered that MUI seems to have some special handling for group class
3309 which will drop notifications on the children which are found to not
3310 understand the attribute.
3312 This is done by checking if an OM_GET on the child returns TRUE.
3313 There's a little problem here because it is not known how big the storage
3314 needed for the attribute in question will be. Almost no class uses anything
3315 bigger than one IPTR. For "big" attributes those return a pointer to the data,
3316 not the data itself. Unfortuntely there are some exceptions like colorwheel
3317 class which does not return a pointer, but the data itself. So it's not
3318 enough to use one single IPTR variable (4 Bytes on 32bit machines, 8 bytes
3319 on 64 bit machines) to store the result of the test-OM_Get.
3321 There is no general way to query the size needed so if one wants to change
3322 Zune to work like MUI one needs to choose a size which one hopes will be
3323 big enough to hold all possible attributes of all classes, old, present
3326 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3327 struct MUIP_Notify
*msg
)
3329 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3332 struct MinList
*ChildList
= NULL
;
3335 data
->dont_forward_get
= 1;
3337 if (GetAttr(msg
->TrigAttr
, obj
, attr
))
3339 data
->dont_forward_get
= 0;
3340 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3342 data
->dont_forward_get
= 0;
3344 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3348 cstate
= (Object
*) ChildList
->mlh_Head
;
3349 while ((child
= NextObject(&cstate
)))
3352 if (GetAttr(msg
->TrigAttr
, child
, attr
))
3354 DoMethodA(child
, (Msg
) msg
);
3355 /* No return here! */
3362 BOOPSI_DISPATCHER(IPTR
, Group_Dispatcher
, cl
, obj
, msg
)
3364 switch (msg
->MethodID
)
3367 return Group__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3369 return Group__OM_DISPOSE(cl
, obj
, msg
);
3371 return Group__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3373 return Group__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3374 case OM_ADDMEMBER
: /* Fall through */
3375 case MUIM_Group_AddTail
:
3376 return Group__MUIM_AddTail(cl
, obj
, (APTR
) msg
);
3377 case MUIM_Group_AddHead
:
3378 return Group__MUIM_AddHead(cl
, obj
, (APTR
) msg
);
3379 case MUIM_Group_Insert
:
3380 return Group__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3381 case OM_REMMEMBER
: /* Fall through */
3382 case MUIM_Group_Remove
:
3383 return Group__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3384 case MUIM_Family_GetChild
:
3385 return Group__MUIM_Family_GetChild(cl
, obj
, (APTR
) msg
);
3386 case MUIM_AskMinMax
:
3387 return Group__MUIM_AskMinMax(cl
, obj
, (APTR
) msg
);
3388 case MUIM_Group_ExitChange
:
3389 return Group__MUIM_ExitChange(cl
, obj
, (APTR
) msg
);
3390 case MUIM_Group_ExitChange2
:
3391 return Group__MUIM_ExitChange2(cl
, obj
, (APTR
) msg
);
3392 case MUIM_Group_InitChange
:
3393 return Group__MUIM_InitChange(cl
, obj
, (APTR
) msg
);
3394 case MUIM_Group_Sort
:
3395 return Group__MUIM_Sort(cl
, obj
, (APTR
) msg
);
3396 case MUIM_Group_DoMethodNoForward
:
3397 return Group__MUIM_DoMethodNoForward(cl
, obj
, (APTR
) msg
);
3398 case MUIM_ConnectParent
:
3399 return Group__MUIM_ConnectParent(cl
, obj
, (APTR
) msg
);
3400 case MUIM_DisconnectParent
:
3401 return Group__MUIM_DisconnectParent(cl
, obj
, (APTR
) msg
);
3403 return Group__MUIM_Layout(cl
, obj
, (APTR
) msg
);
3405 return Group__MUIM_Setup(cl
, obj
, (APTR
) msg
);
3407 return Group__MUIM_Cleanup(cl
, obj
, (APTR
) msg
);
3409 return Group__MUIM_Draw(cl
, obj
, (APTR
) msg
);
3411 case MUIM_FindUData
:
3412 return Group__MUIM_FindUData(cl
, obj
, (APTR
) msg
);
3414 return Group__MUIM_GetUData(cl
, obj
, (APTR
) msg
);
3416 return Group__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
3417 case MUIM_SetUDataOnce
:
3418 return Group__MUIM_SetUDataOnce(cl
, obj
, (APTR
) msg
);
3420 return Group__MUIM_Show(cl
, obj
, (APTR
) msg
);
3422 return Group__MUIM_Hide(cl
, obj
, (APTR
) msg
);
3423 case MUIM_HandleEvent
:
3424 return Group__MUIM_HandleEvent(cl
, obj
, (APTR
) msg
);
3425 case MUIM_DrawBackground
:
3426 return Group__MUIM_DrawBackground(cl
, obj
, (APTR
) msg
);
3427 case MUIM_DragQueryExtended
:
3428 return Group__MUIM_DragQueryExtended(cl
, obj
, (APTR
) msg
);
3429 case MUIM_FindAreaObject
:
3430 return Group__MUIM_FindAreaObject(cl
, obj
, (APTR
) msg
);
3432 return Group__MUIM_Export(cl
, obj
, (APTR
) msg
);
3434 return Group__MUIM_Import(cl
, obj
, (APTR
) msg
);
3438 /* Disabled. See above */
3440 return Group_Notify(cl
, obj
, (APTR
) msg
);
3445 case MUIM_DrawParentBackground
:
3446 case MUIM_DragBegin
:
3448 case MUIM_DragQuery
:
3449 case MUIM_DragFinish
:
3451 case MUIM_CreateDragImage
:
3452 case MUIM_DeleteDragImage
:
3454 case MUIM_GoInactive
:
3455 case MUIM_CreateBubble
:
3456 case MUIM_DeleteBubble
:
3457 case MUIM_CreateShortHelp
:
3458 case MUIM_DeleteShortHelp
:
3461 return DoSuperMethodA(cl
, obj
, (APTR
) msg
);
3462 /* Needs not to be forwarded? */
3465 /* sometimes you want to call a superclass method,
3466 * but not dispatching to child.
3467 * But what to do with list methods in a listview ?
3469 Group_DispatchMsg(cl
, obj
, (APTR
) msg
);
3471 return DoSuperMethodA(cl
, obj
, msg
);
3473 BOOPSI_DISPATCHER_END
3478 const struct __MUIBuiltinClass _MUI_Group_desc
=
3482 sizeof(struct MUI_GroupData
),
3483 (void *) Group_Dispatcher