2 Copyright 1999, David Le Corfec.
3 Copyright 2002-2012, 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)
137 /* During minmax calculations objects with a weight of 0 shall
138 be treated like they had identical min/def/max size, ie. fixed size.
140 During layout objects with 0 weight must be treated like fixed-sized
141 too, but for hgroups only in x direction, and for vgroups only in
142 y direction. I think ... */
144 #define w0_defwidth(x) (_hweight(x) ? _defwidth(x) : _minwidth(x))
145 #define w0_maxwidth(x) (_hweight(x) ? _maxwidth(x) : _minwidth(x))
147 #define w0_defheight(x) (_vweight(x) ? _defheight(x) : _minheight(x))
148 #define w0_maxheight(x) (_vweight(x) ? _maxheight(x) : _minheight(x))
150 static const int __version
= 1;
151 static const int __revision
= 1;
153 IPTR
Group__MUIM_Show(struct IClass
*cl
, Object
*obj
,
154 struct MUIP_Show
*msg
);
155 IPTR
Group__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
156 struct MUIP_Hide
*msg
);
158 /*****************************************************************************/
159 /*****************************************************************************/
162 static ULONG
Group_DispatchMsg(struct IClass
*cl
, Object
*obj
, Msg msg
);
164 static void change_active_page(struct IClass
*cl
, Object
*obj
, LONG page
)
166 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
167 LONG newpage
, num_children
= data
->num_children
;
169 if (!(data
->flags
& GROUP_PAGEMODE
))
172 if (data
->titlegroup
!= NULL
)
177 case MUIV_Group_ActivePage_First
:
180 case MUIV_Group_ActivePage_Last
:
181 newpage
= num_children
- 1;
183 case MUIV_Group_ActivePage_Prev
:
184 newpage
= data
->active_page
- 1;
186 newpage
= num_children
- 1;
188 case MUIV_Group_ActivePage_Next
:
189 case MUIV_Group_ActivePage_Advance
:
190 newpage
= (data
->active_page
+ 1) % num_children
;
197 if (newpage
!= data
->active_page
)
199 if (_flags(obj
) & MADF_CANDRAW
)
200 Group__MUIM_Hide(cl
, obj
, NULL
);
202 data
->active_page
= newpage
;
204 if (_flags(obj
) & MADF_CANDRAW
)
206 DoMethod(obj
, MUIM_Layout
);
207 Group__MUIM_Show(cl
, obj
, NULL
);
209 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
212 if (data
->titlegroup
)
213 set(data
->titlegroup
, MUIA_Group_ActivePage
, newpage
);
217 /**************************************************************************
218 Returns the number of visible children. Visible children are all children
219 that have MADF_SHOWME and not MADF_BORDERGADGET set.
220 **************************************************************************/
221 static int Group_GetNumVisibleChildren(struct MUI_GroupData
*data
,
222 struct MinList
*children
)
224 int num_visible_children
= data
->num_children
;
228 /* As there can be invisible children we have subtract those from the total
229 * number of children */
230 cstate
= (Object
*) children
->mlh_Head
;
231 while ((child
= NextObject(&cstate
)))
233 if (IS_HIDDEN(child
))
234 num_visible_children
--;
236 return num_visible_children
;
239 /**************************************************************************
240 Handles insertion of objects - works based on fact that IDs of all methods
241 that use it are the same for Group and Family and that struct share obj at
243 **************************************************************************/
244 struct MUIP_StructWithObj
246 STACKED ULONG MethodID
;
250 static IPTR
Group__MUIM_AddObject(struct IClass
*cl
, Object
*obj
, Msg msg
)
252 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
253 struct MUIP_StructWithObj
*msgint
= (struct MUIP_StructWithObj
*)msg
;
255 DoMethodA(data
->family
, (Msg
) msg
);
256 data
->num_children
++;
258 /* if we are in an application tree, propagate pointers */
259 if (muiNotifyData(obj
)->mnd_GlobalInfo
)
261 /* Only children of groups can have parents */
263 if ((_flags(obj
) & MADF_INVIRTUALGROUP
)
264 || (data
->flags
& GROUP_VIRTUAL
))
266 _flags(msgint
->obj
) |= MADF_INVIRTUALGROUP
;
269 muiNotifyData(msgint
->obj
)->mnd_ParentObject
= obj
;
270 DoMethod(msgint
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
273 if (_flags(obj
) & MADF_SETUP
)
275 DoSetupMethod(msgint
->obj
, muiRenderInfo(obj
));
277 /* if (_flags(obj) & MADF_CANDRAW) */
278 /* DoShowMethod(msg->opam_Object); */
283 /**************************************************************************
285 **************************************************************************/
286 IPTR
Group__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
288 struct MUI_GroupData
*data
;
289 struct TagItem
*tags
, *tag
;
290 BOOL bad_children
= FALSE
;
291 IPTR disabled
= FALSE
;
292 IPTR frame
= MUIV_Frame_None
;
294 D(bug("[group.mui] OM_NEW, object 0x%p\n", obj
));
296 obj
= (Object
*) DoSuperMethodA(cl
, obj
, (Msg
) msg
);
300 /* Initial local instance data */
301 data
= INST_DATA(cl
, obj
);
303 data
->family
= MUI_NewObjectA(MUIC_Family
, NULL
);
306 CoerceMethod(cl
, obj
, OM_DISPOSE
);
310 data
->horiz_spacing
= -1;
311 data
->vert_spacing
= -1;
314 data
->active_page
= 0;
315 get(obj
, MUIA_Frame
, &frame
);
317 /* parse initial taglist */
318 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
322 case MUIA_Group_Child
:
323 D(bug("[group.mui] Adding child 0x%p\n", tag
->ti_Data
));
326 DoMethod(obj
, OM_ADDMEMBER
, tag
->ti_Data
);
327 /* Set first child as group title */
328 if ((frame
== MUIV_Frame_Register
)
329 && (data
->titlegroup
== NULL
))
330 data
->titlegroup
= (Object
*) tag
->ti_Data
;
336 case MUIA_Group_ActivePage
:
337 change_active_page(cl
, obj
, (LONG
) tag
->ti_Data
);
340 case MUIA_Group_Columns
:
341 data
->columns
= (tag
->ti_Data
) > 1 ? tag
->ti_Data
: 1;
345 case MUIA_Group_Horiz
:
346 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_HORIZ
);
349 case MUIA_Group_HorizSpacing
:
350 data
->flags
|= GROUP_HSPACING
;
351 data
->horiz_spacing
= tag
->ti_Data
;
354 case MUIA_Group_LayoutHook
:
355 data
->layout_hook
= (struct Hook
*)tag
->ti_Data
;
358 case MUIA_Group_PageMode
:
359 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_PAGEMODE
);
362 case MUIA_Group_Rows
:
363 data
->rows
= MAX((ULONG
) tag
->ti_Data
, 1);
367 case MUIA_Group_SameHeight
:
368 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_HEIGHT
);
371 case MUIA_Group_SameSize
:
372 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_HEIGHT
);
373 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_WIDTH
);
376 case MUIA_Group_SameWidth
:
377 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_WIDTH
);
380 case MUIA_Group_Spacing
:
381 data
->flags
|= (GROUP_HSPACING
| GROUP_VSPACING
);
382 data
->horiz_spacing
= tag
->ti_Data
;
383 data
->vert_spacing
= tag
->ti_Data
;
386 case MUIA_Group_VertSpacing
:
387 data
->flags
|= GROUP_VSPACING
;
388 data
->vert_spacing
= tag
->ti_Data
;
391 case MUIA_Group_Virtual
:
392 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_VIRTUAL
);
399 CoerceMethod(cl
, obj
, OM_DISPOSE
);
403 /* D(bug("Group_New(0x%lx)\n",obj)); */
405 if (data
->flags
& GROUP_VIRTUAL
)
407 /* This is used by MUI_Render() to determine if group is virtual.
408 * It then installs a clip region.
409 * Also MUI_Layout() uses this. Probably for speed up reason */
410 _flags(obj
) |= MADF_ISVIRTUALGROUP
;
413 /* will forward MUIA_Disabled to children */
414 get(obj
, MUIA_Disabled
, &disabled
);
417 set(obj
, MUIA_Disabled
, TRUE
);
420 /* This is only used for virtual groups */
421 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
; /* Will be filled on demand */
422 data
->ehn
.ehn_Priority
= 10; /* Will hear the click before all
423 * other normal objects */
424 data
->ehn
.ehn_Flags
= 0;
425 data
->ehn
.ehn_Object
= obj
;
426 data
->ehn
.ehn_Class
= cl
;
430 /**************************************************************************
432 **************************************************************************/
433 IPTR
Group__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
435 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
437 if (data
->row_infos
!= NULL
)
438 mui_free(data
->row_infos
);
439 if (data
->col_infos
!= NULL
)
440 mui_free(data
->col_infos
);
441 if (data
->family
!= NULL
)
442 MUI_DisposeObject(data
->family
);
443 return DoSuperMethodA(cl
, obj
, msg
);
446 /**************************************************************************
448 **************************************************************************/
449 IPTR
Group__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
451 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
452 struct TagItem
*tags
= msg
->ops_AttrList
;
455 BOOL need_recalc
= FALSE
;
458 int virt_offx
= data
->virt_offx
, virt_offy
= data
->virt_offy
;
460 /* There are many ways to find out what tag items provided by set()
461 ** we do know. The best way should be using NextTagItem() and simply
462 ** browsing through the list.
465 /* Parse group attributes before calling DoSuperMethodA(),
466 ** otherwise if an app for example sets up a notification
467 ** on MUIA_Group_ActivePage which calls a hook, and then
468 ** the hook function calls get(obj, MUIA_Group_ActivePage),
469 ** it would get returned the old active page instead of the new
473 while ((tag
= NextTagItem(&tags
)) != NULL
)
477 case MUIA_Group_Columns
:
478 data
->columns
= MAX((ULONG
) tag
->ti_Data
, 1);
482 case MUIA_Group_ActivePage
:
483 change_active_page(cl
, obj
, (LONG
) tag
->ti_Data
);
485 case MUIA_Group_Forward
:
486 forward
= tag
->ti_Data
;
488 case MUIA_Group_HorizSpacing
:
489 data
->flags
|= GROUP_HSPACING
;
490 data
->horiz_spacing
= tag
->ti_Data
;
492 case MUIA_Group_Rows
:
493 data
->rows
= MAX((ULONG
) tag
->ti_Data
, 1);
497 case MUIA_Group_Spacing
:
498 data
->flags
|= (GROUP_HSPACING
| GROUP_VSPACING
);
499 data
->horiz_spacing
= tag
->ti_Data
;
500 data
->vert_spacing
= tag
->ti_Data
;
502 case MUIA_Group_VertSpacing
:
503 data
->flags
|= GROUP_VSPACING
;
504 data
->vert_spacing
= tag
->ti_Data
;
506 case MUIA_Virtgroup_Left
:
507 //kprintf("set virtgroup_left: %d\n", tag->ti_Data);
508 virt_offx
= tag
->ti_Data
;
511 case MUIA_Group_LayoutHook
:
513 [ach] Seems like MUI supports setting this attribute after
514 initialization, even though the documentation states
515 otherwise. At least some programs use it...
517 data
->layout_hook
= (struct Hook
*)tag
->ti_Data
;
520 case MUIA_Virtgroup_Top
:
521 //kprintf("set virtgroup_top: %d\n", tag->ti_Data);
522 virt_offy
= tag
->ti_Data
;
528 if (muiRenderInfo(obj
) && need_recalc
)
529 DoMethod(_win(obj
), MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
531 retval
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
533 /* seems to be the documented behaviour, however it should be slow! */
537 /* Attributes which are to be filtered out, so that they are ignored
538 when OM_SET is passed to group's children */
540 tags
= msg
->ops_AttrList
;
541 while ((tag
= NextTagItem(&tags
)) != NULL
)
550 case MUIA_ContextMenu
:
551 case MUIA_ContextMenuTrigger
:
552 case MUIA_ControlChar
:
553 case MUIA_CycleChain
:
556 case MUIA_Group_ActivePage
:
558 case MUIA_FrameTitle
:
559 case MUIA_HorizWeight
:
563 case MUIA_VertWeight
:
565 case MUIA_Virtgroup_Left
:
566 case MUIA_Virtgroup_Top
:
567 case MUIA_AppMessage
:
568 tag
->ti_Tag
= TAG_IGNORE
;
571 /* D(bug("Group_Set(%p) MUIA_Selected forwarded\n", obj)); */
572 /* tag->ti_Tag = TAG_IGNORE; */
577 Group_DispatchMsg(cl
, obj
, (Msg
) msg
);
581 if (virt_offx
!= data
->virt_offx
|| virt_offy
!= data
->virt_offy
)
583 if (_flags(obj
) & MADF_CANDRAW
)
584 Group__MUIM_Hide(cl
, obj
, NULL
);
585 data
->virt_offx
= virt_offx
;
586 data
->virt_offy
= virt_offy
;
587 /* Relayout ourself, this will also relayout all the children */
588 DoMethod(obj
, MUIM_Layout
);
589 if (_flags(obj
) & MADF_CANDRAW
)
590 Group__MUIM_Show(cl
, obj
, NULL
);
592 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
599 /**************************************************************************
601 **************************************************************************/
602 IPTR
Group__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
604 /* small macro to simplify return value storage */
605 #define STORE *(msg->opg_Storage)
607 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
609 switch (msg
->opg_AttrID
)
617 case MUIA_Group_ActivePage
:
618 STORE
= data
->active_page
;
620 case MUIA_Group_ChildList
:
621 return GetAttr(MUIA_Family_List
, data
->family
, msg
->opg_Storage
);
622 case MUIA_Group_Horiz
:
623 STORE
= (data
->flags
& GROUP_HORIZ
);
625 case MUIA_Group_HorizSpacing
:
626 STORE
= data
->horiz_spacing
;
628 case MUIA_Group_VertSpacing
:
629 STORE
= data
->vert_spacing
;
631 case MUIA_Group_ChildCount
:
632 STORE
= data
->num_children
;
634 case MUIA_Virtgroup_Left
:
635 STORE
= data
->virt_offx
;
637 case MUIA_Virtgroup_Top
:
638 STORE
= data
->virt_offy
;
640 case MUIA_Virtgroup_Width
:
641 STORE
= data
->virt_mwidth
;
643 case MUIA_Virtgroup_Height
:
644 STORE
= data
->virt_mheight
;
646 case MUIA_Virtgroup_MinWidth
:
647 STORE
= data
->saved_minwidth
;
649 case MUIA_Virtgroup_MinHeight
:
650 STORE
= data
->saved_minheight
;
654 /* our handler didn't understand the attribute, we simply pass
655 ** it to our superclass now
657 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
660 /* seems to be the documented behaviour, however it should be slow! */
661 if (!data
->dont_forward_get
&& !data
->dont_forward_methods
)
665 struct MinList
*ChildList
= NULL
;
667 get(data
->family
, MUIA_Family_List
, &(ChildList
));
668 cstate
= (Object
*) ChildList
->mlh_Head
;
669 while ((child
= NextObject(&cstate
)))
670 if (DoMethodA(child
, (Msg
) msg
))
678 /**************************************************************************
680 **************************************************************************/
681 IPTR
Group__MUIM_AddTail(struct IClass
*cl
, Object
*obj
,
682 struct MUIP_Group_AddTail
*msg
)
684 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
687 /**************************************************************************
689 **************************************************************************/
690 IPTR
Group__MUIM_AddHead(struct IClass
*cl
, Object
*obj
,
691 struct MUIP_Group_AddHead
*msg
)
693 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
696 /**************************************************************************
698 **************************************************************************/
699 IPTR
Group__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
700 struct MUIP_Group_Insert
*msg
)
702 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
705 /**************************************************************************
707 **************************************************************************/
708 IPTR
Group__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
709 struct MUIP_Group_Remove
*msg
)
711 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
713 if (_flags(obj
) & MADF_CANDRAW
)
714 DoHideMethod(msg
->obj
);
715 if (_flags(obj
) & MADF_SETUP
)
716 DoMethod(msg
->obj
, MUIM_Cleanup
);
717 if (muiNotifyData(obj
)->mnd_GlobalInfo
)
719 DoMethod(msg
->obj
, MUIM_DisconnectParent
);
720 muiNotifyData(msg
->obj
)->mnd_ParentObject
= NULL
;
722 _flags(msg
->obj
) &= ~MADF_INVIRTUALGROUP
;
725 data
->num_children
--;
726 DoMethodA(data
->family
, (Msg
) msg
);
732 /**************************************************************************
734 **************************************************************************/
735 IPTR
Group__MUIM_ConnectParent(struct IClass
*cl
, Object
*obj
,
736 struct MUIP_ConnectParent
*msg
)
738 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
741 struct MinList
*ChildList
= NULL
;
743 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
745 get(data
->family
, MUIA_Family_List
, &(ChildList
));
746 cstate
= (Object
*) ChildList
->mlh_Head
;
747 while ((child
= NextObject(&cstate
)))
749 if ((_flags(obj
) & MADF_INVIRTUALGROUP
)
750 || (data
->flags
& GROUP_VIRTUAL
))
752 _flags(child
) |= MADF_INVIRTUALGROUP
;
755 /* Only children of groups can have parents */
756 muiNotifyData(child
)->mnd_ParentObject
= obj
;
758 DoMethod(child
, MUIM_ConnectParent
, (IPTR
) obj
);
763 /**************************************************************************
764 MUIM_DisconnectParent
765 **************************************************************************/
766 IPTR
Group__MUIM_DisconnectParent(struct IClass
*cl
, Object
*obj
,
767 struct MUIP_ConnectParent
*msg
)
769 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
772 struct MinList
*ChildList
= NULL
;
774 get(data
->family
, MUIA_Family_List
, &(ChildList
));
775 cstate
= (Object
*) ChildList
->mlh_Head
;
776 while ((child
= NextObject(&cstate
)))
778 DoMethodA(child
, (Msg
) msg
);
779 muiNotifyData(child
)->mnd_ParentObject
= NULL
;
780 _flags(child
) &= ~MADF_INVIRTUALGROUP
;
782 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
787 * Put group in exchange state
789 IPTR
Group__MUIM_InitChange(struct IClass
*cl
, Object
*obj
,
790 struct MUIP_Group_InitChange
*msg
)
792 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
794 data
->flags
|= GROUP_CHANGING
;
800 * Will recalculate display after dynamic adding/removing
802 IPTR
Group__MUIM_ExitChange(struct IClass
*cl
, Object
*obj
,
803 struct MUIP_Group_ExitChange
*msg
)
805 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
807 if (data
->flags
& GROUP_CHANGING
)
809 data
->flags
&= ~GROUP_CHANGING
;
811 if ((_flags(obj
) & MADF_SETUP
) && _win(obj
))
813 Object
*win
= _win(obj
);
814 Object
*parent
= obj
;
816 /* CHECKME: Don't call RecalcDisplay if one of our parents is
817 in GROUP_CHANGING state to prevent crash with Zune prefs
818 program NListtree page because NList/NListtree when
819 killing tree images in MUIM_Cleanup uses InitChange/
820 ExitChange. Zune prefs program uses InitChange/ExitChange
821 when switching page -> nesting -> mess. */
823 while ((parent
= _parent(parent
)))
825 struct MUI_GroupData
*pdata
= INST_DATA(cl
, parent
);
830 if (pdata
->flags
& GROUP_CHANGING
)
837 DoMethod(win
, MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
848 IPTR
Group__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
849 struct MUIP_Group_Sort
*msg
)
851 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
854 msg
->MethodID
= MUIM_Family_Sort
;
856 DoMethodA(data
->family
, (APTR
) msg
);
858 /* restore original message */
859 msg
->MethodID
= MUIM_Group_Sort
;
863 /**************************************************************************
864 MUIM_Group_DoMethodNoForward
866 Executes the given method but does not forward it to the children
867 **************************************************************************/
868 IPTR
Group__MUIM_DoMethodNoForward(struct IClass
*cl
, Object
*obj
,
869 struct MUIP_Group_DoMethodNoForward
*msg
)
871 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
873 data
->dont_forward_methods
= 1; /* disable forwarding */
874 rc
= DoMethodA(obj
, (Msg
) & msg
->DoMethodID
);
875 /* Probably doesn't work correctly on AROS? */
877 data
->dont_forward_methods
= 0;
882 * Propagate a method to group children.
884 static ULONG
Group_DispatchMsg(struct IClass
*cl
, Object
*obj
, Msg msg
)
886 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
889 struct MinList
*ChildList
= NULL
;
891 if (data
->dont_forward_methods
)
894 get(data
->family
, MUIA_Family_List
, &(ChildList
));
895 cstate
= (Object
*) ChildList
->mlh_Head
;
896 while ((child
= NextObject(&cstate
)))
898 DoMethodA(child
, (Msg
) msg
);
904 /**************************************************************************
906 **************************************************************************/
907 IPTR
Group__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
908 struct MUIP_Setup
*msg
)
910 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
915 struct MinList
*ChildList
= NULL
;
917 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
920 ASSERT_VALID_PTR(muiGlobalInfo(obj
));
922 if (!(data
->flags
& GROUP_HSPACING
))
923 data
->horiz_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_hspacing
;
924 if (!(data
->flags
& GROUP_VSPACING
))
925 data
->vert_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_vspacing
;
926 get(data
->family
, MUIA_Family_List
, &(ChildList
));
927 cstate
= cstate_copy
= (Object
*) ChildList
->mlh_Head
;
928 while ((child
= NextObject(&cstate
)))
930 #if 0 /* SHOWME affects only show/hide */
931 if (!(_flags(child
) & MADF_SHOWME
))
935 if (!DoSetupMethod(child
, msg
->RenderInfo
))
937 /* Send MUIM_Cleanup to all objects that received MUIM_Setup.
940 cstate
= cstate_copy
;
941 while ((child
= NextObject(&cstate
)) && (child
!= childFailed
))
943 #if 0 /* SHOWME affects only show/hide */
944 if (!(_flags(child
) & MADF_SHOWME
))
947 DoMethod(child
, MUIM_Cleanup
);
953 if (data
->flags
& GROUP_VIRTUAL
)
955 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
963 /**************************************************************************
965 **************************************************************************/
966 IPTR
Group__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
, Msg msg
)
968 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
971 struct MinList
*ChildList
= NULL
;
973 if (data
->flags
& GROUP_VIRTUAL
)
975 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
979 get(data
->family
, MUIA_Family_List
, &(ChildList
));
980 cstate
= (Object
*) ChildList
->mlh_Head
;
981 while ((child
= NextObject(&cstate
)))
983 #if 0 /* SHOWME affects only show/hide */
984 if (!(_flags(child
) & MADF_SHOWME
))
987 DoMethodA(child
, (Msg
) msg
);
989 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
994 /**************************************************************************
995 MUIM_Draw - draw the group
996 **************************************************************************/
997 IPTR
Group__MUIM_Draw(struct IClass
*cl
, Object
*obj
,
998 struct MUIP_Draw
*msg
)
1000 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1003 struct MinList
*ChildList
= NULL
;
1004 struct Rectangle group_rect
; /* child_rect; */
1006 struct Region
*region
= NULL
;
1007 APTR clip
= (APTR
) - 1;
1009 /* D(bug("Group_Draw(%lx) %ldx%ldx%ldx%ld upd=%d page=%d\n", */
1010 /* obj,_left(obj),_top(obj),_right(obj),_bottom(obj), */
1011 /* data->update, data->active_page)); */
1012 /* D(bug("Group_Draw(%p) msg=0x%08lx flags=0x%08lx\n", */
1013 /* obj, msg->flags, _flags(obj))); */
1015 if (data
->flags
& GROUP_CHANGING
)
1018 if (muiGlobalInfo(obj
)->mgi_Prefs
->window_redraw
==
1019 WINDOW_REDRAW_WITHOUT_CLEAR
)
1021 region
= NewRegion();
1024 struct Rectangle rect
;
1026 rect
.MinX
= _left(obj
);
1027 rect
.MinY
= _top(obj
);
1028 rect
.MaxX
= _right(obj
);
1029 rect
.MaxY
= _bottom(obj
);
1031 OrRectRegion(region
, &rect
);
1033 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1034 cstate
= (Object
*) ChildList
->mlh_Head
;
1035 while ((child
= NextObject(&cstate
)))
1038 /* redraw problem with colorwheel in coloradjust register */
1039 if ((data
->flags
& GROUP_PAGEMODE
)
1040 && ((page
!= data
->active_page
)
1041 && (child
!= data
->titlegroup
)))
1044 if ((muiAreaData(child
)->mad_Flags
& MADF_CANDRAW
)
1045 && (_width(child
) > 0) && (_height(child
) > 0))
1047 rect
.MinX
= MAX(_left(child
), _mleft(obj
));
1048 rect
.MinY
= MAX(_top(child
), _mtop(obj
));
1049 rect
.MaxX
= MIN(_right(child
), _mright(obj
));
1050 rect
.MaxY
= MIN(_bottom(child
), _mbottom(obj
));
1052 if ((rect
.MaxX
>= rect
.MinX
)
1053 && (rect
.MaxY
>= rect
.MinY
))
1055 ClearRectRegion(region
, &rect
);
1060 clip
= MUI_AddClipRegion(muiRenderInfo(obj
), region
);
1064 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1068 MUI_RemoveClipRegion(muiRenderInfo(obj
), clip
);
1074 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1076 /* D(bug("Group_Draw(%p) (after dsma) msg=0x%08lx flags=0x%08lx\n", */
1077 /* obj, msg->flags, _flags(obj))); */
1079 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1)
1082 * update is set when changing active page of a page group
1083 * need to redraw background ourself
1085 DoMethod(obj
, MUIM_DrawBackground
,
1086 _mleft(obj
), _mtop(obj
), _mwidth(obj
), _mheight(obj
),
1087 _mleft(obj
), _mtop(obj
), 0);
1093 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2)
1095 LONG left
, top
, right
, bottom
;
1096 LONG diff_virt_offx
= data
->virt_offx
- data
->old_virt_offx
;
1097 LONG diff_virt_offy
= data
->virt_offy
- data
->old_virt_offy
;
1098 struct Rectangle rect
;
1099 struct Rectangle
*clip_rect
= &muiRenderInfo(obj
)->mri_ClipRect
;
1103 if (!diff_virt_offx
&& !diff_virt_offy
)
1108 /* sba: I don't know how MUI handle this but ScrollRasterBF() made problems when scrolling
1109 ** a (partly visible) virtual groups in a virtual group, because e.g. _mtop() is then
1110 ** smaller than the region. ScrollRasterBF() on AmigaOS then marks the complete region
1111 ** as damaged. Using ScrollWindowRaster() solved that problem but it flickers then.
1112 ** To avoid this we prevent that the scroll area is out of the region bounds.
1113 ** The region bounds are setted in MUI_Redraw() but should probably should go in the
1114 ** MUI's clip functions
1117 left
= MAX(_mleft(obj
), clip_rect
->MinX
);
1118 top
= MAX(_mtop(obj
), clip_rect
->MinY
);
1119 right
= MIN(_mright(obj
), clip_rect
->MaxX
);
1120 bottom
= MIN(_mbottom(obj
), clip_rect
->MaxY
);
1123 ** ScrollRasterBF(_rp(obj), diff_virt_offx, diff_virt_offy, _mleft(obj), _mtop(obj), _mright(obj),_mbottom(obj));
1126 ScrollWindowRaster(_window(obj
), diff_virt_offx
, diff_virt_offy
,
1127 left
, top
, right
, bottom
);
1129 if ((region
= NewRegion()))
1136 if (diff_virt_offx
> 0)
1138 rect
.MinX
= right
- diff_virt_offx
+ 1;
1139 if (rect
.MinX
< left
)
1146 rect
.MaxX
= left
- diff_virt_offx
- 1;
1147 if (rect
.MaxX
> right
)
1151 if (rect
.MinX
<= rect
.MaxX
)
1153 DoMethod(obj
, MUIM_DrawBackground
,
1154 rect
.MinX
, rect
.MinY
,
1155 rect
.MaxX
- rect
.MinX
+ 1,
1156 rect
.MaxY
- rect
.MinY
+ 1,
1157 rect
.MinX
, rect
.MinY
, 0);
1159 OrRectRegion(region
, &rect
);
1168 if (diff_virt_offy
> 0)
1170 rect
.MinY
= bottom
- diff_virt_offy
+ 1;
1171 if (rect
.MinY
< top
)
1178 rect
.MaxY
= top
- diff_virt_offy
- 1;
1179 if (rect
.MaxY
> bottom
)
1182 if (rect
.MinY
<= rect
.MaxY
)
1184 DoMethod(obj
, MUIM_DrawBackground
,
1185 rect
.MinX
, rect
.MinY
,
1186 rect
.MaxX
- rect
.MinX
+ 1,
1187 rect
.MaxY
- rect
.MinY
+ 1,
1188 rect
.MinX
, rect
.MinY
, 0);
1190 OrRectRegion(region
, &rect
);
1198 if (!(msg
->flags
& MADF_DRAWOBJECT
)
1199 && !(msg
->flags
& MADF_DRAWALL
))
1204 if (data
->flags
& GROUP_VIRTUAL
&& !region
)
1206 /* Not really needed if MUI Draws all the objects, maybe that's
1207 * what DRAWALL is for??? */
1208 if ((region
= NewRegion()))
1210 struct Rectangle rect
;
1211 rect
.MinX
= _mleft(obj
);
1212 rect
.MinY
= _mtop(obj
);
1213 rect
.MaxX
= _mright(obj
);
1214 rect
.MaxY
= _mbottom(obj
);
1215 OrRectRegion(region
, &rect
);
1219 /* Add clipping region if we have one */
1221 clip
= MUI_AddClipRegion(muiRenderInfo(obj
), region
);
1223 group_rect
= muiRenderInfo(obj
)->mri_ClipRect
;
1225 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1226 cstate
= (Object
*) ChildList
->mlh_Head
;
1227 while ((child
= NextObject(&cstate
)))
1229 if (!(_flags(child
) & MADF_SHOWME
))
1232 if (child
!= data
->titlegroup
)
1235 if ((data
->flags
& GROUP_PAGEMODE
) && ((page
!= data
->active_page
)
1236 && (child
!= data
->titlegroup
)))
1241 // msg->flags |= MADF_DRAWOBJECT; /* yup, do not forget */
1243 // child_rect.MinX = _left(child);
1244 // child_rect.MinY = _top(child);
1245 // child_rect.MaxX = _right(child);
1246 // child_rect.MaxY = _bottom(child);
1247 /* g_print("intersect: a=(%d, %d, %d, %d) b=(%d, %d, %d, %d)\n", */
1248 /* group_rect.x, group_rect.y, */
1249 /* group_rect.width, group_rect.height, */
1250 /* child_rect.x, child_rect.y, */
1251 /* child_rect.width, child_rect.height); */
1253 // if (gdk_rectangle_intersect(&group_rect, &child_rect,
1254 // &muiRenderInfo(obj)->mri_ClipRect))
1255 // DoMethodA(child, (Msg)msg);
1256 /* if (((msg->flags & MADF_DRAWUPDATE) && data->update) */
1257 /* || (data->flags & GROUP_PAGEMODE)) */
1258 MUI_Redraw(child
, MADF_DRAWOBJECT
);
1260 /* MUI_Redraw(child, msg->flags); */
1261 muiRenderInfo(obj
)->mri_ClipRect
= group_rect
;
1262 /* g_print("set back clip to (%d, %d, %d, %d)\n", */
1263 /* group_rect.x, group_rect.y, group_rect.width, group_rect.height); */
1265 /* D(bug("Group_Draw(%p) end\n", obj)); */
1267 if (data
->flags
& GROUP_VIRTUAL
&& region
&& clip
!= (APTR
) - 1)
1269 MUI_RemoveClipRegion(muiRenderInfo(obj
), clip
);
1272 data
->old_virt_offx
= data
->virt_offx
;
1273 data
->old_virt_offy
= data
->virt_offy
;
1280 #define END_MINMAX() \
1281 tmp.MaxHeight = MAX(tmp.MaxHeight, tmp.MinHeight); \
1282 tmp.MaxWidth = MAX(tmp.MaxWidth, tmp.MinWidth); \
1283 tmp.DefHeight = CLAMP(tmp.DefHeight, tmp.MinHeight, tmp.MaxHeight); \
1284 tmp.DefWidth = CLAMP(tmp.DefWidth, tmp.MinWidth, tmp.MaxWidth); \
1285 msg->MinMaxInfo->MinWidth += tmp.MinWidth; \
1286 msg->MinMaxInfo->MinHeight += tmp.MinHeight; \
1287 msg->MinMaxInfo->MaxWidth += tmp.MaxWidth; \
1288 msg->MinMaxInfo->MaxHeight += tmp.MaxHeight; \
1289 msg->MinMaxInfo->DefWidth += tmp.DefWidth; \
1290 msg->MinMaxInfo->DefHeight += tmp.DefHeight;
1293 * MinMax calculation function. When this is called,
1294 * the children of your group have already been asked
1295 * about their min/max dimension so you can use their
1296 * dimensions to calculate yours.
1299 * - Init minwidth and maxwidth with size needed for total child spacing.
1300 * - 1st pass to find maximum minimum width, to set minwidth of each child
1301 * if they should have the same width (for a row of buttons ...)
1302 * - Adjust minwidth w/o making object bigger than their max size.
1304 static void group_minmax_horiz(struct IClass
*cl
, Object
*obj
,
1305 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1307 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1310 struct MUI_MinMax tmp
;
1311 WORD maxminwidth
= 0;
1312 BOOL found_nonzero_vweight
= FALSE
;
1316 tmp
.MaxHeight
= MUI_MAXMAX
;
1317 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1318 (data
->num_visible_children
- 1) * data
->horiz_spacing
;
1320 if (data
->flags
& GROUP_SAME_WIDTH
)
1322 cstate
= (Object
*) children
->mlh_Head
;
1323 while ((child
= NextObject(&cstate
)))
1325 if (IS_HIDDEN(child
))
1327 maxminwidth
= MAX(maxminwidth
, _minwidth(child
));
1331 data
->samesize_maxmin_horiz
= maxminwidth
;
1332 /* D(bug("group_minmax_horiz(%p) : maxminwidth=%d\n", obj, maxminwidth)); */
1334 data
->horiz_weight_sum
= 0;
1335 cstate
= (Object
*) children
->mlh_Head
;
1336 while ((child
= NextObject(&cstate
)))
1340 if (IS_HIDDEN(child
))
1342 if (data
->flags
& GROUP_SAME_WIDTH
)
1344 minwidth
= MAX(maxminwidth
, _minwidth(child
));
1345 minwidth
= MIN(minwidth
, _maxwidth(child
));
1348 minwidth
= _minwidth(child
);
1349 tmp
.MinWidth
+= minwidth
;
1350 tmp
.DefWidth
+= w0_defwidth(child
);
1351 tmp
.MaxWidth
+= w0_maxwidth(child
);
1352 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, MUI_MAXMAX
);
1353 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1354 tmp
.DefHeight
= MAX(tmp
.DefHeight
, _defheight(child
));
1356 if all children have null weight then maxheight=minheight
1357 if all but some children have null weights, the maxheight
1358 is the min of all maxheights
1360 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, _maxheight(child
));
1361 data
->horiz_weight_sum
+= _hweight(child
);
1362 if (_vweight(child
) > 0)
1364 found_nonzero_vweight
= TRUE
;
1367 if (!found_nonzero_vweight
)
1369 tmp
.MaxHeight
= tmp
.MinHeight
;
1372 //if (data->flags & GROUP_VIRTUAL)
1374 //kprintf("# min %d x %d def %d x %d max %d x %d\n",
1375 // tmp.MinWidth, tmp.MinHeight,
1376 // tmp.DefWidth, tmp.DefHeight,
1377 // tmp.MaxWidth, tmp.MaxHeight);
1383 /* minmax calculation for vertical groups (see group_minmax_horiz)
1385 static void group_minmax_vert(struct IClass
*cl
, Object
*obj
,
1386 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1388 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1391 struct MUI_MinMax tmp
;
1392 WORD maxminheight
= 0;
1393 BOOL found_nonzero_hweight
= FALSE
;
1397 tmp
.MaxWidth
= MUI_MAXMAX
;
1398 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1399 (data
->num_visible_children
- 1) * data
->vert_spacing
;
1401 if (data
->flags
& GROUP_SAME_HEIGHT
)
1403 cstate
= (Object
*) children
->mlh_Head
;
1404 while ((child
= NextObject(&cstate
)))
1406 if (IS_HIDDEN(child
))
1408 maxminheight
= MAX(maxminheight
, _minheight(child
));
1412 data
->samesize_maxmin_vert
= maxminheight
;
1413 data
->vert_weight_sum
= 0;
1414 cstate
= (Object
*) children
->mlh_Head
;
1415 while ((child
= NextObject(&cstate
)))
1417 if (IS_HIDDEN(child
))
1420 if (data
->flags
& GROUP_SAME_HEIGHT
)
1421 _minheight(child
) = MIN(maxminheight
, w0_maxheight(child
));
1422 tmp
.MinHeight
+= _minheight(child
);
1423 tmp
.DefHeight
+= w0_defheight(child
);
1424 tmp
.MaxHeight
+= w0_maxheight(child
);
1425 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, MUI_MAXMAX
);
1426 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1427 tmp
.DefWidth
= MAX(tmp
.DefWidth
, _defwidth(child
));
1428 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, _maxwidth(child
));
1429 data
->vert_weight_sum
+= _vweight(child
);
1430 if (_hweight(child
) > 0)
1432 found_nonzero_hweight
= TRUE
;
1435 if (!found_nonzero_hweight
)
1437 tmp
.MaxWidth
= tmp
.MinWidth
;
1445 minmax_2d_rows_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1446 struct MUI_MinMax
*req
, WORD maxmin_height
, WORD maxdef_height
)
1452 /* do not rewind after the while, to process line by line */
1453 cstate
= (Object
*) children
->mlh_Head
;
1455 for (i
= 0; i
< data
->rows
; i
++)
1457 /* calculate min and max height of this row */
1458 int min_h
= 0, def_h
= 0, max_h
= MUI_MAXMAX
;
1459 BOOL found_nonzero_vweight
= FALSE
;
1461 data
->row_infos
[i
].weight
= 0;
1464 while ((child
= NextObject(&cstate
)))
1466 if (IS_HIDDEN(child
))
1468 if (data
->flags
& GROUP_SAME_HEIGHT
)
1470 _minheight(child
) = MIN(maxmin_height
, w0_maxheight(child
));
1471 _defheight(child
) = MIN(maxdef_height
, w0_maxheight(child
));
1473 min_h
= MAX(min_h
, _minheight(child
));
1474 def_h
= MAX(def_h
, w0_defheight(child
));
1475 max_h
= MIN(max_h
, _maxheight(child
));
1476 if (_vweight(child
) > 0)
1478 found_nonzero_vweight
= TRUE
;
1479 data
->row_infos
[i
].weight
+= _vweight(child
);
1482 if ((j
% data
->columns
) == 0)
1485 if (!found_nonzero_vweight
)
1488 max_h
= MAX(max_h
, min_h
);
1489 /* D(bug("row %d : min_h=%d max_h=%d\n", i, min_h, max_h)); */
1491 data
->row_infos
[i
].min
= min_h
;
1492 data
->row_infos
[i
].max
= max_h
;
1493 data
->vert_weight_sum
+= data
->row_infos
[i
].weight
;
1495 req
->MinHeight
+= min_h
;
1496 req
->DefHeight
+= def_h
;
1497 req
->MaxHeight
+= max_h
;
1498 if (req
->MaxHeight
> MUI_MAXMAX
)
1499 req
->MaxHeight
= MUI_MAXMAX
;
1505 minmax_2d_columns_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1506 struct MUI_MinMax
*req
, WORD maxmin_width
, WORD maxdef_width
)
1512 for (i
= 0; i
< data
->columns
; i
++)
1514 /* calculate min and max width of this column */
1515 int min_w
= 0, def_w
= 0, max_w
= MUI_MAXMAX
;
1516 BOOL found_nonzero_hweight
= FALSE
;
1518 data
->col_infos
[i
].weight
= 0;
1521 /* process all children to get children on a column */
1522 cstate
= (Object
*) children
->mlh_Head
;
1523 while ((child
= NextObject(&cstate
)))
1525 if (IS_HIDDEN(child
))
1528 if (((j
- 1) % data
->columns
) != i
)
1530 if (data
->flags
& GROUP_SAME_WIDTH
)
1532 _minwidth(child
) = MIN(maxmin_width
, w0_maxwidth(child
));
1533 _defwidth(child
) = MIN(maxdef_width
, w0_maxwidth(child
));
1535 min_w
= MAX(min_w
, _minwidth(child
));
1536 def_w
= MAX(def_w
, w0_defwidth(child
));
1538 /* this handles the case of null weight children, which limit
1539 * the max size if they're alone, but not if they are with
1540 * non-null weight obj
1542 max_w
= MIN(max_w
, _maxwidth(child
));
1543 if (_hweight(child
) > 0)
1545 found_nonzero_hweight
= TRUE
;
1546 data
->col_infos
[i
].weight
+= _hweight(child
);
1549 if (!found_nonzero_hweight
)
1552 max_w
= MAX(max_w
, min_w
);
1553 /* D(bug("col %d : min_w=%d max_w=%d\n", i, min_w, max_w)); */
1555 data
->col_infos
[i
].min
= min_w
;
1556 data
->col_infos
[i
].max
= max_w
;
1557 data
->horiz_weight_sum
+= data
->col_infos
[i
].weight
;
1559 req
->MinWidth
+= min_w
;
1560 req
->DefWidth
+= def_w
;
1561 req
->MaxWidth
+= max_w
;
1562 if (req
->MaxWidth
> MUI_MAXMAX
)
1563 req
->MaxWidth
= MUI_MAXMAX
;
1568 group_minmax_2d(struct IClass
*cl
, Object
*obj
,
1569 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1571 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1574 struct MUI_MinMax tmp
;
1582 if (data
->num_children
% data
->rows
)
1585 data
->rows
= data
->num_children
;
1588 data
->columns
= data
->num_children
/ data
->rows
;
1592 if (data
->num_children
% data
->columns
)
1595 data
->columns
= data
->num_children
;
1598 data
->rows
= data
->num_children
/ data
->columns
;
1601 if (data
->columns
< 1)
1606 if (data
->row_infos
!= NULL
)
1607 mui_free(data
->row_infos
);
1609 data
->row_infos
= mui_alloc(data
->rows
* sizeof(struct layout2d_elem
));
1610 if (NULL
== data
->row_infos
)
1613 if (data
->col_infos
!= NULL
)
1614 mui_free(data
->col_infos
);
1617 mui_alloc(data
->columns
* sizeof(struct layout2d_elem
));
1618 if (NULL
== data
->col_infos
)
1621 data
->horiz_weight_sum
= 0;
1622 data
->vert_weight_sum
= 0;
1624 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1625 (data
->rows
- 1) * data
->vert_spacing
;
1626 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1627 (data
->columns
- 1) * data
->horiz_spacing
;
1628 /* get minimum dims if same dims for all children are needed */
1634 if ((data
->flags
& GROUP_SAME_WIDTH
)
1635 || (data
->flags
& GROUP_SAME_HEIGHT
))
1637 cstate
= (Object
*) children
->mlh_Head
;
1638 while ((child
= NextObject(&cstate
)))
1640 if (!(_flags(child
) & MADF_SHOWME
))
1642 maxmin_width
= MAX(maxmin_width
, _minwidth(child
));
1643 maxmin_height
= MAX(maxmin_height
, _minheight(child
));
1644 maxdef_width
= MAX(maxdef_width
, w0_defwidth(child
));
1645 maxdef_height
= MAX(maxdef_height
, w0_defheight(child
));
1647 /* g_print("2d group: mminw=%d mminh=%d\n", */
1648 /* maxmin_width, maxmin_height); */
1650 if (data
->flags
& GROUP_SAME_HEIGHT
)
1651 data
->samesize_maxmin_vert
= maxmin_height
;
1653 data
->samesize_maxmin_vert
= 0;
1655 if (data
->flags
& GROUP_SAME_WIDTH
)
1656 data
->samesize_maxmin_horiz
= maxmin_width
;
1658 data
->samesize_maxmin_horiz
= 0;
1660 minmax_2d_rows_pass(data
, children
, &tmp
, maxmin_height
, maxdef_height
);
1661 minmax_2d_columns_pass(data
, children
, &tmp
, maxmin_width
,
1669 group_minmax_pagemode(struct IClass
*cl
, Object
*obj
,
1670 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1674 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1675 struct MUI_MinMax tmp
= { 0, 0, MUI_MAXMAX
, MUI_MAXMAX
, 0, 0 };
1677 cstate
= (Object
*) children
->mlh_Head
;
1679 D(bug("minmax_pagemode(%lx)\n", obj
, tmp
.DefWidth
));
1681 while ((child
= NextObject(&cstate
)))
1683 if (!(_flags(child
) & MADF_SHOWME
))
1686 if (child
== data
->titlegroup
)
1689 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1690 D(bug("minmax_pagemode(%p) minh child = %d tmpmin=%d\n", obj
,
1691 _minheight(child
), tmp
.MinHeight
));
1692 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1693 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, w0_maxheight(child
));
1694 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, w0_maxwidth(child
));
1695 tmp
.DefHeight
= MAX(tmp
.DefHeight
,
1696 ((w0_defheight(child
) <
1697 MUI_MAXMAX
) ? w0_defheight(child
) : tmp
.DefHeight
));
1700 ((w0_defwidth(child
) <
1701 MUI_MAXMAX
) ? w0_defwidth(child
) : tmp
.DefWidth
));
1702 D(bug("minmax_pagemode(%lx) defw = %ld\n", obj
, tmp
.DefWidth
));
1705 if (data
->titlegroup
)
1707 tmp
.MinHeight
+= _minheight(data
->titlegroup
);
1708 tmp
.MaxHeight
+= w0_maxheight(data
->titlegroup
);
1709 tmp
.DefHeight
+= w0_defheight(data
->titlegroup
);
1715 /**************************************************************************
1716 MUIM_AskMinMax : ask children about min/max sizes, then
1717 either call a hook, or the builtin method, to calculate our minmax
1718 **************************************************************************/
1719 IPTR
Group__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1720 struct MUIP_AskMinMax
*msg
)
1722 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1723 struct MUI_LayoutMsg lm
;
1724 struct MUIP_AskMinMax childMsg
;
1725 struct MUI_MinMax childMinMax
;
1728 LONG super_minwidth
, super_minheight
;
1731 * let our superclass first fill in its size with frame, inner spc etc ...
1733 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1734 super_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1735 super_minheight
= msg
->MinMaxInfo
->MinHeight
;
1740 childMsg
.MethodID
= msg
->MethodID
;
1741 childMsg
.MinMaxInfo
= &childMinMax
;
1742 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
1744 cstate
= (Object
*) lm
.lm_Children
->mlh_Head
;
1746 while ((child
= NextObject(&cstate
)))
1748 if (!(_flags(child
) & MADF_SHOWME
))
1749 /* BORDERGADGETs should handle this itself */
1752 DoMethodA(child
, (Msg
) & childMsg
);
1753 /* D(bug("*** group %lx, child %lx min=%ld,%ld\n", */
1754 /* obj, child, childMinMax.MinWidth, childMinMax.MinHeight)); */
1755 __area_finish_minmax(child
, childMsg
.MinMaxInfo
);
1759 * Use children infos to calculate group size
1761 if (data
->flags
& GROUP_PAGEMODE
)
1763 D(bug("minmax_pagemode(%p) minh initial = %d\n", obj
,
1764 msg
->MinMaxInfo
->MinHeight
));
1765 group_minmax_pagemode(cl
, obj
, lm
.lm_Children
, msg
);
1766 D(bug("minmax_pagemode(%p) minh = %d\n", obj
,
1767 msg
->MinMaxInfo
->MinHeight
));
1769 else if (data
->layout_hook
)
1771 lm
.lm_Type
= MUILM_MINMAX
;
1772 CallHookPkt(data
->layout_hook
, obj
, &lm
);
1774 if (lm
.lm_MinMax
.MaxHeight
< lm
.lm_MinMax
.MinHeight
)
1775 lm
.lm_MinMax
.MaxHeight
= lm
.lm_MinMax
.MinHeight
;
1776 if (lm
.lm_MinMax
.DefHeight
< lm
.lm_MinMax
.MinHeight
)
1777 lm
.lm_MinMax
.DefHeight
= lm
.lm_MinMax
.MinHeight
;
1778 if (lm
.lm_MinMax
.MaxWidth
< lm
.lm_MinMax
.MinWidth
)
1779 lm
.lm_MinMax
.MaxWidth
= lm
.lm_MinMax
.MinWidth
;
1780 if (lm
.lm_MinMax
.DefWidth
< lm
.lm_MinMax
.MinWidth
)
1781 lm
.lm_MinMax
.DefWidth
= lm
.lm_MinMax
.MinWidth
;
1783 //kprintf("### min %d x %d def %d x %d max %d x %d\n",
1784 // msg->MinMaxInfo->MinWidth,
1785 // msg->MinMaxInfo->MinHeight,
1786 // msg->MinMaxInfo->DefWidth,
1787 // msg->MinMaxInfo->DefHeight,
1788 // msg->MinMaxInfo->MaxWidth,
1789 // msg->MinMaxInfo->MaxHeight);
1791 msg
->MinMaxInfo
->MinWidth
+= lm
.lm_MinMax
.MinWidth
;
1792 msg
->MinMaxInfo
->MinHeight
+= lm
.lm_MinMax
.MinHeight
;
1793 msg
->MinMaxInfo
->MaxWidth
+= lm
.lm_MinMax
.MaxWidth
;
1794 if (msg
->MinMaxInfo
->MaxWidth
> MUI_MAXMAX
)
1795 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1796 msg
->MinMaxInfo
->MaxHeight
+= lm
.lm_MinMax
.MaxHeight
;
1797 if (msg
->MinMaxInfo
->MaxHeight
> MUI_MAXMAX
)
1798 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1799 msg
->MinMaxInfo
->DefWidth
+= lm
.lm_MinMax
.DefWidth
;
1800 msg
->MinMaxInfo
->DefHeight
+= lm
.lm_MinMax
.DefHeight
;
1802 //kprintf("#### min %d x %d def %d x %d max %d x %d\n",
1803 // msg->MinMaxInfo->MinWidth,
1804 // msg->MinMaxInfo->MinHeight,
1805 // msg->MinMaxInfo->DefWidth,
1806 // msg->MinMaxInfo->DefHeight,
1807 // msg->MinMaxInfo->MaxWidth,
1808 // msg->MinMaxInfo->MaxHeight);
1813 if ((data
->rows
== 1) && (data
->columns
== 1))
1815 data
->num_visible_children
=
1816 Group_GetNumVisibleChildren(data
, lm
.lm_Children
);
1817 if (data
->flags
& GROUP_HORIZ
)
1818 group_minmax_horiz(cl
, obj
, lm
.lm_Children
, msg
);
1820 group_minmax_vert(cl
, obj
, lm
.lm_Children
, msg
);
1824 group_minmax_2d(cl
, obj
, lm
.lm_Children
, msg
);
1828 if (data
->flags
& GROUP_VIRTUAL
)
1830 data
->saved_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1831 data
->saved_minheight
= msg
->MinMaxInfo
->MinHeight
;
1832 msg
->MinMaxInfo
->MinWidth
= super_minwidth
+ 2;
1833 msg
->MinMaxInfo
->MinHeight
= super_minheight
+ 2;
1835 //kprintf("## min %d x %d def %d x %d max %d x %d\n",
1836 // msg->MinMaxInfo->MinWidth,
1837 // msg->MinMaxInfo->MinHeight,
1838 // msg->MinMaxInfo->DefWidth,
1839 // msg->MinMaxInfo->DefHeight,
1840 // msg->MinMaxInfo->MaxWidth,
1841 // msg->MinMaxInfo->MaxHeight);
1849 // enforce minmax constraint, but also update total growable/shrinkable weights
1850 // while we're at it
1851 static void Layout1D_minmax_constraint(WORD
*sizep
, WORD minsize
,
1852 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
1853 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
, WORD samesize
)
1855 WORD size
= *sizep
, remain
= *remainp
,
1856 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
1857 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
1859 /* D(bug("L1D_minmax_c size=%d min=%d max=%d w=%d ss=%d\n", */
1860 /* size, minsize, maxsize, */
1861 /* weight, samesize)); */
1863 if ((samesize
> 0) && (weight
== 0))
1865 remain
+= size
- samesize
;
1871 if (size
<= minsize
) // too little
1873 remain
+= size
- minsize
;
1876 if (size
== maxsize
)
1879 else if (size
>= maxsize
) // too big
1881 remain
+= size
- maxsize
;
1886 if (!((samesize
> 0) && (weight
== 0)))
1889 weightgrow
+= weight
;
1891 weightshrink
+= weight
;
1896 *sizegrowp
= sizegrow
;
1897 *sizeshrinkp
= sizeshrink
;
1898 *weightgrowp
= weightgrow
;
1899 *weightshrinkp
= weightshrink
;
1903 // redistribute excess size to growable child, or reduce size of a shrinkable
1905 static void Layout1D_redistribution(WORD
*sizep
, WORD minsize
,
1906 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
1907 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
)
1909 WORD size
= *sizep
, remain
= *remainp
,
1910 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
1911 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
1916 if ((remain
> 0) && (size
< maxsize
))
1920 newsize
= (sizegrow
* weight
+ weightgrow
/ 2) / weightgrow
;
1922 /* D(bug("newsize=%ld == size_growa=%ld * w=%ld / weight_grow=%d\n", */
1923 /* newsize, sizegrow, weight, weightgrow)); */
1925 /* take care of off-by-1 errors that may toggle remainder sign
1926 * by ensuring convergence to 0
1928 if (remain
- newsize
+ size
< 0)
1930 /* D(bug("adding remainder=%d => size = %d\n", */
1931 /* remain, size + remain)); */
1937 remain
-= newsize
- size
;
1940 weightgrow
-= weight
;
1943 else if ((remain
< 0) && (size
> minsize
))
1947 newsize
= (sizeshrink
* weight
+ weightshrink
/ 2) / weightshrink
;
1949 /* D(bug("newsize=%ld == size_shrinkables=%ld * w=%ld " */
1950 /* "/ weight_shrinkables=%d\n", */
1951 /* newsize, sizeshrink, weight, weightshrink)); */
1953 if (remain
- newsize
+ size
> 0)
1955 /* D(bug("adding remainder=%d => size = %d\n", */
1956 /* remain, size + remain)); */
1962 remain
-= newsize
- size
;
1965 weightshrink
-= weight
;
1971 *sizegrowp
= sizegrow
;
1972 *sizeshrinkp
= sizeshrink
;
1973 *weightgrowp
= weightgrow
;
1974 *weightshrinkp
= weightshrink
;
1978 // 2 passes at most, less on average (0.5 or 1.5), each does
1979 // - a minmax clamping, evenutally adding to a remainder
1980 // (remainder = missing (underflow) or remaining (overflow) space compared
1981 // to ideal sizes where children fill the whole group)
1982 // - a redistribution of the remainder, by growing (pos. remainder) or
1983 // shrinking (neg. remainder) children able to support it.
1985 // Occasionnaly the first time the redistribution is done, the minmax
1986 // constraint can be broken, thus the extra pass to check and eventually
1987 // redistribute. The second redistribution never breaks minmax constraint
1988 // (there should be a mathematical proof, but feel free to prove me wrong
1990 static void Layout1D_minmax_constraints_and_redistrib(struct MinList
1991 *children
, WORD total_size
, WORD remainder
, WORD samesize
,
1998 for (i
= 0; i
< 2; i
++)
2000 WORD size_growables
= total_size
;
2001 WORD size_shrinkables
= total_size
;
2002 ULONG weight_growables
= 0;
2003 ULONG weight_shrinkables
= 0;
2005 /* D(bug("start : rem=%ld, A=%ld, size_growables=%ld, " */
2006 /* "size_shrinkables=%ld\n", */
2007 /* remainder, total_size, size_growables, size_shrinkables)); */
2009 // minmax constraints
2010 cstate
= (Object
*) children
->mlh_Head
;
2011 while ((child
= NextObject(&cstate
)))
2013 /* WORD old_size; */
2015 if (IS_HIDDEN(child
))
2020 /* old_size = _width(child); */
2022 Layout1D_minmax_constraint(&_width(child
), _minwidth(child
),
2023 _maxwidth(child
), &remainder
, &size_growables
,
2024 &size_shrinkables
, &weight_growables
,
2025 &weight_shrinkables
, _hweight(child
), samesize
);
2027 /* D(bug("loop1 on %p : width=%d was %d, rem=%d, A=%d, " */
2028 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2029 /* child, _width(child), old_size, remainder, total_size, */
2030 /* size_growables, size_shrinkables, _hweight(child), */
2031 /* _minwidth(child), _maxwidth(child))); */
2033 else // ! group_horiz
2035 /* old_size = _height(child); */
2037 Layout1D_minmax_constraint(&_height(child
),
2038 _minheight(child
), _maxheight(child
), &remainder
,
2039 &size_growables
, &size_shrinkables
, &weight_growables
,
2040 &weight_shrinkables
, _vweight(child
), samesize
);
2042 /* D(bug("loop1 on %p : h=%ld was %d, rem=%d, A=%d, " */
2043 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2044 /* child, _height(child), old_size, remainder, total_size,*/
2045 /* size_growables, size_shrinkables, _vweight(child), */
2046 /* _minheight(child), _maxheight(child))); */
2047 } // if (group_horiz)
2048 } // while child, minmax constraints
2054 /* D(bug("mid : rem=%d, A=%d, size_grow=%d, size_shrink=%d, " */
2055 /* "wg=%ld, ws=%ld\n", remainder, total_size, size_growables, */
2056 /* size_shrinkables, weight_growables, weight_shrinkables)); */
2058 // distribute remaining space to possible candidates
2059 cstate
= (Object
*) children
->mlh_Head
;
2060 while (((child
= NextObject(&cstate
)) != NULL
) && (remainder
!= 0))
2062 /* WORD old_size; */
2064 if (IS_HIDDEN(child
))
2069 /* old_size = _width(child); */
2071 Layout1D_redistribution(&_width(child
), _minwidth(child
),
2072 _maxwidth(child
), &remainder
, &size_growables
,
2073 &size_shrinkables
, &weight_growables
,
2074 &weight_shrinkables
, _hweight(child
));
2076 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2077 /* "size_grow=%d, size_shrink=%d\n", child, */
2078 /* _width(child), old_size, remainder, total_size, */
2079 /* size_growables, size_shrinkables)); */
2081 else // ! group_horiz
2083 /* old_size = _height(child); */
2085 Layout1D_redistribution(&_height(child
), _minheight(child
),
2086 _maxheight(child
), &remainder
, &size_growables
,
2087 &size_shrinkables
, &weight_growables
,
2088 &weight_shrinkables
, _vweight(child
));
2090 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2091 /* "size_grow=%d, size_shrink=%d\n", child, */
2092 /* _height(child), old_size, remainder, total_size, */
2093 /* size_growables, size_shrinkables)); */
2094 } // if (group_horiz)
2096 } // while child, redistribution
2098 /* if (remainder != 0) */
2100 /* D(bug("end : rem=%ld, A=%ld, size_grow=%ld, size_shrink=%ld\n", */
2101 /* remainder, total_size, size_growables, size_shrinkables)); */
2103 // dont break here if remainder == 0, some minmax constraints
2104 // may not be respected
2107 // to easily spot layout bugs, nothing like a (division by zero) exception
2108 /* if (remainder != 0) */
2110 /* ASSERT(remainder != 0); */
2111 /* D(bug("gonna crash, remainder = %d\n", remainder)); */
2112 /* remainder /= 0; */
2117 static void Layout1D_weight_constraint(WORD
*total_sizep
,
2118 WORD
*total_init_sizep
,
2119 ULONG
*total_weightp
, WORD
*sizep
, UWORD weight
, WORD minsize
)
2121 if (*total_weightp
> 0)
2122 *sizep
= (*total_sizep
* weight
+ *total_weightp
/ 2)
2127 *total_weightp
-= weight
;
2128 *total_sizep
-= *sizep
;
2129 *total_init_sizep
+= *sizep
;
2133 static void group_layout_vert(struct IClass
*cl
, Object
*obj
,
2134 struct MinList
*children
)
2136 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2140 WORD remainder
; /* must converge to 0 to successfully end layout */
2142 WORD total_size_backup
;
2143 WORD total_init_size
; /* total size of the ideally sized children */
2150 //kprintf("group_layout_vert: virtoff = %d,%d\n",
2151 // data->virt_offx, data->virt_offy);
2153 if (data
->flags
& GROUP_VIRTUAL
)
2156 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2157 _maxwidth(obj
) - _subwidth(obj
));
2158 data
->virt_mheight
=
2159 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2160 _maxheight(obj
) - _subheight(obj
));
2162 layout_width
= data
->virt_mwidth
;
2163 layout_height
= data
->virt_mheight
;
2167 layout_width
= _mwidth(obj
);
2168 layout_height
= _mheight(obj
);
2171 total_weight
= data
->vert_weight_sum
;
2172 total_init_size
= 0;
2174 layout_height
- (data
->num_visible_children
-
2175 1) * data
->vert_spacing
;
2176 total_size_backup
= total_size
;
2178 /* D(bug("\nvert layout for %p, A=%d W=%ld\n", */
2179 /* obj, total_size, total_weight)); */
2181 // weight constraints
2182 // calculate ideal size for each object, and total ideal size
2183 cstate
= (Object
*) children
->mlh_Head
;
2184 while ((child
= NextObject(&cstate
)))
2186 if (IS_HIDDEN(child
))
2189 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2190 &total_weight
, &_height(child
), _vweight(child
),
2192 /* D(bug("child %p : ideal=%d w=%ld\n", */
2193 /* child, _height(child), _vweight(child))); */
2194 } // while child, weight constraints
2196 total_size
= total_size_backup
;
2197 remainder
= total_size
- total_init_size
;
2199 if (data
->flags
& GROUP_VIRTUAL
)
2201 /* This is also true for non virtual groups, but if this would be the
2202 ** case then there is a bug in the layout function
2208 Layout1D_minmax_constraints_and_redistrib(children
,
2211 (data
->flags
& GROUP_SAME_HEIGHT
) ? data
->samesize_maxmin_vert
: 0,
2215 cstate
= (Object
*) children
->mlh_Head
;
2216 while ((child
= NextObject(&cstate
)))
2218 if (IS_HIDDEN(child
))
2221 width
= MIN(_maxwidth(child
), layout_width
);
2222 width
= MAX(width
, _minwidth(child
));
2223 left
= (layout_width
- width
) / 2;
2225 /* D(bug("child %p -> layout %d x %d\n", */
2226 /* child, width, _height(child))); */
2227 if (!MUI_Layout(child
, left
, top
, width
, _height(child
), 0))
2229 top
+= data
->vert_spacing
+ _height(child
);
2235 static void group_layout_horiz(struct IClass
*cl
, Object
*obj
,
2236 struct MinList
*children
)
2238 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2242 WORD remainder
; /* must converge to 0 to succesfully end layout */
2244 WORD total_size_backup
;
2245 WORD total_init_size
; /* total size of the ideally sized children */
2252 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2253 // data->virt_offx, data->virt_offy);
2255 if (data
->flags
& GROUP_VIRTUAL
)
2258 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2259 _maxwidth(obj
) - _subwidth(obj
));
2260 data
->virt_mheight
=
2261 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2262 _maxheight(obj
) - _subheight(obj
));
2264 layout_width
= data
->virt_mwidth
;
2265 layout_height
= data
->virt_mheight
;
2267 //kprintf("group_layout_horiz: layoutsize %d x %d "
2268 // " virtsize %d x %d msize %d x %d\n",
2269 // layout_width, layout_height, data->virt_mwidth,
2270 // data->virt_mheight,
2271 // _mwidth(obj), _mheight(obj));
2275 layout_width
= _mwidth(obj
);
2276 layout_height
= _mheight(obj
);
2279 total_weight
= data
->horiz_weight_sum
;
2280 total_init_size
= 0;
2282 layout_width
- (data
->num_visible_children
-
2283 1) * data
->horiz_spacing
;
2284 total_size_backup
= total_size
;
2286 /* D(bug("\nhoriz layout for %p, A=%d W=%ld\n", */
2287 /* obj, total_size, total_weight)); */
2289 // weight constraints
2290 // calculate ideal size for each object, and total ideal size
2291 cstate
= (Object
*) children
->mlh_Head
;
2292 while ((child
= NextObject(&cstate
)))
2294 if (IS_HIDDEN(child
))
2297 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2298 &total_weight
, &_width(child
), _hweight(child
),
2300 /* D(bug("child %p : ideal=%d w=%ld\n", */
2301 /* child, _width(child), _hweight(child))); */
2302 } // while child, weight constraints
2304 total_size
= total_size_backup
;
2305 if (data
->horiz_weight_sum
> 0)
2306 remainder
= total_size
- total_init_size
;
2310 if (data
->flags
& GROUP_VIRTUAL
)
2312 /* This is also true for non virtual groups, but if this would be the
2313 ** case then there is a bug in the layout function
2319 Layout1D_minmax_constraints_and_redistrib(children
,
2322 (data
->flags
& GROUP_SAME_WIDTH
) ? data
->samesize_maxmin_horiz
: 0,
2326 cstate
= (Object
*) children
->mlh_Head
;
2327 while ((child
= NextObject(&cstate
)))
2329 if (IS_HIDDEN(child
))
2332 height
= MIN(_maxheight(child
), layout_height
);
2333 height
= MAX(height
, _minheight(child
));
2334 top
= (layout_height
- height
) / 2;
2336 /* D(bug("child %p -> layout %d x %d\n", */
2337 /* child, _width(child), height)); */
2338 if (!MUI_Layout(child
, left
, top
, _width(child
), height
, 0))
2340 left
+= data
->horiz_spacing
+ _width(child
);
2346 static void Layout2D_weight_constraint(struct MUI_GroupData
*data
,
2347 struct layout2d_elem
*row_infos
,
2348 struct layout2d_elem
*col_infos
,
2349 WORD total_size_height
, WORD total_size_width
,
2350 WORD
*total_init_height
, WORD
*total_init_width
)
2353 ULONG total_weight_vert
= data
->vert_weight_sum
;
2354 ULONG total_weight_horiz
= data
->horiz_weight_sum
;
2356 *total_init_height
= 0;
2357 *total_init_width
= 0;
2359 /* calc row heights */
2360 for (i
= 0; i
< data
->rows
; i
++)
2362 if (total_weight_vert
> 0)
2364 (total_size_height
* row_infos
[i
].weight
+
2365 total_weight_vert
/ 2) / total_weight_vert
;
2367 row_infos
[i
].dim
= row_infos
[i
].min
;
2369 /* D(bug("l2 row %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2370 /* i, row_infos[i].dim, */
2371 /* row_infos[i].weight, total_size_height, total_weight_vert)); */
2373 total_weight_vert
-= row_infos
[i
].weight
;
2374 total_size_height
-= row_infos
[i
].dim
;
2375 *total_init_height
+= row_infos
[i
].dim
;
2378 /* calc columns widths */
2379 for (i
= 0; i
< data
->columns
; i
++)
2381 if (total_weight_horiz
)
2383 (total_size_width
* col_infos
[i
].weight
+
2384 total_weight_horiz
/ 2) / total_weight_horiz
;
2386 col_infos
[i
].dim
= col_infos
[i
].min
;
2388 /* D(bug("l2 col %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2389 /* i, col_infos[i].dim, */
2390 /* col_infos[i].weight, total_size_width, total_weight_horiz)); */
2392 total_weight_horiz
-= col_infos
[i
].weight
;
2393 total_size_width
-= col_infos
[i
].dim
;
2394 *total_init_width
+= col_infos
[i
].dim
;
2400 static void Layout2D_minmax_constraints_and_redistrib(struct layout2d_elem
2401 *infos
, WORD nitems
, WORD total_size
, WORD samesize
, WORD remainder
)
2405 /* D(bug("L2D mc&r n=%d A=%d ss=%d rem=%d\n", */
2406 /* nitems, total_size, samesize, remainder)); */
2408 for (j
= 0; j
< 2; j
++)
2410 WORD size_growables
= total_size
;
2411 WORD size_shrinkables
= total_size
;
2412 ULONG weight_growables
= 0;
2413 ULONG weight_shrinkables
= 0;
2414 /* WORD old_size; */
2417 // minmax constraints
2418 for (i
= 0; i
< nitems
; i
++)
2420 /* old_size = infos[i].dim; */
2422 /* D(bug("bef loop1 on %d : size=%d, rem=%d, A=%d, " */
2423 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2424 /* i, infos[i].dim, remainder, total_size, */
2425 /* size_growables, size_shrinkables, infos[i].weight, */
2426 /* infos[i].min, infos[i].max)); */
2428 Layout1D_minmax_constraint(&infos
[i
].dim
, infos
[i
].min
,
2429 infos
[i
].max
, &remainder
, &size_growables
,
2430 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2431 infos
[i
].weight
, samesize
);
2433 /* D(bug("loop1 on %d : size=%d was %d, rem=%d, A=%d, " */
2434 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2435 /* i, infos[i].dim, old_size, remainder, total_size, */
2436 /* size_growables, size_shrinkables, infos[i].weight, */
2437 /* infos[i].min, infos[i].max)); */
2443 for (i
= 0; i
< nitems
; i
++)
2445 /* old_size = infos[i].dim; */
2447 /* D(bug("bef loop2 on %d : size=%d, rem=%d, A=%d, " */
2448 /* "size_grow=%d, size_shrink=%d\n", i, */
2449 /* infos[i].dim, remainder, total_size, */
2450 /* size_growables, size_shrinkables)); */
2452 Layout1D_redistribution(&infos
[i
].dim
, infos
[i
].min
,
2453 infos
[i
].max
, &remainder
, &size_growables
,
2454 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2457 /* D(bug("loop2 on %d : size=%d was %d, rem=%d, A=%d, " */
2458 /* "size_grow=%d, size_shrink=%d\n", i, */
2459 /* infos[i].dim, old_size, remainder, total_size, */
2460 /* size_growables, size_shrinkables)); */
2466 layout_2d_distribute_space(struct MUI_GroupData
*data
,
2467 struct layout2d_elem
*row_infos
,
2468 struct layout2d_elem
*col_infos
,
2469 struct MinList
*children
, LONG left_start
, LONG top_start
)
2480 * pass 2 : distribute space
2482 cstate
= (Object
*) children
->mlh_Head
;
2485 for (i
= 0; i
< data
->rows
; i
++)
2487 /* left start for child layout in this row */
2490 /* max height for children in this row */
2491 row_height
= row_infos
[i
].dim
;
2493 /* for each column */
2494 while ((child
= NextObject(&cstate
)))
2501 if (IS_HIDDEN(child
))
2503 /* max width for children in this column */
2504 col_width
= col_infos
[j
].dim
;
2506 /* center child if col width is bigger than child maxwidth */
2507 cwidth
= MIN(_maxwidth(child
), col_width
);
2508 cwidth
= MAX(cwidth
, _minwidth(child
));
2509 cleft
= left
+ (col_width
- cwidth
) / 2;
2511 /* center child if row height is bigger than child maxheight */
2512 cheight
= MIN(_maxheight(child
), row_height
);
2513 cheight
= MAX(cheight
, _minheight(child
));
2514 ctop
= top
+ (row_height
- cheight
) / 2;
2516 /* g_print("layout %d %d %d %d\n", cleft, ctop, cwidth, cheight); */
2517 /* D(bug("2DL/child %p -> layout %d x %d\n", */
2518 /* child, cwidth, cheight)); */
2519 if (!MUI_Layout(child
, cleft
, ctop
, cwidth
, cheight
, 0))
2522 left
+= data
->horiz_spacing
+ col_width
;
2525 if ((j
% data
->columns
) == 0)
2529 top
+= data
->vert_spacing
+ row_height
;
2536 * all children in the same row have the same maximum height
2537 * all children in the same column have the same maximum height
2538 * if a child maximum size is smaller than the biggest minimum size,
2539 * the chid will be centered in the remaining space.
2541 * for each row, determine its height allocation
2542 * weight ? the vertical weight of a row, if no fixed-height child
2543 * in the row, is the sum of all vertical weights of children
2544 * all row members will have the same height
2546 * for each column, determine its width allocation
2547 * all column members will have the same width
2549 /* Write a proper hook function */
2551 group_layout_2d(struct IClass
*cl
, Object
*obj
, struct MinList
*children
)
2553 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2554 WORD left_start
= 0;
2556 WORD total_size_height
=
2557 _mheight(obj
) - (data
->rows
- 1) * data
->vert_spacing
;
2558 WORD total_size_width
=
2559 _mwidth(obj
) - (data
->columns
- 1) * data
->horiz_spacing
;
2560 WORD total_init_height
;
2561 WORD total_init_width
;
2562 WORD remainder_height
;
2563 WORD remainder_width
;
2567 if (data
->rows
== 0 || data
->columns
== 0)
2569 if (data
->num_children
% data
->rows
2570 || data
->num_children
% data
->columns
)
2572 if (data
->row_infos
== NULL
|| data
->col_infos
== NULL
)
2575 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2576 // data->virt_offx, data->virt_offy);
2578 if (data
->flags
& GROUP_VIRTUAL
)
2581 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2582 _maxwidth(obj
) - _subwidth(obj
));
2583 data
->virt_mheight
=
2584 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2585 _maxheight(obj
) - _subheight(obj
));
2587 layout_width
= data
->virt_mwidth
;
2588 layout_height
= data
->virt_mheight
;
2592 layout_width
= _mwidth(obj
);
2593 layout_height
= _mheight(obj
);
2597 layout_height
- (data
->rows
- 1) * data
->vert_spacing
;
2599 layout_width
- (data
->columns
- 1) * data
->horiz_spacing
;
2603 // weight constraints
2604 Layout2D_weight_constraint(data
, data
->row_infos
, data
->col_infos
,
2605 total_size_height
, total_size_width
,
2606 &total_init_height
, &total_init_width
);
2608 remainder_height
= total_size_height
- total_init_height
;
2609 remainder_width
= total_size_width
- total_init_width
;
2611 Layout2D_minmax_constraints_and_redistrib(data
->row_infos
,
2612 data
->rows
, total_size_height
,
2613 /* (data->flags & GROUP_SAME_HEIGHT) ? data->samesize_maxmin_vert : 0, */
2614 0, remainder_height
);
2616 Layout2D_minmax_constraints_and_redistrib(data
->col_infos
,
2617 data
->columns
, total_size_width
,
2618 /* (data->flags & GROUP_SAME_WIDTH) ? data->samesize_maxmin_horiz : 0, */
2619 0, remainder_width
);
2621 layout_2d_distribute_space(data
, data
->row_infos
, data
->col_infos
,
2622 children
, left_start
, top_start
);
2626 /* Write a proper hook function */
2627 static void group_layout_pagemode(struct IClass
*cl
, Object
*obj
,
2628 struct MinList
*children
)
2630 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2635 int w
, h
, yoffset
= 0;
2637 if (data
->flags
& GROUP_VIRTUAL
)
2640 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2641 _maxwidth(obj
) - _subwidth(obj
));
2642 data
->virt_mheight
=
2643 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2644 _maxheight(obj
) - _subheight(obj
));
2646 layout_width
= data
->virt_mwidth
;
2647 layout_height
= data
->virt_mheight
;
2651 layout_width
= _mwidth(obj
);
2652 layout_height
= _mheight(obj
);
2655 if (data
->titlegroup
)
2657 yoffset
= _minheight(data
->titlegroup
);
2658 layout_height
-= yoffset
;
2661 cstate
= (Object
*) children
->mlh_Head
;
2662 while ((child
= NextObject(&cstate
)))
2664 w
= MIN(layout_width
, _maxwidth(child
));
2665 h
= MIN(layout_height
, _maxheight(child
));
2667 if (child
== data
->titlegroup
)
2669 MUI_Layout(child
, (layout_width
- w
) / 2, 0, w
, yoffset
, 0);
2673 D(bug("PM/child %p -> layout %d x %d\n", child
, w
, h
));
2674 MUI_Layout(child
, (layout_width
- w
) / 2,
2675 yoffset
+ (layout_height
- h
) / 2, w
, h
, 0);
2681 /**************************************************************************
2683 Either use a given layout hook, or the builtin method.
2684 **************************************************************************/
2685 IPTR
Group__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
2686 struct MUIP_Layout
*msg
)
2688 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2689 struct MUI_LayoutMsg lm
= { 0 };
2691 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
2692 if (data
->flags
& GROUP_PAGEMODE
)
2694 group_layout_pagemode(cl
, obj
, lm
.lm_Children
);
2696 else if (data
->layout_hook
)
2698 lm
.lm_Type
= MUILM_LAYOUT
;
2699 lm
.lm_Layout
.Width
= _mwidth(obj
);
2700 lm
.lm_Layout
.Height
= _mheight(obj
);
2702 CallHookPkt(data
->layout_hook
, obj
, &lm
);
2704 if (data
->flags
& GROUP_VIRTUAL
)
2706 data
->virt_mwidth
= lm
.lm_Layout
.Width
;
2707 data
->virt_mheight
= lm
.lm_Layout
.Height
;
2712 if ((data
->rows
== 1) && (data
->columns
== 1))
2714 if (data
->flags
& GROUP_HORIZ
)
2715 group_layout_horiz(cl
, obj
, lm
.lm_Children
);
2717 group_layout_vert(cl
, obj
, lm
.lm_Children
);
2720 group_layout_2d(cl
, obj
, lm
.lm_Children
);
2723 if (data
->flags
& GROUP_VIRTUAL
)
2725 WORD new_virt_offx
, new_virt_offy
;
2727 new_virt_offx
= data
->virt_offx
;
2728 new_virt_offy
= data
->virt_offy
;
2730 if (new_virt_offx
+ _mwidth(obj
) > data
->virt_mwidth
)
2732 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
2734 if (new_virt_offx
< 0)
2737 if (new_virt_offy
+ _mheight(obj
) > data
->virt_mheight
)
2739 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
2741 if (new_virt_offy
< 0)
2744 if (new_virt_offx
!= data
->virt_offx
)
2746 nfset(obj
, MUIA_Virtgroup_Left
, new_virt_offx
);
2749 if (new_virt_offy
!= data
->virt_offy
)
2751 nfset(obj
, MUIA_Virtgroup_Top
, new_virt_offy
);
2759 /**************************************************************************
2761 **************************************************************************/
2762 IPTR
Group__MUIM_Show(struct IClass
*cl
, Object
*obj
,
2763 struct MUIP_Show
*msg
)
2765 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2768 struct MinList
*ChildList
= NULL
;
2770 /* If msg is NULL, we won't want that the super method actually gets
2773 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2775 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2776 cstate
= (Object
*) ChildList
->mlh_Head
;
2778 if (data
->flags
& GROUP_PAGEMODE
)
2781 while ((child
= NextObject(&cstate
)))
2783 if (child
== data
->titlegroup
)
2785 DoShowMethod(child
);
2786 continue; /* Title group is not counted as page */
2789 if (page
== data
->active_page
)
2791 DoShowMethod(child
);
2799 while ((child
= NextObject(&cstate
)))
2801 if (!(data
->flags
& GROUP_VIRTUAL
) ||
2802 IsObjectVisible(child
, MUIMasterBase
))
2804 if (_flags(child
) & MADF_SHOWME
)
2805 DoShowMethod(child
);
2812 /**************************************************************************
2814 **************************************************************************/
2815 IPTR
Group__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
2816 struct MUIP_Hide
*msg
)
2818 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2821 struct MinList
*ChildList
= NULL
;
2823 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2824 cstate
= (Object
*) ChildList
->mlh_Head
;
2826 if (data
->flags
& GROUP_PAGEMODE
)
2829 while ((child
= NextObject(&cstate
)))
2831 if (child
== data
->titlegroup
)
2833 DoHideMethod(child
);
2834 continue; /* Title group is not counted as page */
2837 if (page
== data
->active_page
)
2839 DoHideMethod(child
);
2847 while ((child
= NextObject(&cstate
)))
2849 if (_flags(child
) & MADF_CANDRAW
)
2850 DoHideMethod(child
);
2854 /* If msg is NULL, we won't want that the super method actually gets
2857 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2862 * MUIM_FindUData : tests if the MUIA_UserData of the object
2863 * contains the given <udata> and returns the object pointer in this case.
2865 IPTR
Group__MUIM_FindUData(struct IClass
*cl
, Object
*obj
,
2866 struct MUIP_FindUData
*msg
)
2868 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2870 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2873 return DoMethodA(data
->family
, (Msg
) msg
);
2878 * MUIM_GetUData : This method tests if the MUIA_UserData of the object
2879 * contains the given <udata> and gets <attr> to <storage> for itself
2882 IPTR
Group__MUIM_GetUData(struct IClass
*cl
, Object
*obj
,
2883 struct MUIP_GetUData
*msg
)
2885 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2887 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2889 get(obj
, msg
->attr
, msg
->storage
);
2893 return DoMethodA(data
->family
, (Msg
) msg
);
2898 * MUIM_SetUData : This method tests if the MUIA_UserData of the object
2899 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2901 IPTR
Group__MUIM_SetUData(struct IClass
*cl
, Object
*obj
,
2902 struct MUIP_SetUData
*msg
)
2904 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2906 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2907 set(obj
, msg
->attr
, msg
->val
);
2909 DoMethodA(data
->family
, (Msg
) msg
);
2915 * MUIM_SetUDataOnce : This method tests if the MUIA_UserData of the object
2916 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2917 * Stop after the first udata found.
2919 IPTR
Group__MUIM_SetUDataOnce(struct IClass
*cl
, Object
*obj
,
2920 struct MUIP_SetUData
*msg
)
2922 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2924 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2926 set(obj
, msg
->attr
, msg
->val
);
2929 return DoMethodA(data
->family
, (Msg
) msg
);
2932 /**************************************************************************
2933 MUIM_DragQueryExtented
2934 **************************************************************************/
2935 IPTR
Group__MUIM_DragQueryExtended(struct IClass
*cl
, Object
*obj
,
2936 struct MUIP_DragQueryExtended
*msg
)
2938 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2942 struct MinList
*ChildList
= NULL
;
2944 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2945 cstate
= (Object
*) ChildList
->mlh_Head
;
2946 while ((child
= NextObject(&cstate
)))
2948 if (!(_flags(child
) & MADF_CANDRAW
))
2951 if ((found_obj
= (Object
*) DoMethodA(child
, (Msg
) msg
)))
2952 return (IPTR
) found_obj
;
2954 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2957 /**************************************************************************
2959 **************************************************************************/
2960 IPTR
Group__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
2961 struct MUIP_HandleEvent
*msg
)
2963 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2965 /* check this, otherwise a superclass who has IDCMP_MOUSEBUTTONS
2966 eventhandler might call DoSuperMethod, and this function gets
2967 called even when he have not added any eventhandler */
2969 if ((data
->flags
& GROUP_VIRTUAL
) && msg
->imsg
)
2971 switch (msg
->imsg
->Class
)
2973 case IDCMP_MOUSEBUTTONS
:
2974 /* For virtual groups */
2975 if (msg
->imsg
->Code
== SELECTDOWN
)
2977 if (_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
2978 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
2981 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
2982 (IPTR
) & data
->ehn
);
2983 data
->ehn
.ehn_Events
|= IDCMP_INTUITICKS
;
2984 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
2985 (IPTR
) & data
->ehn
);
2990 if (data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
)
2992 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
2993 (IPTR
) & data
->ehn
);
2994 data
->ehn
.ehn_Events
&= ~IDCMP_INTUITICKS
;
2995 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
2996 (IPTR
) & data
->ehn
);
3001 case IDCMP_INTUITICKS
:
3002 if (!(data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
))
3005 if (!(_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
3006 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
3009 LONG new_virt_offx
= data
->virt_offx
;
3010 LONG new_virt_offy
= data
->virt_offy
;
3012 if (msg
->imsg
->MouseX
< _mleft(obj
))
3015 if (new_virt_offx
>= 4)
3020 else if (msg
->imsg
->MouseX
> _mright(obj
))
3024 if (new_virt_offx
> data
->virt_mwidth
- _mwidth(obj
))
3025 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
3026 if (new_virt_offx
< 0)
3030 if (msg
->imsg
->MouseY
< _mtop(obj
))
3033 if (new_virt_offy
>= 4)
3038 else if (msg
->imsg
->MouseY
> _mbottom(obj
))
3042 if (new_virt_offy
> data
->virt_mheight
- _mheight(obj
))
3043 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
3044 if (new_virt_offy
< 0)
3048 if (new_virt_offx
!= data
->virt_offx
3049 || new_virt_offy
!= data
->virt_offy
)
3052 MUIA_Virtgroup_Left
, new_virt_offx
,
3053 MUIA_Virtgroup_Top
, new_virt_offy
,
3054 MUIA_Group_Forward
, FALSE
, TAG_DONE
);
3064 /**************************************************************************
3066 **************************************************************************/
3067 IPTR
Group__MUIM_DrawBackground(struct IClass
*cl
, Object
*obj
,
3068 struct MUIP_DrawBackground
*msg
)
3070 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3072 if (data
->flags
& GROUP_VIRTUAL
)
3074 struct MUIP_DrawBackground msg2
= *msg
;
3076 msg2
.xoffset
+= data
->virt_offx
;
3077 msg2
.yoffset
+= data
->virt_offy
;
3079 return DoSuperMethodA(cl
, obj
, (Msg
) & msg2
);
3082 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3085 /**************************************************************************
3087 Find the given object or return NULL
3088 **************************************************************************/
3089 IPTR
Group__MUIM_FindAreaObject(struct IClass
*cl
, Object
*obj
,
3090 struct MUIP_FindAreaObject
*msg
)
3092 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3095 struct MinList
*ChildList
= NULL
;
3098 if (msg
->obj
== obj
)
3101 // it's one of my children ?
3102 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3103 cstate
= (Object
*) ChildList
->mlh_Head
;
3104 while ((child
= NextObject(&cstate
)))
3106 if (msg
->obj
== child
)
3107 return (IPTR
) child
;
3110 // let the children find it
3111 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3112 cstate
= (Object
*) ChildList
->mlh_Head
;
3113 while ((child
= NextObject(&cstate
)))
3115 Object
*res
= (Object
*) DoMethodA(child
, (Msg
) msg
);
3123 /**************************************************************************
3124 MUIM_Export : to export an objects "contents" to a dataspace object.
3125 **************************************************************************/
3126 static IPTR
Group__MUIM_Export(struct IClass
*cl
, Object
*obj
,
3127 struct MUIP_Export
*msg
)
3129 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3132 struct MinList
*ChildList
= NULL
;
3134 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3138 cstate
= (Object
*) ChildList
->mlh_Head
;
3139 while ((child
= NextObject(&cstate
)))
3141 DoMethodA(child
, (Msg
) msg
);
3148 /**************************************************************************
3149 MUIM_Import : to import an objects "contents" from a dataspace object.
3150 **************************************************************************/
3151 static IPTR
Group__MUIM_Import(struct IClass
*cl
, Object
*obj
,
3152 struct MUIP_Import
*msg
)
3154 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3157 struct MinList
*ChildList
= NULL
;
3159 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3163 cstate
= (Object
*) ChildList
->mlh_Head
;
3164 while ((child
= NextObject(&cstate
)))
3166 DoMethodA(child
, (Msg
) msg
);
3172 /**************************************************************************
3173 MUIM_Notify - disabled now because previous Zune versions had a OM_GET
3174 check in MUIM_Notify which is no longer the case
3175 **************************************************************************/
3177 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3178 struct MUIP_Notify
*msg
)
3180 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3183 struct MinList
*ChildList
;
3185 /* Try at first if understand the message our self
3186 ** We disable the forwarding of the OM_GET message
3187 ** as the MUIM_Notify otherwise would "think" that
3188 ** the group class actually understands the attribute
3189 ** although a child does this only
3191 data
->dont_forward_get
= 1;
3192 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
3194 data
->dont_forward_get
= 0;
3198 /* We ourselves didn't understand the notify tag so we try the
3200 data
->dont_forward_get
= 0;
3202 get(data
->family
, MUIA_Family_List
, (IPTR
*) & (ChildList
));
3203 cstate
= (Object
*) ChildList
->mlh_Head
;
3204 while ((child
= NextObject(&cstate
)))
3206 if (DoMethodA(child
, (Msg
) msg
))
3214 /* Notes about Group_Notify() and echo notification problem:
3215 It was discovered that MUI seems to have some special handling for group class
3216 which will drop notifications on the children which are found to not
3217 understand the attribute.
3219 This is done by checking if an OM_GET on the child returns TRUE.
3220 There's a little problem here because it is not known how big the storage
3221 needed for the attribute in question will be. Almost no class uses anything
3222 bigger than one IPTR. For "big" attributes those return a pointer to the data,
3223 not the data itself. Unfortuntely there are some exceptions like colorwheel
3224 class which does not return a pointer, but the data itself. So it's not
3225 enough to use one single IPTR variable (4 Bytes on 32bit machines, 8 bytes
3226 on 64 bit machines) to store the result of the test-OM_Get.
3228 There is no general way to query the size needed so if one wants to change
3229 Zune to work like MUI one needs to choose a size which one hopes will be
3230 big enough to hold all possible attributes of all classes, old, present
3233 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3234 struct MUIP_Notify
*msg
)
3236 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3239 struct MinList
*ChildList
= NULL
;
3242 data
->dont_forward_get
= 1;
3244 if (GetAttr(msg
->TrigAttr
, obj
, attr
))
3246 data
->dont_forward_get
= 0;
3247 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3249 data
->dont_forward_get
= 0;
3251 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3255 cstate
= (Object
*) ChildList
->mlh_Head
;
3256 while ((child
= NextObject(&cstate
)))
3259 if (GetAttr(msg
->TrigAttr
, child
, attr
))
3261 DoMethodA(child
, (Msg
) msg
);
3262 /* No return here! */
3269 BOOPSI_DISPATCHER(IPTR
, Group_Dispatcher
, cl
, obj
, msg
)
3271 switch (msg
->MethodID
)
3274 return Group__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3276 return Group__OM_DISPOSE(cl
, obj
, msg
);
3278 return Group__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3280 return Group__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3281 case OM_ADDMEMBER
: /* Fall through */
3282 case MUIM_Group_AddTail
:
3283 return Group__MUIM_AddTail(cl
, obj
, (APTR
) msg
);
3284 case MUIM_Group_AddHead
:
3285 return Group__MUIM_AddHead(cl
, obj
, (APTR
) msg
);
3286 case MUIM_Group_Insert
:
3287 return Group__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3288 case OM_REMMEMBER
: /* Fall through */
3289 case MUIM_Group_Remove
:
3290 return Group__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3291 case MUIM_AskMinMax
:
3292 return Group__MUIM_AskMinMax(cl
, obj
, (APTR
) msg
);
3293 case MUIM_Group_ExitChange
:
3294 return Group__MUIM_ExitChange(cl
, obj
, (APTR
) msg
);
3295 case MUIM_Group_InitChange
:
3296 return Group__MUIM_InitChange(cl
, obj
, (APTR
) msg
);
3297 case MUIM_Group_Sort
:
3298 return Group__MUIM_Sort(cl
, obj
, (APTR
) msg
);
3299 case MUIM_Group_DoMethodNoForward
:
3300 return Group__MUIM_DoMethodNoForward(cl
, obj
, (APTR
) msg
);
3301 case MUIM_ConnectParent
:
3302 return Group__MUIM_ConnectParent(cl
, obj
, (APTR
) msg
);
3303 case MUIM_DisconnectParent
:
3304 return Group__MUIM_DisconnectParent(cl
, obj
, (APTR
) msg
);
3306 return Group__MUIM_Layout(cl
, obj
, (APTR
) msg
);
3308 return Group__MUIM_Setup(cl
, obj
, (APTR
) msg
);
3310 return Group__MUIM_Cleanup(cl
, obj
, (APTR
) msg
);
3312 return Group__MUIM_Draw(cl
, obj
, (APTR
) msg
);
3314 case MUIM_FindUData
:
3315 return Group__MUIM_FindUData(cl
, obj
, (APTR
) msg
);
3317 return Group__MUIM_GetUData(cl
, obj
, (APTR
) msg
);
3319 return Group__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
3320 case MUIM_SetUDataOnce
:
3321 return Group__MUIM_SetUDataOnce(cl
, obj
, (APTR
) msg
);
3323 return Group__MUIM_Show(cl
, obj
, (APTR
) msg
);
3325 return Group__MUIM_Hide(cl
, obj
, (APTR
) msg
);
3326 case MUIM_HandleEvent
:
3327 return Group__MUIM_HandleEvent(cl
, obj
, (APTR
) msg
);
3328 case MUIM_DrawBackground
:
3329 return Group__MUIM_DrawBackground(cl
, obj
, (APTR
) msg
);
3330 case MUIM_DragQueryExtended
:
3331 return Group__MUIM_DragQueryExtended(cl
, obj
, (APTR
) msg
);
3332 case MUIM_FindAreaObject
:
3333 return Group__MUIM_FindAreaObject(cl
, obj
, (APTR
) msg
);
3335 return Group__MUIM_Export(cl
, obj
, (APTR
) msg
);
3337 return Group__MUIM_Import(cl
, obj
, (APTR
) msg
);
3341 /* Disabled. See above */
3343 return Group_Notify(cl
, obj
, (APTR
) msg
);
3348 case MUIM_DrawParentBackground
:
3349 case MUIM_DragBegin
:
3351 case MUIM_DragQuery
:
3352 case MUIM_DragFinish
:
3354 case MUIM_CreateDragImage
:
3355 case MUIM_DeleteDragImage
:
3357 case MUIM_GoInactive
:
3358 case MUIM_CreateBubble
:
3359 case MUIM_DeleteBubble
:
3360 case MUIM_CreateShortHelp
:
3361 case MUIM_DeleteShortHelp
:
3364 return DoSuperMethodA(cl
, obj
, (APTR
) msg
);
3365 /* Needs not to be forwarded? */
3368 /* sometimes you want to call a superclass method,
3369 * but not dispatching to child.
3370 * But what to do with list methods in a listview ?
3372 Group_DispatchMsg(cl
, obj
, (APTR
) msg
);
3374 return DoSuperMethodA(cl
, obj
, msg
);
3376 BOOPSI_DISPATCHER_END
3381 const struct __MUIBuiltinClass _MUI_Group_desc
=
3385 sizeof(struct MUI_GroupData
),
3386 (void *) Group_Dispatcher