make sure "S" is generated.
[AROS-Contrib.git] / bgui / cycleclass.c
blobc50159385f200b4595edd47081158fbb2ba3555f
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 IPTR 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 ULONG oact = cd->cd_Active;
169 IPTR data;
170 struct TagItem *tstate = opu->opu_AttrList;
171 struct TagItem *tag;
172 WORD dis = GADGET(obj)->Flags & GFLG_DISABLED;
173 UBYTE **new_labels = NULL;
174 int num_labels;
175 BOOL render = FALSE;
176 struct GadgetInfo *gi = opu->opu_GInfo;
179 * First let the superclass do its thing.
181 AsmDoSuperMethodA(cl, obj, (Msg)opu);
184 * Force the correct activation method.
186 GADGET(obj)->Activation |= GACT_RELVERIFY;
187 GADGET(obj)->Activation &= ~GACT_IMMEDIATE;
189 while ((tag = NextTagItem(&tstate)))
191 data = tag->ti_Data;
192 switch (tag->ti_Tag)
194 case BT_TextAttr:
195 cd->cd_PopupFont = (struct TextAttr *)data;
197 * Let the label know.
199 DoSetMethodNG(cd->cd_ArrayLabel, LAB_TextAttr, data, TAG_DONE);
200 break;
202 case FRM_ThinFrame:
203 if (data) cd->cd_Flags |= CDF_THIN;
204 else cd->cd_Flags &= ~CDF_THIN;
205 break;
207 case CYC_Active:
208 cd->cd_Active = data;
209 break;
211 case CYC_Labels:
213 * Count the number of labels in the array (offset by 1).
215 num_labels = data ? CountLabels((UBYTE **)data) : -1;
217 if (num_labels >= 0)
219 if ((new_labels = BGUI_AllocPoolMem((num_labels + 2) * sizeof(UBYTE *))))
221 if (cd->cd_Labels) BGUI_FreePoolMem(cd->cd_Labels);
222 cd->cd_Labels = new_labels;
223 cd->cd_NumLabels = num_labels;
224 CopyMem((UBYTE *)data, (UBYTE *)new_labels, (num_labels + 1) * sizeof(UBYTE *));
227 render = TRUE;
228 break;
230 case CYC_Popup:
231 if (data) cd->cd_Flags |= CDF_POPUP;
232 else cd->cd_Flags &= ~CDF_POPUP;
233 break;
235 case CYC_PopActive:
236 if (data) cd->cd_Flags |= CDF_POPACTIVE;
237 else cd->cd_Flags &= ~CDF_POPACTIVE;
238 break;
242 if ((GADGET(obj)->Flags & GFLG_DISABLED) != dis)
244 * Re-render when the gadget disabled state changed.
246 render = TRUE;
249 * Here's that sanity check again.
251 if (cd->cd_Active > cd->cd_NumLabels)
252 cd->cd_Active = cd->cd_NumLabels;
254 if ((oact != cd->cd_Active) || new_labels)
257 * Setup new text.
259 DoSetMethodNG(cd->cd_ArrayLabel, LAB_Label, cd->cd_Labels[cd->cd_Active], LAB_Place, PLACE_IN, TAG_DONE);
260 render = TRUE;
263 if (render) DoRenderMethod(obj, gi, GREDRAW_REDRAW);
266 * Notify the target when necessary.
268 if (oact != cd->cd_Active)
270 DoNotifyMethod(obj, gi, 0, GA_ID, GADGET(obj)->GadgetID, CYC_Active, cd->cd_Active, TAG_DONE);
272 return 1;
274 METHOD_END
277 /// RenderArrow
279 * Render the cycle arrow.
281 STATIC VOID RenderArrow(struct BaseInfo *bi, struct IBox *ib, ULONG state, CD *cd)
283 Object *image = cd->cd_Image;
284 ULONG type;
287 * Get coords.
289 int w = cd->cd_ImageWidth;
290 int h = ib->Height;
291 int l = ib->Left - w;
292 int t = ib->Top;
295 * Render the small seperator.
297 BSetDrMd(bi, JAM1);
299 BSetDPenA(bi, (state != IDS_SELECTED) ? SHINEPEN : SHADOWPEN);
300 VLine(bi->bi_RPort, l + w + 1, t + 2, t + h - 3);
302 BSetDPenA(bi, (state != IDS_SELECTED) ? SHADOWPEN : SHINEPEN);
303 VLine(bi->bi_RPort, l + w, t + 2, t + h - 3);
305 if (state == IDS_SELECTED)
307 type = BUILTIN_CYCLE2;
309 else
311 type = (cd->cd_Flags & CDF_POPUP) ? BUILTIN_POPUP : BUILTIN_CYCLE;
315 * Setup and render the image.
317 DoSetMethodNG(image, VIT_BuiltIn, type, IA_Left, l, IA_Top, t, IA_Width, w, IA_Height, h, TAG_END);
318 BDrawImageState(bi, image, 0, 0, state);
321 /// RenderPopupEntry
323 * Render an entry in the popup-list.
325 STATIC VOID RenderPopupEntry(struct BaseInfo *bi, CD *cd, ULONG num, BOOL sel)
327 UWORD ypos, xpos, tlen, pix = cd->cd_Flags & CDF_THIN ? 2 : 4;
328 UBYTE *name = cd->cd_Labels[num];
329 struct RastPort *rp = bi->bi_RPort;
332 * Compute text length.
334 tlen = TextWidth(rp, name);
337 * Compute positions.
339 xpos = (cd->cd_PopWindow->Width - tlen) >> 1;
340 ypos = (num * rp->TxHeight) + 2;
343 * Setup pens for filling.
345 #ifdef ENHANCED
346 BSetDPenA(bi, sel ? BARDETAILPEN : BARBLOCKPEN);
347 #else
348 if (OS30) BSetDPenA(bi, sel ? BARDETAILPEN : BARBLOCKPEN);
349 else BSetDPenA(bi, BLOCKPEN);
350 #endif
353 * RectFill entry.
355 BSetDrMd(bi, JAM1);
356 BRectFill(bi, pix, ypos, cd->cd_PopWindow->Width - pix - 1, ypos + rp->TxHeight - 1);
359 * Setup drawmode.
361 #ifdef ENHANCED
362 BSetDrMd(bi, sel ? JAM2|INVERSVID : JAM2);
363 #else
364 if (OS30) BSetDrMd(bi, sel ? JAM2|INVERSVID : JAM2);
365 else BSetDrMd(bi, JAM2);
366 #endif
369 * Setup pens for text.
371 BSetDPenA(bi, BARDETAILPEN);
372 BSetDPenB(bi, BARBLOCKPEN);
375 * Move to the desired location and render.
377 Move(rp, xpos, ypos + rp->TxBaseline);
378 Text(rp, name, strlen(name));
380 #ifndef ENHANCED
382 * < OS 3.0 will get the entry
383 * complemented if it is selected.
385 if (!OS30 && sel)
387 BSetDrMd(bi, JAM2|COMPLEMENT);
388 BRectFill(bi, pix, ypos, cd->cd_PopWindow->Width - pix - 1, ypos + rp->TxHeight - 1);
390 #endif
393 /// GM_RENDER
395 * Render the object.
397 METHOD(CycleClassRenderX, struct gpRender *, gpr)
399 CD *cd = INST_DATA(cl, obj);
401 DoSuperSetMethodNG(cl, obj, BT_LeftOffset, cd->cd_ImageWidth, TAG_DONE);
403 return AsmDoSuperMethodA(cl, obj, (Msg)gpr);
405 METHOD_END
407 /// BASE_RENDER
409 * Render the object.
411 METHOD(CycleClassRender, struct bmRender *, bmr)
413 CD *cd = INST_DATA(cl, obj);
414 BC *bc = BASE_DATA(obj);
415 struct BaseInfo *bi = bmr->bmr_BInfo;
416 int state = GADGET(obj)->Flags & GFLG_SELECTED ? IDS_SELECTED : IDS_NORMAL;
419 * Render the baseclass.
421 AsmDoSuperMethodA(cl, obj, (Msg)bmr);
424 * Setup array label.
426 *IMAGEBOX(cd->cd_ArrayLabel) = bc->bc_InnerBox;
429 * Render the arrow.
431 RenderArrow(bi, &bc->bc_InnerBox, state, cd);
434 * We always render the active gadget label.
436 BDrawImageState(bi, cd->cd_ArrayLabel, 0, 0, state);
439 * Ghost the gadget when it is disabled.
441 if (GADGET(obj)->Flags & GFLG_DISABLED)
442 BDisableBox(bi, &bc->bc_HitBox);
444 return 1;
446 METHOD_END
449 /// OpenPopupWindow
451 * Open the popup-window.
453 STATIC ASM IPTR OpenPopupWindow(REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct gpInput *gpi)
455 CD *cd = INST_DATA(cl, obj);
456 BC *bc = BASE_DATA(obj);
457 UWORD max_items, num_items, wleft, wtop, wwi, wwh, i;
458 struct IBox *ibox;
459 struct RastPort *rp;
460 struct GadgetInfo *gi = gpi->gpi_GInfo;
461 struct BaseInfo *bi;
462 int ysize;
463 ULONG rc = GMR_NOREUSE;
466 * Get the gadget hitbox bounds.
468 Get_SuperAttr(cl, obj, BT_HitBox, (IPTR *)&ibox);
471 * Open the font.
473 if (cd->cd_PopupFont)
474 cd->cd_Font = BGUI_OpenFont(cd->cd_PopupFont);
476 /* BAD CODE! Does not check OpenFont result! */
478 ysize = cd->cd_Font->tf_YSize;
481 * How many items will fit?
483 max_items = (gi->gi_Screen->Height - 4) / ysize;
486 * How many do we have?
488 num_items = (cd->cd_NumLabels + 1) > max_items ? max_items : (cd->cd_NumLabels + 1);
491 * Compute window position and dimensions.
493 wleft = bc->bc_HitBox.Left + gi->gi_Window->LeftEdge;
494 wwi = bc->bc_HitBox.Width;
495 wwh = (num_items * ysize) + 4;
497 if (cd->cd_Flags & CDF_POPACTIVE)
498 wtop = gi->gi_Screen->MouseY - (2 + ((cd->cd_Active * ysize) + (ysize >> 1)));
499 else
500 wtop = bc->bc_HitBox.Top + bc->bc_HitBox.Height + gi->gi_Window->TopEdge;
503 * Pop the window.
505 cd->cd_PopWindow = OpenWindowTags(NULL, WA_Left, wleft, WA_Top, wtop,
506 WA_Width, wwi, WA_Height, wwh,
507 WA_Flags, 0, WA_IDCMP, 0,
508 WA_Borderless, TRUE, WA_AutoAdjust, TRUE,
509 WA_SmartRefresh, TRUE, WA_NoCareRefresh, TRUE,
510 WA_RMBTrap, TRUE, WA_CustomScreen, gi->gi_Screen,
511 TAG_DONE);
513 * success?
515 if (cd->cd_PopWindow)
518 * No previous selected item.
520 cd->cd_Previous = (UWORD)~0;
522 /* AROS BUGFIX --> AMIGAOS BUGFIX: TAG_DONE missed in both AllocBaseInfoDebug and AllocBaseInfo call below */
523 #ifdef DEBUG_BGUI
524 if ((bi = AllocBaseInfoDebug(__FILE__,__LINE__,BI_Screen, gi->gi_Screen, BI_RastPort, rp = cd->cd_PopWindow->RPort, TAG_DONE)))
525 #else
526 if ((bi = AllocBaseInfo(BI_Screen, gi->gi_Screen, BI_RastPort, rp = cd->cd_PopWindow->RPort, TAG_DONE)))
527 #endif
530 * Setup the font.
532 if (cd->cd_Font) BSetFont(bi, cd->cd_Font);
535 * Setup pop window rastport.
537 BSetDPenA(bi, BARBLOCKPEN);
538 BSetDrMd(bi, JAM1);
541 * Fill...
543 BBoxFill(bi, 0, 0, wwi, wwh);
546 * Setup pop window rastport.
548 BSetDPenA(bi, BARDETAILPEN);
551 * Render border.
553 Move(rp, 0, 0 );
554 Draw(rp, wwi - 1, 0);
555 Draw(rp, wwi - 1, wwh - 1 );
556 Draw(rp, 0, wwh - 1 );
557 Draw(rp, 0, 0 );
559 if (!(cd->cd_Flags & CDF_THIN))
561 Move(rp, 1, 0 );
562 Draw(rp, 1, wwh - 1 );
563 Move(rp, wwi - 2, 0 );
564 Draw(rp, wwi - 2, wwh - 1 );
568 * Render list-entries.
570 for (i = 0; i < num_items; i++)
571 RenderPopupEntry(bi, cd, i, FALSE);
573 FreeBaseInfo(bi);
575 rc = GMR_MEACTIVE;
578 return rc;
582 /// GM_GOACTIVE
584 * Go in active mode.
586 METHOD(CycleClassGoActive, struct gpInput *, gpi)
588 CD *cd = INST_DATA(cl, obj);
589 BC *bc = BASE_DATA(obj);
590 ULONG rc = GMR_NOREUSE;
593 * We don't go active when we are disabled.
595 if ( GADGET( obj )->Flags & GFLG_DISABLED )
596 return( GMR_NOREUSE );
599 * We only go active when triggered by a mouse click.
601 if (gpi->gpi_IEvent)
604 * Let the superclass have a go...
606 AsmDoSuperMethodA(cl, obj, (Msg)gpi);
609 * Popup mode?
611 if (cd->cd_Flags & CDF_POPUP)
613 if (gpi->gpi_GInfo->gi_Window->MouseX > (bc->bc_HitBox.Left + cd->cd_ImageWidth))
616 * Open the popup window.
617 * Do normal selection if the popup window will not open.
619 if (OpenPopupWindow(cl, obj, gpi) == 0) return 0;
622 GADGET(obj)->Flags |= GFLG_SELECTED;
623 DoRenderMethod(obj, gpi->gpi_GInfo, GREDRAW_REDRAW);
624 rc = GMR_MEACTIVE;
626 return rc;
628 METHOD_END
632 * Which entry is selected?
634 STATIC ASM UWORD Selected(REG(a0) CD *cd, REG(a1) struct RastPort *rp)
636 WORD mx = cd->cd_PopWindow->MouseX, my = cd->cd_PopWindow->MouseY;
637 LONG item = ~0;
640 * Mouse in the window?
642 if ( mx >= 4 && mx < ( cd->cd_PopWindow->Width - 4 ) && my >= 2 && my < ( cd->cd_PopWindow->Height - 2 )) {
644 * Find the entry the mouse is over.
646 item = ( my - 2 ) / rp->TxHeight;
648 if ( item > cd->cd_NumLabels ) item = ~0;
650 return(( UWORD )item );
653 /// GM_HANDLEINPUT
655 * Handle the gadget input.
657 METHOD(CycleClassHandleInput, struct gpInput *, gpi)
659 CD *cd = INST_DATA(cl, obj);
660 struct gpHitTest gph;
661 WORD sel = 0, item;
662 struct GadgetInfo *gi = gpi->gpi_GInfo;
663 struct BaseInfo *bi;
664 ULONG rc = GMR_MEACTIVE;
667 * Window up?
669 if (cd->cd_PopWindow)
672 * Is the parent window still activated?
673 * If not we return immediatly.
675 * Security. Intuition should do this already.
677 if (!(gi->gi_Window->Flags & WFLG_WINDOWACTIVE))
678 return GMR_NOREUSE;
680 #ifdef DEBUG_BGUI
681 if ((bi = AllocBaseInfoDebug(__FILE__,__LINE__,BI_GadgetInfo, gi, BI_RastPort, cd->cd_PopWindow->RPort, TAG_DONE)))
682 #else
683 if ((bi = AllocBaseInfo(BI_GadgetInfo, gi, BI_RastPort, cd->cd_PopWindow->RPort, TAG_DONE)))
684 #endif
687 * Where is the mouse?
689 item = Selected(cd, bi->bi_RPort);
692 * Changed?
694 if (item != cd->cd_Previous)
697 * Previous selected item?
699 if (cd->cd_Previous != (UWORD)~0) RenderPopupEntry(bi, cd, cd->cd_Previous, FALSE);
702 * Render current entry.
704 if (item != ~0) RenderPopupEntry(bi, cd, item, TRUE);
707 * Setup item.
709 cd->cd_Previous = item;
711 FreeBaseInfo(bi);
714 * What's the event?
716 if (gpi->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE)
718 switch (gpi->gpi_IEvent->ie_Code)
720 case SELECTUP:
722 * Setup the new label and return VERIFY.
724 if (cd->cd_Previous != (UWORD)~0)
726 if (cd->cd_Active != cd->cd_Previous)
729 * We need notification.
731 cd->cd_Flags |= CDF_NOTIFY;
734 * New active entry.
736 cd->cd_Active = cd->cd_Previous;
739 * Setup the new label.
741 DoSetMethodNG(cd->cd_ArrayLabel, LAB_Label, cd->cd_Labels[cd->cd_Active], LAB_Place, PLACE_IN, TAG_END);
744 * Re-render to show the change.
746 DoRenderMethod(obj, gi, GREDRAW_REDRAW);
749 * We want to notify about the attribute change.
751 rc = GMR_NOREUSE | GMR_VERIFY;
752 } else
753 rc = GMR_NOREUSE;
754 } else
755 rc = GMR_NOREUSE;
756 break;
758 case MENUDOWN:
759 rc = GMR_NOREUSE;
760 break;
765 else
768 * Mouse over the object?
770 gph.MethodID = GM_HITTEST;
771 gph.gpht_GInfo = gpi->gpi_GInfo;
772 gph.gpht_Mouse.X = gpi->gpi_Mouse.X;
773 gph.gpht_Mouse.Y = gpi->gpi_Mouse.Y;
775 if ( AsmDoMethodA( obj, ( Msg )&gph ) == GMR_GADGETHIT )
776 sel = GFLG_SELECTED;
778 if ( gpi->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE ) {
779 switch ( gpi->gpi_IEvent->ie_Code ) {
781 case SELECTUP:
783 * When we are selected we setup a new label
784 * and return VERIFY.
786 if ( sel ) {
788 * Clicked with the shift key down cycles backward.
790 if ( gpi->gpi_IEvent->ie_Qualifier & ( IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT )) {
791 if ( cd->cd_Active ) cd->cd_Active--;
792 else cd->cd_Active = cd->cd_NumLabels;
793 } else {
794 if ( cd->cd_Active < cd->cd_NumLabels ) cd->cd_Active++;
795 else cd->cd_Active = 0;
799 * Setup the new label.
801 DoSetMethodNG( cd->cd_ArrayLabel, LAB_Label, cd->cd_Labels[ cd->cd_Active ], LAB_Place, PLACE_IN, TAG_END );
804 * We want to notify about the attribute change.
806 rc = GMR_NOREUSE | GMR_VERIFY;
807 cd->cd_Flags |= CDF_NOTIFY;
808 } else
810 * We are not selected anymore.
812 rc = GMR_NOREUSE;
814 sel = 0;
815 break;
817 case MENUDOWN:
818 sel = 0;
819 rc = GMR_REUSE;
820 break;
825 * Do we need a visual change?
827 if ((GADGET(obj)->Flags & GFLG_SELECTED) != sel)
830 * Toggle the selected bit.
832 GADGET(obj)->Flags ^= GFLG_SELECTED;
835 * Re-render the gadget.
837 DoRenderMethod(obj, gi, GREDRAW_REDRAW);
840 return rc;
842 METHOD_END
844 /// GM_GOINACTIVE
846 METHOD(CycleClassGoInactive, struct gpGoInactive *, gpgi)
848 CD *cd = INST_DATA( cl, obj );
851 * Popup window open?
853 if ( cd->cd_PopWindow ) {
855 * Close the window.
857 CloseWindow( cd->cd_PopWindow );
858 cd->cd_PopWindow = NULL;
862 * Close the font.
864 if ( cd->cd_Font ) {
865 BGUI_CloseFont( cd->cd_Font );
866 cd->cd_Font = NULL;
870 * Notify?
872 if ( cd->cd_Flags & CDF_NOTIFY ) {
873 DoNotifyMethod( obj, gpgi->gpgi_GInfo, 0L, GA_ID, GADGET( obj )->GadgetID, CYC_Active, cd->cd_Active, TAG_END );
874 cd->cd_Flags &= ~CDF_NOTIFY;
877 return( AsmDoSuperMethodA( cl, obj, ( Msg )gpgi ));
879 METHOD_END
880 /// OM_GET
881 /// OM_GET
883 * Get an attribute.
885 METHOD(CycleClassGet, struct opGet *, opg)
887 CD *cd = INST_DATA(cl, obj);
888 ULONG rc = 1;
889 IPTR *store = opg->opg_Storage;
891 switch (opg->opg_AttrID)
893 case CYC_Active:
894 STORE cd->cd_Active;
895 break;
897 case CYC_Popup:
898 STORE cd->cd_Flags & CDF_POPUP;
899 break;
901 case CYC_PopActive:
902 STORE cd->cd_Flags & CDF_POPACTIVE;
903 break;
905 default:
906 rc = AsmDoSuperMethodA(cl, obj, (Msg)opg);
907 break;
909 return rc;
911 METHOD_END
913 /// OM_DISPOSE
915 * Dispose of the object.
917 METHOD(CycleClassDispose, Msg, msg)
919 CD *cd = INST_DATA(cl, obj);
921 if (cd->cd_ArrayLabel)
922 DisposeObject(cd->cd_ArrayLabel);
923 if (cd->cd_Image)
924 DisposeObject(cd->cd_Image);
926 if (cd->cd_Labels)
927 BGUI_FreePoolMem(cd->cd_Labels);
929 return AsmDoSuperMethodA(cl, obj, msg);
931 METHOD_END
933 /// BASE_DIMENSIONS
935 * The object size is requested.
937 METHOD(CycleClassDimensions, struct bmDimensions *, bmd)
939 CD *cd = INST_DATA(cl, obj);
940 struct BaseInfo *bi = bmd->bmd_BInfo;
941 UBYTE **labels = cd->cd_Labels, *label;
942 int mw = 0, mh = 0;
943 struct TextExtent te;
946 * Find out the size of the largest label.
948 while ((label = *labels++))
951 * Call TextExtent to find out the text width.
953 TextExtent(bi->bi_RPort, label, strlen(label), &te);
954 if (te.te_Width > mw) mw = te.te_Width;
955 if (te.te_Height > mh) mh = te.te_Height;
959 * Include cycle/popup image width.
961 return CalcDimensions(cl, obj, bmd, mw + 30, mh + 2);
963 METHOD_END
965 /// WM_KEYACTIVE
967 * Key activation.
969 METHOD(CycleClassKeyActive, struct wmKeyInput *, wmki)
971 CD *cd = INST_DATA(cl, obj);
972 UWORD qual = wmki->wmki_IEvent->ie_Qualifier;
975 * Shifted is backwards, normal is forward.
977 if (qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
978 cd->cd_Active--;
979 else
980 cd->cd_Active++;
982 if (cd->cd_Active < 0) cd->cd_Active = cd->cd_NumLabels;
983 if (cd->cd_Active > cd->cd_NumLabels) cd->cd_Active = 0;
986 * Setup and re-render.
988 DoSetMethodNG(cd->cd_ArrayLabel, LAB_Label, cd->cd_Labels[cd->cd_Active], LAB_Place, PLACE_IN, TAG_END);
989 DoNotifyMethod(obj, wmki->wmki_GInfo, 0, GA_ID, GADGET(obj)->GadgetID, CYC_Active, cd->cd_Active, TAG_END);
990 DoRenderMethod(obj, wmki->wmki_GInfo, GREDRAW_REDRAW);
993 * Setup object ID.
995 *(wmki->wmki_ID) = GADGET(obj)->GadgetID;
997 return WMKF_VERIFY;
999 METHOD_END
1002 /// Class initialization.
1004 * Function table.
1006 STATIC DPFUNC ClassFunc[] = {
1007 { BASE_RENDER, CycleClassRender, },
1008 { GM_RENDER, CycleClassRenderX, },
1009 { BASE_DIMENSIONS, CycleClassDimensions, },
1011 { OM_NEW, CycleClassNew, },
1012 { OM_SET, CycleClassSetUpdate, },
1013 { OM_UPDATE, CycleClassSetUpdate, },
1014 { OM_GET, CycleClassGet, },
1015 { OM_DISPOSE, CycleClassDispose, },
1016 { GM_GOACTIVE, CycleClassGoActive, },
1017 { GM_HANDLEINPUT, CycleClassHandleInput, },
1018 { GM_GOINACTIVE, CycleClassGoInactive, },
1019 { WM_KEYACTIVE, CycleClassKeyActive, },
1020 { DF_END, NULL, },
1024 * Simple class initialization.
1026 makeproto Class *InitCycleClass(void)
1028 return BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_BASE_GADGET,
1029 CLASS_ObjectSize, sizeof(CD),
1030 CLASS_DFTable, ClassFunc,
1031 TAG_DONE);