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 added to application tree */
280 muiNotifyData(msgint
->obj
)->mnd_ParentObject
= obj
;
282 if (_flags(obj
) & MADF_SETUP
)
284 DoSetupMethod(msgint
->obj
, muiRenderInfo(obj
));
286 /* if (_flags(obj) & MADF_CANDRAW) */
287 /* DoShowMethod(msg->opam_Object); */
292 /**************************************************************************
294 **************************************************************************/
295 IPTR
Group__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
297 struct MUI_GroupData
*data
;
298 struct TagItem
*tags
, *tag
;
299 BOOL bad_children
= FALSE
;
300 IPTR disabled
= FALSE
;
301 IPTR frame
= MUIV_Frame_None
;
303 D(bug("[group.mui] OM_NEW, object 0x%p\n", obj
));
305 obj
= (Object
*) DoSuperMethodA(cl
, obj
, (Msg
) msg
);
309 /* Initial local instance data */
310 data
= INST_DATA(cl
, obj
);
312 data
->family
= MUI_NewObjectA(MUIC_Family
, NULL
);
315 CoerceMethod(cl
, obj
, OM_DISPOSE
);
319 data
->horiz_spacing
= -1;
320 data
->vert_spacing
= -1;
323 data
->active_page
= 0;
324 get(obj
, MUIA_Frame
, &frame
);
326 /* parse initial taglist */
327 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
331 case MUIA_Group_Child
:
332 D(bug("[group.mui] Adding child 0x%p\n", tag
->ti_Data
));
335 DoMethod(obj
, OM_ADDMEMBER
, tag
->ti_Data
);
336 /* Set first child as group title */
337 if ((frame
== MUIV_Frame_Register
)
338 && (data
->titlegroup
== NULL
))
339 data
->titlegroup
= (Object
*) tag
->ti_Data
;
345 case MUIA_Group_ActivePage
:
346 change_active_page(cl
, obj
, (LONG
) tag
->ti_Data
);
349 case MUIA_Group_Columns
:
350 data
->columns
= (tag
->ti_Data
) > 1 ? tag
->ti_Data
: 1;
354 case MUIA_Group_Horiz
:
355 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_HORIZ
);
358 case MUIA_Group_HorizSpacing
:
359 data
->flags
|= GROUP_HSPACING
;
360 data
->horiz_spacing
= tag
->ti_Data
;
363 case MUIA_Group_LayoutHook
:
364 data
->layout_hook
= (struct Hook
*)tag
->ti_Data
;
367 case MUIA_Group_PageMode
:
368 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_PAGEMODE
);
371 case MUIA_Group_Rows
:
372 data
->rows
= MAX((ULONG
) tag
->ti_Data
, 1);
376 case MUIA_Group_SameHeight
:
377 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_HEIGHT
);
380 case MUIA_Group_SameSize
:
381 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_HEIGHT
);
382 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_WIDTH
);
385 case MUIA_Group_SameWidth
:
386 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_WIDTH
);
389 case MUIA_Group_Spacing
:
390 data
->flags
|= (GROUP_HSPACING
| GROUP_VSPACING
);
391 data
->horiz_spacing
= tag
->ti_Data
;
392 data
->vert_spacing
= tag
->ti_Data
;
395 case MUIA_Group_VertSpacing
:
396 data
->flags
|= GROUP_VSPACING
;
397 data
->vert_spacing
= tag
->ti_Data
;
400 case MUIA_Group_Virtual
:
401 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_VIRTUAL
);
408 CoerceMethod(cl
, obj
, OM_DISPOSE
);
412 /* D(bug("Group_New(0x%lx)\n",obj)); */
414 if (data
->flags
& GROUP_VIRTUAL
)
416 /* This is used by MUI_Render() to determine if group is virtual.
417 * It then installs a clip region.
418 * Also MUI_Layout() uses this. Probably for speed up reason */
419 _flags(obj
) |= MADF_ISVIRTUALGROUP
;
422 /* will forward MUIA_Disabled to children */
423 get(obj
, MUIA_Disabled
, &disabled
);
426 set(obj
, MUIA_Disabled
, TRUE
);
429 /* This is only used for virtual groups */
430 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
; /* Will be filled on demand */
431 data
->ehn
.ehn_Priority
= 10; /* Will hear the click before all
432 * other normal objects */
433 data
->ehn
.ehn_Flags
= 0;
434 data
->ehn
.ehn_Object
= obj
;
435 data
->ehn
.ehn_Class
= cl
;
439 /**************************************************************************
441 **************************************************************************/
442 IPTR
Group__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
444 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
446 if (data
->row_infos
!= NULL
)
447 mui_free(data
->row_infos
);
448 if (data
->col_infos
!= NULL
)
449 mui_free(data
->col_infos
);
450 if (data
->family
!= NULL
)
451 MUI_DisposeObject(data
->family
);
452 return DoSuperMethodA(cl
, obj
, msg
);
455 /**************************************************************************
457 **************************************************************************/
458 IPTR
Group__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
460 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
461 struct TagItem
*tags
= msg
->ops_AttrList
;
464 BOOL need_recalc
= FALSE
;
467 int virt_offx
= data
->virt_offx
, virt_offy
= data
->virt_offy
;
469 /* There are many ways to find out what tag items provided by set()
470 ** we do know. The best way should be using NextTagItem() and simply
471 ** browsing through the list.
474 /* Parse group attributes before calling DoSuperMethodA(),
475 ** otherwise if an app for example sets up a notification
476 ** on MUIA_Group_ActivePage which calls a hook, and then
477 ** the hook function calls get(obj, MUIA_Group_ActivePage),
478 ** it would get returned the old active page instead of the new
482 while ((tag
= NextTagItem(&tags
)) != NULL
)
486 case MUIA_Group_Columns
:
487 data
->columns
= MAX((ULONG
) tag
->ti_Data
, 1);
491 case MUIA_Group_ActivePage
:
492 change_active_page(cl
, obj
, (LONG
) tag
->ti_Data
);
494 case MUIA_Group_Forward
:
495 forward
= tag
->ti_Data
;
497 case MUIA_Group_HorizSpacing
:
498 data
->flags
|= GROUP_HSPACING
;
499 data
->horiz_spacing
= tag
->ti_Data
;
501 case MUIA_Group_Rows
:
502 data
->rows
= MAX((ULONG
) tag
->ti_Data
, 1);
506 case MUIA_Group_Spacing
:
507 data
->flags
|= (GROUP_HSPACING
| GROUP_VSPACING
);
508 data
->horiz_spacing
= tag
->ti_Data
;
509 data
->vert_spacing
= tag
->ti_Data
;
511 case MUIA_Group_VertSpacing
:
512 data
->flags
|= GROUP_VSPACING
;
513 data
->vert_spacing
= tag
->ti_Data
;
515 case MUIA_Virtgroup_Left
:
516 //kprintf("set virtgroup_left: %d\n", tag->ti_Data);
517 virt_offx
= tag
->ti_Data
;
520 case MUIA_Group_LayoutHook
:
522 [ach] Seems like MUI supports setting this attribute after
523 initialization, even though the documentation states
524 otherwise. At least some programs use it...
526 data
->layout_hook
= (struct Hook
*)tag
->ti_Data
;
529 case MUIA_Virtgroup_Top
:
530 //kprintf("set virtgroup_top: %d\n", tag->ti_Data);
531 virt_offy
= tag
->ti_Data
;
537 if (muiRenderInfo(obj
) && need_recalc
)
538 DoMethod(_win(obj
), MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
540 retval
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
542 /* seems to be the documented behaviour, however it should be slow! */
546 /* Attributes which are to be filtered out, so that they are ignored
547 when OM_SET is passed to group's children */
549 tags
= msg
->ops_AttrList
;
550 while ((tag
= NextTagItem(&tags
)) != NULL
)
559 case MUIA_ContextMenu
:
560 case MUIA_ContextMenuTrigger
:
561 case MUIA_ControlChar
:
562 case MUIA_CycleChain
:
565 case MUIA_Group_ActivePage
:
567 case MUIA_FrameTitle
:
568 case MUIA_HorizWeight
:
572 case MUIA_VertWeight
:
574 case MUIA_Virtgroup_Left
:
575 case MUIA_Virtgroup_Top
:
576 case MUIA_AppMessage
:
578 tag
->ti_Tag
= TAG_IGNORE
;
581 /* D(bug("Group_Set(%p) MUIA_Selected forwarded\n", obj)); */
582 /* tag->ti_Tag = TAG_IGNORE; */
587 Group_DispatchMsg(cl
, obj
, (Msg
) msg
);
591 if (virt_offx
!= data
->virt_offx
|| virt_offy
!= data
->virt_offy
)
593 if (_flags(obj
) & MADF_CANDRAW
)
594 Group__MUIM_Hide(cl
, obj
, NULL
);
595 data
->virt_offx
= virt_offx
;
596 data
->virt_offy
= virt_offy
;
597 /* Relayout ourself, this will also relayout all the children */
598 DoMethod(obj
, MUIM_Layout
);
599 if (_flags(obj
) & MADF_CANDRAW
)
600 Group__MUIM_Show(cl
, obj
, NULL
);
602 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
609 /**************************************************************************
611 **************************************************************************/
612 IPTR
Group__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
614 /* small macro to simplify return value storage */
615 #define STORE *(msg->opg_Storage)
617 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
619 switch (msg
->opg_AttrID
)
627 case MUIA_Group_ActivePage
:
628 STORE
= data
->active_page
;
630 case MUIA_Group_ChildList
:
631 return GetAttr(MUIA_Family_List
, data
->family
, msg
->opg_Storage
);
632 case MUIA_Group_Horiz
:
633 STORE
= (data
->flags
& GROUP_HORIZ
);
635 case MUIA_Group_HorizSpacing
:
636 STORE
= data
->horiz_spacing
;
638 case MUIA_Group_VertSpacing
:
639 STORE
= data
->vert_spacing
;
641 case MUIA_Group_ChildCount
:
642 STORE
= data
->num_children
;
644 case MUIA_Virtgroup_Left
:
645 STORE
= data
->virt_offx
;
647 case MUIA_Virtgroup_Top
:
648 STORE
= data
->virt_offy
;
650 case MUIA_Virtgroup_Width
:
651 STORE
= data
->virt_mwidth
;
653 case MUIA_Virtgroup_Height
:
654 STORE
= data
->virt_mheight
;
656 case MUIA_Virtgroup_MinWidth
:
657 STORE
= data
->saved_minwidth
;
659 case MUIA_Virtgroup_MinHeight
:
660 STORE
= data
->saved_minheight
;
664 /* our handler didn't understand the attribute, we simply pass
665 ** it to our superclass now
667 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
670 /* seems to be the documented behaviour, however it should be slow! */
671 if (!data
->dont_forward_get
&& !data
->dont_forward_methods
)
675 struct MinList
*ChildList
= NULL
;
677 get(data
->family
, MUIA_Family_List
, &(ChildList
));
678 cstate
= (Object
*) ChildList
->mlh_Head
;
679 while ((child
= NextObject(&cstate
)))
680 if (DoMethodA(child
, (Msg
) msg
))
688 /**************************************************************************
690 **************************************************************************/
691 IPTR
Group__MUIM_AddTail(struct IClass
*cl
, Object
*obj
,
692 struct MUIP_Group_AddTail
*msg
)
694 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
697 /**************************************************************************
699 **************************************************************************/
700 IPTR
Group__MUIM_AddHead(struct IClass
*cl
, Object
*obj
,
701 struct MUIP_Group_AddHead
*msg
)
703 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
706 /**************************************************************************
708 **************************************************************************/
709 IPTR
Group__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
710 struct MUIP_Group_Insert
*msg
)
712 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
715 /**************************************************************************
717 **************************************************************************/
718 IPTR
Group__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
719 struct MUIP_Group_Remove
*msg
)
721 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
723 if (_flags(obj
) & MADF_CANDRAW
)
724 DoHideMethod(msg
->obj
);
725 if (_flags(obj
) & MADF_SETUP
)
726 DoMethod(msg
->obj
, MUIM_Cleanup
);
727 if (muiNotifyData(obj
)->mnd_GlobalInfo
)
729 DoMethod(msg
->obj
, MUIM_DisconnectParent
);
730 muiNotifyData(msg
->obj
)->mnd_ParentObject
= NULL
;
732 _flags(msg
->obj
) &= ~MADF_INVIRTUALGROUP
;
735 if ((data
->flags
& GROUP_CHANGING
) != 0)
736 data
->flags
|= GROUP_CHANGED
;
737 data
->num_children
--;
738 DoMethodA(data
->family
, (Msg
) msg
);
744 /**************************************************************************
746 **************************************************************************/
747 IPTR
Group__MUIM_ConnectParent(struct IClass
*cl
, Object
*obj
,
748 struct MUIP_ConnectParent
*msg
)
750 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
753 struct MinList
*ChildList
= NULL
;
755 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
757 get(data
->family
, MUIA_Family_List
, &(ChildList
));
758 cstate
= (Object
*) ChildList
->mlh_Head
;
759 while ((child
= NextObject(&cstate
)))
761 if ((_flags(obj
) & MADF_INVIRTUALGROUP
)
762 || (data
->flags
& GROUP_VIRTUAL
))
764 _flags(child
) |= MADF_INVIRTUALGROUP
;
767 /* Only children of groups can have parents */
768 muiNotifyData(child
)->mnd_ParentObject
= obj
;
770 DoMethod(child
, MUIM_ConnectParent
, (IPTR
) obj
);
775 /**************************************************************************
776 MUIM_DisconnectParent
777 **************************************************************************/
778 IPTR
Group__MUIM_DisconnectParent(struct IClass
*cl
, Object
*obj
,
779 struct MUIP_ConnectParent
*msg
)
781 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
784 struct MinList
*ChildList
= NULL
;
786 get(data
->family
, MUIA_Family_List
, &(ChildList
));
787 cstate
= (Object
*) ChildList
->mlh_Head
;
788 while ((child
= NextObject(&cstate
)))
790 DoMethodA(child
, (Msg
) msg
);
791 muiNotifyData(child
)->mnd_ParentObject
= NULL
;
792 _flags(child
) &= ~MADF_INVIRTUALGROUP
;
794 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
799 * Put group in exchange state
801 IPTR
Group__MUIM_InitChange(struct IClass
*cl
, Object
*obj
,
802 struct MUIP_Group_InitChange
*msg
)
804 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
806 data
->flags
&= ~GROUP_CHANGED
;
807 data
->flags
|= GROUP_CHANGING
;
813 * Will recalculate display after dynamic adding/removing
815 IPTR
Group__MUIM_ExitChange(struct IClass
*cl
, Object
*obj
,
816 struct MUIP_Group_ExitChange
*msg
)
818 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
820 data
->flags
&= ~GROUP_CHANGING
;
822 if (data
->flags
& GROUP_CHANGED
)
824 data
->flags
&= ~GROUP_CHANGED
;
826 if ((_flags(obj
) & MADF_SETUP
) && _win(obj
))
828 Object
*win
= _win(obj
);
829 Object
*parent
= obj
;
831 /* CHECKME: Don't call RecalcDisplay if one of our parents is
832 in GROUP_CHANGING state to prevent crash with Zune prefs
833 program NListtree page because NList/NListtree when
834 killing tree images in MUIM_Cleanup uses InitChange/
835 ExitChange. Zune prefs program uses InitChange/ExitChange
836 when switching page -> nesting -> mess. */
838 while ((parent
= _parent(parent
)))
840 struct MUI_GroupData
*pdata
= INST_DATA(cl
, parent
);
845 if (pdata
->flags
& GROUP_CHANGING
)
852 DoMethod(win
, MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
861 * Will recalculate display after dynamic adding/removing
863 IPTR
Group__MUIM_ExitChange2(struct IClass
*cl
, Object
*obj
,
864 struct MUIP_Group_ExitChange2
*msg
)
866 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
868 if (data
->flags
& GROUP_CHANGING
)
870 data
->flags
&= ~(GROUP_CHANGING
| GROUP_CHANGED
);
872 if ((_flags(obj
) & MADF_SETUP
) && _win(obj
))
874 Object
*win
= _win(obj
);
875 Object
*parent
= obj
;
877 /* CHECKME: Don't call RecalcDisplay if one of our parents is
878 in GROUP_CHANGING state to prevent crash with Zune prefs
879 program NListtree page because NList/NListtree when
880 killing tree images in MUIM_Cleanup uses InitChange/
881 ExitChange. Zune prefs program uses InitChange/ExitChange
882 when switching page -> nesting -> mess. */
884 while ((parent
= _parent(parent
)))
886 struct MUI_GroupData
*pdata
= INST_DATA(cl
, parent
);
891 if (pdata
->flags
& GROUP_CHANGING
)
898 DoMethod(win
, MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
909 IPTR
Group__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
910 struct MUIP_Group_Sort
*msg
)
912 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
915 msg
->MethodID
= MUIM_Family_Sort
;
917 DoMethodA(data
->family
, (APTR
) msg
);
919 /* restore original message */
920 msg
->MethodID
= MUIM_Group_Sort
;
924 /**************************************************************************
925 MUIM_Group_DoMethodNoForward
927 Executes the given method but does not forward it to the children
928 **************************************************************************/
929 IPTR
Group__MUIM_DoMethodNoForward(struct IClass
*cl
, Object
*obj
,
930 struct MUIP_Group_DoMethodNoForward
*msg
)
932 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
934 data
->dont_forward_methods
= 1; /* disable forwarding */
935 rc
= DoMethodA(obj
, (Msg
) & msg
->DoMethodID
);
936 /* Probably doesn't work correctly on AROS? */
938 data
->dont_forward_methods
= 0;
943 * Propagate a method to group children.
945 static ULONG
Group_DispatchMsg(struct IClass
*cl
, Object
*obj
, Msg msg
)
947 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
950 struct MinList
*ChildList
= NULL
;
952 if (data
->dont_forward_methods
)
955 get(data
->family
, MUIA_Family_List
, &(ChildList
));
956 cstate
= (Object
*) ChildList
->mlh_Head
;
957 while ((child
= NextObject(&cstate
)))
959 DoMethodA(child
, (Msg
) msg
);
965 /**************************************************************************
967 **************************************************************************/
968 IPTR
Group__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
969 struct MUIP_Setup
*msg
)
971 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
976 struct MinList
*ChildList
= NULL
;
978 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
981 ASSERT_VALID_PTR(muiGlobalInfo(obj
));
983 if (!(data
->flags
& GROUP_HSPACING
))
984 data
->horiz_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_hspacing
;
985 if (!(data
->flags
& GROUP_VSPACING
))
986 data
->vert_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_vspacing
;
987 get(data
->family
, MUIA_Family_List
, &(ChildList
));
988 cstate
= cstate_copy
= (Object
*) ChildList
->mlh_Head
;
989 while ((child
= NextObject(&cstate
)))
991 #if 0 /* SHOWME affects only show/hide */
992 if (!(_flags(child
) & MADF_SHOWME
))
996 if (!DoSetupMethod(child
, msg
->RenderInfo
))
998 /* Send MUIM_Cleanup to all objects that received MUIM_Setup.
1000 childFailed
= child
;
1001 cstate
= cstate_copy
;
1002 while ((child
= NextObject(&cstate
)) && (child
!= childFailed
))
1004 #if 0 /* SHOWME affects only show/hide */
1005 if (!(_flags(child
) & MADF_SHOWME
))
1008 DoMethod(child
, MUIM_Cleanup
);
1014 if (data
->flags
& GROUP_VIRTUAL
)
1016 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
1017 (IPTR
) & data
->ehn
);
1024 /**************************************************************************
1026 **************************************************************************/
1027 IPTR
Group__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
, Msg msg
)
1029 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1032 struct MinList
*ChildList
= NULL
;
1034 if (data
->flags
& GROUP_VIRTUAL
)
1036 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
1037 (IPTR
) & data
->ehn
);
1040 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1041 cstate
= (Object
*) ChildList
->mlh_Head
;
1042 while ((child
= NextObject(&cstate
)))
1044 #if 0 /* SHOWME affects only show/hide */
1045 if (!(_flags(child
) & MADF_SHOWME
))
1048 DoMethodA(child
, (Msg
) msg
);
1050 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1055 /**************************************************************************
1056 MUIM_Draw - draw the group
1057 **************************************************************************/
1058 IPTR
Group__MUIM_Draw(struct IClass
*cl
, Object
*obj
,
1059 struct MUIP_Draw
*msg
)
1061 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1064 struct MinList
*ChildList
= NULL
;
1065 struct Rectangle group_rect
; /* child_rect; */
1067 struct Region
*region
= NULL
;
1068 APTR clip
= (APTR
) - 1;
1070 /* D(bug("Group_Draw(%lx) %ldx%ldx%ldx%ld upd=%d page=%d\n", */
1071 /* obj,_left(obj),_top(obj),_right(obj),_bottom(obj), */
1072 /* data->update, data->active_page)); */
1073 /* D(bug("Group_Draw(%p) msg=0x%08lx flags=0x%08lx\n", */
1074 /* obj, msg->flags, _flags(obj))); */
1076 if (data
->flags
& GROUP_CHANGING
)
1079 if (muiGlobalInfo(obj
)->mgi_Prefs
->window_redraw
==
1080 WINDOW_REDRAW_WITHOUT_CLEAR
)
1082 region
= NewRegion();
1085 struct Rectangle rect
;
1087 rect
.MinX
= _left(obj
);
1088 rect
.MinY
= _top(obj
);
1089 rect
.MaxX
= _right(obj
);
1090 rect
.MaxY
= _bottom(obj
);
1092 OrRectRegion(region
, &rect
);
1094 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1095 cstate
= (Object
*) ChildList
->mlh_Head
;
1096 while ((child
= NextObject(&cstate
)))
1098 if (child
!= data
->titlegroup
)
1101 if ((data
->flags
& GROUP_PAGEMODE
) && ((page
!= data
->active_page
)
1102 && (child
!= data
->titlegroup
)))
1105 if ((muiAreaData(child
)->mad_Flags
& MADF_CANDRAW
)
1106 && (_width(child
) > 0) && (_height(child
) > 0))
1108 rect
.MinX
= MAX(_left(child
), _mleft(obj
));
1109 rect
.MinY
= MAX(_top(child
), _mtop(obj
));
1110 rect
.MaxX
= MIN(_right(child
), _mright(obj
));
1111 rect
.MaxY
= MIN(_bottom(child
), _mbottom(obj
));
1113 if ((rect
.MaxX
>= rect
.MinX
)
1114 && (rect
.MaxY
>= rect
.MinY
))
1116 ClearRectRegion(region
, &rect
);
1121 clip
= MUI_AddClipRegion(muiRenderInfo(obj
), region
);
1125 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1129 MUI_RemoveClipRegion(muiRenderInfo(obj
), clip
);
1135 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1137 /* D(bug("Group_Draw(%p) (after dsma) msg=0x%08lx flags=0x%08lx\n", */
1138 /* obj, msg->flags, _flags(obj))); */
1140 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1)
1143 * update is set when changing active page of a page group
1144 * need to redraw background ourself
1146 DoMethod(obj
, MUIM_DrawBackground
,
1147 _mleft(obj
), _mtop(obj
), _mwidth(obj
), _mheight(obj
),
1148 _mleft(obj
), _mtop(obj
), 0);
1154 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2)
1156 LONG left
, top
, right
, bottom
;
1157 LONG diff_virt_offx
= data
->virt_offx
- data
->old_virt_offx
;
1158 LONG diff_virt_offy
= data
->virt_offy
- data
->old_virt_offy
;
1159 struct Rectangle rect
;
1160 struct Rectangle
*clip_rect
= &muiRenderInfo(obj
)->mri_ClipRect
;
1164 if (!diff_virt_offx
&& !diff_virt_offy
)
1169 /* sba: I don't know how MUI handle this but ScrollRasterBF() made problems when scrolling
1170 ** a (partly visible) virtual groups in a virtual group, because e.g. _mtop() is then
1171 ** smaller than the region. ScrollRasterBF() on AmigaOS then marks the complete region
1172 ** as damaged. Using ScrollWindowRaster() solved that problem but it flickers then.
1173 ** To avoid this we prevent that the scroll area is out of the region bounds.
1174 ** The region bounds are setted in MUI_Redraw() but should probably should go in the
1175 ** MUI's clip functions
1178 left
= MAX(_mleft(obj
), clip_rect
->MinX
);
1179 top
= MAX(_mtop(obj
), clip_rect
->MinY
);
1180 right
= MIN(_mright(obj
), clip_rect
->MaxX
);
1181 bottom
= MIN(_mbottom(obj
), clip_rect
->MaxY
);
1184 ** ScrollRasterBF(_rp(obj), diff_virt_offx, diff_virt_offy, _mleft(obj), _mtop(obj), _mright(obj),_mbottom(obj));
1187 ScrollWindowRaster(_window(obj
), diff_virt_offx
, diff_virt_offy
,
1188 left
, top
, right
, bottom
);
1190 if ((region
= NewRegion()))
1197 if (diff_virt_offx
> 0)
1199 rect
.MinX
= right
- diff_virt_offx
+ 1;
1200 if (rect
.MinX
< left
)
1207 rect
.MaxX
= left
- diff_virt_offx
- 1;
1208 if (rect
.MaxX
> right
)
1212 if (rect
.MinX
<= rect
.MaxX
)
1214 DoMethod(obj
, MUIM_DrawBackground
,
1215 rect
.MinX
, rect
.MinY
,
1216 rect
.MaxX
- rect
.MinX
+ 1,
1217 rect
.MaxY
- rect
.MinY
+ 1,
1218 rect
.MinX
, rect
.MinY
, 0);
1220 OrRectRegion(region
, &rect
);
1229 if (diff_virt_offy
> 0)
1231 rect
.MinY
= bottom
- diff_virt_offy
+ 1;
1232 if (rect
.MinY
< top
)
1239 rect
.MaxY
= top
- diff_virt_offy
- 1;
1240 if (rect
.MaxY
> bottom
)
1243 if (rect
.MinY
<= rect
.MaxY
)
1245 DoMethod(obj
, MUIM_DrawBackground
,
1246 rect
.MinX
, rect
.MinY
,
1247 rect
.MaxX
- rect
.MinX
+ 1,
1248 rect
.MaxY
- rect
.MinY
+ 1,
1249 rect
.MinX
, rect
.MinY
, 0);
1251 OrRectRegion(region
, &rect
);
1259 if (!(msg
->flags
& MADF_DRAWOBJECT
)
1260 && !(msg
->flags
& MADF_DRAWALL
))
1265 if (data
->flags
& GROUP_VIRTUAL
&& !region
)
1267 /* Not really needed if MUI Draws all the objects, maybe that's
1268 * what DRAWALL is for??? */
1269 if ((region
= NewRegion()))
1271 struct Rectangle rect
;
1272 rect
.MinX
= _mleft(obj
);
1273 rect
.MinY
= _mtop(obj
);
1274 rect
.MaxX
= _mright(obj
);
1275 rect
.MaxY
= _mbottom(obj
);
1276 OrRectRegion(region
, &rect
);
1280 /* Add clipping region if we have one */
1282 clip
= MUI_AddClipRegion(muiRenderInfo(obj
), region
);
1284 group_rect
= muiRenderInfo(obj
)->mri_ClipRect
;
1286 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1287 cstate
= (Object
*) ChildList
->mlh_Head
;
1288 while ((child
= NextObject(&cstate
)))
1290 if (!(_flags(child
) & MADF_SHOWME
))
1293 if (child
!= data
->titlegroup
)
1296 if ((data
->flags
& GROUP_PAGEMODE
) && ((page
!= data
->active_page
)
1297 && (child
!= data
->titlegroup
)))
1302 // msg->flags |= MADF_DRAWOBJECT; /* yup, do not forget */
1304 // child_rect.MinX = _left(child);
1305 // child_rect.MinY = _top(child);
1306 // child_rect.MaxX = _right(child);
1307 // child_rect.MaxY = _bottom(child);
1308 /* g_print("intersect: a=(%d, %d, %d, %d) b=(%d, %d, %d, %d)\n", */
1309 /* group_rect.x, group_rect.y, */
1310 /* group_rect.width, group_rect.height, */
1311 /* child_rect.x, child_rect.y, */
1312 /* child_rect.width, child_rect.height); */
1314 // if (gdk_rectangle_intersect(&group_rect, &child_rect,
1315 // &muiRenderInfo(obj)->mri_ClipRect))
1316 // DoMethodA(child, (Msg)msg);
1317 /* if (((msg->flags & MADF_DRAWUPDATE) && data->update) */
1318 /* || (data->flags & GROUP_PAGEMODE)) */
1319 MUI_Redraw(child
, MADF_DRAWOBJECT
);
1321 /* MUI_Redraw(child, msg->flags); */
1322 muiRenderInfo(obj
)->mri_ClipRect
= group_rect
;
1323 /* g_print("set back clip to (%d, %d, %d, %d)\n", */
1324 /* group_rect.x, group_rect.y, group_rect.width, group_rect.height); */
1326 /* D(bug("Group_Draw(%p) end\n", obj)); */
1328 if (data
->flags
& GROUP_VIRTUAL
&& region
&& clip
!= (APTR
) - 1)
1330 MUI_RemoveClipRegion(muiRenderInfo(obj
), clip
);
1333 data
->old_virt_offx
= data
->virt_offx
;
1334 data
->old_virt_offy
= data
->virt_offy
;
1341 #define END_MINMAX() \
1342 tmp.MaxHeight = MAX(tmp.MaxHeight, tmp.MinHeight); \
1343 tmp.MaxWidth = MAX(tmp.MaxWidth, tmp.MinWidth); \
1344 tmp.DefHeight = CLAMP(tmp.DefHeight, tmp.MinHeight, tmp.MaxHeight); \
1345 tmp.DefWidth = CLAMP(tmp.DefWidth, tmp.MinWidth, tmp.MaxWidth); \
1346 msg->MinMaxInfo->MinWidth += tmp.MinWidth; \
1347 msg->MinMaxInfo->MinHeight += tmp.MinHeight; \
1348 msg->MinMaxInfo->MaxWidth += tmp.MaxWidth; \
1349 msg->MinMaxInfo->MaxHeight += tmp.MaxHeight; \
1350 msg->MinMaxInfo->DefWidth += tmp.DefWidth; \
1351 msg->MinMaxInfo->DefHeight += tmp.DefHeight;
1354 * MinMax calculation function. When this is called,
1355 * the children of your group have already been asked
1356 * about their min/max dimension so you can use their
1357 * dimensions to calculate yours.
1360 * - Init minwidth and maxwidth with size needed for total child spacing.
1361 * - 1st pass to find maximum minimum width, to set minwidth of each child
1362 * if they should have the same width (for a row of buttons ...)
1363 * - Adjust minwidth w/o making object bigger than their max size.
1365 static void group_minmax_horiz(struct IClass
*cl
, Object
*obj
,
1366 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1368 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1371 struct MUI_MinMax tmp
;
1372 WORD maxminwidth
= 0;
1373 BOOL found_nonzero_vweight
= FALSE
;
1377 tmp
.MaxHeight
= MUI_MAXMAX
;
1378 if (data
->num_visible_children
> 0)
1380 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1381 (data
->num_visible_children
- 1) * data
->horiz_spacing
;
1385 tmp
.MinWidth
= tmp
.DefWidth
= 0;
1386 tmp
.MaxWidth
= MUI_MAXMAX
;
1389 if (data
->flags
& GROUP_SAME_WIDTH
)
1391 cstate
= (Object
*) children
->mlh_Head
;
1392 while ((child
= NextObject(&cstate
)))
1394 if (IS_HIDDEN(child
))
1396 maxminwidth
= MAX(maxminwidth
, _minwidth(child
));
1400 data
->samesize_maxmin_horiz
= maxminwidth
;
1401 /* D(bug("group_minmax_horiz(%p) : maxminwidth=%d\n", obj, maxminwidth)); */
1403 data
->horiz_weight_sum
= 0;
1404 cstate
= (Object
*) children
->mlh_Head
;
1405 while ((child
= NextObject(&cstate
)))
1409 if (IS_HIDDEN(child
))
1411 if (data
->flags
& GROUP_SAME_WIDTH
)
1413 minwidth
= MAX(maxminwidth
, _minwidth(child
));
1414 minwidth
= MIN(minwidth
, _maxwidth(child
));
1417 minwidth
= _minwidth(child
);
1418 tmp
.MinWidth
+= minwidth
;
1419 tmp
.DefWidth
+= w0_defwidth(child
);
1420 tmp
.MaxWidth
+= w0_maxwidth(child
);
1421 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, MUI_MAXMAX
);
1422 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1423 tmp
.DefHeight
= MAX(tmp
.DefHeight
, _defheight(child
));
1425 if all children have null weight then maxheight=minheight
1426 if all but some children have null weights, the maxheight
1427 is the min of all maxheights
1429 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, _maxheight(child
));
1430 data
->horiz_weight_sum
+= _hweight(child
);
1431 if (_vweight(child
) > 0)
1433 found_nonzero_vweight
= TRUE
;
1436 if (!found_nonzero_vweight
)
1438 tmp
.MaxHeight
= tmp
.MinHeight
;
1441 //if (data->flags & GROUP_VIRTUAL)
1443 //kprintf("# min %d x %d def %d x %d max %d x %d\n",
1444 // tmp.MinWidth, tmp.MinHeight,
1445 // tmp.DefWidth, tmp.DefHeight,
1446 // tmp.MaxWidth, tmp.MaxHeight);
1452 /* minmax calculation for vertical groups (see group_minmax_horiz)
1454 static void group_minmax_vert(struct IClass
*cl
, Object
*obj
,
1455 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1457 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1460 struct MUI_MinMax tmp
;
1461 WORD maxminheight
= 0;
1462 BOOL found_nonzero_hweight
= FALSE
;
1466 tmp
.MaxWidth
= MUI_MAXMAX
;
1467 if (data
->num_visible_children
> 0)
1469 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1470 (data
->num_visible_children
- 1) * data
->vert_spacing
;
1474 tmp
.MinHeight
= tmp
.DefHeight
= 0;
1475 tmp
.MaxHeight
= MUI_MAXMAX
;
1478 if (data
->flags
& GROUP_SAME_HEIGHT
)
1480 cstate
= (Object
*) children
->mlh_Head
;
1481 while ((child
= NextObject(&cstate
)))
1483 if (IS_HIDDEN(child
))
1485 maxminheight
= MAX(maxminheight
, _minheight(child
));
1489 data
->samesize_maxmin_vert
= maxminheight
;
1490 data
->vert_weight_sum
= 0;
1491 cstate
= (Object
*) children
->mlh_Head
;
1492 while ((child
= NextObject(&cstate
)))
1494 if (IS_HIDDEN(child
))
1497 if (data
->flags
& GROUP_SAME_HEIGHT
)
1498 _minheight(child
) = MIN(maxminheight
, w0_maxheight(child
));
1499 tmp
.MinHeight
+= _minheight(child
);
1500 tmp
.DefHeight
+= w0_defheight(child
);
1501 tmp
.MaxHeight
+= w0_maxheight(child
);
1502 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, MUI_MAXMAX
);
1503 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1504 tmp
.DefWidth
= MAX(tmp
.DefWidth
, _defwidth(child
));
1505 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, _maxwidth(child
));
1506 data
->vert_weight_sum
+= _vweight(child
);
1507 if (_hweight(child
) > 0)
1509 found_nonzero_hweight
= TRUE
;
1512 if (!found_nonzero_hweight
)
1514 tmp
.MaxWidth
= tmp
.MinWidth
;
1522 minmax_2d_rows_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1523 struct MUI_MinMax
*req
, WORD maxmin_height
, WORD maxdef_height
)
1529 /* do not rewind after the while, to process line by line */
1530 cstate
= (Object
*) children
->mlh_Head
;
1532 for (i
= 0; i
< data
->rows
; i
++)
1534 /* calculate min and max height of this row */
1535 int min_h
= 0, def_h
= 0, max_h
= MUI_MAXMAX
;
1536 BOOL found_nonzero_vweight
= FALSE
;
1538 data
->row_infos
[i
].weight
= 0;
1541 while ((child
= NextObject(&cstate
)))
1543 if (IS_HIDDEN(child
))
1545 if (data
->flags
& GROUP_SAME_HEIGHT
)
1547 _minheight(child
) = MIN(maxmin_height
, w0_maxheight(child
));
1548 _defheight(child
) = MIN(maxdef_height
, w0_maxheight(child
));
1550 min_h
= MAX(min_h
, _minheight(child
));
1551 def_h
= MAX(def_h
, w0_defheight(child
));
1552 max_h
= MIN(max_h
, _maxheight(child
));
1553 if (_vweight(child
) > 0)
1555 found_nonzero_vweight
= TRUE
;
1556 data
->row_infos
[i
].weight
+= _vweight(child
);
1559 if ((j
% data
->columns
) == 0)
1562 if (!found_nonzero_vweight
)
1565 max_h
= MAX(max_h
, min_h
);
1566 /* D(bug("row %d : min_h=%d max_h=%d\n", i, min_h, max_h)); */
1568 data
->row_infos
[i
].min
= min_h
;
1569 data
->row_infos
[i
].max
= max_h
;
1570 data
->vert_weight_sum
+= data
->row_infos
[i
].weight
;
1572 req
->MinHeight
+= min_h
;
1573 req
->DefHeight
+= def_h
;
1574 req
->MaxHeight
+= max_h
;
1575 if (req
->MaxHeight
> MUI_MAXMAX
)
1576 req
->MaxHeight
= MUI_MAXMAX
;
1582 minmax_2d_columns_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1583 struct MUI_MinMax
*req
, WORD maxmin_width
, WORD maxdef_width
)
1589 for (i
= 0; i
< data
->columns
; i
++)
1591 /* calculate min and max width of this column */
1592 int min_w
= 0, def_w
= 0, max_w
= MUI_MAXMAX
;
1593 BOOL found_nonzero_hweight
= FALSE
;
1595 data
->col_infos
[i
].weight
= 0;
1598 /* process all children to get children on a column */
1599 cstate
= (Object
*) children
->mlh_Head
;
1600 while ((child
= NextObject(&cstate
)))
1602 if (IS_HIDDEN(child
))
1605 if (((j
- 1) % data
->columns
) != i
)
1607 if (data
->flags
& GROUP_SAME_WIDTH
)
1609 _minwidth(child
) = MIN(maxmin_width
, w0_maxwidth(child
));
1610 _defwidth(child
) = MIN(maxdef_width
, w0_maxwidth(child
));
1612 min_w
= MAX(min_w
, _minwidth(child
));
1613 def_w
= MAX(def_w
, w0_defwidth(child
));
1615 /* this handles the case of null weight children, which limit
1616 * the max size if they're alone, but not if they are with
1617 * non-null weight obj
1619 max_w
= MIN(max_w
, _maxwidth(child
));
1620 if (_hweight(child
) > 0)
1622 found_nonzero_hweight
= TRUE
;
1623 data
->col_infos
[i
].weight
+= _hweight(child
);
1626 if (!found_nonzero_hweight
)
1629 max_w
= MAX(max_w
, min_w
);
1630 /* D(bug("col %d : min_w=%d max_w=%d\n", i, min_w, max_w)); */
1632 data
->col_infos
[i
].min
= min_w
;
1633 data
->col_infos
[i
].max
= max_w
;
1634 data
->horiz_weight_sum
+= data
->col_infos
[i
].weight
;
1636 req
->MinWidth
+= min_w
;
1637 req
->DefWidth
+= def_w
;
1638 req
->MaxWidth
+= max_w
;
1639 if (req
->MaxWidth
> MUI_MAXMAX
)
1640 req
->MaxWidth
= MUI_MAXMAX
;
1645 group_minmax_2d(struct IClass
*cl
, Object
*obj
,
1646 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1648 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1651 struct MUI_MinMax tmp
;
1659 if (data
->num_children
% data
->rows
)
1662 data
->rows
= data
->num_children
;
1665 data
->columns
= data
->num_children
/ data
->rows
;
1669 if (data
->num_children
% data
->columns
)
1672 data
->columns
= data
->num_children
;
1675 data
->rows
= data
->num_children
/ data
->columns
;
1678 if (data
->columns
< 1)
1683 if (data
->row_infos
!= NULL
)
1684 mui_free(data
->row_infos
);
1686 data
->row_infos
= mui_alloc(data
->rows
* sizeof(struct layout2d_elem
));
1687 if (NULL
== data
->row_infos
)
1690 if (data
->col_infos
!= NULL
)
1691 mui_free(data
->col_infos
);
1694 mui_alloc(data
->columns
* sizeof(struct layout2d_elem
));
1695 if (NULL
== data
->col_infos
)
1698 data
->horiz_weight_sum
= 0;
1699 data
->vert_weight_sum
= 0;
1701 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1702 (data
->rows
- 1) * data
->vert_spacing
;
1703 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1704 (data
->columns
- 1) * data
->horiz_spacing
;
1705 /* get minimum dims if same dims for all children are needed */
1711 if ((data
->flags
& GROUP_SAME_WIDTH
)
1712 || (data
->flags
& GROUP_SAME_HEIGHT
))
1714 cstate
= (Object
*) children
->mlh_Head
;
1715 while ((child
= NextObject(&cstate
)))
1717 if (!(_flags(child
) & MADF_SHOWME
))
1719 maxmin_width
= MAX(maxmin_width
, _minwidth(child
));
1720 maxmin_height
= MAX(maxmin_height
, _minheight(child
));
1721 maxdef_width
= MAX(maxdef_width
, w0_defwidth(child
));
1722 maxdef_height
= MAX(maxdef_height
, w0_defheight(child
));
1724 /* g_print("2d group: mminw=%d mminh=%d\n", */
1725 /* maxmin_width, maxmin_height); */
1727 if (data
->flags
& GROUP_SAME_HEIGHT
)
1728 data
->samesize_maxmin_vert
= maxmin_height
;
1730 data
->samesize_maxmin_vert
= 0;
1732 if (data
->flags
& GROUP_SAME_WIDTH
)
1733 data
->samesize_maxmin_horiz
= maxmin_width
;
1735 data
->samesize_maxmin_horiz
= 0;
1737 minmax_2d_rows_pass(data
, children
, &tmp
, maxmin_height
, maxdef_height
);
1738 minmax_2d_columns_pass(data
, children
, &tmp
, maxmin_width
,
1746 group_minmax_pagemode(struct IClass
*cl
, Object
*obj
,
1747 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1751 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1752 struct MUI_MinMax tmp
= { 0, 0, MUI_MAXMAX
, MUI_MAXMAX
, 0, 0 };
1754 cstate
= (Object
*) children
->mlh_Head
;
1756 D(bug("minmax_pagemode(%lx)\n", obj
, tmp
.DefWidth
));
1758 while ((child
= NextObject(&cstate
)))
1760 if (!(_flags(child
) & MADF_SHOWME
))
1763 if (child
== data
->titlegroup
)
1766 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1767 D(bug("minmax_pagemode(%p) minh child = %d tmpmin=%d\n", obj
,
1768 _minheight(child
), tmp
.MinHeight
));
1769 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1770 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, w0_maxheight(child
));
1771 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, w0_maxwidth(child
));
1772 tmp
.DefHeight
= MAX(tmp
.DefHeight
,
1773 ((w0_defheight(child
) <
1774 MUI_MAXMAX
) ? w0_defheight(child
) : tmp
.DefHeight
));
1777 ((w0_defwidth(child
) <
1778 MUI_MAXMAX
) ? w0_defwidth(child
) : tmp
.DefWidth
));
1779 D(bug("minmax_pagemode(%lx) defw = %ld\n", obj
, tmp
.DefWidth
));
1782 if (data
->titlegroup
)
1784 tmp
.MinHeight
+= _minheight(data
->titlegroup
);
1785 tmp
.MaxHeight
+= w0_maxheight(data
->titlegroup
);
1786 tmp
.DefHeight
+= w0_defheight(data
->titlegroup
);
1792 /**************************************************************************
1793 MUIM_AskMinMax : ask children about min/max sizes, then
1794 either call a hook, or the builtin method, to calculate our minmax
1795 **************************************************************************/
1796 IPTR
Group__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1797 struct MUIP_AskMinMax
*msg
)
1799 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1800 struct MUI_LayoutMsg lm
;
1801 struct MUIP_AskMinMax childMsg
;
1802 struct MUI_MinMax childMinMax
;
1805 LONG super_minwidth
, super_minheight
;
1808 * let our superclass first fill in its size with frame, inner spc etc ...
1810 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1811 super_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1812 super_minheight
= msg
->MinMaxInfo
->MinHeight
;
1817 childMsg
.MethodID
= msg
->MethodID
;
1818 childMsg
.MinMaxInfo
= &childMinMax
;
1819 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
1821 cstate
= (Object
*) lm
.lm_Children
->mlh_Head
;
1823 while ((child
= NextObject(&cstate
)))
1825 if (!(_flags(child
) & MADF_SHOWME
))
1826 /* BORDERGADGETs should handle this itself */
1829 DoMethodA(child
, (Msg
) & childMsg
);
1830 /* D(bug("*** group %lx, child %lx min=%ld,%ld\n", */
1831 /* obj, child, childMinMax.MinWidth, childMinMax.MinHeight)); */
1832 __area_finish_minmax(child
, childMsg
.MinMaxInfo
);
1836 * Use children infos to calculate group size
1838 if (data
->flags
& GROUP_PAGEMODE
)
1840 D(bug("minmax_pagemode(%p) minh initial = %d\n", obj
,
1841 msg
->MinMaxInfo
->MinHeight
));
1842 group_minmax_pagemode(cl
, obj
, lm
.lm_Children
, msg
);
1843 D(bug("minmax_pagemode(%p) minh = %d\n", obj
,
1844 msg
->MinMaxInfo
->MinHeight
));
1846 else if (data
->layout_hook
)
1848 lm
.lm_Type
= MUILM_MINMAX
;
1849 CallHookPkt(data
->layout_hook
, obj
, &lm
);
1851 if (lm
.lm_MinMax
.MaxHeight
< lm
.lm_MinMax
.MinHeight
)
1852 lm
.lm_MinMax
.MaxHeight
= lm
.lm_MinMax
.MinHeight
;
1853 if (lm
.lm_MinMax
.DefHeight
< lm
.lm_MinMax
.MinHeight
)
1854 lm
.lm_MinMax
.DefHeight
= lm
.lm_MinMax
.MinHeight
;
1855 if (lm
.lm_MinMax
.MaxWidth
< lm
.lm_MinMax
.MinWidth
)
1856 lm
.lm_MinMax
.MaxWidth
= lm
.lm_MinMax
.MinWidth
;
1857 if (lm
.lm_MinMax
.DefWidth
< lm
.lm_MinMax
.MinWidth
)
1858 lm
.lm_MinMax
.DefWidth
= lm
.lm_MinMax
.MinWidth
;
1860 //kprintf("### min %d x %d def %d x %d max %d x %d\n",
1861 // msg->MinMaxInfo->MinWidth,
1862 // msg->MinMaxInfo->MinHeight,
1863 // msg->MinMaxInfo->DefWidth,
1864 // msg->MinMaxInfo->DefHeight,
1865 // msg->MinMaxInfo->MaxWidth,
1866 // msg->MinMaxInfo->MaxHeight);
1868 msg
->MinMaxInfo
->MinWidth
+= lm
.lm_MinMax
.MinWidth
;
1869 msg
->MinMaxInfo
->MinHeight
+= lm
.lm_MinMax
.MinHeight
;
1870 msg
->MinMaxInfo
->MaxWidth
+= lm
.lm_MinMax
.MaxWidth
;
1871 if (msg
->MinMaxInfo
->MaxWidth
> MUI_MAXMAX
)
1872 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1873 msg
->MinMaxInfo
->MaxHeight
+= lm
.lm_MinMax
.MaxHeight
;
1874 if (msg
->MinMaxInfo
->MaxHeight
> MUI_MAXMAX
)
1875 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1876 msg
->MinMaxInfo
->DefWidth
+= lm
.lm_MinMax
.DefWidth
;
1877 msg
->MinMaxInfo
->DefHeight
+= lm
.lm_MinMax
.DefHeight
;
1879 //kprintf("#### min %d x %d def %d x %d max %d x %d\n",
1880 // msg->MinMaxInfo->MinWidth,
1881 // msg->MinMaxInfo->MinHeight,
1882 // msg->MinMaxInfo->DefWidth,
1883 // msg->MinMaxInfo->DefHeight,
1884 // msg->MinMaxInfo->MaxWidth,
1885 // msg->MinMaxInfo->MaxHeight);
1890 if ((data
->rows
== 1) && (data
->columns
== 1))
1892 data
->num_visible_children
=
1893 Group_GetNumVisibleChildren(data
, lm
.lm_Children
);
1894 if (data
->flags
& GROUP_HORIZ
)
1895 group_minmax_horiz(cl
, obj
, lm
.lm_Children
, msg
);
1897 group_minmax_vert(cl
, obj
, lm
.lm_Children
, msg
);
1901 group_minmax_2d(cl
, obj
, lm
.lm_Children
, msg
);
1905 if (data
->flags
& GROUP_VIRTUAL
)
1907 data
->saved_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1908 data
->saved_minheight
= msg
->MinMaxInfo
->MinHeight
;
1909 msg
->MinMaxInfo
->MinWidth
= super_minwidth
+ 2;
1910 msg
->MinMaxInfo
->MinHeight
= super_minheight
+ 2;
1912 //kprintf("## min %d x %d def %d x %d max %d x %d\n",
1913 // msg->MinMaxInfo->MinWidth,
1914 // msg->MinMaxInfo->MinHeight,
1915 // msg->MinMaxInfo->DefWidth,
1916 // msg->MinMaxInfo->DefHeight,
1917 // msg->MinMaxInfo->MaxWidth,
1918 // msg->MinMaxInfo->MaxHeight);
1927 // enforce minmax constraint, but also update total growable/shrinkable weights
1928 // while we're at it
1929 static void Layout1D_minmax_constraint(WORD
*sizep
, WORD minsize
,
1930 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
1931 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
, WORD samesize
)
1933 WORD size
= *sizep
, remain
= *remainp
,
1934 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
1935 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
1937 /* D(bug("L1D_minmax_c size=%d min=%d max=%d w=%d ss=%d\n", */
1938 /* size, minsize, maxsize, */
1939 /* weight, samesize)); */
1941 if ((samesize
> 0) && (weight
== 0))
1943 remain
+= size
- samesize
;
1949 if (size
<= minsize
) // too little
1951 remain
+= size
- minsize
;
1954 if (size
== maxsize
)
1957 else if (size
>= maxsize
) // too big
1959 remain
+= size
- maxsize
;
1964 if (!((samesize
> 0) && (weight
== 0)))
1967 weightgrow
+= weight
;
1969 weightshrink
+= weight
;
1974 *sizegrowp
= sizegrow
;
1975 *sizeshrinkp
= sizeshrink
;
1976 *weightgrowp
= weightgrow
;
1977 *weightshrinkp
= weightshrink
;
1981 // redistribute excess size to growable child, or reduce size of a shrinkable
1983 static void Layout1D_redistribution(WORD
*sizep
, WORD minsize
,
1984 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
1985 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
)
1987 WORD size
= *sizep
, remain
= *remainp
,
1988 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
1989 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
1994 if ((remain
> 0) && (size
< maxsize
))
1998 newsize
= (sizegrow
* weight
+ weightgrow
/ 2) / weightgrow
;
2000 /* D(bug("newsize=%ld == size_growa=%ld * w=%ld / weight_grow=%d\n", */
2001 /* newsize, sizegrow, weight, weightgrow)); */
2003 /* take care of off-by-1 errors that may toggle remainder sign
2004 * by ensuring convergence to 0
2006 if (remain
- newsize
+ size
< 0)
2008 /* D(bug("adding remainder=%d => size = %d\n", */
2009 /* remain, size + remain)); */
2015 remain
-= newsize
- size
;
2018 weightgrow
-= weight
;
2021 else if ((remain
< 0) && (size
> minsize
))
2025 newsize
= (sizeshrink
* weight
+ weightshrink
/ 2) / weightshrink
;
2027 /* D(bug("newsize=%ld == size_shrinkables=%ld * w=%ld " */
2028 /* "/ weight_shrinkables=%d\n", */
2029 /* newsize, sizeshrink, weight, weightshrink)); */
2031 if (remain
- newsize
+ size
> 0)
2033 /* D(bug("adding remainder=%d => size = %d\n", */
2034 /* remain, size + remain)); */
2040 remain
-= newsize
- size
;
2043 weightshrink
-= weight
;
2049 *sizegrowp
= sizegrow
;
2050 *sizeshrinkp
= sizeshrink
;
2051 *weightgrowp
= weightgrow
;
2052 *weightshrinkp
= weightshrink
;
2056 // 2 passes at most, less on average (0.5 or 1.5), each does
2057 // - a minmax clamping, evenutally adding to a remainder
2058 // (remainder = missing (underflow) or remaining (overflow) space compared
2059 // to ideal sizes where children fill the whole group)
2060 // - a redistribution of the remainder, by growing (pos. remainder) or
2061 // shrinking (neg. remainder) children able to support it.
2063 // Occasionnaly the first time the redistribution is done, the minmax
2064 // constraint can be broken, thus the extra pass to check and eventually
2065 // redistribute. The second redistribution never breaks minmax constraint
2066 // (there should be a mathematical proof, but feel free to prove me wrong
2068 static void Layout1D_minmax_constraints_and_redistrib(struct MinList
2069 *children
, WORD total_size
, WORD remainder
, WORD samesize
,
2076 for (i
= 0; i
< 2; i
++)
2078 WORD size_growables
= total_size
;
2079 WORD size_shrinkables
= total_size
;
2080 ULONG weight_growables
= 0;
2081 ULONG weight_shrinkables
= 0;
2083 /* D(bug("start : rem=%ld, A=%ld, size_growables=%ld, " */
2084 /* "size_shrinkables=%ld\n", */
2085 /* remainder, total_size, size_growables, size_shrinkables)); */
2087 // minmax constraints
2088 cstate
= (Object
*) children
->mlh_Head
;
2089 while ((child
= NextObject(&cstate
)))
2091 /* WORD old_size; */
2093 if (IS_HIDDEN(child
))
2098 /* old_size = _width(child); */
2100 Layout1D_minmax_constraint(&_width(child
), _minwidth(child
),
2101 _maxwidth(child
), &remainder
, &size_growables
,
2102 &size_shrinkables
, &weight_growables
,
2103 &weight_shrinkables
, _hweight(child
), samesize
);
2105 /* D(bug("loop1 on %p : width=%d was %d, rem=%d, A=%d, " */
2106 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2107 /* child, _width(child), old_size, remainder, total_size, */
2108 /* size_growables, size_shrinkables, _hweight(child), */
2109 /* _minwidth(child), _maxwidth(child))); */
2111 else // ! group_horiz
2113 /* old_size = _height(child); */
2115 Layout1D_minmax_constraint(&_height(child
),
2116 _minheight(child
), _maxheight(child
), &remainder
,
2117 &size_growables
, &size_shrinkables
, &weight_growables
,
2118 &weight_shrinkables
, _vweight(child
), samesize
);
2120 /* D(bug("loop1 on %p : h=%ld was %d, rem=%d, A=%d, " */
2121 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2122 /* child, _height(child), old_size, remainder, total_size,*/
2123 /* size_growables, size_shrinkables, _vweight(child), */
2124 /* _minheight(child), _maxheight(child))); */
2125 } // if (group_horiz)
2126 } // while child, minmax constraints
2132 /* D(bug("mid : rem=%d, A=%d, size_grow=%d, size_shrink=%d, " */
2133 /* "wg=%ld, ws=%ld\n", remainder, total_size, size_growables, */
2134 /* size_shrinkables, weight_growables, weight_shrinkables)); */
2136 // distribute remaining space to possible candidates
2137 cstate
= (Object
*) children
->mlh_Head
;
2138 while (((child
= NextObject(&cstate
)) != NULL
) && (remainder
!= 0))
2140 /* WORD old_size; */
2142 if (IS_HIDDEN(child
))
2147 /* old_size = _width(child); */
2149 Layout1D_redistribution(&_width(child
), _minwidth(child
),
2150 _maxwidth(child
), &remainder
, &size_growables
,
2151 &size_shrinkables
, &weight_growables
,
2152 &weight_shrinkables
, _hweight(child
));
2154 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2155 /* "size_grow=%d, size_shrink=%d\n", child, */
2156 /* _width(child), old_size, remainder, total_size, */
2157 /* size_growables, size_shrinkables)); */
2159 else // ! group_horiz
2161 /* old_size = _height(child); */
2163 Layout1D_redistribution(&_height(child
), _minheight(child
),
2164 _maxheight(child
), &remainder
, &size_growables
,
2165 &size_shrinkables
, &weight_growables
,
2166 &weight_shrinkables
, _vweight(child
));
2168 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2169 /* "size_grow=%d, size_shrink=%d\n", child, */
2170 /* _height(child), old_size, remainder, total_size, */
2171 /* size_growables, size_shrinkables)); */
2172 } // if (group_horiz)
2174 } // while child, redistribution
2176 /* if (remainder != 0) */
2178 /* D(bug("end : rem=%ld, A=%ld, size_grow=%ld, size_shrink=%ld\n", */
2179 /* remainder, total_size, size_growables, size_shrinkables)); */
2181 // dont break here if remainder == 0, some minmax constraints
2182 // may not be respected
2185 // to easily spot layout bugs, nothing like a (division by zero) exception
2186 /* if (remainder != 0) */
2188 /* ASSERT(remainder != 0); */
2189 /* D(bug("gonna crash, remainder = %d\n", remainder)); */
2190 /* remainder /= 0; */
2195 static void Layout1D_weight_constraint(WORD
*total_sizep
,
2196 WORD
*total_init_sizep
,
2197 ULONG
*total_weightp
, WORD
*sizep
, UWORD weight
, WORD minsize
)
2199 if (*total_weightp
> 0)
2200 *sizep
= (*total_sizep
* weight
+ *total_weightp
/ 2)
2205 *total_weightp
-= weight
;
2206 *total_sizep
-= *sizep
;
2207 *total_init_sizep
+= *sizep
;
2211 static void group_layout_vert(struct IClass
*cl
, Object
*obj
,
2212 struct MinList
*children
)
2214 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2218 WORD remainder
; /* must converge to 0 to successfully end layout */
2220 WORD total_size_backup
;
2221 WORD total_init_size
; /* total size of the ideally sized children */
2228 //kprintf("group_layout_vert: virtoff = %d,%d\n",
2229 // data->virt_offx, data->virt_offy);
2231 if (data
->flags
& GROUP_VIRTUAL
)
2234 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2235 _maxwidth(obj
) - _subwidth(obj
));
2236 data
->virt_mheight
=
2237 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2238 _maxheight(obj
) - _subheight(obj
));
2240 layout_width
= data
->virt_mwidth
;
2241 layout_height
= data
->virt_mheight
;
2245 layout_width
= _mwidth(obj
);
2246 layout_height
= _mheight(obj
);
2249 total_weight
= data
->vert_weight_sum
;
2250 total_init_size
= 0;
2252 layout_height
- (data
->num_visible_children
-
2253 1) * data
->vert_spacing
;
2254 total_size_backup
= total_size
;
2256 /* D(bug("\nvert layout for %p, A=%d W=%ld\n", */
2257 /* obj, total_size, total_weight)); */
2259 // weight constraints
2260 // calculate ideal size for each object, and total ideal size
2261 cstate
= (Object
*) children
->mlh_Head
;
2262 while ((child
= NextObject(&cstate
)))
2264 if (IS_HIDDEN(child
))
2267 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2268 &total_weight
, &_height(child
), _vweight(child
),
2270 /* D(bug("child %p : ideal=%d w=%ld\n", */
2271 /* child, _height(child), _vweight(child))); */
2272 } // while child, weight constraints
2274 total_size
= total_size_backup
;
2275 remainder
= total_size
- total_init_size
;
2277 if (data
->flags
& GROUP_VIRTUAL
)
2279 /* This is also true for non virtual groups, but if this would be the
2280 ** case then there is a bug in the layout function
2286 Layout1D_minmax_constraints_and_redistrib(children
,
2289 (data
->flags
& GROUP_SAME_HEIGHT
) ? data
->samesize_maxmin_vert
: 0,
2293 cstate
= (Object
*) children
->mlh_Head
;
2294 while ((child
= NextObject(&cstate
)))
2296 if (IS_HIDDEN(child
))
2299 width
= MIN(_maxwidth(child
), layout_width
);
2300 width
= MAX(width
, _minwidth(child
));
2301 left
= (layout_width
- width
) / 2;
2303 /* D(bug("child %p -> layout %d x %d\n", */
2304 /* child, width, _height(child))); */
2305 if (!MUI_Layout(child
, left
, top
, width
, _height(child
), 0))
2307 top
+= data
->vert_spacing
+ _height(child
);
2313 static void group_layout_horiz(struct IClass
*cl
, Object
*obj
,
2314 struct MinList
*children
)
2316 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2320 WORD remainder
; /* must converge to 0 to succesfully end layout */
2322 WORD total_size_backup
;
2323 WORD total_init_size
; /* total size of the ideally sized children */
2330 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2331 // data->virt_offx, data->virt_offy);
2333 if (data
->flags
& GROUP_VIRTUAL
)
2336 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2337 _maxwidth(obj
) - _subwidth(obj
));
2338 data
->virt_mheight
=
2339 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2340 _maxheight(obj
) - _subheight(obj
));
2342 layout_width
= data
->virt_mwidth
;
2343 layout_height
= data
->virt_mheight
;
2345 //kprintf("group_layout_horiz: layoutsize %d x %d "
2346 // " virtsize %d x %d msize %d x %d\n",
2347 // layout_width, layout_height, data->virt_mwidth,
2348 // data->virt_mheight,
2349 // _mwidth(obj), _mheight(obj));
2353 layout_width
= _mwidth(obj
);
2354 layout_height
= _mheight(obj
);
2357 total_weight
= data
->horiz_weight_sum
;
2358 total_init_size
= 0;
2360 layout_width
- (data
->num_visible_children
-
2361 1) * data
->horiz_spacing
;
2362 total_size_backup
= total_size
;
2364 /* D(bug("\nhoriz layout for %p, A=%d W=%ld\n", */
2365 /* obj, total_size, total_weight)); */
2367 // weight constraints
2368 // calculate ideal size for each object, and total ideal size
2369 cstate
= (Object
*) children
->mlh_Head
;
2370 while ((child
= NextObject(&cstate
)))
2372 if (IS_HIDDEN(child
))
2375 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2376 &total_weight
, &_width(child
), _hweight(child
),
2378 /* D(bug("child %p : ideal=%d w=%ld\n", */
2379 /* child, _width(child), _hweight(child))); */
2380 } // while child, weight constraints
2382 total_size
= total_size_backup
;
2383 if (data
->horiz_weight_sum
> 0)
2384 remainder
= total_size
- total_init_size
;
2388 if (data
->flags
& GROUP_VIRTUAL
)
2390 /* This is also true for non virtual groups, but if this would be the
2391 ** case then there is a bug in the layout function
2397 Layout1D_minmax_constraints_and_redistrib(children
,
2400 (data
->flags
& GROUP_SAME_WIDTH
) ? data
->samesize_maxmin_horiz
: 0,
2404 cstate
= (Object
*) children
->mlh_Head
;
2405 while ((child
= NextObject(&cstate
)))
2407 if (IS_HIDDEN(child
))
2410 height
= MIN(_maxheight(child
), layout_height
);
2411 height
= MAX(height
, _minheight(child
));
2412 top
= (layout_height
- height
) / 2;
2414 /* D(bug("child %p -> layout %d x %d\n", */
2415 /* child, _width(child), height)); */
2416 if (!MUI_Layout(child
, left
, top
, _width(child
), height
, 0))
2418 left
+= data
->horiz_spacing
+ _width(child
);
2424 static void Layout2D_weight_constraint(struct MUI_GroupData
*data
,
2425 struct layout2d_elem
*row_infos
,
2426 struct layout2d_elem
*col_infos
,
2427 WORD total_size_height
, WORD total_size_width
,
2428 WORD
*total_init_height
, WORD
*total_init_width
)
2431 ULONG total_weight_vert
= data
->vert_weight_sum
;
2432 ULONG total_weight_horiz
= data
->horiz_weight_sum
;
2434 *total_init_height
= 0;
2435 *total_init_width
= 0;
2437 /* calc row heights */
2438 for (i
= 0; i
< data
->rows
; i
++)
2440 if (total_weight_vert
> 0)
2442 (total_size_height
* row_infos
[i
].weight
+
2443 total_weight_vert
/ 2) / total_weight_vert
;
2445 row_infos
[i
].dim
= row_infos
[i
].min
;
2447 /* D(bug("l2 row %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2448 /* i, row_infos[i].dim, */
2449 /* row_infos[i].weight, total_size_height, total_weight_vert)); */
2451 total_weight_vert
-= row_infos
[i
].weight
;
2452 total_size_height
-= row_infos
[i
].dim
;
2453 *total_init_height
+= row_infos
[i
].dim
;
2456 /* calc columns widths */
2457 for (i
= 0; i
< data
->columns
; i
++)
2459 if (total_weight_horiz
)
2461 (total_size_width
* col_infos
[i
].weight
+
2462 total_weight_horiz
/ 2) / total_weight_horiz
;
2464 col_infos
[i
].dim
= col_infos
[i
].min
;
2466 /* D(bug("l2 col %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2467 /* i, col_infos[i].dim, */
2468 /* col_infos[i].weight, total_size_width, total_weight_horiz)); */
2470 total_weight_horiz
-= col_infos
[i
].weight
;
2471 total_size_width
-= col_infos
[i
].dim
;
2472 *total_init_width
+= col_infos
[i
].dim
;
2478 static void Layout2D_minmax_constraints_and_redistrib(struct layout2d_elem
2479 *infos
, WORD nitems
, WORD total_size
, WORD samesize
, WORD remainder
)
2483 /* D(bug("L2D mc&r n=%d A=%d ss=%d rem=%d\n", */
2484 /* nitems, total_size, samesize, remainder)); */
2486 for (j
= 0; j
< 2; j
++)
2488 WORD size_growables
= total_size
;
2489 WORD size_shrinkables
= total_size
;
2490 ULONG weight_growables
= 0;
2491 ULONG weight_shrinkables
= 0;
2492 /* WORD old_size; */
2495 // minmax constraints
2496 for (i
= 0; i
< nitems
; i
++)
2498 /* old_size = infos[i].dim; */
2500 /* D(bug("bef loop1 on %d : size=%d, rem=%d, A=%d, " */
2501 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2502 /* i, infos[i].dim, remainder, total_size, */
2503 /* size_growables, size_shrinkables, infos[i].weight, */
2504 /* infos[i].min, infos[i].max)); */
2506 Layout1D_minmax_constraint(&infos
[i
].dim
, infos
[i
].min
,
2507 infos
[i
].max
, &remainder
, &size_growables
,
2508 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2509 infos
[i
].weight
, samesize
);
2511 /* D(bug("loop1 on %d : size=%d was %d, rem=%d, A=%d, " */
2512 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2513 /* i, infos[i].dim, old_size, remainder, total_size, */
2514 /* size_growables, size_shrinkables, infos[i].weight, */
2515 /* infos[i].min, infos[i].max)); */
2521 for (i
= 0; i
< nitems
; i
++)
2523 /* old_size = infos[i].dim; */
2525 /* D(bug("bef loop2 on %d : size=%d, rem=%d, A=%d, " */
2526 /* "size_grow=%d, size_shrink=%d\n", i, */
2527 /* infos[i].dim, remainder, total_size, */
2528 /* size_growables, size_shrinkables)); */
2530 Layout1D_redistribution(&infos
[i
].dim
, infos
[i
].min
,
2531 infos
[i
].max
, &remainder
, &size_growables
,
2532 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2535 /* D(bug("loop2 on %d : size=%d was %d, rem=%d, A=%d, " */
2536 /* "size_grow=%d, size_shrink=%d\n", i, */
2537 /* infos[i].dim, old_size, remainder, total_size, */
2538 /* size_growables, size_shrinkables)); */
2544 layout_2d_distribute_space(struct MUI_GroupData
*data
,
2545 struct layout2d_elem
*row_infos
,
2546 struct layout2d_elem
*col_infos
,
2547 struct MinList
*children
, LONG left_start
, LONG top_start
)
2558 * pass 2 : distribute space
2560 cstate
= (Object
*) children
->mlh_Head
;
2563 for (i
= 0; i
< data
->rows
; i
++)
2565 /* left start for child layout in this row */
2568 /* max height for children in this row */
2569 row_height
= row_infos
[i
].dim
;
2571 /* for each column */
2572 while ((child
= NextObject(&cstate
)))
2579 if (IS_HIDDEN(child
))
2581 /* max width for children in this column */
2582 col_width
= col_infos
[j
].dim
;
2584 /* center child if col width is bigger than child maxwidth */
2585 cwidth
= MIN(_maxwidth(child
), col_width
);
2586 cwidth
= MAX(cwidth
, _minwidth(child
));
2587 cleft
= left
+ (col_width
- cwidth
) / 2;
2589 /* center child if row height is bigger than child maxheight */
2590 cheight
= MIN(_maxheight(child
), row_height
);
2591 cheight
= MAX(cheight
, _minheight(child
));
2592 ctop
= top
+ (row_height
- cheight
) / 2;
2594 /* g_print("layout %d %d %d %d\n", cleft, ctop, cwidth, cheight); */
2595 /* D(bug("2DL/child %p -> layout %d x %d\n", */
2596 /* child, cwidth, cheight)); */
2597 if (!MUI_Layout(child
, cleft
, ctop
, cwidth
, cheight
, 0))
2600 left
+= data
->horiz_spacing
+ col_width
;
2603 if ((j
% data
->columns
) == 0)
2607 top
+= data
->vert_spacing
+ row_height
;
2614 * all children in the same row have the same maximum height
2615 * all children in the same column have the same maximum height
2616 * if a child maximum size is smaller than the biggest minimum size,
2617 * the chid will be centered in the remaining space.
2619 * for each row, determine its height allocation
2620 * weight ? the vertical weight of a row, if no fixed-height child
2621 * in the row, is the sum of all vertical weights of children
2622 * all row members will have the same height
2624 * for each column, determine its width allocation
2625 * all column members will have the same width
2627 /* Write a proper hook function */
2629 group_layout_2d(struct IClass
*cl
, Object
*obj
, struct MinList
*children
)
2631 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2632 WORD left_start
= 0;
2634 WORD total_size_height
=
2635 _mheight(obj
) - (data
->rows
- 1) * data
->vert_spacing
;
2636 WORD total_size_width
=
2637 _mwidth(obj
) - (data
->columns
- 1) * data
->horiz_spacing
;
2638 WORD total_init_height
;
2639 WORD total_init_width
;
2640 WORD remainder_height
;
2641 WORD remainder_width
;
2645 if (data
->rows
== 0 || data
->columns
== 0)
2647 if (data
->num_children
% data
->rows
2648 || data
->num_children
% data
->columns
)
2650 if (data
->row_infos
== NULL
|| data
->col_infos
== NULL
)
2653 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2654 // data->virt_offx, data->virt_offy);
2656 if (data
->flags
& GROUP_VIRTUAL
)
2659 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2660 _maxwidth(obj
) - _subwidth(obj
));
2661 data
->virt_mheight
=
2662 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2663 _maxheight(obj
) - _subheight(obj
));
2665 layout_width
= data
->virt_mwidth
;
2666 layout_height
= data
->virt_mheight
;
2670 layout_width
= _mwidth(obj
);
2671 layout_height
= _mheight(obj
);
2675 layout_height
- (data
->rows
- 1) * data
->vert_spacing
;
2677 layout_width
- (data
->columns
- 1) * data
->horiz_spacing
;
2681 // weight constraints
2682 Layout2D_weight_constraint(data
, data
->row_infos
, data
->col_infos
,
2683 total_size_height
, total_size_width
,
2684 &total_init_height
, &total_init_width
);
2686 remainder_height
= total_size_height
- total_init_height
;
2687 remainder_width
= total_size_width
- total_init_width
;
2689 Layout2D_minmax_constraints_and_redistrib(data
->row_infos
,
2690 data
->rows
, total_size_height
,
2691 /* (data->flags & GROUP_SAME_HEIGHT) ? data->samesize_maxmin_vert : 0, */
2692 0, remainder_height
);
2694 Layout2D_minmax_constraints_and_redistrib(data
->col_infos
,
2695 data
->columns
, total_size_width
,
2696 /* (data->flags & GROUP_SAME_WIDTH) ? data->samesize_maxmin_horiz : 0, */
2697 0, remainder_width
);
2699 layout_2d_distribute_space(data
, data
->row_infos
, data
->col_infos
,
2700 children
, left_start
, top_start
);
2704 /* Write a proper hook function */
2705 static void group_layout_pagemode(struct IClass
*cl
, Object
*obj
,
2706 struct MinList
*children
)
2708 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2713 int w
, h
, yoffset
= 0;
2715 if (data
->flags
& GROUP_VIRTUAL
)
2718 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2719 _maxwidth(obj
) - _subwidth(obj
));
2720 data
->virt_mheight
=
2721 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2722 _maxheight(obj
) - _subheight(obj
));
2724 layout_width
= data
->virt_mwidth
;
2725 layout_height
= data
->virt_mheight
;
2729 layout_width
= _mwidth(obj
);
2730 layout_height
= _mheight(obj
);
2733 if (data
->titlegroup
)
2735 yoffset
= _minheight(data
->titlegroup
);
2736 layout_height
-= yoffset
;
2739 cstate
= (Object
*) children
->mlh_Head
;
2740 while ((child
= NextObject(&cstate
)))
2742 w
= MIN(layout_width
, _maxwidth(child
));
2743 h
= MIN(layout_height
, _maxheight(child
));
2745 if (child
== data
->titlegroup
)
2747 MUI_Layout(child
, (layout_width
- w
) / 2, 0, w
, yoffset
, 0);
2751 D(bug("PM/child %p -> layout %d x %d\n", child
, w
, h
));
2752 MUI_Layout(child
, (layout_width
- w
) / 2,
2753 yoffset
+ (layout_height
- h
) / 2, w
, h
, 0);
2759 /**************************************************************************
2761 Either use a given layout hook, or the builtin method.
2762 **************************************************************************/
2763 IPTR
Group__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
2764 struct MUIP_Layout
*msg
)
2766 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2767 struct MUI_LayoutMsg lm
= { 0 };
2769 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
2770 if (data
->flags
& GROUP_PAGEMODE
)
2772 group_layout_pagemode(cl
, obj
, lm
.lm_Children
);
2774 else if (data
->layout_hook
)
2776 lm
.lm_Type
= MUILM_LAYOUT
;
2777 lm
.lm_Layout
.Width
= _mwidth(obj
);
2778 lm
.lm_Layout
.Height
= _mheight(obj
);
2780 CallHookPkt(data
->layout_hook
, obj
, &lm
);
2782 if (data
->flags
& GROUP_VIRTUAL
)
2784 data
->virt_mwidth
= lm
.lm_Layout
.Width
;
2785 data
->virt_mheight
= lm
.lm_Layout
.Height
;
2790 if ((data
->rows
== 1) && (data
->columns
== 1))
2792 if (data
->flags
& GROUP_HORIZ
)
2793 group_layout_horiz(cl
, obj
, lm
.lm_Children
);
2795 group_layout_vert(cl
, obj
, lm
.lm_Children
);
2798 group_layout_2d(cl
, obj
, lm
.lm_Children
);
2801 if (data
->flags
& GROUP_VIRTUAL
)
2803 WORD new_virt_offx
, new_virt_offy
;
2805 new_virt_offx
= data
->virt_offx
;
2806 new_virt_offy
= data
->virt_offy
;
2808 if (new_virt_offx
+ _mwidth(obj
) > data
->virt_mwidth
)
2810 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
2812 if (new_virt_offx
< 0)
2815 if (new_virt_offy
+ _mheight(obj
) > data
->virt_mheight
)
2817 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
2819 if (new_virt_offy
< 0)
2822 if (new_virt_offx
!= data
->virt_offx
)
2824 nfset(obj
, MUIA_Virtgroup_Left
, new_virt_offx
);
2827 if (new_virt_offy
!= data
->virt_offy
)
2829 nfset(obj
, MUIA_Virtgroup_Top
, new_virt_offy
);
2837 /**************************************************************************
2839 **************************************************************************/
2840 IPTR
Group__MUIM_Show(struct IClass
*cl
, Object
*obj
,
2841 struct MUIP_Show
*msg
)
2843 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2846 struct MinList
*ChildList
= NULL
;
2848 /* If msg is NULL, we won't want that the super method actually gets
2851 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2853 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2854 cstate
= (Object
*) ChildList
->mlh_Head
;
2856 if (data
->flags
& GROUP_PAGEMODE
)
2859 while ((child
= NextObject(&cstate
)))
2861 if (child
== data
->titlegroup
)
2863 DoShowMethod(child
);
2864 continue; /* Title group is not counted as page */
2867 if (page
== data
->active_page
)
2869 DoShowMethod(child
);
2877 while ((child
= NextObject(&cstate
)))
2879 if (!(data
->flags
& GROUP_VIRTUAL
) ||
2880 IsObjectVisible(child
, MUIMasterBase
))
2882 if (_flags(child
) & MADF_SHOWME
)
2883 DoShowMethod(child
);
2890 /**************************************************************************
2892 **************************************************************************/
2893 IPTR
Group__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
2894 struct MUIP_Hide
*msg
)
2896 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2899 struct MinList
*ChildList
= NULL
;
2901 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2902 cstate
= (Object
*) ChildList
->mlh_Head
;
2904 if (data
->flags
& GROUP_PAGEMODE
)
2907 while ((child
= NextObject(&cstate
)))
2909 if (child
== data
->titlegroup
)
2911 DoHideMethod(child
);
2912 continue; /* Title group is not counted as page */
2915 if (page
== data
->active_page
)
2917 DoHideMethod(child
);
2925 while ((child
= NextObject(&cstate
)))
2927 if (_flags(child
) & MADF_CANDRAW
)
2928 DoHideMethod(child
);
2932 /* If msg is NULL, we won't want that the super method actually gets
2935 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2940 * MUIM_FindUData : tests if the MUIA_UserData of the object
2941 * contains the given <udata> and returns the object pointer in this case.
2943 IPTR
Group__MUIM_FindUData(struct IClass
*cl
, Object
*obj
,
2944 struct MUIP_FindUData
*msg
)
2946 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2948 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2951 return DoMethodA(data
->family
, (Msg
) msg
);
2956 * MUIM_GetUData : This method tests if the MUIA_UserData of the object
2957 * contains the given <udata> and gets <attr> to <storage> for itself
2960 IPTR
Group__MUIM_GetUData(struct IClass
*cl
, Object
*obj
,
2961 struct MUIP_GetUData
*msg
)
2963 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2965 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2967 get(obj
, msg
->attr
, msg
->storage
);
2971 return DoMethodA(data
->family
, (Msg
) msg
);
2976 * MUIM_SetUData : This method tests if the MUIA_UserData of the object
2977 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2979 IPTR
Group__MUIM_SetUData(struct IClass
*cl
, Object
*obj
,
2980 struct MUIP_SetUData
*msg
)
2982 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2984 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2985 set(obj
, msg
->attr
, msg
->val
);
2987 DoMethodA(data
->family
, (Msg
) msg
);
2993 * MUIM_SetUDataOnce : This method tests if the MUIA_UserData of the object
2994 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2995 * Stop after the first udata found.
2997 IPTR
Group__MUIM_SetUDataOnce(struct IClass
*cl
, Object
*obj
,
2998 struct MUIP_SetUData
*msg
)
3000 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3002 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
3004 set(obj
, msg
->attr
, msg
->val
);
3007 return DoMethodA(data
->family
, (Msg
) msg
);
3010 /**************************************************************************
3011 MUIM_DragQueryExtented
3012 **************************************************************************/
3013 IPTR
Group__MUIM_DragQueryExtended(struct IClass
*cl
, Object
*obj
,
3014 struct MUIP_DragQueryExtended
*msg
)
3016 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3020 struct MinList
*ChildList
= NULL
;
3022 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3023 cstate
= (Object
*) ChildList
->mlh_Head
;
3024 while ((child
= NextObject(&cstate
)))
3026 if (!(_flags(child
) & MADF_CANDRAW
))
3029 if ((found_obj
= (Object
*) DoMethodA(child
, (Msg
) msg
)))
3030 return (IPTR
) found_obj
;
3032 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3035 /**************************************************************************
3037 **************************************************************************/
3038 IPTR
Group__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
3039 struct MUIP_HandleEvent
*msg
)
3041 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3043 /* check this, otherwise a superclass who has IDCMP_MOUSEBUTTONS
3044 eventhandler might call DoSuperMethod, and this function gets
3045 called even when he have not added any eventhandler */
3047 if ((data
->flags
& GROUP_VIRTUAL
) && msg
->imsg
)
3049 switch (msg
->imsg
->Class
)
3051 case IDCMP_MOUSEBUTTONS
:
3052 /* For virtual groups */
3053 if (msg
->imsg
->Code
== SELECTDOWN
)
3055 if (_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
3056 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
3059 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3060 (IPTR
) & data
->ehn
);
3061 data
->ehn
.ehn_Events
|= IDCMP_INTUITICKS
;
3062 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3063 (IPTR
) & data
->ehn
);
3068 if (data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
)
3070 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3071 (IPTR
) & data
->ehn
);
3072 data
->ehn
.ehn_Events
&= ~IDCMP_INTUITICKS
;
3073 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3074 (IPTR
) & data
->ehn
);
3079 case IDCMP_INTUITICKS
:
3080 if (!(data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
))
3083 if (!(_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
3084 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
3087 LONG new_virt_offx
= data
->virt_offx
;
3088 LONG new_virt_offy
= data
->virt_offy
;
3090 if (msg
->imsg
->MouseX
< _mleft(obj
))
3093 if (new_virt_offx
>= 4)
3098 else if (msg
->imsg
->MouseX
> _mright(obj
))
3102 if (new_virt_offx
> data
->virt_mwidth
- _mwidth(obj
))
3103 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
3104 if (new_virt_offx
< 0)
3108 if (msg
->imsg
->MouseY
< _mtop(obj
))
3111 if (new_virt_offy
>= 4)
3116 else if (msg
->imsg
->MouseY
> _mbottom(obj
))
3120 if (new_virt_offy
> data
->virt_mheight
- _mheight(obj
))
3121 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
3122 if (new_virt_offy
< 0)
3126 if (new_virt_offx
!= data
->virt_offx
3127 || new_virt_offy
!= data
->virt_offy
)
3130 MUIA_Virtgroup_Left
, new_virt_offx
,
3131 MUIA_Virtgroup_Top
, new_virt_offy
,
3132 MUIA_Group_Forward
, FALSE
, TAG_DONE
);
3142 /**************************************************************************
3144 **************************************************************************/
3145 IPTR
Group__MUIM_DrawBackground(struct IClass
*cl
, Object
*obj
,
3146 struct MUIP_DrawBackground
*msg
)
3148 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3150 if (data
->flags
& GROUP_VIRTUAL
)
3152 struct MUIP_DrawBackground msg2
= *msg
;
3154 msg2
.xoffset
+= data
->virt_offx
;
3155 msg2
.yoffset
+= data
->virt_offy
;
3157 return DoSuperMethodA(cl
, obj
, (Msg
) & msg2
);
3160 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3163 /**************************************************************************
3165 Find the given object or return NULL
3166 **************************************************************************/
3167 IPTR
Group__MUIM_FindAreaObject(struct IClass
*cl
, Object
*obj
,
3168 struct MUIP_FindAreaObject
*msg
)
3170 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3173 struct MinList
*ChildList
= NULL
;
3176 if (msg
->obj
== obj
)
3179 // it's one of my children ?
3180 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3181 cstate
= (Object
*) ChildList
->mlh_Head
;
3182 while ((child
= NextObject(&cstate
)))
3184 if (msg
->obj
== child
)
3185 return (IPTR
) child
;
3188 // let the children find it
3189 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3190 cstate
= (Object
*) ChildList
->mlh_Head
;
3191 while ((child
= NextObject(&cstate
)))
3193 Object
*res
= (Object
*) DoMethodA(child
, (Msg
) msg
);
3201 /**************************************************************************
3202 MUIM_Export : to export an object's "contents" to a dataspace object.
3203 **************************************************************************/
3204 static IPTR
Group__MUIM_Export(struct IClass
*cl
, Object
*obj
,
3205 struct MUIP_Export
*msg
)
3207 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3210 struct MinList
*ChildList
= NULL
;
3212 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3216 cstate
= (Object
*) ChildList
->mlh_Head
;
3217 while ((child
= NextObject(&cstate
)))
3219 DoMethodA(child
, (Msg
) msg
);
3226 /**************************************************************************
3227 MUIM_Import : to import an object's "contents" from a dataspace object.
3228 **************************************************************************/
3229 static IPTR
Group__MUIM_Import(struct IClass
*cl
, Object
*obj
,
3230 struct MUIP_Import
*msg
)
3232 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3235 struct MinList
*ChildList
= NULL
;
3237 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3241 cstate
= (Object
*) ChildList
->mlh_Head
;
3242 while ((child
= NextObject(&cstate
)))
3244 DoMethodA(child
, (Msg
) msg
);
3250 /**************************************************************************
3251 MUIM_Notify - disabled now because previous Zune versions had a OM_GET
3252 check in MUIM_Notify which is no longer the case
3253 **************************************************************************/
3255 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3256 struct MUIP_Notify
*msg
)
3258 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3261 struct MinList
*ChildList
;
3263 /* Try at first if understand the message our self
3264 ** We disable the forwarding of the OM_GET message
3265 ** as the MUIM_Notify otherwise would "think" that
3266 ** the group class actually understands the attribute
3267 ** although a child does this only
3269 data
->dont_forward_get
= 1;
3270 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
3272 data
->dont_forward_get
= 0;
3276 /* We ourselves didn't understand the notify tag so we try the
3278 data
->dont_forward_get
= 0;
3280 get(data
->family
, MUIA_Family_List
, (IPTR
*) & (ChildList
));
3281 cstate
= (Object
*) ChildList
->mlh_Head
;
3282 while ((child
= NextObject(&cstate
)))
3284 if (DoMethodA(child
, (Msg
) msg
))
3292 /* Notes about Group_Notify() and echo notification problem:
3293 It was discovered that MUI seems to have some special handling for group class
3294 which will drop notifications on the children which are found to not
3295 understand the attribute.
3297 This is done by checking if an OM_GET on the child returns TRUE.
3298 There's a little problem here because it is not known how big the storage
3299 needed for the attribute in question will be. Almost no class uses anything
3300 bigger than one IPTR. For "big" attributes those return a pointer to the data,
3301 not the data itself. Unfortuntely there are some exceptions like colorwheel
3302 class which does not return a pointer, but the data itself. So it's not
3303 enough to use one single IPTR variable (4 Bytes on 32bit machines, 8 bytes
3304 on 64 bit machines) to store the result of the test-OM_Get.
3306 There is no general way to query the size needed so if one wants to change
3307 Zune to work like MUI one needs to choose a size which one hopes will be
3308 big enough to hold all possible attributes of all classes, old, present
3311 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3312 struct MUIP_Notify
*msg
)
3314 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3317 struct MinList
*ChildList
= NULL
;
3320 data
->dont_forward_get
= 1;
3322 if (GetAttr(msg
->TrigAttr
, obj
, attr
))
3324 data
->dont_forward_get
= 0;
3325 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3327 data
->dont_forward_get
= 0;
3329 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3333 cstate
= (Object
*) ChildList
->mlh_Head
;
3334 while ((child
= NextObject(&cstate
)))
3337 if (GetAttr(msg
->TrigAttr
, child
, attr
))
3339 DoMethodA(child
, (Msg
) msg
);
3340 /* No return here! */
3347 BOOPSI_DISPATCHER(IPTR
, Group_Dispatcher
, cl
, obj
, msg
)
3349 switch (msg
->MethodID
)
3352 return Group__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3354 return Group__OM_DISPOSE(cl
, obj
, msg
);
3356 return Group__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3358 return Group__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3359 case OM_ADDMEMBER
: /* Fall through */
3360 case MUIM_Group_AddTail
:
3361 return Group__MUIM_AddTail(cl
, obj
, (APTR
) msg
);
3362 case MUIM_Group_AddHead
:
3363 return Group__MUIM_AddHead(cl
, obj
, (APTR
) msg
);
3364 case MUIM_Group_Insert
:
3365 return Group__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3366 case OM_REMMEMBER
: /* Fall through */
3367 case MUIM_Group_Remove
:
3368 return Group__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3369 case MUIM_AskMinMax
:
3370 return Group__MUIM_AskMinMax(cl
, obj
, (APTR
) msg
);
3371 case MUIM_Group_ExitChange
:
3372 return Group__MUIM_ExitChange(cl
, obj
, (APTR
) msg
);
3373 case MUIM_Group_ExitChange2
:
3374 return Group__MUIM_ExitChange2(cl
, obj
, (APTR
) msg
);
3375 case MUIM_Group_InitChange
:
3376 return Group__MUIM_InitChange(cl
, obj
, (APTR
) msg
);
3377 case MUIM_Group_Sort
:
3378 return Group__MUIM_Sort(cl
, obj
, (APTR
) msg
);
3379 case MUIM_Group_DoMethodNoForward
:
3380 return Group__MUIM_DoMethodNoForward(cl
, obj
, (APTR
) msg
);
3381 case MUIM_ConnectParent
:
3382 return Group__MUIM_ConnectParent(cl
, obj
, (APTR
) msg
);
3383 case MUIM_DisconnectParent
:
3384 return Group__MUIM_DisconnectParent(cl
, obj
, (APTR
) msg
);
3386 return Group__MUIM_Layout(cl
, obj
, (APTR
) msg
);
3388 return Group__MUIM_Setup(cl
, obj
, (APTR
) msg
);
3390 return Group__MUIM_Cleanup(cl
, obj
, (APTR
) msg
);
3392 return Group__MUIM_Draw(cl
, obj
, (APTR
) msg
);
3394 case MUIM_FindUData
:
3395 return Group__MUIM_FindUData(cl
, obj
, (APTR
) msg
);
3397 return Group__MUIM_GetUData(cl
, obj
, (APTR
) msg
);
3399 return Group__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
3400 case MUIM_SetUDataOnce
:
3401 return Group__MUIM_SetUDataOnce(cl
, obj
, (APTR
) msg
);
3403 return Group__MUIM_Show(cl
, obj
, (APTR
) msg
);
3405 return Group__MUIM_Hide(cl
, obj
, (APTR
) msg
);
3406 case MUIM_HandleEvent
:
3407 return Group__MUIM_HandleEvent(cl
, obj
, (APTR
) msg
);
3408 case MUIM_DrawBackground
:
3409 return Group__MUIM_DrawBackground(cl
, obj
, (APTR
) msg
);
3410 case MUIM_DragQueryExtended
:
3411 return Group__MUIM_DragQueryExtended(cl
, obj
, (APTR
) msg
);
3412 case MUIM_FindAreaObject
:
3413 return Group__MUIM_FindAreaObject(cl
, obj
, (APTR
) msg
);
3415 return Group__MUIM_Export(cl
, obj
, (APTR
) msg
);
3417 return Group__MUIM_Import(cl
, obj
, (APTR
) msg
);
3421 /* Disabled. See above */
3423 return Group_Notify(cl
, obj
, (APTR
) msg
);
3428 case MUIM_DrawParentBackground
:
3429 case MUIM_DragBegin
:
3431 case MUIM_DragQuery
:
3432 case MUIM_DragFinish
:
3434 case MUIM_CreateDragImage
:
3435 case MUIM_DeleteDragImage
:
3437 case MUIM_GoInactive
:
3438 case MUIM_CreateBubble
:
3439 case MUIM_DeleteBubble
:
3440 case MUIM_CreateShortHelp
:
3441 case MUIM_DeleteShortHelp
:
3444 return DoSuperMethodA(cl
, obj
, (APTR
) msg
);
3445 /* Needs not to be forwarded? */
3448 /* sometimes you want to call a superclass method,
3449 * but not dispatching to child.
3450 * But what to do with list methods in a listview ?
3452 Group_DispatchMsg(cl
, obj
, (APTR
) msg
);
3454 return DoSuperMethodA(cl
, obj
, msg
);
3456 BOOPSI_DISPATCHER_END
3461 const struct __MUIBuiltinClass _MUI_Group_desc
=
3465 sizeof(struct MUI_GroupData
),
3466 (void *) Group_Dispatcher