2 Copyright © 2002-2006, The AROS Development Team. All rights reserved.
9 #include <exec/types.h>
11 #include <clib/alib_protos.h>
12 #include <proto/intuition.h>
13 #include <proto/graphics.h>
14 #include <proto/utility.h>
15 #include <proto/exec.h>
16 #include <proto/muimaster.h>
19 #include "muimaster_intern.h"
22 #include "balance_private.h"
24 /* #define MYDEBUG 0 */
27 extern struct Library
*MUIMasterBase
;
30 * [FirstBound .... <- balance -> .... SecondBound]
34 IPTR
Balance__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
36 struct Balance_DATA
*data
;
37 const struct TagItem
*tags
;
40 obj
= (Object
*)DoSuperMethodA(cl
, obj
, (Msg
)msg
);
45 /* Initial local instance data */
46 data
= INST_DATA(cl
, obj
);
48 /* parse initial taglist */
50 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
)); )
54 case MUIA_Balance_Quiet
:
59 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
;
60 data
->ehn
.ehn_Priority
= 0;
61 data
->ehn
.ehn_Flags
= 0;
62 data
->ehn
.ehn_Object
= obj
;
63 data
->ehn
.ehn_Class
= cl
;
65 D(bug("Balance_New(0x%lx)\n",obj
));
70 IPTR
Balance__MUIM_Setup(struct IClass
*cl
, Object
*obj
, struct MUIP_Setup
*msg
)
72 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
74 if (!(DoSuperMethodA(cl
, obj
, (Msg
) msg
)))
78 get(_parent(obj
), MUIA_Group_Horiz
, &data
->horizgroup
);
80 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
)&data
->ehn
);
85 IPTR
Balance__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
, struct MUIP_Cleanup
*msg
)
87 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
89 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
)&data
->ehn
);
91 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
94 /**************************************************************************
96 **************************************************************************/
97 IPTR
Balance__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
, struct MUIP_AskMinMax
*msg
)
99 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
101 DoSuperMethodA(cl
, obj
, (Msg
)msg
);
103 if (data
->horizgroup
)
105 msg
->MinMaxInfo
->MinWidth
+= 3;
106 msg
->MinMaxInfo
->DefWidth
= msg
->MinMaxInfo
->MinWidth
;
107 msg
->MinMaxInfo
->MaxWidth
= msg
->MinMaxInfo
->DefWidth
;
108 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
112 msg
->MinMaxInfo
->MinHeight
+= 3;
113 msg
->MinMaxInfo
->DefHeight
= msg
->MinMaxInfo
->MinHeight
;
114 msg
->MinMaxInfo
->MaxHeight
= msg
->MinMaxInfo
->DefHeight
;
115 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
122 IPTR
Balance__MUIM_Draw(struct IClass
*cl
, Object
*obj
, struct MUIP_Draw
*msg
)
124 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
125 struct MUI_RenderInfo
*mri
;
128 DoSuperMethodA(cl
, obj
, (Msg
)msg
);
130 if (!(msg
->flags
& MADF_DRAWOBJECT
))
133 if (_mwidth(obj
) < 1 || _mheight(obj
) < 1)
136 mri
= muiRenderInfo(obj
);
138 if (data
->state
== NOT_CLICKED
)
149 if (data
->horizgroup
)
151 SetAPen(_rp(obj
), _pens(obj
)[col1
]);
152 Move(_rp(obj
), _mleft(obj
), _mtop(obj
));
153 Draw(_rp(obj
), _mleft(obj
), _mbottom(obj
));
154 SetAPen(_rp(obj
), _pens(obj
)[MPEN_FILL
]);
155 Move(_rp(obj
), _mleft(obj
) + 1, _mtop(obj
));
156 Draw(_rp(obj
), _mleft(obj
) + 1, _mbottom(obj
));
157 SetAPen(_rp(obj
), _pens(obj
)[col2
]);
158 Move(_rp(obj
), _mleft(obj
) + 2, _mtop(obj
));
159 Draw(_rp(obj
), _mleft(obj
) + 2, _mbottom(obj
));
163 SetAPen(_rp(obj
), _pens(obj
)[col1
]);
164 Move(_rp(obj
), _mleft(obj
), _mtop(obj
));
165 Draw(_rp(obj
), _mright(obj
), _mtop(obj
));
166 SetAPen(_rp(obj
), _pens(obj
)[MPEN_FILL
]);
167 Move(_rp(obj
), _mleft(obj
), _mtop(obj
) + 1);
168 Draw(_rp(obj
), _mright(obj
), _mtop(obj
) + 1);
169 SetAPen(_rp(obj
), _pens(obj
)[col2
]);
170 Move(_rp(obj
), _mleft(obj
), _mtop(obj
) + 2);
171 Draw(_rp(obj
), _mright(obj
), _mtop(obj
) + 2);
177 static void draw_object_frame (Object
*obj
, Object
*o
, BOOL fixed
)
179 SetAPen(_rp(obj
), _pens(obj
)[MPEN_TEXT
]);
180 Move(_rp(obj
), _left(o
), _top(o
));
181 Draw(_rp(obj
), _left(o
), _bottom(o
));
182 Draw(_rp(obj
), _right(o
), _bottom(o
));
183 Draw(_rp(obj
), _right(o
), _top(o
));
184 Draw(_rp(obj
), _left(o
), _top(o
));
187 Draw(_rp(obj
), _right(o
), _bottom(o
));
188 Move(_rp(obj
), _right(o
), _top(o
));
189 Draw(_rp(obj
), _left(o
), _bottom(o
));
193 static LONG
get_first_bound (struct Balance_DATA
*data
, Object
*obj
)
197 if (data
->horizgroup
)
199 get(_parent(obj
), MUIA_Group_HorizSpacing
, &spacing
);
200 return _left(obj
) + _minwidth(obj
) + _subwidth(obj
) + spacing
;
204 get(_parent(obj
), MUIA_Group_VertSpacing
, &spacing
);
205 return _top(obj
) + _minheight(obj
) + _subheight(obj
) + spacing
;
209 static LONG
get_second_bound (struct Balance_DATA
*data
, Object
*obj
)
213 if (data
->horizgroup
)
215 get(_parent(obj
), MUIA_Group_HorizSpacing
, &spacing
);
216 return _right(obj
) - _minwidth(obj
) - _subwidth(obj
) - spacing
;
220 get(_parent(obj
), MUIA_Group_VertSpacing
, &spacing
);
221 return _bottom(obj
) - _minheight(obj
) - _subheight(obj
) - spacing
;
226 static LONG
get_first_bound_multi (struct Balance_DATA
*data
, Object
*obj
)
228 if (data
->horizgroup
)
230 return _mleft(_parent(obj
));
234 return _mtop(_parent(obj
));
238 static LONG
get_second_bound_multi (struct Balance_DATA
*data
, Object
*obj
)
240 if (data
->horizgroup
)
242 return _mright(_parent(obj
));
246 return _mbottom(_parent(obj
));
250 static BOOL
is_fixed_size (struct Balance_DATA
*data
, Object
*obj
)
252 if (data
->horizgroup
)
254 return (_minwidth(obj
) == _maxwidth(obj
));
258 return (_minheight(obj
) == _maxheight(obj
));
263 static ULONG
get_total_weight_2(struct Balance_DATA
*data
, Object
*objA
, Object
*objB
)
265 if (data
->horizgroup
)
267 return _hweight(objA
) + _hweight(objB
);
271 return _vweight(objA
) + _vweight(objB
);
276 static void set_weight_2 (struct Balance_DATA
*data
, WORD current
)
281 if (current
>= data
->second_bound
)
284 weightA
= data
->total_weight
;
285 D(bug("weightB = 0\n"));
287 else if (current
<= data
->first_bound
)
290 weightB
= data
->total_weight
;
291 D(bug("weightA = 0\n"));
295 D(bug("L=%ld, mid=%ld, R=%ld || M=%d\n",
296 data
->first_bound
, data
->clickpos
, data
->second_bound
,
298 weightA
= (current
- data
->first_bound
+ 1) * data
->total_weight
299 / (data
->second_bound
- data
->first_bound
+ 1);
301 D(bug("found wA = %ld\n", weightA
));
302 if (weightA
> data
->total_weight
)
304 D(bug("*** weightA > data->total_weight\n"));
305 weightA
= data
->total_weight
;
307 weightB
= data
->total_weight
- weightA
;
310 if (data
->horizgroup
)
312 _hweight(data
->obj_before
) = weightA
;
313 _hweight(data
->obj_after
) = weightB
;
317 _vweight(data
->obj_before
) = weightA
;
318 _vweight(data
->obj_after
) = weightB
;
323 static void recalc_weights_neighbours (struct IClass
*cl
, Object
*obj
, WORD mouse
)
325 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
327 if ((data
->total_weight
== -1) || (data
->first_bound
== -1) || (data
->second_bound
== -1))
330 Object
*object_state
;
332 object_state
= (Object
*)data
->objs
->lh_Head
;
333 while ((sibling
= NextObject(&object_state
)))
335 if (!(_flags(sibling
) & MADF_SHOWME
))
337 /* D(bug("sibling %lx\n", sibling)); */
340 while ((sibling
= NextObject(&object_state
)))
342 if (!(_flags(sibling
) & MADF_SHOWME
))
344 data
->obj_after
= sibling
;
349 data
->obj_before
= sibling
;
351 if (!(data
->obj_before
&& data
->obj_after
))
353 D(bug("Balance(%0xlx): missing siblings; before=%lx, after=%lx\n",
354 obj
, data
->obj_before
, data
->obj_after
));
357 if (data
->total_weight
== -1)
358 data
->total_weight
= get_total_weight_2(data
, data
->obj_before
, data
->obj_after
);
359 if (data
->first_bound
== -1)
360 data
->first_bound
= get_first_bound(data
, data
->obj_before
);
361 if (data
->second_bound
== -1)
362 data
->second_bound
= get_second_bound(data
, data
->obj_after
);
365 set_weight_2(data
, mouse
);
368 static LONG
get_weight (struct Balance_DATA
*data
, Object
*obj
)
370 if (data
->horizgroup
)
372 return _hweight(obj
);
376 return _vweight(obj
);
380 static void set_weight (struct Balance_DATA
*data
, Object
*obj
, LONG w
)
382 if (data
->horizgroup
)
392 static LONG
get_size (struct Balance_DATA
*data
, Object
*obj
)
394 if (data
->horizgroup
)
405 static void set_interpolated_weight (struct Balance_DATA
*data
, Object
*obj
,
406 LONG oldw
, LONG neww
)
408 if (data
->horizgroup
)
411 _hweight(obj
) = _hweight(obj
) * neww
/ oldw
;
418 _vweight(obj
) = _vweight(obj
) * neww
/ oldw
;
426 static void set_weight_all (struct Balance_DATA
*data
, Object
*obj
, WORD current
)
430 LONG ldelta
, rdelta
, lwbygad
, rwbygad
, lbonus
, rbonus
, lneg
, rneg
, lzero
, rzero
, count
;
434 if (data
->lsize
&& data
->rsize
)
437 + ((current
- data
->clickpos
)
438 * ((data
->lsum
/ (double)data
->lsize
) + (data
->rsum
/ (double)data
->rsize
))
442 weightA
= data
->lsum
;
444 if (weightA
> data
->total_weight
)
446 D(bug("*** weightA > data->total_weight\n"));
447 weightA
= data
->total_weight
;
451 D(bug("*** weightA < 0n"));
454 weightB
= data
->total_weight
- weightA
;
455 D(bug("normal : weights = %ld/%ld\n", weightA
, weightB
));
458 ldelta
= weightA
- data
->oldWeightA
;
459 rdelta
= weightB
- data
->oldWeightB
;
460 lwbygad
= ldelta
/ data
->lsiblings
;
461 rwbygad
= rdelta
/ data
->rsiblings
;
462 lbonus
= ldelta
% data
->lsiblings
;
465 rbonus
= rdelta
% data
->rsiblings
;
468 lfirst
= (int) ((double)data
->lsiblings
*rand()/(RAND_MAX
+1.0));
469 rfirst
= (int) ((double)data
->rsiblings
*rand()/(RAND_MAX
+1.0));
475 Object
*object_state
;
476 WORD left
= data
->lsiblings
;
478 D(bug("delta=%ld/%ld; wbygad=%ld/%ld; bonus=%ld/%ld; first=%d/%d\n", ldelta
, rdelta
,
479 lwbygad
, rwbygad
, lbonus
, rbonus
, lfirst
, rfirst
));
483 D(bug("avoiding deadloop\n"));
491 /* D(bug("left weight : from %d to %d\n", data->lsum, weightA)); */
492 /* D(bug("right weight : from %d to %d\n", data->rsum, weightB)); */
493 object_state
= (Object
*)data
->objs
->lh_Head
;
494 while ((sibling
= NextObject(&object_state
)))
496 if (!(_flags(sibling
) & MADF_SHOWME
))
498 if (is_fixed_size(data
, sibling
))
501 /* D(bug(" B %d\n", left)); */
505 w1
= get_weight(data
, sibling
);
507 if (w2
|| (count
< 2))
510 if ((lfirst
-- <= 0) && lbonus
-- > 0)
511 w2
+= ((ldelta
> 0) ? 1 : -1);
518 set_weight(data
, sibling
, w2
);
519 /* D(bug(" w (left) from %d to %d (%ld -> %ld)\n", w1, w2, data->oldWeightA, weightA)); */
525 w1
= get_weight(data
, sibling
);
527 if (w2
|| (count
< 2))
530 if ((rfirst
-- <= 0) && rbonus
-- > 0)
531 w2
+= ((rdelta
> 0) ? 1 : -1);
538 set_weight(data
, sibling
, w2
);
539 /* D(bug(" w (right) from %d to %d (%ld -> %ld)\n", w1, w2, data->oldWeightB, weightB)); */
544 if (lzero
== data
->lsiblings
)
546 if (rzero
== data
->rsiblings
)
549 lwbygad
= lneg
/ (data
->lsiblings
- lzero
);
550 lbonus
= -(lneg
% (data
->lsiblings
- lzero
)) + lbonus
;
551 rwbygad
= rneg
/ (data
->rsiblings
- rzero
);
552 rbonus
= -(rneg
% (data
->rsiblings
- rzero
)) + rbonus
;
553 } while (lneg
|| rneg
|| (lbonus
> 0) || (rbonus
> 0));
555 data
->oldWeightA
= weightA
;
556 data
->oldWeightB
= weightB
;
560 static void recalc_weights_all (struct IClass
*cl
, Object
*obj
, WORD mouse
)
562 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
563 Object
*first
= NULL
;
566 D(bug("recalc_weights_all\n"));
568 if ((data
->total_weight
== -1) || (data
->lsiblings
== -1) || (data
->rsiblings
== -1)
569 || (data
->first_bound
== -1) || (data
->second_bound
== -1))
572 Object
*object_state
;
581 object_state
= (Object
*)data
->objs
->lh_Head
;
582 for (next
= NextObject(&object_state
); next
; next
= NextObject(&object_state
))
585 if (!(_flags(sibling
) & MADF_SHOWME
))
595 if (is_fixed_size(data
, sibling
))
602 data
->lsum
+= get_weight(data
, sibling
);
603 data
->lsize
+= get_size(data
, sibling
);
610 data
->lsum
+= get_weight(data
, sibling
);
611 data
->lsize
+= get_size(data
, sibling
);
616 data
->rsum
+= get_weight(data
, sibling
);
617 data
->rsize
+= get_size(data
, sibling
);
623 if (!first
|| !mid
|| !last
)
625 if (data
->total_weight
== -1)
626 data
->total_weight
= data
->lsum
+ data
->rsum
;
628 if (data
->first_bound
== -1)
629 data
->first_bound
= get_first_bound_multi(data
, first
);
631 if (data
->second_bound
== -1)
632 data
->second_bound
= get_second_bound_multi(data
, last
);
634 data
->oldWeightA
= data
->lsum
;
635 data
->oldWeightB
= data
->rsum
;
637 D(bug("Total Weight = %ld, left = %ld, right = %ld\n", data
->total_weight
, data
->lsum
, data
->rsum
));
638 D(bug("bound 1 = %ld, bound 2 = %ld\n", data
->first_bound
, data
->second_bound
));
639 set_weight_all(data
, obj
, mouse
);
643 static void handle_move (struct IClass
*cl
, Object
*obj
, WORD mouse
)
645 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
647 if (data
->state
== CLICKED
)
648 recalc_weights_all(cl
, obj
, mouse
);
649 else if (data
->state
== SHIFT_CLICKED
)
650 recalc_weights_neighbours(cl
, obj
, mouse
);
654 /* relayout with new weights */
655 DoMethod(_parent(obj
), MUIM_Layout
);
657 /* full drawing, or sketch */
658 if (muiGlobalInfo(obj
)->mgi_Prefs
->balancing_look
== BALANCING_SHOW_OBJECTS
)
660 MUI_Redraw(_parent(obj
), MADF_DRAWALL
);
665 Object
*object_state
;
667 DoMethod(_parent(obj
), MUIM_DrawBackground
, _mleft(_parent(obj
)),
668 _mtop(_parent(obj
)), _mwidth(_parent(obj
)), _mheight(_parent(obj
)),
670 /* for each child, draw a black frame */
671 object_state
= (Object
*)data
->objs
->lh_Head
;
672 while ((sibling
= NextObject(&object_state
)))
674 if (!(_flags(sibling
) & MADF_SHOWME
))
676 /* D(bug("sibling %lx\n", sibling)); */
678 draw_object_frame(obj
, sibling
, is_fixed_size(data
, sibling
));
684 /**************************************************************************
686 **************************************************************************/
687 IPTR
Balance__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
, struct MUIP_HandleEvent
*msg
)
689 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
693 switch (msg
->imsg
->Class
)
695 case IDCMP_MOUSEBUTTONS
:
696 if (msg
->imsg
->Code
== SELECTDOWN
)
698 if (_isinobject(msg
->imsg
->MouseX
, msg
->imsg
->MouseY
))
700 get(_parent(obj
), MUIA_Group_ChildList
, &data
->objs
);
701 data
->clickpos
= data
->horizgroup
? msg
->imsg
->MouseX
: msg
->imsg
->MouseY
;
702 data
->lastpos
= data
->clickpos
;
703 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
)&data
->ehn
);
704 data
->ehn
.ehn_Events
|= IDCMP_MOUSEMOVE
;
705 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
)&data
->ehn
);
706 if (msg
->imsg
->Qualifier
& (IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
))
708 data
->state
= SHIFT_CLICKED
;
709 data
->obj_before
= NULL
;
710 data
->obj_after
= NULL
;
714 data
->state
= CLICKED
;
715 data
->lsiblings
= -1;
716 data
->rsiblings
= -1;
718 data
->total_weight
= -1;
719 data
->first_bound
= -1;
720 data
->second_bound
= -1;
722 MUI_Redraw(obj
, MADF_DRAWOBJECT
);
725 else /* msg->imsg->Code != SELECTDOWN */
727 if (data
->state
!= NOT_CLICKED
)
729 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
)&data
->ehn
);
730 data
->ehn
.ehn_Events
&= ~IDCMP_MOUSEMOVE
;
731 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
)&data
->ehn
);
732 data
->state
= NOT_CLICKED
;
733 if (data
->total_weight
!= -1)
734 MUI_Redraw(_parent(obj
), MADF_DRAWALL
);
736 MUI_Redraw(obj
, MADF_DRAWALL
);
741 case IDCMP_MOUSEMOVE
:
743 if ((data
->horizgroup
) && (msg
->imsg
->MouseX
== data
->lastpos
))
745 if ((!data
->horizgroup
) && (msg
->imsg
->MouseY
== data
->lastpos
))
750 if (data
->horizgroup
)
752 handle_move(cl
, obj
, msg
->imsg
->MouseX
);
753 data
->lastpos
= msg
->imsg
->MouseX
;
757 handle_move(cl
, obj
, msg
->imsg
->MouseY
);
758 data
->lastpos
= msg
->imsg
->MouseY
;
768 #if ZUNE_BUILTIN_BALANCE
769 BOOPSI_DISPATCHER(IPTR
, Balance_Dispatcher
, cl
, obj
, msg
)
771 switch (msg
->MethodID
)
773 case OM_NEW
: return Balance__OM_NEW(cl
, obj
, (struct opSet
*) msg
);
774 case MUIM_Setup
: return Balance__MUIM_Setup(cl
, obj
, (APTR
)msg
);
775 case MUIM_Cleanup
: return Balance__MUIM_Cleanup(cl
, obj
, (APTR
)msg
);
776 case MUIM_AskMinMax
: return Balance__MUIM_AskMinMax(cl
, obj
, (APTR
)msg
);
777 case MUIM_Draw
: return Balance__MUIM_Draw(cl
, obj
, (APTR
)msg
);
778 case MUIM_HandleEvent
: return Balance__MUIM_HandleEvent(cl
, obj
, (APTR
)msg
);
779 default: return DoSuperMethodA(cl
, obj
, msg
);
782 BOOPSI_DISPATCHER_END
784 const struct __MUIBuiltinClass _MUI_Balance_desc
=
788 sizeof(struct Balance_DATA
),
789 (void*)Balance_Dispatcher