Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / libs / muimaster / classes / group.c
blob76c9f9809388aee014f2619ec5a791bb629d663d
1 /*
2 Copyright 1999, David Le Corfec.
3 Copyright 2002-2006, The AROS Development Team.
4 All rights reserved.
6 $Id$
7 */
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"
21 #include "mui.h"
22 #include "support.h"
23 #include "prefs.h"
25 /* #define MYDEBUG 1 */
26 #include "debug.h"
28 #define ROUND(x) ((int)(x + 0.5))
29 #define IS_HIDDEN(obj) (! (_flags(obj) & MADF_SHOWME) || (_flags(obj) & MADF_BORDERGADGET))
31 /* Attributes filtered out in OM_SET, before OM_SET gets passed to children.
32 Tested with MUI under UAE/AOS.
34 notifyclass:
36 MUIA_HelpLine
37 MUIA_HelpNode
38 MUIA_ObjectID
39 MUIA_UserData
41 areaclass:
43 MUIA_ContextMenu
44 MUIA_ContextMenuTrigger
45 MUIA_ControlChar
46 MUIA_CycleChain
47 MUIA_Draggable
48 MUIA_FillArea
49 MUIA_Frame
50 MUIA_FrameTitle
51 MUIA_HorizWeight
52 MUIA_Pressed
53 MUIA_Selected
54 MUIA_ShortHelp
55 MUIA_ShowMe
56 MUIA_VertWeight
57 MUIA_Weight
61 struct layout2d_elem {
62 WORD min;
63 WORD max;
64 WORD dim;
65 ULONG weight;
69 struct MUI_GroupData
71 Object *family;
72 struct Hook *layout_hook;
73 ULONG flags;
74 ULONG columns;
75 ULONG rows;
76 struct layout2d_elem *row_infos;
77 struct layout2d_elem *col_infos;
78 LONG active_page;
79 ULONG horiz_spacing;
80 ULONG vert_spacing;
81 ULONG num_childs;
82 ULONG num_visible_children; /* for horiz/vert group only */
83 ULONG horiz_weight_sum;
84 ULONG vert_weight_sum;
85 ULONG samesize_maxmin_horiz;
86 ULONG samesize_maxmin_vert;
87 ULONG update; /* for MUI_Redraw() 1 - do not redraw the frame, 2 - the virtual pos has changed */
88 struct MUI_EventHandlerNode ehn;
89 LONG virt_offx, virt_offy; /* diplay offsets */
90 LONG old_virt_offx, old_virt_offy; /* Saved virtual positions, used for update == 2 */
91 LONG virt_mwidth,virt_mheight; /* The complete width */
92 LONG saved_minwidth,saved_minheight;
93 LONG dont_forward_get; /* Setted temporary to 1 so that the get method is not forwarded */
94 LONG dont_forward_methods; /* Setted temporary to 1, meaning that the methods are not forwarded to the group's children */
97 #define GROUP_HORIZ (1<<1)
98 #define GROUP_SAME_WIDTH (1<<2)
99 #define GROUP_SAME_HEIGHT (1<<3)
100 #define GROUP_CHANGING (1<<4)
101 #define GROUP_PAGEMODE (1<<5)
102 #define GROUP_VIRTUAL (1<<6)
103 #define GROUP_HSPACING (1<<7)
104 #define GROUP_VSPACING (1<<8)
107 /* During minmax calculations objects with a weight of 0 shall
108 be treated like they had identical min/def/max size, ie. fixed size.
110 During layout objects with 0 weight must be treated like fixed-sized
111 too, but for hgroups only in x direction, and for vgroups only in
112 y direction. I think ... */
114 #define w0_defwidth(x) (_hweight(x) ? _defwidth(x) : _minwidth(x))
115 #define w0_maxwidth(x) (_hweight(x) ? _maxwidth(x) : _minwidth(x))
117 #define w0_defheight(x) (_vweight(x) ? _defheight(x) : _minheight(x))
118 #define w0_maxheight(x) (_vweight(x) ? _maxheight(x) : _minheight(x))
120 static const int __version = 1;
121 static const int __revision = 1;
123 IPTR Group__MUIM_Show(struct IClass *cl, Object *obj, struct MUIP_Show *msg);
124 IPTR Group__MUIM_Hide(struct IClass *cl, Object *obj, struct MUIP_Hide *msg);
126 /******************************************************************************/
127 /******************************************************************************/
130 static ULONG Group_DispatchMsg(struct IClass *cl, Object *obj, Msg msg);
132 static void change_active_page (struct IClass *cl, Object *obj, LONG page)
134 struct MUI_GroupData *data = INST_DATA(cl, obj);
135 LONG newpage;
137 if (!(data->flags & GROUP_PAGEMODE)) return;
139 switch (page)
141 case MUIV_Group_ActivePage_First:
142 newpage = 0;
143 break;
144 case MUIV_Group_ActivePage_Last:
145 newpage = data->num_childs - 1;
146 break;
147 case MUIV_Group_ActivePage_Prev:
148 newpage = data->active_page - 1;
149 if (newpage == -1)
150 newpage = data->num_childs - 1;
151 break;
152 case MUIV_Group_ActivePage_Next:
153 case MUIV_Group_ActivePage_Advance:
154 newpage = (data->active_page + 1) % data->num_childs;
155 break;
156 default:
157 newpage = page;
158 break;
161 if (newpage != data->active_page)
163 if (_flags(obj) & MADF_CANDRAW) Group__MUIM_Hide(cl,obj,NULL);
164 data->active_page = newpage;
165 if (_flags(obj) & MADF_CANDRAW)
167 DoMethod(obj,MUIM_Layout);
168 Group__MUIM_Show(cl,obj,NULL);
169 data->update = 1;
170 MUI_Redraw(obj, MADF_DRAWUPDATE);
175 /**************************************************************************
176 Returns the number of visible children. Visible children are all children
177 with have MADF_SHOWME and not MADF_BORDERGADGET set.
178 **************************************************************************/
179 static int Group_GetNumVisibleChildren(struct MUI_GroupData *data, struct MinList *children)
181 int num_visible_children = data->num_childs;
182 Object *cstate;
183 Object *child;
185 /* As there can be unvisible children we have subtract those from the total
186 * number of children */
187 cstate = (Object *)children->mlh_Head;
188 while ((child = NextObject(&cstate)))
190 if (IS_HIDDEN(child))
191 num_visible_children--;
193 return num_visible_children;
196 /**************************************************************************
197 OM_NEW - Constructor
198 **************************************************************************/
199 IPTR Group__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
201 struct MUI_GroupData *data;
202 struct TagItem *tags,*tag;
203 BOOL bad_childs = FALSE;
204 ULONG disabled;
206 obj = (Object *)DoSuperMethodA(cl, obj, (Msg)msg);
207 if (!obj) return 0;
209 /* Initial local instance data */
210 data = INST_DATA(cl, obj);
212 data->family = MUI_NewObjectA(MUIC_Family, NULL);
213 if (!data->family)
215 CoerceMethod(cl,obj,OM_DISPOSE);
216 return 0;
219 data->horiz_spacing = -1;
220 data->vert_spacing = -1;
221 data->columns = 1;
222 data->rows = 1;
224 /* parse initial taglist */
225 for (tags = msg->ops_AttrList; (tag = NextTagItem((const struct TagItem **)&tags)); )
227 switch (tag->ti_Tag)
229 case MUIA_Group_Child:
230 if (tag->ti_Data) DoMethod(obj, OM_ADDMEMBER, tag->ti_Data);
231 else bad_childs = TRUE;
232 break;
234 case MUIA_Group_ActivePage:
235 change_active_page(cl, obj, (LONG)tag->ti_Data);
236 break;
238 case MUIA_Group_Columns:
239 data->columns = (tag->ti_Data)>1?tag->ti_Data:1;
240 data->rows = 0;
241 break;
243 case MUIA_Group_Horiz:
244 _handle_bool_tag(data->flags, tag->ti_Data, GROUP_HORIZ);
245 break;
247 case MUIA_Group_HorizSpacing:
248 data->flags |= GROUP_HSPACING;
249 data->horiz_spacing = tag->ti_Data;
250 break;
252 case MUIA_Group_LayoutHook:
253 data->layout_hook = (struct Hook *)tag->ti_Data;
254 break;
256 case MUIA_Group_PageMode:
257 _handle_bool_tag(data->flags, tag->ti_Data, GROUP_PAGEMODE);
258 break;
260 case MUIA_Group_Rows:
261 data->rows = MAX((ULONG)tag->ti_Data, 1);
262 data->columns = 0;
263 break;
265 case MUIA_Group_SameHeight:
266 _handle_bool_tag(data->flags, tag->ti_Data, GROUP_SAME_HEIGHT);
267 break;
269 case MUIA_Group_SameSize:
270 _handle_bool_tag(data->flags, tag->ti_Data, GROUP_SAME_HEIGHT);
271 _handle_bool_tag(data->flags, tag->ti_Data, GROUP_SAME_WIDTH);
272 break;
274 case MUIA_Group_SameWidth:
275 _handle_bool_tag(data->flags, tag->ti_Data, GROUP_SAME_WIDTH);
276 break;
278 case MUIA_Group_Spacing:
279 data->flags |= (GROUP_HSPACING | GROUP_VSPACING);
280 data->horiz_spacing = tag->ti_Data;
281 data->vert_spacing = tag->ti_Data;
282 break;
284 case MUIA_Group_VertSpacing:
285 data->flags |= GROUP_VSPACING;
286 data->vert_spacing = tag->ti_Data;
287 break;
289 case MUIA_Group_Virtual:
290 _handle_bool_tag(data->flags, tag->ti_Data, GROUP_VIRTUAL);
291 break;
295 if (bad_childs)
297 CoerceMethod(cl, obj, OM_DISPOSE);
298 return 0;
301 /* D(bug("Group_New(0x%lx)\n",obj)); */
303 if (data->flags & GROUP_VIRTUAL)
305 /* This is used by MUI_Render() to determine if group is virtual. It then installs a clip region.
306 * Also MUI_Layout() uses this. Probably for speed up reason */
307 _flags(obj) |= MADF_ISVIRTUALGROUP;
310 /* will forward MUIA_Disabled to childs */
311 get(obj, MUIA_Disabled, &disabled);
312 if (disabled)
314 set(obj, MUIA_Disabled, TRUE);
317 /* This is only used for virtual groups */
318 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS; /* Will be filled on demand */
319 data->ehn.ehn_Priority = 10; /* Will hear the click before all other normal objects */
320 data->ehn.ehn_Flags = 0;
321 data->ehn.ehn_Object = obj;
322 data->ehn.ehn_Class = cl;
323 return (IPTR)obj;
326 /**************************************************************************
327 OM_DISPOSE
328 **************************************************************************/
329 IPTR Group__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
331 struct MUI_GroupData *data = INST_DATA(cl, obj);
333 if (data->row_infos != NULL)
334 mui_free(data->row_infos);
335 if (data->col_infos != NULL)
336 mui_free(data->col_infos);
337 if (data->family != NULL)
338 MUI_DisposeObject(data->family);
339 return DoSuperMethodA(cl, obj, msg);
342 /**************************************************************************
343 OM_SET
344 **************************************************************************/
345 IPTR Group__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
347 struct MUI_GroupData *data = INST_DATA(cl, obj);
348 struct TagItem *tags = msg->ops_AttrList;
349 struct TagItem *tag;
350 BOOL forward = TRUE;
351 BOOL need_recalc = FALSE;
352 IPTR retval;
354 int virt_offx = data->virt_offx, virt_offy = data->virt_offy;
356 /* There are many ways to find out what tag items provided by set()
357 ** we do know. The best way should be using NextTagItem() and simply
358 ** browsing through the list.
361 /* Parse group attributes before calling DoSuperMethodA(),
362 ** otherwise if an app for example sets up a notification
363 ** on MUIA_Group_ActivePage which calls a hook, and then
364 ** the hook function calls get(obj, MUIA_Group_ActivePage),
365 ** it would get returned the old active page instead of the new
366 ** active page
369 while ((tag = NextTagItem((const struct TagItem **)&tags)) != NULL)
371 switch (tag->ti_Tag)
373 case MUIA_Group_Columns:
374 data->columns = MAX((ULONG)tag->ti_Data, 1);
375 data->rows = 0;
376 need_recalc = TRUE;
377 break;
378 case MUIA_Group_ActivePage:
379 change_active_page(cl, obj, (LONG)tag->ti_Data);
380 break;
381 case MUIA_Group_Forward:
382 forward = tag->ti_Data;
383 break;
384 case MUIA_Group_HorizSpacing:
385 data->flags |= GROUP_HSPACING;
386 data->horiz_spacing = tag->ti_Data;
387 break;
388 case MUIA_Group_Rows:
389 data->rows = MAX((ULONG)tag->ti_Data, 1);
390 data->columns = 0;
391 need_recalc = TRUE;
392 break;
393 case MUIA_Group_Spacing:
394 data->flags |= (GROUP_HSPACING | GROUP_VSPACING);
395 data->horiz_spacing = tag->ti_Data;
396 data->vert_spacing = tag->ti_Data;
397 break;
398 case MUIA_Group_VertSpacing:
399 data->flags |= GROUP_VSPACING;
400 data->vert_spacing = tag->ti_Data;
401 break;
402 case MUIA_Virtgroup_Left:
403 //kprintf("set virtgroup_left: %d\n", tag->ti_Data);
404 virt_offx = tag->ti_Data;
405 break;
407 case MUIA_Group_LayoutHook:
409 [ach] Seems like MUI supports setting this attribute after
410 initialization, even though the documentation states
411 otherwise. Atleast some programs use it...
413 data->layout_hook = (struct Hook *)tag->ti_Data;
414 break;
416 case MUIA_Virtgroup_Top:
417 //kprintf("set virtgroup_top: %d\n", tag->ti_Data);
418 virt_offy = tag->ti_Data;
419 break;
425 if (need_recalc)
426 DoMethod(_win(obj), MUIM_Window_RecalcDisplay, (IPTR)obj);
428 retval = DoSuperMethodA(cl, obj, (Msg)msg);
430 /* seems to be the documented behaviour, however it should be slow! */
432 if (forward)
434 /* Attributes which are to be filtered out, so that they are ignored
435 when OM_SET is passed to group's children */
437 tags = msg->ops_AttrList;
438 while ((tag = NextTagItem((const struct TagItem **)&tags)) != NULL)
440 switch (tag->ti_Tag)
442 case MUIA_HelpLine:
443 case MUIA_HelpNode:
444 case MUIA_ObjectID:
445 case MUIA_UserData:
447 case MUIA_ContextMenu:
448 case MUIA_ContextMenuTrigger:
449 case MUIA_ControlChar:
450 case MUIA_CycleChain:
451 case MUIA_Draggable:
452 case MUIA_FillArea:
453 case MUIA_Group_ActivePage:
454 case MUIA_Frame:
455 case MUIA_FrameTitle:
456 case MUIA_HorizWeight:
457 case MUIA_Pressed:
458 case MUIA_ShortHelp:
459 case MUIA_ShowMe:
460 case MUIA_VertWeight:
461 case MUIA_Weight:
462 case MUIA_Virtgroup_Left:
463 case MUIA_Virtgroup_Top:
464 tag->ti_Tag = TAG_IGNORE;
465 break;
466 case MUIA_Selected:
467 /* D(bug("Group_Set(%p) MUIA_Selected forwarded\n", obj)); */
468 /* tag->ti_Tag = TAG_IGNORE; */
469 break;
473 Group_DispatchMsg(cl, obj, (Msg)msg);
477 if (virt_offx != data->virt_offx || virt_offy != data->virt_offy)
479 if (_flags(obj) & MADF_CANDRAW) Group__MUIM_Hide(cl,obj,NULL);
480 data->virt_offx = virt_offx;
481 data->virt_offy = virt_offy;
482 /* Relayout ourself, this will also relayout all the children */
483 DoMethod(obj,MUIM_Layout);
484 if (_flags(obj) & MADF_CANDRAW) Group__MUIM_Show(cl,obj,NULL);
485 data->update = 2;
486 MUI_Redraw(obj,MADF_DRAWUPDATE);
489 return retval;
493 /**************************************************************************
494 OM_GET
495 **************************************************************************/
496 IPTR Group__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
498 /* small macro to simplify return value storage */
499 #define STORE *(msg->opg_Storage)
501 struct MUI_GroupData *data = INST_DATA(cl, obj);
503 switch (msg->opg_AttrID)
505 case MUIA_Version: STORE = __version; return 1;
506 case MUIA_Revision: STORE = __revision; return 1;
507 case MUIA_Group_ActivePage: STORE = data->active_page; return 1;
508 case MUIA_Group_ChildList: return GetAttr(MUIA_Family_List, data->family, msg->opg_Storage);
509 case MUIA_Group_Horiz: STORE = (data->flags & GROUP_HORIZ); return 1;
510 case MUIA_Group_HorizSpacing: STORE = data->horiz_spacing; return 1;
511 case MUIA_Group_VertSpacing: STORE = data->vert_spacing; return 1;
512 case MUIA_Virtgroup_Left: STORE = data->virt_offx; return 1;
513 case MUIA_Virtgroup_Top: STORE = data->virt_offy; return 1;
514 case MUIA_Virtgroup_Width: STORE = data->virt_mwidth; return 1;
515 case MUIA_Virtgroup_Height: STORE = data->virt_mheight; return 1;
516 case MUIA_Virtgroup_MinWidth: STORE = data->saved_minwidth; return 1;
517 case MUIA_Virtgroup_MinHeight: STORE = data->saved_minheight; return 1;
520 /* our handler didn't understand the attribute, we simply pass
521 ** it to our superclass now
523 if (DoSuperMethodA(cl, obj, (Msg) msg)) return 1;
525 /* seems to be the documented behaviour, however it should be slow! */
526 // if (!data->dont_forward_get)
528 Object *cstate;
529 Object *child;
530 struct MinList *ChildList;
532 get(data->family, MUIA_Family_List, &(ChildList));
533 cstate = (Object *)ChildList->mlh_Head;
534 while ((child = NextObject(&cstate)))
535 if (DoMethodA(child, (Msg)msg)) return 1;
537 return 0;
538 #undef STORE
542 /**************************************************************************
543 OM_ADDMEMBER
544 **************************************************************************/
545 IPTR Group__OM_ADDMEMBER(struct IClass *cl, Object *obj, struct opMember *msg)
547 struct MUI_GroupData *data = INST_DATA(cl, obj);
549 /* D(bug("Group_AddMember(0x%lx, 0x%lx)\n",obj, msg->opam_Object)); */
551 DoMethodA(data->family, (Msg)msg);
552 data->num_childs++;
554 /* if we are in an application tree, propagate pointers */
555 if (muiNotifyData(obj)->mnd_GlobalInfo)
557 /* Only childs of groups can have parents */
559 if ((_flags(obj) & MADF_INVIRTUALGROUP) || (data->flags & GROUP_VIRTUAL))
561 _flags(msg->opam_Object) |= MADF_INVIRTUALGROUP;
564 muiNotifyData(msg->opam_Object)->mnd_ParentObject = obj;
565 DoMethod(msg->opam_Object, MUIM_ConnectParent, (IPTR)obj);
568 if (_flags(obj) & MADF_SETUP)
570 DoSetupMethod(msg->opam_Object, muiRenderInfo(obj));
572 /* if (_flags(obj) & MADF_CANDRAW) */
573 /* DoShowMethod(msg->opam_Object); */
575 return TRUE;
578 /**************************************************************************
579 OM_REMMEMBER
580 **************************************************************************/
581 IPTR Group__OM_REMMEMBER(struct IClass *cl, Object *obj, struct opMember *msg)
583 struct MUI_GroupData *data = INST_DATA(cl, obj);
585 if (_flags(obj) & MADF_CANDRAW)
586 DoHideMethod(msg->opam_Object);
587 if (_flags(obj) & MADF_SETUP)
588 DoMethod(msg->opam_Object, MUIM_Cleanup);
589 if (muiNotifyData(obj)->mnd_GlobalInfo)
591 DoMethod(msg->opam_Object, MUIM_DisconnectParent);
592 muiNotifyData(msg->opam_Object)->mnd_ParentObject = NULL;
594 _flags(msg->opam_Object) &= ~MADF_INVIRTUALGROUP;
597 data->num_childs--;
598 DoMethodA(data->family, (Msg)msg);
600 return TRUE;
604 /**************************************************************************
605 MUIM_ConnectParent
606 **************************************************************************/
607 IPTR Group__MUIM_ConnectParent(struct IClass *cl, Object *obj, struct MUIP_ConnectParent *msg)
609 struct MUI_GroupData *data = INST_DATA(cl, obj);
610 Object *cstate;
611 Object *child;
612 struct MinList *ChildList;
614 DoSuperMethodA(cl,obj,(Msg)msg);
616 get(data->family, MUIA_Family_List, &(ChildList));
617 cstate = (Object *)ChildList->mlh_Head;
618 while ((child = NextObject(&cstate)))
620 if ((_flags(obj) & MADF_INVIRTUALGROUP) || (data->flags & GROUP_VIRTUAL))
622 _flags(child) |= MADF_INVIRTUALGROUP;
625 /* Only childs of groups can have parents */
626 muiNotifyData(child)->mnd_ParentObject = obj;
628 DoMethod(child, MUIM_ConnectParent, (IPTR)obj);
630 return TRUE;
633 /**************************************************************************
634 MUIM_DisconnectParent
635 **************************************************************************/
636 IPTR Group__MUIM_DisconnectParent(struct IClass *cl, Object *obj, struct MUIP_ConnectParent *msg)
638 struct MUI_GroupData *data = INST_DATA(cl, obj);
639 Object *cstate;
640 Object *child;
641 struct MinList *ChildList;
643 get(data->family, MUIA_Family_List, &(ChildList));
644 cstate = (Object *)ChildList->mlh_Head;
645 while ((child = NextObject(&cstate)))
647 DoMethodA(child, (Msg)msg);
648 muiNotifyData(child)->mnd_ParentObject = NULL;
649 _flags(child) &= ~MADF_INVIRTUALGROUP;
651 DoSuperMethodA(cl,obj,(Msg)msg);
652 return TRUE;
656 * Put group in exchange state
658 IPTR Group__MUIM_InitChange(struct IClass *cl, Object *obj,
659 struct MUIP_Group_InitChange *msg)
661 struct MUI_GroupData *data = INST_DATA(cl, obj);
663 data->flags |= GROUP_CHANGING;
664 return TRUE;
669 * Will recalculate display after dynamic adding/removing
671 IPTR Group__MUIM_ExitChange(struct IClass *cl, Object *obj,
672 struct MUIP_Group_ExitChange *msg)
674 struct MUI_GroupData *data = INST_DATA(cl, obj);
676 if (data->flags & GROUP_CHANGING)
678 data->flags &= ~GROUP_CHANGING;
680 if ((_flags(obj) & MADF_SETUP) && _win(obj))
681 DoMethod(_win(obj), MUIM_Window_RecalcDisplay, (IPTR)obj);
684 return TRUE;
689 * Sort the family
691 IPTR Group__MUIM_Sort(struct IClass *cl, Object *obj, struct MUIP_Group_Sort *msg)
693 struct MUI_GroupData *data = INST_DATA(cl, obj);
695 /* modify message */
696 msg->MethodID = MUIM_Family_Sort;
698 DoMethodA(data->family, (APTR)msg);
700 /* restore original message */
701 msg->MethodID = MUIM_Group_Sort;
702 return TRUE;
705 /**************************************************************************
706 MUIM_Group_DoMethodNoForward
708 Executes the given method but does not forward it to the children
709 **************************************************************************/
710 IPTR Group__MUIM_DoMethodNoForward(struct IClass *cl, Object *obj, struct MUIP_Group_DoMethodNoForward *msg)
712 struct MUI_GroupData *data = INST_DATA(cl, obj);
713 IPTR rc;
714 data->dont_forward_methods = 1; /* disable forwarding */
715 rc = DoMethodA(obj, (Msg)&msg->DoMethodID); /* Probably doesn't not work correctly on AROS? */
716 data->dont_forward_methods = 0;
717 return rc;
721 * Propagate a method to group childs.
723 static ULONG Group_DispatchMsg(struct IClass *cl, Object *obj, Msg msg)
725 struct MUI_GroupData *data = INST_DATA(cl, obj);
726 Object *cstate;
727 Object *child;
728 struct MinList *ChildList;
730 if (data->dont_forward_methods) return TRUE;
732 get(data->family, MUIA_Family_List, &(ChildList));
733 cstate = (Object *)ChildList->mlh_Head;
734 while ((child = NextObject(&cstate)))
735 DoMethodA(child, (Msg)msg);
736 return TRUE;
740 /**************************************************************************
741 MUIM_Setup
742 **************************************************************************/
743 IPTR Group__MUIM_Setup(struct IClass *cl, Object *obj, struct MUIP_Setup *msg)
745 struct MUI_GroupData *data = INST_DATA(cl, obj);
746 Object *cstate;
747 Object *cstate_copy;
748 Object *child;
749 Object *childFailed;
750 struct MinList *ChildList;
752 if (!DoSuperMethodA(cl, obj, (Msg)msg))
753 return FALSE;
755 ASSERT_VALID_PTR(muiGlobalInfo(obj));
757 if (!(data->flags & GROUP_HSPACING))
758 data->horiz_spacing = muiGlobalInfo(obj)->mgi_Prefs->group_hspacing;
759 if (!(data->flags & GROUP_VSPACING))
760 data->vert_spacing = muiGlobalInfo(obj)->mgi_Prefs->group_vspacing;
761 get(data->family, MUIA_Family_List, &(ChildList));
762 cstate = cstate_copy = (Object *)ChildList->mlh_Head;
763 while ((child = NextObject(&cstate)))
765 #if 0 /* SHOWME affects only show/hide */
766 if (! (_flags(child) & MADF_SHOWME))
767 continue;
768 #endif
770 if (!DoSetupMethod(child, msg->RenderInfo))
772 /* Send MUIM_Cleanup to all objects that received MUIM_Setup.
774 childFailed = child;
775 cstate = cstate_copy;
776 while ((child = NextObject(&cstate)) && (child != childFailed))
778 #if 0 /* SHOWME affects only show/hide */
779 if (! (_flags(child) & MADF_SHOWME))
780 continue;
781 #endif
782 DoMethod(child, MUIM_Cleanup);
784 return FALSE;
788 if (data->flags & GROUP_VIRTUAL)
790 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
793 return TRUE;
797 /**************************************************************************
798 MUIM_Cleanup
799 **************************************************************************/
800 IPTR Group__MUIM_Cleanup(struct IClass *cl, Object *obj, Msg msg)
802 struct MUI_GroupData *data = INST_DATA(cl, obj);
803 Object *cstate;
804 Object *child;
805 struct MinList *ChildList;
807 if (data->flags & GROUP_VIRTUAL)
809 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
812 get(data->family, MUIA_Family_List, &(ChildList));
813 cstate = (Object *)ChildList->mlh_Head;
814 while ((child = NextObject(&cstate)))
816 #if 0 /* SHOWME affects only show/hide */
817 if (! (_flags(child) & MADF_SHOWME))
818 continue;
819 #endif
820 DoMethodA(child, (Msg)msg);
822 return DoSuperMethodA(cl, obj, (Msg)msg);
827 /**************************************************************************
828 MUIM_Draw - draw the group
829 **************************************************************************/
830 IPTR Group__MUIM_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
832 struct MUI_GroupData *data = INST_DATA(cl, obj);
833 Object *cstate;
834 Object *child;
835 struct MinList *ChildList;
836 struct Rectangle group_rect; /* child_rect;*/
837 int page;
838 struct Region *region = NULL;
839 APTR clip = (APTR)-1;
841 /* D(bug("Group_Draw(%lx) %ldx%ldx%ldx%ld upd=%d page=%d\n", */
842 /* obj,_left(obj),_top(obj),_right(obj),_bottom(obj), */
843 /* data->update, data->active_page)); */
844 /* D(bug("Group_Draw(%p) msg=0x%08lx flags=0x%08lx\n", obj, msg->flags, _flags(obj))); */
846 if (data->flags & GROUP_CHANGING)
847 return FALSE;
849 if (muiGlobalInfo(obj)->mgi_Prefs->window_redraw == WINDOW_REDRAW_WITHOUT_CLEAR)
851 region = NewRegion();
852 if (region)
854 struct Rectangle rect;
856 rect.MinX = _left(obj);
857 rect.MinY = _top(obj);
858 rect.MaxX = _right(obj);
859 rect.MaxY = _bottom(obj);
861 OrRectRegion(region, &rect);
862 page = -1;
863 get(data->family, MUIA_Family_List, &(ChildList));
864 cstate = (Object *)ChildList->mlh_Head;
865 while ((child = NextObject(&cstate)))
867 /*page++;*//* redraw problem with colorwheel in coloradjust register */
868 if ((data->flags & GROUP_PAGEMODE) && (page != data->active_page))
869 continue;
871 if ((muiAreaData(child)->mad_Flags & MADF_CANDRAW)
872 && (_width(child) > 0)
873 && (_height(child) > 0))
875 rect.MinX = MAX(_left(child) , _mleft (obj));
876 rect.MinY = MAX(_top(child) , _mtop (obj));
877 rect.MaxX = MIN(_right(child) , _mright (obj));
878 rect.MaxY = MIN(_bottom(child), _mbottom(obj));
880 if ((rect.MaxX >= rect.MinX) && (rect.MaxY >= rect.MinY))
882 ClearRectRegion(region, &rect);
887 clip = MUI_AddClipRegion(muiRenderInfo(obj), region);
891 DoSuperMethodA(cl, obj, (Msg)msg);
893 if (region)
895 MUI_RemoveClipRegion(muiRenderInfo(obj), clip);
896 region = NULL;
899 else
901 DoSuperMethodA(cl, obj, (Msg)msg);
903 /* D(bug("Group_Draw(%p) (after dsma) msg=0x%08lx flags=0x%08lx\n", */
904 /* obj, msg->flags, _flags(obj))); */
906 if ((msg->flags & MADF_DRAWUPDATE) && data->update == 1)
909 * update is set when changing active page of a page group
910 * need to redraw background ourself
912 DoMethod(obj, MUIM_DrawBackground,
913 _mleft(obj), _mtop(obj), _mwidth(obj), _mheight(obj), _mleft(obj), _mtop(obj), 0);
915 data->update = 0;
916 } else
918 if ((msg->flags & MADF_DRAWUPDATE) && data->update == 2)
920 LONG left,top,right,bottom;
921 LONG diff_virt_offx = data->virt_offx - data->old_virt_offx;
922 LONG diff_virt_offy = data->virt_offy - data->old_virt_offy;
923 struct Rectangle rect;
924 struct Rectangle *clip_rect = &muiRenderInfo(obj)->mri_ClipRect;
926 data->update = 0;
928 if (!diff_virt_offx && !diff_virt_offy)
930 return 1;
933 /* sba: I don't know how MUI handle this but ScrollRasterBF() made problems when scrolling
934 ** a (partly visible) virtual groups in a virtual group, because e.g. _mtop() is then
935 ** smaller than the region. ScrollRasterBF() on AmigaOS then marks the complete region
936 ** as damaged. Using ScrollWindowRaster() solved that problem but it flickers then.
937 ** To avoid this we prevent that the scroll area is out of the region bounds.
938 ** The region bounds are setted in MUI_Redraw() but should probably should go in the
939 ** MUI's clip functions
942 left = MAX(_mleft(obj),clip_rect->MinX);
943 top = MAX(_mtop(obj),clip_rect->MinY);
944 right = MIN(_mright(obj),clip_rect->MaxX);
945 bottom = MIN(_mbottom(obj),clip_rect->MaxY);
947 /* old code was
948 ** ScrollRasterBF(_rp(obj), diff_virt_offx, diff_virt_offy, _mleft(obj), _mtop(obj), _mright(obj),_mbottom(obj));
951 ScrollWindowRaster(_window(obj), diff_virt_offx, diff_virt_offy, left, top, right,bottom);
953 if ((region = NewRegion()))
955 if (diff_virt_offx)
957 rect.MinY = top;
958 rect.MaxY = bottom;
960 if (diff_virt_offx > 0)
962 rect.MinX = right - diff_virt_offx + 1;
963 if (rect.MinX < left) rect.MinX = left;
964 rect.MaxX = right;
965 } else
967 rect.MinX = left;
968 rect.MaxX = left - diff_virt_offx - 1;
969 if (rect.MaxX > right) rect.MaxX = right;
972 if (rect.MinX <= rect.MaxX)
974 DoMethod(obj, MUIM_DrawBackground,
975 rect.MinX, rect.MinY,
976 rect.MaxX - rect.MinX + 1,
977 rect.MaxY - rect.MinY + 1,
978 rect.MinX, rect.MinY, 0);
980 OrRectRegion(region,&rect);
984 if (diff_virt_offy)
986 rect.MinX = left;
987 rect.MaxX = right;
989 if (diff_virt_offy > 0)
991 rect.MinY = bottom - diff_virt_offy + 1;
992 if (rect.MinY < top) rect.MinY = top;
993 rect.MaxY = bottom;
994 } else
996 rect.MinY = top;
997 rect.MaxY = top - diff_virt_offy - 1;
998 if (rect.MaxY > bottom) rect.MaxY = bottom;
1000 if (rect.MinY <= rect.MaxY)
1002 DoMethod(obj, MUIM_DrawBackground,
1003 rect.MinX, rect.MinY,
1004 rect.MaxX - rect.MinX + 1,
1005 rect.MaxY - rect.MinY + 1,
1006 rect.MinX, rect.MinY, 0);
1008 OrRectRegion(region,&rect);
1013 } else
1015 if (!(msg->flags & MADF_DRAWOBJECT) && !(msg->flags & MADF_DRAWALL))
1016 return TRUE;
1020 if (data->flags & GROUP_VIRTUAL && !region)
1022 /* Not really needed if MUI Draws all the objects, maybe that's where DRAWALL is for??? */
1023 if ((region = NewRegion()))
1025 struct Rectangle rect;
1026 rect.MinX = _mleft(obj);
1027 rect.MinY = _mtop(obj);
1028 rect.MaxX = _mright(obj);
1029 rect.MaxY = _mbottom(obj);
1030 OrRectRegion(region,&rect);
1034 /* Add clipping region if we have one */
1035 if (region) clip = MUI_AddClipRegion(muiRenderInfo(obj),region);
1037 group_rect = muiRenderInfo(obj)->mri_ClipRect;
1038 page = -1;
1039 get(data->family, MUIA_Family_List, &(ChildList));
1040 cstate = (Object *)ChildList->mlh_Head;
1041 while ((child = NextObject(&cstate)))
1043 if (! (_flags(child) & MADF_SHOWME))
1044 continue;
1045 ++page;
1046 if ((data->flags & GROUP_PAGEMODE) && (page != data->active_page))
1048 continue;
1051 // msg->flags |= MADF_DRAWOBJECT; /* yup, do not forget */
1053 // child_rect.MinX = _left(child);
1054 // child_rect.MinY = _top(child);
1055 // child_rect.MaxX = _right(child);
1056 // child_rect.MaxY = _bottom(child);
1057 /* g_print("intersect: a=(%d, %d, %d, %d) b=(%d, %d, %d, %d)\n", */
1058 /* group_rect.x, group_rect.y, */
1059 /* group_rect.width, group_rect.height, */
1060 /* child_rect.x, child_rect.y, */
1061 /* child_rect.width, child_rect.height); */
1063 // if (gdk_rectangle_intersect(&group_rect, &child_rect,
1064 // &muiRenderInfo(obj)->mri_ClipRect))
1065 // DoMethodA(child, (Msg)msg);
1066 /* if (((msg->flags & MADF_DRAWUPDATE) && data->update) || (data->flags & GROUP_PAGEMODE)) */
1067 MUI_Redraw(child, MADF_DRAWOBJECT);
1068 /* else */
1069 /* MUI_Redraw(child, msg->flags); */
1070 muiRenderInfo(obj)->mri_ClipRect = group_rect;
1071 /* g_print("set back clip to (%d, %d, %d, %d)\n", */
1072 /* group_rect.x, group_rect.y, group_rect.width, group_rect.height); */
1074 /* D(bug("Group_Draw(%p) end\n", obj)); */
1076 if (data->flags & GROUP_VIRTUAL && region && clip != (APTR)-1)
1078 MUI_RemoveClipRegion(muiRenderInfo(obj), clip);
1081 data->old_virt_offx = data->virt_offx;
1082 data->old_virt_offy = data->virt_offy;
1083 data->update = 0;
1085 return TRUE;
1089 #define END_MINMAX() \
1090 tmp.MaxHeight = MAX(tmp.MaxHeight, tmp.MinHeight); \
1091 tmp.MaxWidth = MAX(tmp.MaxWidth, tmp.MinWidth); \
1092 tmp.DefHeight = CLAMP(tmp.DefHeight, tmp.MinHeight, tmp.MaxHeight); \
1093 tmp.DefWidth = CLAMP(tmp.DefWidth, tmp.MinWidth, tmp.MaxWidth); \
1094 msg->MinMaxInfo->MinWidth += tmp.MinWidth; \
1095 msg->MinMaxInfo->MinHeight += tmp.MinHeight; \
1096 msg->MinMaxInfo->MaxWidth += tmp.MaxWidth; \
1097 msg->MinMaxInfo->MaxHeight += tmp.MaxHeight; \
1098 msg->MinMaxInfo->DefWidth += tmp.DefWidth; \
1099 msg->MinMaxInfo->DefHeight += tmp.DefHeight;
1102 * MinMax calculation function. When this is called,
1103 * the children of your group have already been asked
1104 * about their min/max dimension so you can use their
1105 * dimensions to calculate yours.
1107 * Notes:
1108 * - Init minwidth and maxwidth with size needed for total child spacing.
1109 * - 1st pass to find maximum minimum width, to set minwidth of each child
1110 * if they should have the same width (for a row of buttons ...)
1111 * - Adjust minwidth w/o making object bigger than their max size.
1113 static void group_minmax_horiz(struct IClass *cl, Object *obj,
1114 struct MinList *children, struct MUIP_AskMinMax *msg)
1116 struct MUI_GroupData *data = INST_DATA(cl, obj);
1117 Object *cstate;
1118 Object *child;
1119 struct MUI_MinMax tmp;
1120 WORD maxminwidth = 0;
1121 BOOL found_nonzero_vweight = FALSE;
1123 tmp.MinHeight = 0;
1124 tmp.DefHeight = 0;
1125 tmp.MaxHeight = MUI_MAXMAX;
1126 tmp.MinWidth = tmp.DefWidth = tmp.MaxWidth =
1127 (data->num_visible_children - 1) * data->horiz_spacing;
1129 if (data->flags & GROUP_SAME_WIDTH) {
1130 cstate = (Object *)children->mlh_Head;
1131 while ((child = NextObject(&cstate))) {
1132 if (IS_HIDDEN(child))
1133 continue;
1134 maxminwidth = MAX(maxminwidth, _minwidth(child));
1138 data->samesize_maxmin_horiz = maxminwidth;
1139 /* D(bug("group_minmax_horiz(%p) : maxminwidth=%d\n", obj, maxminwidth)); */
1141 data->horiz_weight_sum = 0;
1142 cstate = (Object *)children->mlh_Head;
1143 while ((child = NextObject(&cstate))) {
1144 WORD minwidth;
1146 if (IS_HIDDEN(child))
1147 continue;
1148 if (data->flags & GROUP_SAME_WIDTH)
1150 minwidth = MAX(maxminwidth, _minwidth(child));
1151 minwidth = MIN(minwidth, _maxwidth(child));
1153 else
1154 minwidth = _minwidth(child);
1155 tmp.MinWidth += minwidth;
1156 tmp.DefWidth += w0_defwidth(child);
1157 tmp.MaxWidth += w0_maxwidth(child);
1158 tmp.MaxWidth = MIN(tmp.MaxWidth, MUI_MAXMAX);
1159 tmp.MinHeight = MAX(tmp.MinHeight, _minheight(child));
1160 tmp.DefHeight = MAX(tmp.DefHeight, _defheight(child));
1162 if all childs have null weight then maxheight=minheight
1163 if all but some childs have null weights, the maxheight
1164 is the min of all maxheights
1166 tmp.MaxHeight = MIN(tmp.MaxHeight, _maxheight(child));
1167 data->horiz_weight_sum += _hweight(child);
1168 if (_vweight(child) > 0)
1170 found_nonzero_vweight = TRUE;
1173 if (!found_nonzero_vweight)
1175 tmp.MaxHeight = tmp.MinHeight;
1178 //if (data->flags & GROUP_VIRTUAL)
1180 //kprintf("# min %d x %d def %d x %d max %d x %d\n",
1181 // tmp.MinWidth, tmp.MinHeight,
1182 // tmp.DefWidth, tmp.DefHeight,
1183 // tmp.MaxWidth, tmp.MaxHeight);
1186 END_MINMAX();
1189 /* minmax calculation for vertical groups (see group_minmax_horiz)
1191 static void group_minmax_vert(struct IClass *cl, Object *obj,
1192 struct MinList *children, struct MUIP_AskMinMax *msg)
1194 struct MUI_GroupData *data = INST_DATA(cl, obj);
1195 Object *cstate;
1196 Object *child;
1197 struct MUI_MinMax tmp;
1198 WORD maxminheight = 0;
1199 BOOL found_nonzero_hweight = FALSE;
1201 tmp.MinWidth = 0;
1202 tmp.DefWidth = 0;
1203 tmp.MaxWidth = MUI_MAXMAX;
1204 tmp.MinHeight = tmp.DefHeight = tmp.MaxHeight =
1205 (data->num_visible_children - 1) * data->vert_spacing;
1207 if (data->flags & GROUP_SAME_HEIGHT)
1209 cstate = (Object *)children->mlh_Head;
1210 while ((child = NextObject(&cstate))) {
1211 if (IS_HIDDEN(child))
1212 continue;
1213 maxminheight = MAX(maxminheight, _minheight(child));
1217 data->samesize_maxmin_vert = maxminheight;
1218 data->vert_weight_sum = 0;
1219 cstate = (Object *)children->mlh_Head;
1220 while ((child = NextObject(&cstate)))
1222 if (IS_HIDDEN(child))
1223 continue;
1225 if (data->flags & GROUP_SAME_HEIGHT)
1226 _minheight(child) = MIN(maxminheight, w0_maxheight(child));
1227 tmp.MinHeight += _minheight(child);
1228 tmp.DefHeight += w0_defheight(child);
1229 tmp.MaxHeight += w0_maxheight(child);
1230 tmp.MaxHeight = MIN(tmp.MaxHeight, MUI_MAXMAX);
1231 tmp.MinWidth = MAX(tmp.MinWidth, _minwidth(child));
1232 tmp.DefWidth = MAX(tmp.DefWidth, _defwidth(child));
1233 tmp.MaxWidth = MIN(tmp.MaxWidth, _maxwidth(child));
1234 data->vert_weight_sum += _vweight(child);
1235 if (_hweight(child) > 0)
1237 found_nonzero_hweight = TRUE;
1240 if (!found_nonzero_hweight)
1242 tmp.MaxWidth = tmp.MinWidth;
1245 END_MINMAX();
1249 static void
1250 minmax_2d_rows_pass (struct MUI_GroupData *data, struct MinList *children,
1251 struct MUI_MinMax *req, WORD maxmin_height, WORD maxdef_height)
1253 int i, j;
1254 Object *cstate;
1255 Object *child;
1257 /* do not rewind after the while, to process line by line */
1258 cstate = (Object *)children->mlh_Head;
1259 /* for each row */
1260 for (i = 0; i < data->rows; i++) {
1261 /* calculate min and max height of this row */
1262 int min_h = 0, def_h = 0, max_h = MUI_MAXMAX;
1263 BOOL found_nonzero_vweight = FALSE;
1265 data->row_infos[i].weight = 0;
1267 j = 0;
1268 while ((child = NextObject(&cstate))) {
1269 if (IS_HIDDEN(child))
1270 continue;
1271 if (data->flags & GROUP_SAME_HEIGHT)
1273 _minheight(child) = MIN(maxmin_height, w0_maxheight(child));
1274 _defheight(child) = MIN(maxdef_height, w0_maxheight(child));
1276 min_h = MAX(min_h, _minheight(child));
1277 def_h = MAX(def_h, w0_defheight(child));
1278 max_h = MIN(max_h, _maxheight(child));
1279 if (_vweight(child) > 0)
1281 found_nonzero_vweight = TRUE;
1282 data->row_infos[i].weight += _vweight(child);
1284 ++j;
1285 if ((j % data->columns) == 0)
1286 break;
1288 if (!found_nonzero_vweight)
1289 max_h = min_h;
1290 else
1291 max_h = MAX(max_h, min_h);
1292 /* D(bug("row %d : min_h=%d max_h=%d\n", i, min_h, max_h)); */
1294 data->row_infos[i].min = min_h;
1295 data->row_infos[i].max = max_h;
1296 data->vert_weight_sum += data->row_infos[i].weight;
1298 req->MinHeight += min_h;
1299 req->DefHeight += def_h;
1300 req->MaxHeight += max_h;
1301 if (req->MaxHeight > MUI_MAXMAX)
1302 req->MaxHeight = MUI_MAXMAX;
1307 static void
1308 minmax_2d_columns_pass (struct MUI_GroupData *data, struct MinList *children,
1309 struct MUI_MinMax *req, WORD maxmin_width, WORD maxdef_width)
1311 int i, j;
1312 Object *cstate;
1313 Object *child;
1315 for (i = 0; i < data->columns; i++) {
1316 /* calculate min and max width of this column */
1317 int min_w = 0, def_w = 0, max_w = MUI_MAXMAX;
1318 BOOL found_nonzero_hweight = FALSE;
1320 data->col_infos[i].weight = 0;
1322 j = 0;
1323 /* process all childs to get childs on a column */
1324 cstate = (Object *)children->mlh_Head;
1325 while ((child = NextObject(&cstate))) {
1326 if (IS_HIDDEN(child))
1327 continue;
1328 ++j;
1329 if (((j - 1) % data->columns) != i)
1330 continue;
1331 if (data->flags & GROUP_SAME_WIDTH)
1333 _minwidth(child) = MIN(maxmin_width, w0_maxwidth(child));
1334 _defwidth(child) = MIN(maxdef_width, w0_maxwidth(child));
1336 min_w = MAX(min_w, _minwidth(child));
1337 def_w = MAX(def_w, w0_defwidth(child));
1339 /* this handles the case of null weight childs, which limit
1340 * the max size if they're alone, but not if they are with
1341 * non-null weight obj
1343 max_w = MIN(max_w, _maxwidth(child));
1344 if (_hweight(child) > 0)
1346 found_nonzero_hweight = TRUE;
1347 data->col_infos[i].weight += _hweight(child);
1350 if (!found_nonzero_hweight)
1351 max_w = min_w;
1352 else
1353 max_w = MAX(max_w, min_w);
1354 /* D(bug("col %d : min_w=%d max_w=%d\n", i, min_w, max_w)); */
1356 data->col_infos[i].min = min_w;
1357 data->col_infos[i].max = max_w;
1358 data->horiz_weight_sum += data->col_infos[i].weight;
1360 req->MinWidth += min_w;
1361 req->DefWidth += def_w;
1362 req->MaxWidth += max_w;
1363 if (req->MaxWidth > MUI_MAXMAX)
1364 req->MaxWidth = MUI_MAXMAX;
1368 static void
1369 group_minmax_2d(struct IClass *cl, Object *obj,
1370 struct MinList *children, struct MUIP_AskMinMax *msg)
1372 struct MUI_GroupData *data = INST_DATA(cl, obj);
1373 Object *cstate;
1374 Object *child;
1375 struct MUI_MinMax tmp;
1376 WORD maxmin_width;
1377 WORD maxmin_height;
1378 WORD maxdef_width;
1379 WORD maxdef_height;
1381 if (!data->columns)
1383 if (data->num_childs % data->rows)
1385 data->columns = 1;
1386 data->rows = data->num_childs;
1388 else
1389 data->columns = data->num_childs / data->rows;
1391 else
1393 if (data->num_childs % data->columns)
1395 data->rows = 1;
1396 data->columns = data->num_childs;
1398 else
1399 data->rows = data->num_childs / data->columns;
1402 if (data->columns < 1)
1403 data->columns = 1;
1404 if (data->rows < 1)
1405 data->rows = 1;
1407 if (data->row_infos != NULL)
1408 mui_free(data->row_infos);
1410 data->row_infos = mui_alloc(data->rows * sizeof(struct layout2d_elem));
1411 if (NULL == data->row_infos)
1412 return;
1414 if (data->col_infos != NULL)
1415 mui_free(data->col_infos);
1417 data->col_infos = mui_alloc(data->columns * sizeof(struct layout2d_elem));
1418 if (NULL == data->col_infos)
1419 return;
1421 data->horiz_weight_sum = 0;
1422 data->vert_weight_sum = 0;
1424 tmp.MinHeight = tmp.DefHeight = tmp.MaxHeight = (data->rows - 1) * data->vert_spacing;
1425 tmp.MinWidth = tmp.DefWidth = tmp.MaxWidth = (data->columns - 1) * data->horiz_spacing;
1426 /* get minimum dims if same dims for all childs are needed */
1427 maxmin_width = 0;
1428 maxmin_height = 0;
1429 maxdef_width = 0;
1430 maxdef_height = 0;
1432 if ((data->flags & GROUP_SAME_WIDTH) || (data->flags & GROUP_SAME_HEIGHT)) {
1433 cstate = (Object *)children->mlh_Head;
1434 while ((child = NextObject(&cstate))) {
1435 if (! (_flags(child) & MADF_SHOWME))
1436 continue;
1437 maxmin_width = MAX(maxmin_width, _minwidth(child));
1438 maxmin_height = MAX(maxmin_height, _minheight(child));
1439 maxdef_width = MAX(maxdef_width, w0_defwidth(child));
1440 maxdef_height = MAX(maxdef_height, w0_defheight(child));
1442 /* g_print("2d group: mminw=%d mminh=%d\n", maxmin_width, maxmin_height); */
1444 if (data->flags & GROUP_SAME_HEIGHT)
1445 data->samesize_maxmin_vert = maxmin_height;
1446 else
1447 data->samesize_maxmin_vert = 0;
1449 if (data->flags & GROUP_SAME_WIDTH)
1450 data->samesize_maxmin_horiz = maxmin_width;
1451 else
1452 data->samesize_maxmin_horiz = 0;
1454 minmax_2d_rows_pass (data, children, &tmp, maxmin_height, maxdef_height);
1455 minmax_2d_columns_pass (data, children, &tmp, maxmin_width, maxdef_width);
1457 END_MINMAX();
1461 static void
1462 group_minmax_pagemode(struct IClass *cl, Object *obj,
1463 struct MinList *children, struct MUIP_AskMinMax *msg)
1465 Object *cstate;
1466 Object *child;
1467 struct MUI_MinMax tmp = { 0, 0, MUI_MAXMAX, MUI_MAXMAX, 0, 0 };
1469 cstate = (Object *)children->mlh_Head;
1470 /* D(bug("minmax_pagemode(%lx)\n", obj, tmp.DefWidth)); */
1471 while ((child = NextObject(&cstate)))
1473 if (! (_flags(child) & MADF_SHOWME))
1474 continue;
1476 tmp.MinHeight = MAX(tmp.MinHeight, _minheight(child));
1477 D(bug("minmax_pagemode(%p) minh child = %d tmpmin=%d\n", obj, _minheight(child), tmp.MinHeight));
1478 tmp.MinWidth = MAX(tmp.MinWidth, _minwidth(child));
1479 tmp.MaxHeight = MIN(tmp.MaxHeight, w0_maxheight(child));
1480 tmp.MaxWidth = MIN(tmp.MaxWidth, w0_maxwidth(child));
1481 tmp.DefHeight = MAX(tmp.DefHeight,
1482 ((w0_defheight(child) < MUI_MAXMAX) ? w0_defheight(child) : tmp.DefHeight));
1483 tmp.DefWidth = MAX(tmp.DefWidth,
1484 ((w0_defwidth(child) < MUI_MAXMAX) ? w0_defwidth(child) : tmp.DefWidth));
1485 /* D(bug("minmax_pagemode(%lx) defw = %ld\n", obj, tmp.DefWidth)); */
1487 END_MINMAX();
1490 /**************************************************************************
1491 MUIM_AskMinMax : ask childs about min/max sizes, then
1492 either call a hook, or the builtin method, to calculate our minmax
1493 **************************************************************************/
1494 IPTR Group__MUIM_AskMinMax(struct IClass *cl, Object *obj, struct MUIP_AskMinMax *msg)
1496 struct MUI_GroupData *data = INST_DATA(cl, obj);
1497 struct MUI_LayoutMsg lm;
1498 struct MUIP_AskMinMax childMsg;
1499 struct MUI_MinMax childMinMax;
1500 Object *cstate;
1501 Object *child;
1502 LONG super_minwidth,super_minheight;
1505 * let our superclass first fill in its size with frame, inner spc etc ...
1507 DoSuperMethodA(cl, obj, (Msg)msg);
1508 super_minwidth = msg->MinMaxInfo->MinWidth;
1509 super_minheight = msg->MinMaxInfo->MinHeight;
1512 * Ask children
1514 childMsg.MethodID = msg->MethodID;
1515 childMsg.MinMaxInfo = &childMinMax;
1516 get(data->family, MUIA_Family_List, &(lm.lm_Children));
1518 cstate = (Object *)lm.lm_Children->mlh_Head;
1520 while ((child = NextObject(&cstate)))
1522 if (! (_flags(child) & MADF_SHOWME)) /* BORDERGADGETs should handle this itself */
1523 continue;
1524 /* Ask child */
1525 DoMethodA(child, (Msg)&childMsg);
1526 /* D(bug("*** group %lx, child %lx min=%ld,%ld\n", obj, child, childMinMax.MinWidth, childMinMax.MinHeight)); */
1527 __area_finish_minmax(child, childMsg.MinMaxInfo);
1531 * Use childs infos to calculate group size
1533 if (data->flags & GROUP_PAGEMODE)
1535 D(bug("minmax_pagemode(%p) minh initial = %d\n", obj, msg->MinMaxInfo->MinHeight));
1536 group_minmax_pagemode(cl, obj, lm.lm_Children, msg);
1537 D(bug("minmax_pagemode(%p) minh = %d\n", obj, msg->MinMaxInfo->MinHeight));
1539 else if (data->layout_hook)
1541 lm.lm_Type = MUILM_MINMAX;
1542 CallHookPkt(data->layout_hook, obj, &lm);
1544 if (lm.lm_MinMax.MaxHeight < lm.lm_MinMax.MinHeight)
1545 lm.lm_MinMax.MaxHeight = lm.lm_MinMax.MinHeight;
1546 if (lm.lm_MinMax.DefHeight < lm.lm_MinMax.MinHeight)
1547 lm.lm_MinMax.DefHeight = lm.lm_MinMax.MinHeight;
1548 if (lm.lm_MinMax.MaxWidth < lm.lm_MinMax.MinWidth)
1549 lm.lm_MinMax.MaxWidth = lm.lm_MinMax.MinWidth;
1550 if (lm.lm_MinMax.DefWidth < lm.lm_MinMax.MinWidth)
1551 lm.lm_MinMax.DefWidth = lm.lm_MinMax.MinWidth;
1553 //kprintf("### min %d x %d def %d x %d max %d x %d\n",
1554 // msg->MinMaxInfo->MinWidth,
1555 // msg->MinMaxInfo->MinHeight,
1556 // msg->MinMaxInfo->DefWidth,
1557 // msg->MinMaxInfo->DefHeight,
1558 // msg->MinMaxInfo->MaxWidth,
1559 // msg->MinMaxInfo->MaxHeight);
1561 msg->MinMaxInfo->MinWidth += lm.lm_MinMax.MinWidth;
1562 msg->MinMaxInfo->MinHeight += lm.lm_MinMax.MinHeight;
1563 msg->MinMaxInfo->MaxWidth += lm.lm_MinMax.MaxWidth;
1564 if (msg->MinMaxInfo->MaxWidth > MUI_MAXMAX)
1565 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
1566 msg->MinMaxInfo->MaxHeight += lm.lm_MinMax.MaxHeight;
1567 if (msg->MinMaxInfo->MaxHeight > MUI_MAXMAX)
1568 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1569 msg->MinMaxInfo->DefWidth += lm.lm_MinMax.DefWidth;
1570 msg->MinMaxInfo->DefHeight += lm.lm_MinMax.DefHeight;
1572 //kprintf("#### min %d x %d def %d x %d max %d x %d\n",
1573 // msg->MinMaxInfo->MinWidth,
1574 // msg->MinMaxInfo->MinHeight,
1575 // msg->MinMaxInfo->DefWidth,
1576 // msg->MinMaxInfo->DefHeight,
1577 // msg->MinMaxInfo->MaxWidth,
1578 // msg->MinMaxInfo->MaxHeight);
1581 else
1583 if ((data->rows == 1) && (data->columns == 1))
1585 data->num_visible_children = Group_GetNumVisibleChildren(data, lm.lm_Children);
1586 if (data->flags & GROUP_HORIZ)
1587 group_minmax_horiz(cl, obj, lm.lm_Children, msg);
1588 else
1589 group_minmax_vert(cl, obj, lm.lm_Children, msg);
1591 else
1593 group_minmax_2d(cl, obj, lm.lm_Children, msg);
1597 if (data->flags & GROUP_VIRTUAL)
1599 data->saved_minwidth = msg->MinMaxInfo->MinWidth;
1600 data->saved_minheight = msg->MinMaxInfo->MinHeight;
1601 msg->MinMaxInfo->MinWidth = super_minwidth + 2;
1602 msg->MinMaxInfo->MinHeight = super_minheight + 2;
1604 //kprintf("## min %d x %d def %d x %d max %d x %d\n",
1605 // msg->MinMaxInfo->MinWidth,
1606 // msg->MinMaxInfo->MinHeight,
1607 // msg->MinMaxInfo->DefWidth,
1608 // msg->MinMaxInfo->DefHeight,
1609 // msg->MinMaxInfo->MaxWidth,
1610 // msg->MinMaxInfo->MaxHeight);
1613 return 0;
1618 // enforce minmax constraint, but also update total growable/shrinkable weights
1619 // while we're at it
1620 static void Layout1D_minmax_constraint (
1621 WORD *sizep, WORD minsize, WORD maxsize, WORD *remainp, WORD *sizegrowp,
1622 WORD *sizeshrinkp, ULONG *weightgrowp, ULONG *weightshrinkp, UWORD weight,
1623 WORD samesize)
1625 WORD size = *sizep, remain = *remainp,
1626 sizegrow = *sizegrowp, sizeshrink = *sizeshrinkp;
1627 ULONG weightgrow = *weightgrowp, weightshrink = *weightshrinkp;
1629 /* D(bug("L1D_minmax_c size=%d min=%d max=%d w=%d ss=%d\n", size, minsize, maxsize, */
1630 /* weight, samesize)); */
1632 if ((samesize > 0) && (weight == 0))
1634 remain += size - samesize;
1635 size = samesize;
1636 sizeshrink -= size;
1637 sizegrow -= size;
1640 if (size <= minsize) // too little
1642 remain += size - minsize;
1643 size = minsize;
1644 sizeshrink -= size;
1645 if (size == maxsize)
1646 sizegrow -= size;
1648 else if (size >= maxsize) // too big
1650 remain += size - maxsize;
1651 size = maxsize;
1652 sizegrow -= size;
1655 if (!((samesize > 0) && (weight == 0)))
1657 if (size < maxsize)
1658 weightgrow += weight;
1659 if (size > minsize)
1660 weightshrink += weight;
1663 *sizep = size; *remainp = remain;
1664 *sizegrowp = sizegrow; *sizeshrinkp = sizeshrink;
1665 *weightgrowp = weightgrow; *weightshrinkp = weightshrink;
1669 // redistribute excess size to growable child, or reduce size of a shrinkable
1670 // child
1671 static void Layout1D_redistribution (
1672 WORD *sizep, WORD minsize, WORD maxsize, WORD *remainp, WORD *sizegrowp,
1673 WORD *sizeshrinkp, ULONG *weightgrowp, ULONG *weightshrinkp, UWORD weight
1676 WORD size = *sizep, remain = *remainp,
1677 sizegrow = *sizegrowp, sizeshrink = *sizeshrinkp;
1678 ULONG weightgrow = *weightgrowp, weightshrink = *weightshrinkp;
1680 if (weight == 0)
1681 return;
1683 if ((remain > 0) && (size < maxsize))
1685 LONG newsize;
1687 newsize = (sizegrow * weight + weightgrow / 2) / weightgrow;
1689 /* D(bug("newsize=%ld == size_growa=%ld * w=%ld / weight_grow=%d\n", */
1690 /* newsize, sizegrow, weight, weightgrow)); */
1692 /* take care of off-by-1 errors that may toggle remainder sign
1693 * by ensuring convergence to 0
1695 if (remain - newsize + size < 0)
1697 /* D(bug("adding remainder=%d => size = %d\n", */
1698 /* remain, size + remain)); */
1699 size += remain;
1700 remain = 0;
1702 else
1704 remain -= newsize - size;
1705 size = newsize;
1706 sizegrow -= size;
1707 weightgrow -= weight;
1710 else if ((remain < 0) && (size > minsize))
1712 LONG newsize;
1714 newsize = (sizeshrink * weight + weightshrink / 2) / weightshrink;
1716 /* D(bug("newsize=%ld == size_shrinkables=%ld * w=%ld / weight_shrinkables=%d\n", */
1717 /* newsize, sizeshrink, weight, weightshrink)); */
1719 if (remain - newsize + size > 0)
1721 /* D(bug("adding remainder=%d => size = %d\n", */
1722 /* remain, size + remain)); */
1723 size += remain;
1724 remain = 0;
1726 else
1728 remain -= newsize - size;
1729 size = newsize;
1730 sizeshrink -= size;
1731 weightshrink -= weight;
1735 *sizep = size; *remainp = remain;
1736 *sizegrowp = sizegrow; *sizeshrinkp = sizeshrink;
1737 *weightgrowp = weightgrow; *weightshrinkp = weightshrink;
1741 // 2 passes at most, less on average (0.5 or 1.5), each does
1742 // - a minmax clamping, evenutally adding to a remainder
1743 // (remainder = missing (underflow) or remaining (overflow) space compared
1744 // to ideal sizes where childs fill the whole group)
1745 // - a redistribution of the remainder, by growing (pos. remainder) or
1746 // shrinking (neg. remainder) childs able to support it.
1748 // Occasionnaly the first time the redistribution is done, the minmax
1749 // constraint can be broken, thus the extra pass to check and eventually
1750 // redistribute. The second redistribution never breaks minmax constraint
1751 // (there should be a mathematical proof, but feel free to prove me wrong
1752 // with an example)
1753 static void Layout1D_minmax_constraints_and_redistrib (
1754 struct MinList *children,
1755 WORD total_size,
1756 WORD remainder,
1757 WORD samesize,
1758 BOOL group_horiz
1761 Object *cstate;
1762 Object *child;
1763 int i;
1765 for (i = 0; i < 2; i++)
1767 WORD size_growables = total_size;
1768 WORD size_shrinkables = total_size;
1769 ULONG weight_growables = 0;
1770 ULONG weight_shrinkables = 0;
1772 /* D(bug("start : rem=%ld, A=%ld, size_growables=%ld, size_shrinkables=%ld\n", */
1773 /* remainder, total_size, size_growables, size_shrinkables)); */
1775 // minmax constraints
1776 cstate = (Object *)children->mlh_Head;
1777 while ((child = NextObject(&cstate)))
1779 WORD old_size;
1781 if (IS_HIDDEN(child))
1782 continue;
1784 if (group_horiz)
1786 old_size = _width(child);
1788 Layout1D_minmax_constraint(
1789 &_width(child), _minwidth(child), _maxwidth(child),
1790 &remainder,
1791 &size_growables, &size_shrinkables,
1792 &weight_growables, &weight_shrinkables,
1793 _hweight(child), samesize);
1795 /* D(bug("loop1 on %p : width=%d was %d, rem=%d, A=%d, " */
1796 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
1797 /* child, _width(child), old_size, remainder, total_size, */
1798 /* size_growables, size_shrinkables, _hweight(child), */
1799 /* _minwidth(child), _maxwidth(child))); */
1801 else // ! group_horiz
1803 old_size = _height(child);
1805 Layout1D_minmax_constraint(
1806 &_height(child), _minheight(child), _maxheight(child),
1807 &remainder,
1808 &size_growables, &size_shrinkables,
1809 &weight_growables, &weight_shrinkables,
1810 _vweight(child), samesize);
1812 /* D(bug("loop1 on %p : h=%ld was %d, rem=%d, A=%d, " */
1813 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
1814 /* child, _height(child), old_size, remainder, total_size, */
1815 /* size_growables, size_shrinkables, _vweight(child), */
1816 /* _minheight(child), _maxheight(child))); */
1817 } // if (group_horiz)
1818 } // while child, minmax constraints
1820 // mid-pass break
1821 if (remainder == 0)
1822 break;
1824 /* D(bug("mid : rem=%d, A=%d, size_grow=%d, size_shrink=%d, " */
1825 /* "wg=%ld, ws=%ld\n", remainder, total_size, size_growables, */
1826 /* size_shrinkables, weight_growables, weight_shrinkables)); */
1828 // distribute remaining space to possible candidates
1829 cstate = (Object *)children->mlh_Head;
1830 while (((child = NextObject(&cstate)) != NULL) && (remainder != 0))
1832 WORD old_size;
1834 if (IS_HIDDEN(child))
1835 continue;
1837 if (group_horiz)
1839 old_size = _width(child);
1841 Layout1D_redistribution(
1842 &_width(child), _minwidth(child), _maxwidth(child),
1843 &remainder,
1844 &size_growables, &size_shrinkables,
1845 &weight_growables, &weight_shrinkables,
1846 _hweight(child));
1848 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
1849 /* "size_grow=%d, size_shrink=%d\n", child, */
1850 /* _width(child), old_size, remainder, total_size, */
1851 /* size_growables, size_shrinkables)); */
1853 else // ! group_horiz
1855 old_size = _height(child);
1857 Layout1D_redistribution(
1858 &_height(child), _minheight(child), _maxheight(child),
1859 &remainder,
1860 &size_growables, &size_shrinkables,
1861 &weight_growables, &weight_shrinkables,
1862 _vweight(child));
1864 /* D(bug("loop2 on %p : h=%d was %d, rem=%d, A=%d, " */
1865 /* "size_grow=%d, size_shrink=%d\n", child, */
1866 /* _height(child), old_size, remainder, total_size, */
1867 /* size_growables, size_shrinkables)); */
1868 } // if (group_horiz)
1870 } // while child, redistribution
1872 /* if (remainder != 0) */
1873 /* { */
1874 /* D(bug("end : rem=%ld, A=%ld, size_grow=%ld, size_shrink=%ld\n", */
1875 /* remainder, total_size, size_growables, size_shrinkables)); */
1876 /* } */
1877 // dont break here if remainder == 0, some minmax constraints
1878 // may not be respected
1879 } // end for
1881 // to easily spot layout bugs, nothing like a (division by zero) exception
1882 /* if (remainder != 0) */
1883 /* { */
1884 /* ASSERT(remainder != 0); */
1885 /* D(bug("gonna crash, remainder = %d\n", remainder)); */
1886 /* remainder /= 0; */
1887 /* } */
1891 static void Layout1D_weight_constraint (
1892 WORD *total_sizep,
1893 WORD *total_init_sizep,
1894 ULONG *total_weightp,
1895 WORD *sizep,
1896 UWORD weight,
1897 WORD minsize
1900 if (*total_weightp > 0)
1901 *sizep = (*total_sizep * weight + *total_weightp / 2)
1902 / *total_weightp;
1903 else
1904 *sizep = minsize;
1906 *total_weightp -= weight;
1907 *total_sizep -= *sizep;
1908 *total_init_sizep += *sizep;
1912 static void group_layout_vert(struct IClass *cl, Object *obj, struct MinList *children)
1914 struct MUI_GroupData *data = INST_DATA(cl, obj);
1915 Object *cstate;
1916 Object *child;
1917 ULONG total_weight;
1918 WORD remainder; /* must converge to 0 to succesfully end layout */
1919 WORD total_size;
1920 WORD total_size_backup;
1921 WORD total_init_size; /* total size of the ideally sized childs */
1922 WORD width;
1923 WORD left = 0;
1924 WORD top = 0;
1925 WORD layout_width;
1926 WORD layout_height;
1928 //kprintf("group_layout_vert: virtoff = %d,%d\n", data->virt_offx, data->virt_offy);
1930 if (data->flags & GROUP_VIRTUAL)
1932 data->virt_mwidth = CLAMP(_mwidth(obj), data->saved_minwidth - _subwidth(obj), _maxwidth(obj) - _subwidth(obj));
1933 data->virt_mheight = CLAMP(_mheight(obj), data->saved_minheight - _subheight(obj), _maxheight(obj) - _subheight(obj));
1935 layout_width = data->virt_mwidth;
1936 layout_height = data->virt_mheight;
1938 else
1940 layout_width = _mwidth(obj);
1941 layout_height = _mheight(obj);
1944 total_weight = data->vert_weight_sum;
1945 total_init_size = 0;
1946 total_size = layout_height - (data->num_visible_children - 1) * data->vert_spacing;
1947 total_size_backup = total_size;
1949 /* D(bug("\nvert layout for %p, A=%d W=%ld\n", obj, total_size, total_weight)); */
1951 // weight constraints
1952 // calculate ideal size for each object, and total ideal size
1953 cstate = (Object *)children->mlh_Head;
1954 while ((child = NextObject(&cstate)))
1956 if (IS_HIDDEN(child))
1957 continue;
1959 Layout1D_weight_constraint(
1960 &total_size, &total_init_size, &total_weight,
1961 &_height(child), _vweight(child), _minheight(child));
1962 /* D(bug("child %p : ideal=%d w=%ld\n", */
1963 /* child, _height(child), _vweight(child))); */
1964 } // while child, weight constraints
1966 total_size = total_size_backup;
1967 remainder = total_size - total_init_size;
1969 if (data->flags & GROUP_VIRTUAL)
1971 /* This is also true for non virtual groups, but if this would be the case
1972 ** then there is a bug in the layout function
1974 if (total_size < 0) total_size = 0;
1977 Layout1D_minmax_constraints_and_redistrib (
1978 children,
1979 total_size,
1980 remainder,
1981 (data->flags & GROUP_SAME_HEIGHT) ? data->samesize_maxmin_vert : 0,
1982 FALSE);
1984 // do the layout
1985 cstate = (Object *)children->mlh_Head;
1986 while ((child = NextObject(&cstate)))
1988 if (IS_HIDDEN(child))
1989 continue;
1991 width = MIN(_maxwidth(child), layout_width);
1992 width = MAX(width, _minwidth(child));
1993 left = (layout_width - width) / 2;
1995 /* D(bug("child %p -> layout %d x %d\n", child, width, _height(child))); */
1996 if (!MUI_Layout(child, left, top, width, _height(child), 0))
1997 return;
1998 top += data->vert_spacing + _height(child);
2004 static void group_layout_horiz(struct IClass *cl, Object *obj, struct MinList *children)
2006 struct MUI_GroupData *data = INST_DATA(cl, obj);
2007 Object *cstate;
2008 Object *child;
2009 ULONG total_weight;
2010 WORD remainder; /* must converge to 0 to succesfully end layout */
2011 WORD total_size;
2012 WORD total_size_backup;
2013 WORD total_init_size; /* total size of the ideally sized childs */
2014 WORD height;
2015 WORD top = 0;
2016 WORD left = 0;
2017 WORD layout_width;
2018 WORD layout_height;
2020 //kprintf("group_layout_horiz: virtoff = %d,%d\n", data->virt_offx, data->virt_offy);
2022 if (data->flags & GROUP_VIRTUAL)
2024 data->virt_mwidth = CLAMP(_mwidth(obj), data->saved_minwidth - _subwidth(obj), _maxwidth(obj) - _subwidth(obj));
2025 data->virt_mheight = CLAMP(_mheight(obj), data->saved_minheight - _subheight(obj), _maxheight(obj) - _subheight(obj));
2027 layout_width = data->virt_mwidth;
2028 layout_height = data->virt_mheight;
2030 //kprintf("group_layout_horiz: layoutsize %d x %d virtsize %d x %d msize %d x %d\n",
2031 // layout_width, layout_height, data->virt_mwidth, data->virt_mheight,
2032 // _mwidth(obj), _mheight(obj));
2035 else
2037 layout_width = _mwidth(obj);
2038 layout_height = _mheight(obj);
2041 total_weight = data->horiz_weight_sum;
2042 total_init_size = 0;
2043 total_size = layout_width - (data->num_visible_children - 1) * data->horiz_spacing;
2044 total_size_backup = total_size;
2046 /* D(bug("\nhoriz layout for %p, A=%d W=%ld\n", obj, total_size, total_weight)); */
2048 // weight constraints
2049 // calculate ideal size for each object, and total ideal size
2050 cstate = (Object *)children->mlh_Head;
2051 while ((child = NextObject(&cstate)))
2053 if (IS_HIDDEN(child))
2054 continue;
2056 Layout1D_weight_constraint(
2057 &total_size, &total_init_size, &total_weight,
2058 &_width(child), _hweight(child), _minwidth(child));
2059 /* D(bug("child %p : ideal=%d w=%ld\n", */
2060 /* child, _width(child), _hweight(child))); */
2061 } // while child, weight constraints
2063 total_size = total_size_backup;
2064 if (data->horiz_weight_sum > 0)
2065 remainder = total_size - total_init_size;
2066 else
2067 remainder = 0;
2069 if (data->flags & GROUP_VIRTUAL)
2071 /* This is also true for non virtual groups, but if this would be the case
2072 ** then there is a bug in the layout function
2074 if (total_size < 0) total_size = 0;
2077 Layout1D_minmax_constraints_and_redistrib (
2078 children,
2079 total_size,
2080 remainder,
2081 (data->flags & GROUP_SAME_WIDTH) ? data->samesize_maxmin_horiz : 0,
2082 TRUE);
2084 // do the layout
2085 cstate = (Object *)children->mlh_Head;
2086 while ((child = NextObject(&cstate)))
2088 if (IS_HIDDEN(child))
2089 continue;
2091 height = MIN(_maxheight(child), layout_height);
2092 height = MAX(height, _minheight(child));
2093 top = (layout_height - height) / 2;
2095 /* D(bug("child %p -> layout %d x %d\n", child, _width(child), height)); */
2096 if (!MUI_Layout(child, left, top, _width(child), height, 0))
2097 return;
2098 left += data->horiz_spacing + _width(child);
2104 static void Layout2D_weight_constraint (
2105 struct MUI_GroupData *data,
2106 struct layout2d_elem *row_infos,
2107 struct layout2d_elem *col_infos,
2108 WORD total_size_height, WORD total_size_width,
2109 WORD *total_init_height, WORD *total_init_width)
2111 int i;
2112 ULONG total_weight_vert = data->vert_weight_sum;
2113 ULONG total_weight_horiz = data->horiz_weight_sum;
2115 *total_init_height = 0;
2116 *total_init_width = 0;
2118 /* calc row heights */
2119 for (i = 0; i < data->rows; i++)
2121 if (total_weight_vert > 0)
2122 row_infos[i].dim = (total_size_height * row_infos[i].weight + total_weight_vert / 2)
2123 / total_weight_vert;
2124 else
2125 row_infos[i].dim = row_infos[i].min;
2127 /* D(bug("l2 row %d : ideal = %d with w=%d, A=%d, W=%d\n", i, row_infos[i].dim, */
2128 /* row_infos[i].weight, total_size_height, total_weight_vert)); */
2130 total_weight_vert -= row_infos[i].weight;
2131 total_size_height -= row_infos[i].dim;
2132 *total_init_height += row_infos[i].dim;
2135 /* calc columns widths */
2136 for (i = 0; i < data->columns; i++)
2138 if (total_weight_horiz)
2139 col_infos[i].dim = (total_size_width * col_infos[i].weight + total_weight_horiz / 2 )
2140 / total_weight_horiz;
2141 else
2142 col_infos[i].dim = col_infos[i].min;
2144 /* D(bug("l2 col %d : ideal = %d with w=%d, A=%d, W=%d\n", i, col_infos[i].dim, */
2145 /* col_infos[i].weight, total_size_width, total_weight_horiz)); */
2147 total_weight_horiz -= col_infos[i].weight;
2148 total_size_width -= col_infos[i].dim;
2149 *total_init_width += col_infos[i].dim;
2155 static void Layout2D_minmax_constraints_and_redistrib (
2156 struct layout2d_elem *infos,
2157 WORD nitems,
2158 WORD total_size,
2159 WORD samesize,
2160 WORD remainder)
2162 int j;
2164 /* D(bug("L2D mc&r n=%d A=%d ss=%d rem=%d\n", nitems, total_size, samesize, remainder)); */
2166 for (j = 0; j < 2; j++)
2168 WORD size_growables = total_size;
2169 WORD size_shrinkables = total_size;
2170 ULONG weight_growables = 0;
2171 ULONG weight_shrinkables = 0;
2172 WORD old_size;
2173 int i;
2175 // minmax constraints
2176 for (i = 0; i < nitems; i++)
2178 old_size = infos[i].dim;
2180 /* D(bug("bef loop1 on %d : size=%d, rem=%d, A=%d, " */
2181 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2182 /* i, infos[i].dim, remainder, total_size, */
2183 /* size_growables, size_shrinkables, infos[i].weight, */
2184 /* infos[i].min, infos[i].max)); */
2186 Layout1D_minmax_constraint(
2187 &infos[i].dim, infos[i].min, infos[i].max,
2188 &remainder,
2189 &size_growables, &size_shrinkables,
2190 &weight_growables, &weight_shrinkables,
2191 infos[i].weight,
2192 samesize
2195 /* D(bug("loop1 on %d : size=%d was %d, rem=%d, A=%d, " */
2196 /* "sizegrow=%d, sizeshrink=%d w=%d min=%d max=%d\n", */
2197 /* i, infos[i].dim, old_size, remainder, total_size, */
2198 /* size_growables, size_shrinkables, infos[i].weight, */
2199 /* infos[i].min, infos[i].max)); */
2202 if (remainder == 0)
2203 break;
2205 for (i = 0; i < nitems; i++)
2207 old_size = infos[i].dim;
2209 /* D(bug("bef loop2 on %d : size=%d, rem=%d, A=%d, " */
2210 /* "size_grow=%d, size_shrink=%d\n", i, */
2211 /* infos[i].dim, remainder, total_size, */
2212 /* size_growables, size_shrinkables)); */
2214 Layout1D_redistribution(
2215 &infos[i].dim, infos[i].min, infos[i].max,
2216 &remainder,
2217 &size_growables, &size_shrinkables,
2218 &weight_growables, &weight_shrinkables,
2219 infos[i].weight);
2221 /* D(bug("loop2 on %d : size=%d was %d, rem=%d, A=%d, " */
2222 /* "size_grow=%d, size_shrink=%d\n", i, */
2223 /* infos[i].dim, old_size, remainder, total_size, */
2224 /* size_growables, size_shrinkables)); */
2229 static void
2230 layout_2d_distribute_space (struct MUI_GroupData *data,
2231 struct layout2d_elem *row_infos,
2232 struct layout2d_elem *col_infos,
2233 struct MinList *children,
2234 LONG left_start, LONG top_start)
2236 Object *cstate;
2237 Object *child;
2238 LONG left;
2239 LONG top;
2240 LONG col_width;
2241 LONG row_height;
2242 int i, j;
2245 * pass 2 : distribute space
2247 cstate = (Object *)children->mlh_Head;
2248 top = top_start;
2249 /* for each row */
2250 for (i = 0; i < data->rows; i++)
2252 /* left start for child layout in this row */
2253 left = left_start;
2255 /* max height for childs in this row */
2256 row_height = row_infos[i].dim;
2257 j = 0;
2258 /* for each column */
2259 while ((child = NextObject(&cstate)))
2261 LONG cleft;
2262 LONG ctop;
2263 LONG cwidth;
2264 LONG cheight;
2266 if (IS_HIDDEN(child))
2267 continue;
2268 /* max width for childs in this column */
2269 col_width = col_infos[j].dim;
2271 /* center child if col width is bigger than child maxwidth */
2272 cwidth = MIN(_maxwidth(child), col_width);
2273 cwidth = MAX(cwidth, _minwidth(child));
2274 cleft = left + (col_width - cwidth) / 2;
2276 /* center child if row height is bigger than child maxheight */
2277 cheight = MIN(_maxheight(child), row_height);
2278 cheight = MAX(cheight, _minheight(child));
2279 ctop = top + (row_height - cheight) / 2;
2281 /* g_print("layout %d %d %d %d\n", cleft, ctop, cwidth, cheight); */
2282 /* D(bug("2DL/child %p -> layout %d x %d\n", child, cwidth, cheight)); */
2283 if (!MUI_Layout(child, cleft, ctop, cwidth, cheight, 0))
2284 return;
2286 left += data->horiz_spacing + col_width;
2288 ++j;
2289 if ((j % data->columns) == 0)
2290 break;
2293 top += data->vert_spacing + row_height;
2300 * all childs in the same row have the same maximum height
2301 * all childs in the same column have the same maximum height
2302 * if a child maximum size is smaller than the biggest minimum size,
2303 * the chid will be centered in the remaining space.
2305 * for each row, determine its height allocation
2306 * weight ? the vertical weight of a row, if no fixed-height child
2307 * in the row, is the sum of all vertical weights of childs
2308 * all row members will have the same height
2310 * for each column, determine its width allocation
2311 * all column members will have the same width
2313 /* Write a proper hook function */
2314 static void
2315 group_layout_2d(struct IClass *cl, Object *obj, struct MinList *children)
2317 struct MUI_GroupData *data = INST_DATA(cl, obj);
2318 WORD left_start = 0;
2319 WORD top_start = 0;
2320 WORD total_size_height = _mheight(obj) - (data->rows - 1) * data->vert_spacing;
2321 WORD total_size_width = _mwidth(obj) - (data->columns - 1) * data->horiz_spacing;
2322 WORD total_init_height;
2323 WORD total_init_width;
2324 WORD remainder_height;
2325 WORD remainder_width;
2326 WORD layout_width;
2327 WORD layout_height;
2329 if (data->rows == 0 || data->columns == 0)
2330 return;
2331 if (data->num_childs % data->rows || data->num_childs % data->columns)
2332 return;
2333 if (data->row_infos == NULL || data->col_infos == NULL)
2334 return;
2336 //kprintf("group_layout_horiz: virtoff = %d,%d\n", data->virt_offx, data->virt_offy);
2338 if (data->flags & GROUP_VIRTUAL)
2340 data->virt_mwidth = CLAMP(_mwidth(obj), data->saved_minwidth - _subwidth(obj), _maxwidth(obj) - _subwidth(obj));
2341 data->virt_mheight = CLAMP(_mheight(obj), data->saved_minheight - _subheight(obj), _maxheight(obj) - _subheight(obj));
2343 layout_width = data->virt_mwidth;
2344 layout_height = data->virt_mheight;
2346 else
2348 layout_width = _mwidth(obj);
2349 layout_height = _mheight(obj);
2352 total_size_height = layout_height - (data->rows - 1) * data->vert_spacing;
2353 total_size_width = layout_width - (data->columns - 1) * data->horiz_spacing;
2355 // fix left/top ?
2357 // weight constraints
2358 Layout2D_weight_constraint (
2359 data, data->row_infos, data->col_infos,
2360 total_size_height, total_size_width,
2361 &total_init_height, &total_init_width);
2363 remainder_height = total_size_height - total_init_height;
2364 remainder_width = total_size_width - total_init_width;
2366 Layout2D_minmax_constraints_and_redistrib(
2367 data->row_infos,
2368 data->rows,
2369 total_size_height,
2370 /* (data->flags & GROUP_SAME_HEIGHT) ? data->samesize_maxmin_vert : 0, */
2372 remainder_height);
2374 Layout2D_minmax_constraints_and_redistrib(
2375 data->col_infos,
2376 data->columns,
2377 total_size_width,
2378 /* (data->flags & GROUP_SAME_WIDTH) ? data->samesize_maxmin_horiz : 0, */
2380 remainder_width);
2382 layout_2d_distribute_space (data, data->row_infos, data->col_infos,
2383 children, left_start, top_start);
2387 /* Write a proper hook function */
2388 static void group_layout_pagemode (struct IClass *cl, Object *obj, struct MinList *children)
2390 struct MUI_GroupData *data = INST_DATA(cl, obj);
2391 Object *cstate;
2392 Object *child;
2393 WORD layout_width;
2394 WORD layout_height;
2395 int w, h;
2397 if (data->flags & GROUP_VIRTUAL)
2399 data->virt_mwidth = CLAMP(_mwidth(obj), data->saved_minwidth - _subwidth(obj), _maxwidth(obj) - _subwidth(obj));
2400 data->virt_mheight = CLAMP(_mheight(obj), data->saved_minheight - _subheight(obj), _maxheight(obj) - _subheight(obj));
2402 layout_width = data->virt_mwidth;
2403 layout_height = data->virt_mheight;
2405 else
2407 layout_width = _mwidth(obj);
2408 layout_height = _mheight(obj);
2411 cstate = (Object *)children->mlh_Head;
2412 while ((child = NextObject(&cstate)))
2414 w = MIN(layout_width, _maxwidth(child));
2415 h = MIN(layout_height, _maxheight(child));
2417 /* D(bug("PM/child %p -> layout %d x %d\n", child, w, h)); */
2418 MUI_Layout(child, (layout_width - w) / 2, (layout_height - h) / 2,
2419 w, h, 0);
2424 /**************************************************************************
2425 MUIM_Layout
2426 Either use a given layout hook, or the builtin method.
2427 **************************************************************************/
2428 IPTR Group__MUIM_Layout(struct IClass *cl, Object *obj, struct MUIP_Layout *msg)
2430 struct MUI_GroupData *data = INST_DATA(cl, obj);
2431 struct MUI_LayoutMsg lm;
2433 get(data->family, MUIA_Family_List, &(lm.lm_Children));
2434 if (data->flags & GROUP_PAGEMODE)
2436 group_layout_pagemode(cl, obj, lm.lm_Children);
2438 else if (data->layout_hook)
2440 lm.lm_Type = MUILM_LAYOUT;
2441 lm.lm_Layout.Width = _mwidth(obj);
2442 lm.lm_Layout.Height = _mheight(obj);
2444 CallHookPkt(data->layout_hook, obj, &lm);
2446 if (data->flags & GROUP_VIRTUAL)
2448 data->virt_mwidth = lm.lm_Layout.Width;
2449 data->virt_mheight = lm.lm_Layout.Height;
2452 else
2454 if ((data->rows == 1) && (data->columns == 1))
2456 if (data->flags & GROUP_HORIZ)
2457 group_layout_horiz(cl, obj, lm.lm_Children);
2458 else
2459 group_layout_vert(cl, obj, lm.lm_Children);
2461 else
2462 group_layout_2d(cl, obj, lm.lm_Children);
2465 if (data->flags & GROUP_VIRTUAL)
2467 WORD new_virt_offx, new_virt_offy;
2469 new_virt_offx = data->virt_offx;
2470 new_virt_offy = data->virt_offy;
2472 if (new_virt_offx + _mwidth(obj) > data->virt_mwidth)
2474 new_virt_offx = data->virt_mwidth - _mwidth(obj);
2476 if (new_virt_offx < 0) new_virt_offx = 0;
2478 if (new_virt_offy + _mheight(obj) > data->virt_mheight)
2480 new_virt_offy = data->virt_mheight - _mheight(obj);
2482 if (new_virt_offy < 0) new_virt_offy = 0;
2484 if (new_virt_offx != data->virt_offx)
2486 nfset(obj, MUIA_Virtgroup_Left, new_virt_offx);
2489 if (new_virt_offy != data->virt_offy)
2491 nfset(obj, MUIA_Virtgroup_Top, new_virt_offy);
2496 return 0;
2499 /**************************************************************************
2500 MUIM_Show
2501 **************************************************************************/
2502 IPTR Group__MUIM_Show(struct IClass *cl, Object *obj, struct MUIP_Show *msg)
2504 struct MUI_GroupData *data = INST_DATA(cl, obj);
2505 Object *cstate;
2506 Object *child;
2507 struct MinList *ChildList;
2509 /* If msg is NULL, we won't want that the super method actually gets this call */
2510 if (msg) DoSuperMethodA(cl,obj,(Msg)msg);
2512 get(data->family, MUIA_Family_List, &(ChildList));
2513 cstate = (Object *)ChildList->mlh_Head;
2515 if (data->flags & GROUP_PAGEMODE)
2517 int page = 0;
2518 while ((child = NextObject(&cstate)))
2520 if (page == data->active_page)
2522 DoShowMethod(child);
2523 break;
2525 page++;
2527 } else
2529 while ((child = NextObject(&cstate)))
2531 if (!(data->flags & GROUP_VIRTUAL) ||
2532 IsObjectVisible(child,MUIMasterBase))
2534 if (_flags(child) & MADF_SHOWME)
2535 DoShowMethod(child);
2539 return TRUE;
2542 /**************************************************************************
2543 MUIM_Hide
2544 **************************************************************************/
2545 IPTR Group__MUIM_Hide(struct IClass *cl, Object *obj, struct MUIP_Hide *msg)
2547 struct MUI_GroupData *data = INST_DATA(cl, obj);
2548 Object *cstate;
2549 Object *child;
2550 struct MinList *ChildList;
2552 get(data->family, MUIA_Family_List, &(ChildList));
2553 cstate = (Object *)ChildList->mlh_Head;
2555 if (data->flags & GROUP_PAGEMODE)
2557 int page = 0;
2558 while ((child = NextObject(&cstate)))
2560 if (page == data->active_page)
2562 DoHideMethod(child);
2563 break;
2565 page++;
2567 } else
2569 while ((child = NextObject(&cstate)))
2571 if (_flags(child) & MADF_CANDRAW)
2572 DoHideMethod(child);
2576 /* If msg is NULL, we won't want that the super method actually gets this call */
2577 if (msg) return DoSuperMethodA(cl,obj,(Msg)msg);
2578 return 1;
2582 * MUIM_FindUData : tests if the MUIA_UserData of the object
2583 * contains the given <udata> and returns the object pointer in this case.
2585 IPTR Group__MUIM_FindUData(struct IClass *cl, Object *obj, struct MUIP_FindUData *msg)
2587 struct MUI_GroupData *data = INST_DATA(cl, obj);
2589 if (muiNotifyData(obj)->mnd_UserData == msg->udata)
2590 return (IPTR)obj;
2592 return DoMethodA(data->family, (Msg)msg);
2597 * MUIM_GetUData : This method tests if the MUIA_UserData of the object
2598 * contains the given <udata> and gets <attr> to <storage> for itself
2599 * in this case.
2601 IPTR Group__MUIM_GetUData(struct IClass *cl, Object *obj, struct MUIP_GetUData *msg)
2603 struct MUI_GroupData *data = INST_DATA(cl, obj);
2605 if (muiNotifyData(obj)->mnd_UserData == msg->udata)
2607 get(obj, msg->attr, msg->storage);
2608 return TRUE;
2611 return DoMethodA(data->family, (Msg)msg);
2616 * MUIM_SetUData : This method tests if the MUIA_UserData of the object
2617 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2619 IPTR Group__MUIM_SetUData(struct IClass *cl, Object *obj, struct MUIP_SetUData *msg)
2621 struct MUI_GroupData *data = INST_DATA(cl, obj);
2623 if (muiNotifyData(obj)->mnd_UserData == msg->udata)
2624 set(obj, msg->attr, msg->val);
2626 DoMethodA(data->family, (Msg)msg);
2627 return TRUE;
2632 * MUIM_SetUDataOnce : This method tests if the MUIA_UserData of the object
2633 * contains the given <udata> and sets <attr> to <val> for itself in this case.
2634 * Stop after the first udata found.
2636 IPTR Group__MUIM_SetUDataOnce(struct IClass *cl, Object *obj, struct MUIP_SetUData *msg)
2638 struct MUI_GroupData *data = INST_DATA(cl, obj);
2640 if (muiNotifyData(obj)->mnd_UserData == msg->udata)
2642 set(obj, msg->attr, msg->val);
2643 return TRUE;
2645 return DoMethodA(data->family, (Msg)msg);
2648 /**************************************************************************
2649 MUIM_DragQueryExtented
2650 **************************************************************************/
2651 IPTR Group__MUIM_DragQueryExtended(struct IClass *cl, Object *obj, struct MUIP_DragQueryExtended *msg)
2653 struct MUI_GroupData *data = INST_DATA(cl, obj);
2654 Object *cstate;
2655 Object *child;
2656 Object *found_obj;
2657 struct MinList *ChildList;
2659 get(data->family, MUIA_Family_List, &(ChildList));
2660 cstate = (Object *)ChildList->mlh_Head;
2661 while ((child = NextObject(&cstate)))
2663 if (! (_flags(child) & MADF_CANDRAW))
2664 continue;
2666 if ((found_obj = (Object*)DoMethodA(child, (Msg)msg)))
2667 return (IPTR)found_obj;
2669 return DoSuperMethodA(cl,obj,(Msg)msg);
2672 /**************************************************************************
2673 MUIM_HandleEvent
2674 **************************************************************************/
2675 IPTR Group__MUIM_HandleEvent(struct IClass *cl, Object *obj, struct MUIP_HandleEvent *msg)
2677 struct MUI_GroupData *data = INST_DATA(cl, obj);
2679 /* check this, otherwise a superclass who has IDCMP_MOUSEBUTTONS
2680 eventhandler might call DoSuperMethod, and this function gets
2681 called even when he have not added any eventhandler */
2683 if ((data->flags & GROUP_VIRTUAL) && msg->imsg)
2685 switch (msg->imsg->Class)
2687 case IDCMP_MOUSEBUTTONS:
2688 /* For virtual groups */
2689 if (msg->imsg->Code == SELECTDOWN)
2691 if (_between(_mleft(obj),msg->imsg->MouseX,_mright(obj)) && _between(_mtop(obj),msg->imsg->MouseY,_mbottom(obj)))
2693 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
2694 data->ehn.ehn_Events |= IDCMP_INTUITICKS;
2695 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
2697 } else
2699 if (data->ehn.ehn_Events & IDCMP_INTUITICKS)
2701 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR)&data->ehn);
2702 data->ehn.ehn_Events &= ~IDCMP_INTUITICKS;
2703 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR)&data->ehn);
2706 break;
2708 case IDCMP_INTUITICKS:
2709 if (!(data->ehn.ehn_Events & IDCMP_INTUITICKS)) break;
2711 if (!(_between(_mleft(obj),msg->imsg->MouseX,_mright(obj)) && _between(_mtop(obj),msg->imsg->MouseY,_mbottom(obj))))
2713 LONG new_virt_offx = data->virt_offx;
2714 LONG new_virt_offy = data->virt_offy;
2716 if (msg->imsg->MouseX < _mleft(obj))
2718 /* scroll left */
2719 if (new_virt_offx >= 4) new_virt_offx -= 4;
2720 else new_virt_offx = 0;
2722 else if (msg->imsg->MouseX > _mright(obj))
2724 /* scroll right */
2725 new_virt_offx += 4;
2726 if (new_virt_offx > data->virt_mwidth - _mwidth(obj)) new_virt_offx = data->virt_mwidth - _mwidth(obj);
2727 if (new_virt_offx < 0) new_virt_offx = 0;
2730 if (msg->imsg->MouseY < _mtop(obj))
2732 /* scroll top */
2733 if (new_virt_offy >= 4) new_virt_offy -= 4;
2734 else new_virt_offy = 0;
2736 else if (msg->imsg->MouseY > _mbottom(obj))
2738 /* scroll bottom */
2739 new_virt_offy += 4;
2740 if (new_virt_offy > data->virt_mheight - _mheight(obj)) new_virt_offy = data->virt_mheight - _mheight(obj);
2741 if (new_virt_offy < 0) new_virt_offy = 0;
2744 if (new_virt_offx != data->virt_offx || new_virt_offy != data->virt_offy)
2746 SetAttrs(obj,
2747 MUIA_Virtgroup_Left, new_virt_offx,
2748 MUIA_Virtgroup_Top, new_virt_offy,
2749 MUIA_Group_Forward, FALSE,
2750 TAG_DONE);
2753 break;
2757 return 0;
2760 /**************************************************************************
2761 MUIM_DrawBackground
2762 **************************************************************************/
2763 IPTR Group__MUIM_DrawBackground(struct IClass *cl, Object *obj, struct MUIP_DrawBackground *msg)
2765 struct MUI_GroupData *data = INST_DATA(cl, obj);
2767 if (data->flags & GROUP_VIRTUAL)
2769 struct MUIP_DrawBackground msg2 = *msg;
2771 msg2.xoffset += data->virt_offx;
2772 msg2.yoffset += data->virt_offy;
2774 return DoSuperMethodA(cl, obj, (Msg)&msg2);
2777 return DoSuperMethodA(cl, obj, (Msg)msg);
2780 /**************************************************************************
2781 MUIM_FindAreaObject
2782 Find the given object or return NULL
2783 **************************************************************************/
2784 IPTR Group__MUIM_FindAreaObject(struct IClass *cl, Object *obj,
2785 struct MUIP_FindAreaObject *msg)
2787 struct MUI_GroupData *data = INST_DATA(cl, obj);
2788 Object *cstate;
2789 Object *child;
2790 struct MinList *ChildList;
2792 // it's me ?
2793 if (msg->obj == obj)
2794 return (IPTR)obj;
2796 // it's one of my childs ?
2797 get(data->family, MUIA_Family_List, &(ChildList));
2798 cstate = (Object *)ChildList->mlh_Head;
2799 while ((child = NextObject(&cstate)))
2801 if (msg->obj == child)
2802 return (IPTR)child;
2805 // let the childs find it
2806 get(data->family, MUIA_Family_List, &(ChildList));
2807 cstate = (Object *)ChildList->mlh_Head;
2808 while ((child = NextObject(&cstate)))
2810 Object *res = (Object *)DoMethodA(child, (Msg)msg);
2811 if (res != NULL)
2812 return (IPTR)res;
2815 return (IPTR)NULL;
2818 /**************************************************************************
2819 MUIM_Export : to export an objects "contents" to a dataspace object.
2820 **************************************************************************/
2821 static IPTR Group__MUIM_Export(struct IClass *cl, Object *obj, struct MUIP_Export *msg)
2823 struct MUI_GroupData *data = INST_DATA(cl, obj);
2824 Object *cstate;
2825 Object *child;
2826 struct MinList *ChildList;
2828 get(data->family, MUIA_Family_List, &(ChildList));
2829 cstate = (Object *)ChildList->mlh_Head;
2830 while ((child = NextObject(&cstate)))
2832 DoMethodA(child, (Msg)msg);
2835 return 0;
2839 /**************************************************************************
2840 MUIM_Import : to import an objects "contents" from a dataspace object.
2841 **************************************************************************/
2842 static IPTR Group__MUIM_Import(struct IClass *cl, Object *obj, struct MUIP_Import *msg)
2844 struct MUI_GroupData *data = INST_DATA(cl, obj);
2845 Object *cstate;
2846 Object *child;
2847 struct MinList *ChildList;
2849 get(data->family, MUIA_Family_List, &(ChildList));
2850 cstate = (Object *)ChildList->mlh_Head;
2851 while ((child = NextObject(&cstate)))
2853 DoMethodA(child, (Msg)msg);
2856 return 0;
2859 /**************************************************************************
2860 MUIM_Notify - disabled now because previous Zune versions had a OM_GET
2861 check in MUIM_Notify which is no longer the case
2862 **************************************************************************/
2863 #if 0
2864 STATIC IPTR Group_Notify(struct IClass *cl, Object *obj, struct MUIP_Notify *msg)
2866 struct MUI_GroupData *data = INST_DATA(cl, obj);
2867 Object *cstate;
2868 Object *child;
2869 struct MinList *ChildList;
2871 /* Try at first if understand the message our self
2872 ** We disable the forwarding of the OM_GET message
2873 ** as the MUIM_Notify otherwise would "think" that
2874 ** the group class actually understands the attribute
2875 ** although a child does this only
2877 data->dont_forward_get = 1;
2878 if (DoSuperMethodA(cl,obj,(Msg)msg))
2880 data->dont_forward_get = 0;
2881 return 1;
2884 /* We ourself didn't understand the notify tag so we try the children now */
2885 data->dont_forward_get = 0;
2887 get(data->family, MUIA_Family_List, (IPTR *)&(ChildList));
2888 cstate = (Object *)ChildList->mlh_Head;
2889 while ((child = NextObject(&cstate)))
2891 if (DoMethodA(child, (Msg)msg)) return 1;
2893 return 0;
2895 #endif
2897 #if 1
2898 /* Notes about Group_Notify() and echo notification problem:
2899 It was discovered that MUI seems to have some special handling for group class
2900 which will drop notifications on the children which are found to not
2901 understand the attribute.
2903 This is done by checking if an OM_GET on the child returns TRUE.
2904 There's a little problem here because it is not known how big the storage
2905 needed for the attribute in question will be. Almost no class uses anything
2906 bigger than one IPTR. For "big" attributes those return a pointer to the data,
2907 not the data itself. Unfortuntely there are some exceptions like colorwheel
2908 class which does not return a pointer, but the data itself. So it's not
2909 enough to use one single IPTR variable (4 Bytes on 32bit machines, 8 bytes
2910 on 64 bit machines) to store the result of the test-OM_Get.
2912 There is no general way to query the size needed so if one wants to change
2913 Zune to work like MUI one needs to choose a size which one hopes will be
2914 big enough to hold all possible attributes of all classes, old, present
2915 and future ones.
2917 STATIC IPTR Group_Notify(struct IClass *cl, Object *obj, struct MUIP_Notify *msg)
2919 struct MUI_GroupData *data = INST_DATA(cl, obj);
2920 Object *cstate;
2921 Object *child;
2922 struct MinList *ChildList;
2924 DoSuperMethodA(cl,obj,(Msg)msg);
2925 get(data->family, MUIA_Family_List, &(ChildList));
2926 cstate = (Object *)ChildList->mlh_Head;
2927 while ((child = NextObject(&cstate)))
2929 IPTR attr[30];
2931 if (GetAttr(msg->TrigAttr, child, attr))
2933 DoMethodA(child, (Msg)msg);
2936 return TRUE;
2938 #endif
2940 BOOPSI_DISPATCHER(IPTR, Group_Dispatcher, cl, obj, msg)
2942 switch (msg->MethodID)
2944 case OM_NEW: return Group__OM_NEW(cl, obj, (struct opSet *) msg);
2945 case OM_DISPOSE: return Group__OM_DISPOSE(cl, obj, msg);
2946 case OM_SET: return Group__OM_SET(cl, obj, (struct opSet *)msg);
2947 case OM_GET: return Group__OM_GET(cl, obj, (struct opGet *)msg);
2948 case OM_ADDMEMBER: return Group__OM_ADDMEMBER(cl, obj, (APTR)msg);
2949 case OM_REMMEMBER: return Group__OM_REMMEMBER(cl, obj, (APTR)msg);
2950 case MUIM_AskMinMax: return Group__MUIM_AskMinMax(cl, obj, (APTR)msg);
2951 case MUIM_Group_ExitChange: return Group__MUIM_ExitChange(cl, obj, (APTR)msg);
2952 case MUIM_Group_InitChange: return Group__MUIM_InitChange(cl, obj, (APTR)msg);
2953 case MUIM_Group_Sort: return Group__MUIM_Sort(cl, obj, (APTR)msg);
2954 case MUIM_Group_DoMethodNoForward: return Group__MUIM_DoMethodNoForward(cl, obj, (APTR)msg);
2955 case MUIM_ConnectParent: return Group__MUIM_ConnectParent(cl, obj, (APTR)msg);
2956 case MUIM_DisconnectParent: return Group__MUIM_DisconnectParent(cl, obj, (APTR)msg);
2957 case MUIM_Layout: return Group__MUIM_Layout(cl, obj, (APTR)msg);
2958 case MUIM_Setup: return Group__MUIM_Setup(cl, obj, (APTR)msg);
2959 case MUIM_Cleanup: return Group__MUIM_Cleanup(cl, obj, (APTR)msg);
2960 case MUIM_Draw: return Group__MUIM_Draw(cl, obj, (APTR)msg);
2962 case MUIM_FindUData: return Group__MUIM_FindUData(cl, obj, (APTR)msg);
2963 case MUIM_GetUData: return Group__MUIM_GetUData(cl, obj, (APTR)msg);
2964 case MUIM_SetUData: return Group__MUIM_SetUData(cl, obj, (APTR)msg);
2965 case MUIM_SetUDataOnce: return Group__MUIM_SetUDataOnce(cl, obj, (APTR)msg);
2966 case MUIM_Show: return Group__MUIM_Show(cl, obj, (APTR)msg);
2967 case MUIM_Hide: return Group__MUIM_Hide(cl, obj, (APTR)msg);
2968 case MUIM_HandleEvent: return Group__MUIM_HandleEvent(cl,obj, (APTR)msg);
2969 case MUIM_DrawBackground: return Group__MUIM_DrawBackground(cl, obj, (APTR)msg);
2970 case MUIM_DragQueryExtended:return Group__MUIM_DragQueryExtended(cl, obj, (APTR)msg);
2971 case MUIM_FindAreaObject: return Group__MUIM_FindAreaObject(cl, obj, (APTR)msg);
2972 case MUIM_Export: return Group__MUIM_Export(cl, obj, (APTR) msg);
2973 case MUIM_Import: return Group__MUIM_Import(cl, obj, (APTR) msg);
2975 //#if 0
2976 #if 1
2977 /* Disabled. See above */
2978 case MUIM_Notify: return Group_Notify(cl, obj, (APTR)msg);
2979 #endif
2980 case MUIM_Set:
2981 case MUIM_MultiSet:
2982 case MUIM_CallHook:
2983 case MUIM_DrawParentBackground:
2984 case MUIM_DragBegin:
2985 case MUIM_DragDrop:
2986 case MUIM_DragQuery:
2987 case MUIM_DragFinish:
2988 case MUIM_DoDrag:
2989 case MUIM_CreateDragImage:
2990 case MUIM_DeleteDragImage:
2991 case MUIM_GoActive:
2992 case MUIM_GoInactive:
2993 case MUIM_CreateBubble:
2994 case MUIM_DeleteBubble:
2995 case MUIM_CreateShortHelp:
2996 case MUIM_DeleteShortHelp:
2997 case OM_ADDTAIL:
2998 case OM_REMOVE:
2999 return DoSuperMethodA(cl, obj, (APTR)msg); /* Needs not to be forwarded? */
3002 /* sometimes you want to call a superclass method,
3003 * but not dispatching to child.
3004 * But what to do with list methods in a listview ?
3006 Group_DispatchMsg(cl, obj, (APTR)msg);
3008 return DoSuperMethodA(cl, obj, msg);
3010 BOOPSI_DISPATCHER_END
3014 * Class descriptor.
3016 const struct __MUIBuiltinClass _MUI_Group_desc = {
3017 MUIC_Group,
3018 MUIC_Area,
3019 sizeof(struct MUI_GroupData),
3020 (void*)Group_Dispatcher