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)
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 subtract those from the total
230 * 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 muiNotifyData(msgint
->obj
)->mnd_ParentObject
= obj
;
273 DoMethod(msgint
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
276 if (_flags(obj
) & MADF_SETUP
)
278 DoSetupMethod(msgint
->obj
, muiRenderInfo(obj
));
280 /* if (_flags(obj) & MADF_CANDRAW) */
281 /* DoShowMethod(msg->opam_Object); */
286 /**************************************************************************
288 **************************************************************************/
289 IPTR
Group__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
291 struct MUI_GroupData
*data
;
292 struct TagItem
*tags
, *tag
;
293 BOOL bad_children
= FALSE
;
294 IPTR disabled
= FALSE
;
295 IPTR frame
= MUIV_Frame_None
;
297 D(bug("[group.mui] OM_NEW, object 0x%p\n", obj
));
299 obj
= (Object
*) DoSuperMethodA(cl
, obj
, (Msg
) msg
);
303 /* Initial local instance data */
304 data
= INST_DATA(cl
, obj
);
306 data
->family
= MUI_NewObjectA(MUIC_Family
, NULL
);
309 CoerceMethod(cl
, obj
, OM_DISPOSE
);
313 data
->horiz_spacing
= -1;
314 data
->vert_spacing
= -1;
317 data
->active_page
= 0;
318 get(obj
, MUIA_Frame
, &frame
);
320 /* parse initial taglist */
321 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
325 case MUIA_Group_Child
:
326 D(bug("[group.mui] Adding child 0x%p\n", tag
->ti_Data
));
329 DoMethod(obj
, OM_ADDMEMBER
, tag
->ti_Data
);
330 /* Set first child as group title */
331 if ((frame
== MUIV_Frame_Register
)
332 && (data
->titlegroup
== NULL
))
333 data
->titlegroup
= (Object
*) tag
->ti_Data
;
339 case MUIA_Group_ActivePage
:
340 change_active_page(cl
, obj
, (LONG
) tag
->ti_Data
);
343 case MUIA_Group_Columns
:
344 data
->columns
= (tag
->ti_Data
) > 1 ? tag
->ti_Data
: 1;
348 case MUIA_Group_Horiz
:
349 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_HORIZ
);
352 case MUIA_Group_HorizSpacing
:
353 data
->flags
|= GROUP_HSPACING
;
354 data
->horiz_spacing
= tag
->ti_Data
;
357 case MUIA_Group_LayoutHook
:
358 data
->layout_hook
= (struct Hook
*)tag
->ti_Data
;
361 case MUIA_Group_PageMode
:
362 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_PAGEMODE
);
365 case MUIA_Group_Rows
:
366 data
->rows
= MAX((ULONG
) tag
->ti_Data
, 1);
370 case MUIA_Group_SameHeight
:
371 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_HEIGHT
);
374 case MUIA_Group_SameSize
:
375 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_HEIGHT
);
376 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_WIDTH
);
379 case MUIA_Group_SameWidth
:
380 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_SAME_WIDTH
);
383 case MUIA_Group_Spacing
:
384 data
->flags
|= (GROUP_HSPACING
| GROUP_VSPACING
);
385 data
->horiz_spacing
= tag
->ti_Data
;
386 data
->vert_spacing
= tag
->ti_Data
;
389 case MUIA_Group_VertSpacing
:
390 data
->flags
|= GROUP_VSPACING
;
391 data
->vert_spacing
= tag
->ti_Data
;
394 case MUIA_Group_Virtual
:
395 _handle_bool_tag(data
->flags
, tag
->ti_Data
, GROUP_VIRTUAL
);
402 CoerceMethod(cl
, obj
, OM_DISPOSE
);
406 /* D(bug("Group_New(0x%lx)\n",obj)); */
408 if (data
->flags
& GROUP_VIRTUAL
)
410 /* This is used by MUI_Render() to determine if group is virtual.
411 * It then installs a clip region.
412 * Also MUI_Layout() uses this. Probably for speed up reason */
413 _flags(obj
) |= MADF_ISVIRTUALGROUP
;
416 /* will forward MUIA_Disabled to children */
417 get(obj
, MUIA_Disabled
, &disabled
);
420 set(obj
, MUIA_Disabled
, TRUE
);
423 /* This is only used for virtual groups */
424 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
; /* Will be filled on demand */
425 data
->ehn
.ehn_Priority
= 10; /* Will hear the click before all
426 * other normal objects */
427 data
->ehn
.ehn_Flags
= 0;
428 data
->ehn
.ehn_Object
= obj
;
429 data
->ehn
.ehn_Class
= cl
;
433 /**************************************************************************
435 **************************************************************************/
436 IPTR
Group__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
438 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
440 if (data
->row_infos
!= NULL
)
441 mui_free(data
->row_infos
);
442 if (data
->col_infos
!= NULL
)
443 mui_free(data
->col_infos
);
444 if (data
->family
!= NULL
)
445 MUI_DisposeObject(data
->family
);
446 return DoSuperMethodA(cl
, obj
, msg
);
449 /**************************************************************************
451 **************************************************************************/
452 IPTR
Group__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
454 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
455 struct TagItem
*tags
= msg
->ops_AttrList
;
458 BOOL need_recalc
= FALSE
;
461 int virt_offx
= data
->virt_offx
, virt_offy
= data
->virt_offy
;
463 /* There are many ways to find out what tag items provided by set()
464 ** we do know. The best way should be using NextTagItem() and simply
465 ** browsing through the list.
468 /* Parse group attributes before calling DoSuperMethodA(),
469 ** otherwise if an app for example sets up a notification
470 ** on MUIA_Group_ActivePage which calls a hook, and then
471 ** the hook function calls get(obj, MUIA_Group_ActivePage),
472 ** it would get returned the old active page instead of the new
476 while ((tag
= NextTagItem(&tags
)) != NULL
)
480 case MUIA_Group_Columns
:
481 data
->columns
= MAX((ULONG
) tag
->ti_Data
, 1);
485 case MUIA_Group_ActivePage
:
486 change_active_page(cl
, obj
, (LONG
) tag
->ti_Data
);
488 case MUIA_Group_Forward
:
489 forward
= tag
->ti_Data
;
491 case MUIA_Group_HorizSpacing
:
492 data
->flags
|= GROUP_HSPACING
;
493 data
->horiz_spacing
= tag
->ti_Data
;
495 case MUIA_Group_Rows
:
496 data
->rows
= MAX((ULONG
) tag
->ti_Data
, 1);
500 case MUIA_Group_Spacing
:
501 data
->flags
|= (GROUP_HSPACING
| GROUP_VSPACING
);
502 data
->horiz_spacing
= tag
->ti_Data
;
503 data
->vert_spacing
= tag
->ti_Data
;
505 case MUIA_Group_VertSpacing
:
506 data
->flags
|= GROUP_VSPACING
;
507 data
->vert_spacing
= tag
->ti_Data
;
509 case MUIA_Virtgroup_Left
:
510 //kprintf("set virtgroup_left: %d\n", tag->ti_Data);
511 virt_offx
= tag
->ti_Data
;
514 case MUIA_Group_LayoutHook
:
516 [ach] Seems like MUI supports setting this attribute after
517 initialization, even though the documentation states
518 otherwise. At least some programs use it...
520 data
->layout_hook
= (struct Hook
*)tag
->ti_Data
;
523 case MUIA_Virtgroup_Top
:
524 //kprintf("set virtgroup_top: %d\n", tag->ti_Data);
525 virt_offy
= tag
->ti_Data
;
531 if (muiRenderInfo(obj
) && need_recalc
)
532 DoMethod(_win(obj
), MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
534 retval
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
536 /* seems to be the documented behaviour, however it should be slow! */
540 /* Attributes which are to be filtered out, so that they are ignored
541 when OM_SET is passed to group's children */
543 tags
= msg
->ops_AttrList
;
544 while ((tag
= NextTagItem(&tags
)) != NULL
)
553 case MUIA_ContextMenu
:
554 case MUIA_ContextMenuTrigger
:
555 case MUIA_ControlChar
:
556 case MUIA_CycleChain
:
559 case MUIA_Group_ActivePage
:
561 case MUIA_FrameTitle
:
562 case MUIA_HorizWeight
:
566 case MUIA_VertWeight
:
568 case MUIA_Virtgroup_Left
:
569 case MUIA_Virtgroup_Top
:
570 case MUIA_AppMessage
:
571 tag
->ti_Tag
= TAG_IGNORE
;
574 /* D(bug("Group_Set(%p) MUIA_Selected forwarded\n", obj)); */
575 /* tag->ti_Tag = TAG_IGNORE; */
580 Group_DispatchMsg(cl
, obj
, (Msg
) msg
);
584 if (virt_offx
!= data
->virt_offx
|| virt_offy
!= data
->virt_offy
)
586 if (_flags(obj
) & MADF_CANDRAW
)
587 Group__MUIM_Hide(cl
, obj
, NULL
);
588 data
->virt_offx
= virt_offx
;
589 data
->virt_offy
= virt_offy
;
590 /* Relayout ourself, this will also relayout all the children */
591 DoMethod(obj
, MUIM_Layout
);
592 if (_flags(obj
) & MADF_CANDRAW
)
593 Group__MUIM_Show(cl
, obj
, NULL
);
595 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
602 /**************************************************************************
604 **************************************************************************/
605 IPTR
Group__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
607 /* small macro to simplify return value storage */
608 #define STORE *(msg->opg_Storage)
610 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
612 switch (msg
->opg_AttrID
)
620 case MUIA_Group_ActivePage
:
621 STORE
= data
->active_page
;
623 case MUIA_Group_ChildList
:
624 return GetAttr(MUIA_Family_List
, data
->family
, msg
->opg_Storage
);
625 case MUIA_Group_Horiz
:
626 STORE
= (data
->flags
& GROUP_HORIZ
);
628 case MUIA_Group_HorizSpacing
:
629 STORE
= data
->horiz_spacing
;
631 case MUIA_Group_VertSpacing
:
632 STORE
= data
->vert_spacing
;
634 case MUIA_Group_ChildCount
:
635 STORE
= data
->num_children
;
637 case MUIA_Virtgroup_Left
:
638 STORE
= data
->virt_offx
;
640 case MUIA_Virtgroup_Top
:
641 STORE
= data
->virt_offy
;
643 case MUIA_Virtgroup_Width
:
644 STORE
= data
->virt_mwidth
;
646 case MUIA_Virtgroup_Height
:
647 STORE
= data
->virt_mheight
;
649 case MUIA_Virtgroup_MinWidth
:
650 STORE
= data
->saved_minwidth
;
652 case MUIA_Virtgroup_MinHeight
:
653 STORE
= data
->saved_minheight
;
657 /* our handler didn't understand the attribute, we simply pass
658 ** it to our superclass now
660 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
663 /* seems to be the documented behaviour, however it should be slow! */
664 if (!data
->dont_forward_get
&& !data
->dont_forward_methods
)
668 struct MinList
*ChildList
= NULL
;
670 get(data
->family
, MUIA_Family_List
, &(ChildList
));
671 cstate
= (Object
*) ChildList
->mlh_Head
;
672 while ((child
= NextObject(&cstate
)))
673 if (DoMethodA(child
, (Msg
) msg
))
681 /**************************************************************************
683 **************************************************************************/
684 IPTR
Group__MUIM_AddTail(struct IClass
*cl
, Object
*obj
,
685 struct MUIP_Group_AddTail
*msg
)
687 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
690 /**************************************************************************
692 **************************************************************************/
693 IPTR
Group__MUIM_AddHead(struct IClass
*cl
, Object
*obj
,
694 struct MUIP_Group_AddHead
*msg
)
696 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
699 /**************************************************************************
701 **************************************************************************/
702 IPTR
Group__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
703 struct MUIP_Group_Insert
*msg
)
705 return Group__MUIM_AddObject(cl
, obj
, (Msg
) msg
);
708 /**************************************************************************
710 **************************************************************************/
711 IPTR
Group__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
712 struct MUIP_Group_Remove
*msg
)
714 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
716 if (_flags(obj
) & MADF_CANDRAW
)
717 DoHideMethod(msg
->obj
);
718 if (_flags(obj
) & MADF_SETUP
)
719 DoMethod(msg
->obj
, MUIM_Cleanup
);
720 if (muiNotifyData(obj
)->mnd_GlobalInfo
)
722 DoMethod(msg
->obj
, MUIM_DisconnectParent
);
723 muiNotifyData(msg
->obj
)->mnd_ParentObject
= NULL
;
725 _flags(msg
->obj
) &= ~MADF_INVIRTUALGROUP
;
728 if ((data
->flags
& GROUP_CHANGING
) != 0)
729 data
->flags
|= GROUP_CHANGED
;
730 data
->num_children
--;
731 DoMethodA(data
->family
, (Msg
) msg
);
737 /**************************************************************************
739 **************************************************************************/
740 IPTR
Group__MUIM_ConnectParent(struct IClass
*cl
, Object
*obj
,
741 struct MUIP_ConnectParent
*msg
)
743 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
746 struct MinList
*ChildList
= NULL
;
748 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
750 get(data
->family
, MUIA_Family_List
, &(ChildList
));
751 cstate
= (Object
*) ChildList
->mlh_Head
;
752 while ((child
= NextObject(&cstate
)))
754 if ((_flags(obj
) & MADF_INVIRTUALGROUP
)
755 || (data
->flags
& GROUP_VIRTUAL
))
757 _flags(child
) |= MADF_INVIRTUALGROUP
;
760 /* Only children of groups can have parents */
761 muiNotifyData(child
)->mnd_ParentObject
= obj
;
763 DoMethod(child
, MUIM_ConnectParent
, (IPTR
) obj
);
768 /**************************************************************************
769 MUIM_DisconnectParent
770 **************************************************************************/
771 IPTR
Group__MUIM_DisconnectParent(struct IClass
*cl
, Object
*obj
,
772 struct MUIP_ConnectParent
*msg
)
774 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
777 struct MinList
*ChildList
= NULL
;
779 get(data
->family
, MUIA_Family_List
, &(ChildList
));
780 cstate
= (Object
*) ChildList
->mlh_Head
;
781 while ((child
= NextObject(&cstate
)))
783 DoMethodA(child
, (Msg
) msg
);
784 muiNotifyData(child
)->mnd_ParentObject
= NULL
;
785 _flags(child
) &= ~MADF_INVIRTUALGROUP
;
787 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
792 * Put group in exchange state
794 IPTR
Group__MUIM_InitChange(struct IClass
*cl
, Object
*obj
,
795 struct MUIP_Group_InitChange
*msg
)
797 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
799 data
->flags
&= ~GROUP_CHANGED
;
800 data
->flags
|= GROUP_CHANGING
;
806 * Will recalculate display after dynamic adding/removing
808 IPTR
Group__MUIM_ExitChange(struct IClass
*cl
, Object
*obj
,
809 struct MUIP_Group_ExitChange
*msg
)
811 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
813 data
->flags
&= ~GROUP_CHANGING
;
815 if (data
->flags
& GROUP_CHANGED
)
817 data
->flags
&= ~GROUP_CHANGED
;
819 if ((_flags(obj
) & MADF_SETUP
) && _win(obj
))
821 Object
*win
= _win(obj
);
822 Object
*parent
= obj
;
824 /* CHECKME: Don't call RecalcDisplay if one of our parents is
825 in GROUP_CHANGING state to prevent crash with Zune prefs
826 program NListtree page because NList/NListtree when
827 killing tree images in MUIM_Cleanup uses InitChange/
828 ExitChange. Zune prefs program uses InitChange/ExitChange
829 when switching page -> nesting -> mess. */
831 while ((parent
= _parent(parent
)))
833 struct MUI_GroupData
*pdata
= INST_DATA(cl
, parent
);
838 if (pdata
->flags
& GROUP_CHANGING
)
845 DoMethod(win
, MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
854 * Will recalculate display after dynamic adding/removing
856 IPTR
Group__MUIM_ExitChange2(struct IClass
*cl
, Object
*obj
,
857 struct MUIP_Group_ExitChange2
*msg
)
859 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
861 if (data
->flags
& GROUP_CHANGING
)
863 data
->flags
&= ~(GROUP_CHANGING
| GROUP_CHANGED
);
865 if ((_flags(obj
) & MADF_SETUP
) && _win(obj
))
867 Object
*win
= _win(obj
);
868 Object
*parent
= obj
;
870 /* CHECKME: Don't call RecalcDisplay if one of our parents is
871 in GROUP_CHANGING state to prevent crash with Zune prefs
872 program NListtree page because NList/NListtree when
873 killing tree images in MUIM_Cleanup uses InitChange/
874 ExitChange. Zune prefs program uses InitChange/ExitChange
875 when switching page -> nesting -> mess. */
877 while ((parent
= _parent(parent
)))
879 struct MUI_GroupData
*pdata
= INST_DATA(cl
, parent
);
884 if (pdata
->flags
& GROUP_CHANGING
)
891 DoMethod(win
, MUIM_Window_RecalcDisplay
, (IPTR
) obj
);
902 IPTR
Group__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
903 struct MUIP_Group_Sort
*msg
)
905 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
908 msg
->MethodID
= MUIM_Family_Sort
;
910 DoMethodA(data
->family
, (APTR
) msg
);
912 /* restore original message */
913 msg
->MethodID
= MUIM_Group_Sort
;
917 /**************************************************************************
918 MUIM_Group_DoMethodNoForward
920 Executes the given method but does not forward it to the children
921 **************************************************************************/
922 IPTR
Group__MUIM_DoMethodNoForward(struct IClass
*cl
, Object
*obj
,
923 struct MUIP_Group_DoMethodNoForward
*msg
)
925 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
927 data
->dont_forward_methods
= 1; /* disable forwarding */
928 rc
= DoMethodA(obj
, (Msg
) & msg
->DoMethodID
);
929 /* Probably doesn't work correctly on AROS? */
931 data
->dont_forward_methods
= 0;
936 * Propagate a method to group children.
938 static ULONG
Group_DispatchMsg(struct IClass
*cl
, Object
*obj
, Msg msg
)
940 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
943 struct MinList
*ChildList
= NULL
;
945 if (data
->dont_forward_methods
)
948 get(data
->family
, MUIA_Family_List
, &(ChildList
));
949 cstate
= (Object
*) ChildList
->mlh_Head
;
950 while ((child
= NextObject(&cstate
)))
952 DoMethodA(child
, (Msg
) msg
);
958 /**************************************************************************
960 **************************************************************************/
961 IPTR
Group__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
962 struct MUIP_Setup
*msg
)
964 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
969 struct MinList
*ChildList
= NULL
;
971 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
974 ASSERT_VALID_PTR(muiGlobalInfo(obj
));
976 if (!(data
->flags
& GROUP_HSPACING
))
977 data
->horiz_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_hspacing
;
978 if (!(data
->flags
& GROUP_VSPACING
))
979 data
->vert_spacing
= muiGlobalInfo(obj
)->mgi_Prefs
->group_vspacing
;
980 get(data
->family
, MUIA_Family_List
, &(ChildList
));
981 cstate
= cstate_copy
= (Object
*) ChildList
->mlh_Head
;
982 while ((child
= NextObject(&cstate
)))
984 #if 0 /* SHOWME affects only show/hide */
985 if (!(_flags(child
) & MADF_SHOWME
))
989 if (!DoSetupMethod(child
, msg
->RenderInfo
))
991 /* Send MUIM_Cleanup to all objects that received MUIM_Setup.
994 cstate
= cstate_copy
;
995 while ((child
= NextObject(&cstate
)) && (child
!= childFailed
))
997 #if 0 /* SHOWME affects only show/hide */
998 if (!(_flags(child
) & MADF_SHOWME
))
1001 DoMethod(child
, MUIM_Cleanup
);
1007 if (data
->flags
& GROUP_VIRTUAL
)
1009 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
1010 (IPTR
) & data
->ehn
);
1017 /**************************************************************************
1019 **************************************************************************/
1020 IPTR
Group__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
, Msg msg
)
1022 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1025 struct MinList
*ChildList
= NULL
;
1027 if (data
->flags
& GROUP_VIRTUAL
)
1029 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
1030 (IPTR
) & data
->ehn
);
1033 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1034 cstate
= (Object
*) ChildList
->mlh_Head
;
1035 while ((child
= NextObject(&cstate
)))
1037 #if 0 /* SHOWME affects only show/hide */
1038 if (!(_flags(child
) & MADF_SHOWME
))
1041 DoMethodA(child
, (Msg
) msg
);
1043 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1048 /**************************************************************************
1049 MUIM_Draw - draw the group
1050 **************************************************************************/
1051 IPTR
Group__MUIM_Draw(struct IClass
*cl
, Object
*obj
,
1052 struct MUIP_Draw
*msg
)
1054 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1057 struct MinList
*ChildList
= NULL
;
1058 struct Rectangle group_rect
; /* child_rect; */
1060 struct Region
*region
= NULL
;
1061 APTR clip
= (APTR
) - 1;
1063 /* D(bug("Group_Draw(%lx) %ldx%ldx%ldx%ld upd=%d page=%d\n", */
1064 /* obj,_left(obj),_top(obj),_right(obj),_bottom(obj), */
1065 /* data->update, data->active_page)); */
1066 /* D(bug("Group_Draw(%p) msg=0x%08lx flags=0x%08lx\n", */
1067 /* obj, msg->flags, _flags(obj))); */
1069 if (data
->flags
& GROUP_CHANGING
)
1072 if (muiGlobalInfo(obj
)->mgi_Prefs
->window_redraw
==
1073 WINDOW_REDRAW_WITHOUT_CLEAR
)
1075 region
= NewRegion();
1078 struct Rectangle rect
;
1080 rect
.MinX
= _left(obj
);
1081 rect
.MinY
= _top(obj
);
1082 rect
.MaxX
= _right(obj
);
1083 rect
.MaxY
= _bottom(obj
);
1085 OrRectRegion(region
, &rect
);
1087 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1088 cstate
= (Object
*) ChildList
->mlh_Head
;
1089 while ((child
= NextObject(&cstate
)))
1092 /* redraw problem with colorwheel in coloradjust register */
1093 if ((data
->flags
& GROUP_PAGEMODE
)
1094 && ((page
!= data
->active_page
)
1095 && (child
!= data
->titlegroup
)))
1098 if ((muiAreaData(child
)->mad_Flags
& MADF_CANDRAW
)
1099 && (_width(child
) > 0) && (_height(child
) > 0))
1101 rect
.MinX
= MAX(_left(child
), _mleft(obj
));
1102 rect
.MinY
= MAX(_top(child
), _mtop(obj
));
1103 rect
.MaxX
= MIN(_right(child
), _mright(obj
));
1104 rect
.MaxY
= MIN(_bottom(child
), _mbottom(obj
));
1106 if ((rect
.MaxX
>= rect
.MinX
)
1107 && (rect
.MaxY
>= rect
.MinY
))
1109 ClearRectRegion(region
, &rect
);
1114 clip
= MUI_AddClipRegion(muiRenderInfo(obj
), region
);
1118 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1122 MUI_RemoveClipRegion(muiRenderInfo(obj
), clip
);
1128 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1130 /* D(bug("Group_Draw(%p) (after dsma) msg=0x%08lx flags=0x%08lx\n", */
1131 /* obj, msg->flags, _flags(obj))); */
1133 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1)
1136 * update is set when changing active page of a page group
1137 * need to redraw background ourself
1139 DoMethod(obj
, MUIM_DrawBackground
,
1140 _mleft(obj
), _mtop(obj
), _mwidth(obj
), _mheight(obj
),
1141 _mleft(obj
), _mtop(obj
), 0);
1147 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2)
1149 LONG left
, top
, right
, bottom
;
1150 LONG diff_virt_offx
= data
->virt_offx
- data
->old_virt_offx
;
1151 LONG diff_virt_offy
= data
->virt_offy
- data
->old_virt_offy
;
1152 struct Rectangle rect
;
1153 struct Rectangle
*clip_rect
= &muiRenderInfo(obj
)->mri_ClipRect
;
1157 if (!diff_virt_offx
&& !diff_virt_offy
)
1162 /* sba: I don't know how MUI handle this but ScrollRasterBF() made problems when scrolling
1163 ** a (partly visible) virtual groups in a virtual group, because e.g. _mtop() is then
1164 ** smaller than the region. ScrollRasterBF() on AmigaOS then marks the complete region
1165 ** as damaged. Using ScrollWindowRaster() solved that problem but it flickers then.
1166 ** To avoid this we prevent that the scroll area is out of the region bounds.
1167 ** The region bounds are setted in MUI_Redraw() but should probably should go in the
1168 ** MUI's clip functions
1171 left
= MAX(_mleft(obj
), clip_rect
->MinX
);
1172 top
= MAX(_mtop(obj
), clip_rect
->MinY
);
1173 right
= MIN(_mright(obj
), clip_rect
->MaxX
);
1174 bottom
= MIN(_mbottom(obj
), clip_rect
->MaxY
);
1177 ** ScrollRasterBF(_rp(obj), diff_virt_offx, diff_virt_offy, _mleft(obj), _mtop(obj), _mright(obj),_mbottom(obj));
1180 ScrollWindowRaster(_window(obj
), diff_virt_offx
, diff_virt_offy
,
1181 left
, top
, right
, bottom
);
1183 if ((region
= NewRegion()))
1190 if (diff_virt_offx
> 0)
1192 rect
.MinX
= right
- diff_virt_offx
+ 1;
1193 if (rect
.MinX
< left
)
1200 rect
.MaxX
= left
- diff_virt_offx
- 1;
1201 if (rect
.MaxX
> right
)
1205 if (rect
.MinX
<= rect
.MaxX
)
1207 DoMethod(obj
, MUIM_DrawBackground
,
1208 rect
.MinX
, rect
.MinY
,
1209 rect
.MaxX
- rect
.MinX
+ 1,
1210 rect
.MaxY
- rect
.MinY
+ 1,
1211 rect
.MinX
, rect
.MinY
, 0);
1213 OrRectRegion(region
, &rect
);
1222 if (diff_virt_offy
> 0)
1224 rect
.MinY
= bottom
- diff_virt_offy
+ 1;
1225 if (rect
.MinY
< top
)
1232 rect
.MaxY
= top
- diff_virt_offy
- 1;
1233 if (rect
.MaxY
> bottom
)
1236 if (rect
.MinY
<= rect
.MaxY
)
1238 DoMethod(obj
, MUIM_DrawBackground
,
1239 rect
.MinX
, rect
.MinY
,
1240 rect
.MaxX
- rect
.MinX
+ 1,
1241 rect
.MaxY
- rect
.MinY
+ 1,
1242 rect
.MinX
, rect
.MinY
, 0);
1244 OrRectRegion(region
, &rect
);
1252 if (!(msg
->flags
& MADF_DRAWOBJECT
)
1253 && !(msg
->flags
& MADF_DRAWALL
))
1258 if (data
->flags
& GROUP_VIRTUAL
&& !region
)
1260 /* Not really needed if MUI Draws all the objects, maybe that's
1261 * what DRAWALL is for??? */
1262 if ((region
= NewRegion()))
1264 struct Rectangle rect
;
1265 rect
.MinX
= _mleft(obj
);
1266 rect
.MinY
= _mtop(obj
);
1267 rect
.MaxX
= _mright(obj
);
1268 rect
.MaxY
= _mbottom(obj
);
1269 OrRectRegion(region
, &rect
);
1273 /* Add clipping region if we have one */
1275 clip
= MUI_AddClipRegion(muiRenderInfo(obj
), region
);
1277 group_rect
= muiRenderInfo(obj
)->mri_ClipRect
;
1279 get(data
->family
, MUIA_Family_List
, &(ChildList
));
1280 cstate
= (Object
*) ChildList
->mlh_Head
;
1281 while ((child
= NextObject(&cstate
)))
1283 if (!(_flags(child
) & MADF_SHOWME
))
1286 if (child
!= data
->titlegroup
)
1289 if ((data
->flags
& GROUP_PAGEMODE
) && ((page
!= data
->active_page
)
1290 && (child
!= data
->titlegroup
)))
1295 // msg->flags |= MADF_DRAWOBJECT; /* yup, do not forget */
1297 // child_rect.MinX = _left(child);
1298 // child_rect.MinY = _top(child);
1299 // child_rect.MaxX = _right(child);
1300 // child_rect.MaxY = _bottom(child);
1301 /* g_print("intersect: a=(%d, %d, %d, %d) b=(%d, %d, %d, %d)\n", */
1302 /* group_rect.x, group_rect.y, */
1303 /* group_rect.width, group_rect.height, */
1304 /* child_rect.x, child_rect.y, */
1305 /* child_rect.width, child_rect.height); */
1307 // if (gdk_rectangle_intersect(&group_rect, &child_rect,
1308 // &muiRenderInfo(obj)->mri_ClipRect))
1309 // DoMethodA(child, (Msg)msg);
1310 /* if (((msg->flags & MADF_DRAWUPDATE) && data->update) */
1311 /* || (data->flags & GROUP_PAGEMODE)) */
1312 MUI_Redraw(child
, MADF_DRAWOBJECT
);
1314 /* MUI_Redraw(child, msg->flags); */
1315 muiRenderInfo(obj
)->mri_ClipRect
= group_rect
;
1316 /* g_print("set back clip to (%d, %d, %d, %d)\n", */
1317 /* group_rect.x, group_rect.y, group_rect.width, group_rect.height); */
1319 /* D(bug("Group_Draw(%p) end\n", obj)); */
1321 if (data
->flags
& GROUP_VIRTUAL
&& region
&& clip
!= (APTR
) - 1)
1323 MUI_RemoveClipRegion(muiRenderInfo(obj
), clip
);
1326 data
->old_virt_offx
= data
->virt_offx
;
1327 data
->old_virt_offy
= data
->virt_offy
;
1334 #define END_MINMAX() \
1335 tmp.MaxHeight = MAX(tmp.MaxHeight, tmp.MinHeight); \
1336 tmp.MaxWidth = MAX(tmp.MaxWidth, tmp.MinWidth); \
1337 tmp.DefHeight = CLAMP(tmp.DefHeight, tmp.MinHeight, tmp.MaxHeight); \
1338 tmp.DefWidth = CLAMP(tmp.DefWidth, tmp.MinWidth, tmp.MaxWidth); \
1339 msg->MinMaxInfo->MinWidth += tmp.MinWidth; \
1340 msg->MinMaxInfo->MinHeight += tmp.MinHeight; \
1341 msg->MinMaxInfo->MaxWidth += tmp.MaxWidth; \
1342 msg->MinMaxInfo->MaxHeight += tmp.MaxHeight; \
1343 msg->MinMaxInfo->DefWidth += tmp.DefWidth; \
1344 msg->MinMaxInfo->DefHeight += tmp.DefHeight;
1347 * MinMax calculation function. When this is called,
1348 * the children of your group have already been asked
1349 * about their min/max dimension so you can use their
1350 * dimensions to calculate yours.
1353 * - Init minwidth and maxwidth with size needed for total child spacing.
1354 * - 1st pass to find maximum minimum width, to set minwidth of each child
1355 * if they should have the same width (for a row of buttons ...)
1356 * - Adjust minwidth w/o making object bigger than their max size.
1358 static void group_minmax_horiz(struct IClass
*cl
, Object
*obj
,
1359 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1361 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1364 struct MUI_MinMax tmp
;
1365 WORD maxminwidth
= 0;
1366 BOOL found_nonzero_vweight
= FALSE
;
1370 tmp
.MaxHeight
= MUI_MAXMAX
;
1371 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1372 (data
->num_visible_children
- 1) * data
->horiz_spacing
;
1374 if (data
->flags
& GROUP_SAME_WIDTH
)
1376 cstate
= (Object
*) children
->mlh_Head
;
1377 while ((child
= NextObject(&cstate
)))
1379 if (IS_HIDDEN(child
))
1381 maxminwidth
= MAX(maxminwidth
, _minwidth(child
));
1385 data
->samesize_maxmin_horiz
= maxminwidth
;
1386 /* D(bug("group_minmax_horiz(%p) : maxminwidth=%d\n", obj, maxminwidth)); */
1388 data
->horiz_weight_sum
= 0;
1389 cstate
= (Object
*) children
->mlh_Head
;
1390 while ((child
= NextObject(&cstate
)))
1394 if (IS_HIDDEN(child
))
1396 if (data
->flags
& GROUP_SAME_WIDTH
)
1398 minwidth
= MAX(maxminwidth
, _minwidth(child
));
1399 minwidth
= MIN(minwidth
, _maxwidth(child
));
1402 minwidth
= _minwidth(child
);
1403 tmp
.MinWidth
+= minwidth
;
1404 tmp
.DefWidth
+= w0_defwidth(child
);
1405 tmp
.MaxWidth
+= w0_maxwidth(child
);
1406 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, MUI_MAXMAX
);
1407 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1408 tmp
.DefHeight
= MAX(tmp
.DefHeight
, _defheight(child
));
1410 if all children have null weight then maxheight=minheight
1411 if all but some children have null weights, the maxheight
1412 is the min of all maxheights
1414 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, _maxheight(child
));
1415 data
->horiz_weight_sum
+= _hweight(child
);
1416 if (_vweight(child
) > 0)
1418 found_nonzero_vweight
= TRUE
;
1421 if (!found_nonzero_vweight
)
1423 tmp
.MaxHeight
= tmp
.MinHeight
;
1426 //if (data->flags & GROUP_VIRTUAL)
1428 //kprintf("# min %d x %d def %d x %d max %d x %d\n",
1429 // tmp.MinWidth, tmp.MinHeight,
1430 // tmp.DefWidth, tmp.DefHeight,
1431 // tmp.MaxWidth, tmp.MaxHeight);
1437 /* minmax calculation for vertical groups (see group_minmax_horiz)
1439 static void group_minmax_vert(struct IClass
*cl
, Object
*obj
,
1440 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1442 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1445 struct MUI_MinMax tmp
;
1446 WORD maxminheight
= 0;
1447 BOOL found_nonzero_hweight
= FALSE
;
1451 tmp
.MaxWidth
= MUI_MAXMAX
;
1452 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1453 (data
->num_visible_children
- 1) * data
->vert_spacing
;
1455 if (data
->flags
& GROUP_SAME_HEIGHT
)
1457 cstate
= (Object
*) children
->mlh_Head
;
1458 while ((child
= NextObject(&cstate
)))
1460 if (IS_HIDDEN(child
))
1462 maxminheight
= MAX(maxminheight
, _minheight(child
));
1466 data
->samesize_maxmin_vert
= maxminheight
;
1467 data
->vert_weight_sum
= 0;
1468 cstate
= (Object
*) children
->mlh_Head
;
1469 while ((child
= NextObject(&cstate
)))
1471 if (IS_HIDDEN(child
))
1474 if (data
->flags
& GROUP_SAME_HEIGHT
)
1475 _minheight(child
) = MIN(maxminheight
, w0_maxheight(child
));
1476 tmp
.MinHeight
+= _minheight(child
);
1477 tmp
.DefHeight
+= w0_defheight(child
);
1478 tmp
.MaxHeight
+= w0_maxheight(child
);
1479 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, MUI_MAXMAX
);
1480 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1481 tmp
.DefWidth
= MAX(tmp
.DefWidth
, _defwidth(child
));
1482 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, _maxwidth(child
));
1483 data
->vert_weight_sum
+= _vweight(child
);
1484 if (_hweight(child
) > 0)
1486 found_nonzero_hweight
= TRUE
;
1489 if (!found_nonzero_hweight
)
1491 tmp
.MaxWidth
= tmp
.MinWidth
;
1499 minmax_2d_rows_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1500 struct MUI_MinMax
*req
, WORD maxmin_height
, WORD maxdef_height
)
1506 /* do not rewind after the while, to process line by line */
1507 cstate
= (Object
*) children
->mlh_Head
;
1509 for (i
= 0; i
< data
->rows
; i
++)
1511 /* calculate min and max height of this row */
1512 int min_h
= 0, def_h
= 0, max_h
= MUI_MAXMAX
;
1513 BOOL found_nonzero_vweight
= FALSE
;
1515 data
->row_infos
[i
].weight
= 0;
1518 while ((child
= NextObject(&cstate
)))
1520 if (IS_HIDDEN(child
))
1522 if (data
->flags
& GROUP_SAME_HEIGHT
)
1524 _minheight(child
) = MIN(maxmin_height
, w0_maxheight(child
));
1525 _defheight(child
) = MIN(maxdef_height
, w0_maxheight(child
));
1527 min_h
= MAX(min_h
, _minheight(child
));
1528 def_h
= MAX(def_h
, w0_defheight(child
));
1529 max_h
= MIN(max_h
, _maxheight(child
));
1530 if (_vweight(child
) > 0)
1532 found_nonzero_vweight
= TRUE
;
1533 data
->row_infos
[i
].weight
+= _vweight(child
);
1536 if ((j
% data
->columns
) == 0)
1539 if (!found_nonzero_vweight
)
1542 max_h
= MAX(max_h
, min_h
);
1543 /* D(bug("row %d : min_h=%d max_h=%d\n", i, min_h, max_h)); */
1545 data
->row_infos
[i
].min
= min_h
;
1546 data
->row_infos
[i
].max
= max_h
;
1547 data
->vert_weight_sum
+= data
->row_infos
[i
].weight
;
1549 req
->MinHeight
+= min_h
;
1550 req
->DefHeight
+= def_h
;
1551 req
->MaxHeight
+= max_h
;
1552 if (req
->MaxHeight
> MUI_MAXMAX
)
1553 req
->MaxHeight
= MUI_MAXMAX
;
1559 minmax_2d_columns_pass(struct MUI_GroupData
*data
, struct MinList
*children
,
1560 struct MUI_MinMax
*req
, WORD maxmin_width
, WORD maxdef_width
)
1566 for (i
= 0; i
< data
->columns
; i
++)
1568 /* calculate min and max width of this column */
1569 int min_w
= 0, def_w
= 0, max_w
= MUI_MAXMAX
;
1570 BOOL found_nonzero_hweight
= FALSE
;
1572 data
->col_infos
[i
].weight
= 0;
1575 /* process all children to get children on a column */
1576 cstate
= (Object
*) children
->mlh_Head
;
1577 while ((child
= NextObject(&cstate
)))
1579 if (IS_HIDDEN(child
))
1582 if (((j
- 1) % data
->columns
) != i
)
1584 if (data
->flags
& GROUP_SAME_WIDTH
)
1586 _minwidth(child
) = MIN(maxmin_width
, w0_maxwidth(child
));
1587 _defwidth(child
) = MIN(maxdef_width
, w0_maxwidth(child
));
1589 min_w
= MAX(min_w
, _minwidth(child
));
1590 def_w
= MAX(def_w
, w0_defwidth(child
));
1592 /* this handles the case of null weight children, which limit
1593 * the max size if they're alone, but not if they are with
1594 * non-null weight obj
1596 max_w
= MIN(max_w
, _maxwidth(child
));
1597 if (_hweight(child
) > 0)
1599 found_nonzero_hweight
= TRUE
;
1600 data
->col_infos
[i
].weight
+= _hweight(child
);
1603 if (!found_nonzero_hweight
)
1606 max_w
= MAX(max_w
, min_w
);
1607 /* D(bug("col %d : min_w=%d max_w=%d\n", i, min_w, max_w)); */
1609 data
->col_infos
[i
].min
= min_w
;
1610 data
->col_infos
[i
].max
= max_w
;
1611 data
->horiz_weight_sum
+= data
->col_infos
[i
].weight
;
1613 req
->MinWidth
+= min_w
;
1614 req
->DefWidth
+= def_w
;
1615 req
->MaxWidth
+= max_w
;
1616 if (req
->MaxWidth
> MUI_MAXMAX
)
1617 req
->MaxWidth
= MUI_MAXMAX
;
1622 group_minmax_2d(struct IClass
*cl
, Object
*obj
,
1623 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1625 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1628 struct MUI_MinMax tmp
;
1636 if (data
->num_children
% data
->rows
)
1639 data
->rows
= data
->num_children
;
1642 data
->columns
= data
->num_children
/ data
->rows
;
1646 if (data
->num_children
% data
->columns
)
1649 data
->columns
= data
->num_children
;
1652 data
->rows
= data
->num_children
/ data
->columns
;
1655 if (data
->columns
< 1)
1660 if (data
->row_infos
!= NULL
)
1661 mui_free(data
->row_infos
);
1663 data
->row_infos
= mui_alloc(data
->rows
* sizeof(struct layout2d_elem
));
1664 if (NULL
== data
->row_infos
)
1667 if (data
->col_infos
!= NULL
)
1668 mui_free(data
->col_infos
);
1671 mui_alloc(data
->columns
* sizeof(struct layout2d_elem
));
1672 if (NULL
== data
->col_infos
)
1675 data
->horiz_weight_sum
= 0;
1676 data
->vert_weight_sum
= 0;
1678 tmp
.MinHeight
= tmp
.DefHeight
= tmp
.MaxHeight
=
1679 (data
->rows
- 1) * data
->vert_spacing
;
1680 tmp
.MinWidth
= tmp
.DefWidth
= tmp
.MaxWidth
=
1681 (data
->columns
- 1) * data
->horiz_spacing
;
1682 /* get minimum dims if same dims for all children are needed */
1688 if ((data
->flags
& GROUP_SAME_WIDTH
)
1689 || (data
->flags
& GROUP_SAME_HEIGHT
))
1691 cstate
= (Object
*) children
->mlh_Head
;
1692 while ((child
= NextObject(&cstate
)))
1694 if (!(_flags(child
) & MADF_SHOWME
))
1696 maxmin_width
= MAX(maxmin_width
, _minwidth(child
));
1697 maxmin_height
= MAX(maxmin_height
, _minheight(child
));
1698 maxdef_width
= MAX(maxdef_width
, w0_defwidth(child
));
1699 maxdef_height
= MAX(maxdef_height
, w0_defheight(child
));
1701 /* g_print("2d group: mminw=%d mminh=%d\n", */
1702 /* maxmin_width, maxmin_height); */
1704 if (data
->flags
& GROUP_SAME_HEIGHT
)
1705 data
->samesize_maxmin_vert
= maxmin_height
;
1707 data
->samesize_maxmin_vert
= 0;
1709 if (data
->flags
& GROUP_SAME_WIDTH
)
1710 data
->samesize_maxmin_horiz
= maxmin_width
;
1712 data
->samesize_maxmin_horiz
= 0;
1714 minmax_2d_rows_pass(data
, children
, &tmp
, maxmin_height
, maxdef_height
);
1715 minmax_2d_columns_pass(data
, children
, &tmp
, maxmin_width
,
1723 group_minmax_pagemode(struct IClass
*cl
, Object
*obj
,
1724 struct MinList
*children
, struct MUIP_AskMinMax
*msg
)
1728 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1729 struct MUI_MinMax tmp
= { 0, 0, MUI_MAXMAX
, MUI_MAXMAX
, 0, 0 };
1731 cstate
= (Object
*) children
->mlh_Head
;
1733 D(bug("minmax_pagemode(%lx)\n", obj
, tmp
.DefWidth
));
1735 while ((child
= NextObject(&cstate
)))
1737 if (!(_flags(child
) & MADF_SHOWME
))
1740 if (child
== data
->titlegroup
)
1743 tmp
.MinHeight
= MAX(tmp
.MinHeight
, _minheight(child
));
1744 D(bug("minmax_pagemode(%p) minh child = %d tmpmin=%d\n", obj
,
1745 _minheight(child
), tmp
.MinHeight
));
1746 tmp
.MinWidth
= MAX(tmp
.MinWidth
, _minwidth(child
));
1747 tmp
.MaxHeight
= MIN(tmp
.MaxHeight
, w0_maxheight(child
));
1748 tmp
.MaxWidth
= MIN(tmp
.MaxWidth
, w0_maxwidth(child
));
1749 tmp
.DefHeight
= MAX(tmp
.DefHeight
,
1750 ((w0_defheight(child
) <
1751 MUI_MAXMAX
) ? w0_defheight(child
) : tmp
.DefHeight
));
1754 ((w0_defwidth(child
) <
1755 MUI_MAXMAX
) ? w0_defwidth(child
) : tmp
.DefWidth
));
1756 D(bug("minmax_pagemode(%lx) defw = %ld\n", obj
, tmp
.DefWidth
));
1759 if (data
->titlegroup
)
1761 tmp
.MinHeight
+= _minheight(data
->titlegroup
);
1762 tmp
.MaxHeight
+= w0_maxheight(data
->titlegroup
);
1763 tmp
.DefHeight
+= w0_defheight(data
->titlegroup
);
1769 /**************************************************************************
1770 MUIM_AskMinMax : ask children about min/max sizes, then
1771 either call a hook, or the builtin method, to calculate our minmax
1772 **************************************************************************/
1773 IPTR
Group__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1774 struct MUIP_AskMinMax
*msg
)
1776 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
1777 struct MUI_LayoutMsg lm
;
1778 struct MUIP_AskMinMax childMsg
;
1779 struct MUI_MinMax childMinMax
;
1782 LONG super_minwidth
, super_minheight
;
1785 * let our superclass first fill in its size with frame, inner spc etc ...
1787 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1788 super_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1789 super_minheight
= msg
->MinMaxInfo
->MinHeight
;
1794 childMsg
.MethodID
= msg
->MethodID
;
1795 childMsg
.MinMaxInfo
= &childMinMax
;
1796 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
1798 cstate
= (Object
*) lm
.lm_Children
->mlh_Head
;
1800 while ((child
= NextObject(&cstate
)))
1802 if (!(_flags(child
) & MADF_SHOWME
))
1803 /* BORDERGADGETs should handle this itself */
1806 DoMethodA(child
, (Msg
) & childMsg
);
1807 /* D(bug("*** group %lx, child %lx min=%ld,%ld\n", */
1808 /* obj, child, childMinMax.MinWidth, childMinMax.MinHeight)); */
1809 __area_finish_minmax(child
, childMsg
.MinMaxInfo
);
1813 * Use children infos to calculate group size
1815 if (data
->flags
& GROUP_PAGEMODE
)
1817 D(bug("minmax_pagemode(%p) minh initial = %d\n", obj
,
1818 msg
->MinMaxInfo
->MinHeight
));
1819 group_minmax_pagemode(cl
, obj
, lm
.lm_Children
, msg
);
1820 D(bug("minmax_pagemode(%p) minh = %d\n", obj
,
1821 msg
->MinMaxInfo
->MinHeight
));
1823 else if (data
->layout_hook
)
1825 lm
.lm_Type
= MUILM_MINMAX
;
1826 CallHookPkt(data
->layout_hook
, obj
, &lm
);
1828 if (lm
.lm_MinMax
.MaxHeight
< lm
.lm_MinMax
.MinHeight
)
1829 lm
.lm_MinMax
.MaxHeight
= lm
.lm_MinMax
.MinHeight
;
1830 if (lm
.lm_MinMax
.DefHeight
< lm
.lm_MinMax
.MinHeight
)
1831 lm
.lm_MinMax
.DefHeight
= lm
.lm_MinMax
.MinHeight
;
1832 if (lm
.lm_MinMax
.MaxWidth
< lm
.lm_MinMax
.MinWidth
)
1833 lm
.lm_MinMax
.MaxWidth
= lm
.lm_MinMax
.MinWidth
;
1834 if (lm
.lm_MinMax
.DefWidth
< lm
.lm_MinMax
.MinWidth
)
1835 lm
.lm_MinMax
.DefWidth
= lm
.lm_MinMax
.MinWidth
;
1837 //kprintf("### min %d x %d def %d x %d max %d x %d\n",
1838 // msg->MinMaxInfo->MinWidth,
1839 // msg->MinMaxInfo->MinHeight,
1840 // msg->MinMaxInfo->DefWidth,
1841 // msg->MinMaxInfo->DefHeight,
1842 // msg->MinMaxInfo->MaxWidth,
1843 // msg->MinMaxInfo->MaxHeight);
1845 msg
->MinMaxInfo
->MinWidth
+= lm
.lm_MinMax
.MinWidth
;
1846 msg
->MinMaxInfo
->MinHeight
+= lm
.lm_MinMax
.MinHeight
;
1847 msg
->MinMaxInfo
->MaxWidth
+= lm
.lm_MinMax
.MaxWidth
;
1848 if (msg
->MinMaxInfo
->MaxWidth
> MUI_MAXMAX
)
1849 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1850 msg
->MinMaxInfo
->MaxHeight
+= lm
.lm_MinMax
.MaxHeight
;
1851 if (msg
->MinMaxInfo
->MaxHeight
> MUI_MAXMAX
)
1852 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1853 msg
->MinMaxInfo
->DefWidth
+= lm
.lm_MinMax
.DefWidth
;
1854 msg
->MinMaxInfo
->DefHeight
+= lm
.lm_MinMax
.DefHeight
;
1856 //kprintf("#### min %d x %d def %d x %d max %d x %d\n",
1857 // msg->MinMaxInfo->MinWidth,
1858 // msg->MinMaxInfo->MinHeight,
1859 // msg->MinMaxInfo->DefWidth,
1860 // msg->MinMaxInfo->DefHeight,
1861 // msg->MinMaxInfo->MaxWidth,
1862 // msg->MinMaxInfo->MaxHeight);
1867 if ((data
->rows
== 1) && (data
->columns
== 1))
1869 data
->num_visible_children
=
1870 Group_GetNumVisibleChildren(data
, lm
.lm_Children
);
1871 if (data
->flags
& GROUP_HORIZ
)
1872 group_minmax_horiz(cl
, obj
, lm
.lm_Children
, msg
);
1874 group_minmax_vert(cl
, obj
, lm
.lm_Children
, msg
);
1878 group_minmax_2d(cl
, obj
, lm
.lm_Children
, msg
);
1882 if (data
->flags
& GROUP_VIRTUAL
)
1884 data
->saved_minwidth
= msg
->MinMaxInfo
->MinWidth
;
1885 data
->saved_minheight
= msg
->MinMaxInfo
->MinHeight
;
1886 msg
->MinMaxInfo
->MinWidth
= super_minwidth
+ 2;
1887 msg
->MinMaxInfo
->MinHeight
= super_minheight
+ 2;
1889 //kprintf("## min %d x %d def %d x %d max %d x %d\n",
1890 // msg->MinMaxInfo->MinWidth,
1891 // msg->MinMaxInfo->MinHeight,
1892 // msg->MinMaxInfo->DefWidth,
1893 // msg->MinMaxInfo->DefHeight,
1894 // msg->MinMaxInfo->MaxWidth,
1895 // msg->MinMaxInfo->MaxHeight);
1903 // enforce minmax constraint, but also update total growable/shrinkable weights
1904 // while we're at it
1905 static void Layout1D_minmax_constraint(WORD
*sizep
, WORD minsize
,
1906 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
1907 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
, WORD samesize
)
1909 WORD size
= *sizep
, remain
= *remainp
,
1910 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
1911 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
1913 /* D(bug("L1D_minmax_c size=%d min=%d max=%d w=%d ss=%d\n", */
1914 /* size, minsize, maxsize, */
1915 /* weight, samesize)); */
1917 if ((samesize
> 0) && (weight
== 0))
1919 remain
+= size
- samesize
;
1925 if (size
<= minsize
) // too little
1927 remain
+= size
- minsize
;
1930 if (size
== maxsize
)
1933 else if (size
>= maxsize
) // too big
1935 remain
+= size
- maxsize
;
1940 if (!((samesize
> 0) && (weight
== 0)))
1943 weightgrow
+= weight
;
1945 weightshrink
+= weight
;
1950 *sizegrowp
= sizegrow
;
1951 *sizeshrinkp
= sizeshrink
;
1952 *weightgrowp
= weightgrow
;
1953 *weightshrinkp
= weightshrink
;
1957 // redistribute excess size to growable child, or reduce size of a shrinkable
1959 static void Layout1D_redistribution(WORD
*sizep
, WORD minsize
,
1960 WORD maxsize
, WORD
*remainp
, WORD
*sizegrowp
, WORD
*sizeshrinkp
,
1961 ULONG
*weightgrowp
, ULONG
*weightshrinkp
, UWORD weight
)
1963 WORD size
= *sizep
, remain
= *remainp
,
1964 sizegrow
= *sizegrowp
, sizeshrink
= *sizeshrinkp
;
1965 ULONG weightgrow
= *weightgrowp
, weightshrink
= *weightshrinkp
;
1970 if ((remain
> 0) && (size
< maxsize
))
1974 newsize
= (sizegrow
* weight
+ weightgrow
/ 2) / weightgrow
;
1976 /* D(bug("newsize=%ld == size_growa=%ld * w=%ld / weight_grow=%d\n", */
1977 /* newsize, sizegrow, weight, weightgrow)); */
1979 /* take care of off-by-1 errors that may toggle remainder sign
1980 * by ensuring convergence to 0
1982 if (remain
- newsize
+ size
< 0)
1984 /* D(bug("adding remainder=%d => size = %d\n", */
1985 /* remain, size + remain)); */
1991 remain
-= newsize
- size
;
1994 weightgrow
-= weight
;
1997 else if ((remain
< 0) && (size
> minsize
))
2001 newsize
= (sizeshrink
* weight
+ weightshrink
/ 2) / weightshrink
;
2003 /* D(bug("newsize=%ld == size_shrinkables=%ld * w=%ld " */
2004 /* "/ weight_shrinkables=%d\n", */
2005 /* newsize, sizeshrink, weight, weightshrink)); */
2007 if (remain
- newsize
+ size
> 0)
2009 /* D(bug("adding remainder=%d => size = %d\n", */
2010 /* remain, size + remain)); */
2016 remain
-= newsize
- size
;
2019 weightshrink
-= weight
;
2025 *sizegrowp
= sizegrow
;
2026 *sizeshrinkp
= sizeshrink
;
2027 *weightgrowp
= weightgrow
;
2028 *weightshrinkp
= weightshrink
;
2032 // 2 passes at most, less on average (0.5 or 1.5), each does
2033 // - a minmax clamping, evenutally adding to a remainder
2034 // (remainder = missing (underflow) or remaining (overflow) space compared
2035 // to ideal sizes where children fill the whole group)
2036 // - a redistribution of the remainder, by growing (pos. remainder) or
2037 // shrinking (neg. remainder) children able to support it.
2039 // Occasionnaly the first time the redistribution is done, the minmax
2040 // constraint can be broken, thus the extra pass to check and eventually
2041 // redistribute. The second redistribution never breaks minmax constraint
2042 // (there should be a mathematical proof, but feel free to prove me wrong
2044 static void Layout1D_minmax_constraints_and_redistrib(struct MinList
2045 *children
, WORD total_size
, WORD remainder
, WORD samesize
,
2052 for (i
= 0; i
< 2; i
++)
2054 WORD size_growables
= total_size
;
2055 WORD size_shrinkables
= total_size
;
2056 ULONG weight_growables
= 0;
2057 ULONG weight_shrinkables
= 0;
2059 /* D(bug("start : rem=%ld, A=%ld, size_growables=%ld, " */
2060 /* "size_shrinkables=%ld\n", */
2061 /* remainder, total_size, size_growables, size_shrinkables)); */
2063 // minmax constraints
2064 cstate
= (Object
*) children
->mlh_Head
;
2065 while ((child
= NextObject(&cstate
)))
2067 /* WORD old_size; */
2069 if (IS_HIDDEN(child
))
2074 /* old_size = _width(child); */
2076 Layout1D_minmax_constraint(&_width(child
), _minwidth(child
),
2077 _maxwidth(child
), &remainder
, &size_growables
,
2078 &size_shrinkables
, &weight_growables
,
2079 &weight_shrinkables
, _hweight(child
), samesize
);
2081 /* D(bug("loop1 on %p : width=%d was %d, rem=%d, A=%d, " */
2082 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2083 /* child, _width(child), old_size, remainder, total_size, */
2084 /* size_growables, size_shrinkables, _hweight(child), */
2085 /* _minwidth(child), _maxwidth(child))); */
2087 else // ! group_horiz
2089 /* old_size = _height(child); */
2091 Layout1D_minmax_constraint(&_height(child
),
2092 _minheight(child
), _maxheight(child
), &remainder
,
2093 &size_growables
, &size_shrinkables
, &weight_growables
,
2094 &weight_shrinkables
, _vweight(child
), samesize
);
2096 /* D(bug("loop1 on %p : h=%ld was %d, rem=%d, A=%d, " */
2097 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2098 /* child, _height(child), old_size, remainder, total_size,*/
2099 /* size_growables, size_shrinkables, _vweight(child), */
2100 /* _minheight(child), _maxheight(child))); */
2101 } // if (group_horiz)
2102 } // while child, minmax constraints
2108 /* D(bug("mid : rem=%d, A=%d, size_grow=%d, size_shrink=%d, " */
2109 /* "wg=%ld, ws=%ld\n", remainder, total_size, size_growables, */
2110 /* size_shrinkables, weight_growables, weight_shrinkables)); */
2112 // distribute remaining space to possible candidates
2113 cstate
= (Object
*) children
->mlh_Head
;
2114 while (((child
= NextObject(&cstate
)) != NULL
) && (remainder
!= 0))
2116 /* WORD old_size; */
2118 if (IS_HIDDEN(child
))
2123 /* old_size = _width(child); */
2125 Layout1D_redistribution(&_width(child
), _minwidth(child
),
2126 _maxwidth(child
), &remainder
, &size_growables
,
2127 &size_shrinkables
, &weight_growables
,
2128 &weight_shrinkables
, _hweight(child
));
2130 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2131 /* "size_grow=%d, size_shrink=%d\n", child, */
2132 /* _width(child), old_size, remainder, total_size, */
2133 /* size_growables, size_shrinkables)); */
2135 else // ! group_horiz
2137 /* old_size = _height(child); */
2139 Layout1D_redistribution(&_height(child
), _minheight(child
),
2140 _maxheight(child
), &remainder
, &size_growables
,
2141 &size_shrinkables
, &weight_growables
,
2142 &weight_shrinkables
, _vweight(child
));
2144 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
2145 /* "size_grow=%d, size_shrink=%d\n", child, */
2146 /* _height(child), old_size, remainder, total_size, */
2147 /* size_growables, size_shrinkables)); */
2148 } // if (group_horiz)
2150 } // while child, redistribution
2152 /* if (remainder != 0) */
2154 /* D(bug("end : rem=%ld, A=%ld, size_grow=%ld, size_shrink=%ld\n", */
2155 /* remainder, total_size, size_growables, size_shrinkables)); */
2157 // dont break here if remainder == 0, some minmax constraints
2158 // may not be respected
2161 // to easily spot layout bugs, nothing like a (division by zero) exception
2162 /* if (remainder != 0) */
2164 /* ASSERT(remainder != 0); */
2165 /* D(bug("gonna crash, remainder = %d\n", remainder)); */
2166 /* remainder /= 0; */
2171 static void Layout1D_weight_constraint(WORD
*total_sizep
,
2172 WORD
*total_init_sizep
,
2173 ULONG
*total_weightp
, WORD
*sizep
, UWORD weight
, WORD minsize
)
2175 if (*total_weightp
> 0)
2176 *sizep
= (*total_sizep
* weight
+ *total_weightp
/ 2)
2181 *total_weightp
-= weight
;
2182 *total_sizep
-= *sizep
;
2183 *total_init_sizep
+= *sizep
;
2187 static void group_layout_vert(struct IClass
*cl
, Object
*obj
,
2188 struct MinList
*children
)
2190 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2194 WORD remainder
; /* must converge to 0 to successfully end layout */
2196 WORD total_size_backup
;
2197 WORD total_init_size
; /* total size of the ideally sized children */
2204 //kprintf("group_layout_vert: virtoff = %d,%d\n",
2205 // data->virt_offx, data->virt_offy);
2207 if (data
->flags
& GROUP_VIRTUAL
)
2210 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2211 _maxwidth(obj
) - _subwidth(obj
));
2212 data
->virt_mheight
=
2213 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2214 _maxheight(obj
) - _subheight(obj
));
2216 layout_width
= data
->virt_mwidth
;
2217 layout_height
= data
->virt_mheight
;
2221 layout_width
= _mwidth(obj
);
2222 layout_height
= _mheight(obj
);
2225 total_weight
= data
->vert_weight_sum
;
2226 total_init_size
= 0;
2228 layout_height
- (data
->num_visible_children
-
2229 1) * data
->vert_spacing
;
2230 total_size_backup
= total_size
;
2232 /* D(bug("\nvert layout for %p, A=%d W=%ld\n", */
2233 /* obj, total_size, total_weight)); */
2235 // weight constraints
2236 // calculate ideal size for each object, and total ideal size
2237 cstate
= (Object
*) children
->mlh_Head
;
2238 while ((child
= NextObject(&cstate
)))
2240 if (IS_HIDDEN(child
))
2243 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2244 &total_weight
, &_height(child
), _vweight(child
),
2246 /* D(bug("child %p : ideal=%d w=%ld\n", */
2247 /* child, _height(child), _vweight(child))); */
2248 } // while child, weight constraints
2250 total_size
= total_size_backup
;
2251 remainder
= total_size
- total_init_size
;
2253 if (data
->flags
& GROUP_VIRTUAL
)
2255 /* This is also true for non virtual groups, but if this would be the
2256 ** case then there is a bug in the layout function
2262 Layout1D_minmax_constraints_and_redistrib(children
,
2265 (data
->flags
& GROUP_SAME_HEIGHT
) ? data
->samesize_maxmin_vert
: 0,
2269 cstate
= (Object
*) children
->mlh_Head
;
2270 while ((child
= NextObject(&cstate
)))
2272 if (IS_HIDDEN(child
))
2275 width
= MIN(_maxwidth(child
), layout_width
);
2276 width
= MAX(width
, _minwidth(child
));
2277 left
= (layout_width
- width
) / 2;
2279 /* D(bug("child %p -> layout %d x %d\n", */
2280 /* child, width, _height(child))); */
2281 if (!MUI_Layout(child
, left
, top
, width
, _height(child
), 0))
2283 top
+= data
->vert_spacing
+ _height(child
);
2289 static void group_layout_horiz(struct IClass
*cl
, Object
*obj
,
2290 struct MinList
*children
)
2292 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2296 WORD remainder
; /* must converge to 0 to succesfully end layout */
2298 WORD total_size_backup
;
2299 WORD total_init_size
; /* total size of the ideally sized children */
2306 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2307 // data->virt_offx, data->virt_offy);
2309 if (data
->flags
& GROUP_VIRTUAL
)
2312 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2313 _maxwidth(obj
) - _subwidth(obj
));
2314 data
->virt_mheight
=
2315 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2316 _maxheight(obj
) - _subheight(obj
));
2318 layout_width
= data
->virt_mwidth
;
2319 layout_height
= data
->virt_mheight
;
2321 //kprintf("group_layout_horiz: layoutsize %d x %d "
2322 // " virtsize %d x %d msize %d x %d\n",
2323 // layout_width, layout_height, data->virt_mwidth,
2324 // data->virt_mheight,
2325 // _mwidth(obj), _mheight(obj));
2329 layout_width
= _mwidth(obj
);
2330 layout_height
= _mheight(obj
);
2333 total_weight
= data
->horiz_weight_sum
;
2334 total_init_size
= 0;
2336 layout_width
- (data
->num_visible_children
-
2337 1) * data
->horiz_spacing
;
2338 total_size_backup
= total_size
;
2340 /* D(bug("\nhoriz layout for %p, A=%d W=%ld\n", */
2341 /* obj, total_size, total_weight)); */
2343 // weight constraints
2344 // calculate ideal size for each object, and total ideal size
2345 cstate
= (Object
*) children
->mlh_Head
;
2346 while ((child
= NextObject(&cstate
)))
2348 if (IS_HIDDEN(child
))
2351 Layout1D_weight_constraint(&total_size
, &total_init_size
,
2352 &total_weight
, &_width(child
), _hweight(child
),
2354 /* D(bug("child %p : ideal=%d w=%ld\n", */
2355 /* child, _width(child), _hweight(child))); */
2356 } // while child, weight constraints
2358 total_size
= total_size_backup
;
2359 if (data
->horiz_weight_sum
> 0)
2360 remainder
= total_size
- total_init_size
;
2364 if (data
->flags
& GROUP_VIRTUAL
)
2366 /* This is also true for non virtual groups, but if this would be the
2367 ** case then there is a bug in the layout function
2373 Layout1D_minmax_constraints_and_redistrib(children
,
2376 (data
->flags
& GROUP_SAME_WIDTH
) ? data
->samesize_maxmin_horiz
: 0,
2380 cstate
= (Object
*) children
->mlh_Head
;
2381 while ((child
= NextObject(&cstate
)))
2383 if (IS_HIDDEN(child
))
2386 height
= MIN(_maxheight(child
), layout_height
);
2387 height
= MAX(height
, _minheight(child
));
2388 top
= (layout_height
- height
) / 2;
2390 /* D(bug("child %p -> layout %d x %d\n", */
2391 /* child, _width(child), height)); */
2392 if (!MUI_Layout(child
, left
, top
, _width(child
), height
, 0))
2394 left
+= data
->horiz_spacing
+ _width(child
);
2400 static void Layout2D_weight_constraint(struct MUI_GroupData
*data
,
2401 struct layout2d_elem
*row_infos
,
2402 struct layout2d_elem
*col_infos
,
2403 WORD total_size_height
, WORD total_size_width
,
2404 WORD
*total_init_height
, WORD
*total_init_width
)
2407 ULONG total_weight_vert
= data
->vert_weight_sum
;
2408 ULONG total_weight_horiz
= data
->horiz_weight_sum
;
2410 *total_init_height
= 0;
2411 *total_init_width
= 0;
2413 /* calc row heights */
2414 for (i
= 0; i
< data
->rows
; i
++)
2416 if (total_weight_vert
> 0)
2418 (total_size_height
* row_infos
[i
].weight
+
2419 total_weight_vert
/ 2) / total_weight_vert
;
2421 row_infos
[i
].dim
= row_infos
[i
].min
;
2423 /* D(bug("l2 row %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2424 /* i, row_infos[i].dim, */
2425 /* row_infos[i].weight, total_size_height, total_weight_vert)); */
2427 total_weight_vert
-= row_infos
[i
].weight
;
2428 total_size_height
-= row_infos
[i
].dim
;
2429 *total_init_height
+= row_infos
[i
].dim
;
2432 /* calc columns widths */
2433 for (i
= 0; i
< data
->columns
; i
++)
2435 if (total_weight_horiz
)
2437 (total_size_width
* col_infos
[i
].weight
+
2438 total_weight_horiz
/ 2) / total_weight_horiz
;
2440 col_infos
[i
].dim
= col_infos
[i
].min
;
2442 /* D(bug("l2 col %d : ideal = %d with w=%d, A=%d, W=%d\n", */
2443 /* i, col_infos[i].dim, */
2444 /* col_infos[i].weight, total_size_width, total_weight_horiz)); */
2446 total_weight_horiz
-= col_infos
[i
].weight
;
2447 total_size_width
-= col_infos
[i
].dim
;
2448 *total_init_width
+= col_infos
[i
].dim
;
2454 static void Layout2D_minmax_constraints_and_redistrib(struct layout2d_elem
2455 *infos
, WORD nitems
, WORD total_size
, WORD samesize
, WORD remainder
)
2459 /* D(bug("L2D mc&r n=%d A=%d ss=%d rem=%d\n", */
2460 /* nitems, total_size, samesize, remainder)); */
2462 for (j
= 0; j
< 2; j
++)
2464 WORD size_growables
= total_size
;
2465 WORD size_shrinkables
= total_size
;
2466 ULONG weight_growables
= 0;
2467 ULONG weight_shrinkables
= 0;
2468 /* WORD old_size; */
2471 // minmax constraints
2472 for (i
= 0; i
< nitems
; i
++)
2474 /* old_size = infos[i].dim; */
2476 /* D(bug("bef loop1 on %d : size=%d, rem=%d, A=%d, " */
2477 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2478 /* i, infos[i].dim, remainder, total_size, */
2479 /* size_growables, size_shrinkables, infos[i].weight, */
2480 /* infos[i].min, infos[i].max)); */
2482 Layout1D_minmax_constraint(&infos
[i
].dim
, infos
[i
].min
,
2483 infos
[i
].max
, &remainder
, &size_growables
,
2484 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2485 infos
[i
].weight
, samesize
);
2487 /* D(bug("loop1 on %d : size=%d was %d, rem=%d, A=%d, " */
2488 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2489 /* i, infos[i].dim, old_size, remainder, total_size, */
2490 /* size_growables, size_shrinkables, infos[i].weight, */
2491 /* infos[i].min, infos[i].max)); */
2497 for (i
= 0; i
< nitems
; i
++)
2499 /* old_size = infos[i].dim; */
2501 /* D(bug("bef loop2 on %d : size=%d, rem=%d, A=%d, " */
2502 /* "size_grow=%d, size_shrink=%d\n", i, */
2503 /* infos[i].dim, remainder, total_size, */
2504 /* size_growables, size_shrinkables)); */
2506 Layout1D_redistribution(&infos
[i
].dim
, infos
[i
].min
,
2507 infos
[i
].max
, &remainder
, &size_growables
,
2508 &size_shrinkables
, &weight_growables
, &weight_shrinkables
,
2511 /* D(bug("loop2 on %d : size=%d was %d, rem=%d, A=%d, " */
2512 /* "size_grow=%d, size_shrink=%d\n", i, */
2513 /* infos[i].dim, old_size, remainder, total_size, */
2514 /* size_growables, size_shrinkables)); */
2520 layout_2d_distribute_space(struct MUI_GroupData
*data
,
2521 struct layout2d_elem
*row_infos
,
2522 struct layout2d_elem
*col_infos
,
2523 struct MinList
*children
, LONG left_start
, LONG top_start
)
2534 * pass 2 : distribute space
2536 cstate
= (Object
*) children
->mlh_Head
;
2539 for (i
= 0; i
< data
->rows
; i
++)
2541 /* left start for child layout in this row */
2544 /* max height for children in this row */
2545 row_height
= row_infos
[i
].dim
;
2547 /* for each column */
2548 while ((child
= NextObject(&cstate
)))
2555 if (IS_HIDDEN(child
))
2557 /* max width for children in this column */
2558 col_width
= col_infos
[j
].dim
;
2560 /* center child if col width is bigger than child maxwidth */
2561 cwidth
= MIN(_maxwidth(child
), col_width
);
2562 cwidth
= MAX(cwidth
, _minwidth(child
));
2563 cleft
= left
+ (col_width
- cwidth
) / 2;
2565 /* center child if row height is bigger than child maxheight */
2566 cheight
= MIN(_maxheight(child
), row_height
);
2567 cheight
= MAX(cheight
, _minheight(child
));
2568 ctop
= top
+ (row_height
- cheight
) / 2;
2570 /* g_print("layout %d %d %d %d\n", cleft, ctop, cwidth, cheight); */
2571 /* D(bug("2DL/child %p -> layout %d x %d\n", */
2572 /* child, cwidth, cheight)); */
2573 if (!MUI_Layout(child
, cleft
, ctop
, cwidth
, cheight
, 0))
2576 left
+= data
->horiz_spacing
+ col_width
;
2579 if ((j
% data
->columns
) == 0)
2583 top
+= data
->vert_spacing
+ row_height
;
2590 * all children in the same row have the same maximum height
2591 * all children in the same column have the same maximum height
2592 * if a child maximum size is smaller than the biggest minimum size,
2593 * the chid will be centered in the remaining space.
2595 * for each row, determine its height allocation
2596 * weight ? the vertical weight of a row, if no fixed-height child
2597 * in the row, is the sum of all vertical weights of children
2598 * all row members will have the same height
2600 * for each column, determine its width allocation
2601 * all column members will have the same width
2603 /* Write a proper hook function */
2605 group_layout_2d(struct IClass
*cl
, Object
*obj
, struct MinList
*children
)
2607 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2608 WORD left_start
= 0;
2610 WORD total_size_height
=
2611 _mheight(obj
) - (data
->rows
- 1) * data
->vert_spacing
;
2612 WORD total_size_width
=
2613 _mwidth(obj
) - (data
->columns
- 1) * data
->horiz_spacing
;
2614 WORD total_init_height
;
2615 WORD total_init_width
;
2616 WORD remainder_height
;
2617 WORD remainder_width
;
2621 if (data
->rows
== 0 || data
->columns
== 0)
2623 if (data
->num_children
% data
->rows
2624 || data
->num_children
% data
->columns
)
2626 if (data
->row_infos
== NULL
|| data
->col_infos
== NULL
)
2629 //kprintf("group_layout_horiz: virtoff = %d,%d\n",
2630 // data->virt_offx, data->virt_offy);
2632 if (data
->flags
& GROUP_VIRTUAL
)
2635 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2636 _maxwidth(obj
) - _subwidth(obj
));
2637 data
->virt_mheight
=
2638 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2639 _maxheight(obj
) - _subheight(obj
));
2641 layout_width
= data
->virt_mwidth
;
2642 layout_height
= data
->virt_mheight
;
2646 layout_width
= _mwidth(obj
);
2647 layout_height
= _mheight(obj
);
2651 layout_height
- (data
->rows
- 1) * data
->vert_spacing
;
2653 layout_width
- (data
->columns
- 1) * data
->horiz_spacing
;
2657 // weight constraints
2658 Layout2D_weight_constraint(data
, data
->row_infos
, data
->col_infos
,
2659 total_size_height
, total_size_width
,
2660 &total_init_height
, &total_init_width
);
2662 remainder_height
= total_size_height
- total_init_height
;
2663 remainder_width
= total_size_width
- total_init_width
;
2665 Layout2D_minmax_constraints_and_redistrib(data
->row_infos
,
2666 data
->rows
, total_size_height
,
2667 /* (data->flags & GROUP_SAME_HEIGHT) ? data->samesize_maxmin_vert : 0, */
2668 0, remainder_height
);
2670 Layout2D_minmax_constraints_and_redistrib(data
->col_infos
,
2671 data
->columns
, total_size_width
,
2672 /* (data->flags & GROUP_SAME_WIDTH) ? data->samesize_maxmin_horiz : 0, */
2673 0, remainder_width
);
2675 layout_2d_distribute_space(data
, data
->row_infos
, data
->col_infos
,
2676 children
, left_start
, top_start
);
2680 /* Write a proper hook function */
2681 static void group_layout_pagemode(struct IClass
*cl
, Object
*obj
,
2682 struct MinList
*children
)
2684 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2689 int w
, h
, yoffset
= 0;
2691 if (data
->flags
& GROUP_VIRTUAL
)
2694 CLAMP(_mwidth(obj
), data
->saved_minwidth
- _subwidth(obj
),
2695 _maxwidth(obj
) - _subwidth(obj
));
2696 data
->virt_mheight
=
2697 CLAMP(_mheight(obj
), data
->saved_minheight
- _subheight(obj
),
2698 _maxheight(obj
) - _subheight(obj
));
2700 layout_width
= data
->virt_mwidth
;
2701 layout_height
= data
->virt_mheight
;
2705 layout_width
= _mwidth(obj
);
2706 layout_height
= _mheight(obj
);
2709 if (data
->titlegroup
)
2711 yoffset
= _minheight(data
->titlegroup
);
2712 layout_height
-= yoffset
;
2715 cstate
= (Object
*) children
->mlh_Head
;
2716 while ((child
= NextObject(&cstate
)))
2718 w
= MIN(layout_width
, _maxwidth(child
));
2719 h
= MIN(layout_height
, _maxheight(child
));
2721 if (child
== data
->titlegroup
)
2723 MUI_Layout(child
, (layout_width
- w
) / 2, 0, w
, yoffset
, 0);
2727 D(bug("PM/child %p -> layout %d x %d\n", child
, w
, h
));
2728 MUI_Layout(child
, (layout_width
- w
) / 2,
2729 yoffset
+ (layout_height
- h
) / 2, w
, h
, 0);
2735 /**************************************************************************
2737 Either use a given layout hook, or the builtin method.
2738 **************************************************************************/
2739 IPTR
Group__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
2740 struct MUIP_Layout
*msg
)
2742 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2743 struct MUI_LayoutMsg lm
= { 0 };
2745 get(data
->family
, MUIA_Family_List
, &(lm
.lm_Children
));
2746 if (data
->flags
& GROUP_PAGEMODE
)
2748 group_layout_pagemode(cl
, obj
, lm
.lm_Children
);
2750 else if (data
->layout_hook
)
2752 lm
.lm_Type
= MUILM_LAYOUT
;
2753 lm
.lm_Layout
.Width
= _mwidth(obj
);
2754 lm
.lm_Layout
.Height
= _mheight(obj
);
2756 CallHookPkt(data
->layout_hook
, obj
, &lm
);
2758 if (data
->flags
& GROUP_VIRTUAL
)
2760 data
->virt_mwidth
= lm
.lm_Layout
.Width
;
2761 data
->virt_mheight
= lm
.lm_Layout
.Height
;
2766 if ((data
->rows
== 1) && (data
->columns
== 1))
2768 if (data
->flags
& GROUP_HORIZ
)
2769 group_layout_horiz(cl
, obj
, lm
.lm_Children
);
2771 group_layout_vert(cl
, obj
, lm
.lm_Children
);
2774 group_layout_2d(cl
, obj
, lm
.lm_Children
);
2777 if (data
->flags
& GROUP_VIRTUAL
)
2779 WORD new_virt_offx
, new_virt_offy
;
2781 new_virt_offx
= data
->virt_offx
;
2782 new_virt_offy
= data
->virt_offy
;
2784 if (new_virt_offx
+ _mwidth(obj
) > data
->virt_mwidth
)
2786 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
2788 if (new_virt_offx
< 0)
2791 if (new_virt_offy
+ _mheight(obj
) > data
->virt_mheight
)
2793 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
2795 if (new_virt_offy
< 0)
2798 if (new_virt_offx
!= data
->virt_offx
)
2800 nfset(obj
, MUIA_Virtgroup_Left
, new_virt_offx
);
2803 if (new_virt_offy
!= data
->virt_offy
)
2805 nfset(obj
, MUIA_Virtgroup_Top
, new_virt_offy
);
2813 /**************************************************************************
2815 **************************************************************************/
2816 IPTR
Group__MUIM_Show(struct IClass
*cl
, Object
*obj
,
2817 struct MUIP_Show
*msg
)
2819 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2822 struct MinList
*ChildList
= NULL
;
2824 /* If msg is NULL, we won't want that the super method actually gets
2827 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2829 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2830 cstate
= (Object
*) ChildList
->mlh_Head
;
2832 if (data
->flags
& GROUP_PAGEMODE
)
2835 while ((child
= NextObject(&cstate
)))
2837 if (child
== data
->titlegroup
)
2839 DoShowMethod(child
);
2840 continue; /* Title group is not counted as page */
2843 if (page
== data
->active_page
)
2845 DoShowMethod(child
);
2853 while ((child
= NextObject(&cstate
)))
2855 if (!(data
->flags
& GROUP_VIRTUAL
) ||
2856 IsObjectVisible(child
, MUIMasterBase
))
2858 if (_flags(child
) & MADF_SHOWME
)
2859 DoShowMethod(child
);
2866 /**************************************************************************
2868 **************************************************************************/
2869 IPTR
Group__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
2870 struct MUIP_Hide
*msg
)
2872 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2875 struct MinList
*ChildList
= NULL
;
2877 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2878 cstate
= (Object
*) ChildList
->mlh_Head
;
2880 if (data
->flags
& GROUP_PAGEMODE
)
2883 while ((child
= NextObject(&cstate
)))
2885 if (child
== data
->titlegroup
)
2887 DoHideMethod(child
);
2888 continue; /* Title group is not counted as page */
2891 if (page
== data
->active_page
)
2893 DoHideMethod(child
);
2901 while ((child
= NextObject(&cstate
)))
2903 if (_flags(child
) & MADF_CANDRAW
)
2904 DoHideMethod(child
);
2908 /* If msg is NULL, we won't want that the super method actually gets
2911 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2916 * MUIM_FindUData : tests if the MUIA_UserData of the object
2917 * contains the given <udata> and returns the object pointer in this case.
2919 IPTR
Group__MUIM_FindUData(struct IClass
*cl
, Object
*obj
,
2920 struct MUIP_FindUData
*msg
)
2922 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2924 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2927 return DoMethodA(data
->family
, (Msg
) msg
);
2932 * MUIM_GetUData : This method tests if the MUIA_UserData of the object
2933 * contains the given <udata> and gets <attr> to <storage> for itself
2936 IPTR
Group__MUIM_GetUData(struct IClass
*cl
, Object
*obj
,
2937 struct MUIP_GetUData
*msg
)
2939 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2941 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2943 get(obj
, msg
->attr
, msg
->storage
);
2947 return DoMethodA(data
->family
, (Msg
) msg
);
2952 * MUIM_SetUData : This method tests if the MUIA_UserData of the object
2953 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2955 IPTR
Group__MUIM_SetUData(struct IClass
*cl
, Object
*obj
,
2956 struct MUIP_SetUData
*msg
)
2958 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2960 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2961 set(obj
, msg
->attr
, msg
->val
);
2963 DoMethodA(data
->family
, (Msg
) msg
);
2969 * MUIM_SetUDataOnce : This method tests if the MUIA_UserData of the object
2970 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2971 * Stop after the first udata found.
2973 IPTR
Group__MUIM_SetUDataOnce(struct IClass
*cl
, Object
*obj
,
2974 struct MUIP_SetUData
*msg
)
2976 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2978 if (muiNotifyData(obj
)->mnd_UserData
== msg
->udata
)
2980 set(obj
, msg
->attr
, msg
->val
);
2983 return DoMethodA(data
->family
, (Msg
) msg
);
2986 /**************************************************************************
2987 MUIM_DragQueryExtented
2988 **************************************************************************/
2989 IPTR
Group__MUIM_DragQueryExtended(struct IClass
*cl
, Object
*obj
,
2990 struct MUIP_DragQueryExtended
*msg
)
2992 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
2996 struct MinList
*ChildList
= NULL
;
2998 get(data
->family
, MUIA_Family_List
, &(ChildList
));
2999 cstate
= (Object
*) ChildList
->mlh_Head
;
3000 while ((child
= NextObject(&cstate
)))
3002 if (!(_flags(child
) & MADF_CANDRAW
))
3005 if ((found_obj
= (Object
*) DoMethodA(child
, (Msg
) msg
)))
3006 return (IPTR
) found_obj
;
3008 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3011 /**************************************************************************
3013 **************************************************************************/
3014 IPTR
Group__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
3015 struct MUIP_HandleEvent
*msg
)
3017 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3019 /* check this, otherwise a superclass who has IDCMP_MOUSEBUTTONS
3020 eventhandler might call DoSuperMethod, and this function gets
3021 called even when he have not added any eventhandler */
3023 if ((data
->flags
& GROUP_VIRTUAL
) && msg
->imsg
)
3025 switch (msg
->imsg
->Class
)
3027 case IDCMP_MOUSEBUTTONS
:
3028 /* For virtual groups */
3029 if (msg
->imsg
->Code
== SELECTDOWN
)
3031 if (_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
3032 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
3035 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3036 (IPTR
) & data
->ehn
);
3037 data
->ehn
.ehn_Events
|= IDCMP_INTUITICKS
;
3038 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3039 (IPTR
) & data
->ehn
);
3044 if (data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
)
3046 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3047 (IPTR
) & data
->ehn
);
3048 data
->ehn
.ehn_Events
&= ~IDCMP_INTUITICKS
;
3049 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3050 (IPTR
) & data
->ehn
);
3055 case IDCMP_INTUITICKS
:
3056 if (!(data
->ehn
.ehn_Events
& IDCMP_INTUITICKS
))
3059 if (!(_between(_mleft(obj
), msg
->imsg
->MouseX
, _mright(obj
))
3060 && _between(_mtop(obj
), msg
->imsg
->MouseY
,
3063 LONG new_virt_offx
= data
->virt_offx
;
3064 LONG new_virt_offy
= data
->virt_offy
;
3066 if (msg
->imsg
->MouseX
< _mleft(obj
))
3069 if (new_virt_offx
>= 4)
3074 else if (msg
->imsg
->MouseX
> _mright(obj
))
3078 if (new_virt_offx
> data
->virt_mwidth
- _mwidth(obj
))
3079 new_virt_offx
= data
->virt_mwidth
- _mwidth(obj
);
3080 if (new_virt_offx
< 0)
3084 if (msg
->imsg
->MouseY
< _mtop(obj
))
3087 if (new_virt_offy
>= 4)
3092 else if (msg
->imsg
->MouseY
> _mbottom(obj
))
3096 if (new_virt_offy
> data
->virt_mheight
- _mheight(obj
))
3097 new_virt_offy
= data
->virt_mheight
- _mheight(obj
);
3098 if (new_virt_offy
< 0)
3102 if (new_virt_offx
!= data
->virt_offx
3103 || new_virt_offy
!= data
->virt_offy
)
3106 MUIA_Virtgroup_Left
, new_virt_offx
,
3107 MUIA_Virtgroup_Top
, new_virt_offy
,
3108 MUIA_Group_Forward
, FALSE
, TAG_DONE
);
3118 /**************************************************************************
3120 **************************************************************************/
3121 IPTR
Group__MUIM_DrawBackground(struct IClass
*cl
, Object
*obj
,
3122 struct MUIP_DrawBackground
*msg
)
3124 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3126 if (data
->flags
& GROUP_VIRTUAL
)
3128 struct MUIP_DrawBackground msg2
= *msg
;
3130 msg2
.xoffset
+= data
->virt_offx
;
3131 msg2
.yoffset
+= data
->virt_offy
;
3133 return DoSuperMethodA(cl
, obj
, (Msg
) & msg2
);
3136 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3139 /**************************************************************************
3141 Find the given object or return NULL
3142 **************************************************************************/
3143 IPTR
Group__MUIM_FindAreaObject(struct IClass
*cl
, Object
*obj
,
3144 struct MUIP_FindAreaObject
*msg
)
3146 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3149 struct MinList
*ChildList
= NULL
;
3152 if (msg
->obj
== obj
)
3155 // it's one of my children ?
3156 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3157 cstate
= (Object
*) ChildList
->mlh_Head
;
3158 while ((child
= NextObject(&cstate
)))
3160 if (msg
->obj
== child
)
3161 return (IPTR
) child
;
3164 // let the children find it
3165 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3166 cstate
= (Object
*) ChildList
->mlh_Head
;
3167 while ((child
= NextObject(&cstate
)))
3169 Object
*res
= (Object
*) DoMethodA(child
, (Msg
) msg
);
3177 /**************************************************************************
3178 MUIM_Export : to export an objects "contents" to a dataspace object.
3179 **************************************************************************/
3180 static IPTR
Group__MUIM_Export(struct IClass
*cl
, Object
*obj
,
3181 struct MUIP_Export
*msg
)
3183 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3186 struct MinList
*ChildList
= NULL
;
3188 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3192 cstate
= (Object
*) ChildList
->mlh_Head
;
3193 while ((child
= NextObject(&cstate
)))
3195 DoMethodA(child
, (Msg
) msg
);
3202 /**************************************************************************
3203 MUIM_Import : to import an objects "contents" from a dataspace object.
3204 **************************************************************************/
3205 static IPTR
Group__MUIM_Import(struct IClass
*cl
, Object
*obj
,
3206 struct MUIP_Import
*msg
)
3208 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3211 struct MinList
*ChildList
= NULL
;
3213 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3217 cstate
= (Object
*) ChildList
->mlh_Head
;
3218 while ((child
= NextObject(&cstate
)))
3220 DoMethodA(child
, (Msg
) msg
);
3226 /**************************************************************************
3227 MUIM_Notify - disabled now because previous Zune versions had a OM_GET
3228 check in MUIM_Notify which is no longer the case
3229 **************************************************************************/
3231 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3232 struct MUIP_Notify
*msg
)
3234 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3237 struct MinList
*ChildList
;
3239 /* Try at first if understand the message our self
3240 ** We disable the forwarding of the OM_GET message
3241 ** as the MUIM_Notify otherwise would "think" that
3242 ** the group class actually understands the attribute
3243 ** although a child does this only
3245 data
->dont_forward_get
= 1;
3246 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
3248 data
->dont_forward_get
= 0;
3252 /* We ourselves didn't understand the notify tag so we try the
3254 data
->dont_forward_get
= 0;
3256 get(data
->family
, MUIA_Family_List
, (IPTR
*) & (ChildList
));
3257 cstate
= (Object
*) ChildList
->mlh_Head
;
3258 while ((child
= NextObject(&cstate
)))
3260 if (DoMethodA(child
, (Msg
) msg
))
3268 /* Notes about Group_Notify() and echo notification problem:
3269 It was discovered that MUI seems to have some special handling for group class
3270 which will drop notifications on the children which are found to not
3271 understand the attribute.
3273 This is done by checking if an OM_GET on the child returns TRUE.
3274 There's a little problem here because it is not known how big the storage
3275 needed for the attribute in question will be. Almost no class uses anything
3276 bigger than one IPTR. For "big" attributes those return a pointer to the data,
3277 not the data itself. Unfortuntely there are some exceptions like colorwheel
3278 class which does not return a pointer, but the data itself. So it's not
3279 enough to use one single IPTR variable (4 Bytes on 32bit machines, 8 bytes
3280 on 64 bit machines) to store the result of the test-OM_Get.
3282 There is no general way to query the size needed so if one wants to change
3283 Zune to work like MUI one needs to choose a size which one hopes will be
3284 big enough to hold all possible attributes of all classes, old, present
3287 STATIC IPTR
Group_Notify(struct IClass
*cl
, Object
*obj
,
3288 struct MUIP_Notify
*msg
)
3290 struct MUI_GroupData
*data
= INST_DATA(cl
, obj
);
3293 struct MinList
*ChildList
= NULL
;
3296 data
->dont_forward_get
= 1;
3298 if (GetAttr(msg
->TrigAttr
, obj
, attr
))
3300 data
->dont_forward_get
= 0;
3301 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3303 data
->dont_forward_get
= 0;
3305 get(data
->family
, MUIA_Family_List
, &(ChildList
));
3309 cstate
= (Object
*) ChildList
->mlh_Head
;
3310 while ((child
= NextObject(&cstate
)))
3313 if (GetAttr(msg
->TrigAttr
, child
, attr
))
3315 DoMethodA(child
, (Msg
) msg
);
3316 /* No return here! */
3323 BOOPSI_DISPATCHER(IPTR
, Group_Dispatcher
, cl
, obj
, msg
)
3325 switch (msg
->MethodID
)
3328 return Group__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3330 return Group__OM_DISPOSE(cl
, obj
, msg
);
3332 return Group__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3334 return Group__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3335 case OM_ADDMEMBER
: /* Fall through */
3336 case MUIM_Group_AddTail
:
3337 return Group__MUIM_AddTail(cl
, obj
, (APTR
) msg
);
3338 case MUIM_Group_AddHead
:
3339 return Group__MUIM_AddHead(cl
, obj
, (APTR
) msg
);
3340 case MUIM_Group_Insert
:
3341 return Group__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3342 case OM_REMMEMBER
: /* Fall through */
3343 case MUIM_Group_Remove
:
3344 return Group__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3345 case MUIM_AskMinMax
:
3346 return Group__MUIM_AskMinMax(cl
, obj
, (APTR
) msg
);
3347 case MUIM_Group_ExitChange
:
3348 return Group__MUIM_ExitChange(cl
, obj
, (APTR
) msg
);
3349 case MUIM_Group_ExitChange2
:
3350 return Group__MUIM_ExitChange2(cl
, obj
, (APTR
) msg
);
3351 case MUIM_Group_InitChange
:
3352 return Group__MUIM_InitChange(cl
, obj
, (APTR
) msg
);
3353 case MUIM_Group_Sort
:
3354 return Group__MUIM_Sort(cl
, obj
, (APTR
) msg
);
3355 case MUIM_Group_DoMethodNoForward
:
3356 return Group__MUIM_DoMethodNoForward(cl
, obj
, (APTR
) msg
);
3357 case MUIM_ConnectParent
:
3358 return Group__MUIM_ConnectParent(cl
, obj
, (APTR
) msg
);
3359 case MUIM_DisconnectParent
:
3360 return Group__MUIM_DisconnectParent(cl
, obj
, (APTR
) msg
);
3362 return Group__MUIM_Layout(cl
, obj
, (APTR
) msg
);
3364 return Group__MUIM_Setup(cl
, obj
, (APTR
) msg
);
3366 return Group__MUIM_Cleanup(cl
, obj
, (APTR
) msg
);
3368 return Group__MUIM_Draw(cl
, obj
, (APTR
) msg
);
3370 case MUIM_FindUData
:
3371 return Group__MUIM_FindUData(cl
, obj
, (APTR
) msg
);
3373 return Group__MUIM_GetUData(cl
, obj
, (APTR
) msg
);
3375 return Group__MUIM_SetUData(cl
, obj
, (APTR
) msg
);
3376 case MUIM_SetUDataOnce
:
3377 return Group__MUIM_SetUDataOnce(cl
, obj
, (APTR
) msg
);
3379 return Group__MUIM_Show(cl
, obj
, (APTR
) msg
);
3381 return Group__MUIM_Hide(cl
, obj
, (APTR
) msg
);
3382 case MUIM_HandleEvent
:
3383 return Group__MUIM_HandleEvent(cl
, obj
, (APTR
) msg
);
3384 case MUIM_DrawBackground
:
3385 return Group__MUIM_DrawBackground(cl
, obj
, (APTR
) msg
);
3386 case MUIM_DragQueryExtended
:
3387 return Group__MUIM_DragQueryExtended(cl
, obj
, (APTR
) msg
);
3388 case MUIM_FindAreaObject
:
3389 return Group__MUIM_FindAreaObject(cl
, obj
, (APTR
) msg
);
3391 return Group__MUIM_Export(cl
, obj
, (APTR
) msg
);
3393 return Group__MUIM_Import(cl
, obj
, (APTR
) msg
);
3397 /* Disabled. See above */
3399 return Group_Notify(cl
, obj
, (APTR
) msg
);
3404 case MUIM_DrawParentBackground
:
3405 case MUIM_DragBegin
:
3407 case MUIM_DragQuery
:
3408 case MUIM_DragFinish
:
3410 case MUIM_CreateDragImage
:
3411 case MUIM_DeleteDragImage
:
3413 case MUIM_GoInactive
:
3414 case MUIM_CreateBubble
:
3415 case MUIM_DeleteBubble
:
3416 case MUIM_CreateShortHelp
:
3417 case MUIM_DeleteShortHelp
:
3420 return DoSuperMethodA(cl
, obj
, (APTR
) msg
);
3421 /* Needs not to be forwarded? */
3424 /* sometimes you want to call a superclass method,
3425 * but not dispatching to child.
3426 * But what to do with list methods in a listview ?
3428 Group_DispatchMsg(cl
, obj
, (APTR
) msg
);
3430 return DoSuperMethodA(cl
, obj
, msg
);
3432 BOOPSI_DISPATCHER_END
3437 const struct __MUIBuiltinClass _MUI_Group_desc
=
3441 sizeof(struct MUI_GroupData
),
3442 (void *) Group_Dispatcher