2 Copyright 2002-2006, The AROS Development Team. All rights reserved.
6 #include <graphics/gfx.h>
7 #include <graphics/view.h>
8 #include <clib/alib_protos.h>
9 #include <proto/exec.h>
10 #include <proto/graphics.h>
11 #include <proto/utility.h>
12 #include <proto/intuition.h>
13 #include <proto/muimaster.h>
21 #include "muimaster_intern.h"
24 #include "textengine.h"
26 extern struct Library
*MUIMasterBase
;
39 struct MUI_EventHandlerNode ehn
;
40 struct Hook pressedhook
;
41 struct MUI_ImageSpec_intern
*popbg
;
42 struct Window
*popwin
;
51 #define POPITEM_EXTRAWIDTH 4
52 #define POPITEM_EXTRAHEIGHT 2
54 void PressedHookFunc(struct Hook
*hook
, Object
*obj
, APTR msg
)
56 struct MUI_CycleData
*data
;
57 Class
*cl
= (Class
*) hook
->h_Data
;
60 data
= INST_DATA(cl
, obj
);
62 act
= ++data
->entries_active
;
63 if (act
>= data
->entries_num
)
66 set(obj
, MUIA_Cycle_Active
, act
);
69 /**************************************************************************
71 **************************************************************************/
72 IPTR
Cycle__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
74 struct MUI_CycleData
*data
;
75 struct TagItem
*tag
, *tags
;
76 Object
*pageobj
, *imgobj
;
79 obj
= (Object
*) DoSuperNewTags
82 MUIA_Background
, MUII_ButtonBack
,
83 MUIA_InputMode
, MUIV_InputMode_RelVerify
,
86 MUIA_Group_Horiz
, TRUE
,
87 Child
, (IPTR
) (imgobj
= ImageObject
,
89 MUIA_Image_Spec
, (IPTR
) "6:17",
90 MUIA_Image_FreeVert
, TRUE
,
92 Child
, (IPTR
) (pageobj
= PageGroup
, End
),
93 TAG_MORE
, (IPTR
) msg
->ops_AttrList
);
98 data
= INST_DATA(cl
, obj
);
100 data
->pageobj
= pageobj
;
101 data
->imgobj
= imgobj
;
103 data
->pressedhook
.h_Entry
= HookEntry
;
104 data
->pressedhook
.h_SubEntry
= (HOOKFUNC
) PressedHookFunc
;
105 data
->pressedhook
.h_Data
= cl
;
107 /* parse initial taglist */
109 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
113 case MUIA_Cycle_Entries
:
114 data
->entries
= (const char **)tag
->ti_Data
;
117 case MUIA_Cycle_Active
:
118 data
->entries_active
= tag
->ti_Data
;
125 D(bug("Cycle_New: No Entries specified!\n"));
126 CoerceMethod(cl
, obj
, OM_DISPOSE
);
130 /* Count the number of entries */
131 for (i
= 0; data
->entries
[i
]; i
++)
136 MUIA_Text_Contents
, (IPTR
) data
->entries
[i
],
137 MUIA_Text_PreParse
, (IPTR
) "\033c", End
;
141 D(bug("Cycle_New: Could not create page object specified!\n"));
142 CoerceMethod(cl
, obj
, OM_DISPOSE
);
146 DoMethod(pageobj
, OM_ADDMEMBER
, (IPTR
) page
);
148 data
->entries_num
= i
;
150 if ((data
->entries_active
>= 0)
151 && (data
->entries_active
< data
->entries_num
))
153 set(pageobj
, MUIA_Group_ActivePage
, data
->entries_active
);
157 data
->entries_active
= 0;
161 DoMethod(obj
, MUIM_Notify
, MUIA_Pressed
, FALSE
,
162 (IPTR
) obj
, 2, MUIM_CallHook
, (IPTR
) & data
->pressedhook
);
164 DoMethod(imgobj
, MUIM_Notify
, MUIA_Pressed
, FALSE
,
165 (IPTR
) obj
, 3, MUIM_Set
, MUIA_Cycle_Active
, MUIV_Cycle_Active_Next
);
171 /**************************************************************************
173 **************************************************************************/
174 IPTR
Cycle__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
176 struct MUI_CycleData
*data
;
177 struct TagItem
*tag
, *tags
;
179 BOOL noforward
= TRUE
;
181 data
= INST_DATA(cl
, obj
);
183 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
187 case MUIA_Cycle_Active
:
188 l
= (LONG
) tag
->ti_Data
;
190 if (l
== MUIV_Cycle_Active_Next
)
192 l
= data
->entries_active
+ 1;
193 if (l
>= data
->entries_num
)
196 else if (l
== MUIV_Cycle_Active_Prev
)
198 l
= data
->entries_active
- 1;
200 l
= data
->entries_num
- 1;
203 if (l
>= 0 && l
< data
->entries_num
)
205 data
->entries_active
= l
;
206 set(data
->pageobj
, MUIA_Group_ActivePage
,
207 data
->entries_active
);
219 struct opSet ops
= *msg
;
220 struct TagItem tags
[] = {
221 {MUIA_Group_Forward
, FALSE
},
225 /* Zune must also be compilable with SAS C on Amiga */
226 tags
[1].ti_Data
= (IPTR
) msg
->ops_AttrList
;
228 ops
.ops_AttrList
= tags
;
230 return DoSuperMethodA(cl
, obj
, (Msg
) & ops
);
234 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
238 /**************************************************************************
240 **************************************************************************/
241 IPTR
Cycle__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
243 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
244 #define STORE *(msg->opg_Storage)
246 switch (msg
->opg_AttrID
)
248 case MUIA_Cycle_Active
:
249 STORE
= data
->entries_active
;
253 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
256 /**************************************************************************
258 **************************************************************************/
259 IPTR
Cycle__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
260 struct MUIP_Setup
*msg
)
262 struct MUI_CycleData
*data
;
264 if (!(DoSuperMethodA(cl
, obj
, (Msg
) msg
)))
267 data
= INST_DATA(cl
, obj
);
269 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
| IDCMP_RAWKEY
;
270 data
->ehn
.ehn_Priority
= 1;
271 data
->ehn
.ehn_Flags
= 0;
272 data
->ehn
.ehn_Object
= obj
;
273 data
->ehn
.ehn_Class
= cl
;
275 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) & data
->ehn
);
280 /**************************************************************************
282 **************************************************************************/
283 IPTR
Cycle__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
284 struct MUIP_Cleanup
*msg
)
286 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
288 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) & data
->ehn
);
290 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
293 static void KillPopupWin(Object
*obj
, struct MUI_CycleData
*data
)
295 struct MinList
*childlist
= NULL
;
296 Object
*child
, *cstate
;
300 CloseWindow(data
->popwin
);
306 zune_imspec_hide(data
->popbg
);
307 zune_imspec_cleanup(data
->popbg
);
311 get(data
->pageobj
, MUIA_Group_ChildList
, &childlist
);
313 cstate
= (Object
*) childlist
->mlh_Head
;
314 while ((child
= NextObject(&cstate
)))
318 get(child
, MUIA_UserData
, &text
);
322 zune_text_destroy(text
);
324 set(child
, MUIA_UserData
, 0);
327 if (data
->ehn
.ehn_Events
& IDCMP_MOUSEMOVE
)
329 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
331 data
->ehn
.ehn_Events
&= ~IDCMP_MOUSEMOVE
;
332 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
338 static void RenderPopupItem(Object
*obj
, struct MUI_CycleData
*data
,
341 struct MinList
*childlist
= NULL
;
342 struct RastPort
*saverp
;
343 Object
*child
, *cstate
;
345 WORD x1
, y1
, x2
, y2
, i
= which
;
347 get(data
->pageobj
, MUIA_Group_ChildList
, &childlist
);
348 cstate
= (Object
*) childlist
->mlh_Head
;
350 while ((child
= NextObject(&cstate
)) && i
--)
357 get(child
, MUIA_UserData
, &text
);
359 return; /* paranoia */
362 _rp(obj
) = data
->popwin
->RPort
;
364 x1
= data
->popitemoffx
;
365 x2
= x1
+ data
->popitemwidth
- 1;
366 y1
= data
->popitemoffy
+ which
* data
->popitemheight
;
367 y2
= y1
+ data
->popitemheight
- 1;
369 if (which
== data
->activepopitem
)
373 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
375 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_SHADOW
]);
376 RectFill(data
->popwin
->RPort
, x1
, y1
, x1
, y2
);
377 RectFill(data
->popwin
->RPort
, x1
+ 1, y1
, x2
- 1, y1
);
378 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_SHINE
]);
379 RectFill(data
->popwin
->RPort
, x2
, y1
, x2
, y2
);
380 RectFill(data
->popwin
->RPort
, x1
+ 1, y2
, x2
- 1, y2
);
385 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_FILL
]);
386 RectFill(data
->popwin
->RPort
, x1
+ off
, y1
+ off
, x2
- off
,
393 zune_imspec_draw(data
->popbg
, muiRenderInfo(obj
),
394 x1
, y1
, x2
- x1
+ 1, y2
- y1
+ 1, x1
, y1
, 0);
398 SetAPen(data
->popwin
->RPort
, 0);
399 RectFill(data
->popwin
->RPort
, x1
, y1
, x2
, y2
);
403 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_TEXT
]);
405 y1
+= POPITEM_EXTRAHEIGHT
/ 2;
406 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
411 zune_text_draw(text
, obj
, x1
, x2
, y1
);
417 static BOOL
MakePopupWin(Object
*obj
, struct MUI_CycleData
*data
)
419 const struct ZuneFrameGfx
*zframe
;
420 struct MinList
*childlist
= NULL
;
421 struct RastPort
*rp
, *saverp
;
422 Object
*child
, *cstate
;
423 WORD x
, y
, winx
, winy
, winw
, winh
, i
;
425 data
->popitemwidth
= 0;
426 data
->popitemheight
= 0;
428 get(data
->pageobj
, MUIA_Group_ChildList
, &childlist
);
429 cstate
= (Object
*) childlist
->mlh_Head
;
430 while ((child
= NextObject(&cstate
)))
432 set(child
, MUIA_UserData
, 0);
435 data
->popitemwidth
= _width(data
->pageobj
);
436 data
->popitemheight
= _height(data
->pageobj
);
438 data
->popitemwidth
+= POPITEM_EXTRAWIDTH
;
439 data
->popitemheight
+= POPITEM_EXTRAHEIGHT
;
441 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
443 data
->popitemwidth
+= 2;
444 data
->popitemheight
+= 2;
449 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
]);
452 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].innerLeft
+
456 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].innerTop
+
459 winw
= data
->popitemwidth
+ data
->popitemoffx
+
460 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].innerRight
+
463 winh
= data
->popitemheight
* data
->entries_num
+ data
->popitemoffy
+
464 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].
465 innerBottom
+ zframe
->ibottom
;
467 if ((winw
> _screen(obj
)->Width
) || (winh
> _screen(obj
)->Height
))
473 cstate
= (Object
*) childlist
->mlh_Head
;
474 while ((child
= NextObject(&cstate
)))
478 text
= zune_text_new("\33c", data
->entries
[i
++], ZTEXT_ARG_NONE
, 0);
482 zune_text_get_bounds(text
, obj
);
483 set(child
, MUIA_UserData
, (IPTR
) text
);
486 if (i
!= data
->entries_num
)
488 KillPopupWin(obj
, data
);
492 data
->popbg
= zune_imspec_setup(MUII_PopupBack
, muiRenderInfo(obj
));
494 zune_imspec_show(data
->popbg
, obj
);
496 winx
= _window(obj
)->LeftEdge
+ _mleft(data
->pageobj
) -
497 data
->popitemoffx
- POPITEM_EXTRAWIDTH
/ 2;
499 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_position
==
500 CYCLE_MENU_POSITION_BELOW
)
502 winy
= _window(obj
)->TopEdge
+ _bottom(obj
) + 1;
507 _window(obj
)->TopEdge
+ _mtop(data
->pageobj
) -
508 data
->popitemoffy
- POPITEM_EXTRAHEIGHT
/ 2 -
509 data
->entries_active
* data
->popitemheight
;
513 OpenWindowTags(NULL
, WA_CustomScreen
, (IPTR
) _screen(obj
), WA_Left
,
514 winx
, WA_Top
, winy
, WA_Width
, winw
, WA_Height
, winh
, WA_AutoAdjust
,
515 TRUE
, WA_Borderless
, TRUE
, WA_Activate
, FALSE
, WA_BackFill
,
516 (IPTR
) LAYERS_NOBACKFILL
, TAG_DONE
);
523 rp
= data
->popwin
->RPort
;
527 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0, winw
, winh
,
530 /* FIXME: Render with popup background */
534 zune_imspec_draw(data
->popbg
, muiRenderInfo(obj
),
535 zframe
->ileft
, zframe
->itop
,
536 winw
- zframe
->ileft
- zframe
->iright
,
537 winh
- zframe
->itop
- zframe
->ibottom
,
538 zframe
->ileft
, zframe
->itop
, 0);
543 RectFill(rp
, zframe
->ileft
, zframe
->itop
,
544 winw
- 1 - zframe
->iright
, winh
- 1 - zframe
->ibottom
);
547 x
= data
->popitemoffx
;
548 y
= data
->popitemoffy
+ POPITEM_EXTRAHEIGHT
/ 2;
550 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
556 cstate
= (Object
*) childlist
->mlh_Head
;
557 while ((child
= NextObject(&cstate
)))
561 get(child
, MUIA_UserData
, &text
);
563 SetAPen(_rp(obj
), _pens(obj
)[MPEN_TEXT
]);
564 if (text
) /* paranoia */
566 zune_text_draw(text
, obj
, x
, x
+ data
->popitemwidth
- 1, y
);
569 y
+= data
->popitemheight
;
574 data
->activepopitem
= -1;
580 /**************************************************************************
582 **************************************************************************/
583 IPTR
Cycle__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
584 struct MUIP_HandleEvent
*msg
)
586 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
587 BOOL fallthroughtomousemove
= FALSE
;
589 if (msg
->muikey
!= MUIKEY_NONE
)
592 data
->popwin
? data
->activepopitem
: data
->entries_active
;
593 int new_active
= old_active
;
598 case MUIKEY_WINDOW_CLOSE
:
601 KillPopupWin(obj
, data
);
607 if (data
->entries_num
<
608 muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_min_entries
)
610 /* fall through to MUIKEY_DOWN */
612 else if (!data
->popwin
)
614 if (MakePopupWin(obj
, data
))
616 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
618 data
->ehn
.ehn_Events
|= IDCMP_MOUSEMOVE
;
619 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
626 /* fall through to MUIKEY_DOWN */
629 else if (data
->popwin
)
631 KillPopupWin(obj
, data
);
632 if (new_active
!= -1)
634 set(obj
, MUIA_Cycle_Active
, new_active
);
639 /* no break here, because of fall-throughs above */
642 if (new_active
< data
->entries_num
- 1)
646 else if (!data
->popwin
)
659 else if (!data
->popwin
)
661 new_active
= data
->entries_num
- 1;
673 case MUIKEY_PAGEDOWN
:
675 new_active
= data
->entries_num
- 1;
680 if (new_active
!= old_active
)
684 data
->activepopitem
= new_active
;
686 if (old_active
!= -1)
687 RenderPopupItem(obj
, data
, old_active
);
688 if (new_active
!= -1)
689 RenderPopupItem(obj
, data
, new_active
);
694 set(obj
, MUIA_Cycle_Active
, new_active
);
700 return MUI_EventHandlerRC_Eat
;
706 muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_min_entries
)
711 switch (msg
->imsg
->Class
)
713 case IDCMP_MOUSEBUTTONS
:
714 switch (msg
->imsg
->Code
)
717 if (_between(_right(data
->imgobj
) + 1, msg
->imsg
->MouseX
,
719 && _between(_top(obj
), msg
->imsg
->MouseY
, _bottom(obj
))
720 && (muiAreaData(obj
)->mad_Flags
& MADF_CANDRAW
)
723 if (MakePopupWin(obj
, data
))
725 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
727 data
->ehn
.ehn_Events
|= IDCMP_MOUSEMOVE
;
728 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
731 fallthroughtomousemove
= TRUE
;
735 else if (data
->popwin
)
737 /* fall through to SELECTUP/MENUUP/MIDDLEUP */
751 KillPopupWin(obj
, data
);
752 if ((data
->activepopitem
!= -1) &&
753 ((msg
->imsg
->Code
== SELECTUP
)
754 || (msg
->imsg
->Code
== SELECTDOWN
)))
756 set(obj
, MUIA_Cycle_Active
, data
->activepopitem
);
758 return MUI_EventHandlerRC_Eat
;
765 if (!fallthroughtomousemove
)
770 case IDCMP_MOUSEMOVE
:
773 WORD x
= data
->popwin
->MouseX
;
774 WORD y
= data
->popwin
->MouseY
- data
->popitemoffy
;
777 if ((x
>= 0) && (y
>= 0) &&
778 (x
< data
->popwin
->Width
)
779 && (y
< data
->popitemheight
* data
->entries_num
))
781 newactive
= y
/ data
->popitemheight
;
784 if (newactive
!= data
->activepopitem
)
786 WORD oldactive
= data
->activepopitem
;
788 data
->activepopitem
= newactive
;
791 RenderPopupItem(obj
, data
, oldactive
);
793 RenderPopupItem(obj
, data
, newactive
);
797 return MUI_EventHandlerRC_Eat
;
806 /**************************************************************************
808 **************************************************************************/
809 IPTR
Cycle__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
810 struct MUIP_Hide
*msg
)
812 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
816 KillPopupWin(obj
, data
);
819 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
822 /**************************************************************************
823 MUIM_Export - to export an objects "contents" to a dataspace object.
824 **************************************************************************/
825 IPTR
Cycle__MUIM_Export(struct IClass
*cl
, Object
*obj
,
826 struct MUIP_Export
*msg
)
828 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
831 if ((id
= muiNotifyData(obj
)->mnd_ObjectID
))
833 LONG value
= data
->entries_active
;
834 DoMethod(msg
->dataspace
, MUIM_Dataspace_Add
,
835 (IPTR
) & value
, sizeof(value
), (IPTR
) id
);
840 /**************************************************************************
841 MUIM_Import - to import an objects "contents" from a dataspace object.
842 **************************************************************************/
843 IPTR
Cycle__MUIM_Import(struct IClass
*cl
, Object
*obj
,
844 struct MUIP_Import
*msg
)
849 if ((id
= muiNotifyData(obj
)->mnd_ObjectID
))
851 if ((s
= (LONG
*) DoMethod(msg
->dataspace
, MUIM_Dataspace_Find
,
854 set(obj
, MUIA_Cycle_Active
, *s
);
860 BOOPSI_DISPATCHER(IPTR
, Cycle_Dispatcher
, cl
, obj
, msg
)
862 switch (msg
->MethodID
)
865 return Cycle__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
867 return Cycle__OM_SET(cl
, obj
, (struct opSet
*)msg
);
869 return Cycle__OM_GET(cl
, obj
, (struct opGet
*)msg
);
871 return Cycle__MUIM_Setup(cl
, obj
, (APTR
) msg
);
873 return Cycle__MUIM_Cleanup(cl
, obj
, (APTR
) msg
);
875 return Cycle__MUIM_Hide(cl
, obj
, (APTR
) msg
);
876 case MUIM_HandleEvent
:
877 return Cycle__MUIM_HandleEvent(cl
, obj
, (APTR
) msg
);
879 return Cycle__MUIM_Export(cl
, obj
, (APTR
) msg
);
881 return Cycle__MUIM_Import(cl
, obj
, (APTR
) msg
);
884 return DoSuperMethodA(cl
, obj
, msg
);
886 BOOPSI_DISPATCHER_END
891 const struct __MUIBuiltinClass _MUI_Cycle_desc
=
895 sizeof(struct MUI_CycleData
),
896 (void *) Cycle_Dispatcher