2 Copyright 1999, David Le Corfec.
3 Copyright 2002-2015, 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
);
745 /**************************************************************************
747 **************************************************************************/
748 IPTR
Group__MUIM_ConnectParent(struct IClass
*cl
, Object
*obj
,
749 struct MUIP_ConnectParent
*msg
)
751 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
754 struct MinList
*ChildList
= NULL
;
756 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
758 get(data
->family
, MUIA_Family_List
, &(ChildList
));
759 cstate
= (Object
*) ChildList
->mlh_Head
;
760 while ((child
= NextObject(&cstate
)))
762 if ((_flags(obj
) & MADF_INVIRTUALGROUP
)
763 || (data
->flags
& GROUP_VIRTUAL
))
765 _flags(child
) |= MADF_INVIRTUALGROUP
;
768 /* Only children of groups can have parents */
769 muiNotifyData(child
)->mnd_ParentObject
= obj
;
771 DoMethod(child
, MUIM_ConnectParent
, (IPTR
) obj
);
776 /**************************************************************************
777 MUIM_DisconnectParent
778 **************************************************************************/
779 IPTR
Group__MUIM_DisconnectParent(struct IClass
*cl
, Object
*obj
,
780 struct MUIP_ConnectParent
*msg
)
782 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
785 struct MinList
*ChildList
= NULL
;
787 get(data
->family
, MUIA_Family_List
, &(ChildList
));
788 cstate
= (Object
*) ChildList
->mlh_Head
;
789 while ((child
= NextObject(&cstate
)))
791 DoMethodA(child
, (Msg
) msg
);
792 muiNotifyData(child
)->mnd_ParentObject
= NULL
;
793 _flags(child
) &= ~MADF_INVIRTUALGROUP
;
795 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
800 * Put group in exchange state
802 IPTR
Group__MUIM_InitChange(struct IClass
*cl
, Object
*obj
,
803 struct MUIP_Group_InitChange
*msg
)
805 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
807 data
->flags
&= ~GROUP_CHANGED
;
808 data
->flags
|= GROUP_CHANGING
;
814 * Will recalculate display after dynamic adding/removing
816 IPTR
Group__MUIM_ExitChange(struct IClass
*cl
, Object
*obj
,
817 struct MUIP_Group_ExitChange
*msg
)
819 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
821 data
->flags
&= ~GROUP_CHANGING
;
824 /* Code is invalid. ExitChange needs to re-layout each time (tested
825 * with MUI 3.8 and MUI 4.0 on m68k).
826 * This is temporary change until proper implementaion is in place. */
827 if (data
->flags
& GROUP_CHANGED
)
830 data
->flags
&= ~GROUP_CHANGED
;
832 if ((_flags(obj
) & MADF_SETUP
) && _win(obj
))
834 Object
*win
= _win(obj
);
835 Object
*parent
= obj
;
837 /* CHECKME: Don't call RecalcDisplay if one of our parents is
838 in GROUP_CHANGING state to prevent crash with Zune prefs
839 program NListtree page because NList/NListtree when
840 killing tree images in MUIM_Cleanup uses InitChange/
841 ExitChange. Zune prefs program uses InitChange/ExitChange
842 when switching page -> nesting -> mess. */
844 while ((parent
= _parent(parent
)))
846 struct MUI_GroupData
*pdata
= INST_DATA(cl
, parent
);
851 if (pdata
->flags
& GROUP_CHANGING
)
858 DoMethod(win
, MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
867 * Will recalculate display after dynamic adding/removing
869 IPTR
Group__MUIM_ExitChange2(struct IClass
*cl
, Object
*obj
,
870 struct MUIP_Group_ExitChange2
*msg
)
872 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
874 if (data
->flags
& GROUP_CHANGING
)
876 data
->flags
&= ~(GROUP_CHANGING
| GROUP_CHANGED
);
878 if ((_flags(obj
) & MADF_SETUP
) && _win(obj
))
880 Object
*win
= _win(obj
);
881 Object
*parent
= obj
;
883 /* CHECKME: Don't call RecalcDisplay if one of our parents is
884 in GROUP_CHANGING state to prevent crash with Zune prefs
885 program NListtree page because NList/NListtree when
886 killing tree images in MUIM_Cleanup uses InitChange/
887 ExitChange. Zune prefs program uses InitChange/ExitChange
888 when switching page -> nesting -> mess. */
890 while ((parent
= _parent(parent
)))
892 struct MUI_GroupData
*pdata
= INST_DATA(cl
, parent
);
897 if (pdata
->flags
& GROUP_CHANGING
)
904 DoMethod(win
, MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
915 IPTR
Group__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
916 struct MUIP_Group_Sort
*msg
)
918 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
921 msg
->MethodID
= MUIM_Family_Sort
;
923 DoMethodA(data
->family
, (APTR
) msg
);
925 /* restore original message */
926 msg
->MethodID
= MUIM_Group_Sort
;
930 /**************************************************************************
931 MUIM_Group_DoMethodNoForward
933 Executes the given method but does not forward it to the children
934 **************************************************************************/
935 IPTR
Group__MUIM_DoMethodNoForward(struct IClass
*cl
, Object
*obj
,
936 struct MUIP_Group_DoMethodNoForward
*msg
)
938 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
940 data
->dont_forward_methods
= 1; /* disable forwarding */
941 rc
= DoMethodA(obj
, (Msg
) & msg
->DoMethodID
);
942 /* Probably doesn't work correctly on AROS? */
944 data
->dont_forward_methods
= 0;
949 * Propagate a method to group children.
951 static ULONG
Group_DispatchMsg(struct IClass
*cl
, Object
*obj
, Msg msg
)
953 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
956 struct MinList
*ChildList
= NULL
;
958 if (data
->dont_forward_methods
)
961 get(data
->family
, MUIA_Family_List
, &(ChildList
));
962 cstate
= (Object
*) ChildList
->mlh_Head
;
963 while ((child
= NextObject(&cstate
)))
965 DoMethodA(child
, (Msg
) msg
);
971 /**************************************************************************
973 **************************************************************************/
974 IPTR
Group__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
975 struct MUIP_Setup
*msg
)
977 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
982 struct MinList
*ChildList
= NULL
;
984 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
987 ASSERT_VALID_PTR(muiGlobalInfo(obj
));
989 if (!(data
->flags
& GROUP_HSPACING
))
990 data
->horiz_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_hspacing
;
991 if (!(data
->flags
& GROUP_VSPACING
))
992 data
->vert_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_vspacing
;
993 get(data
->family
, MUIA_Family_List
, &(ChildList
));
994 cstate
= cstate_copy
= (Object
*) ChildList
->mlh_Head
;
995 while ((child
= NextObject(&cstate
)))
997 #if 0 /* SHOWME affects only show/hide */
998 if (!(_flags(child
) & MADF_SHOWME
))
1002 if (!DoSetupMethod(child
, msg
->RenderInfo
))
1004 /* Send MUIM_Cleanup to all objects that received MUIM_Setup.
1006 childFailed
= child
;
1007 cstate
= cstate_copy
;
1008 while ((child
= NextObject(&cstate
)) && (child
!= childFailed
))
1010 #if 0 /* SHOWME affects only show/hide */
1011 if (!(_flags(child
) & MADF_SHOWME
))
1014 DoMethod(child
, MUIM_Cleanup
);
1020 if (data
->flags
& GROUP_VIRTUAL
)
1022 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
1023 (IPTR
) & data
->ehn
);
1030 /**************************************************************************
1032 **************************************************************************/
1033 IPTR
Group__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
, Msg msg
)
1035 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1038 struct MinList
*ChildList
= NULL
;
1040 if (data
->flags
& GROUP_VIRTUAL
)
1042 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
1043 (IPTR
) & data
->ehn
);
1046 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1047 cstate
= (Object
*) ChildList
->mlh_Head
;
1048 while ((child
= NextObject(&cstate
)))
1050 #if 0 /* SHOWME affects only show/hide */
1051 if (!(_flags(child
) & MADF_SHOWME
))
1054 DoMethodA(child
, (Msg
) msg
);
1056 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1059 static struct Region
*group_children_clip_region(struct IClass
*cl
,
1062 struct Region
*region
= NULL
;
1064 region
= NewRegion();
1067 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1068 struct Rectangle rect
;
1070 struct MinList
*ChildList
= NULL
;
1074 rect
.MinX
= _left(obj
);
1075 rect
.MinY
= _top(obj
);
1076 rect
.MaxX
= _right(obj
);
1077 rect
.MaxY
= _bottom(obj
);
1079 OrRectRegion(region
, &rect
);
1080 get(data
->family
, MUIA_Family_List
, &ChildList
);
1081 cstate
= (Object
*) ChildList
->mlh_Head
;
1082 while ((child
= NextObject(&cstate
)))
1084 if (child
!= data
->titlegroup
)
1087 if ((data
->flags
& GROUP_PAGEMODE
) && (page
!= data
->active_page
)
1088 && (child
!= data
->titlegroup
))
1091 if ((muiAreaData(child
)->mad_Flags
& MADF_CANDRAW
)
1092 && (_width(child
) > 0) && (_height(child
) > 0))
1094 rect
.MinX
= MAX(_left(child
), _mleft(obj
));
1095 rect
.MinY
= MAX(_top(child
), _mtop(obj
));
1096 rect
.MaxX
= MIN(_right(child
), _mright(obj
));
1097 rect
.MaxY
= MIN(_bottom(child
), _mbottom(obj
));
1099 if ((rect
.MaxX
>= rect
.MinX
) && (rect
.MaxY
>= rect
.MinY
))
1101 ClearRectRegion(region
, &rect
);
1110 /**************************************************************************
1111 MUIM_Draw - draw the group
1112 **************************************************************************/
1113 IPTR
Group__MUIM_Draw(struct IClass
*cl
, Object
*obj
,
1114 struct MUIP_Draw
*msg
)
1116 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1119 struct MinList
*ChildList
= NULL
;
1120 struct Rectangle group_rect
; /* child_rect; */
1122 struct Region
*region
= NULL
;
1123 APTR clip
= (APTR
) - 1;
1125 if (data
->flags
& GROUP_CHANGING
)
1128 if (muiGlobalInfo(obj
)->mgi_Prefs
->window_redraw
1129 == WINDOW_REDRAW_WITHOUT_CLEAR
)
1131 struct Region
*r
= group_children_clip_region(cl
, obj
);
1134 c
= MUI_AddClipRegion(muiRenderInfo(obj
), r
);
1136 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1139 MUI_RemoveClipRegion(muiRenderInfo(obj
), c
);
1143 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1146 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1)
1148 struct Region
*r
= NULL
;
1151 if (muiGlobalInfo(obj
)->mgi_Prefs
->window_redraw
1152 == WINDOW_REDRAW_WITHOUT_CLEAR
)
1153 r
= group_children_clip_region(cl
, obj
);
1156 c
= MUI_AddClipRegion(muiRenderInfo(obj
), r
);
1159 * update is set when changing active page of a page group
1160 * need to redraw background ourself
1162 DoMethod(obj
, MUIM_DrawBackground
,
1163 _mleft(obj
), _mtop(obj
), _mwidth(obj
), _mheight(obj
),
1164 _mleft(obj
), _mtop(obj
), 0);
1167 MUI_RemoveClipRegion(muiRenderInfo(obj
), c
);
1171 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2)
1173 LONG left
, top
, right
, bottom
;
1174 LONG diff_virt_offx
= data
->virt_offx
- data
->old_virt_offx
;
1175 LONG diff_virt_offy
= data
->virt_offy
- data
->old_virt_offy
;
1176 struct Rectangle rect
;
1177 struct Rectangle
*clip_rect
= &muiRenderInfo(obj
)->mri_ClipRect
;
1181 if (!diff_virt_offx
&& !diff_virt_offy
)
1186 /* sba: I don't know how MUI handle this but ScrollRasterBF() made problems when scrolling
1187 ** a (partly visible) virtual groups in a virtual group, because e.g. _mtop() is then
1188 ** smaller than the region. ScrollRasterBF() on AmigaOS then marks the complete region
1189 ** as damaged. Using ScrollWindowRaster() solved that problem but it flickers then.
1190 ** To avoid this we prevent that the scroll area is out of the region bounds.
1191 ** The region bounds are setted in MUI_Redraw() but should probably should go in the
1192 ** MUI's clip functions
1195 left
= MAX(_mleft(obj
), clip_rect
->MinX
);
1196 top
= MAX(_mtop(obj
), clip_rect
->MinY
);
1197 right
= MIN(_mright(obj
), clip_rect
->MaxX
);
1198 bottom
= MIN(_mbottom(obj
), clip_rect
->MaxY
);
1201 ** ScrollRasterBF(_rp(obj), diff_virt_offx, diff_virt_offy, _mleft(obj), _mtop(obj), _mright(obj),_mbottom(obj));
1204 ScrollWindowRaster(_window(obj
), diff_virt_offx
, diff_virt_offy
,
1205 left
, top
, right
, bottom
);
1207 if ((region
= NewRegion()))
1214 if (diff_virt_offx
> 0)
1216 rect
.MinX
= right
- diff_virt_offx
+ 1;
1217 if (rect
.MinX
< left
)
1224 rect
.MaxX
= left
- diff_virt_offx
- 1;
1225 if (rect
.MaxX
> right
)
1229 if (rect
.MinX
<= rect
.MaxX
)
1231 DoMethod(obj
, MUIM_DrawBackground
,
1232 rect
.MinX
, rect
.MinY
,
1233 rect
.MaxX
- rect
.MinX
+ 1,
1234 rect
.MaxY
- rect
.MinY
+ 1,
1235 rect
.MinX
, rect
.MinY
, 0);
1237 OrRectRegion(region
, &rect
);
1246 if (diff_virt_offy
> 0)
1248 rect
.MinY
= bottom
- diff_virt_offy
+ 1;
1249 if (rect
.MinY
< top
)
1256 rect
.MaxY
= top
- diff_virt_offy
- 1;
1257 if (rect
.MaxY
> bottom
)
1260 if (rect
.MinY
<= rect
.MaxY
)
1262 DoMethod(obj
, MUIM_DrawBackground
,
1263 rect
.MinX
, rect
.MinY
,
1264 rect
.MaxX
- rect
.MinX
+ 1,
1265 rect
.MaxY
- rect
.MinY
+ 1,
1266 rect
.MinX
, rect
.MinY
, 0);
1268 OrRectRegion(region
, &rect
);
1276 if (!(msg
->flags
& MADF_DRAWOBJECT
)
1277 && !(msg
->flags
& MADF_DRAWALL
))
1282 if (data
->flags
& GROUP_VIRTUAL
&& !region
)
1284 /* Not really needed if MUI Draws all the objects, maybe that's
1285 * what DRAWALL is for??? */
1286 if ((region
= NewRegion()))
1288 struct Rectangle rect
;
1289 rect
.MinX
= _mleft(obj
);
1290 rect
.MinY
= _mtop(obj
);
1291 rect
.MaxX
= _mright(obj
);
1292 rect
.MaxY
= _mbottom(obj
);
1293 OrRectRegion(region
, &rect
);
1297 /* Add clipping region if we have one */
1299 clip
= MUI_AddClipRegion(muiRenderInfo(obj
), region
);
1301 group_rect
= muiRenderInfo(obj
)->mri_ClipRect
;
1303 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1304 cstate
= (Object
*) ChildList
->mlh_Head
;
1305 while ((child
= NextObject(&cstate
)))
1307 if (!(_flags(child
) & MADF_SHOWME
))
1310 if (child
!= data
->titlegroup
)
1313 if ((data
->flags
& GROUP_PAGEMODE
) && ((page
!= data
->active_page
)
1314 && (child
!= data
->titlegroup
)))
1319 if ((data
->flags
& GROUP_PAGEMODE
) && (child
== data
->titlegroup
)
1320 && (msg
->flags
& MADF_DRAWUPDATE
) && (data
->update
== 1))
1322 /* Do not issue a re-draw to title group during page switch.
1323 * The group will re-draw itself due to setting of
1324 * MUIA_Group_ActivePage attribute.
1329 MUI_Redraw(child
, MADF_DRAWOBJECT
);
1330 muiRenderInfo(obj
)->mri_ClipRect
= group_rect
;
1333 if (data
->flags
& GROUP_VIRTUAL
&& region
&& clip
!= (APTR
) - 1)
1335 MUI_RemoveClipRegion(muiRenderInfo(obj
), clip
);
1338 data
->old_virt_offx
= data
->virt_offx
;
1339 data
->old_virt_offy
= data
->virt_offy
;
1346 #define END_MINMAX() \
1347 tmp.MaxHeight = MAX(tmp.MaxHeight, tmp.MinHeight); \
1348 tmp.MaxWidth = MAX(tmp.MaxWidth, tmp.MinWidth); \
1349 tmp.DefHeight = CLAMP(tmp.DefHeight, tmp.MinHeight, tmp.MaxHeight); \
1350 tmp.DefWidth = CLAMP(tmp.DefWidth, tmp.MinWidth, tmp.MaxWidth); \
1351 msg->MinMaxInfo->MinWidth += tmp.MinWidth; \
1352 msg->MinMaxInfo->MinHeight += tmp.MinHeight; \
1353 msg->MinMaxInfo->MaxWidth += tmp.MaxWidth; \
1354 msg->MinMaxInfo->MaxHeight += tmp.MaxHeight; \
1355 msg->MinMaxInfo->DefWidth += tmp.DefWidth; \
1356 msg->MinMaxInfo->DefHeight += tmp.DefHeight;
1359 * MinMax calculation function. When this is called,
1360 * the children of your group have already been asked
1361 * about their min/max dimension so you can use their
1362 * dimensions to calculate yours.
1365 * - Init minwidth and maxwidth with size needed for total child spacing.
1366 * - 1st pass to find maximum minimum width, to set minwidth of each child
1367 * if they should have the same width (for a row of buttons ...)
1368 * - Adjust minwidth w/o making object bigger than their max size.
1370 static void group_minmax_horiz(struct IClass
*cl
, Object
*obj
,
1371 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1373 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1376 struct MUI_MinMax tmp
;
1377 WORD maxminwidth
= 0;
1378 BOOL found_nonzero_vweight
= FALSE
;
1382 tmp
.MaxHeight
= MUI_MAXMAX
;
1383 if (data
->num_visible_children
> 0)
1385 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1386 (data
->num_visible_children
- 1) * data
->horiz_spacing
;
1390 tmp
.MinWidth
= tmp
.DefWidth
= 0;
1391 tmp
.MaxWidth
= MUI_MAXMAX
;
1394 if (data
->flags
& GROUP_SAME_WIDTH
)
1396 cstate
= (Object
*) children
->mlh_Head
;
1397 while ((child
= NextObject(&cstate
)))
1399 if (IS_HIDDEN(child
))
1401 maxminwidth
= MAX(maxminwidth
, _minwidth(child
));
1405 data
->samesize_maxmin_horiz
= maxminwidth
;
1406 /* D(bug("group_minmax_horiz(%p) : maxminwidth=%d\n", obj, maxminwidth)); */
1408 data
->horiz_weight_sum
= 0;
1409 cstate
= (Object
*) children
->mlh_Head
;
1410 while ((child
= NextObject(&cstate
)))
1414 if (IS_HIDDEN(child
))
1416 if (data
->flags
& GROUP_SAME_WIDTH
)
1418 minwidth
= MAX(maxminwidth
, _minwidth(child
));
1419 minwidth
= MIN(minwidth
, _maxwidth(child
));
1422 minwidth
= _minwidth(child
);
1423 tmp
.MinWidth
+= minwidth
;
1424 tmp
.DefWidth
+= w0_defwidth(child
);
1425 tmp
.MaxWidth
+= w0_maxwidth(child
);
1426 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, MUI_MAXMAX
);
1427 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1428 tmp
.DefHeight
= MAX(tmp
.DefHeight
, _defheight(child
));
1430 if all children have null weight then maxheight=minheight
1431 if all but some children have null weights, the maxheight
1432 is the min of all maxheights
1434 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, _maxheight(child
));
1435 data
->horiz_weight_sum
+= _hweight(child
);
1436 if (_vweight(child
) > 0)
1438 found_nonzero_vweight
= TRUE
;
1441 if (!found_nonzero_vweight
)
1443 tmp
.MaxHeight
= tmp
.MinHeight
;
1446 //if (data->flags & GROUP_VIRTUAL)
1448 //kprintf("# min %d x %d def %d x %d max %d x %d\n",
1449 // tmp.MinWidth, tmp.MinHeight,
1450 // tmp.DefWidth, tmp.DefHeight,
1451 // tmp.MaxWidth, tmp.MaxHeight);
1457 /* minmax calculation for vertical groups (see group_minmax_horiz)
1459 static void group_minmax_vert(struct IClass
*cl
, Object
*obj
,
1460 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1462 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1465 struct MUI_MinMax tmp
;
1466 WORD maxminheight
= 0;
1467 BOOL found_nonzero_hweight
= FALSE
;
1471 tmp
.MaxWidth
= MUI_MAXMAX
;
1472 if (data
->num_visible_children
> 0)
1474 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1475 (data
->num_visible_children
- 1) * data
->vert_spacing
;
1479 tmp
.MinHeight
= tmp
.DefHeight
= 0;
1480 tmp
.MaxHeight
= MUI_MAXMAX
;
1483 if (data
->flags
& GROUP_SAME_HEIGHT
)
1485 cstate
= (Object
*) children
->mlh_Head
;
1486 while ((child
= NextObject(&cstate
)))
1488 if (IS_HIDDEN(child
))
1490 maxminheight
= MAX(maxminheight
, _minheight(child
));
1494 data
->samesize_maxmin_vert
= maxminheight
;
1495 data
->vert_weight_sum
= 0;
1496 cstate
= (Object
*) children
->mlh_Head
;
1497 while ((child
= NextObject(&cstate
)))
1499 if (IS_HIDDEN(child
))
1502 if (data
->flags
& GROUP_SAME_HEIGHT
)
1503 _minheight(child
) = MIN(maxminheight
, w0_maxheight(child
));
1504 tmp
.MinHeight
+= _minheight(child
);
1505 tmp
.DefHeight
+= w0_defheight(child
);
1506 tmp
.MaxHeight
+= w0_maxheight(child
);
1507 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, MUI_MAXMAX
);
1508 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1509 tmp
.DefWidth
= MAX(tmp
.DefWidth
, _defwidth(child
));
1510 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, _maxwidth(child
));
1511 data
->vert_weight_sum
+= _vweight(child
);
1512 if (_hweight(child
) > 0)
1514 found_nonzero_hweight
= TRUE
;
1517 if (!found_nonzero_hweight
)
1519 tmp
.MaxWidth
= tmp
.MinWidth
;
1527 minmax_2d_rows_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1528 struct MUI_MinMax
*req
, WORD maxmin_height
, WORD maxdef_height
)
1534 /* do not rewind after the while, to process line by line */
1535 cstate
= (Object
*) children
->mlh_Head
;
1537 for (i
= 0; i
< data
->rows
; i
++)
1539 /* calculate min and max height of this row */
1540 int min_h
= 0, def_h
= 0, max_h
= MUI_MAXMAX
;
1541 BOOL found_nonzero_vweight
= FALSE
;
1543 data
->row_infos
[i
].weight
= 0;
1546 while ((child
= NextObject(&cstate
)))
1548 if (IS_HIDDEN(child
))
1550 if (data
->flags
& GROUP_SAME_HEIGHT
)
1552 _minheight(child
) = MIN(maxmin_height
, w0_maxheight(child
));
1553 _defheight(child
) = MIN(maxdef_height
, w0_maxheight(child
));
1555 min_h
= MAX(min_h
, _minheight(child
));
1556 def_h
= MAX(def_h
, w0_defheight(child
));
1557 max_h
= MIN(max_h
, _maxheight(child
));
1558 if (_vweight(child
) > 0)
1560 found_nonzero_vweight
= TRUE
;
1561 data
->row_infos
[i
].weight
+= _vweight(child
);
1564 if ((j
% data
->columns
) == 0)
1567 if (!found_nonzero_vweight
)
1570 max_h
= MAX(max_h
, min_h
);
1571 /* D(bug("row %d : min_h=%d max_h=%d\n", i, min_h, max_h)); */
1573 data
->row_infos
[i
].min
= min_h
;
1574 data
->row_infos
[i
].max
= max_h
;
1575 data
->vert_weight_sum
+= data
->row_infos
[i
].weight
;
1577 req
->MinHeight
+= min_h
;
1578 req
->DefHeight
+= def_h
;
1579 req
->MaxHeight
+= max_h
;
1580 if (req
->MaxHeight
> MUI_MAXMAX
)
1581 req
->MaxHeight
= MUI_MAXMAX
;
1587 minmax_2d_columns_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1588 struct MUI_MinMax
*req
, WORD maxmin_width
, WORD maxdef_width
)
1594 for (i
= 0; i
< data
->columns
; i
++)
1596 /* calculate min and max width of this column */
1597 int min_w
= 0, def_w
= 0, max_w
= MUI_MAXMAX
;
1598 BOOL found_nonzero_hweight
= FALSE
;
1600 data
->col_infos
[i
].weight
= 0;
1603 /* process all children to get children on a column */
1604 cstate
= (Object
*) children
->mlh_Head
;
1605 while ((child
= NextObject(&cstate
)))
1607 if (IS_HIDDEN(child
))
1610 if (((j
- 1) % data
->columns
) != i
)
1612 if (data
->flags
& GROUP_SAME_WIDTH
)
1614 _minwidth(child
) = MIN(maxmin_width
, w0_maxwidth(child
));
1615 _defwidth(child
) = MIN(maxdef_width
, w0_maxwidth(child
));
1617 min_w
= MAX(min_w
, _minwidth(child
));
1618 def_w
= MAX(def_w
, w0_defwidth(child
));
1620 /* this handles the case of null weight children, which limit
1621 * the max size if they're alone, but not if they are with
1622 * non-null weight obj
1624 max_w
= MIN(max_w
, _maxwidth(child
));
1625 if (_hweight(child
) > 0)
1627 found_nonzero_hweight
= TRUE
;
1628 data
->col_infos
[i
].weight
+= _hweight(child
);
1631 if (!found_nonzero_hweight
)
1634 max_w
= MAX(max_w
, min_w
);
1635 /* D(bug("col %d : min_w=%d max_w=%d\n", i, min_w, max_w)); */
1637 data
->col_infos
[i
].min
= min_w
;
1638 data
->col_infos
[i
].max
= max_w
;
1639 data
->horiz_weight_sum
+= data
->col_infos
[i
].weight
;
1641 req
->MinWidth
+= min_w
;
1642 req
->DefWidth
+= def_w
;
1643 req
->MaxWidth
+= max_w
;
1644 if (req
->MaxWidth
> MUI_MAXMAX
)
1645 req
->MaxWidth
= MUI_MAXMAX
;
1650 group_minmax_2d(struct IClass
*cl
, Object
*obj
,
1651 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1653 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1656 struct MUI_MinMax tmp
;
1664 if (data
->num_children
% data
->rows
)
1667 data
->rows
= data
->num_children
;
1670 data
->columns
= data
->num_children
/ data
->rows
;
1674 if (data
->num_children
% data
->columns
)
1677 data
->columns
= data
->num_children
;
1680 data
->rows
= data
->num_children
/ data
->columns
;
1683 if (data
->columns
< 1)
1688 if (data
->row_infos
!= NULL
)
1689 mui_free(data
->row_infos
);
1691 data
->row_infos
= mui_alloc(data
->rows
* sizeof(struct layout2d_elem
));
1692 if (NULL
== data
->row_infos
)
1695 if (data
->col_infos
!= NULL
)
1696 mui_free(data
->col_infos
);
1699 mui_alloc(data
->columns
* sizeof(struct layout2d_elem
));
1700 if (NULL
== data
->col_infos
)
1703 data
->horiz_weight_sum
= 0;
1704 data
->vert_weight_sum
= 0;
1706 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1707 (data
->rows
- 1) * data
->vert_spacing
;
1708 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1709 (data
->columns
- 1) * data
->horiz_spacing
;
1710 /* get minimum dims if same dims for all children are needed */
1716 if ((data
->flags
& GROUP_SAME_WIDTH
)
1717 || (data
->flags
& GROUP_SAME_HEIGHT
))
1719 cstate
= (Object
*) children
->mlh_Head
;
1720 while ((child
= NextObject(&cstate
)))
1722 if (!(_flags(child
) & MADF_SHOWME
))
1724 maxmin_width
= MAX(maxmin_width
, _minwidth(child
));
1725 maxmin_height
= MAX(maxmin_height
, _minheight(child
));
1726 maxdef_width
= MAX(maxdef_width
, w0_defwidth(child
));
1727 maxdef_height
= MAX(maxdef_height
, w0_defheight(child
));
1729 /* g_print("2d group: mminw=%d mminh=%d\n", */
1730 /* maxmin_width, maxmin_height); */
1732 if (data
->flags
& GROUP_SAME_HEIGHT
)
1733 data
->samesize_maxmin_vert
= maxmin_height
;
1735 data
->samesize_maxmin_vert
= 0;
1737 if (data
->flags
& GROUP_SAME_WIDTH
)
1738 data
->samesize_maxmin_horiz
= maxmin_width
;
1740 data
->samesize_maxmin_horiz
= 0;
1742 minmax_2d_rows_pass(data
, children
, &tmp
, maxmin_height
, maxdef_height
);
1743 minmax_2d_columns_pass(data
, children
, &tmp
, maxmin_width
,
1751 group_minmax_pagemode(struct IClass
*cl
, Object
*obj
,
1752 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1756 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1757 struct MUI_MinMax tmp
= { 0, 0, MUI_MAXMAX
, MUI_MAXMAX
, 0, 0 };
1759 cstate
= (Object
*) children
->mlh_Head
;
1761 D(bug("minmax_pagemode(%lx)\n", obj
, tmp
.DefWidth
));
1763 while ((child
= NextObject(&cstate
)))
1765 if (!(_flags(child
) & MADF_SHOWME
))
1768 if (child
== data
->titlegroup
)
1771 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1772 D(bug("minmax_pagemode(%p) minh child = %d tmpmin=%d\n", obj
,
1773 _minheight(child
), tmp
.MinHeight
));
1774 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1775 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, w0_maxheight(child
));
1776 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, w0_maxwidth(child
));
1777 tmp
.DefHeight
= MAX(tmp
.DefHeight
,
1778 ((w0_defheight(child
) <
1779 MUI_MAXMAX
) ? w0_defheight(child
) : tmp
.DefHeight
));
1782 ((w0_defwidth(child
) <
1783 MUI_MAXMAX
) ? w0_defwidth(child
) : tmp
.DefWidth
));
1784 D(bug("minmax_pagemode(%lx) defw = %ld\n", obj
, tmp
.DefWidth
));
1787 if (data
->titlegroup
)
1789 tmp
.MinHeight
+= _minheight(data
->titlegroup
);
1790 tmp
.MaxHeight
+= w0_maxheight(data
->titlegroup
);
1791 tmp
.DefHeight
+= w0_defheight(data
->titlegroup
);
1797 /**************************************************************************
1798 MUIM_AskMinMax : ask children about min/max sizes, then
1799 either call a hook, or the builtin method, to calculate our minmax
1800 **************************************************************************/
1801 IPTR
Group__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1802 struct MUIP_AskMinMax
*msg
)
1804 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1805 struct MUI_LayoutMsg lm
;
1806 struct MUIP_AskMinMax childMsg
;
1807 struct MUI_MinMax childMinMax
;
1810 LONG super_minwidth
, super_minheight
;
1813 * let our superclass first fill in its size with frame, inner spc etc ...
1815 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1816 super_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1817 super_minheight
= msg
->MinMaxInfo
->MinHeight
;
1822 childMsg
.MethodID
= msg
->MethodID
;
1823 childMsg
.MinMaxInfo
= &childMinMax
;
1824 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
1826 cstate
= (Object
*) lm
.lm_Children
->mlh_Head
;
1828 while ((child
= NextObject(&cstate
)))
1830 if (!(_flags(child
) & MADF_SHOWME
))
1831 /* BORDERGADGETs should handle this itself */
1834 DoMethodA(child
, (Msg
) & childMsg
);
1835 /* D(bug("*** group %lx, child %lx min=%ld,%ld\n", */
1836 /* obj, child, childMinMax.MinWidth, childMinMax.MinHeight)); */
1837 __area_finish_minmax(child
, childMsg
.MinMaxInfo
);
1841 * Use children infos to calculate group size
1843 if (data
->flags
& GROUP_PAGEMODE
)
1845 D(bug("minmax_pagemode(%p) minh initial = %d\n", obj
,
1846 msg
->MinMaxInfo
->MinHeight
));
1847 group_minmax_pagemode(cl
, obj
, lm
.lm_Children
, msg
);
1848 D(bug("minmax_pagemode(%p) minh = %d\n", obj
,
1849 msg
->MinMaxInfo
->MinHeight
));
1851 else if (data
->layout_hook
)
1853 lm
.lm_Type
= MUILM_MINMAX
;
1854 CallHookPkt(data
->layout_hook
, obj
, &lm
);
1856 if (lm
.lm_MinMax
.MaxHeight
< lm
.lm_MinMax
.MinHeight
)
1857 lm
.lm_MinMax
.MaxHeight
= lm
.lm_MinMax
.MinHeight
;
1858 if (lm
.lm_MinMax
.DefHeight
< lm
.lm_MinMax
.MinHeight
)
1859 lm
.lm_MinMax
.DefHeight
= lm
.lm_MinMax
.MinHeight
;
1860 if (lm
.lm_MinMax
.MaxWidth
< lm
.lm_MinMax
.MinWidth
)
1861 lm
.lm_MinMax
.MaxWidth
= lm
.lm_MinMax
.MinWidth
;
1862 if (lm
.lm_MinMax
.DefWidth
< lm
.lm_MinMax
.MinWidth
)
1863 lm
.lm_MinMax
.DefWidth
= lm
.lm_MinMax
.MinWidth
;
1865 //kprintf("### min %d x %d def %d x %d max %d x %d\n",
1866 // msg->MinMaxInfo->MinWidth,
1867 // msg->MinMaxInfo->MinHeight,
1868 // msg->MinMaxInfo->DefWidth,
1869 // msg->MinMaxInfo->DefHeight,
1870 // msg->MinMaxInfo->MaxWidth,
1871 // msg->MinMaxInfo->MaxHeight);
1873 msg
->MinMaxInfo
->MinWidth
+= lm
.lm_MinMax
.MinWidth
;
1874 msg
->MinMaxInfo
->MinHeight
+= lm
.lm_MinMax
.MinHeight
;
1875 msg
->MinMaxInfo
->MaxWidth
+= lm
.lm_MinMax
.MaxWidth
;
1876 if (msg
->MinMaxInfo
->MaxWidth
> MUI_MAXMAX
)
1877 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1878 msg
->MinMaxInfo
->MaxHeight
+= lm
.lm_MinMax
.MaxHeight
;
1879 if (msg
->MinMaxInfo
->MaxHeight
> MUI_MAXMAX
)
1880 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1881 msg
->MinMaxInfo
->DefWidth
+= lm
.lm_MinMax
.DefWidth
;
1882 msg
->MinMaxInfo
->DefHeight
+= lm
.lm_MinMax
.DefHeight
;
1884 //kprintf("#### min %d x %d def %d x %d max %d x %d\n",
1885 // msg->MinMaxInfo->MinWidth,
1886 // msg->MinMaxInfo->MinHeight,
1887 // msg->MinMaxInfo->DefWidth,
1888 // msg->MinMaxInfo->DefHeight,
1889 // msg->MinMaxInfo->MaxWidth,
1890 // msg->MinMaxInfo->MaxHeight);
1895 if ((data
->rows
== 1) && (data
->columns
== 1))
1897 data
->num_visible_children
=
1898 Group_GetNumVisibleChildren(data
, lm
.lm_Children
);
1899 if (data
->flags
& GROUP_HORIZ
)
1900 group_minmax_horiz(cl
, obj
, lm
.lm_Children
, msg
);
1902 group_minmax_vert(cl
, obj
, lm
.lm_Children
, msg
);
1906 group_minmax_2d(cl
, obj
, lm
.lm_Children
, msg
);
1910 if (data
->flags
& GROUP_VIRTUAL
)
1912 data
->saved_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1913 data
->saved_minheight
= msg
->MinMaxInfo
->MinHeight
;
1914 msg
->MinMaxInfo
->MinWidth
= super_minwidth
+ 2;
1915 msg
->MinMaxInfo
->MinHeight
= super_minheight
+ 2;
1917 //kprintf("## min %d x %d def %d x %d max %d x %d\n",
1918 // msg->MinMaxInfo->MinWidth,
1919 // msg->MinMaxInfo->MinHeight,
1920 // msg->MinMaxInfo->DefWidth,
1921 // msg->MinMaxInfo->DefHeight,
1922 // msg->MinMaxInfo->MaxWidth,
1923 // msg->MinMaxInfo->MaxHeight);
1932 // enforce minmax constraint, but also update total growable/shrinkable weights
1933 // while we're at it
1934 static void Layout1D_minmax_constraint(WORD
*sizep
, WORD minsize
,
1935 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
1936 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
, WORD samesize
)
1938 WORD size
= *sizep
, remain
= *remainp
,
1939 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
1940 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
1942 /* D(bug("L1D_minmax_c size=%d min=%d max=%d w=%d ss=%d\n", */
1943 /* size, minsize, maxsize, */
1944 /* weight, samesize)); */
1946 if ((samesize
> 0) && (weight
== 0))
1948 remain
+= size
- samesize
;
1954 if (size
<= minsize
) // too little
1956 remain
+= size
- minsize
;
1959 if (size
== maxsize
)
1962 else if (size
>= maxsize
) // too big
1964 remain
+= size
- maxsize
;
1969 if (!((samesize
> 0) && (weight
== 0)))
1972 weightgrow
+= weight
;
1974 weightshrink
+= weight
;
1979 *sizegrowp
= sizegrow
;
1980 *sizeshrinkp
= sizeshrink
;
1981 *weightgrowp
= weightgrow
;
1982 *weightshrinkp
= weightshrink
;
1986 // redistribute excess size to growable child, or reduce size of a shrinkable
1988 static void Layout1D_redistribution(WORD
*sizep
, WORD minsize
,
1989 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
1990 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
)
1992 WORD size
= *sizep
, remain
= *remainp
,
1993 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
1994 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
1999 if ((remain
> 0) && (size
< maxsize
))
2003 newsize
= (sizegrow
* weight
+ weightgrow
/ 2) / weightgrow
;
2005 /* D(bug("newsize=%ld == size_growa=%ld * w=%ld / weight_grow=%d\n", */
2006 /* newsize, sizegrow, weight, weightgrow)); */
2008 /* take care of off-by-1 errors that may toggle remainder sign
2009 * by ensuring convergence to 0
2011 if (remain
- newsize
+ size
< 0)
2013 /* D(bug("adding remainder=%d => size = %d\n", */
2014 /* remain, size + remain)); */
2020 remain
-= newsize
- size
;
2023 weightgrow
-= weight
;
2026 else if ((remain
< 0) && (size
> minsize
))
2030 newsize
= (sizeshrink
* weight
+ weightshrink
/ 2) / weightshrink
;
2032 /* D(bug("newsize=%ld == size_shrinkables=%ld * w=%ld " */
2033 /* "/ weight_shrinkables=%d\n", */
2034 /* newsize, sizeshrink, weight, weightshrink)); */
2036 if (remain
- newsize
+ size
> 0)
2038 /* D(bug("adding remainder=%d => size = %d\n", */
2039 /* remain, size + remain)); */
2045 remain
-= newsize
- size
;
2048 weightshrink
-= weight
;
2054 *sizegrowp
= sizegrow
;
2055 *sizeshrinkp
= sizeshrink
;
2056 *weightgrowp
= weightgrow
;
2057 *weightshrinkp
= weightshrink
;
2061 // 2 passes at most, less on average (0.5 or 1.5), each does
2062 // - a minmax clamping, evenutally adding to a remainder
2063 // (remainder = missing (underflow) or remaining (overflow) space compared
2064 // to ideal sizes where children fill the whole group)
2065 // - a redistribution of the remainder, by growing (pos. remainder) or
2066 // shrinking (neg. remainder) children able to support it.
2068 // Occasionnaly the first time the redistribution is done, the minmax
2069 // constraint can be broken, thus the extra pass to check and eventually
2070 // redistribute. The second redistribution never breaks minmax constraint
2071 // (there should be a mathematical proof, but feel free to prove me wrong
2073 static void Layout1D_minmax_constraints_and_redistrib(struct MinList
2074 *children
, WORD total_size
, WORD remainder
, WORD samesize
,
2081 for (i
= 0; i
< 2; i
++)
2083 WORD size_growables
= total_size
;
2084 WORD size_shrinkables
= total_size
;
2085 ULONG weight_growables
= 0;
2086 ULONG weight_shrinkables
= 0;
2088 /* D(bug("start : rem=%ld, A=%ld, size_growables=%ld, " */
2089 /* "size_shrinkables=%ld\n", */
2090 /* remainder, total_size, size_growables, size_shrinkables)); */
2092 // minmax constraints
2093 cstate
= (Object
*) children
->mlh_Head
;
2094 while ((child
= NextObject(&cstate
)))
2096 /* WORD old_size; */
2098 if (IS_HIDDEN(child
))
2103 /* old_size = _width(child); */
2105 Layout1D_minmax_constraint(&_width(child
), _minwidth(child
),
2106 _maxwidth(child
), &remainder
, &size_growables
,
2107 &size_shrinkables
, &weight_growables
,
2108 &weight_shrinkables
, _hweight(child
), samesize
);
2110 /* D(bug("loop1 on %p : width=%d was %d, rem=%d, A=%d, " */
2111 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2112 /* child, _width(child), old_size, remainder, total_size, */
2113 /* size_growables, size_shrinkables, _hweight(child), */
2114 /* _minwidth(child), _maxwidth(child))); */
2116 else // ! group_horiz
2118 /* old_size = _height(child); */
2120 Layout1D_minmax_constraint(&_height(child
),
2121 _minheight(child
), _maxheight(child
), &remainder
,
2122 &size_growables
, &size_shrinkables
, &weight_growables
,
2123 &weight_shrinkables
, _vweight(child
), samesize
);
2125 /* D(bug("loop1 on %p : h=%ld was %d, rem=%d, A=%d, " */
2126 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2127 /* child, _height(child), old_size, remainder, total_size,*/
2128 /* size_growables, size_shrinkables, _vweight(child), */
2129 /* _minheight(child), _maxheight(child))); */
2130 } // if (group_horiz)
2131 } // while child, minmax constraints
2137 /* D(bug("mid : rem=%d, A=%d, size_grow=%d, size_shrink=%d, " */
2138 /* "wg=%ld, ws=%ld\n", remainder, total_size, size_growables, */
2139 /* size_shrinkables, weight_growables, weight_shrinkables)); */
2141 // distribute remaining space to possible candidates
2142 cstate
= (Object
*) children
->mlh_Head
;
2143 while (((child
= NextObject(&cstate
)) != NULL
) && (remainder
!= 0))
2145 /* WORD old_size; */
2147 if (IS_HIDDEN(child
))
2152 /* old_size = _width(child); */
2154 Layout1D_redistribution(&_width(child
), _minwidth(child
),
2155 _maxwidth(child
), &remainder
, &size_growables
,
2156 &size_shrinkables
, &weight_growables
,
2157 &weight_shrinkables
, _hweight(child
));
2159 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2160 /* "size_grow=%d, size_shrink=%d\n", child, */
2161 /* _width(child), old_size, remainder, total_size, */
2162 /* size_growables, size_shrinkables)); */
2164 else // ! group_horiz
2166 /* old_size = _height(child); */
2168 Layout1D_redistribution(&_height(child
), _minheight(child
),
2169 _maxheight(child
), &remainder
, &size_growables
,
2170 &size_shrinkables
, &weight_growables
,
2171 &weight_shrinkables
, _vweight(child
));
2173 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2174 /* "size_grow=%d, size_shrink=%d\n", child, */
2175 /* _height(child), old_size, remainder, total_size, */
2176 /* size_growables, size_shrinkables)); */
2177 } // if (group_horiz)
2179 } // while child, redistribution
2181 /* if (remainder != 0) */
2183 /* D(bug("end : rem=%ld, A=%ld, size_grow=%ld, size_shrink=%ld\n", */
2184 /* remainder, total_size, size_growables, size_shrinkables)); */
2186 // dont break here if remainder == 0, some minmax constraints
2187 // may not be respected
2190 // to easily spot layout bugs, nothing like a (division by zero) exception
2191 /* if (remainder != 0) */
2193 /* ASSERT(remainder != 0); */
2194 /* D(bug("gonna crash, remainder = %d\n", remainder)); */
2195 /* remainder /= 0; */
2200 static void Layout1D_weight_constraint(WORD
*total_sizep
,
2201 WORD
*total_init_sizep
,
2202 ULONG
*total_weightp
, WORD
*sizep
, UWORD weight
, WORD minsize
)
2204 if (*total_weightp
> 0)
2205 *sizep
= (*total_sizep
* weight
+ *total_weightp
/ 2)
2210 *total_weightp
-= weight
;
2211 *total_sizep
-= *sizep
;
2212 *total_init_sizep
+= *sizep
;
2216 static void group_layout_vert(struct IClass
*cl
, Object
*obj
,
2217 struct MinList
*children
)
2219 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2223 WORD remainder
; /* must converge to 0 to successfully end layout */
2225 WORD total_size_backup
;
2226 WORD total_init_size
; /* total size of the ideally sized children */
2233 //kprintf("group_layout_vert: virtoff = %d,%d\n",
2234 // data->virt_offx, data->virt_offy);
2236 if (data
->flags
& GROUP_VIRTUAL
)
2239 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2240 _maxwidth(obj
) - _subwidth(obj
));
2241 data
->virt_mheight
=
2242 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2243 _maxheight(obj
) - _subheight(obj
));
2245 layout_width
= data
->virt_mwidth
;
2246 layout_height
= data
->virt_mheight
;
2250 layout_width
= _mwidth(obj
);
2251 layout_height
= _mheight(obj
);
2254 total_weight
= data
->vert_weight_sum
;
2255 total_init_size
= 0;
2257 layout_height
- (data
->num_visible_children
-
2258 1) * data
->vert_spacing
;
2259 total_size_backup
= total_size
;
2261 /* D(bug("\nvert layout for %p, A=%d W=%ld\n", */
2262 /* obj, total_size, total_weight)); */
2264 // weight constraints
2265 // calculate ideal size for each object, and total ideal size
2266 cstate
= (Object
*) children
->mlh_Head
;
2267 while ((child
= NextObject(&cstate
)))
2269 if (IS_HIDDEN(child
))
2272 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2273 &total_weight
, &_height(child
), _vweight(child
),
2275 /* D(bug("child %p : ideal=%d w=%ld\n", */
2276 /* child, _height(child), _vweight(child))); */
2277 } // while child, weight constraints
2279 total_size
= total_size_backup
;
2280 remainder
= total_size
- total_init_size
;
2282 if (data
->flags
& GROUP_VIRTUAL
)
2284 /* This is also true for non virtual groups, but if this would be the
2285 ** case then there is a bug in the layout function
2291 Layout1D_minmax_constraints_and_redistrib(children
,
2294 (data
->flags
& GROUP_SAME_HEIGHT
) ? data
->samesize_maxmin_vert
: 0,
2298 cstate
= (Object
*) children
->mlh_Head
;
2299 while ((child
= NextObject(&cstate
)))
2301 if (IS_HIDDEN(child
))
2304 width
= MIN(_maxwidth(child
), layout_width
);
2305 width
= MAX(width
, _minwidth(child
));
2306 left
= (layout_width
- width
) / 2;
2308 /* D(bug("child %p -> layout %d x %d\n", */
2309 /* child, width, _height(child))); */
2310 if (!MUI_Layout(child
, left
, top
, width
, _height(child
), 0))
2312 top
+= data
->vert_spacing
+ _height(child
);
2318 static void group_layout_horiz(struct IClass
*cl
, Object
*obj
,
2319 struct MinList
*children
)
2321 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2325 WORD remainder
; /* must converge to 0 to succesfully end layout */
2327 WORD total_size_backup
;
2328 WORD total_init_size
; /* total size of the ideally sized children */
2335 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2336 // data->virt_offx, data->virt_offy);
2338 if (data
->flags
& GROUP_VIRTUAL
)
2341 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2342 _maxwidth(obj
) - _subwidth(obj
));
2343 data
->virt_mheight
=
2344 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2345 _maxheight(obj
) - _subheight(obj
));
2347 layout_width
= data
->virt_mwidth
;
2348 layout_height
= data
->virt_mheight
;
2350 //kprintf("group_layout_horiz: layoutsize %d x %d "
2351 // " virtsize %d x %d msize %d x %d\n",
2352 // layout_width, layout_height, data->virt_mwidth,
2353 // data->virt_mheight,
2354 // _mwidth(obj), _mheight(obj));
2358 layout_width
= _mwidth(obj
);
2359 layout_height
= _mheight(obj
);
2362 total_weight
= data
->horiz_weight_sum
;
2363 total_init_size
= 0;
2365 layout_width
- (data
->num_visible_children
-
2366 1) * data
->horiz_spacing
;
2367 total_size_backup
= total_size
;
2369 /* D(bug("\nhoriz layout for %p, A=%d W=%ld\n", */
2370 /* obj, total_size, total_weight)); */
2372 // weight constraints
2373 // calculate ideal size for each object, and total ideal size
2374 cstate
= (Object
*) children
->mlh_Head
;
2375 while ((child
= NextObject(&cstate
)))
2377 if (IS_HIDDEN(child
))
2380 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2381 &total_weight
, &_width(child
), _hweight(child
),
2383 /* D(bug("child %p : ideal=%d w=%ld\n", */
2384 /* child, _width(child), _hweight(child))); */
2385 } // while child, weight constraints
2387 total_size
= total_size_backup
;
2388 if (data
->horiz_weight_sum
> 0)
2389 remainder
= total_size
- total_init_size
;
2393 if (data
->flags
& GROUP_VIRTUAL
)
2395 /* This is also true for non virtual groups, but if this would be the
2396 ** case then there is a bug in the layout function
2402 Layout1D_minmax_constraints_and_redistrib(children
,
2405 (data
->flags
& GROUP_SAME_WIDTH
) ? data
->samesize_maxmin_horiz
: 0,
2409 cstate
= (Object
*) children
->mlh_Head
;
2410 while ((child
= NextObject(&cstate
)))
2412 if (IS_HIDDEN(child
))
2415 height
= MIN(_maxheight(child
), layout_height
);
2416 height
= MAX(height
, _minheight(child
));
2417 top
= (layout_height
- height
) / 2;
2419 /* D(bug("child %p -> layout %d x %d\n", */
2420 /* child, _width(child), height)); */
2421 if (!MUI_Layout(child
, left
, top
, _width(child
), height
, 0))
2423 left
+= data
->horiz_spacing
+ _width(child
);
2429 static void Layout2D_weight_constraint(struct MUI_GroupData
*data
,
2430 struct layout2d_elem
*row_infos
,
2431 struct layout2d_elem
*col_infos
,
2432 WORD total_size_height
, WORD total_size_width
,
2433 WORD
*total_init_height
, WORD
*total_init_width
)
2436 ULONG total_weight_vert
= data
->vert_weight_sum
;
2437 ULONG total_weight_horiz
= data
->horiz_weight_sum
;
2439 *total_init_height
= 0;
2440 *total_init_width
= 0;
2442 /* calc row heights */
2443 for (i
= 0; i
< data
->rows
; i
++)
2445 if (total_weight_vert
> 0)
2447 (total_size_height
* row_infos
[i
].weight
+
2448 total_weight_vert
/ 2) / total_weight_vert
;
2450 row_infos
[i
].dim
= row_infos
[i
].min
;
2452 /* D(bug("l2 row %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2453 /* i, row_infos[i].dim, */
2454 /* row_infos[i].weight, total_size_height, total_weight_vert)); */
2456 total_weight_vert
-= row_infos
[i
].weight
;
2457 total_size_height
-= row_infos
[i
].dim
;
2458 *total_init_height
+= row_infos
[i
].dim
;
2461 /* calc columns widths */
2462 for (i
= 0; i
< data
->columns
; i
++)
2464 if (total_weight_horiz
)
2466 (total_size_width
* col_infos
[i
].weight
+
2467 total_weight_horiz
/ 2) / total_weight_horiz
;
2469 col_infos
[i
].dim
= col_infos
[i
].min
;
2471 /* D(bug("l2 col %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2472 /* i, col_infos[i].dim, */
2473 /* col_infos[i].weight, total_size_width, total_weight_horiz)); */
2475 total_weight_horiz
-= col_infos
[i
].weight
;
2476 total_size_width
-= col_infos
[i
].dim
;
2477 *total_init_width
+= col_infos
[i
].dim
;
2483 static void Layout2D_minmax_constraints_and_redistrib(struct layout2d_elem
2484 *infos
, WORD nitems
, WORD total_size
, WORD samesize
, WORD remainder
)
2488 /* D(bug("L2D mc&r n=%d A=%d ss=%d rem=%d\n", */
2489 /* nitems, total_size, samesize, remainder)); */
2491 for (j
= 0; j
< 2; j
++)
2493 WORD size_growables
= total_size
;
2494 WORD size_shrinkables
= total_size
;
2495 ULONG weight_growables
= 0;
2496 ULONG weight_shrinkables
= 0;
2497 /* WORD old_size; */
2500 // minmax constraints
2501 for (i
= 0; i
< nitems
; i
++)
2503 /* old_size = infos[i].dim; */
2505 /* D(bug("bef loop1 on %d : size=%d, rem=%d, A=%d, " */
2506 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2507 /* i, infos[i].dim, remainder, total_size, */
2508 /* size_growables, size_shrinkables, infos[i].weight, */
2509 /* infos[i].min, infos[i].max)); */
2511 Layout1D_minmax_constraint(&infos
[i
].dim
, infos
[i
].min
,
2512 infos
[i
].max
, &remainder
, &size_growables
,
2513 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2514 infos
[i
].weight
, samesize
);
2516 /* D(bug("loop1 on %d : size=%d was %d, rem=%d, A=%d, " */
2517 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2518 /* i, infos[i].dim, old_size, remainder, total_size, */
2519 /* size_growables, size_shrinkables, infos[i].weight, */
2520 /* infos[i].min, infos[i].max)); */
2526 for (i
= 0; i
< nitems
; i
++)
2528 /* old_size = infos[i].dim; */
2530 /* D(bug("bef loop2 on %d : size=%d, rem=%d, A=%d, " */
2531 /* "size_grow=%d, size_shrink=%d\n", i, */
2532 /* infos[i].dim, remainder, total_size, */
2533 /* size_growables, size_shrinkables)); */
2535 Layout1D_redistribution(&infos
[i
].dim
, infos
[i
].min
,
2536 infos
[i
].max
, &remainder
, &size_growables
,
2537 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2540 /* D(bug("loop2 on %d : size=%d was %d, rem=%d, A=%d, " */
2541 /* "size_grow=%d, size_shrink=%d\n", i, */
2542 /* infos[i].dim, old_size, remainder, total_size, */
2543 /* size_growables, size_shrinkables)); */
2549 layout_2d_distribute_space(struct MUI_GroupData
*data
,
2550 struct layout2d_elem
*row_infos
,
2551 struct layout2d_elem
*col_infos
,
2552 struct MinList
*children
, LONG left_start
, LONG top_start
)
2563 * pass 2 : distribute space
2565 cstate
= (Object
*) children
->mlh_Head
;
2568 for (i
= 0; i
< data
->rows
; i
++)
2570 /* left start for child layout in this row */
2573 /* max height for children in this row */
2574 row_height
= row_infos
[i
].dim
;
2576 /* for each column */
2577 while ((child
= NextObject(&cstate
)))
2584 if (IS_HIDDEN(child
))
2586 /* max width for children in this column */
2587 col_width
= col_infos
[j
].dim
;
2589 /* center child if col width is bigger than child maxwidth */
2590 cwidth
= MIN(_maxwidth(child
), col_width
);
2591 cwidth
= MAX(cwidth
, _minwidth(child
));
2592 cleft
= left
+ (col_width
- cwidth
) / 2;
2594 /* center child if row height is bigger than child maxheight */
2595 cheight
= MIN(_maxheight(child
), row_height
);
2596 cheight
= MAX(cheight
, _minheight(child
));
2597 ctop
= top
+ (row_height
- cheight
) / 2;
2599 /* g_print("layout %d %d %d %d\n", cleft, ctop, cwidth, cheight); */
2600 /* D(bug("2DL/child %p -> layout %d x %d\n", */
2601 /* child, cwidth, cheight)); */
2602 if (!MUI_Layout(child
, cleft
, ctop
, cwidth
, cheight
, 0))
2605 left
+= data
->horiz_spacing
+ col_width
;
2608 if ((j
% data
->columns
) == 0)
2612 top
+= data
->vert_spacing
+ row_height
;
2619 * all children in the same row have the same maximum height
2620 * all children in the same column have the same maximum height
2621 * if a child maximum size is smaller than the biggest minimum size,
2622 * the chid will be centered in the remaining space.
2624 * for each row, determine its height allocation
2625 * weight ? the vertical weight of a row, if no fixed-height child
2626 * in the row, is the sum of all vertical weights of children
2627 * all row members will have the same height
2629 * for each column, determine its width allocation
2630 * all column members will have the same width
2632 /* Write a proper hook function */
2634 group_layout_2d(struct IClass
*cl
, Object
*obj
, struct MinList
*children
)
2636 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2637 WORD left_start
= 0;
2639 WORD total_size_height
=
2640 _mheight(obj
) - (data
->rows
- 1) * data
->vert_spacing
;
2641 WORD total_size_width
=
2642 _mwidth(obj
) - (data
->columns
- 1) * data
->horiz_spacing
;
2643 WORD total_init_height
;
2644 WORD total_init_width
;
2645 WORD remainder_height
;
2646 WORD remainder_width
;
2650 if (data
->rows
== 0 || data
->columns
== 0)
2652 if (data
->num_children
% data
->rows
2653 || data
->num_children
% data
->columns
)
2655 if (data
->row_infos
== NULL
|| data
->col_infos
== NULL
)
2658 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2659 // data->virt_offx, data->virt_offy);
2661 if (data
->flags
& GROUP_VIRTUAL
)
2664 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2665 _maxwidth(obj
) - _subwidth(obj
));
2666 data
->virt_mheight
=
2667 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2668 _maxheight(obj
) - _subheight(obj
));
2670 layout_width
= data
->virt_mwidth
;
2671 layout_height
= data
->virt_mheight
;
2675 layout_width
= _mwidth(obj
);
2676 layout_height
= _mheight(obj
);
2680 layout_height
- (data
->rows
- 1) * data
->vert_spacing
;
2682 layout_width
- (data
->columns
- 1) * data
->horiz_spacing
;
2686 // weight constraints
2687 Layout2D_weight_constraint(data
, data
->row_infos
, data
->col_infos
,
2688 total_size_height
, total_size_width
,
2689 &total_init_height
, &total_init_width
);
2691 remainder_height
= total_size_height
- total_init_height
;
2692 remainder_width
= total_size_width
- total_init_width
;
2694 Layout2D_minmax_constraints_and_redistrib(data
->row_infos
,
2695 data
->rows
, total_size_height
,
2696 /* (data->flags & GROUP_SAME_HEIGHT) ? data->samesize_maxmin_vert : 0, */
2697 0, remainder_height
);
2699 Layout2D_minmax_constraints_and_redistrib(data
->col_infos
,
2700 data
->columns
, total_size_width
,
2701 /* (data->flags & GROUP_SAME_WIDTH) ? data->samesize_maxmin_horiz : 0, */
2702 0, remainder_width
);
2704 layout_2d_distribute_space(data
, data
->row_infos
, data
->col_infos
,
2705 children
, left_start
, top_start
);
2709 /* Write a proper hook function */
2710 static void group_layout_pagemode(struct IClass
*cl
, Object
*obj
,
2711 struct MinList
*children
)
2713 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2718 int w
, h
, yoffset
= 0;
2720 if (data
->flags
& GROUP_VIRTUAL
)
2723 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2724 _maxwidth(obj
) - _subwidth(obj
));
2725 data
->virt_mheight
=
2726 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2727 _maxheight(obj
) - _subheight(obj
));
2729 layout_width
= data
->virt_mwidth
;
2730 layout_height
= data
->virt_mheight
;
2734 layout_width
= _mwidth(obj
);
2735 layout_height
= _mheight(obj
);
2738 if (data
->titlegroup
)
2740 yoffset
= _minheight(data
->titlegroup
);
2741 layout_height
-= yoffset
;
2744 cstate
= (Object
*) children
->mlh_Head
;
2745 while ((child
= NextObject(&cstate
)))
2747 w
= MIN(layout_width
, _maxwidth(child
));
2748 h
= MIN(layout_height
, _maxheight(child
));
2750 if (child
== data
->titlegroup
)
2752 MUI_Layout(child
, (layout_width
- w
) / 2, 0, w
, yoffset
, 0);
2756 D(bug("PM/child %p -> layout %d x %d\n", child
, w
, h
));
2757 MUI_Layout(child
, (layout_width
- w
) / 2,
2758 yoffset
+ (layout_height
- h
) / 2, w
, h
, 0);
2764 /**************************************************************************
2766 Either use a given layout hook, or the builtin method.
2767 **************************************************************************/
2768 IPTR
Group__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
2769 struct MUIP_Layout
*msg
)
2771 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2772 struct MUI_LayoutMsg lm
= { 0 };
2774 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
2775 if (data
->flags
& GROUP_PAGEMODE
)
2777 group_layout_pagemode(cl
, obj
, lm
.lm_Children
);
2779 else if (data
->layout_hook
)
2781 lm
.lm_Type
= MUILM_LAYOUT
;
2782 lm
.lm_Layout
.Width
= _mwidth(obj
);
2783 lm
.lm_Layout
.Height
= _mheight(obj
);
2785 CallHookPkt(data
->layout_hook
, obj
, &lm
);
2787 if (data
->flags
& GROUP_VIRTUAL
)
2789 data
->virt_mwidth
= lm
.lm_Layout
.Width
;
2790 data
->virt_mheight
= lm
.lm_Layout
.Height
;
2795 if ((data
->rows
== 1) && (data
->columns
== 1))
2797 if (data
->flags
& GROUP_HORIZ
)
2798 group_layout_horiz(cl
, obj
, lm
.lm_Children
);
2800 group_layout_vert(cl
, obj
, lm
.lm_Children
);
2803 group_layout_2d(cl
, obj
, lm
.lm_Children
);
2806 if (data
->flags
& GROUP_VIRTUAL
)
2808 WORD new_virt_offx
, new_virt_offy
;
2810 new_virt_offx
= data
->virt_offx
;
2811 new_virt_offy
= data
->virt_offy
;
2813 if (new_virt_offx
+ _mwidth(obj
) > data
->virt_mwidth
)
2815 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
2817 if (new_virt_offx
< 0)
2820 if (new_virt_offy
+ _mheight(obj
) > data
->virt_mheight
)
2822 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
2824 if (new_virt_offy
< 0)
2827 if (new_virt_offx
!= data
->virt_offx
)
2829 nfset(obj
, MUIA_Virtgroup_Left
, new_virt_offx
);
2832 if (new_virt_offy
!= data
->virt_offy
)
2834 nfset(obj
, MUIA_Virtgroup_Top
, new_virt_offy
);
2842 /**************************************************************************
2844 **************************************************************************/
2845 IPTR
Group__MUIM_Show(struct IClass
*cl
, Object
*obj
,
2846 struct MUIP_Show
*msg
)
2848 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2851 struct MinList
*ChildList
= NULL
;
2853 /* If msg is NULL, we won't want that the super method actually gets
2856 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2858 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2859 cstate
= (Object
*) ChildList
->mlh_Head
;
2861 if (data
->flags
& GROUP_PAGEMODE
)
2864 while ((child
= NextObject(&cstate
)))
2866 if (child
== data
->titlegroup
)
2868 DoShowMethod(child
);
2869 continue; /* Title group is not counted as page */
2872 if (page
== data
->active_page
)
2874 DoShowMethod(child
);
2882 while ((child
= NextObject(&cstate
)))
2884 if (!(data
->flags
& GROUP_VIRTUAL
) ||
2885 IsObjectVisible(child
, MUIMasterBase
))
2887 if (_flags(child
) & MADF_SHOWME
)
2888 DoShowMethod(child
);
2895 /**************************************************************************
2897 **************************************************************************/
2898 IPTR
Group__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
2899 struct MUIP_Hide
*msg
)
2901 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2904 struct MinList
*ChildList
= NULL
;
2906 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2907 cstate
= (Object
*) ChildList
->mlh_Head
;
2909 if (data
->flags
& GROUP_PAGEMODE
)
2912 while ((child
= NextObject(&cstate
)))
2914 if (child
== data
->titlegroup
)
2916 DoHideMethod(child
);
2917 continue; /* Title group is not counted as page */
2920 if (page
== data
->active_page
)
2922 DoHideMethod(child
);
2930 while ((child
= NextObject(&cstate
)))
2932 if (_flags(child
) & MADF_CANDRAW
)
2933 DoHideMethod(child
);
2937 /* If msg is NULL, we won't want that the super method actually gets
2940 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2945 * MUIM_FindUData : tests if the MUIA_UserData of the object
2946 * contains the given <udata> and returns the object pointer in this case.
2948 IPTR
Group__MUIM_FindUData(struct IClass
*cl
, Object
*obj
,
2949 struct MUIP_FindUData
*msg
)
2951 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2953 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2956 return DoMethodA(data
->family
, (Msg
) msg
);
2961 * MUIM_GetUData : This method tests if the MUIA_UserData of the object
2962 * contains the given <udata> and gets <attr> to <storage> for itself
2965 IPTR
Group__MUIM_GetUData(struct IClass
*cl
, Object
*obj
,
2966 struct MUIP_GetUData
*msg
)
2968 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2970 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2972 get(obj
, msg
->attr
, msg
->storage
);
2976 return DoMethodA(data
->family
, (Msg
) msg
);
2981 * MUIM_SetUData : This method tests if the MUIA_UserData of the object
2982 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2984 IPTR
Group__MUIM_SetUData(struct IClass
*cl
, Object
*obj
,
2985 struct MUIP_SetUData
*msg
)
2987 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2989 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2990 set(obj
, msg
->attr
, msg
->val
);
2992 DoMethodA(data
->family
, (Msg
) msg
);
2998 * MUIM_SetUDataOnce : This method tests if the MUIA_UserData of the object
2999 * contains the given <udata> and sets <attr> to <val> for itself in this case.
3000 * Stop after the first udata found.
3002 IPTR
Group__MUIM_SetUDataOnce(struct IClass
*cl
, Object
*obj
,
3003 struct MUIP_SetUData
*msg
)
3005 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3007 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
3009 set(obj
, msg
->attr
, msg
->val
);
3012 return DoMethodA(data
->family
, (Msg
) msg
);
3015 /**************************************************************************
3016 MUIM_DragQueryExtented
3017 **************************************************************************/
3018 IPTR
Group__MUIM_DragQueryExtended(struct IClass
*cl
, Object
*obj
,
3019 struct MUIP_DragQueryExtended
*msg
)
3021 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3025 struct MinList
*ChildList
= NULL
;
3027 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3028 cstate
= (Object
*) ChildList
->mlh_Head
;
3029 while ((child
= NextObject(&cstate
)))
3031 if (!(_flags(child
) & MADF_CANDRAW
))
3034 if ((found_obj
= (Object
*) DoMethodA(child
, (Msg
) msg
)))
3035 return (IPTR
) found_obj
;
3037 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3040 /**************************************************************************
3042 **************************************************************************/
3043 IPTR
Group__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
3044 struct MUIP_HandleEvent
*msg
)
3046 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3048 /* check this, otherwise a superclass who has IDCMP_MOUSEBUTTONS
3049 eventhandler might call DoSuperMethod, and this function gets
3050 called even when he have not added any eventhandler */
3052 if ((data
->flags
& GROUP_VIRTUAL
) && msg
->imsg
)
3054 switch (msg
->imsg
->Class
)
3056 case IDCMP_MOUSEBUTTONS
:
3057 /* For virtual groups */
3058 if (msg
->imsg
->Code
== SELECTDOWN
)
3060 if (_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
3061 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
3064 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3065 (IPTR
) & data
->ehn
);
3066 data
->ehn
.ehn_Events
|= IDCMP_INTUITICKS
;
3067 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3068 (IPTR
) & data
->ehn
);
3073 if (data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
)
3075 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3076 (IPTR
) & data
->ehn
);
3077 data
->ehn
.ehn_Events
&= ~IDCMP_INTUITICKS
;
3078 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3079 (IPTR
) & data
->ehn
);
3084 case IDCMP_INTUITICKS
:
3085 if (!(data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
))
3088 if (!(_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
3089 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
3092 LONG new_virt_offx
= data
->virt_offx
;
3093 LONG new_virt_offy
= data
->virt_offy
;
3095 if (msg
->imsg
->MouseX
< _mleft(obj
))
3098 if (new_virt_offx
>= 4)
3103 else if (msg
->imsg
->MouseX
> _mright(obj
))
3107 if (new_virt_offx
> data
->virt_mwidth
- _mwidth(obj
))
3108 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
3109 if (new_virt_offx
< 0)
3113 if (msg
->imsg
->MouseY
< _mtop(obj
))
3116 if (new_virt_offy
>= 4)
3121 else if (msg
->imsg
->MouseY
> _mbottom(obj
))
3125 if (new_virt_offy
> data
->virt_mheight
- _mheight(obj
))
3126 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
3127 if (new_virt_offy
< 0)
3131 if (new_virt_offx
!= data
->virt_offx
3132 || new_virt_offy
!= data
->virt_offy
)
3135 MUIA_Virtgroup_Left
, new_virt_offx
,
3136 MUIA_Virtgroup_Top
, new_virt_offy
,
3137 MUIA_Group_Forward
, FALSE
, TAG_DONE
);
3147 /**************************************************************************
3149 **************************************************************************/
3150 IPTR
Group__MUIM_DrawBackground(struct IClass
*cl
, Object
*obj
,
3151 struct MUIP_DrawBackground
*msg
)
3153 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3155 if (data
->flags
& GROUP_VIRTUAL
)
3157 struct MUIP_DrawBackground msg2
= *msg
;
3159 msg2
.xoffset
+= data
->virt_offx
;
3160 msg2
.yoffset
+= data
->virt_offy
;
3162 return DoSuperMethodA(cl
, obj
, (Msg
) & msg2
);
3165 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3168 /**************************************************************************
3170 Find the given object or return NULL
3171 **************************************************************************/
3172 IPTR
Group__MUIM_FindAreaObject(struct IClass
*cl
, Object
*obj
,
3173 struct MUIP_FindAreaObject
*msg
)
3175 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3178 struct MinList
*ChildList
= NULL
;
3181 if (msg
->obj
== obj
)
3184 // it's one of my children ?
3185 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3186 cstate
= (Object
*) ChildList
->mlh_Head
;
3187 while ((child
= NextObject(&cstate
)))
3189 if (msg
->obj
== child
)
3190 return (IPTR
) child
;
3193 // let the children find it
3194 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3195 cstate
= (Object
*) ChildList
->mlh_Head
;
3196 while ((child
= NextObject(&cstate
)))
3198 Object
*res
= (Object
*) DoMethodA(child
, (Msg
) msg
);
3206 /**************************************************************************
3207 MUIM_Export : to export an object's "contents" to a dataspace object.
3208 **************************************************************************/
3209 static IPTR
Group__MUIM_Export(struct IClass
*cl
, Object
*obj
,
3210 struct MUIP_Export
*msg
)
3212 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3215 struct MinList
*ChildList
= NULL
;
3217 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3221 cstate
= (Object
*) ChildList
->mlh_Head
;
3222 while ((child
= NextObject(&cstate
)))
3224 DoMethodA(child
, (Msg
) msg
);
3231 /**************************************************************************
3232 MUIM_Import : to import an object's "contents" from a dataspace object.
3233 **************************************************************************/
3234 static IPTR
Group__MUIM_Import(struct IClass
*cl
, Object
*obj
,
3235 struct MUIP_Import
*msg
)
3237 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3240 struct MinList
*ChildList
= NULL
;
3242 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3246 cstate
= (Object
*) ChildList
->mlh_Head
;
3247 while ((child
= NextObject(&cstate
)))
3249 DoMethodA(child
, (Msg
) msg
);
3255 /**************************************************************************
3256 MUIM_Notify - disabled now because previous Zune versions had a OM_GET
3257 check in MUIM_Notify which is no longer the case
3258 **************************************************************************/
3260 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3261 struct MUIP_Notify
*msg
)
3263 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3266 struct MinList
*ChildList
;
3268 /* Try at first if understand the message our self
3269 ** We disable the forwarding of the OM_GET message
3270 ** as the MUIM_Notify otherwise would "think" that
3271 ** the group class actually understands the attribute
3272 ** although a child does this only
3274 data
->dont_forward_get
= 1;
3275 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
3277 data
->dont_forward_get
= 0;
3281 /* We ourselves didn't understand the notify tag so we try the
3283 data
->dont_forward_get
= 0;
3285 get(data
->family
, MUIA_Family_List
, (IPTR
*) & (ChildList
));
3286 cstate
= (Object
*) ChildList
->mlh_Head
;
3287 while ((child
= NextObject(&cstate
)))
3289 if (DoMethodA(child
, (Msg
) msg
))
3297 /* Notes about Group_Notify() and echo notification problem:
3298 It was discovered that MUI seems to have some special handling for group class
3299 which will drop notifications on the children which are found to not
3300 understand the attribute.
3302 This is done by checking if an OM_GET on the child returns TRUE.
3303 There's a little problem here because it is not known how big the storage
3304 needed for the attribute in question will be. Almost no class uses anything
3305 bigger than one IPTR. For "big" attributes those return a pointer to the data,
3306 not the data itself. Unfortuntely there are some exceptions like colorwheel
3307 class which does not return a pointer, but the data itself. So it's not
3308 enough to use one single IPTR variable (4 Bytes on 32bit machines, 8 bytes
3309 on 64 bit machines) to store the result of the test-OM_Get.
3311 There is no general way to query the size needed so if one wants to change
3312 Zune to work like MUI one needs to choose a size which one hopes will be
3313 big enough to hold all possible attributes of all classes, old, present
3316 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3317 struct MUIP_Notify
*msg
)
3319 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3322 struct MinList
*ChildList
= NULL
;
3325 data
->dont_forward_get
= 1;
3327 if (GetAttr(msg
->TrigAttr
, obj
, attr
))
3329 data
->dont_forward_get
= 0;
3330 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3332 data
->dont_forward_get
= 0;
3334 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3338 cstate
= (Object
*) ChildList
->mlh_Head
;
3339 while ((child
= NextObject(&cstate
)))
3342 if (GetAttr(msg
->TrigAttr
, child
, attr
))
3344 DoMethodA(child
, (Msg
) msg
);
3345 /* No return here! */
3352 BOOPSI_DISPATCHER(IPTR
, Group_Dispatcher
, cl
, obj
, msg
)
3354 switch (msg
->MethodID
)
3357 return Group__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3359 return Group__OM_DISPOSE(cl
, obj
, msg
);
3361 return Group__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3363 return Group__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3364 case OM_ADDMEMBER
: /* Fall through */
3365 case MUIM_Group_AddTail
:
3366 return Group__MUIM_AddTail(cl
, obj
, (APTR
) msg
);
3367 case MUIM_Group_AddHead
:
3368 return Group__MUIM_AddHead(cl
, obj
, (APTR
) msg
);
3369 case MUIM_Group_Insert
:
3370 return Group__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3371 case OM_REMMEMBER
: /* Fall through */
3372 case MUIM_Group_Remove
:
3373 return Group__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3374 case MUIM_AskMinMax
:
3375 return Group__MUIM_AskMinMax(cl
, obj
, (APTR
) msg
);
3376 case MUIM_Group_ExitChange
:
3377 return Group__MUIM_ExitChange(cl
, obj
, (APTR
) msg
);
3378 case MUIM_Group_ExitChange2
:
3379 return Group__MUIM_ExitChange2(cl
, obj
, (APTR
) msg
);
3380 case MUIM_Group_InitChange
:
3381 return Group__MUIM_InitChange(cl
, obj
, (APTR
) msg
);
3382 case MUIM_Group_Sort
:
3383 return Group__MUIM_Sort(cl
, obj
, (APTR
) msg
);
3384 case MUIM_Group_DoMethodNoForward
:
3385 return Group__MUIM_DoMethodNoForward(cl
, obj
, (APTR
) msg
);
3386 case MUIM_ConnectParent
:
3387 return Group__MUIM_ConnectParent(cl
, obj
, (APTR
) msg
);
3388 case MUIM_DisconnectParent
:
3389 return Group__MUIM_DisconnectParent(cl
, obj
, (APTR
) msg
);
3391 return Group__MUIM_Layout(cl
, obj
, (APTR
) msg
);
3393 return Group__MUIM_Setup(cl
, obj
, (APTR
) msg
);
3395 return Group__MUIM_Cleanup(cl
, obj
, (APTR
) msg
);
3397 return Group__MUIM_Draw(cl
, obj
, (APTR
) msg
);
3399 case MUIM_FindUData
:
3400 return Group__MUIM_FindUData(cl
, obj
, (APTR
) msg
);
3402 return Group__MUIM_GetUData(cl
, obj
, (APTR
) msg
);
3404 return Group__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
3405 case MUIM_SetUDataOnce
:
3406 return Group__MUIM_SetUDataOnce(cl
, obj
, (APTR
) msg
);
3408 return Group__MUIM_Show(cl
, obj
, (APTR
) msg
);
3410 return Group__MUIM_Hide(cl
, obj
, (APTR
) msg
);
3411 case MUIM_HandleEvent
:
3412 return Group__MUIM_HandleEvent(cl
, obj
, (APTR
) msg
);
3413 case MUIM_DrawBackground
:
3414 return Group__MUIM_DrawBackground(cl
, obj
, (APTR
) msg
);
3415 case MUIM_DragQueryExtended
:
3416 return Group__MUIM_DragQueryExtended(cl
, obj
, (APTR
) msg
);
3417 case MUIM_FindAreaObject
:
3418 return Group__MUIM_FindAreaObject(cl
, obj
, (APTR
) msg
);
3420 return Group__MUIM_Export(cl
, obj
, (APTR
) msg
);
3422 return Group__MUIM_Import(cl
, obj
, (APTR
) msg
);
3426 /* Disabled. See above */
3428 return Group_Notify(cl
, obj
, (APTR
) msg
);
3433 case MUIM_DrawParentBackground
:
3434 case MUIM_DragBegin
:
3436 case MUIM_DragQuery
:
3437 case MUIM_DragFinish
:
3439 case MUIM_CreateDragImage
:
3440 case MUIM_DeleteDragImage
:
3442 case MUIM_GoInactive
:
3443 case MUIM_CreateBubble
:
3444 case MUIM_DeleteBubble
:
3445 case MUIM_CreateShortHelp
:
3446 case MUIM_DeleteShortHelp
:
3449 return DoSuperMethodA(cl
, obj
, (APTR
) msg
);
3450 /* Needs not to be forwarded? */
3453 /* sometimes you want to call a superclass method,
3454 * but not dispatching to child.
3455 * But what to do with list methods in a listview ?
3457 Group_DispatchMsg(cl
, obj
, (APTR
) msg
);
3459 return DoSuperMethodA(cl
, obj
, msg
);
3461 BOOPSI_DISPATCHER_END
3466 const struct __MUIBuiltinClass _MUI_Group_desc
=
3470 sizeof(struct MUI_GroupData
),
3471 (void *) Group_Dispatcher