2 Copyright © 2002-2014, 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 CONST_STRPTR default_entries
[] =
60 static void UpdateEntries(Object
*obj
, struct MUI_CycleData
*data
);
61 static void KillPopupWin(Object
*obj
, struct MUI_CycleData
*data
);
63 void PressedHookFunc(struct Hook
*hook
, Object
*obj
, APTR msg
)
65 struct MUI_CycleData
*data
;
66 Class
*cl
= (Class
*) hook
->h_Data
;
69 data
= INST_DATA(cl
, obj
);
71 act
= ++data
->entries_active
;
72 if (act
>= data
->entries_num
)
75 set(obj
, MUIA_Cycle_Active
, act
);
78 /**************************************************************************
80 **************************************************************************/
81 IPTR
Cycle__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
83 struct MUI_CycleData
*data
;
84 struct TagItem
*tag
, *tags
;
85 Object
*pageobj
, *imgobj
;
87 obj
= (Object
*) DoSuperNewTags
90 MUIA_Background
, MUII_ButtonBack
,
91 MUIA_InputMode
, MUIV_InputMode_RelVerify
,
94 MUIA_Group_Horiz
, TRUE
,
95 Child
, (IPTR
) (imgobj
= ImageObject
,
97 MUIA_Image_Spec
, (IPTR
) "6:17",
98 MUIA_Image_FreeVert
, TRUE
,
100 Child
, (IPTR
) (pageobj
= PageGroup
, End
),
101 TAG_MORE
, (IPTR
) msg
->ops_AttrList
);
106 data
= INST_DATA(cl
, obj
);
108 data
->pageobj
= pageobj
;
109 data
->imgobj
= imgobj
;
111 data
->pressedhook
.h_Entry
= HookEntry
;
112 data
->pressedhook
.h_SubEntry
= (HOOKFUNC
) PressedHookFunc
;
113 data
->pressedhook
.h_Data
= cl
;
115 data
->entries
= (const char **)default_entries
;
117 /* parse initial taglist */
119 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
123 case MUIA_Cycle_Entries
:
124 data
->entries
= (const char **)tag
->ti_Data
;
127 case MUIA_Cycle_Active
:
128 data
->entries_active
= tag
->ti_Data
;
133 UpdateEntries(obj
, data
);
135 if ((data
->entries_active
>= 0)
136 && (data
->entries_active
< data
->entries_num
))
138 set(pageobj
, MUIA_Group_ActivePage
, data
->entries_active
);
142 data
->entries_active
= 0;
146 DoMethod(obj
, MUIM_Notify
, MUIA_Pressed
, FALSE
,
147 (IPTR
) obj
, 2, MUIM_CallHook
, (IPTR
) & data
->pressedhook
);
149 DoMethod(imgobj
, MUIM_Notify
, MUIA_Pressed
, FALSE
,
150 (IPTR
) obj
, 3, MUIM_Set
, MUIA_Cycle_Active
, MUIV_Cycle_Active_Next
);
156 /**************************************************************************
158 **************************************************************************/
159 IPTR
Cycle__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
161 struct MUI_CycleData
*data
;
162 struct TagItem
*tag
, *tags
;
164 BOOL noforward
= TRUE
;
166 data
= INST_DATA(cl
, obj
);
168 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
172 case MUIA_Cycle_Entries
:
173 data
->entries
= (const char **)tag
->ti_Data
;
174 UpdateEntries(obj
, data
);
177 case MUIA_Cycle_Active
:
178 l
= (LONG
) tag
->ti_Data
;
180 if (l
== MUIV_Cycle_Active_Next
)
182 l
= data
->entries_active
+ 1;
183 if (l
>= data
->entries_num
)
186 else if (l
== MUIV_Cycle_Active_Prev
)
188 l
= data
->entries_active
- 1;
190 l
= data
->entries_num
- 1;
193 if (l
>= 0 && l
< data
->entries_num
)
195 data
->entries_active
= l
;
196 set(data
->pageobj
, MUIA_Group_ActivePage
,
197 data
->entries_active
);
209 struct opSet ops
= *msg
;
210 struct TagItem tags
[] = {
211 {MUIA_Group_Forward
, FALSE
},
215 /* Zune must also be compilable with SAS C on Amiga */
216 tags
[1].ti_Data
= (IPTR
) msg
->ops_AttrList
;
218 ops
.ops_AttrList
= tags
;
220 return DoSuperMethodA(cl
, obj
, (Msg
) & ops
);
224 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
228 /**************************************************************************
230 **************************************************************************/
231 IPTR
Cycle__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
233 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
234 #define STORE *(msg->opg_Storage)
236 switch (msg
->opg_AttrID
)
238 case MUIA_Cycle_Active
:
239 STORE
= data
->entries_active
;
243 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
246 /**************************************************************************
248 **************************************************************************/
249 IPTR
Cycle__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
250 struct MUIP_Setup
*msg
)
252 struct MUI_CycleData
*data
;
254 if (!(DoSuperMethodA(cl
, obj
, (Msg
) msg
)))
257 data
= INST_DATA(cl
, obj
);
259 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
| IDCMP_RAWKEY
;
260 data
->ehn
.ehn_Priority
= 1;
261 data
->ehn
.ehn_Flags
= 0;
262 data
->ehn
.ehn_Object
= obj
;
263 data
->ehn
.ehn_Class
= cl
;
265 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) & data
->ehn
);
270 /**************************************************************************
272 **************************************************************************/
273 IPTR
Cycle__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
274 struct MUIP_Cleanup
*msg
)
276 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
278 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) & data
->ehn
);
280 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
283 static void UpdateEntries(Object
*obj
, struct MUI_CycleData
*data
)
285 struct MinList
*childlist
= NULL
;
286 Object
*page
, *cstate
;
289 /* Ensure list isn't displayed while we update it */
290 KillPopupWin(obj
, data
);
292 /* Destroy old entries */
293 get(data
->pageobj
, MUIA_Group_ChildList
, &childlist
);
295 cstate
= (Object
*) childlist
->mlh_Head
;
296 while ((page
= NextObject(&cstate
)))
298 DoMethod(data
->pageobj
, OM_REMMEMBER
, (IPTR
) page
);
299 DoMethod(page
, OM_DISPOSE
);
302 /* Count the number of entries */
303 for (i
= 0; data
->entries
[i
]; i
++)
306 MUIA_Text_Contents
, (IPTR
) data
->entries
[i
],
307 MUIA_Text_PreParse
, (IPTR
) "\033c", End
;
311 D(bug("Cycle_New: Could not create page object specified!\n"));
315 DoMethod(data
->pageobj
, OM_ADDMEMBER
, (IPTR
) page
);
317 data
->entries_num
= i
;
320 static void KillPopupWin(Object
*obj
, struct MUI_CycleData
*data
)
322 struct MinList
*childlist
= NULL
;
323 Object
*child
, *cstate
;
327 CloseWindow(data
->popwin
);
333 zune_imspec_hide(data
->popbg
);
334 zune_imspec_cleanup(data
->popbg
);
338 get(data
->pageobj
, MUIA_Group_ChildList
, &childlist
);
340 cstate
= (Object
*) childlist
->mlh_Head
;
341 while ((child
= NextObject(&cstate
)))
345 get(child
, MUIA_UserData
, &text
);
349 zune_text_destroy(text
);
351 set(child
, MUIA_UserData
, 0);
354 if (data
->ehn
.ehn_Events
& IDCMP_MOUSEMOVE
)
356 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
358 data
->ehn
.ehn_Events
&= ~IDCMP_MOUSEMOVE
;
359 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
365 static void RenderPopupItem(Object
*obj
, struct MUI_CycleData
*data
,
368 struct MinList
*childlist
= NULL
;
369 struct RastPort
*saverp
;
370 Object
*child
, *cstate
;
372 WORD x1
, y1
, x2
, y2
, i
= which
;
374 get(data
->pageobj
, MUIA_Group_ChildList
, &childlist
);
375 cstate
= (Object
*) childlist
->mlh_Head
;
377 while ((child
= NextObject(&cstate
)) && i
--)
384 get(child
, MUIA_UserData
, &text
);
386 return; /* paranoia */
389 _rp(obj
) = data
->popwin
->RPort
;
391 x1
= data
->popitemoffx
;
392 x2
= x1
+ data
->popitemwidth
- 1;
393 y1
= data
->popitemoffy
+ which
* data
->popitemheight
;
394 y2
= y1
+ data
->popitemheight
- 1;
396 if (which
== data
->activepopitem
)
400 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
402 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_SHADOW
]);
403 RectFill(data
->popwin
->RPort
, x1
, y1
, x1
, y2
);
404 RectFill(data
->popwin
->RPort
, x1
+ 1, y1
, x2
- 1, y1
);
405 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_SHINE
]);
406 RectFill(data
->popwin
->RPort
, x2
, y1
, x2
, y2
);
407 RectFill(data
->popwin
->RPort
, x1
+ 1, y2
, x2
- 1, y2
);
412 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_FILL
]);
413 RectFill(data
->popwin
->RPort
, x1
+ off
, y1
+ off
, x2
- off
,
420 zune_imspec_draw(data
->popbg
, muiRenderInfo(obj
),
421 x1
, y1
, x2
- x1
+ 1, y2
- y1
+ 1, x1
, y1
, 0);
425 SetAPen(data
->popwin
->RPort
, 0);
426 RectFill(data
->popwin
->RPort
, x1
, y1
, x2
, y2
);
430 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_TEXT
]);
432 y1
+= POPITEM_EXTRAHEIGHT
/ 2;
433 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
438 zune_text_draw(text
, obj
, x1
, x2
, y1
);
444 static BOOL
MakePopupWin(Object
*obj
, struct MUI_CycleData
*data
)
446 const struct ZuneFrameGfx
*zframe
;
447 struct MinList
*childlist
= NULL
;
448 struct RastPort
*rp
, *saverp
;
449 Object
*child
, *cstate
;
450 WORD x
, y
, winx
, winy
, winw
, winh
, i
;
452 data
->popitemwidth
= 0;
453 data
->popitemheight
= 0;
455 get(data
->pageobj
, MUIA_Group_ChildList
, &childlist
);
456 cstate
= (Object
*) childlist
->mlh_Head
;
457 while ((child
= NextObject(&cstate
)))
459 set(child
, MUIA_UserData
, 0);
462 data
->popitemwidth
= _width(data
->pageobj
);
463 data
->popitemheight
= _height(data
->pageobj
);
465 data
->popitemwidth
+= POPITEM_EXTRAWIDTH
;
466 data
->popitemheight
+= POPITEM_EXTRAHEIGHT
;
468 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
470 data
->popitemwidth
+= 2;
471 data
->popitemheight
+= 2;
476 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
]);
479 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].innerLeft
+
483 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].innerTop
+
486 winw
= data
->popitemwidth
+ data
->popitemoffx
+
487 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].innerRight
+
490 winh
= data
->popitemheight
* data
->entries_num
+ data
->popitemoffy
+
491 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].
492 innerBottom
+ zframe
->ibottom
;
494 if ((winw
> _screen(obj
)->Width
) || (winh
> _screen(obj
)->Height
))
500 cstate
= (Object
*) childlist
->mlh_Head
;
501 while ((child
= NextObject(&cstate
)))
505 text
= zune_text_new("\33c", data
->entries
[i
++], ZTEXT_ARG_NONE
, 0);
509 zune_text_get_bounds(text
, obj
);
510 set(child
, MUIA_UserData
, (IPTR
) text
);
513 if (i
!= data
->entries_num
)
515 KillPopupWin(obj
, data
);
519 data
->popbg
= zune_imspec_setup(MUII_PopupBack
, muiRenderInfo(obj
));
521 zune_imspec_show(data
->popbg
, obj
);
523 winx
= _window(obj
)->LeftEdge
+ _mleft(data
->pageobj
) -
524 data
->popitemoffx
- POPITEM_EXTRAWIDTH
/ 2;
526 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_position
==
527 CYCLE_MENU_POSITION_BELOW
)
529 winy
= _window(obj
)->TopEdge
+ _bottom(obj
) + 1;
534 _window(obj
)->TopEdge
+ _mtop(data
->pageobj
) -
535 data
->popitemoffy
- POPITEM_EXTRAHEIGHT
/ 2 -
536 data
->entries_active
* data
->popitemheight
;
540 OpenWindowTags(NULL
, WA_CustomScreen
, (IPTR
) _screen(obj
), WA_Left
,
541 winx
, WA_Top
, winy
, WA_Width
, winw
, WA_Height
, winh
, WA_AutoAdjust
,
542 TRUE
, WA_Borderless
, TRUE
, WA_Activate
, FALSE
, WA_BackFill
,
543 (IPTR
) LAYERS_NOBACKFILL
, TAG_DONE
);
550 rp
= data
->popwin
->RPort
;
554 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0, winw
, winh
,
557 /* FIXME: Render with popup background */
561 zune_imspec_draw(data
->popbg
, muiRenderInfo(obj
),
562 zframe
->ileft
, zframe
->itop
,
563 winw
- zframe
->ileft
- zframe
->iright
,
564 winh
- zframe
->itop
- zframe
->ibottom
,
565 zframe
->ileft
, zframe
->itop
, 0);
570 RectFill(rp
, zframe
->ileft
, zframe
->itop
,
571 winw
- 1 - zframe
->iright
, winh
- 1 - zframe
->ibottom
);
574 x
= data
->popitemoffx
;
575 y
= data
->popitemoffy
+ POPITEM_EXTRAHEIGHT
/ 2;
577 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
583 cstate
= (Object
*) childlist
->mlh_Head
;
584 while ((child
= NextObject(&cstate
)))
588 get(child
, MUIA_UserData
, &text
);
590 SetAPen(_rp(obj
), _pens(obj
)[MPEN_TEXT
]);
591 if (text
) /* paranoia */
593 zune_text_draw(text
, obj
, x
, x
+ data
->popitemwidth
- 1, y
);
596 y
+= data
->popitemheight
;
601 data
->activepopitem
= -1;
607 /**************************************************************************
609 **************************************************************************/
610 IPTR
Cycle__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
611 struct MUIP_HandleEvent
*msg
)
613 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
614 BOOL fallthroughtomousemove
= FALSE
;
616 if (msg
->muikey
!= MUIKEY_NONE
)
619 data
->popwin
? data
->activepopitem
: data
->entries_active
;
620 int new_active
= old_active
;
625 case MUIKEY_WINDOW_CLOSE
:
628 KillPopupWin(obj
, data
);
634 if (data
->entries_num
<
635 muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_min_entries
)
637 /* fall through to MUIKEY_DOWN */
639 else if (!data
->popwin
)
641 if (MakePopupWin(obj
, data
))
643 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
645 data
->ehn
.ehn_Events
|= IDCMP_MOUSEMOVE
;
646 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
653 /* fall through to MUIKEY_DOWN */
656 else if (data
->popwin
)
658 KillPopupWin(obj
, data
);
659 if (new_active
!= -1)
661 set(obj
, MUIA_Cycle_Active
, new_active
);
666 /* no break here, because of fall-throughs above */
669 if (new_active
< data
->entries_num
- 1)
673 else if (!data
->popwin
)
686 else if (!data
->popwin
)
688 new_active
= data
->entries_num
- 1;
700 case MUIKEY_PAGEDOWN
:
702 new_active
= data
->entries_num
- 1;
707 if (new_active
!= old_active
)
711 data
->activepopitem
= new_active
;
713 if (old_active
!= -1)
714 RenderPopupItem(obj
, data
, old_active
);
715 if (new_active
!= -1)
716 RenderPopupItem(obj
, data
, new_active
);
721 set(obj
, MUIA_Cycle_Active
, new_active
);
727 return MUI_EventHandlerRC_Eat
;
733 muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_min_entries
)
738 switch (msg
->imsg
->Class
)
740 case IDCMP_MOUSEBUTTONS
:
741 switch (msg
->imsg
->Code
)
744 if (_between(_right(data
->imgobj
) + 1, msg
->imsg
->MouseX
,
746 && _between(_top(obj
), msg
->imsg
->MouseY
, _bottom(obj
))
747 && (muiAreaData(obj
)->mad_Flags
& MADF_CANDRAW
)
750 if (MakePopupWin(obj
, data
))
752 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
754 data
->ehn
.ehn_Events
|= IDCMP_MOUSEMOVE
;
755 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
758 fallthroughtomousemove
= TRUE
;
762 else if (data
->popwin
)
764 /* fall through to SELECTUP/MENUUP/MIDDLEUP */
778 KillPopupWin(obj
, data
);
779 if ((data
->activepopitem
!= -1) &&
780 ((msg
->imsg
->Code
== SELECTUP
)
781 || (msg
->imsg
->Code
== SELECTDOWN
)))
783 set(obj
, MUIA_Cycle_Active
, data
->activepopitem
);
785 return MUI_EventHandlerRC_Eat
;
792 if (!fallthroughtomousemove
)
797 case IDCMP_MOUSEMOVE
:
800 WORD x
= data
->popwin
->MouseX
;
801 WORD y
= data
->popwin
->MouseY
- data
->popitemoffy
;
804 if ((x
>= 0) && (y
>= 0) &&
805 (x
< data
->popwin
->Width
)
806 && (y
< data
->popitemheight
* data
->entries_num
))
808 newactive
= y
/ data
->popitemheight
;
811 if (newactive
!= data
->activepopitem
)
813 WORD oldactive
= data
->activepopitem
;
815 data
->activepopitem
= newactive
;
818 RenderPopupItem(obj
, data
, oldactive
);
820 RenderPopupItem(obj
, data
, newactive
);
824 return MUI_EventHandlerRC_Eat
;
833 /**************************************************************************
835 **************************************************************************/
836 IPTR
Cycle__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
837 struct MUIP_Hide
*msg
)
839 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
843 KillPopupWin(obj
, data
);
846 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
849 /**************************************************************************
850 MUIM_Export - to export an object's "contents" to a dataspace object.
851 **************************************************************************/
852 IPTR
Cycle__MUIM_Export(struct IClass
*cl
, Object
*obj
,
853 struct MUIP_Export
*msg
)
855 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
858 if ((id
= muiNotifyData(obj
)->mnd_ObjectID
))
860 LONG value
= data
->entries_active
;
861 DoMethod(msg
->dataspace
, MUIM_Dataspace_Add
,
862 (IPTR
) & value
, sizeof(value
), (IPTR
) id
);
867 /**************************************************************************
868 MUIM_Import - to import an object's "contents" from a dataspace object.
869 **************************************************************************/
870 IPTR
Cycle__MUIM_Import(struct IClass
*cl
, Object
*obj
,
871 struct MUIP_Import
*msg
)
876 if ((id
= muiNotifyData(obj
)->mnd_ObjectID
))
878 if ((s
= (LONG
*) DoMethod(msg
->dataspace
, MUIM_Dataspace_Find
,
881 set(obj
, MUIA_Cycle_Active
, *s
);
887 BOOPSI_DISPATCHER(IPTR
, Cycle_Dispatcher
, cl
, obj
, msg
)
889 switch (msg
->MethodID
)
892 return Cycle__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
894 return Cycle__OM_SET(cl
, obj
, (struct opSet
*)msg
);
896 return Cycle__OM_GET(cl
, obj
, (struct opGet
*)msg
);
898 return Cycle__MUIM_Setup(cl
, obj
, (APTR
) msg
);
900 return Cycle__MUIM_Cleanup(cl
, obj
, (APTR
) msg
);
902 return Cycle__MUIM_Hide(cl
, obj
, (APTR
) msg
);
903 case MUIM_HandleEvent
:
904 return Cycle__MUIM_HandleEvent(cl
, obj
, (APTR
) msg
);
906 return Cycle__MUIM_Export(cl
, obj
, (APTR
) msg
);
908 return Cycle__MUIM_Import(cl
, obj
, (APTR
) msg
);
911 return DoSuperMethodA(cl
, obj
, msg
);
913 BOOPSI_DISPATCHER_END
918 const struct __MUIBuiltinClass _MUI_Cycle_desc
=
922 sizeof(struct MUI_CycleData
),
923 (void *) Cycle_Dispatcher