revert between 56095 -> 55830 in arch
[AROS.git] / workbench / libs / asl / cycleclass.c
blob1a79512a7d21d77397b19c03a1f0fe93c76b9468
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: english
7 */
9 #include <proto/alib.h>
10 #include <proto/exec.h>
11 #include <proto/dos.h>
12 #include <proto/utility.h>
13 #include <proto/intuition.h>
14 #include <proto/graphics.h>
15 #include <proto/cybergraphics.h>
16 #include <exec/memory.h>
17 #include <intuition/screens.h>
18 #include <intuition/icclass.h>
19 #include <intuition/cghooks.h>
20 #include <intuition/imageclass.h>
21 #include <intuition/gadgetclass.h>
22 #include <graphics/gfx.h>
23 #include <cybergraphx/cybergraphics.h>
25 #include <string.h>
27 #include "asl_intern.h"
28 #include "layout.h"
30 #define SDEBUG 0
31 #define DEBUG 0
33 #include <aros/debug.h>
35 #define CLASS_ASLBASE ((struct AslBase_intern *)cl->cl_UserData)
36 #define HOOK_ASLBASE ((struct AslBase_intern *)hook->h_Data)
38 #define AslBase CLASS_ASLBASE
40 /********************** ASL CYCLE CLASS **************************************************/
42 #define CYCLEIMAGEWIDTH 19
43 #define ARROWWIDTH 7
44 #define ARROWHEIGHT 4
46 #define ARROW_DOWN 1
47 #define ARROW_UP 2
49 /* it is possible to scroll faster through the
50 ** popup after TURBOCOUNTDOWN intuiticks
51 ** (= 1/10 sec) by moving around the mouse
52 ** (to force mousemove events to be sent to
53 ** the gadget)
56 #define TURBOCOUNTDOWN 5
58 /***********************************************************************************/
60 IPTR AslCycle__OM_SET(Class * cl, Object * o, struct opSet *msg);
62 /***********************************************************************************/
64 static void RenderObject_Update(Class *cl, Object *o, struct GadgetInfo *gi)
66 struct RastPort *rp;
68 if ((rp = ObtainGIRPort(gi)))
70 DoMethod(o, GM_RENDER,
71 (IPTR) gi,
72 (IPTR) rp,
73 GREDRAW_UPDATE);
75 ReleaseGIRPort(rp);
79 /***********************************************************************************/
81 static void DrawArrow(Class *cl, struct RastPort *rp, WORD x1, WORD y1, WORD type)
83 WORD dy = 1;
85 if (type == ARROW_UP)
87 y1 += 3; dy = -1;
90 RectFill(rp, x1, y1, x1 + 6, y1); y1 += dy;
91 RectFill(rp, x1 + 1, y1, x1 + 5, y1); y1 += dy;
92 RectFill(rp, x1 + 2, y1, x1 + 4, y1); y1 += dy;
93 WritePixel(rp, x1 + 3, y1);
96 /***********************************************************************************/
98 static void DrawUpArrow(Class *cl, struct AslCycleData *data, struct DrawInfo *dri, BOOL force)
100 WORD x;
101 BOOL black;
103 if (data->visible == data->numitems) return;
105 black = data->top > 0 ? TRUE : FALSE;
106 if (force || (black != data->uparrowblack))
108 data->uparrowblack = black;
110 SetAPen(data->rp, dri->dri_Pens[black ? SHADOWPEN : BACKGROUNDPEN]);
112 x = data->borderleft + (data->itemwidth - ARROWWIDTH) / 2;
114 DrawArrow(cl, data->rp, data->menuleft + x, data->menutop + data->menuy1 - ARROWHEIGHT - 1, ARROW_UP);
118 /***********************************************************************************/
120 static void DrawDownArrow(Class *cl, struct AslCycleData *data, struct DrawInfo *dri, BOOL force)
122 WORD x;
123 BOOL black;
125 if (data->visible == data->numitems) return;
127 black = data->top + data->visible < data->numitems ? TRUE : FALSE;
128 if (force || (black != data->downarrowblack))
130 data->downarrowblack = black;
132 SetAPen(data->rp, dri->dri_Pens[black ? SHADOWPEN : BACKGROUNDPEN]);
134 x = data->borderleft + (data->itemwidth - ARROWWIDTH) / 2;
136 DrawArrow(cl, data->rp, data->menuleft + x, data->menutop + data->menuy2 + 2, ARROW_DOWN);
140 /***********************************************************************************/
142 static void DrawItem(Class *cl, struct AslCycleData *data, struct DrawInfo *dri, WORD num, BOOL nowhitefill)
144 struct CycleItem *item;
145 WORD off,x,y;
147 off = num - data->top;
149 if ((off >= 0) && (off < data->visible))
151 item = &data->itemmemory[num];
153 x = data->menuleft + data->menux1;
154 y = data->menutop + data->menuy1 + off * data->itemheight;
156 if ((num == data->selected) || !nowhitefill)
158 SetAPen(data->rp, dri->dri_Pens[(num == data->selected) ? SHADOWPEN : SHINEPEN]);
159 RectFill(data->rp, x, y,
160 x + data->itemwidth - 1,
161 y + data->itemheight - 1);
164 x = (x + x + data->itemwidth - item->pixellen) / 2;
165 y += data->font->tf_Baseline + 1;
167 SetAPen(data->rp, dri->dri_Pens[(num == data->selected) ? SHINEPEN : TEXTPEN]);
168 Move(data->rp, x, y);
169 Text(data->rp, item->string, item->charlen);
171 } /* if ((off >= 0) && (off < data->visible)) */
174 /***********************************************************************************/
176 static void DrawMenu(Class *cl, struct AslCycleData *data, struct DrawInfo *dri)
178 WORD i, x1, y1, x2, y2;
180 x1 = data->menuleft;
181 y1 = data->menutop;
183 x2 = x1 + data->menuwidth - 1;
184 y2 = y1 + data->menuheight - 1;
186 SetAPen(data->rp, dri->dri_Pens[SHADOWPEN]);
187 RectFill(data->rp, x1, y1, x2, y1);
188 RectFill(data->rp, x2, y1 + 1, x2, y2);
189 RectFill(data->rp, x1, y2, x2 - 1, y2);
190 RectFill(data->rp, x1, y1 + 1, x1, y2 - 1);
192 SetAPen (data->rp, dri->dri_Pens[SHINEPEN]);
193 RectFill(data->rp, x1 + 1, y1 + 1, x2 - 1, y2 - 1);
195 for(i = data->top;i < data->top + data->visible;i++)
197 DrawItem(cl, data, dri, i,TRUE);
200 DrawUpArrow(cl, data, dri, TRUE);
201 DrawDownArrow(cl, data, dri,TRUE);
204 /***********************************************************************************/
206 static void UnselectActiveItem(Class *cl, struct AslCycleData *data, struct DrawInfo *dri)
208 WORD old;
210 old = data->selected;
211 data->selected = -1;
212 DrawItem(cl, data, dri, old, FALSE);
215 /***********************************************************************************/
217 IPTR AslCycle__OM_NEW(Class * cl, Object * o, struct opSet *msg)
219 struct AslCycleData *data;
220 struct TagItem fitags[] =
222 {IA_FrameType, FRAME_BUTTON},
223 {IA_EdgesOnly, FALSE },
224 {TAG_DONE , 0UL }
227 struct Gadget *g = (struct Gadget *)DoSuperMethodA(cl, o, (Msg)msg);
228 if (g)
230 data = INST_DATA(cl, g);
232 /* We want to get a GM_LAYOUT message, no matter if gadget is GFLG_RELRIGHT/RELBOTTOM/
233 RELWIDTH/RELHEIGHT or not */
234 g->Flags |= GFLG_RELSPECIAL;
236 data->frame = NewObjectA(NULL, FRAMEICLASS, fitags);
237 if (data->frame)
239 AslCycle__OM_SET(cl, (Object *)g, msg);
240 } else {
242 CoerceMethod(cl, (Object *)g, OM_DISPOSE);
247 return (IPTR)g;
250 /***********************************************************************************/
252 IPTR AslCycle__OM_DISPOSE(Class * cl, Object * o, Msg msg)
254 struct AslCycleData *data = INST_DATA(cl, o);
256 if (data->itemmemory) FreeVec(data->itemmemory);
257 if (data->frame) DisposeObject(data->frame);
259 return DoSuperMethodA(cl, o, msg);
262 /***********************************************************************************/
264 IPTR AslCycle__OM_SET(Class * cl, Object * o, struct opSet *msg)
266 struct AslCycleData *data = INST_DATA(cl, o);
267 struct TagItem *tag, *tstate = msg->ops_AttrList;
268 IPTR retval, tidata;
270 retval = DoSuperMethod(cl, o, OM_SET, (IPTR) msg->ops_AttrList, (IPTR) msg->ops_GInfo);
272 while((tag = NextTagItem(&tstate)))
274 tidata = tag->ti_Data;
276 switch(tag->ti_Tag)
278 case ASLCY_Active:
279 data->active = tidata;
280 retval += 1;
281 break;
283 case ASLCY_Labels:
284 data->labels = (char **)tidata;
286 if (data->itemmemory)
288 FreeVec(data->itemmemory);
289 data->itemmemory = 0;
292 data->active = 0;
293 data->numitems = 0;
295 if (data->labels)
297 WORD i;
299 for(i = 0; data->labels[i]; i++)
303 if (i) data->itemmemory = AllocVec(i * sizeof(struct CycleItem), MEMF_PUBLIC | MEMF_CLEAR);
305 if (!data->itemmemory)
307 data->labels = 0;
308 } else {
309 struct CycleItem *item = data->itemmemory;
311 data->numitems = i;
313 for(i = 0; i < data->numitems;i++,item++)
315 item->string = data->labels[i];
316 item->charlen = strlen(item->string);
319 if (msg->ops_GInfo)
321 struct gpLayout gpl;
323 gpl.MethodID = GM_LAYOUT;
324 gpl.gpl_GInfo = msg->ops_GInfo;
325 gpl.gpl_Initial = 0;
327 DoMethodA(o, (Msg)&gpl);
330 } /* if (data->itemmemory) */
332 } /* if (data->labels) */
334 retval += 1;
335 break;
337 case ASLCY_Font:
338 data->font = (struct TextFont *)tidata;
339 retval += 1;
340 break;
342 } /* switch(tag->ti_Tag) */
344 } /* while((tag = NextTagItem(&tstate))) */
346 if (retval)
348 RenderObject_Update(cl, o, msg->ops_GInfo);
351 return retval;
355 /***********************************************************************************/
357 IPTR AslCycle__OM_GET(Class * cl, Object * o, struct opGet *msg)
359 struct AslCycleData *data = INST_DATA(cl, o);
361 IPTR retval = 1;
363 switch(msg->opg_AttrID)
365 case ASLCY_Active:
366 *msg->opg_Storage = data->active;
367 break;
369 default:
370 retval = DoSuperMethodA(cl, o, (Msg)msg);
371 break;
374 return retval;
377 /***********************************************************************************/
379 IPTR AslCycle__GM_LAYOUT(Class * cl, struct Gadget * g, struct gpLayout *msg)
381 struct AslCycleData *data = INST_DATA(cl, g);
382 struct CycleItem *item;
383 WORD len, i;
384 WORD x, y, w, h;
386 getgadgetcoords(g, msg->gpl_GInfo, &x, &y, &w, &h);
388 if (!data->font) data->font = msg->gpl_GInfo->gi_DrInfo->dri_Font;
390 item = data->itemmemory;
391 len = 0;
393 InitRastPort(&data->clonerp);
394 SetFont(&data->clonerp, data->font);
396 for (i = 0; i < data->numitems; i++, item++)
398 item->pixellen = TextLength(&data->clonerp, item->string, item->charlen);
399 if (item->pixellen > len) len = item->pixellen;
402 data->itemwidth = len + 2;
403 i = w - CYCLEIMAGEWIDTH - BORDERCYCLESPACINGX;
404 if (data->itemwidth < i) data->itemwidth = i;
406 data->itemheight = data->font->tf_YSize + 2;
408 data->borderleft = 4;
409 data->borderright = 4;
410 data->bordertop = 4;
411 data->borderbottom = 4;
413 data->menuwidth = data->itemwidth + data->borderleft + data->borderright;
415 data->menuheight = data->numitems * data->itemheight +
416 data->bordertop +
417 data->borderbottom;
419 data->menux1 = data->borderleft;
421 data->maypopup = TRUE;
423 if (data->menuheight > msg->gpl_GInfo->gi_Screen->Height)
425 data->visible = (msg->gpl_GInfo->gi_Screen->Height -
426 data->bordertop -
427 data->borderbottom -
428 (ARROWHEIGHT + 2) * 2) / data->itemheight;
430 if (data->visible < 2)
432 data->maypopup = FALSE;
433 } else {
434 data->menuheight = data->bordertop +
435 data->visible * data->itemheight +
436 data->borderbottom +
437 (ARROWHEIGHT + 2) * 2;
439 data->menuy1 = data->bordertop + ARROWHEIGHT + 2;
441 } else {
442 data->visible = data->numitems;
443 data->menuy1 = data->bordertop;
446 data->menux2 = data->menux1 + data->itemwidth - 1;
447 data->menuy2 = data->menuy1 + data->visible * data->itemheight - 1;
449 return 0;
452 /***********************************************************************************/
454 IPTR AslCycle__GM_RENDER(Class * cl, struct Gadget * g, struct gpRender *msg)
456 struct AslCycleData *data = INST_DATA(cl, g);
457 struct RastPort *rp = msg->gpr_RPort;
458 struct DrawInfo *dri = msg->gpr_GInfo->gi_DrInfo;
459 struct CycleItem *item;
460 WORD gadx, gady, gadw, gadh, x, y, y2, a1, a2;
462 BOOL selected;
464 if (rp)
466 struct TagItem im_tags[] =
468 {IA_Width , 0 },
469 {IA_Height , 0 },
470 {TAG_DONE }
473 getgadgetcoords(g, msg->gpr_GInfo, &gadx, &gady, &gadw, &gadh);
475 im_tags[0].ti_Data = gadw;
476 im_tags[1].ti_Data = gadh;
478 SetAttrsA(data->frame, im_tags);
480 DrawImageState(msg->gpr_RPort,
481 (struct Image *)data->frame,
482 gadx,
483 gady,
484 (g->Flags & GFLG_SELECTED) ? IDS_SELECTED : IDS_NORMAL,
485 msg->gpr_GInfo->gi_DrInfo);
488 if (data->labels)
490 selected = (g->Flags & GFLG_SELECTED) ? TRUE: FALSE;
491 SetABPenDrMd(rp, dri->dri_Pens[selected ? FILLTEXTPEN : TEXTPEN], 0, JAM1);
493 item = &data->itemmemory[data->active];
495 a1 = gadx + BORDERCYCLESPACINGX;
496 a2 = gadx + gadw - CYCLEIMAGEWIDTH - BORDERCYCLESPACINGX;
497 x = (a1 + a2 - item->pixellen) / 2;
499 y = gady + (gadh - data->font->tf_YSize) / 2 + data->font->tf_Baseline;
501 SetFont(rp, data->font);
503 Move(rp, x, y);
504 Text(rp, item->string, item->charlen);
507 x = gadx + gadw - CYCLEIMAGEWIDTH;
508 y = gady + 2;
509 y2 = gady + gadh - 1 - 2;
511 /* separator bar */
513 SetAPen(rp, dri->dri_Pens[SHINEPEN]);
514 RectFill(rp, x + 1, y , x + 1, y2);
515 SetAPen(rp, dri->dri_Pens[SHADOWPEN]);
516 RectFill(rp, x, y, x, y2);
518 y = gady + (gadh - 4) / 2;
519 x += 6;
521 DrawArrow(cl, rp, x, y, ARROW_DOWN);
523 } /* if (rp) */
525 return 0;
528 /***********************************************************************************/
530 IPTR AslCycle__GM_GOACTIVE(Class * cl, struct Gadget * g, struct gpInput *msg)
532 struct AslCycleData *data = INST_DATA(cl, g);
533 WORD x, y, x2, y2, gadx, gady, gadw, gadh;
535 IPTR rc = GMR_MEACTIVE;
537 if (!data->labels || !msg->gpi_IEvent) return GMR_NOREUSE;
539 data->popup = FALSE;
540 data->sentgadgetup = FALSE;
541 data->turbocountdown = TURBOCOUNTDOWN;
543 getgadgetcoords(g, msg->gpi_GInfo, &gadx, &gady, &gadw, &gadh);
545 x = msg->gpi_GInfo->gi_Window->MouseX;
547 if (data->maypopup && (data->numitems > 2) && (x < gadx + gadw - CYCLEIMAGEWIDTH))
549 x = msg->gpi_GInfo->gi_Window->LeftEdge + gadx;
550 y = msg->gpi_GInfo->gi_Window->TopEdge + gady + gadh;
552 if (x < 0) x = 0;
553 if ((x + data->menuwidth) > msg->gpi_GInfo->gi_Screen->Width)
555 x = msg->gpi_GInfo->gi_Screen->Width - data->menuwidth;
558 if (y < 0) y = 0;
559 if ((y + data->menuheight) > msg->gpi_GInfo->gi_Screen->Height)
561 y = msg->gpi_GInfo->gi_Screen->Height - data->menuheight;
564 x2 = x + data->menuwidth - 1;
565 y2 = y + data->menuheight - 1;
567 if ((data->popupwindow = OpenWindowTags(0,WA_CustomScreen, (IPTR) msg->gpi_GInfo->gi_Screen,
568 WA_Left, x,
569 WA_Top, y,
570 WA_Width, data->menuwidth,
571 WA_Height, data->menuheight,
572 WA_Flags, WFLG_BORDERLESS,
573 WA_BackFill, (IPTR) LAYERS_NOBACKFILL,
574 TAG_DONE)))
576 data->menuleft = 0;
577 data->menutop = 0;
578 data->rp = data->popupwindow->RPort;
582 if (data->popupwindow)
584 data->layerx1 = x; data->layery1 = y;
585 data->layerx2 = x2; data->layery2 = y2;
587 data->top = 0;
588 data->selected = -1;
589 SetDrMd(data->rp, JAM1);
590 SetFont(data->rp, data->font);
592 data->popup = TRUE;
593 DrawMenu(cl, data, msg->gpi_GInfo->gi_DrInfo);
596 } /* if (data->maypopup && (data->numitems > 2) && (x < gadx + gadw - CYCLEIMAGEWIDTH)) */
597 else
599 g->Flags |= GFLG_SELECTED;
600 RenderObject_Update(cl, (Object *)g, msg->gpi_GInfo);
603 return rc;
606 /***********************************************************************************/
608 IPTR AslCycle__GM_HANDLEINPUT(Class * cl, struct Gadget * g, struct gpInput *msg)
610 struct AslCycleData *data = INST_DATA(cl, g);
611 WORD gadx, gady, gadw, gadh, x, y, i;
612 IPTR rc = GMR_MEACTIVE;
614 getgadgetcoords(g, msg->gpi_GInfo, &gadx, &gady, &gadw, &gadh);
616 if (data->popup)
618 if ((msg->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE) &&
619 (msg->gpi_IEvent->ie_Code == (IECODE_LBUTTON | IECODE_UP_PREFIX)))
621 rc = GMR_NOREUSE;
622 if (data->selected != -1)
624 data->active = data->selected;
625 data->sentgadgetup = TRUE;
627 rc |= GMR_VERIFY;
628 *msg->gpi_Termination = data->active;
630 goto done;
634 x = msg->gpi_GInfo->gi_Screen->MouseX - data->layerx1;
635 y = msg->gpi_GInfo->gi_Screen->MouseY - data->layery1;
637 if ((x < data->menux1) || (x > data->menux2))
639 UnselectActiveItem(cl, data, msg->gpi_GInfo->gi_DrInfo);
640 } else {
641 i = (y - data->menuy1) / data->itemheight;
643 if ((i >= data->visible) || (y < data->menuy1))
645 UnselectActiveItem(cl, data, msg->gpi_GInfo->gi_DrInfo);
647 if (data->turbocountdown && (msg->gpi_IEvent->ie_Class == IECLASS_TIMER))
649 data->turbocountdown--;
652 if (!data->turbocountdown || (msg->gpi_IEvent->ie_Class == IECLASS_TIMER))
654 if (i >= data->visible)
656 // scroll down
657 if (data->top + data->visible < data->numitems)
659 ClipBlit(data->rp, data->menux1 + data->menuleft, data->menuy1 + data->menutop + data->itemheight,
660 data->rp, data->menux1 + data->menuleft, data->menuy1 + data->menutop, data->itemwidth, data->itemheight * (data->visible - 1), 192);
661 data->top++;
662 DrawItem(cl, data, msg->gpi_GInfo->gi_DrInfo, data->top + data->visible - 1, FALSE);
663 DrawUpArrow(cl, data, msg->gpi_GInfo->gi_DrInfo, FALSE);
664 DrawDownArrow(cl, data, msg->gpi_GInfo->gi_DrInfo, FALSE);
666 } else {
667 // scroll up
668 if (data->top > 0)
670 ClipBlit(data->rp, data->menux1 + data->menuleft, data->menuy1 + data->menutop,
671 data->rp, data->menux1 + data->menuleft, data->menuy1 + data->menutop + data->itemheight, data->itemwidth, data->itemheight * (data->visible - 1), 192);
672 data->top--;
673 DrawItem(cl, data, msg->gpi_GInfo->gi_DrInfo, data->top, FALSE);
674 DrawUpArrow(cl, data, msg->gpi_GInfo->gi_DrInfo, FALSE);
675 DrawDownArrow(cl, data, msg->gpi_GInfo->gi_DrInfo, FALSE);
678 } /* if (!data->turbocountdown || (msg->gpi_IEvent->ie_Class == IECLASS_TIMER)) */
680 } else {
682 data->turbocountdown = TURBOCOUNTDOWN;
683 x = data->selected;
684 data->selected = data->top + i;
685 if (data->selected != x)
687 DrawItem(cl, data, msg->gpi_GInfo->gi_DrInfo, x, FALSE);
688 DrawItem(cl, data, msg->gpi_GInfo->gi_DrInfo, data->selected, FALSE);
693 } else { /* if (data->popup) */
695 /* like a GadTools cycle gadget */
697 switch(msg->gpi_IEvent->ie_Class)
699 case IECLASS_RAWMOUSE:
700 switch(msg->gpi_IEvent->ie_Code)
702 case IECODE_LBUTTON | IECODE_UP_PREFIX:
703 if (g->Flags & GFLG_SELECTED)
705 data->active++;
706 if (data->active >= data->numitems) data->active = 0;
708 g->Flags &= (~GFLG_SELECTED);
709 RenderObject_Update(cl, (Object *)g, msg->gpi_GInfo);
710 rc |= GMR_VERIFY;
711 *msg->gpi_Termination = g->GadgetID;
713 rc |= GMR_NOREUSE;
714 break;
716 default:
717 if ((msg->gpi_Mouse.X >= 0 ) &&
718 (msg->gpi_Mouse.Y >= 0 ) &&
719 (msg->gpi_Mouse.X < gadw) &&
720 (msg->gpi_Mouse.Y < gadh))
722 if (!(g->Flags & GFLG_SELECTED))
724 g->Flags |= GFLG_SELECTED;
725 RenderObject_Update(cl, (Object *)g, msg->gpi_GInfo);
727 } else {
728 if (g->Flags & GFLG_SELECTED)
730 g->Flags &= (~GFLG_SELECTED);
731 RenderObject_Update(cl, (Object *)g, msg->gpi_GInfo);
734 rc = GMR_MEACTIVE;
736 break;
738 } /* switch(msg->gpi_IEvent->ie_Code) */
740 } /* switch(msg->gpi_IEvent->ie_Class) */
742 } /* if (data->popup) {...} else { */
744 done:
746 return rc;
750 /***********************************************************************************/
752 IPTR AslCycle__GM_GOINACTIVE(Class * cl, Object * o, struct gpGoInactive *msg)
754 struct AslCycleData *data = INST_DATA(cl, o);
756 if (data->popupwindow)
758 CloseWindow(data->popupwindow);
759 data->popupwindow = 0;
762 if (data->sentgadgetup)
764 RenderObject_Update(cl, o, msg->gpgi_GInfo);
767 return 0;
770 /***********************************************************************************/