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
:
577 tag
->ti_Tag
= TAG_IGNORE
;
580 /* D(bug("Group_Set(%p) MUIA_Selected forwarded\n", obj)); */
581 /* tag->ti_Tag = TAG_IGNORE; */
586 Group_DispatchMsg(cl
, obj
, (Msg
) msg
);
590 if (virt_offx
!= data
->virt_offx
|| virt_offy
!= data
->virt_offy
)
592 if (_flags(obj
) & MADF_CANDRAW
)
593 Group__MUIM_Hide(cl
, obj
, NULL
);
594 data
->virt_offx
= virt_offx
;
595 data
->virt_offy
= virt_offy
;
596 /* Relayout ourself, this will also relayout all the children */
597 DoMethod(obj
, MUIM_Layout
);
598 if (_flags(obj
) & MADF_CANDRAW
)
599 Group__MUIM_Show(cl
, obj
, NULL
);
601 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
608 /**************************************************************************
610 **************************************************************************/
611 IPTR
Group__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
613 /* small macro to simplify return value storage */
614 #define STORE *(msg->opg_Storage)
616 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
618 switch (msg
->opg_AttrID
)
626 case MUIA_Group_ActivePage
:
627 STORE
= data
->active_page
;
629 case MUIA_Group_ChildList
:
630 return GetAttr(MUIA_Family_List
, data
->family
, msg
->opg_Storage
);
631 case MUIA_Group_Horiz
:
632 STORE
= (data
->flags
& GROUP_HORIZ
);
634 case MUIA_Group_HorizSpacing
:
635 STORE
= data
->horiz_spacing
;
637 case MUIA_Group_VertSpacing
:
638 STORE
= data
->vert_spacing
;
640 case MUIA_Group_ChildCount
:
641 STORE
= data
->num_children
;
643 case MUIA_Virtgroup_Left
:
644 STORE
= data
->virt_offx
;
646 case MUIA_Virtgroup_Top
:
647 STORE
= data
->virt_offy
;
649 case MUIA_Virtgroup_Width
:
650 STORE
= data
->virt_mwidth
;
652 case MUIA_Virtgroup_Height
:
653 STORE
= data
->virt_mheight
;
655 case MUIA_Virtgroup_MinWidth
:
656 STORE
= data
->saved_minwidth
;
658 case MUIA_Virtgroup_MinHeight
:
659 STORE
= data
->saved_minheight
;
663 /* our handler didn't understand the attribute, we simply pass
664 ** it to our superclass now
666 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
669 /* seems to be the documented behaviour, however it should be slow! */
670 if (!data
->dont_forward_get
&& !data
->dont_forward_methods
)
674 struct MinList
*ChildList
= NULL
;
676 get(data
->family
, MUIA_Family_List
, &(ChildList
));
677 cstate
= (Object
*) ChildList
->mlh_Head
;
678 while ((child
= NextObject(&cstate
)))
679 if (DoMethodA(child
, (Msg
) msg
))
687 /**************************************************************************
689 **************************************************************************/
690 IPTR
Group__MUIM_AddTail(struct IClass
*cl
, Object
*obj
,
691 struct MUIP_Group_AddTail
*msg
)
693 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
696 /**************************************************************************
698 **************************************************************************/
699 IPTR
Group__MUIM_AddHead(struct IClass
*cl
, Object
*obj
,
700 struct MUIP_Group_AddHead
*msg
)
702 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
705 /**************************************************************************
707 **************************************************************************/
708 IPTR
Group__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
709 struct MUIP_Group_Insert
*msg
)
711 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
714 /**************************************************************************
716 **************************************************************************/
717 IPTR
Group__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
718 struct MUIP_Group_Remove
*msg
)
720 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
722 if (_flags(obj
) & MADF_CANDRAW
)
723 DoHideMethod(msg
->obj
);
724 if (_flags(obj
) & MADF_SETUP
)
725 DoMethod(msg
->obj
, MUIM_Cleanup
);
726 if (muiNotifyData(obj
)->mnd_GlobalInfo
)
728 DoMethod(msg
->obj
, MUIM_DisconnectParent
);
729 muiNotifyData(msg
->obj
)->mnd_ParentObject
= NULL
;
731 _flags(msg
->obj
) &= ~MADF_INVIRTUALGROUP
;
734 if ((data
->flags
& GROUP_CHANGING
) != 0)
735 data
->flags
|= GROUP_CHANGED
;
736 data
->num_children
--;
737 DoMethodA(data
->family
, (Msg
) msg
);
743 /**************************************************************************
745 **************************************************************************/
746 IPTR
Group__MUIM_ConnectParent(struct IClass
*cl
, Object
*obj
,
747 struct MUIP_ConnectParent
*msg
)
749 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
752 struct MinList
*ChildList
= NULL
;
754 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
756 get(data
->family
, MUIA_Family_List
, &(ChildList
));
757 cstate
= (Object
*) ChildList
->mlh_Head
;
758 while ((child
= NextObject(&cstate
)))
760 if ((_flags(obj
) & MADF_INVIRTUALGROUP
)
761 || (data
->flags
& GROUP_VIRTUAL
))
763 _flags(child
) |= MADF_INVIRTUALGROUP
;
766 /* Only children of groups can have parents */
767 muiNotifyData(child
)->mnd_ParentObject
= obj
;
769 DoMethod(child
, MUIM_ConnectParent
, (IPTR
) obj
);
774 /**************************************************************************
775 MUIM_DisconnectParent
776 **************************************************************************/
777 IPTR
Group__MUIM_DisconnectParent(struct IClass
*cl
, Object
*obj
,
778 struct MUIP_ConnectParent
*msg
)
780 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
783 struct MinList
*ChildList
= NULL
;
785 get(data
->family
, MUIA_Family_List
, &(ChildList
));
786 cstate
= (Object
*) ChildList
->mlh_Head
;
787 while ((child
= NextObject(&cstate
)))
789 DoMethodA(child
, (Msg
) msg
);
790 muiNotifyData(child
)->mnd_ParentObject
= NULL
;
791 _flags(child
) &= ~MADF_INVIRTUALGROUP
;
793 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
798 * Put group in exchange state
800 IPTR
Group__MUIM_InitChange(struct IClass
*cl
, Object
*obj
,
801 struct MUIP_Group_InitChange
*msg
)
803 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
805 data
->flags
&= ~GROUP_CHANGED
;
806 data
->flags
|= GROUP_CHANGING
;
812 * Will recalculate display after dynamic adding/removing
814 IPTR
Group__MUIM_ExitChange(struct IClass
*cl
, Object
*obj
,
815 struct MUIP_Group_ExitChange
*msg
)
817 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
819 data
->flags
&= ~GROUP_CHANGING
;
821 if (data
->flags
& GROUP_CHANGED
)
823 data
->flags
&= ~GROUP_CHANGED
;
825 if ((_flags(obj
) & MADF_SETUP
) && _win(obj
))
827 Object
*win
= _win(obj
);
828 Object
*parent
= obj
;
830 /* CHECKME: Don't call RecalcDisplay if one of our parents is
831 in GROUP_CHANGING state to prevent crash with Zune prefs
832 program NListtree page because NList/NListtree when
833 killing tree images in MUIM_Cleanup uses InitChange/
834 ExitChange. Zune prefs program uses InitChange/ExitChange
835 when switching page -> nesting -> mess. */
837 while ((parent
= _parent(parent
)))
839 struct MUI_GroupData
*pdata
= INST_DATA(cl
, parent
);
844 if (pdata
->flags
& GROUP_CHANGING
)
851 DoMethod(win
, MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
860 * Will recalculate display after dynamic adding/removing
862 IPTR
Group__MUIM_ExitChange2(struct IClass
*cl
, Object
*obj
,
863 struct MUIP_Group_ExitChange2
*msg
)
865 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
867 if (data
->flags
& GROUP_CHANGING
)
869 data
->flags
&= ~(GROUP_CHANGING
| GROUP_CHANGED
);
871 if ((_flags(obj
) & MADF_SETUP
) && _win(obj
))
873 Object
*win
= _win(obj
);
874 Object
*parent
= obj
;
876 /* CHECKME: Don't call RecalcDisplay if one of our parents is
877 in GROUP_CHANGING state to prevent crash with Zune prefs
878 program NListtree page because NList/NListtree when
879 killing tree images in MUIM_Cleanup uses InitChange/
880 ExitChange. Zune prefs program uses InitChange/ExitChange
881 when switching page -> nesting -> mess. */
883 while ((parent
= _parent(parent
)))
885 struct MUI_GroupData
*pdata
= INST_DATA(cl
, parent
);
890 if (pdata
->flags
& GROUP_CHANGING
)
897 DoMethod(win
, MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
908 IPTR
Group__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
909 struct MUIP_Group_Sort
*msg
)
911 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
914 msg
->MethodID
= MUIM_Family_Sort
;
916 DoMethodA(data
->family
, (APTR
) msg
);
918 /* restore original message */
919 msg
->MethodID
= MUIM_Group_Sort
;
923 /**************************************************************************
924 MUIM_Group_DoMethodNoForward
926 Executes the given method but does not forward it to the children
927 **************************************************************************/
928 IPTR
Group__MUIM_DoMethodNoForward(struct IClass
*cl
, Object
*obj
,
929 struct MUIP_Group_DoMethodNoForward
*msg
)
931 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
933 data
->dont_forward_methods
= 1; /* disable forwarding */
934 rc
= DoMethodA(obj
, (Msg
) & msg
->DoMethodID
);
935 /* Probably doesn't work correctly on AROS? */
937 data
->dont_forward_methods
= 0;
942 * Propagate a method to group children.
944 static ULONG
Group_DispatchMsg(struct IClass
*cl
, Object
*obj
, Msg msg
)
946 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
949 struct MinList
*ChildList
= NULL
;
951 if (data
->dont_forward_methods
)
954 get(data
->family
, MUIA_Family_List
, &(ChildList
));
955 cstate
= (Object
*) ChildList
->mlh_Head
;
956 while ((child
= NextObject(&cstate
)))
958 DoMethodA(child
, (Msg
) msg
);
964 /**************************************************************************
966 **************************************************************************/
967 IPTR
Group__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
968 struct MUIP_Setup
*msg
)
970 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
975 struct MinList
*ChildList
= NULL
;
977 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
980 ASSERT_VALID_PTR(muiGlobalInfo(obj
));
982 if (!(data
->flags
& GROUP_HSPACING
))
983 data
->horiz_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_hspacing
;
984 if (!(data
->flags
& GROUP_VSPACING
))
985 data
->vert_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_vspacing
;
986 get(data
->family
, MUIA_Family_List
, &(ChildList
));
987 cstate
= cstate_copy
= (Object
*) ChildList
->mlh_Head
;
988 while ((child
= NextObject(&cstate
)))
990 #if 0 /* SHOWME affects only show/hide */
991 if (!(_flags(child
) & MADF_SHOWME
))
995 if (!DoSetupMethod(child
, msg
->RenderInfo
))
997 /* Send MUIM_Cleanup to all objects that received MUIM_Setup.
1000 cstate
= cstate_copy
;
1001 while ((child
= NextObject(&cstate
)) && (child
!= childFailed
))
1003 #if 0 /* SHOWME affects only show/hide */
1004 if (!(_flags(child
) & MADF_SHOWME
))
1007 DoMethod(child
, MUIM_Cleanup
);
1013 if (data
->flags
& GROUP_VIRTUAL
)
1015 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
1016 (IPTR
) & data
->ehn
);
1023 /**************************************************************************
1025 **************************************************************************/
1026 IPTR
Group__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
, Msg msg
)
1028 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1031 struct MinList
*ChildList
= NULL
;
1033 if (data
->flags
& GROUP_VIRTUAL
)
1035 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
1036 (IPTR
) & data
->ehn
);
1039 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1040 cstate
= (Object
*) ChildList
->mlh_Head
;
1041 while ((child
= NextObject(&cstate
)))
1043 #if 0 /* SHOWME affects only show/hide */
1044 if (!(_flags(child
) & MADF_SHOWME
))
1047 DoMethodA(child
, (Msg
) msg
);
1049 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1054 /**************************************************************************
1055 MUIM_Draw - draw the group
1056 **************************************************************************/
1057 IPTR
Group__MUIM_Draw(struct IClass
*cl
, Object
*obj
,
1058 struct MUIP_Draw
*msg
)
1060 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1063 struct MinList
*ChildList
= NULL
;
1064 struct Rectangle group_rect
; /* child_rect; */
1066 struct Region
*region
= NULL
;
1067 APTR clip
= (APTR
) - 1;
1069 /* D(bug("Group_Draw(%lx) %ldx%ldx%ldx%ld upd=%d page=%d\n", */
1070 /* obj,_left(obj),_top(obj),_right(obj),_bottom(obj), */
1071 /* data->update, data->active_page)); */
1072 /* D(bug("Group_Draw(%p) msg=0x%08lx flags=0x%08lx\n", */
1073 /* obj, msg->flags, _flags(obj))); */
1075 if (data
->flags
& GROUP_CHANGING
)
1078 if (muiGlobalInfo(obj
)->mgi_Prefs
->window_redraw
==
1079 WINDOW_REDRAW_WITHOUT_CLEAR
)
1081 region
= NewRegion();
1084 struct Rectangle rect
;
1086 rect
.MinX
= _left(obj
);
1087 rect
.MinY
= _top(obj
);
1088 rect
.MaxX
= _right(obj
);
1089 rect
.MaxY
= _bottom(obj
);
1091 OrRectRegion(region
, &rect
);
1093 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1094 cstate
= (Object
*) ChildList
->mlh_Head
;
1095 while ((child
= NextObject(&cstate
)))
1098 /* redraw problem with colorwheel in coloradjust register */
1099 if ((data
->flags
& GROUP_PAGEMODE
)
1100 && ((page
!= data
->active_page
)
1101 && (child
!= data
->titlegroup
)))
1104 if ((muiAreaData(child
)->mad_Flags
& MADF_CANDRAW
)
1105 && (_width(child
) > 0) && (_height(child
) > 0))
1107 rect
.MinX
= MAX(_left(child
), _mleft(obj
));
1108 rect
.MinY
= MAX(_top(child
), _mtop(obj
));
1109 rect
.MaxX
= MIN(_right(child
), _mright(obj
));
1110 rect
.MaxY
= MIN(_bottom(child
), _mbottom(obj
));
1112 if ((rect
.MaxX
>= rect
.MinX
)
1113 && (rect
.MaxY
>= rect
.MinY
))
1115 ClearRectRegion(region
, &rect
);
1120 clip
= MUI_AddClipRegion(muiRenderInfo(obj
), region
);
1124 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1128 MUI_RemoveClipRegion(muiRenderInfo(obj
), clip
);
1134 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1136 /* D(bug("Group_Draw(%p) (after dsma) msg=0x%08lx flags=0x%08lx\n", */
1137 /* obj, msg->flags, _flags(obj))); */
1139 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1)
1142 * update is set when changing active page of a page group
1143 * need to redraw background ourself
1145 DoMethod(obj
, MUIM_DrawBackground
,
1146 _mleft(obj
), _mtop(obj
), _mwidth(obj
), _mheight(obj
),
1147 _mleft(obj
), _mtop(obj
), 0);
1153 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2)
1155 LONG left
, top
, right
, bottom
;
1156 LONG diff_virt_offx
= data
->virt_offx
- data
->old_virt_offx
;
1157 LONG diff_virt_offy
= data
->virt_offy
- data
->old_virt_offy
;
1158 struct Rectangle rect
;
1159 struct Rectangle
*clip_rect
= &muiRenderInfo(obj
)->mri_ClipRect
;
1163 if (!diff_virt_offx
&& !diff_virt_offy
)
1168 /* sba: I don't know how MUI handle this but ScrollRasterBF() made problems when scrolling
1169 ** a (partly visible) virtual groups in a virtual group, because e.g. _mtop() is then
1170 ** smaller than the region. ScrollRasterBF() on AmigaOS then marks the complete region
1171 ** as damaged. Using ScrollWindowRaster() solved that problem but it flickers then.
1172 ** To avoid this we prevent that the scroll area is out of the region bounds.
1173 ** The region bounds are setted in MUI_Redraw() but should probably should go in the
1174 ** MUI's clip functions
1177 left
= MAX(_mleft(obj
), clip_rect
->MinX
);
1178 top
= MAX(_mtop(obj
), clip_rect
->MinY
);
1179 right
= MIN(_mright(obj
), clip_rect
->MaxX
);
1180 bottom
= MIN(_mbottom(obj
), clip_rect
->MaxY
);
1183 ** ScrollRasterBF(_rp(obj), diff_virt_offx, diff_virt_offy, _mleft(obj), _mtop(obj), _mright(obj),_mbottom(obj));
1186 ScrollWindowRaster(_window(obj
), diff_virt_offx
, diff_virt_offy
,
1187 left
, top
, right
, bottom
);
1189 if ((region
= NewRegion()))
1196 if (diff_virt_offx
> 0)
1198 rect
.MinX
= right
- diff_virt_offx
+ 1;
1199 if (rect
.MinX
< left
)
1206 rect
.MaxX
= left
- diff_virt_offx
- 1;
1207 if (rect
.MaxX
> right
)
1211 if (rect
.MinX
<= rect
.MaxX
)
1213 DoMethod(obj
, MUIM_DrawBackground
,
1214 rect
.MinX
, rect
.MinY
,
1215 rect
.MaxX
- rect
.MinX
+ 1,
1216 rect
.MaxY
- rect
.MinY
+ 1,
1217 rect
.MinX
, rect
.MinY
, 0);
1219 OrRectRegion(region
, &rect
);
1228 if (diff_virt_offy
> 0)
1230 rect
.MinY
= bottom
- diff_virt_offy
+ 1;
1231 if (rect
.MinY
< top
)
1238 rect
.MaxY
= top
- diff_virt_offy
- 1;
1239 if (rect
.MaxY
> bottom
)
1242 if (rect
.MinY
<= rect
.MaxY
)
1244 DoMethod(obj
, MUIM_DrawBackground
,
1245 rect
.MinX
, rect
.MinY
,
1246 rect
.MaxX
- rect
.MinX
+ 1,
1247 rect
.MaxY
- rect
.MinY
+ 1,
1248 rect
.MinX
, rect
.MinY
, 0);
1250 OrRectRegion(region
, &rect
);
1258 if (!(msg
->flags
& MADF_DRAWOBJECT
)
1259 && !(msg
->flags
& MADF_DRAWALL
))
1264 if (data
->flags
& GROUP_VIRTUAL
&& !region
)
1266 /* Not really needed if MUI Draws all the objects, maybe that's
1267 * what DRAWALL is for??? */
1268 if ((region
= NewRegion()))
1270 struct Rectangle rect
;
1271 rect
.MinX
= _mleft(obj
);
1272 rect
.MinY
= _mtop(obj
);
1273 rect
.MaxX
= _mright(obj
);
1274 rect
.MaxY
= _mbottom(obj
);
1275 OrRectRegion(region
, &rect
);
1279 /* Add clipping region if we have one */
1281 clip
= MUI_AddClipRegion(muiRenderInfo(obj
), region
);
1283 group_rect
= muiRenderInfo(obj
)->mri_ClipRect
;
1285 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1286 cstate
= (Object
*) ChildList
->mlh_Head
;
1287 while ((child
= NextObject(&cstate
)))
1289 if (!(_flags(child
) & MADF_SHOWME
))
1292 if (child
!= data
->titlegroup
)
1295 if ((data
->flags
& GROUP_PAGEMODE
) && ((page
!= data
->active_page
)
1296 && (child
!= data
->titlegroup
)))
1301 // msg->flags |= MADF_DRAWOBJECT; /* yup, do not forget */
1303 // child_rect.MinX = _left(child);
1304 // child_rect.MinY = _top(child);
1305 // child_rect.MaxX = _right(child);
1306 // child_rect.MaxY = _bottom(child);
1307 /* g_print("intersect: a=(%d, %d, %d, %d) b=(%d, %d, %d, %d)\n", */
1308 /* group_rect.x, group_rect.y, */
1309 /* group_rect.width, group_rect.height, */
1310 /* child_rect.x, child_rect.y, */
1311 /* child_rect.width, child_rect.height); */
1313 // if (gdk_rectangle_intersect(&group_rect, &child_rect,
1314 // &muiRenderInfo(obj)->mri_ClipRect))
1315 // DoMethodA(child, (Msg)msg);
1316 /* if (((msg->flags & MADF_DRAWUPDATE) && data->update) */
1317 /* || (data->flags & GROUP_PAGEMODE)) */
1318 MUI_Redraw(child
, MADF_DRAWOBJECT
);
1320 /* MUI_Redraw(child, msg->flags); */
1321 muiRenderInfo(obj
)->mri_ClipRect
= group_rect
;
1322 /* g_print("set back clip to (%d, %d, %d, %d)\n", */
1323 /* group_rect.x, group_rect.y, group_rect.width, group_rect.height); */
1325 /* D(bug("Group_Draw(%p) end\n", obj)); */
1327 if (data
->flags
& GROUP_VIRTUAL
&& region
&& clip
!= (APTR
) - 1)
1329 MUI_RemoveClipRegion(muiRenderInfo(obj
), clip
);
1332 data
->old_virt_offx
= data
->virt_offx
;
1333 data
->old_virt_offy
= data
->virt_offy
;
1340 #define END_MINMAX() \
1341 tmp.MaxHeight = MAX(tmp.MaxHeight, tmp.MinHeight); \
1342 tmp.MaxWidth = MAX(tmp.MaxWidth, tmp.MinWidth); \
1343 tmp.DefHeight = CLAMP(tmp.DefHeight, tmp.MinHeight, tmp.MaxHeight); \
1344 tmp.DefWidth = CLAMP(tmp.DefWidth, tmp.MinWidth, tmp.MaxWidth); \
1345 msg->MinMaxInfo->MinWidth += tmp.MinWidth; \
1346 msg->MinMaxInfo->MinHeight += tmp.MinHeight; \
1347 msg->MinMaxInfo->MaxWidth += tmp.MaxWidth; \
1348 msg->MinMaxInfo->MaxHeight += tmp.MaxHeight; \
1349 msg->MinMaxInfo->DefWidth += tmp.DefWidth; \
1350 msg->MinMaxInfo->DefHeight += tmp.DefHeight;
1353 * MinMax calculation function. When this is called,
1354 * the children of your group have already been asked
1355 * about their min/max dimension so you can use their
1356 * dimensions to calculate yours.
1359 * - Init minwidth and maxwidth with size needed for total child spacing.
1360 * - 1st pass to find maximum minimum width, to set minwidth of each child
1361 * if they should have the same width (for a row of buttons ...)
1362 * - Adjust minwidth w/o making object bigger than their max size.
1364 static void group_minmax_horiz(struct IClass
*cl
, Object
*obj
,
1365 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1367 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1370 struct MUI_MinMax tmp
;
1371 WORD maxminwidth
= 0;
1372 BOOL found_nonzero_vweight
= FALSE
;
1376 tmp
.MaxHeight
= MUI_MAXMAX
;
1377 if (data
->num_visible_children
> 0)
1379 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1380 (data
->num_visible_children
- 1) * data
->horiz_spacing
;
1384 tmp
.MinWidth
= tmp
.DefWidth
= 0;
1385 tmp
.MaxWidth
= MUI_MAXMAX
;
1388 if (data
->flags
& GROUP_SAME_WIDTH
)
1390 cstate
= (Object
*) children
->mlh_Head
;
1391 while ((child
= NextObject(&cstate
)))
1393 if (IS_HIDDEN(child
))
1395 maxminwidth
= MAX(maxminwidth
, _minwidth(child
));
1399 data
->samesize_maxmin_horiz
= maxminwidth
;
1400 /* D(bug("group_minmax_horiz(%p) : maxminwidth=%d\n", obj, maxminwidth)); */
1402 data
->horiz_weight_sum
= 0;
1403 cstate
= (Object
*) children
->mlh_Head
;
1404 while ((child
= NextObject(&cstate
)))
1408 if (IS_HIDDEN(child
))
1410 if (data
->flags
& GROUP_SAME_WIDTH
)
1412 minwidth
= MAX(maxminwidth
, _minwidth(child
));
1413 minwidth
= MIN(minwidth
, _maxwidth(child
));
1416 minwidth
= _minwidth(child
);
1417 tmp
.MinWidth
+= minwidth
;
1418 tmp
.DefWidth
+= w0_defwidth(child
);
1419 tmp
.MaxWidth
+= w0_maxwidth(child
);
1420 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, MUI_MAXMAX
);
1421 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1422 tmp
.DefHeight
= MAX(tmp
.DefHeight
, _defheight(child
));
1424 if all children have null weight then maxheight=minheight
1425 if all but some children have null weights, the maxheight
1426 is the min of all maxheights
1428 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, _maxheight(child
));
1429 data
->horiz_weight_sum
+= _hweight(child
);
1430 if (_vweight(child
) > 0)
1432 found_nonzero_vweight
= TRUE
;
1435 if (!found_nonzero_vweight
)
1437 tmp
.MaxHeight
= tmp
.MinHeight
;
1440 //if (data->flags & GROUP_VIRTUAL)
1442 //kprintf("# min %d x %d def %d x %d max %d x %d\n",
1443 // tmp.MinWidth, tmp.MinHeight,
1444 // tmp.DefWidth, tmp.DefHeight,
1445 // tmp.MaxWidth, tmp.MaxHeight);
1451 /* minmax calculation for vertical groups (see group_minmax_horiz)
1453 static void group_minmax_vert(struct IClass
*cl
, Object
*obj
,
1454 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1456 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1459 struct MUI_MinMax tmp
;
1460 WORD maxminheight
= 0;
1461 BOOL found_nonzero_hweight
= FALSE
;
1465 tmp
.MaxWidth
= MUI_MAXMAX
;
1466 if (data
->num_visible_children
> 0)
1468 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1469 (data
->num_visible_children
- 1) * data
->vert_spacing
;
1473 tmp
.MinHeight
= tmp
.DefHeight
= 0;
1474 tmp
.MaxHeight
= MUI_MAXMAX
;
1477 if (data
->flags
& GROUP_SAME_HEIGHT
)
1479 cstate
= (Object
*) children
->mlh_Head
;
1480 while ((child
= NextObject(&cstate
)))
1482 if (IS_HIDDEN(child
))
1484 maxminheight
= MAX(maxminheight
, _minheight(child
));
1488 data
->samesize_maxmin_vert
= maxminheight
;
1489 data
->vert_weight_sum
= 0;
1490 cstate
= (Object
*) children
->mlh_Head
;
1491 while ((child
= NextObject(&cstate
)))
1493 if (IS_HIDDEN(child
))
1496 if (data
->flags
& GROUP_SAME_HEIGHT
)
1497 _minheight(child
) = MIN(maxminheight
, w0_maxheight(child
));
1498 tmp
.MinHeight
+= _minheight(child
);
1499 tmp
.DefHeight
+= w0_defheight(child
);
1500 tmp
.MaxHeight
+= w0_maxheight(child
);
1501 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, MUI_MAXMAX
);
1502 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1503 tmp
.DefWidth
= MAX(tmp
.DefWidth
, _defwidth(child
));
1504 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, _maxwidth(child
));
1505 data
->vert_weight_sum
+= _vweight(child
);
1506 if (_hweight(child
) > 0)
1508 found_nonzero_hweight
= TRUE
;
1511 if (!found_nonzero_hweight
)
1513 tmp
.MaxWidth
= tmp
.MinWidth
;
1521 minmax_2d_rows_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1522 struct MUI_MinMax
*req
, WORD maxmin_height
, WORD maxdef_height
)
1528 /* do not rewind after the while, to process line by line */
1529 cstate
= (Object
*) children
->mlh_Head
;
1531 for (i
= 0; i
< data
->rows
; i
++)
1533 /* calculate min and max height of this row */
1534 int min_h
= 0, def_h
= 0, max_h
= MUI_MAXMAX
;
1535 BOOL found_nonzero_vweight
= FALSE
;
1537 data
->row_infos
[i
].weight
= 0;
1540 while ((child
= NextObject(&cstate
)))
1542 if (IS_HIDDEN(child
))
1544 if (data
->flags
& GROUP_SAME_HEIGHT
)
1546 _minheight(child
) = MIN(maxmin_height
, w0_maxheight(child
));
1547 _defheight(child
) = MIN(maxdef_height
, w0_maxheight(child
));
1549 min_h
= MAX(min_h
, _minheight(child
));
1550 def_h
= MAX(def_h
, w0_defheight(child
));
1551 max_h
= MIN(max_h
, _maxheight(child
));
1552 if (_vweight(child
) > 0)
1554 found_nonzero_vweight
= TRUE
;
1555 data
->row_infos
[i
].weight
+= _vweight(child
);
1558 if ((j
% data
->columns
) == 0)
1561 if (!found_nonzero_vweight
)
1564 max_h
= MAX(max_h
, min_h
);
1565 /* D(bug("row %d : min_h=%d max_h=%d\n", i, min_h, max_h)); */
1567 data
->row_infos
[i
].min
= min_h
;
1568 data
->row_infos
[i
].max
= max_h
;
1569 data
->vert_weight_sum
+= data
->row_infos
[i
].weight
;
1571 req
->MinHeight
+= min_h
;
1572 req
->DefHeight
+= def_h
;
1573 req
->MaxHeight
+= max_h
;
1574 if (req
->MaxHeight
> MUI_MAXMAX
)
1575 req
->MaxHeight
= MUI_MAXMAX
;
1581 minmax_2d_columns_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1582 struct MUI_MinMax
*req
, WORD maxmin_width
, WORD maxdef_width
)
1588 for (i
= 0; i
< data
->columns
; i
++)
1590 /* calculate min and max width of this column */
1591 int min_w
= 0, def_w
= 0, max_w
= MUI_MAXMAX
;
1592 BOOL found_nonzero_hweight
= FALSE
;
1594 data
->col_infos
[i
].weight
= 0;
1597 /* process all children to get children on a column */
1598 cstate
= (Object
*) children
->mlh_Head
;
1599 while ((child
= NextObject(&cstate
)))
1601 if (IS_HIDDEN(child
))
1604 if (((j
- 1) % data
->columns
) != i
)
1606 if (data
->flags
& GROUP_SAME_WIDTH
)
1608 _minwidth(child
) = MIN(maxmin_width
, w0_maxwidth(child
));
1609 _defwidth(child
) = MIN(maxdef_width
, w0_maxwidth(child
));
1611 min_w
= MAX(min_w
, _minwidth(child
));
1612 def_w
= MAX(def_w
, w0_defwidth(child
));
1614 /* this handles the case of null weight children, which limit
1615 * the max size if they're alone, but not if they are with
1616 * non-null weight obj
1618 max_w
= MIN(max_w
, _maxwidth(child
));
1619 if (_hweight(child
) > 0)
1621 found_nonzero_hweight
= TRUE
;
1622 data
->col_infos
[i
].weight
+= _hweight(child
);
1625 if (!found_nonzero_hweight
)
1628 max_w
= MAX(max_w
, min_w
);
1629 /* D(bug("col %d : min_w=%d max_w=%d\n", i, min_w, max_w)); */
1631 data
->col_infos
[i
].min
= min_w
;
1632 data
->col_infos
[i
].max
= max_w
;
1633 data
->horiz_weight_sum
+= data
->col_infos
[i
].weight
;
1635 req
->MinWidth
+= min_w
;
1636 req
->DefWidth
+= def_w
;
1637 req
->MaxWidth
+= max_w
;
1638 if (req
->MaxWidth
> MUI_MAXMAX
)
1639 req
->MaxWidth
= MUI_MAXMAX
;
1644 group_minmax_2d(struct IClass
*cl
, Object
*obj
,
1645 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1647 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1650 struct MUI_MinMax tmp
;
1658 if (data
->num_children
% data
->rows
)
1661 data
->rows
= data
->num_children
;
1664 data
->columns
= data
->num_children
/ data
->rows
;
1668 if (data
->num_children
% data
->columns
)
1671 data
->columns
= data
->num_children
;
1674 data
->rows
= data
->num_children
/ data
->columns
;
1677 if (data
->columns
< 1)
1682 if (data
->row_infos
!= NULL
)
1683 mui_free(data
->row_infos
);
1685 data
->row_infos
= mui_alloc(data
->rows
* sizeof(struct layout2d_elem
));
1686 if (NULL
== data
->row_infos
)
1689 if (data
->col_infos
!= NULL
)
1690 mui_free(data
->col_infos
);
1693 mui_alloc(data
->columns
* sizeof(struct layout2d_elem
));
1694 if (NULL
== data
->col_infos
)
1697 data
->horiz_weight_sum
= 0;
1698 data
->vert_weight_sum
= 0;
1700 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1701 (data
->rows
- 1) * data
->vert_spacing
;
1702 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1703 (data
->columns
- 1) * data
->horiz_spacing
;
1704 /* get minimum dims if same dims for all children are needed */
1710 if ((data
->flags
& GROUP_SAME_WIDTH
)
1711 || (data
->flags
& GROUP_SAME_HEIGHT
))
1713 cstate
= (Object
*) children
->mlh_Head
;
1714 while ((child
= NextObject(&cstate
)))
1716 if (!(_flags(child
) & MADF_SHOWME
))
1718 maxmin_width
= MAX(maxmin_width
, _minwidth(child
));
1719 maxmin_height
= MAX(maxmin_height
, _minheight(child
));
1720 maxdef_width
= MAX(maxdef_width
, w0_defwidth(child
));
1721 maxdef_height
= MAX(maxdef_height
, w0_defheight(child
));
1723 /* g_print("2d group: mminw=%d mminh=%d\n", */
1724 /* maxmin_width, maxmin_height); */
1726 if (data
->flags
& GROUP_SAME_HEIGHT
)
1727 data
->samesize_maxmin_vert
= maxmin_height
;
1729 data
->samesize_maxmin_vert
= 0;
1731 if (data
->flags
& GROUP_SAME_WIDTH
)
1732 data
->samesize_maxmin_horiz
= maxmin_width
;
1734 data
->samesize_maxmin_horiz
= 0;
1736 minmax_2d_rows_pass(data
, children
, &tmp
, maxmin_height
, maxdef_height
);
1737 minmax_2d_columns_pass(data
, children
, &tmp
, maxmin_width
,
1745 group_minmax_pagemode(struct IClass
*cl
, Object
*obj
,
1746 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1750 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1751 struct MUI_MinMax tmp
= { 0, 0, MUI_MAXMAX
, MUI_MAXMAX
, 0, 0 };
1753 cstate
= (Object
*) children
->mlh_Head
;
1755 D(bug("minmax_pagemode(%lx)\n", obj
, tmp
.DefWidth
));
1757 while ((child
= NextObject(&cstate
)))
1759 if (!(_flags(child
) & MADF_SHOWME
))
1762 if (child
== data
->titlegroup
)
1765 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1766 D(bug("minmax_pagemode(%p) minh child = %d tmpmin=%d\n", obj
,
1767 _minheight(child
), tmp
.MinHeight
));
1768 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1769 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, w0_maxheight(child
));
1770 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, w0_maxwidth(child
));
1771 tmp
.DefHeight
= MAX(tmp
.DefHeight
,
1772 ((w0_defheight(child
) <
1773 MUI_MAXMAX
) ? w0_defheight(child
) : tmp
.DefHeight
));
1776 ((w0_defwidth(child
) <
1777 MUI_MAXMAX
) ? w0_defwidth(child
) : tmp
.DefWidth
));
1778 D(bug("minmax_pagemode(%lx) defw = %ld\n", obj
, tmp
.DefWidth
));
1781 if (data
->titlegroup
)
1783 tmp
.MinHeight
+= _minheight(data
->titlegroup
);
1784 tmp
.MaxHeight
+= w0_maxheight(data
->titlegroup
);
1785 tmp
.DefHeight
+= w0_defheight(data
->titlegroup
);
1791 /**************************************************************************
1792 MUIM_AskMinMax : ask children about min/max sizes, then
1793 either call a hook, or the builtin method, to calculate our minmax
1794 **************************************************************************/
1795 IPTR
Group__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1796 struct MUIP_AskMinMax
*msg
)
1798 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1799 struct MUI_LayoutMsg lm
;
1800 struct MUIP_AskMinMax childMsg
;
1801 struct MUI_MinMax childMinMax
;
1804 LONG super_minwidth
, super_minheight
;
1807 * let our superclass first fill in its size with frame, inner spc etc ...
1809 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1810 super_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1811 super_minheight
= msg
->MinMaxInfo
->MinHeight
;
1816 childMsg
.MethodID
= msg
->MethodID
;
1817 childMsg
.MinMaxInfo
= &childMinMax
;
1818 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
1820 cstate
= (Object
*) lm
.lm_Children
->mlh_Head
;
1822 while ((child
= NextObject(&cstate
)))
1824 if (!(_flags(child
) & MADF_SHOWME
))
1825 /* BORDERGADGETs should handle this itself */
1828 DoMethodA(child
, (Msg
) & childMsg
);
1829 /* D(bug("*** group %lx, child %lx min=%ld,%ld\n", */
1830 /* obj, child, childMinMax.MinWidth, childMinMax.MinHeight)); */
1831 __area_finish_minmax(child
, childMsg
.MinMaxInfo
);
1835 * Use children infos to calculate group size
1837 if (data
->flags
& GROUP_PAGEMODE
)
1839 D(bug("minmax_pagemode(%p) minh initial = %d\n", obj
,
1840 msg
->MinMaxInfo
->MinHeight
));
1841 group_minmax_pagemode(cl
, obj
, lm
.lm_Children
, msg
);
1842 D(bug("minmax_pagemode(%p) minh = %d\n", obj
,
1843 msg
->MinMaxInfo
->MinHeight
));
1845 else if (data
->layout_hook
)
1847 lm
.lm_Type
= MUILM_MINMAX
;
1848 CallHookPkt(data
->layout_hook
, obj
, &lm
);
1850 if (lm
.lm_MinMax
.MaxHeight
< lm
.lm_MinMax
.MinHeight
)
1851 lm
.lm_MinMax
.MaxHeight
= lm
.lm_MinMax
.MinHeight
;
1852 if (lm
.lm_MinMax
.DefHeight
< lm
.lm_MinMax
.MinHeight
)
1853 lm
.lm_MinMax
.DefHeight
= lm
.lm_MinMax
.MinHeight
;
1854 if (lm
.lm_MinMax
.MaxWidth
< lm
.lm_MinMax
.MinWidth
)
1855 lm
.lm_MinMax
.MaxWidth
= lm
.lm_MinMax
.MinWidth
;
1856 if (lm
.lm_MinMax
.DefWidth
< lm
.lm_MinMax
.MinWidth
)
1857 lm
.lm_MinMax
.DefWidth
= lm
.lm_MinMax
.MinWidth
;
1859 //kprintf("### min %d x %d def %d x %d max %d x %d\n",
1860 // msg->MinMaxInfo->MinWidth,
1861 // msg->MinMaxInfo->MinHeight,
1862 // msg->MinMaxInfo->DefWidth,
1863 // msg->MinMaxInfo->DefHeight,
1864 // msg->MinMaxInfo->MaxWidth,
1865 // msg->MinMaxInfo->MaxHeight);
1867 msg
->MinMaxInfo
->MinWidth
+= lm
.lm_MinMax
.MinWidth
;
1868 msg
->MinMaxInfo
->MinHeight
+= lm
.lm_MinMax
.MinHeight
;
1869 msg
->MinMaxInfo
->MaxWidth
+= lm
.lm_MinMax
.MaxWidth
;
1870 if (msg
->MinMaxInfo
->MaxWidth
> MUI_MAXMAX
)
1871 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1872 msg
->MinMaxInfo
->MaxHeight
+= lm
.lm_MinMax
.MaxHeight
;
1873 if (msg
->MinMaxInfo
->MaxHeight
> MUI_MAXMAX
)
1874 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1875 msg
->MinMaxInfo
->DefWidth
+= lm
.lm_MinMax
.DefWidth
;
1876 msg
->MinMaxInfo
->DefHeight
+= lm
.lm_MinMax
.DefHeight
;
1878 //kprintf("#### min %d x %d def %d x %d max %d x %d\n",
1879 // msg->MinMaxInfo->MinWidth,
1880 // msg->MinMaxInfo->MinHeight,
1881 // msg->MinMaxInfo->DefWidth,
1882 // msg->MinMaxInfo->DefHeight,
1883 // msg->MinMaxInfo->MaxWidth,
1884 // msg->MinMaxInfo->MaxHeight);
1889 if ((data
->rows
== 1) && (data
->columns
== 1))
1891 data
->num_visible_children
=
1892 Group_GetNumVisibleChildren(data
, lm
.lm_Children
);
1893 if (data
->flags
& GROUP_HORIZ
)
1894 group_minmax_horiz(cl
, obj
, lm
.lm_Children
, msg
);
1896 group_minmax_vert(cl
, obj
, lm
.lm_Children
, msg
);
1900 group_minmax_2d(cl
, obj
, lm
.lm_Children
, msg
);
1904 if (data
->flags
& GROUP_VIRTUAL
)
1906 data
->saved_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1907 data
->saved_minheight
= msg
->MinMaxInfo
->MinHeight
;
1908 msg
->MinMaxInfo
->MinWidth
= super_minwidth
+ 2;
1909 msg
->MinMaxInfo
->MinHeight
= super_minheight
+ 2;
1911 //kprintf("## min %d x %d def %d x %d max %d x %d\n",
1912 // msg->MinMaxInfo->MinWidth,
1913 // msg->MinMaxInfo->MinHeight,
1914 // msg->MinMaxInfo->DefWidth,
1915 // msg->MinMaxInfo->DefHeight,
1916 // msg->MinMaxInfo->MaxWidth,
1917 // msg->MinMaxInfo->MaxHeight);
1926 // enforce minmax constraint, but also update total growable/shrinkable weights
1927 // while we're at it
1928 static void Layout1D_minmax_constraint(WORD
*sizep
, WORD minsize
,
1929 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
1930 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
, WORD samesize
)
1932 WORD size
= *sizep
, remain
= *remainp
,
1933 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
1934 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
1936 /* D(bug("L1D_minmax_c size=%d min=%d max=%d w=%d ss=%d\n", */
1937 /* size, minsize, maxsize, */
1938 /* weight, samesize)); */
1940 if ((samesize
> 0) && (weight
== 0))
1942 remain
+= size
- samesize
;
1948 if (size
<= minsize
) // too little
1950 remain
+= size
- minsize
;
1953 if (size
== maxsize
)
1956 else if (size
>= maxsize
) // too big
1958 remain
+= size
- maxsize
;
1963 if (!((samesize
> 0) && (weight
== 0)))
1966 weightgrow
+= weight
;
1968 weightshrink
+= weight
;
1973 *sizegrowp
= sizegrow
;
1974 *sizeshrinkp
= sizeshrink
;
1975 *weightgrowp
= weightgrow
;
1976 *weightshrinkp
= weightshrink
;
1980 // redistribute excess size to growable child, or reduce size of a shrinkable
1982 static void Layout1D_redistribution(WORD
*sizep
, WORD minsize
,
1983 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
1984 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
)
1986 WORD size
= *sizep
, remain
= *remainp
,
1987 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
1988 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
1993 if ((remain
> 0) && (size
< maxsize
))
1997 newsize
= (sizegrow
* weight
+ weightgrow
/ 2) / weightgrow
;
1999 /* D(bug("newsize=%ld == size_growa=%ld * w=%ld / weight_grow=%d\n", */
2000 /* newsize, sizegrow, weight, weightgrow)); */
2002 /* take care of off-by-1 errors that may toggle remainder sign
2003 * by ensuring convergence to 0
2005 if (remain
- newsize
+ size
< 0)
2007 /* D(bug("adding remainder=%d => size = %d\n", */
2008 /* remain, size + remain)); */
2014 remain
-= newsize
- size
;
2017 weightgrow
-= weight
;
2020 else if ((remain
< 0) && (size
> minsize
))
2024 newsize
= (sizeshrink
* weight
+ weightshrink
/ 2) / weightshrink
;
2026 /* D(bug("newsize=%ld == size_shrinkables=%ld * w=%ld " */
2027 /* "/ weight_shrinkables=%d\n", */
2028 /* newsize, sizeshrink, weight, weightshrink)); */
2030 if (remain
- newsize
+ size
> 0)
2032 /* D(bug("adding remainder=%d => size = %d\n", */
2033 /* remain, size + remain)); */
2039 remain
-= newsize
- size
;
2042 weightshrink
-= weight
;
2048 *sizegrowp
= sizegrow
;
2049 *sizeshrinkp
= sizeshrink
;
2050 *weightgrowp
= weightgrow
;
2051 *weightshrinkp
= weightshrink
;
2055 // 2 passes at most, less on average (0.5 or 1.5), each does
2056 // - a minmax clamping, evenutally adding to a remainder
2057 // (remainder = missing (underflow) or remaining (overflow) space compared
2058 // to ideal sizes where children fill the whole group)
2059 // - a redistribution of the remainder, by growing (pos. remainder) or
2060 // shrinking (neg. remainder) children able to support it.
2062 // Occasionnaly the first time the redistribution is done, the minmax
2063 // constraint can be broken, thus the extra pass to check and eventually
2064 // redistribute. The second redistribution never breaks minmax constraint
2065 // (there should be a mathematical proof, but feel free to prove me wrong
2067 static void Layout1D_minmax_constraints_and_redistrib(struct MinList
2068 *children
, WORD total_size
, WORD remainder
, WORD samesize
,
2075 for (i
= 0; i
< 2; i
++)
2077 WORD size_growables
= total_size
;
2078 WORD size_shrinkables
= total_size
;
2079 ULONG weight_growables
= 0;
2080 ULONG weight_shrinkables
= 0;
2082 /* D(bug("start : rem=%ld, A=%ld, size_growables=%ld, " */
2083 /* "size_shrinkables=%ld\n", */
2084 /* remainder, total_size, size_growables, size_shrinkables)); */
2086 // minmax constraints
2087 cstate
= (Object
*) children
->mlh_Head
;
2088 while ((child
= NextObject(&cstate
)))
2090 /* WORD old_size; */
2092 if (IS_HIDDEN(child
))
2097 /* old_size = _width(child); */
2099 Layout1D_minmax_constraint(&_width(child
), _minwidth(child
),
2100 _maxwidth(child
), &remainder
, &size_growables
,
2101 &size_shrinkables
, &weight_growables
,
2102 &weight_shrinkables
, _hweight(child
), samesize
);
2104 /* D(bug("loop1 on %p : width=%d was %d, rem=%d, A=%d, " */
2105 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2106 /* child, _width(child), old_size, remainder, total_size, */
2107 /* size_growables, size_shrinkables, _hweight(child), */
2108 /* _minwidth(child), _maxwidth(child))); */
2110 else // ! group_horiz
2112 /* old_size = _height(child); */
2114 Layout1D_minmax_constraint(&_height(child
),
2115 _minheight(child
), _maxheight(child
), &remainder
,
2116 &size_growables
, &size_shrinkables
, &weight_growables
,
2117 &weight_shrinkables
, _vweight(child
), samesize
);
2119 /* D(bug("loop1 on %p : h=%ld was %d, rem=%d, A=%d, " */
2120 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2121 /* child, _height(child), old_size, remainder, total_size,*/
2122 /* size_growables, size_shrinkables, _vweight(child), */
2123 /* _minheight(child), _maxheight(child))); */
2124 } // if (group_horiz)
2125 } // while child, minmax constraints
2131 /* D(bug("mid : rem=%d, A=%d, size_grow=%d, size_shrink=%d, " */
2132 /* "wg=%ld, ws=%ld\n", remainder, total_size, size_growables, */
2133 /* size_shrinkables, weight_growables, weight_shrinkables)); */
2135 // distribute remaining space to possible candidates
2136 cstate
= (Object
*) children
->mlh_Head
;
2137 while (((child
= NextObject(&cstate
)) != NULL
) && (remainder
!= 0))
2139 /* WORD old_size; */
2141 if (IS_HIDDEN(child
))
2146 /* old_size = _width(child); */
2148 Layout1D_redistribution(&_width(child
), _minwidth(child
),
2149 _maxwidth(child
), &remainder
, &size_growables
,
2150 &size_shrinkables
, &weight_growables
,
2151 &weight_shrinkables
, _hweight(child
));
2153 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2154 /* "size_grow=%d, size_shrink=%d\n", child, */
2155 /* _width(child), old_size, remainder, total_size, */
2156 /* size_growables, size_shrinkables)); */
2158 else // ! group_horiz
2160 /* old_size = _height(child); */
2162 Layout1D_redistribution(&_height(child
), _minheight(child
),
2163 _maxheight(child
), &remainder
, &size_growables
,
2164 &size_shrinkables
, &weight_growables
,
2165 &weight_shrinkables
, _vweight(child
));
2167 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2168 /* "size_grow=%d, size_shrink=%d\n", child, */
2169 /* _height(child), old_size, remainder, total_size, */
2170 /* size_growables, size_shrinkables)); */
2171 } // if (group_horiz)
2173 } // while child, redistribution
2175 /* if (remainder != 0) */
2177 /* D(bug("end : rem=%ld, A=%ld, size_grow=%ld, size_shrink=%ld\n", */
2178 /* remainder, total_size, size_growables, size_shrinkables)); */
2180 // dont break here if remainder == 0, some minmax constraints
2181 // may not be respected
2184 // to easily spot layout bugs, nothing like a (division by zero) exception
2185 /* if (remainder != 0) */
2187 /* ASSERT(remainder != 0); */
2188 /* D(bug("gonna crash, remainder = %d\n", remainder)); */
2189 /* remainder /= 0; */
2194 static void Layout1D_weight_constraint(WORD
*total_sizep
,
2195 WORD
*total_init_sizep
,
2196 ULONG
*total_weightp
, WORD
*sizep
, UWORD weight
, WORD minsize
)
2198 if (*total_weightp
> 0)
2199 *sizep
= (*total_sizep
* weight
+ *total_weightp
/ 2)
2204 *total_weightp
-= weight
;
2205 *total_sizep
-= *sizep
;
2206 *total_init_sizep
+= *sizep
;
2210 static void group_layout_vert(struct IClass
*cl
, Object
*obj
,
2211 struct MinList
*children
)
2213 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2217 WORD remainder
; /* must converge to 0 to successfully end layout */
2219 WORD total_size_backup
;
2220 WORD total_init_size
; /* total size of the ideally sized children */
2227 //kprintf("group_layout_vert: virtoff = %d,%d\n",
2228 // data->virt_offx, data->virt_offy);
2230 if (data
->flags
& GROUP_VIRTUAL
)
2233 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2234 _maxwidth(obj
) - _subwidth(obj
));
2235 data
->virt_mheight
=
2236 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2237 _maxheight(obj
) - _subheight(obj
));
2239 layout_width
= data
->virt_mwidth
;
2240 layout_height
= data
->virt_mheight
;
2244 layout_width
= _mwidth(obj
);
2245 layout_height
= _mheight(obj
);
2248 total_weight
= data
->vert_weight_sum
;
2249 total_init_size
= 0;
2251 layout_height
- (data
->num_visible_children
-
2252 1) * data
->vert_spacing
;
2253 total_size_backup
= total_size
;
2255 /* D(bug("\nvert layout for %p, A=%d W=%ld\n", */
2256 /* obj, total_size, total_weight)); */
2258 // weight constraints
2259 // calculate ideal size for each object, and total ideal size
2260 cstate
= (Object
*) children
->mlh_Head
;
2261 while ((child
= NextObject(&cstate
)))
2263 if (IS_HIDDEN(child
))
2266 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2267 &total_weight
, &_height(child
), _vweight(child
),
2269 /* D(bug("child %p : ideal=%d w=%ld\n", */
2270 /* child, _height(child), _vweight(child))); */
2271 } // while child, weight constraints
2273 total_size
= total_size_backup
;
2274 remainder
= total_size
- total_init_size
;
2276 if (data
->flags
& GROUP_VIRTUAL
)
2278 /* This is also true for non virtual groups, but if this would be the
2279 ** case then there is a bug in the layout function
2285 Layout1D_minmax_constraints_and_redistrib(children
,
2288 (data
->flags
& GROUP_SAME_HEIGHT
) ? data
->samesize_maxmin_vert
: 0,
2292 cstate
= (Object
*) children
->mlh_Head
;
2293 while ((child
= NextObject(&cstate
)))
2295 if (IS_HIDDEN(child
))
2298 width
= MIN(_maxwidth(child
), layout_width
);
2299 width
= MAX(width
, _minwidth(child
));
2300 left
= (layout_width
- width
) / 2;
2302 /* D(bug("child %p -> layout %d x %d\n", */
2303 /* child, width, _height(child))); */
2304 if (!MUI_Layout(child
, left
, top
, width
, _height(child
), 0))
2306 top
+= data
->vert_spacing
+ _height(child
);
2312 static void group_layout_horiz(struct IClass
*cl
, Object
*obj
,
2313 struct MinList
*children
)
2315 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2319 WORD remainder
; /* must converge to 0 to succesfully end layout */
2321 WORD total_size_backup
;
2322 WORD total_init_size
; /* total size of the ideally sized children */
2329 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2330 // data->virt_offx, data->virt_offy);
2332 if (data
->flags
& GROUP_VIRTUAL
)
2335 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2336 _maxwidth(obj
) - _subwidth(obj
));
2337 data
->virt_mheight
=
2338 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2339 _maxheight(obj
) - _subheight(obj
));
2341 layout_width
= data
->virt_mwidth
;
2342 layout_height
= data
->virt_mheight
;
2344 //kprintf("group_layout_horiz: layoutsize %d x %d "
2345 // " virtsize %d x %d msize %d x %d\n",
2346 // layout_width, layout_height, data->virt_mwidth,
2347 // data->virt_mheight,
2348 // _mwidth(obj), _mheight(obj));
2352 layout_width
= _mwidth(obj
);
2353 layout_height
= _mheight(obj
);
2356 total_weight
= data
->horiz_weight_sum
;
2357 total_init_size
= 0;
2359 layout_width
- (data
->num_visible_children
-
2360 1) * data
->horiz_spacing
;
2361 total_size_backup
= total_size
;
2363 /* D(bug("\nhoriz layout for %p, A=%d W=%ld\n", */
2364 /* obj, total_size, total_weight)); */
2366 // weight constraints
2367 // calculate ideal size for each object, and total ideal size
2368 cstate
= (Object
*) children
->mlh_Head
;
2369 while ((child
= NextObject(&cstate
)))
2371 if (IS_HIDDEN(child
))
2374 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2375 &total_weight
, &_width(child
), _hweight(child
),
2377 /* D(bug("child %p : ideal=%d w=%ld\n", */
2378 /* child, _width(child), _hweight(child))); */
2379 } // while child, weight constraints
2381 total_size
= total_size_backup
;
2382 if (data
->horiz_weight_sum
> 0)
2383 remainder
= total_size
- total_init_size
;
2387 if (data
->flags
& GROUP_VIRTUAL
)
2389 /* This is also true for non virtual groups, but if this would be the
2390 ** case then there is a bug in the layout function
2396 Layout1D_minmax_constraints_and_redistrib(children
,
2399 (data
->flags
& GROUP_SAME_WIDTH
) ? data
->samesize_maxmin_horiz
: 0,
2403 cstate
= (Object
*) children
->mlh_Head
;
2404 while ((child
= NextObject(&cstate
)))
2406 if (IS_HIDDEN(child
))
2409 height
= MIN(_maxheight(child
), layout_height
);
2410 height
= MAX(height
, _minheight(child
));
2411 top
= (layout_height
- height
) / 2;
2413 /* D(bug("child %p -> layout %d x %d\n", */
2414 /* child, _width(child), height)); */
2415 if (!MUI_Layout(child
, left
, top
, _width(child
), height
, 0))
2417 left
+= data
->horiz_spacing
+ _width(child
);
2423 static void Layout2D_weight_constraint(struct MUI_GroupData
*data
,
2424 struct layout2d_elem
*row_infos
,
2425 struct layout2d_elem
*col_infos
,
2426 WORD total_size_height
, WORD total_size_width
,
2427 WORD
*total_init_height
, WORD
*total_init_width
)
2430 ULONG total_weight_vert
= data
->vert_weight_sum
;
2431 ULONG total_weight_horiz
= data
->horiz_weight_sum
;
2433 *total_init_height
= 0;
2434 *total_init_width
= 0;
2436 /* calc row heights */
2437 for (i
= 0; i
< data
->rows
; i
++)
2439 if (total_weight_vert
> 0)
2441 (total_size_height
* row_infos
[i
].weight
+
2442 total_weight_vert
/ 2) / total_weight_vert
;
2444 row_infos
[i
].dim
= row_infos
[i
].min
;
2446 /* D(bug("l2 row %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2447 /* i, row_infos[i].dim, */
2448 /* row_infos[i].weight, total_size_height, total_weight_vert)); */
2450 total_weight_vert
-= row_infos
[i
].weight
;
2451 total_size_height
-= row_infos
[i
].dim
;
2452 *total_init_height
+= row_infos
[i
].dim
;
2455 /* calc columns widths */
2456 for (i
= 0; i
< data
->columns
; i
++)
2458 if (total_weight_horiz
)
2460 (total_size_width
* col_infos
[i
].weight
+
2461 total_weight_horiz
/ 2) / total_weight_horiz
;
2463 col_infos
[i
].dim
= col_infos
[i
].min
;
2465 /* D(bug("l2 col %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2466 /* i, col_infos[i].dim, */
2467 /* col_infos[i].weight, total_size_width, total_weight_horiz)); */
2469 total_weight_horiz
-= col_infos
[i
].weight
;
2470 total_size_width
-= col_infos
[i
].dim
;
2471 *total_init_width
+= col_infos
[i
].dim
;
2477 static void Layout2D_minmax_constraints_and_redistrib(struct layout2d_elem
2478 *infos
, WORD nitems
, WORD total_size
, WORD samesize
, WORD remainder
)
2482 /* D(bug("L2D mc&r n=%d A=%d ss=%d rem=%d\n", */
2483 /* nitems, total_size, samesize, remainder)); */
2485 for (j
= 0; j
< 2; j
++)
2487 WORD size_growables
= total_size
;
2488 WORD size_shrinkables
= total_size
;
2489 ULONG weight_growables
= 0;
2490 ULONG weight_shrinkables
= 0;
2491 /* WORD old_size; */
2494 // minmax constraints
2495 for (i
= 0; i
< nitems
; i
++)
2497 /* old_size = infos[i].dim; */
2499 /* D(bug("bef loop1 on %d : size=%d, rem=%d, A=%d, " */
2500 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2501 /* i, infos[i].dim, remainder, total_size, */
2502 /* size_growables, size_shrinkables, infos[i].weight, */
2503 /* infos[i].min, infos[i].max)); */
2505 Layout1D_minmax_constraint(&infos
[i
].dim
, infos
[i
].min
,
2506 infos
[i
].max
, &remainder
, &size_growables
,
2507 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2508 infos
[i
].weight
, samesize
);
2510 /* D(bug("loop1 on %d : size=%d was %d, rem=%d, A=%d, " */
2511 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2512 /* i, infos[i].dim, old_size, remainder, total_size, */
2513 /* size_growables, size_shrinkables, infos[i].weight, */
2514 /* infos[i].min, infos[i].max)); */
2520 for (i
= 0; i
< nitems
; i
++)
2522 /* old_size = infos[i].dim; */
2524 /* D(bug("bef loop2 on %d : size=%d, rem=%d, A=%d, " */
2525 /* "size_grow=%d, size_shrink=%d\n", i, */
2526 /* infos[i].dim, remainder, total_size, */
2527 /* size_growables, size_shrinkables)); */
2529 Layout1D_redistribution(&infos
[i
].dim
, infos
[i
].min
,
2530 infos
[i
].max
, &remainder
, &size_growables
,
2531 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2534 /* D(bug("loop2 on %d : size=%d was %d, rem=%d, A=%d, " */
2535 /* "size_grow=%d, size_shrink=%d\n", i, */
2536 /* infos[i].dim, old_size, remainder, total_size, */
2537 /* size_growables, size_shrinkables)); */
2543 layout_2d_distribute_space(struct MUI_GroupData
*data
,
2544 struct layout2d_elem
*row_infos
,
2545 struct layout2d_elem
*col_infos
,
2546 struct MinList
*children
, LONG left_start
, LONG top_start
)
2557 * pass 2 : distribute space
2559 cstate
= (Object
*) children
->mlh_Head
;
2562 for (i
= 0; i
< data
->rows
; i
++)
2564 /* left start for child layout in this row */
2567 /* max height for children in this row */
2568 row_height
= row_infos
[i
].dim
;
2570 /* for each column */
2571 while ((child
= NextObject(&cstate
)))
2578 if (IS_HIDDEN(child
))
2580 /* max width for children in this column */
2581 col_width
= col_infos
[j
].dim
;
2583 /* center child if col width is bigger than child maxwidth */
2584 cwidth
= MIN(_maxwidth(child
), col_width
);
2585 cwidth
= MAX(cwidth
, _minwidth(child
));
2586 cleft
= left
+ (col_width
- cwidth
) / 2;
2588 /* center child if row height is bigger than child maxheight */
2589 cheight
= MIN(_maxheight(child
), row_height
);
2590 cheight
= MAX(cheight
, _minheight(child
));
2591 ctop
= top
+ (row_height
- cheight
) / 2;
2593 /* g_print("layout %d %d %d %d\n", cleft, ctop, cwidth, cheight); */
2594 /* D(bug("2DL/child %p -> layout %d x %d\n", */
2595 /* child, cwidth, cheight)); */
2596 if (!MUI_Layout(child
, cleft
, ctop
, cwidth
, cheight
, 0))
2599 left
+= data
->horiz_spacing
+ col_width
;
2602 if ((j
% data
->columns
) == 0)
2606 top
+= data
->vert_spacing
+ row_height
;
2613 * all children in the same row have the same maximum height
2614 * all children in the same column have the same maximum height
2615 * if a child maximum size is smaller than the biggest minimum size,
2616 * the chid will be centered in the remaining space.
2618 * for each row, determine its height allocation
2619 * weight ? the vertical weight of a row, if no fixed-height child
2620 * in the row, is the sum of all vertical weights of children
2621 * all row members will have the same height
2623 * for each column, determine its width allocation
2624 * all column members will have the same width
2626 /* Write a proper hook function */
2628 group_layout_2d(struct IClass
*cl
, Object
*obj
, struct MinList
*children
)
2630 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2631 WORD left_start
= 0;
2633 WORD total_size_height
=
2634 _mheight(obj
) - (data
->rows
- 1) * data
->vert_spacing
;
2635 WORD total_size_width
=
2636 _mwidth(obj
) - (data
->columns
- 1) * data
->horiz_spacing
;
2637 WORD total_init_height
;
2638 WORD total_init_width
;
2639 WORD remainder_height
;
2640 WORD remainder_width
;
2644 if (data
->rows
== 0 || data
->columns
== 0)
2646 if (data
->num_children
% data
->rows
2647 || data
->num_children
% data
->columns
)
2649 if (data
->row_infos
== NULL
|| data
->col_infos
== NULL
)
2652 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2653 // data->virt_offx, data->virt_offy);
2655 if (data
->flags
& GROUP_VIRTUAL
)
2658 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2659 _maxwidth(obj
) - _subwidth(obj
));
2660 data
->virt_mheight
=
2661 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2662 _maxheight(obj
) - _subheight(obj
));
2664 layout_width
= data
->virt_mwidth
;
2665 layout_height
= data
->virt_mheight
;
2669 layout_width
= _mwidth(obj
);
2670 layout_height
= _mheight(obj
);
2674 layout_height
- (data
->rows
- 1) * data
->vert_spacing
;
2676 layout_width
- (data
->columns
- 1) * data
->horiz_spacing
;
2680 // weight constraints
2681 Layout2D_weight_constraint(data
, data
->row_infos
, data
->col_infos
,
2682 total_size_height
, total_size_width
,
2683 &total_init_height
, &total_init_width
);
2685 remainder_height
= total_size_height
- total_init_height
;
2686 remainder_width
= total_size_width
- total_init_width
;
2688 Layout2D_minmax_constraints_and_redistrib(data
->row_infos
,
2689 data
->rows
, total_size_height
,
2690 /* (data->flags & GROUP_SAME_HEIGHT) ? data->samesize_maxmin_vert : 0, */
2691 0, remainder_height
);
2693 Layout2D_minmax_constraints_and_redistrib(data
->col_infos
,
2694 data
->columns
, total_size_width
,
2695 /* (data->flags & GROUP_SAME_WIDTH) ? data->samesize_maxmin_horiz : 0, */
2696 0, remainder_width
);
2698 layout_2d_distribute_space(data
, data
->row_infos
, data
->col_infos
,
2699 children
, left_start
, top_start
);
2703 /* Write a proper hook function */
2704 static void group_layout_pagemode(struct IClass
*cl
, Object
*obj
,
2705 struct MinList
*children
)
2707 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2712 int w
, h
, yoffset
= 0;
2714 if (data
->flags
& GROUP_VIRTUAL
)
2717 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2718 _maxwidth(obj
) - _subwidth(obj
));
2719 data
->virt_mheight
=
2720 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2721 _maxheight(obj
) - _subheight(obj
));
2723 layout_width
= data
->virt_mwidth
;
2724 layout_height
= data
->virt_mheight
;
2728 layout_width
= _mwidth(obj
);
2729 layout_height
= _mheight(obj
);
2732 if (data
->titlegroup
)
2734 yoffset
= _minheight(data
->titlegroup
);
2735 layout_height
-= yoffset
;
2738 cstate
= (Object
*) children
->mlh_Head
;
2739 while ((child
= NextObject(&cstate
)))
2741 w
= MIN(layout_width
, _maxwidth(child
));
2742 h
= MIN(layout_height
, _maxheight(child
));
2744 if (child
== data
->titlegroup
)
2746 MUI_Layout(child
, (layout_width
- w
) / 2, 0, w
, yoffset
, 0);
2750 D(bug("PM/child %p -> layout %d x %d\n", child
, w
, h
));
2751 MUI_Layout(child
, (layout_width
- w
) / 2,
2752 yoffset
+ (layout_height
- h
) / 2, w
, h
, 0);
2758 /**************************************************************************
2760 Either use a given layout hook, or the builtin method.
2761 **************************************************************************/
2762 IPTR
Group__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
2763 struct MUIP_Layout
*msg
)
2765 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2766 struct MUI_LayoutMsg lm
= { 0 };
2768 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
2769 if (data
->flags
& GROUP_PAGEMODE
)
2771 group_layout_pagemode(cl
, obj
, lm
.lm_Children
);
2773 else if (data
->layout_hook
)
2775 lm
.lm_Type
= MUILM_LAYOUT
;
2776 lm
.lm_Layout
.Width
= _mwidth(obj
);
2777 lm
.lm_Layout
.Height
= _mheight(obj
);
2779 CallHookPkt(data
->layout_hook
, obj
, &lm
);
2781 if (data
->flags
& GROUP_VIRTUAL
)
2783 data
->virt_mwidth
= lm
.lm_Layout
.Width
;
2784 data
->virt_mheight
= lm
.lm_Layout
.Height
;
2789 if ((data
->rows
== 1) && (data
->columns
== 1))
2791 if (data
->flags
& GROUP_HORIZ
)
2792 group_layout_horiz(cl
, obj
, lm
.lm_Children
);
2794 group_layout_vert(cl
, obj
, lm
.lm_Children
);
2797 group_layout_2d(cl
, obj
, lm
.lm_Children
);
2800 if (data
->flags
& GROUP_VIRTUAL
)
2802 WORD new_virt_offx
, new_virt_offy
;
2804 new_virt_offx
= data
->virt_offx
;
2805 new_virt_offy
= data
->virt_offy
;
2807 if (new_virt_offx
+ _mwidth(obj
) > data
->virt_mwidth
)
2809 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
2811 if (new_virt_offx
< 0)
2814 if (new_virt_offy
+ _mheight(obj
) > data
->virt_mheight
)
2816 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
2818 if (new_virt_offy
< 0)
2821 if (new_virt_offx
!= data
->virt_offx
)
2823 nfset(obj
, MUIA_Virtgroup_Left
, new_virt_offx
);
2826 if (new_virt_offy
!= data
->virt_offy
)
2828 nfset(obj
, MUIA_Virtgroup_Top
, new_virt_offy
);
2836 /**************************************************************************
2838 **************************************************************************/
2839 IPTR
Group__MUIM_Show(struct IClass
*cl
, Object
*obj
,
2840 struct MUIP_Show
*msg
)
2842 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2845 struct MinList
*ChildList
= NULL
;
2847 /* If msg is NULL, we won't want that the super method actually gets
2850 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2852 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2853 cstate
= (Object
*) ChildList
->mlh_Head
;
2855 if (data
->flags
& GROUP_PAGEMODE
)
2858 while ((child
= NextObject(&cstate
)))
2860 if (child
== data
->titlegroup
)
2862 DoShowMethod(child
);
2863 continue; /* Title group is not counted as page */
2866 if (page
== data
->active_page
)
2868 DoShowMethod(child
);
2876 while ((child
= NextObject(&cstate
)))
2878 if (!(data
->flags
& GROUP_VIRTUAL
) ||
2879 IsObjectVisible(child
, MUIMasterBase
))
2881 if (_flags(child
) & MADF_SHOWME
)
2882 DoShowMethod(child
);
2889 /**************************************************************************
2891 **************************************************************************/
2892 IPTR
Group__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
2893 struct MUIP_Hide
*msg
)
2895 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2898 struct MinList
*ChildList
= NULL
;
2900 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2901 cstate
= (Object
*) ChildList
->mlh_Head
;
2903 if (data
->flags
& GROUP_PAGEMODE
)
2906 while ((child
= NextObject(&cstate
)))
2908 if (child
== data
->titlegroup
)
2910 DoHideMethod(child
);
2911 continue; /* Title group is not counted as page */
2914 if (page
== data
->active_page
)
2916 DoHideMethod(child
);
2924 while ((child
= NextObject(&cstate
)))
2926 if (_flags(child
) & MADF_CANDRAW
)
2927 DoHideMethod(child
);
2931 /* If msg is NULL, we won't want that the super method actually gets
2934 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2939 * MUIM_FindUData : tests if the MUIA_UserData of the object
2940 * contains the given <udata> and returns the object pointer in this case.
2942 IPTR
Group__MUIM_FindUData(struct IClass
*cl
, Object
*obj
,
2943 struct MUIP_FindUData
*msg
)
2945 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2947 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2950 return DoMethodA(data
->family
, (Msg
) msg
);
2955 * MUIM_GetUData : This method tests if the MUIA_UserData of the object
2956 * contains the given <udata> and gets <attr> to <storage> for itself
2959 IPTR
Group__MUIM_GetUData(struct IClass
*cl
, Object
*obj
,
2960 struct MUIP_GetUData
*msg
)
2962 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2964 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2966 get(obj
, msg
->attr
, msg
->storage
);
2970 return DoMethodA(data
->family
, (Msg
) msg
);
2975 * MUIM_SetUData : This method tests if the MUIA_UserData of the object
2976 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2978 IPTR
Group__MUIM_SetUData(struct IClass
*cl
, Object
*obj
,
2979 struct MUIP_SetUData
*msg
)
2981 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2983 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2984 set(obj
, msg
->attr
, msg
->val
);
2986 DoMethodA(data
->family
, (Msg
) msg
);
2992 * MUIM_SetUDataOnce : This method tests if the MUIA_UserData of the object
2993 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2994 * Stop after the first udata found.
2996 IPTR
Group__MUIM_SetUDataOnce(struct IClass
*cl
, Object
*obj
,
2997 struct MUIP_SetUData
*msg
)
2999 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3001 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
3003 set(obj
, msg
->attr
, msg
->val
);
3006 return DoMethodA(data
->family
, (Msg
) msg
);
3009 /**************************************************************************
3010 MUIM_DragQueryExtented
3011 **************************************************************************/
3012 IPTR
Group__MUIM_DragQueryExtended(struct IClass
*cl
, Object
*obj
,
3013 struct MUIP_DragQueryExtended
*msg
)
3015 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3019 struct MinList
*ChildList
= NULL
;
3021 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3022 cstate
= (Object
*) ChildList
->mlh_Head
;
3023 while ((child
= NextObject(&cstate
)))
3025 if (!(_flags(child
) & MADF_CANDRAW
))
3028 if ((found_obj
= (Object
*) DoMethodA(child
, (Msg
) msg
)))
3029 return (IPTR
) found_obj
;
3031 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3034 /**************************************************************************
3036 **************************************************************************/
3037 IPTR
Group__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
3038 struct MUIP_HandleEvent
*msg
)
3040 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3042 /* check this, otherwise a superclass who has IDCMP_MOUSEBUTTONS
3043 eventhandler might call DoSuperMethod, and this function gets
3044 called even when he have not added any eventhandler */
3046 if ((data
->flags
& GROUP_VIRTUAL
) && msg
->imsg
)
3048 switch (msg
->imsg
->Class
)
3050 case IDCMP_MOUSEBUTTONS
:
3051 /* For virtual groups */
3052 if (msg
->imsg
->Code
== SELECTDOWN
)
3054 if (_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
3055 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
3058 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3059 (IPTR
) & data
->ehn
);
3060 data
->ehn
.ehn_Events
|= IDCMP_INTUITICKS
;
3061 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3062 (IPTR
) & data
->ehn
);
3067 if (data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
)
3069 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3070 (IPTR
) & data
->ehn
);
3071 data
->ehn
.ehn_Events
&= ~IDCMP_INTUITICKS
;
3072 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3073 (IPTR
) & data
->ehn
);
3078 case IDCMP_INTUITICKS
:
3079 if (!(data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
))
3082 if (!(_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
3083 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
3086 LONG new_virt_offx
= data
->virt_offx
;
3087 LONG new_virt_offy
= data
->virt_offy
;
3089 if (msg
->imsg
->MouseX
< _mleft(obj
))
3092 if (new_virt_offx
>= 4)
3097 else if (msg
->imsg
->MouseX
> _mright(obj
))
3101 if (new_virt_offx
> data
->virt_mwidth
- _mwidth(obj
))
3102 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
3103 if (new_virt_offx
< 0)
3107 if (msg
->imsg
->MouseY
< _mtop(obj
))
3110 if (new_virt_offy
>= 4)
3115 else if (msg
->imsg
->MouseY
> _mbottom(obj
))
3119 if (new_virt_offy
> data
->virt_mheight
- _mheight(obj
))
3120 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
3121 if (new_virt_offy
< 0)
3125 if (new_virt_offx
!= data
->virt_offx
3126 || new_virt_offy
!= data
->virt_offy
)
3129 MUIA_Virtgroup_Left
, new_virt_offx
,
3130 MUIA_Virtgroup_Top
, new_virt_offy
,
3131 MUIA_Group_Forward
, FALSE
, TAG_DONE
);
3141 /**************************************************************************
3143 **************************************************************************/
3144 IPTR
Group__MUIM_DrawBackground(struct IClass
*cl
, Object
*obj
,
3145 struct MUIP_DrawBackground
*msg
)
3147 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3149 if (data
->flags
& GROUP_VIRTUAL
)
3151 struct MUIP_DrawBackground msg2
= *msg
;
3153 msg2
.xoffset
+= data
->virt_offx
;
3154 msg2
.yoffset
+= data
->virt_offy
;
3156 return DoSuperMethodA(cl
, obj
, (Msg
) & msg2
);
3159 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3162 /**************************************************************************
3164 Find the given object or return NULL
3165 **************************************************************************/
3166 IPTR
Group__MUIM_FindAreaObject(struct IClass
*cl
, Object
*obj
,
3167 struct MUIP_FindAreaObject
*msg
)
3169 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3172 struct MinList
*ChildList
= NULL
;
3175 if (msg
->obj
== obj
)
3178 // it's one of my children ?
3179 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3180 cstate
= (Object
*) ChildList
->mlh_Head
;
3181 while ((child
= NextObject(&cstate
)))
3183 if (msg
->obj
== child
)
3184 return (IPTR
) child
;
3187 // let the children find it
3188 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3189 cstate
= (Object
*) ChildList
->mlh_Head
;
3190 while ((child
= NextObject(&cstate
)))
3192 Object
*res
= (Object
*) DoMethodA(child
, (Msg
) msg
);
3200 /**************************************************************************
3201 MUIM_Export : to export an object's "contents" to a dataspace object.
3202 **************************************************************************/
3203 static IPTR
Group__MUIM_Export(struct IClass
*cl
, Object
*obj
,
3204 struct MUIP_Export
*msg
)
3206 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3209 struct MinList
*ChildList
= NULL
;
3211 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3215 cstate
= (Object
*) ChildList
->mlh_Head
;
3216 while ((child
= NextObject(&cstate
)))
3218 DoMethodA(child
, (Msg
) msg
);
3225 /**************************************************************************
3226 MUIM_Import : to import an object's "contents" from a dataspace object.
3227 **************************************************************************/
3228 static IPTR
Group__MUIM_Import(struct IClass
*cl
, Object
*obj
,
3229 struct MUIP_Import
*msg
)
3231 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3234 struct MinList
*ChildList
= NULL
;
3236 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3240 cstate
= (Object
*) ChildList
->mlh_Head
;
3241 while ((child
= NextObject(&cstate
)))
3243 DoMethodA(child
, (Msg
) msg
);
3249 /**************************************************************************
3250 MUIM_Notify - disabled now because previous Zune versions had a OM_GET
3251 check in MUIM_Notify which is no longer the case
3252 **************************************************************************/
3254 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3255 struct MUIP_Notify
*msg
)
3257 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3260 struct MinList
*ChildList
;
3262 /* Try at first if understand the message our self
3263 ** We disable the forwarding of the OM_GET message
3264 ** as the MUIM_Notify otherwise would "think" that
3265 ** the group class actually understands the attribute
3266 ** although a child does this only
3268 data
->dont_forward_get
= 1;
3269 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
3271 data
->dont_forward_get
= 0;
3275 /* We ourselves didn't understand the notify tag so we try the
3277 data
->dont_forward_get
= 0;
3279 get(data
->family
, MUIA_Family_List
, (IPTR
*) & (ChildList
));
3280 cstate
= (Object
*) ChildList
->mlh_Head
;
3281 while ((child
= NextObject(&cstate
)))
3283 if (DoMethodA(child
, (Msg
) msg
))
3291 /* Notes about Group_Notify() and echo notification problem:
3292 It was discovered that MUI seems to have some special handling for group class
3293 which will drop notifications on the children which are found to not
3294 understand the attribute.
3296 This is done by checking if an OM_GET on the child returns TRUE.
3297 There's a little problem here because it is not known how big the storage
3298 needed for the attribute in question will be. Almost no class uses anything
3299 bigger than one IPTR. For "big" attributes those return a pointer to the data,
3300 not the data itself. Unfortuntely there are some exceptions like colorwheel
3301 class which does not return a pointer, but the data itself. So it's not
3302 enough to use one single IPTR variable (4 Bytes on 32bit machines, 8 bytes
3303 on 64 bit machines) to store the result of the test-OM_Get.
3305 There is no general way to query the size needed so if one wants to change
3306 Zune to work like MUI one needs to choose a size which one hopes will be
3307 big enough to hold all possible attributes of all classes, old, present
3310 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3311 struct MUIP_Notify
*msg
)
3313 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3316 struct MinList
*ChildList
= NULL
;
3319 data
->dont_forward_get
= 1;
3321 if (GetAttr(msg
->TrigAttr
, obj
, attr
))
3323 data
->dont_forward_get
= 0;
3324 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3326 data
->dont_forward_get
= 0;
3328 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3332 cstate
= (Object
*) ChildList
->mlh_Head
;
3333 while ((child
= NextObject(&cstate
)))
3336 if (GetAttr(msg
->TrigAttr
, child
, attr
))
3338 DoMethodA(child
, (Msg
) msg
);
3339 /* No return here! */
3346 BOOPSI_DISPATCHER(IPTR
, Group_Dispatcher
, cl
, obj
, msg
)
3348 switch (msg
->MethodID
)
3351 return Group__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3353 return Group__OM_DISPOSE(cl
, obj
, msg
);
3355 return Group__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3357 return Group__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3358 case OM_ADDMEMBER
: /* Fall through */
3359 case MUIM_Group_AddTail
:
3360 return Group__MUIM_AddTail(cl
, obj
, (APTR
) msg
);
3361 case MUIM_Group_AddHead
:
3362 return Group__MUIM_AddHead(cl
, obj
, (APTR
) msg
);
3363 case MUIM_Group_Insert
:
3364 return Group__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3365 case OM_REMMEMBER
: /* Fall through */
3366 case MUIM_Group_Remove
:
3367 return Group__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3368 case MUIM_AskMinMax
:
3369 return Group__MUIM_AskMinMax(cl
, obj
, (APTR
) msg
);
3370 case MUIM_Group_ExitChange
:
3371 return Group__MUIM_ExitChange(cl
, obj
, (APTR
) msg
);
3372 case MUIM_Group_ExitChange2
:
3373 return Group__MUIM_ExitChange2(cl
, obj
, (APTR
) msg
);
3374 case MUIM_Group_InitChange
:
3375 return Group__MUIM_InitChange(cl
, obj
, (APTR
) msg
);
3376 case MUIM_Group_Sort
:
3377 return Group__MUIM_Sort(cl
, obj
, (APTR
) msg
);
3378 case MUIM_Group_DoMethodNoForward
:
3379 return Group__MUIM_DoMethodNoForward(cl
, obj
, (APTR
) msg
);
3380 case MUIM_ConnectParent
:
3381 return Group__MUIM_ConnectParent(cl
, obj
, (APTR
) msg
);
3382 case MUIM_DisconnectParent
:
3383 return Group__MUIM_DisconnectParent(cl
, obj
, (APTR
) msg
);
3385 return Group__MUIM_Layout(cl
, obj
, (APTR
) msg
);
3387 return Group__MUIM_Setup(cl
, obj
, (APTR
) msg
);
3389 return Group__MUIM_Cleanup(cl
, obj
, (APTR
) msg
);
3391 return Group__MUIM_Draw(cl
, obj
, (APTR
) msg
);
3393 case MUIM_FindUData
:
3394 return Group__MUIM_FindUData(cl
, obj
, (APTR
) msg
);
3396 return Group__MUIM_GetUData(cl
, obj
, (APTR
) msg
);
3398 return Group__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
3399 case MUIM_SetUDataOnce
:
3400 return Group__MUIM_SetUDataOnce(cl
, obj
, (APTR
) msg
);
3402 return Group__MUIM_Show(cl
, obj
, (APTR
) msg
);
3404 return Group__MUIM_Hide(cl
, obj
, (APTR
) msg
);
3405 case MUIM_HandleEvent
:
3406 return Group__MUIM_HandleEvent(cl
, obj
, (APTR
) msg
);
3407 case MUIM_DrawBackground
:
3408 return Group__MUIM_DrawBackground(cl
, obj
, (APTR
) msg
);
3409 case MUIM_DragQueryExtended
:
3410 return Group__MUIM_DragQueryExtended(cl
, obj
, (APTR
) msg
);
3411 case MUIM_FindAreaObject
:
3412 return Group__MUIM_FindAreaObject(cl
, obj
, (APTR
) msg
);
3414 return Group__MUIM_Export(cl
, obj
, (APTR
) msg
);
3416 return Group__MUIM_Import(cl
, obj
, (APTR
) msg
);
3420 /* Disabled. See above */
3422 return Group_Notify(cl
, obj
, (APTR
) msg
);
3427 case MUIM_DrawParentBackground
:
3428 case MUIM_DragBegin
:
3430 case MUIM_DragQuery
:
3431 case MUIM_DragFinish
:
3433 case MUIM_CreateDragImage
:
3434 case MUIM_DeleteDragImage
:
3436 case MUIM_GoInactive
:
3437 case MUIM_CreateBubble
:
3438 case MUIM_DeleteBubble
:
3439 case MUIM_CreateShortHelp
:
3440 case MUIM_DeleteShortHelp
:
3443 return DoSuperMethodA(cl
, obj
, (APTR
) msg
);
3444 /* Needs not to be forwarded? */
3447 /* sometimes you want to call a superclass method,
3448 * but not dispatching to child.
3449 * But what to do with list methods in a listview ?
3451 Group_DispatchMsg(cl
, obj
, (APTR
) msg
);
3453 return DoSuperMethodA(cl
, obj
, msg
);
3455 BOOPSI_DISPATCHER_END
3460 const struct __MUIBuiltinClass _MUI_Group_desc
=
3464 sizeof(struct MUI_GroupData
),
3465 (void *) Group_Dispatcher