2 Copyright © 2002-2013, 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
;
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
,
71 struct MUIP_Setup
*msg
)
73 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
75 if (!(DoSuperMethodA(cl
, obj
, (Msg
) msg
)))
79 get(_parent(obj
), MUIA_Group_Horiz
, &data
->horizgroup
);
81 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) & data
->ehn
);
86 IPTR
Balance__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
87 struct MUIP_Cleanup
*msg
)
89 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
91 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) & data
->ehn
);
93 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
96 /**************************************************************************
98 **************************************************************************/
99 IPTR
Balance__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
100 struct MUIP_AskMinMax
*msg
)
102 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
104 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
106 if (data
->horizgroup
)
108 msg
->MinMaxInfo
->MinWidth
+= 3;
109 msg
->MinMaxInfo
->DefWidth
= msg
->MinMaxInfo
->MinWidth
;
110 msg
->MinMaxInfo
->MaxWidth
= msg
->MinMaxInfo
->DefWidth
;
111 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
115 msg
->MinMaxInfo
->MinHeight
+= 3;
116 msg
->MinMaxInfo
->DefHeight
= msg
->MinMaxInfo
->MinHeight
;
117 msg
->MinMaxInfo
->MaxHeight
= msg
->MinMaxInfo
->DefHeight
;
118 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
125 IPTR
Balance__MUIM_Draw(struct IClass
*cl
, Object
*obj
,
126 struct MUIP_Draw
*msg
)
128 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
131 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
133 if (!(msg
->flags
& MADF_DRAWOBJECT
))
136 if (_mwidth(obj
) < 1 || _mheight(obj
) < 1)
139 if (data
->state
== NOT_CLICKED
)
150 if (data
->horizgroup
)
152 SetAPen(_rp(obj
), _pens(obj
)[col1
]);
153 Move(_rp(obj
), _mleft(obj
), _mtop(obj
));
154 Draw(_rp(obj
), _mleft(obj
), _mbottom(obj
));
155 SetAPen(_rp(obj
), _pens(obj
)[MPEN_FILL
]);
156 Move(_rp(obj
), _mleft(obj
) + 1, _mtop(obj
));
157 Draw(_rp(obj
), _mleft(obj
) + 1, _mbottom(obj
));
158 SetAPen(_rp(obj
), _pens(obj
)[col2
]);
159 Move(_rp(obj
), _mleft(obj
) + 2, _mtop(obj
));
160 Draw(_rp(obj
), _mleft(obj
) + 2, _mbottom(obj
));
164 SetAPen(_rp(obj
), _pens(obj
)[col1
]);
165 Move(_rp(obj
), _mleft(obj
), _mtop(obj
));
166 Draw(_rp(obj
), _mright(obj
), _mtop(obj
));
167 SetAPen(_rp(obj
), _pens(obj
)[MPEN_FILL
]);
168 Move(_rp(obj
), _mleft(obj
), _mtop(obj
) + 1);
169 Draw(_rp(obj
), _mright(obj
), _mtop(obj
) + 1);
170 SetAPen(_rp(obj
), _pens(obj
)[col2
]);
171 Move(_rp(obj
), _mleft(obj
), _mtop(obj
) + 2);
172 Draw(_rp(obj
), _mright(obj
), _mtop(obj
) + 2);
178 static void draw_object_frame(Object
*obj
, Object
*o
, BOOL fixed
)
180 SetAPen(_rp(obj
), _pens(obj
)[MPEN_TEXT
]);
181 Move(_rp(obj
), _left(o
), _top(o
));
182 Draw(_rp(obj
), _left(o
), _bottom(o
));
183 Draw(_rp(obj
), _right(o
), _bottom(o
));
184 Draw(_rp(obj
), _right(o
), _top(o
));
185 Draw(_rp(obj
), _left(o
), _top(o
));
188 Draw(_rp(obj
), _right(o
), _bottom(o
));
189 Move(_rp(obj
), _right(o
), _top(o
));
190 Draw(_rp(obj
), _left(o
), _bottom(o
));
194 static LONG
get_first_bound(struct Balance_DATA
*data
, Object
*obj
)
198 if (data
->horizgroup
)
200 get(_parent(obj
), MUIA_Group_HorizSpacing
, &spacing
);
201 return _left(obj
) + _minwidth(obj
) + _subwidth(obj
) + spacing
;
205 get(_parent(obj
), MUIA_Group_VertSpacing
, &spacing
);
206 return _top(obj
) + _minheight(obj
) + _subheight(obj
) + spacing
;
210 static LONG
get_second_bound(struct Balance_DATA
*data
, Object
*obj
)
214 if (data
->horizgroup
)
216 get(_parent(obj
), MUIA_Group_HorizSpacing
, &spacing
);
217 return _right(obj
) - _minwidth(obj
) - _subwidth(obj
) - spacing
;
221 get(_parent(obj
), MUIA_Group_VertSpacing
, &spacing
);
222 return _bottom(obj
) - _minheight(obj
) - _subheight(obj
) - spacing
;
227 static LONG
get_first_bound_multi(struct Balance_DATA
*data
, Object
*obj
)
229 if (data
->horizgroup
)
231 return _mleft(_parent(obj
));
235 return _mtop(_parent(obj
));
239 static LONG
get_second_bound_multi(struct Balance_DATA
*data
, Object
*obj
)
241 if (data
->horizgroup
)
243 return _mright(_parent(obj
));
247 return _mbottom(_parent(obj
));
251 static BOOL
is_fixed_size(struct Balance_DATA
*data
, Object
*obj
)
253 if (data
->horizgroup
)
255 return (_minwidth(obj
) == _maxwidth(obj
));
259 return (_minheight(obj
) == _maxheight(obj
));
264 static ULONG
get_total_weight_2(struct Balance_DATA
*data
, Object
*objA
,
267 if (data
->horizgroup
)
269 return _hweight(objA
) + _hweight(objB
);
273 return _vweight(objA
) + _vweight(objB
);
278 static void set_weight_2(struct Balance_DATA
*data
, WORD current
)
283 if (current
>= data
->second_bound
)
286 weightA
= data
->total_weight
;
287 D(bug("weightB = 0\n"));
289 else if (current
<= data
->first_bound
)
292 weightB
= data
->total_weight
;
293 D(bug("weightA = 0\n"));
297 D(bug("L=%ld, mid=%ld, R=%ld || M=%d\n",
298 data
->first_bound
, data
->clickpos
, data
->second_bound
,
300 weightA
= (current
- data
->first_bound
+ 1) * data
->total_weight
301 / (data
->second_bound
- data
->first_bound
+ 1);
303 D(bug("found wA = %ld\n", weightA
));
304 if (weightA
> data
->total_weight
)
306 D(bug("*** weightA > data->total_weight\n"));
307 weightA
= data
->total_weight
;
309 weightB
= data
->total_weight
- weightA
;
312 if (data
->horizgroup
)
314 _hweight(data
->obj_before
) = weightA
;
315 _hweight(data
->obj_after
) = weightB
;
319 _vweight(data
->obj_before
) = weightA
;
320 _vweight(data
->obj_after
) = weightB
;
325 static void recalc_weights_neighbours(struct IClass
*cl
, Object
*obj
,
328 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
330 if ((data
->total_weight
== -1) || (data
->first_bound
== -1)
331 || (data
->second_bound
== -1))
334 Object
*object_state
;
336 object_state
= (Object
*) data
->objs
->lh_Head
;
337 while ((sibling
= NextObject(&object_state
)))
339 if (!(_flags(sibling
) & MADF_SHOWME
))
341 /* D(bug("sibling %lx\n", sibling)); */
344 while ((sibling
= NextObject(&object_state
)))
346 if (!(_flags(sibling
) & MADF_SHOWME
))
348 data
->obj_after
= sibling
;
353 data
->obj_before
= sibling
;
355 if (!(data
->obj_before
&& data
->obj_after
))
358 ("Balance(%0xlx): missing siblings; before=%lx, after=%lx\n",
359 obj
, data
->obj_before
, data
->obj_after
));
362 if (data
->total_weight
== -1)
364 get_total_weight_2(data
, data
->obj_before
, data
->obj_after
);
365 if (data
->first_bound
== -1)
366 data
->first_bound
= get_first_bound(data
, data
->obj_before
);
367 if (data
->second_bound
== -1)
368 data
->second_bound
= get_second_bound(data
, data
->obj_after
);
371 set_weight_2(data
, mouse
);
374 static LONG
get_weight(struct Balance_DATA
*data
, Object
*obj
)
376 if (data
->horizgroup
)
378 return _hweight(obj
);
382 return _vweight(obj
);
386 static void set_weight(struct Balance_DATA
*data
, Object
*obj
, LONG w
)
388 if (data
->horizgroup
)
398 static LONG
get_size(struct Balance_DATA
*data
, Object
*obj
)
400 if (data
->horizgroup
)
411 static void set_interpolated_weight(struct Balance_DATA
*data
, Object
*obj
,
412 LONG oldw
, LONG neww
)
414 if (data
->horizgroup
)
417 _hweight(obj
) = _hweight(obj
) * neww
/ oldw
;
424 _vweight(obj
) = _vweight(obj
) * neww
/ oldw
;
432 static void set_weight_all(struct Balance_DATA
*data
, Object
*obj
,
437 LONG ldelta
, rdelta
, lwbygad
, rwbygad
, lbonus
, rbonus
, lneg
, rneg
,
442 if (data
->lsize
&& data
->rsize
)
445 + ((current
- data
->clickpos
)
446 * ((data
->lsum
/ (double)data
->lsize
) +
447 (data
->rsum
/ (double)data
->rsize
)) / 2.0);
450 weightA
= data
->lsum
;
452 if (weightA
> data
->total_weight
)
454 D(bug("*** weightA > data->total_weight\n"));
455 weightA
= data
->total_weight
;
459 D(bug("*** weightA < 0n"));
462 weightB
= data
->total_weight
- weightA
;
463 D(bug("normal : weights = %ld/%ld\n", weightA
, weightB
));
466 ldelta
= weightA
- data
->oldWeightA
;
467 rdelta
= weightB
- data
->oldWeightB
;
468 lwbygad
= ldelta
/ data
->lsiblings
;
469 rwbygad
= rdelta
/ data
->rsiblings
;
470 lbonus
= ldelta
% data
->lsiblings
;
473 rbonus
= rdelta
% data
->rsiblings
;
476 lfirst
= (int)((double)data
->lsiblings
* rand() / (RAND_MAX
+ 1.0));
477 rfirst
= (int)((double)data
->rsiblings
* rand() / (RAND_MAX
+ 1.0));
483 Object
*object_state
;
484 WORD left
= data
->lsiblings
;
486 D(bug("delta=%ld/%ld; wbygad=%ld/%ld; bonus=%ld/%ld; first=%d/%d\n",
487 ldelta
, rdelta
, lwbygad
, rwbygad
, lbonus
, rbonus
, lfirst
,
492 D(bug("avoiding deadloop\n"));
500 /* D(bug("left weight : from %d to %d\n", data->lsum, weightA)); */
501 /* D(bug("right weight : from %d to %d\n", data->rsum, weightB)); */
502 object_state
= (Object
*) data
->objs
->lh_Head
;
503 while ((sibling
= NextObject(&object_state
)))
505 if (!(_flags(sibling
) & MADF_SHOWME
))
507 if (is_fixed_size(data
, sibling
))
510 /* D(bug(" B %d\n", left)); */
514 w1
= get_weight(data
, sibling
);
516 if (w2
|| (count
< 2))
519 if ((lfirst
-- <= 0) && lbonus
-- > 0)
520 w2
+= ((ldelta
> 0) ? 1 : -1);
527 set_weight(data
, sibling
, w2
);
528 /* D(bug(" w (left) from %d to %d (%ld -> %ld)\n",
529 * w1, w2, data->oldWeightA, weightA)); */
535 w1
= get_weight(data
, sibling
);
537 if (w2
|| (count
< 2))
540 if ((rfirst
-- <= 0) && rbonus
-- > 0)
541 w2
+= ((rdelta
> 0) ? 1 : -1);
548 set_weight(data
, sibling
, w2
);
549 /* D(bug(" w (right) from %d to %d (%ld -> %ld)\n",
550 * w1, w2, data->oldWeightB, weightB)); */
555 if (lzero
== data
->lsiblings
)
557 if (rzero
== data
->rsiblings
)
560 lwbygad
= lneg
/ (data
->lsiblings
- lzero
);
561 lbonus
= -(lneg
% (data
->lsiblings
- lzero
)) + lbonus
;
562 rwbygad
= rneg
/ (data
->rsiblings
- rzero
);
563 rbonus
= -(rneg
% (data
->rsiblings
- rzero
)) + rbonus
;
565 while (lneg
|| rneg
|| (lbonus
> 0) || (rbonus
> 0));
567 data
->oldWeightA
= weightA
;
568 data
->oldWeightB
= weightB
;
572 static void recalc_weights_all(struct IClass
*cl
, Object
*obj
, WORD mouse
)
574 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
575 Object
*first
= NULL
;
578 D(bug("recalc_weights_all\n"));
580 if ((data
->total_weight
== -1) || (data
->lsiblings
== -1)
581 || (data
->rsiblings
== -1) || (data
->first_bound
== -1)
582 || (data
->second_bound
== -1))
585 Object
*object_state
;
594 object_state
= (Object
*) data
->objs
->lh_Head
;
595 for (next
= NextObject(&object_state
); next
;
596 next
= NextObject(&object_state
))
599 if (!(_flags(sibling
) & MADF_SHOWME
))
609 if (is_fixed_size(data
, sibling
))
616 data
->lsum
+= get_weight(data
, sibling
);
617 data
->lsize
+= get_size(data
, sibling
);
624 data
->lsum
+= get_weight(data
, sibling
);
625 data
->lsize
+= get_size(data
, sibling
);
630 data
->rsum
+= get_weight(data
, sibling
);
631 data
->rsize
+= get_size(data
, sibling
);
637 if (!first
|| !mid
|| !last
)
639 if (data
->total_weight
== -1)
640 data
->total_weight
= data
->lsum
+ data
->rsum
;
642 if (data
->first_bound
== -1)
643 data
->first_bound
= get_first_bound_multi(data
, first
);
645 if (data
->second_bound
== -1)
646 data
->second_bound
= get_second_bound_multi(data
, last
);
648 data
->oldWeightA
= data
->lsum
;
649 data
->oldWeightB
= data
->rsum
;
651 D(bug("Total Weight = %ld, left = %ld, right = %ld\n",
652 data
->total_weight
, data
->lsum
, data
->rsum
));
653 D(bug("bound 1 = %ld, bound 2 = %ld\n", data
->first_bound
,
654 data
->second_bound
));
655 set_weight_all(data
, obj
, mouse
);
659 static void handle_move(struct IClass
*cl
, Object
*obj
, WORD mouse
)
661 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
663 if (data
->state
== CLICKED
)
664 recalc_weights_all(cl
, obj
, mouse
);
665 else if (data
->state
== SHIFT_CLICKED
)
666 recalc_weights_neighbours(cl
, obj
, mouse
);
670 /* full drawing, or sketch */
671 if (muiGlobalInfo(obj
)->mgi_Prefs
->balancing_look
==
672 BALANCING_SHOW_OBJECTS
)
674 DoMethod(_parent(obj
), MUIM_Hide
);
676 /* relayout with new weights */
677 DoMethod(_parent(obj
), MUIM_Layout
);
679 DoMethod(_parent(obj
), MUIM_Show
);
681 MUI_Redraw(_parent(obj
), MADF_DRAWALL
);
686 Object
*object_state
;
688 DoMethod(_parent(obj
), MUIM_DrawBackground
, _mleft(_parent(obj
)),
689 _mtop(_parent(obj
)), _mwidth(_parent(obj
)),
690 _mheight(_parent(obj
)), 0, 0, 0);
692 /* relayout with new weights */
693 DoMethod(_parent(obj
), MUIM_Layout
);
695 DoMethod(obj
, MADF_DRAWOBJECT
);
697 /* for each child, draw a black frame */
698 object_state
= (Object
*) data
->objs
->lh_Head
;
699 while ((sibling
= NextObject(&object_state
)))
701 if ((!(_flags(sibling
) & MADF_SHOWME
)) && (obj
!= sibling
))
703 /* D(bug("sibling %lx\n", sibling)); */
705 draw_object_frame(obj
, sibling
, is_fixed_size(data
, sibling
));
711 /**************************************************************************
713 **************************************************************************/
714 IPTR
Balance__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
715 struct MUIP_HandleEvent
*msg
)
717 struct Balance_DATA
*data
= INST_DATA(cl
, obj
);
721 switch (msg
->imsg
->Class
)
723 case IDCMP_MOUSEBUTTONS
:
724 if (msg
->imsg
->Code
== SELECTDOWN
)
726 if (_isinobject(obj
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
))
728 get(_parent(obj
), MUIA_Group_ChildList
, &data
->objs
);
730 data
->horizgroup
? msg
->imsg
->MouseX
: msg
->imsg
->
732 data
->lastpos
= data
->clickpos
;
733 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
735 data
->ehn
.ehn_Events
|= IDCMP_MOUSEMOVE
;
736 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
739 Qualifier
& (IEQUALIFIER_LSHIFT
|
742 data
->state
= SHIFT_CLICKED
;
743 data
->obj_before
= NULL
;
744 data
->obj_after
= NULL
;
748 data
->state
= CLICKED
;
749 data
->lsiblings
= -1;
750 data
->rsiblings
= -1;
752 data
->total_weight
= -1;
753 data
->first_bound
= -1;
754 data
->second_bound
= -1;
756 MUI_Redraw(obj
, MADF_DRAWOBJECT
);
759 else /* msg->imsg->Code != SELECTDOWN */
761 if (data
->state
!= NOT_CLICKED
)
763 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
765 data
->ehn
.ehn_Events
&= ~IDCMP_MOUSEMOVE
;
766 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
768 data
->state
= NOT_CLICKED
;
769 if (data
->total_weight
!= -1)
771 DoMethod(_parent(obj
), MUIM_Hide
);
773 /* relayout with new weights */
774 DoMethod(_parent(obj
), MUIM_Layout
);
776 DoMethod(_parent(obj
), MUIM_Show
);
777 MUI_Redraw(_parent(obj
), MADF_DRAWOBJECT
);
780 MUI_Redraw(obj
, MADF_DRAWALL
);
785 case IDCMP_MOUSEMOVE
:
787 if ((data
->horizgroup
)
788 && (msg
->imsg
->MouseX
== data
->lastpos
))
790 if ((!data
->horizgroup
)
791 && (msg
->imsg
->MouseY
== data
->lastpos
))
797 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
800 if (data
->horizgroup
)
802 handle_move(cl
, obj
, msg
->imsg
->MouseX
);
803 data
->lastpos
= msg
->imsg
->MouseX
;
807 handle_move(cl
, obj
, msg
->imsg
->MouseY
);
808 data
->lastpos
= msg
->imsg
->MouseY
;
811 data
->ehn
.ehn_Events
|= IDCMP_MOUSEMOVE
;
812 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
822 #if ZUNE_BUILTIN_BALANCE
823 BOOPSI_DISPATCHER(IPTR
, Balance_Dispatcher
, cl
, obj
, msg
)
825 switch (msg
->MethodID
)
828 return Balance__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
830 return Balance__MUIM_Setup(cl
, obj
, (APTR
) msg
);
832 return Balance__MUIM_Cleanup(cl
, obj
, (APTR
) msg
);
834 return Balance__MUIM_AskMinMax(cl
, obj
, (APTR
) msg
);
836 return Balance__MUIM_Draw(cl
, obj
, (APTR
) msg
);
837 case MUIM_HandleEvent
:
838 return Balance__MUIM_HandleEvent(cl
, obj
, (APTR
) msg
);
840 return DoSuperMethodA(cl
, obj
, msg
);
843 BOOPSI_DISPATCHER_END
const struct __MUIBuiltinClass _MUI_Balance_desc
=
847 sizeof(struct Balance_DATA
),
848 (void *)Balance_Dispatcher