This should solve an error which made the nightly build fail with:
[AROS-Contrib.git] / bgui / cycleclass.c
blob83cc2704f460bd90f3889ccf963253c416f86ae9
1 /*
2 * @(#) $Header$
4 * BGUI library
5 * cycleclass.c
7 * (C) Copyright 1998 Manuel Lemos.
8 * (C) Copyright 1996-1997 Ian J. Einman.
9 * (C) Copyright 1993-1996 Jaba Development.
10 * (C) Copyright 1993-1996 Jan van den Baard.
11 * All Rights Reserved.
13 * $Log$
14 * Revision 42.8 2004/06/16 20:16:48 verhaegs
15 * Use METHODPROTO, METHOD_END and REGFUNCPROTOn where needed.
17 * Revision 42.7 2002/09/17 17:11:16 stegerg
18 * inversvid drawmode together with Text() works now, so no
19 * workaround needed.
21 * Revision 42.6 2000/08/17 15:09:18 chodorowski
22 * Fixed compiler warnings.
24 * Revision 42.5 2000/07/18 18:32:38 stegerg
25 * The AllocBaseInfo/AllocBaseInfoDebug calls in OpenPopUpWindow method
26 * missed a TAG_DONE. Manuel, if you read this: this is a real (also in AmigaOS)
27 * bug, not just AROS!!!
29 * Revision 42.4 2000/07/11 17:04:41 stegerg
30 * temp fix for small gfx bug which happens because of INVERSVID
31 * drawmode not yet working in AROS.
33 * Revision 42.3 2000/05/29 15:42:49 stegerg
34 * fixed some "comparison is always 1 due to limited range of data type"
35 * errors
37 * Revision 42.2 2000/05/15 19:27:01 stegerg
38 * another hundreds of REG() macro replacements in func headers/protos.
40 * Revision 42.1 2000/05/14 23:32:47 stegerg
41 * changed over 200 function headers which all use register
42 * parameters (oh boy ...), because the simple REG() macro
43 * doesn't work with AROS. And there are still hundreds
44 * of headers left to be fixed :(
46 * Many of these functions would also work with stack
47 * params, but since i have fixed every single one
48 * I encountered up to now, I guess will have to do
49 * the same for the rest.
51 * Revision 42.0 2000/05/09 22:08:45 mlemos
52 * Bumped to revision 42.0 before handing BGUI to AROS team
54 * Revision 41.11 2000/05/09 19:54:08 mlemos
55 * Merged with the branch Manuel_Lemos_fixes.
57 * Revision 41.10.2.3 1998/12/07 03:06:57 mlemos
58 * Replaced OpenFont and CloseFont calls by the respective BGUI debug macros.
60 * Revision 41.10.2.2 1998/03/01 23:06:01 mlemos
61 * Corrected RastPort tag where GadgetInfo was being passed.
63 * Revision 41.10.2.1 1998/03/01 15:37:32 mlemos
64 * Added support to track BaseInfo memory leaks.
66 * Revision 41.10 1998/02/25 21:11:52 mlemos
67 * Bumping to 41.10
69 * Revision 1.1 1998/02/25 17:07:59 mlemos
70 * Ian sources
75 /// Class definitions.
77 #include "include/classdefs.h"
80 * Object instance data.
82 typedef struct {
83 struct Window *cd_PopWindow; /* Popup window pointer. */
84 Object *cd_ArrayLabel; /* Label object for active label. */
85 Object *cd_Image; /* Image for the popcycle. */
86 UBYTE **cd_Labels; /* Array of object labels. */
87 ULONG cd_Active; /* Active label. */
88 ULONG cd_NumLabels; /* Amount of labels. */
89 struct TextAttr *cd_PopupFont; /* Font for pop window. */
90 struct TextFont *cd_Font; /* General font. */
91 UWORD cd_Flags; /* See below. */
92 UWORD cd_Previous; /* Previously selected label. */
93 UWORD cd_ImageWidth; /* Width of area for clicking. */
94 } CD;
96 #define CDF_POPUP (1<<0) /* Popup mode. */
97 #define CDF_NOTIFY (1<<1) /* Notify change. */
98 #define CDF_THIN (1<<2) /* Thin frames. */
99 #define CDF_POPACTIVE (1<<3) /* Pop on active entry. */
103 /// OM_NEW
105 * Create a new object.
107 METHOD(CycleClassNew, struct opSet *, ops)
109 CD *cd;
110 struct TagItem *tags;
111 ULONG rc;
113 tags = DefTagList(BGUI_CYCLE_GADGET, ops->ops_AttrList);
116 * First we let the superclass
117 * create an object.
119 if (rc = NewSuperObject(cl, obj, tags))
122 * Get instance data.
124 cd = INST_DATA(cl, rc);
127 * Set up imagery.
129 cd->cd_ImageWidth = 18;
131 cd->cd_Image = BGUI_NewObject(BGUI_VECTOR_IMAGE, VIT_BuiltIn, BUILTIN_CYCLE,
132 TAG_DONE);
135 * Setup a Label class object used to render the active label.
137 cd->cd_ArrayLabel = BGUI_NewObject(BGUI_LABEL_IMAGE, LAB_Place, PLACE_IN,
138 LAB_Highlight, FALSE,
139 LAB_Underscore, 0,
140 IMAGE_ErasePen, 0,
141 TAG_DONE);
143 AsmCoerceMethod(cl, (Object *)rc, OM_SET, tags, NULL);
145 if (cd->cd_ArrayLabel && cd->cd_Image && cd->cd_Labels)
149 else
151 AsmCoerceMethod(cl, (Object *)rc, OM_DISPOSE);
152 rc = 0;
155 FreeTagItems(tags);
157 return rc;
159 METHOD_END
161 /// OM_SET
163 * Change the object attributes.
165 METHOD(CycleClassSetUpdate, struct opUpdate *, opu)
167 CD *cd = INST_DATA(cl, obj);
168 struct TagItem *tstate = opu->opu_AttrList, *tag;
169 ULONG oact = cd->cd_Active, data;
170 WORD dis = GADGET(obj)->Flags & GFLG_DISABLED;
171 UBYTE **new_labels = NULL;
172 int num_labels;
173 BOOL render = FALSE;
174 struct GadgetInfo *gi = opu->opu_GInfo;
177 * First let the superclass do its thing.
179 AsmDoSuperMethodA(cl, obj, (Msg)opu);
182 * Force the correct activation method.
184 GADGET(obj)->Activation |= GACT_RELVERIFY;
185 GADGET(obj)->Activation &= ~GACT_IMMEDIATE;
187 while (tag = NextTagItem(&tstate))
189 data = tag->ti_Data;
190 switch (tag->ti_Tag)
192 case BT_TextAttr:
193 cd->cd_PopupFont = (struct TextAttr *)data;
195 * Let the label know.
197 DoSetMethodNG(cd->cd_ArrayLabel, LAB_TextAttr, data, TAG_DONE);
198 break;
200 case FRM_ThinFrame:
201 if (data) cd->cd_Flags |= CDF_THIN;
202 else cd->cd_Flags &= ~CDF_THIN;
203 break;
205 case CYC_Active:
206 cd->cd_Active = data;
207 break;
209 case CYC_Labels:
211 * Count the number of labels in the array (offset by 1).
213 num_labels = data ? CountLabels((UBYTE **)data) : -1;
215 if (num_labels >= 0)
217 if (new_labels = BGUI_AllocPoolMem((num_labels + 2) * sizeof(UBYTE *)))
219 if (cd->cd_Labels) BGUI_FreePoolMem(cd->cd_Labels);
220 cd->cd_Labels = new_labels;
221 cd->cd_NumLabels = num_labels;
222 CopyMem((UBYTE *)data, (UBYTE *)new_labels, (num_labels + 1) * sizeof(UBYTE *));
225 render = TRUE;
226 break;
228 case CYC_Popup:
229 if (data) cd->cd_Flags |= CDF_POPUP;
230 else cd->cd_Flags &= ~CDF_POPUP;
231 break;
233 case CYC_PopActive:
234 if (data) cd->cd_Flags |= CDF_POPACTIVE;
235 else cd->cd_Flags &= ~CDF_POPACTIVE;
236 break;
240 if ((GADGET(obj)->Flags & GFLG_DISABLED) != dis)
242 * Re-render when the gadget disabled state changed.
244 render = TRUE;
247 * Here's that sanity check again.
249 if (cd->cd_Active > cd->cd_NumLabels)
250 cd->cd_Active = cd->cd_NumLabels;
252 if ((oact != cd->cd_Active) || new_labels)
255 * Setup new text.
257 DoSetMethodNG(cd->cd_ArrayLabel, LAB_Label, cd->cd_Labels[cd->cd_Active], LAB_Place, PLACE_IN, TAG_DONE);
258 render = TRUE;
261 if (render) DoRenderMethod(obj, gi, GREDRAW_REDRAW);
264 * Notify the target when necessary.
266 if (oact != cd->cd_Active)
268 DoNotifyMethod(obj, gi, 0, GA_ID, GADGET(obj)->GadgetID, CYC_Active, cd->cd_Active, TAG_DONE);
270 return 1;
272 METHOD_END
275 /// RenderArrow
277 * Render the cycle arrow.
279 STATIC VOID RenderArrow(struct BaseInfo *bi, struct IBox *ib, ULONG state, CD *cd)
281 Object *image = cd->cd_Image;
282 ULONG type;
285 * Get coords.
287 int w = cd->cd_ImageWidth;
288 int h = ib->Height;
289 int l = ib->Left - w;
290 int t = ib->Top;
293 * Render the small seperator.
295 BSetDrMd(bi, JAM1);
297 BSetDPenA(bi, (state != IDS_SELECTED) ? SHINEPEN : SHADOWPEN);
298 VLine(bi->bi_RPort, l + w + 1, t + 2, t + h - 3);
300 BSetDPenA(bi, (state != IDS_SELECTED) ? SHADOWPEN : SHINEPEN);
301 VLine(bi->bi_RPort, l + w, t + 2, t + h - 3);
303 if (state == IDS_SELECTED)
305 type = BUILTIN_CYCLE2;
307 else
309 type = (cd->cd_Flags & CDF_POPUP) ? BUILTIN_POPUP : BUILTIN_CYCLE;
313 * Setup and render the image.
315 DoSetMethodNG(image, VIT_BuiltIn, type, IA_Left, l, IA_Top, t, IA_Width, w, IA_Height, h, TAG_END);
316 BDrawImageState(bi, image, 0, 0, state);
319 /// RenderPopupEntry
321 * Render an entry in the popup-list.
323 STATIC VOID RenderPopupEntry(struct BaseInfo *bi, CD *cd, ULONG num, BOOL sel)
325 UWORD ypos, xpos, tlen, pix = cd->cd_Flags & CDF_THIN ? 2 : 4;
326 UBYTE *name = cd->cd_Labels[num];
327 struct RastPort *rp = bi->bi_RPort;
330 * Compute text length.
332 tlen = TextWidth(rp, name);
335 * Compute positions.
337 xpos = (cd->cd_PopWindow->Width - tlen) >> 1;
338 ypos = (num * rp->TxHeight) + 2;
341 * Setup pens for filling.
343 #ifdef ENHANCED
344 BSetDPenA(bi, sel ? BARDETAILPEN : BARBLOCKPEN);
345 #else
346 if (OS30) BSetDPenA(bi, sel ? BARDETAILPEN : BARBLOCKPEN);
347 else BSetDPenA(bi, BLOCKPEN);
348 #endif
351 * RectFill entry.
353 BSetDrMd(bi, JAM1);
354 BRectFill(bi, pix, ypos, cd->cd_PopWindow->Width - pix - 1, ypos + rp->TxHeight - 1);
357 * Setup drawmode.
359 #ifdef ENHANCED
360 BSetDrMd(bi, sel ? JAM2|INVERSVID : JAM2);
361 #else
362 if (OS30) BSetDrMd(bi, sel ? JAM2|INVERSVID : JAM2);
363 else BSetDrMd(bi, JAM2);
364 #endif
367 * Setup pens for text.
369 BSetDPenA(bi, BARDETAILPEN);
370 BSetDPenB(bi, BARBLOCKPEN);
373 * Move to the desired location and render.
375 Move(rp, xpos, ypos + rp->TxBaseline);
376 Text(rp, name, strlen(name));
378 #ifndef ENHANCED
380 * < OS 3.0 will get the entry
381 * complemented if it is selected.
383 if (!OS30 && sel)
385 BSetDrMd(bi, JAM2|COMPLEMENT);
386 BRectFill(bi, pix, ypos, cd->cd_PopWindow->Width - pix - 1, ypos + rp->TxHeight - 1);
388 #endif
391 /// GM_RENDER
393 * Render the object.
395 METHOD(CycleClassRenderX, struct gpRender *, gpr)
397 CD *cd = INST_DATA(cl, obj);
399 DoSuperSetMethodNG(cl, obj, BT_LeftOffset, cd->cd_ImageWidth, TAG_DONE);
401 return AsmDoSuperMethodA(cl, obj, (Msg)gpr);
403 METHOD_END
405 /// BASE_RENDER
407 * Render the object.
409 METHOD(CycleClassRender, struct bmRender *, bmr)
411 CD *cd = INST_DATA(cl, obj);
412 BC *bc = BASE_DATA(obj);
413 struct BaseInfo *bi = bmr->bmr_BInfo;
414 int state = GADGET(obj)->Flags & GFLG_SELECTED ? IDS_SELECTED : IDS_NORMAL;
417 * Render the baseclass.
419 AsmDoSuperMethodA(cl, obj, (Msg)bmr);
422 * Setup array label.
424 *IMAGEBOX(cd->cd_ArrayLabel) = bc->bc_InnerBox;
427 * Render the arrow.
429 RenderArrow(bi, &bc->bc_InnerBox, state, cd);
432 * We always render the active gadget label.
434 BDrawImageState(bi, cd->cd_ArrayLabel, 0, 0, state);
437 * Ghost the gadget when it is disabled.
439 if (GADGET(obj)->Flags & GFLG_DISABLED)
440 BDisableBox(bi, &bc->bc_HitBox);
442 return 1;
444 METHOD_END
447 /// OpenPopupWindow
449 * Open the popup-window.
451 METHOD(OpenPopupWindow, struct gpInput *, gpi)
453 CD *cd = INST_DATA(cl, obj);
454 BC *bc = BASE_DATA(obj);
455 UWORD max_items, num_items, wleft, wtop, wwi, wwh, bg, i;
456 struct IBox *ibox;
457 struct RastPort *rp;
458 struct GadgetInfo *gi = gpi->gpi_GInfo;
459 struct BaseInfo *bi;
460 int ysize;
461 ULONG rc = GMR_NOREUSE;
464 * Get the gadget hitbox bounds.
466 Get_SuperAttr(cl, obj, BT_HitBox, &ibox);
469 * Open the font.
471 if (cd->cd_PopupFont)
472 cd->cd_Font = BGUI_OpenFont(cd->cd_PopupFont);
474 /* BAD CODE! Does not check OpenFont result! */
476 ysize = cd->cd_Font->tf_YSize;
479 * How many items will fit?
481 max_items = (gi->gi_Screen->Height - 4) / ysize;
484 * How many do we have?
486 num_items = (cd->cd_NumLabels + 1) > max_items ? max_items : (cd->cd_NumLabels + 1);
489 * Compute window position and dimensions.
491 wleft = bc->bc_HitBox.Left + gi->gi_Window->LeftEdge;
492 wwi = bc->bc_HitBox.Width;
493 wwh = (num_items * ysize) + 4;
495 if (cd->cd_Flags & CDF_POPACTIVE)
496 wtop = gi->gi_Screen->MouseY - (2 + ((cd->cd_Active * ysize) + (ysize >> 1)));
497 else
498 wtop = bc->bc_HitBox.Top + bc->bc_HitBox.Height + gi->gi_Window->TopEdge;
501 * Pop the window.
503 cd->cd_PopWindow = OpenWindowTags(NULL, WA_Left, wleft, WA_Top, wtop,
504 WA_Width, wwi, WA_Height, wwh,
505 WA_Flags, 0, WA_IDCMP, 0,
506 WA_Borderless, TRUE, WA_AutoAdjust, TRUE,
507 WA_SmartRefresh, TRUE, WA_NoCareRefresh, TRUE,
508 WA_RMBTrap, TRUE, WA_CustomScreen, gi->gi_Screen,
509 TAG_DONE);
511 * success?
513 if (cd->cd_PopWindow)
516 * No previous selected item.
518 cd->cd_Previous = (UWORD)~0;
520 /* AROS BUGFIX --> AMIGAOS BUGFIX: TAG_DONE missed in both AllocBaseInfoDebug and AllocBaseInfo call below */
521 #ifdef DEBUG_BGUI
522 if (bi = AllocBaseInfoDebug(__FILE__,__LINE__,BI_Screen, gi->gi_Screen, BI_RastPort, rp = cd->cd_PopWindow->RPort, TAG_DONE))
523 #else
524 if (bi = AllocBaseInfo(BI_Screen, gi->gi_Screen, BI_RastPort, rp = cd->cd_PopWindow->RPort, TAG_DONE))
525 #endif
528 * Setup the font.
530 if (cd->cd_Font) BSetFont(bi, cd->cd_Font);
533 * Setup pop window rastport.
535 BSetDPenA(bi, BARBLOCKPEN);
536 BSetDrMd(bi, JAM1);
539 * Fill...
541 BBoxFill(bi, 0, 0, wwi, wwh);
544 * Setup pop window rastport.
546 BSetDPenA(bi, BARDETAILPEN);
549 * Render border.
551 Move(rp, 0, 0 );
552 Draw(rp, wwi - 1, 0);
553 Draw(rp, wwi - 1, wwh - 1 );
554 Draw(rp, 0, wwh - 1 );
555 Draw(rp, 0, 0 );
557 if (!(cd->cd_Flags & CDF_THIN))
559 Move(rp, 1, 0 );
560 Draw(rp, 1, wwh - 1 );
561 Move(rp, wwi - 2, 0 );
562 Draw(rp, wwi - 2, wwh - 1 );
566 * Render list-entries.
568 for (i = 0; i < num_items; i++)
569 RenderPopupEntry(bi, cd, i, FALSE);
571 FreeBaseInfo(bi);
573 rc = GMR_MEACTIVE;
576 return rc;
578 METHOD_END
581 /// GM_GOACTIVE
583 * Go in active mode.
585 METHOD(CycleClassGoActive, struct gpInput *, gpi)
587 CD *cd = INST_DATA(cl, obj);
588 BC *bc = BASE_DATA(obj);
589 ULONG rc = GMR_NOREUSE;
592 * We don't go active when we are disabled.
594 if ( GADGET( obj )->Flags & GFLG_DISABLED )
595 return( GMR_NOREUSE );
598 * We only go active when triggered by a mouse click.
600 if (gpi->gpi_IEvent)
603 * Let the superclass have a go...
605 AsmDoSuperMethodA(cl, obj, (Msg)gpi);
608 * Popup mode?
610 if (cd->cd_Flags & CDF_POPUP)
612 if (gpi->gpi_GInfo->gi_Window->MouseX > (bc->bc_HitBox.Left + cd->cd_ImageWidth))
615 * Open the popup window.
616 * Do normal selection if the popup window will not open.
618 if (OpenPopupWindow(cl, obj, gpi) == 0) return 0;
621 GADGET(obj)->Flags |= GFLG_SELECTED;
622 DoRenderMethod(obj, gpi->gpi_GInfo, GREDRAW_REDRAW);
623 rc = GMR_MEACTIVE;
625 return rc;
627 METHOD_END
631 * Which entry is selected?
633 //STATIC ASM UWORD Selected(REG(a0) CD *cd, REG(a1) struct RastPort *rp)
634 STATIC ASM REGFUNC2(UWORD, Selected,
635 REGPARAM(A0, CD *, cd),
636 REGPARAM(A1, struct RastPort *, rp))
638 WORD mx = cd->cd_PopWindow->MouseX, my = cd->cd_PopWindow->MouseY;
639 LONG item = ~0;
642 * Mouse in the window?
644 if ( mx >= 4 && mx < ( cd->cd_PopWindow->Width - 4 ) && my >= 2 && my < ( cd->cd_PopWindow->Height - 2 )) {
646 * Find the entry the mouse is over.
648 item = ( my - 2 ) / rp->TxHeight;
650 if ( item > cd->cd_NumLabels ) item = ~0;
652 return(( UWORD )item );
654 REGFUNC_END
655 /// GM_HANDLEINPUT
657 * Handle the gadget input.
659 METHOD(CycleClassHandleInput, struct gpInput *, gpi)
661 CD *cd = INST_DATA(cl, obj);
662 struct gpHitTest gph;
663 WORD sel = 0, item;
664 struct GadgetInfo *gi = gpi->gpi_GInfo;
665 struct BaseInfo *bi;
666 ULONG rc = GMR_MEACTIVE;
669 * Window up?
671 if (cd->cd_PopWindow)
674 * Is the parent window still activated?
675 * If not we return immediatly.
677 * Security. Intuition should do this already.
679 if (!(gi->gi_Window->Flags & WFLG_WINDOWACTIVE))
680 return GMR_NOREUSE;
682 #ifdef DEBUG_BGUI
683 if (bi = AllocBaseInfoDebug(__FILE__,__LINE__,BI_GadgetInfo, gi, BI_RastPort, cd->cd_PopWindow->RPort, TAG_DONE))
684 #else
685 if (bi = AllocBaseInfo(BI_GadgetInfo, gi, BI_RastPort, cd->cd_PopWindow->RPort, TAG_DONE))
686 #endif
689 * Where is the mouse?
691 item = Selected(cd, bi->bi_RPort);
694 * Changed?
696 if (item != cd->cd_Previous)
699 * Previous selected item?
701 if (cd->cd_Previous != (UWORD)~0) RenderPopupEntry(bi, cd, cd->cd_Previous, FALSE);
704 * Render current entry.
706 if (item != ~0) RenderPopupEntry(bi, cd, item, TRUE);
709 * Setup item.
711 cd->cd_Previous = item;
713 FreeBaseInfo(bi);
716 * What's the event?
718 if (gpi->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE)
720 switch (gpi->gpi_IEvent->ie_Code)
722 case SELECTUP:
724 * Setup the new label and return VERIFY.
726 if (cd->cd_Previous != (UWORD)~0)
728 if (cd->cd_Active != cd->cd_Previous)
731 * We need notification.
733 cd->cd_Flags |= CDF_NOTIFY;
736 * New active entry.
738 cd->cd_Active = cd->cd_Previous;
741 * Setup the new label.
743 DoSetMethodNG(cd->cd_ArrayLabel, LAB_Label, cd->cd_Labels[cd->cd_Active], LAB_Place, PLACE_IN, TAG_END);
746 * Re-render to show the change.
748 DoRenderMethod(obj, gi, GREDRAW_REDRAW);
751 * We want to notify about the attribute change.
753 rc = GMR_NOREUSE | GMR_VERIFY;
754 } else
755 rc = GMR_NOREUSE;
756 } else
757 rc = GMR_NOREUSE;
758 break;
760 case MENUDOWN:
761 rc = GMR_NOREUSE;
762 break;
767 else
770 * Mouse over the object?
772 gph.MethodID = GM_HITTEST;
773 gph.gpht_GInfo = gpi->gpi_GInfo;
774 gph.gpht_Mouse.X = gpi->gpi_Mouse.X;
775 gph.gpht_Mouse.Y = gpi->gpi_Mouse.Y;
777 if ( AsmDoMethodA( obj, ( Msg )&gph ) == GMR_GADGETHIT )
778 sel = GFLG_SELECTED;
780 if ( gpi->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE ) {
781 switch ( gpi->gpi_IEvent->ie_Code ) {
783 case SELECTUP:
785 * When we are selected we setup a new label
786 * and return VERIFY.
788 if ( sel ) {
790 * Clicked with the shift key down cycles backward.
792 if ( gpi->gpi_IEvent->ie_Qualifier & ( IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT )) {
793 if ( cd->cd_Active ) cd->cd_Active--;
794 else cd->cd_Active = cd->cd_NumLabels;
795 } else {
796 if ( cd->cd_Active < cd->cd_NumLabels ) cd->cd_Active++;
797 else cd->cd_Active = 0;
801 * Setup the new label.
803 DoSetMethodNG( cd->cd_ArrayLabel, LAB_Label, cd->cd_Labels[ cd->cd_Active ], LAB_Place, PLACE_IN, TAG_END );
806 * We want to notify about the attribute change.
808 rc = GMR_NOREUSE | GMR_VERIFY;
809 cd->cd_Flags |= CDF_NOTIFY;
810 } else
812 * We are not selected anymore.
814 rc = GMR_NOREUSE;
816 sel = 0;
817 break;
819 case MENUDOWN:
820 sel = 0;
821 rc = GMR_REUSE;
822 break;
827 * Do we need a visual change?
829 if ((GADGET(obj)->Flags & GFLG_SELECTED) != sel)
832 * Toggle the selected bit.
834 GADGET(obj)->Flags ^= GFLG_SELECTED;
837 * Re-render the gadget.
839 DoRenderMethod(obj, gi, GREDRAW_REDRAW);
842 return rc;
844 METHOD_END
846 /// GM_GOINACTIVE
848 METHOD(CycleClassGoInactive, struct gpGoInactive *, gpgi)
850 CD *cd = INST_DATA( cl, obj );
853 * Popup window open?
855 if ( cd->cd_PopWindow ) {
857 * Close the window.
859 CloseWindow( cd->cd_PopWindow );
860 cd->cd_PopWindow = NULL;
864 * Close the font.
866 if ( cd->cd_Font ) {
867 BGUI_CloseFont( cd->cd_Font );
868 cd->cd_Font = NULL;
872 * Notify?
874 if ( cd->cd_Flags & CDF_NOTIFY ) {
875 DoNotifyMethod( obj, gpgi->gpgi_GInfo, 0L, GA_ID, GADGET( obj )->GadgetID, CYC_Active, cd->cd_Active, TAG_END );
876 cd->cd_Flags &= ~CDF_NOTIFY;
879 return( AsmDoSuperMethodA( cl, obj, ( Msg )gpgi ));
881 METHOD_END
882 /// OM_GET
883 /// OM_GET
885 * Get an attribute.
887 METHOD(CycleClassGet, struct opGet *, opg)
889 CD *cd = INST_DATA(cl, obj);
890 ULONG rc = 1, *store = opg->opg_Storage;
892 switch (opg->opg_AttrID)
894 case CYC_Active:
895 STORE cd->cd_Active;
896 break;
898 case CYC_Popup:
899 STORE cd->cd_Flags & CDF_POPUP;
900 break;
902 case CYC_PopActive:
903 STORE cd->cd_Flags & CDF_POPACTIVE;
904 break;
906 default:
907 rc = AsmDoSuperMethodA(cl, obj, (Msg)opg);
908 break;
910 return rc;
912 METHOD_END
914 /// OM_DISPOSE
916 * Dispose of the object.
918 METHOD(CycleClassDispose, Msg, msg)
920 CD *cd = INST_DATA(cl, obj);
922 if (cd->cd_ArrayLabel)
923 DisposeObject(cd->cd_ArrayLabel);
924 if (cd->cd_Image)
925 DisposeObject(cd->cd_Image);
927 if (cd->cd_Labels)
928 BGUI_FreePoolMem(cd->cd_Labels);
930 return AsmDoSuperMethodA(cl, obj, msg);
932 METHOD_END
934 /// BASE_DIMENSIONS
936 * The object size is requested.
938 METHOD(CycleClassDimensions, struct bmDimensions *, bmd)
940 CD *cd = INST_DATA(cl, obj);
941 struct BaseInfo *bi = bmd->bmd_BInfo;
942 UBYTE **labels = cd->cd_Labels, *label;
943 int mw = 0, mh = 0;
944 struct TextExtent te;
947 * Find out the size of the largest label.
949 while (label = *labels++)
952 * Call TextExtent to find out the text width.
954 TextExtent(bi->bi_RPort, label, strlen(label), &te);
955 if (te.te_Width > mw) mw = te.te_Width;
956 if (te.te_Height > mh) mh = te.te_Height;
960 * Include cycle/popup image width.
962 return CalcDimensions(cl, obj, bmd, mw + 30, mh + 2);
964 METHOD_END
966 /// WM_KEYACTIVE
968 * Key activation.
970 METHOD(CycleClassKeyActive, struct wmKeyInput *, wmki)
972 CD *cd = INST_DATA(cl, obj);
973 UWORD qual = wmki->wmki_IEvent->ie_Qualifier;
976 * Shifted is backwards, normal is forward.
978 if (qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
979 cd->cd_Active--;
980 else
981 cd->cd_Active++;
983 if (cd->cd_Active < 0) cd->cd_Active = cd->cd_NumLabels;
984 if (cd->cd_Active > cd->cd_NumLabels) cd->cd_Active = 0;
987 * Setup and re-render.
989 DoSetMethodNG(cd->cd_ArrayLabel, LAB_Label, cd->cd_Labels[cd->cd_Active], LAB_Place, PLACE_IN, TAG_END);
990 DoNotifyMethod(obj, wmki->wmki_GInfo, 0, GA_ID, GADGET(obj)->GadgetID, CYC_Active, cd->cd_Active, TAG_END);
991 DoRenderMethod(obj, wmki->wmki_GInfo, GREDRAW_REDRAW);
994 * Setup object ID.
996 *(wmki->wmki_ID) = GADGET(obj)->GadgetID;
998 return WMKF_VERIFY;
1000 METHOD_END
1003 /// Class initialization.
1005 * Function table.
1007 STATIC DPFUNC ClassFunc[] = {
1008 BASE_RENDER, (FUNCPTR)CycleClassRender,
1009 GM_RENDER, (FUNCPTR)CycleClassRenderX,
1010 BASE_DIMENSIONS, (FUNCPTR)CycleClassDimensions,
1012 OM_NEW, (FUNCPTR)CycleClassNew,
1013 OM_SET, (FUNCPTR)CycleClassSetUpdate,
1014 OM_UPDATE, (FUNCPTR)CycleClassSetUpdate,
1015 OM_GET, (FUNCPTR)CycleClassGet,
1016 OM_DISPOSE, (FUNCPTR)CycleClassDispose,
1017 GM_GOACTIVE, (FUNCPTR)CycleClassGoActive,
1018 GM_HANDLEINPUT, (FUNCPTR)CycleClassHandleInput,
1019 GM_GOINACTIVE, (FUNCPTR)CycleClassGoInactive,
1020 WM_KEYACTIVE, (FUNCPTR)CycleClassKeyActive,
1021 DF_END, NULL,
1025 * Simple class initialization.
1027 makeproto Class *InitCycleClass(void)
1029 return BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_BASE_GADGET,
1030 CLASS_ObjectSize, sizeof(CD),
1031 CLASS_DFTable, ClassFunc,
1032 TAG_DONE);