Some fix for scrolling with lasso.
[tangerine.git] / workbench / libs / muimaster / classes / group.c
blob9e651484ebc8adae5c6202241fa7a4a8a1b0d2d6
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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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, (IPTR *)&(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_Notify - disabled now because previous Zune versions had a OM_GET
2820 check in MUIM_Notify which is no longer the case
2821 **************************************************************************/
2822 #if 0
2823 STATIC IPTR Group_Notify(struct IClass *cl, Object *obj, struct MUIP_Notify *msg)
2825 struct MUI_GroupData *data = INST_DATA(cl, obj);
2826 Object *cstate;
2827 Object *child;
2828 struct MinList *ChildList;
2830 /* Try at first if understand the message our self
2831 ** We disable the forwarding of the OM_GET message
2832 ** as the MUIM_Notify otherwise would "think" that
2833 ** the group class actually understands the attribute
2834 ** although a child does this only
2836 data->dont_forward_get = 1;
2837 if (DoSuperMethodA(cl,obj,(Msg)msg))
2839 data->dont_forward_get = 0;
2840 return 1;
2843 /* We ourself didn't understand the notify tag so we try the children now */
2844 data->dont_forward_get = 0;
2846 get(data->family, MUIA_Family_List, (IPTR *)&(ChildList));
2847 cstate = (Object *)ChildList->mlh_Head;
2848 while ((child = NextObject(&cstate)))
2850 if (DoMethodA(child, (Msg)msg)) return 1;
2852 return 0;
2854 #endif
2856 BOOPSI_DISPATCHER(IPTR, Group_Dispatcher, cl, obj, msg)
2858 switch (msg->MethodID)
2860 case OM_NEW: return Group__OM_NEW(cl, obj, (struct opSet *) msg);
2861 case OM_DISPOSE: return Group__OM_DISPOSE(cl, obj, msg);
2862 case OM_SET: return Group__OM_SET(cl, obj, (struct opSet *)msg);
2863 case OM_GET: return Group__OM_GET(cl, obj, (struct opGet *)msg);
2864 case OM_ADDMEMBER: return Group__OM_ADDMEMBER(cl, obj, (APTR)msg);
2865 case OM_REMMEMBER: return Group__OM_REMMEMBER(cl, obj, (APTR)msg);
2866 case MUIM_AskMinMax: return Group__MUIM_AskMinMax(cl, obj, (APTR)msg);
2867 case MUIM_Group_ExitChange: return Group__MUIM_ExitChange(cl, obj, (APTR)msg);
2868 case MUIM_Group_InitChange: return Group__MUIM_InitChange(cl, obj, (APTR)msg);
2869 case MUIM_Group_Sort: return Group__MUIM_Sort(cl, obj, (APTR)msg);
2870 case MUIM_Group_DoMethodNoForward: return Group__MUIM_DoMethodNoForward(cl, obj, (APTR)msg);
2871 case MUIM_ConnectParent: return Group__MUIM_ConnectParent(cl, obj, (APTR)msg);
2872 case MUIM_DisconnectParent: return Group__MUIM_DisconnectParent(cl, obj, (APTR)msg);
2873 case MUIM_Layout: return Group__MUIM_Layout(cl, obj, (APTR)msg);
2874 case MUIM_Setup: return Group__MUIM_Setup(cl, obj, (APTR)msg);
2875 case MUIM_Cleanup: return Group__MUIM_Cleanup(cl, obj, (APTR)msg);
2876 case MUIM_Draw: return Group__MUIM_Draw(cl, obj, (APTR)msg);
2878 case MUIM_FindUData: return Group__MUIM_FindUData(cl, obj, (APTR)msg);
2879 case MUIM_GetUData: return Group__MUIM_GetUData(cl, obj, (APTR)msg);
2880 case MUIM_SetUData: return Group__MUIM_SetUData(cl, obj, (APTR)msg);
2881 case MUIM_SetUDataOnce: return Group__MUIM_SetUDataOnce(cl, obj, (APTR)msg);
2882 case MUIM_Show: return Group__MUIM_Show(cl, obj, (APTR)msg);
2883 case MUIM_Hide: return Group__MUIM_Hide(cl, obj, (APTR)msg);
2884 case MUIM_HandleEvent: return Group__MUIM_HandleEvent(cl,obj, (APTR)msg);
2885 case MUIM_DrawBackground: return Group__MUIM_DrawBackground(cl, obj, (APTR)msg);
2886 case MUIM_DragQueryExtended:return Group__MUIM_DragQueryExtended(cl, obj, (APTR)msg);
2887 case MUIM_FindAreaObject: return Group__MUIM_FindAreaObject(cl, obj, (APTR)msg);
2889 #if 0
2890 /* Disabled. See above */
2891 case MUIM_Notify: return Group_Notify(cl, obj, (APTR)msg);
2892 #endif
2893 case MUIM_Set:
2894 case MUIM_MultiSet:
2895 case MUIM_CallHook:
2896 case MUIM_DrawParentBackground:
2897 case MUIM_DragBegin:
2898 case MUIM_DragDrop:
2899 case MUIM_DragQuery:
2900 case MUIM_DragFinish:
2901 case MUIM_DoDrag:
2902 case MUIM_CreateDragImage:
2903 case MUIM_DeleteDragImage:
2904 case MUIM_GoActive:
2905 case MUIM_GoInactive:
2906 case MUIM_CreateBubble:
2907 case MUIM_DeleteBubble:
2908 case MUIM_CreateShortHelp:
2909 case MUIM_DeleteShortHelp:
2910 case OM_ADDTAIL:
2911 case OM_REMOVE:
2912 return DoSuperMethodA(cl, obj, (APTR)msg); /* Needs not to be forwarded? */
2915 /* sometimes you want to call a superclass method,
2916 * but not dispatching to child.
2917 * But what to do with list methods in a listview ?
2919 Group_DispatchMsg(cl, obj, (APTR)msg);
2921 return DoSuperMethodA(cl, obj, msg);
2923 BOOPSI_DISPATCHER_END
2927 * Class descriptor.
2929 const struct __MUIBuiltinClass _MUI_Group_desc = {
2930 MUIC_Group,
2931 MUIC_Area,
2932 sizeof(struct MUI_GroupData),
2933 (void*)Group_Dispatcher