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
;
167 data
= INST_DATA(cl
, obj
);
169 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
173 case MUIA_Cycle_Entries
:
174 data
->entries
= (const char **)tag
->ti_Data
;
175 DoMethod(data
->pageobj
, MUIM_Group_InitChange
);
176 UpdateEntries(obj
, data
);
177 DoMethod(data
->pageobj
, MUIM_Group_ExitChange
);
179 data
->entries_active
= 0;
180 set(data
->pageobj
, MUIA_Group_ActivePage
,
181 data
->entries_active
);
184 case MUIA_Cycle_Active
:
185 l
= (LONG
) tag
->ti_Data
;
187 if (l
== MUIV_Cycle_Active_Next
)
189 l
= data
->entries_active
+ 1;
190 if (l
>= data
->entries_num
)
193 else if (l
== MUIV_Cycle_Active_Prev
)
195 l
= data
->entries_active
- 1;
197 l
= data
->entries_num
- 1;
200 if (l
>= 0 && l
< data
->entries_num
)
202 data
->entries_active
= l
;
203 set(data
->pageobj
, MUIA_Group_ActivePage
,
204 data
->entries_active
);
216 struct TagItem tags
[] = {
217 {MUIA_Group_Forward
, FALSE
},
218 {TAG_MORE
, (IPTR
)msg
->ops_AttrList
}
220 supMsg
.MethodID
= msg
->MethodID
;
221 supMsg
.ops_AttrList
= tags
;
222 supMsg
.ops_GInfo
= msg
->ops_GInfo
;
224 return DoSuperMethodA(cl
, obj
, (Msg
) & supMsg
);
228 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
232 /**************************************************************************
234 **************************************************************************/
235 IPTR
Cycle__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
237 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
238 #define STORE *(msg->opg_Storage)
240 switch (msg
->opg_AttrID
)
242 case MUIA_Cycle_Active
:
243 STORE
= data
->entries_active
;
247 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
250 /**************************************************************************
252 **************************************************************************/
253 IPTR
Cycle__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
254 struct MUIP_Setup
*msg
)
256 struct MUI_CycleData
*data
;
258 if (!(DoSuperMethodA(cl
, obj
, (Msg
) msg
)))
261 data
= INST_DATA(cl
, obj
);
263 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
| IDCMP_RAWKEY
;
264 data
->ehn
.ehn_Priority
= 1;
265 data
->ehn
.ehn_Flags
= 0;
266 data
->ehn
.ehn_Object
= obj
;
267 data
->ehn
.ehn_Class
= cl
;
269 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) & data
->ehn
);
274 /**************************************************************************
276 **************************************************************************/
277 IPTR
Cycle__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
278 struct MUIP_Cleanup
*msg
)
280 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
282 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) & data
->ehn
);
284 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
287 static void UpdateEntries(Object
*obj
, struct MUI_CycleData
*data
)
289 struct MinList
*childlist
= NULL
;
290 Object
*page
, *cstate
;
293 /* Ensure list isn't displayed while we update it */
294 KillPopupWin(obj
, data
);
296 /* Destroy old entries */
297 get(data
->pageobj
, MUIA_Group_ChildList
, &childlist
);
299 cstate
= (Object
*) childlist
->mlh_Head
;
300 while ((page
= NextObject(&cstate
)))
302 DoMethod(data
->pageobj
, OM_REMMEMBER
, (IPTR
) page
);
303 DoMethod(page
, OM_DISPOSE
);
306 /* Count the number of entries */
307 for (i
= 0; data
->entries
&& data
->entries
[i
]; i
++)
310 MUIA_Text_Contents
, (IPTR
) data
->entries
[i
],
311 MUIA_Text_PreParse
, (IPTR
) "\033c", End
;
315 D(bug("Cycle_New: Could not create page object specified!\n"));
319 DoMethod(data
->pageobj
, OM_ADDMEMBER
, (IPTR
) page
);
321 data
->entries_num
= i
;
324 static void KillPopupWin(Object
*obj
, struct MUI_CycleData
*data
)
326 struct MinList
*childlist
= NULL
;
327 Object
*child
, *cstate
;
331 CloseWindow(data
->popwin
);
337 zune_imspec_hide(data
->popbg
);
338 zune_imspec_cleanup(data
->popbg
);
342 get(data
->pageobj
, MUIA_Group_ChildList
, &childlist
);
344 cstate
= (Object
*) childlist
->mlh_Head
;
345 while ((child
= NextObject(&cstate
)))
349 get(child
, MUIA_UserData
, &text
);
353 zune_text_destroy(text
);
355 set(child
, MUIA_UserData
, 0);
358 if (data
->ehn
.ehn_Events
& IDCMP_MOUSEMOVE
)
360 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
362 data
->ehn
.ehn_Events
&= ~IDCMP_MOUSEMOVE
;
363 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
369 static void RenderPopupItem(Object
*obj
, struct MUI_CycleData
*data
,
372 struct MinList
*childlist
= NULL
;
373 struct RastPort
*saverp
;
374 Object
*child
, *cstate
;
376 WORD x1
, y1
, x2
, y2
, i
= which
;
378 get(data
->pageobj
, MUIA_Group_ChildList
, &childlist
);
379 cstate
= (Object
*) childlist
->mlh_Head
;
381 while ((child
= NextObject(&cstate
)) && i
--)
388 get(child
, MUIA_UserData
, &text
);
390 return; /* paranoia */
393 _rp(obj
) = data
->popwin
->RPort
;
395 x1
= data
->popitemoffx
;
396 x2
= x1
+ data
->popitemwidth
- 1;
397 y1
= data
->popitemoffy
+ which
* data
->popitemheight
;
398 y2
= y1
+ data
->popitemheight
- 1;
400 if (which
== data
->activepopitem
)
404 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
406 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_SHADOW
]);
407 RectFill(data
->popwin
->RPort
, x1
, y1
, x1
, y2
);
408 RectFill(data
->popwin
->RPort
, x1
+ 1, y1
, x2
- 1, y1
);
409 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_SHINE
]);
410 RectFill(data
->popwin
->RPort
, x2
, y1
, x2
, y2
);
411 RectFill(data
->popwin
->RPort
, x1
+ 1, y2
, x2
- 1, y2
);
416 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_FILL
]);
417 RectFill(data
->popwin
->RPort
, x1
+ off
, y1
+ off
, x2
- off
,
424 zune_imspec_draw(data
->popbg
, muiRenderInfo(obj
),
425 x1
, y1
, x2
- x1
+ 1, y2
- y1
+ 1, x1
, y1
, 0);
429 SetAPen(data
->popwin
->RPort
, 0);
430 RectFill(data
->popwin
->RPort
, x1
, y1
, x2
, y2
);
434 SetAPen(data
->popwin
->RPort
, _pens(obj
)[MPEN_TEXT
]);
436 y1
+= POPITEM_EXTRAHEIGHT
/ 2;
437 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
442 zune_text_draw(text
, obj
, x1
, x2
, y1
);
448 static BOOL
MakePopupWin(Object
*obj
, struct MUI_CycleData
*data
)
450 const struct ZuneFrameGfx
*zframe
;
451 struct MinList
*childlist
= NULL
;
452 struct RastPort
*rp
, *saverp
;
453 Object
*child
, *cstate
;
454 WORD x
, y
, winx
, winy
, winw
, winh
, i
;
456 data
->popitemwidth
= 0;
457 data
->popitemheight
= 0;
459 get(data
->pageobj
, MUIA_Group_ChildList
, &childlist
);
460 cstate
= (Object
*) childlist
->mlh_Head
;
461 while ((child
= NextObject(&cstate
)))
463 set(child
, MUIA_UserData
, 0);
466 data
->popitemwidth
= _width(data
->pageobj
);
467 data
->popitemheight
= _height(data
->pageobj
);
469 data
->popitemwidth
+= POPITEM_EXTRAWIDTH
;
470 data
->popitemheight
+= POPITEM_EXTRAHEIGHT
;
472 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
474 data
->popitemwidth
+= 2;
475 data
->popitemheight
+= 2;
480 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
]);
483 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].innerLeft
+
487 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].innerTop
+
490 winw
= data
->popitemwidth
+ data
->popitemoffx
+
491 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].innerRight
+
494 winh
= data
->popitemheight
* data
->entries_num
+ data
->popitemoffy
+
495 muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_PopUp
].
496 innerBottom
+ zframe
->ibottom
;
498 if ((winw
> _screen(obj
)->Width
) || (winh
> _screen(obj
)->Height
))
504 cstate
= (Object
*) childlist
->mlh_Head
;
505 while ((child
= NextObject(&cstate
)))
509 text
= zune_text_new("\33c", data
->entries
[i
++], ZTEXT_ARG_NONE
, 0);
513 zune_text_get_bounds(text
, obj
);
514 set(child
, MUIA_UserData
, (IPTR
) text
);
517 if (i
!= data
->entries_num
)
519 KillPopupWin(obj
, data
);
523 data
->popbg
= zune_imspec_setup(MUII_PopupBack
, muiRenderInfo(obj
));
525 zune_imspec_show(data
->popbg
, obj
);
527 winx
= _window(obj
)->LeftEdge
+ _mleft(data
->pageobj
) -
528 data
->popitemoffx
- POPITEM_EXTRAWIDTH
/ 2;
530 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_position
==
531 CYCLE_MENU_POSITION_BELOW
)
533 winy
= _window(obj
)->TopEdge
+ _bottom(obj
) + 1;
538 _window(obj
)->TopEdge
+ _mtop(data
->pageobj
) -
539 data
->popitemoffy
- POPITEM_EXTRAHEIGHT
/ 2 -
540 data
->entries_active
* data
->popitemheight
;
544 OpenWindowTags(NULL
, WA_CustomScreen
, (IPTR
) _screen(obj
), WA_Left
,
545 winx
, WA_Top
, winy
, WA_Width
, winw
, WA_Height
, winh
, WA_AutoAdjust
,
546 TRUE
, WA_Borderless
, TRUE
, WA_Activate
, FALSE
, WA_BackFill
,
547 (IPTR
) LAYERS_NOBACKFILL
, TAG_DONE
);
554 rp
= data
->popwin
->RPort
;
558 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0, winw
, winh
,
561 /* FIXME: Render with popup background */
565 zune_imspec_draw(data
->popbg
, muiRenderInfo(obj
),
566 zframe
->ileft
, zframe
->itop
,
567 winw
- zframe
->ileft
- zframe
->iright
,
568 winh
- zframe
->itop
- zframe
->ibottom
,
569 zframe
->ileft
, zframe
->itop
, 0);
574 RectFill(rp
, zframe
->ileft
, zframe
->itop
,
575 winw
- 1 - zframe
->iright
, winh
- 1 - zframe
->ibottom
);
578 x
= data
->popitemoffx
;
579 y
= data
->popitemoffy
+ POPITEM_EXTRAHEIGHT
/ 2;
581 if (muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_recessed_entries
)
587 cstate
= (Object
*) childlist
->mlh_Head
;
588 while ((child
= NextObject(&cstate
)))
592 get(child
, MUIA_UserData
, &text
);
594 SetAPen(_rp(obj
), _pens(obj
)[MPEN_TEXT
]);
595 if (text
) /* paranoia */
597 zune_text_draw(text
, obj
, x
, x
+ data
->popitemwidth
- 1, y
);
600 y
+= data
->popitemheight
;
605 data
->activepopitem
= -1;
611 /**************************************************************************
613 **************************************************************************/
614 IPTR
Cycle__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
615 struct MUIP_HandleEvent
*msg
)
617 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
618 BOOL fallthroughtomousemove
= FALSE
;
620 if (msg
->muikey
!= MUIKEY_NONE
)
623 data
->popwin
? data
->activepopitem
: data
->entries_active
;
624 int new_active
= old_active
;
629 case MUIKEY_WINDOW_CLOSE
:
632 KillPopupWin(obj
, data
);
638 if (data
->entries_num
<
639 muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_min_entries
)
641 /* fall through to MUIKEY_DOWN */
643 else if (!data
->popwin
)
645 if (MakePopupWin(obj
, data
))
647 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
649 data
->ehn
.ehn_Events
|= IDCMP_MOUSEMOVE
;
650 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
657 /* fall through to MUIKEY_DOWN */
660 else if (data
->popwin
)
662 KillPopupWin(obj
, data
);
663 if (new_active
!= -1)
665 set(obj
, MUIA_Cycle_Active
, new_active
);
670 /* no break here, because of fall-throughs above */
673 if (new_active
< data
->entries_num
- 1)
677 else if (!data
->popwin
)
690 else if (!data
->popwin
)
692 new_active
= data
->entries_num
- 1;
704 case MUIKEY_PAGEDOWN
:
706 new_active
= data
->entries_num
- 1;
711 if (new_active
!= old_active
)
715 data
->activepopitem
= new_active
;
717 if (old_active
!= -1)
718 RenderPopupItem(obj
, data
, old_active
);
719 if (new_active
!= -1)
720 RenderPopupItem(obj
, data
, new_active
);
725 set(obj
, MUIA_Cycle_Active
, new_active
);
731 return MUI_EventHandlerRC_Eat
;
737 muiGlobalInfo(obj
)->mgi_Prefs
->cycle_menu_min_entries
)
742 switch (msg
->imsg
->Class
)
744 case IDCMP_MOUSEBUTTONS
:
745 switch (msg
->imsg
->Code
)
748 if (_between(_right(data
->imgobj
) + 1, msg
->imsg
->MouseX
,
750 && _between(_top(obj
), msg
->imsg
->MouseY
, _bottom(obj
))
751 && (muiAreaData(obj
)->mad_Flags
& MADF_CANDRAW
)
754 if (MakePopupWin(obj
, data
))
756 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
758 data
->ehn
.ehn_Events
|= IDCMP_MOUSEMOVE
;
759 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
762 fallthroughtomousemove
= TRUE
;
766 else if (data
->popwin
)
768 /* fall through to SELECTUP/MENUUP/MIDDLEUP */
782 KillPopupWin(obj
, data
);
783 if ((data
->activepopitem
!= -1) &&
784 ((msg
->imsg
->Code
== SELECTUP
)
785 || (msg
->imsg
->Code
== SELECTDOWN
)))
787 set(obj
, MUIA_Cycle_Active
, data
->activepopitem
);
789 return MUI_EventHandlerRC_Eat
;
796 if (!fallthroughtomousemove
)
801 case IDCMP_MOUSEMOVE
:
804 WORD x
= data
->popwin
->MouseX
;
805 WORD y
= data
->popwin
->MouseY
- data
->popitemoffy
;
808 if ((x
>= 0) && (y
>= 0) &&
809 (x
< data
->popwin
->Width
)
810 && (y
< data
->popitemheight
* data
->entries_num
))
812 newactive
= y
/ data
->popitemheight
;
815 if (newactive
!= data
->activepopitem
)
817 WORD oldactive
= data
->activepopitem
;
819 data
->activepopitem
= newactive
;
822 RenderPopupItem(obj
, data
, oldactive
);
824 RenderPopupItem(obj
, data
, newactive
);
828 return MUI_EventHandlerRC_Eat
;
837 /**************************************************************************
839 **************************************************************************/
840 IPTR
Cycle__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
841 struct MUIP_Hide
*msg
)
843 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
847 KillPopupWin(obj
, data
);
850 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
853 /**************************************************************************
854 MUIM_Export - to export an object's "contents" to a dataspace object.
855 **************************************************************************/
856 IPTR
Cycle__MUIM_Export(struct IClass
*cl
, Object
*obj
,
857 struct MUIP_Export
*msg
)
859 struct MUI_CycleData
*data
= INST_DATA(cl
, obj
);
862 if ((id
= muiNotifyData(obj
)->mnd_ObjectID
))
864 LONG value
= data
->entries_active
;
865 DoMethod(msg
->dataspace
, MUIM_Dataspace_Add
,
866 (IPTR
) & value
, sizeof(value
), (IPTR
) id
);
871 /**************************************************************************
872 MUIM_Import - to import an object's "contents" from a dataspace object.
873 **************************************************************************/
874 IPTR
Cycle__MUIM_Import(struct IClass
*cl
, Object
*obj
,
875 struct MUIP_Import
*msg
)
880 if ((id
= muiNotifyData(obj
)->mnd_ObjectID
))
882 if ((s
= (LONG
*) DoMethod(msg
->dataspace
, MUIM_Dataspace_Find
,
885 set(obj
, MUIA_Cycle_Active
, *s
);
891 BOOPSI_DISPATCHER(IPTR
, Cycle_Dispatcher
, cl
, obj
, msg
)
893 switch (msg
->MethodID
)
896 return Cycle__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
898 return Cycle__OM_SET(cl
, obj
, (struct opSet
*)msg
);
900 return Cycle__OM_GET(cl
, obj
, (struct opGet
*)msg
);
902 return Cycle__MUIM_Setup(cl
, obj
, (APTR
) msg
);
904 return Cycle__MUIM_Cleanup(cl
, obj
, (APTR
) msg
);
906 return Cycle__MUIM_Hide(cl
, obj
, (APTR
) msg
);
907 case MUIM_HandleEvent
:
908 return Cycle__MUIM_HandleEvent(cl
, obj
, (APTR
) msg
);
910 return Cycle__MUIM_Export(cl
, obj
, (APTR
) msg
);
912 return Cycle__MUIM_Import(cl
, obj
, (APTR
) msg
);
915 return DoSuperMethodA(cl
, obj
, msg
);
917 BOOPSI_DISPATCHER_END
922 const struct __MUIBuiltinClass _MUI_Cycle_desc
=
926 sizeof(struct MUI_CycleData
),
927 (void *) Cycle_Dispatcher