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.
14 * Revision 42.3 2004/06/16 20:16:48 verhaegs
15 * Use METHODPROTO, METHOD_END and REGFUNCPROTOn where needed.
17 * Revision 42.2 2000/05/15 19:27:00 stegerg
18 * another hundreds of REG() macro replacements in func headers/protos.
20 * Revision 42.1 2000/05/14 23:32:46 stegerg
21 * changed over 200 function headers which all use register
22 * parameters (oh boy ...), because the simple REG() macro
23 * doesn't work with AROS. And there are still hundreds
24 * of headers left to be fixed :(
26 * Many of these functions would also work with stack
27 * params, but since i have fixed every single one
28 * I encountered up to now, I guess will have to do
29 * the same for the rest.
31 * Revision 42.0 2000/05/09 22:08:32 mlemos
32 * Bumped to revision 42.0 before handing BGUI to AROS team
34 * Revision 41.11 2000/05/09 19:53:59 mlemos
35 * Merged with the branch Manuel_Lemos_fixes.
37 * Revision 41.10.2.3 1999/07/31 01:54:49 mlemos
38 * Ensured that the base object frame is restored before the object is
39 * disposed if the frame object was overwritte by the button class.
41 * Revision 41.10.2.2 1998/12/06 23:01:41 mlemos
42 * Fixed bug of select only buttons being deselected by keyboard activation.
44 * Revision 41.10.2.1 1998/11/17 16:05:36 mlemos
45 * Fixed the return value of BASE_RENDER to always reflect image changes.
47 * Revision 41.10 1998/02/25 21:11:42 mlemos
50 * Revision 1.1 1998/02/25 17:07:43 mlemos
56 /// Class definitions.
57 #include "include/classdefs.h"
60 * Object instance data.
63 ULONG bd_Flags
; /* See below. */
64 struct Image
*bd_Image
; /* Intuition image. */
65 struct Image
*bd_SelImage
; /* Selected intuition image. */
66 Object
*bd_Vector
; /* Vector image. */
67 Object
*bd_SelVector
; /* Selected vector image. */
68 Object
*bd_StoreFrame
; /* Storage for frame object. */
69 UWORD bd_ScaleWidth
; /* Design width of the vector. */
70 UWORD bd_ScaleHeight
; /* Design height of the vector. */
73 #define BDF_NO_DESELECT (1<<0) /* Don't deselect when selected. */
74 #define BDF_ENCLOSE (1<<1) /* Enclose image in frame. */
75 #define BDF_SYSIMAGE (1<<2) /* This is a system image. */
76 #define BDF_STORED_FRAME (1<<3) /* Stored base instance frame. */
80 * Change the object's attributes.
82 STATIC ASM IPTR
ButtonSetAttrs(REG(a0
) Class
*cl
, REG(a2
) Object
*obj
, REG(a1
) struct opSet
*ops
)
84 BD
*bd
= INST_DATA(cl
, obj
);
85 BC
*bc
= BASE_DATA(obj
);
88 struct TagItem
*tstate
= ops
->ops_AttrList
;
95 while ((tag
= NextTagItem(&tstate
)))
98 switch (attr
= tag
->ti_Tag
)
100 case VIT_VectorArray
:
106 DoSetMethodNG(bd
->bd_Vector
, attr
, data
, TAG_DONE
);
112 if (bd
->bd_Flags
& BDF_SYSIMAGE
)
114 DoSetMethodNG((Object
*)bd
->bd_Image
, SYSIA_Which
, data
, TAG_DONE
);
117 bd
->bd_Image
= (struct Image
*)BGUI_NewObject(BGUI_SYSTEM_IMAGE
, SYSIA_Which
, data
, TAG_DONE
);
118 bd
->bd_StoreFrame
= bc
->bc_Frame
;
119 bd
->bd_Flags
|= BDF_STORED_FRAME
;
121 bd
->bd_SelImage
= NULL
;
122 bd
->bd_Flags
|= BDF_SYSIMAGE
;
127 case BUTTON_SelectedImage
:
128 if (bd
->bd_Flags
& BDF_SYSIMAGE
)
130 bc
->bc_Frame
= bd
->bd_StoreFrame
;
131 bd
->bd_StoreFrame
= NULL
;
132 bd
->bd_Flags
&= ~BDF_STORED_FRAME
;
133 if (bd
->bd_Image
) DisposeObject(bd
->bd_Image
);
134 bd
->bd_Flags
&= ~BDF_SYSIMAGE
;
136 if (attr
== BUTTON_Image
)
138 bd
->bd_Image
= (struct Image
*)data
;
143 bd
->bd_SelImage
= (struct Image
*)data
;
149 if (bd
->bd_Vector
) DisposeObject(bd
->bd_Vector
);
150 bd
->bd_Vector
= (Object
*)data
;
154 case BUTTON_SelectedVector
:
155 if (bd
->bd_SelVector
) DisposeObject(bd
->bd_SelVector
);
156 bd
->bd_SelVector
= (Object
*)data
;
160 case BUTTON_ScaleMinWidth
:
161 bd
->bd_ScaleWidth
= data
;
164 case BUTTON_ScaleMinHeight
:
165 bd
->bd_ScaleHeight
= data
;
168 case BUTTON_SelectOnly
:
169 if (data
) bd
->bd_Flags
|= BDF_NO_DESELECT
;
170 else bd
->bd_Flags
&= ~BDF_NO_DESELECT
;
173 case BUTTON_EncloseImage
:
174 if (data
) bd
->bd_Flags
|= BDF_ENCLOSE
;
175 else bd
->bd_Flags
&= ~BDF_ENCLOSE
;
181 * Force the correct activation flags.
183 if (GADGET(obj
)->Activation
& GACT_TOGGLESELECT
)
185 GADGET(obj
)->Activation
|= GACT_IMMEDIATE
;
186 GADGET(obj
)->Activation
&= ~GACT_RELVERIFY
;
190 GADGET(obj
)->Activation
&= ~GACT_IMMEDIATE
;
191 GADGET(obj
)->Activation
|= GACT_RELVERIFY
;
199 * Create a new object.
201 METHOD(ButtonClassNew
, struct opSet
*, ops
)
204 struct TagItem
*tags
;
206 struct opSet opn
= *ops
;
208 tags
= DefTagList(BGUI_BUTTON_GADGET
, ops
->ops_AttrList
);
211 * First we let the superclass
214 if ((rc
= NewSuperObject(cl
, obj
, tags
)))
217 * Get the instance data.
219 bd
= INST_DATA(cl
, rc
);
221 opn
.ops_AttrList
= tags
;
222 ButtonSetAttrs(cl
, (Object
*)rc
, &opn
);
225 * See if we get a vector image.
227 if (!bd
->bd_Image
&& !bd
->bd_Vector
)
228 bd
->bd_Vector
= CreateVector(tags
);
236 /// OM_SET, OM_UPDATE
238 * Change the object's attributes.
240 METHOD(ButtonClassSetUpdate
, struct opUpdate
*, opu
)
242 BD
*bd
= INST_DATA(cl
, obj
);
243 WORD dis
= GADGET(obj
)->Flags
& GFLG_DISABLED
;
244 WORD sel
= GADGET(obj
)->Flags
& GFLG_SELECTED
;
248 * First we let the superclass do it's thing.
250 AsmDoSuperMethodA(cl
, obj
, (Msg
)opu
);
253 * F*ck interim messages.
255 if (opu
->MethodID
== OM_UPDATE
&& (opu
->opu_Flags
& OPUF_INTERIM
))
258 vis
= ButtonSetAttrs(cl
, obj
, (struct opSet
*)opu
);
261 * Visual change necessary?
263 if (((GADGET(obj
)->Flags
& GFLG_DISABLED
) != dis
) ||
264 ((GADGET(obj
)->Flags
& GFLG_SELECTED
) != sel
) || vis
)
266 DoRenderMethod(obj
, opu
->opu_GInfo
, GREDRAW_REDRAW
);
270 * Notify target when a toggle gadget's selected state changed.
272 if (GADGET(obj
)->Activation
& GACT_TOGGLESELECT
)
274 if ((GADGET(obj
)->Flags
& GFLG_SELECTED
) != sel
)
277 * Special MX magic...
279 if (!(sel
&& (bd
->bd_Flags
& BDF_NO_DESELECT
)))
281 DoNotifyMethod(obj
, opu
->opu_GInfo
, 0, GA_ID
, GADGET(obj
)->GadgetID
,
282 GA_Selected
, !sel
, GA_UserData
, GADGET(obj
)->UserData
, TAG_END
);
295 METHOD(ButtonClassRender
, struct bmRender
*, bmr
)
297 BD
*bd
= INST_DATA(cl
, obj
);
298 BC
*bc
= BASE_DATA(obj
);
299 struct BaseInfo
*bi
= bmr
->bmr_BInfo
;
300 struct Image
*image
= NULL
;
301 Object
*vector
= NULL
;
304 ULONG state
= GadgetState(bi
, obj
, FALSE
);
307 * Render the baseclass.
309 rc
=AsmDoSuperMethodA(cl
, obj
, (Msg
)bmr
);
312 * Pick up the image to render.
314 if (GADGET(obj
)->Flags
& GFLG_SELECTED
)
316 image
= bd
->bd_SelImage
;
317 vector
= bd
->bd_SelVector
;
319 if (!image
) image
= bd
->bd_Image
;
320 if (!vector
) vector
= bd
->bd_Vector
;
323 * Setup and render the gadget.
327 if (bd
->bd_Flags
& BDF_SYSIMAGE
)
330 * Setup the image dimensions.
332 image
->LeftEdge
= bc
->bc_OuterBox
.Left
;
333 image
->TopEdge
= bc
->bc_OuterBox
.Top
;
334 image
->Width
= bc
->bc_OuterBox
.Width
;
335 image
->Height
= bc
->bc_OuterBox
.Height
;
342 * Setup the left and top edge.
344 image
->LeftEdge
= bc
->bc_InnerBox
.Left
;
345 image
->TopEdge
= bc
->bc_InnerBox
.Top
;
348 * Center it in the hitbox.
350 x
= (bc
->bc_InnerBox
.Width
- image
->Width
) >> 1;
351 y
= (bc
->bc_InnerBox
.Height
- image
->Height
) >> 1;
356 BDrawImageState(bi
, (Object
*)image
, x
, y
, state
);
363 * Setup vector bounds.
365 DoSetMethodNG(vector
,
366 IA_Left
, bc
->bc_InnerBox
.Left
- 1, IA_Top
, bc
->bc_InnerBox
.Top
- 1,
367 IA_Width
, bc
->bc_InnerBox
.Width
+ 2, IA_Height
, bc
->bc_InnerBox
.Height
+ 2,
373 rc
= AsmDoMethod(vector
, BASE_RENDER
, bi
, state
);
379 if (GADGET(obj
)->Flags
& GFLG_DISABLED
)
380 BDisableBox(bi
, &bc
->bc_HitBox
);
390 STATIC
METHOD(ButtonClassGoActive
, struct gpInput
*, gpi
)
392 BD
*bd
= INST_DATA(cl
, obj
);
394 struct GadgetInfo
*gi
= gpi
->gpi_GInfo
;
397 * We cannot go active when
400 if (GADGET(obj
)->Flags
& GFLG_DISABLED
)
404 * We must be triggered by a mouse click
405 * or something simular.
410 * Let the superclass have a go...
412 AsmDoSuperMethodA(cl
, obj
, (Msg
)gpi
);
417 if (GADGET(obj
)->Activation
& GACT_TOGGLESELECT
)
420 * Special MX magic...
422 if ((bd
->bd_Flags
& BDF_NO_DESELECT
) && (GADGET( obj
)->Flags
& GFLG_SELECTED
))
426 * Toggle selected bit.
428 GADGET(obj
)->Flags
^= GFLG_SELECTED
;
433 DoRenderMethod(obj
, gi
, GREDRAW_REDRAW
);
434 DoNotifyMethod(obj
, gi
, 0, GA_ID
, GADGET(obj
)->GadgetID
,
435 GA_Selected
, GADGET(obj
)->Flags
& GFLG_SELECTED
,
436 GA_UserData
, GADGET(obj
)->UserData
, TAG_DONE
);
438 rc
= GMR_NOREUSE
| GMR_VERIFY
;
443 * Normal buttons require input.
445 GADGET(obj
)->Flags
|= GFLG_SELECTED
;
446 DoRenderMethod(obj
, gpi
->gpi_GInfo
, GREDRAW_REDRAW
);
459 * Handle button gadget input.
461 STATIC
METHOD(ButtonClassHandleInput
, struct gpInput
*,gpi
)
464 struct gpHitTest gph
;
465 struct GadgetInfo
*gi
= gpi
->gpi_GInfo
;
466 ULONG rc
= GMR_MEACTIVE
;
469 * Mouse over the object?
471 gph
.MethodID
= GM_HITTEST
;
473 gph
.gpht_Mouse
.X
= gpi
->gpi_Mouse
.X
;
474 gph
.gpht_Mouse
.Y
= gpi
->gpi_Mouse
.Y
;
476 if (AsmDoMethodA(obj
, (Msg
)&gph
) == GMR_GADGETHIT
)
482 if (gpi
->gpi_IEvent
->ie_Class
== IECLASS_RAWMOUSE
)
484 switch (gpi
->gpi_IEvent
->ie_Code
)
490 * When we are selected we verify.
495 * Send final notification.
497 DoNotifyMethod(obj
, gi
, 0, GA_ID
, GADGET(obj
)->GadgetID
, GA_UserData
, GADGET(obj
)->UserData
, TAG_END
);
498 rc
= GMR_NOREUSE
|GMR_VERIFY
;
511 * Another button aborts the selection.
513 DoSetMethodNG(obj
, BT_ReportID
, FALSE
, TAG_DONE
);
518 } else if ( gpi
->gpi_IEvent
->ie_Class
== IECLASS_TIMER
) {
520 * Every timer tick will result in an interim
521 * notification while the object is selected.
524 DoNotifyMethod(obj
, gi
, OPUF_INTERIM
, GA_ID
, GADGET(obj
)->GadgetID
, GA_UserData
, GADGET(obj
)->UserData
, TAG_END
);
530 if ((GADGET(obj
)->Flags
& GFLG_SELECTED
) != sel
)
533 * Flip selected bit and redraw.
535 GADGET(obj
)->Flags
^= GFLG_SELECTED
;
536 DoRenderMethod(obj
, gi
, GREDRAW_REDRAW
);
545 * They want to know something.
547 METHOD(ButtonClassGet
, struct opGet
*, opg
)
550 IPTR
*store
= opg
->opg_Storage
;
552 switch (opg
->opg_AttrID
)
555 * We make GA_Selected OM_GET'able.
558 STORE (GADGET(obj
)->Flags
& GFLG_SELECTED
);
562 rc
= AsmDoSuperMethodA(cl
, obj
, (Msg
)opg
);
571 * Dispose of ourselves.
573 METHOD(ButtonClassDispose
, Msg
, msg
)
575 BD
*bd
= INST_DATA(cl
, obj
);
576 BC
*bc
= BASE_DATA(obj
);
578 if ((bd
->bd_Flags
& BDF_SYSIMAGE
) && bd
->bd_Image
)
579 DisposeObject(bd
->bd_Image
);
581 if(bd
->bd_Flags
& BDF_STORED_FRAME
)
582 bc
->bc_Frame
= bd
->bd_StoreFrame
;
585 DisposeObject(bd
->bd_Vector
);
587 if (bd
->bd_SelVector
)
588 DisposeObject(bd
->bd_SelVector
);
590 return AsmDoSuperMethodA(cl
, obj
, msg
);
596 * We are activated by a key.
598 METHOD(ButtonClassKeyActive
, struct wmKeyInput
*, wmki
)
600 ULONG rc
= WMKF_MEACTIVE
;
601 struct GadgetInfo
*gi
= wmki
->wmki_GInfo
;
602 BD
*bd
= INST_DATA(cl
, obj
);
604 * If we are toggle-select we do not
607 if (GADGET(obj
)->Activation
& GACT_TOGGLESELECT
)
610 * Toggle-select buttons do not
611 * respond to repeated keys.
613 if ((!(wmki
->wmki_IEvent
->ie_Qualifier
& IEQUALIFIER_REPEAT
)
614 && (!(bd
->bd_Flags
& BDF_NO_DESELECT
)))
615 || !(GADGET(obj
)->Flags
& GFLG_SELECTED
))
620 GADGET(obj
)->Flags
^= GFLG_SELECTED
;
625 DoRenderMethod(obj
, gi
, GREDRAW_REDRAW
);
628 * Notify our state change.
630 DoNotifyMethod(obj
, gi
, 0, GA_ID
, GADGET( obj
)->GadgetID
, GA_Selected
, GADGET( obj
)->Flags
& GFLG_SELECTED
? TRUE
: FALSE
, GA_UserData
, GADGET( obj
)->UserData
, TAG_END
);
635 *(wmki
->wmki_ID
) = GADGET(obj
)->GadgetID
;
647 GADGET(obj
)->Flags
|= GFLG_SELECTED
;
652 DoRenderMethod(obj
, gi
, GREDRAW_REDRAW
);
660 * Handle key input messages.
662 METHOD(ButtonClassKeyInput
, struct wmKeyInput
*, wmki
)
664 ULONG rc
= WMKF_MEACTIVE
;
665 UWORD qual
= wmki
->wmki_IEvent
->ie_Qualifier
;
666 UWORD code
= wmki
->wmki_IEvent
->ie_Code
, key
;
667 struct GadgetInfo
*gi
= wmki
->wmki_GInfo
;
672 if (!(qual
& IEQUALIFIER_REPEAT
))
677 if (code
& IECODE_UP_PREFIX
)
680 * Check which key is released.
682 key
= MapKey(code
& ~IECODE_UP_PREFIX
, qual
, &wmki
->wmki_IEvent
->ie_EventAddress
);
685 * Is it the one that activated us?
687 if (*wmki
->wmki_Key
== key
|| *wmki
->wmki_Key
== tolower(key
))
692 DoNotifyMethod(obj
, gi
, 0, GA_ID
, GADGET(obj
)->GadgetID
, GA_UserData
, GADGET(obj
)->UserData
, TAG_END
);
697 *(wmki
->wmki_ID
) = GADGET(obj
)->GadgetID
;
701 else if ((qual
& (IEQUALIFIER_LSHIFT
|IEQUALIFIER_RSHIFT
)) || wmki
->wmki_IEvent
->ie_Code
== 0x45)
704 * We have been cancelled by either a SHIFT key
712 * Repeated key messages will trigger
713 * an interim notification.
715 DoNotifyMethod( obj
, gi
, OPUF_INTERIM
, GA_ID
, GADGET(obj
)->GadgetID
, GA_Selected
, GADGET(obj
)->Flags
& GFLG_SELECTED
? TRUE
: FALSE
, GA_UserData
, GADGET( obj
)->UserData
, TAG_END
);
723 * We are forced to de-activate.
725 METHOD(ButtonClassKeyInActive
, struct wmKeyInActive
*, wmkia
)
728 * Change visuals to un-selected when
731 if (!(GADGET(obj
)->Activation
& GACT_TOGGLESELECT
))
733 if (GADGET(obj
)->Flags
& GFLG_SELECTED
)
735 GADGET(obj
)->Flags
&= ~GFLG_SELECTED
;
736 DoRenderMethod( obj
, wmkia
->wmkia_GInfo
, GREDRAW_REDRAW
);
746 * They want our minimum dimensions.
748 METHOD(ButtonClassDimensions
, struct bmDimensions
*, bmd
)
750 BD
*bd
= INST_DATA(cl
, obj
);
751 struct BaseInfo
*bi
= bmd
->bmd_BInfo
;
754 UWORD mx
= 1, my
= 1;
757 if (bd
->bd_Image
|| bd
->bd_SelImage
)
760 * Get minimum sizes of the available images.
764 if (mx
< bd
->bd_Image
->Width
) mx
= bd
->bd_Image
->Width
;
765 if (my
< bd
->bd_Image
->Height
) my
= bd
->bd_Image
->Height
;
769 * Did we get a selected image?
773 if (mx
< bd
->bd_SelImage
->Width
) mx
= bd
->bd_SelImage
->Width
;
774 if (my
< bd
->bd_SelImage
->Height
) my
= bd
->bd_SelImage
->Height
;
777 if (!(bd
->bd_Flags
& BDF_ENCLOSE
))
783 if (bd
->bd_Flags
& BDF_SYSIMAGE
)
787 Get_Attr((Object
*)bd
->bd_Image
, SYSIA_Which
, &tmp
);
789 temp
= NewObject(NULL
, "sysiclass", SYSIA_Which
, tmp
, SYSIA_DrawInfo
, bi
->bi_DrInfo
,
790 SYSIA_Size
, (bi
->bi_IScreen
->Flags
& SCREENHIRES
) ? SYSISIZE_MEDRES
: SYSISIZE_LOWRES
, TAG_DONE
);
794 if (mx
< IMAGE(temp
)->Width
) mx
= IMAGE(temp
)->Width
;
795 if (my
< IMAGE(temp
)->Height
) my
= IMAGE(temp
)->Height
;
801 else if (bd
->bd_Vector
|| bd
->bd_SelVector
)
806 if (bd
->bd_ScaleWidth
&& bd
->bd_ScaleHeight
)
810 rx
= bi
->bi_DrInfo
->dri_Resolution
.X
;
811 ry
= bi
->bi_DrInfo
->dri_Resolution
.Y
;
818 my
= bi
->bi_RPort
->TxHeight
;
819 mx
= (my
* ry
* bd
->bd_ScaleWidth
) / (rx
* bd
->bd_ScaleHeight
);
824 * Get minimum vector sizes.
828 Get_Attr(bd
->bd_Vector
, VIT_MinWidth
, &tmp
);
829 if (mx
< tmp
) mx
= tmp
;
830 Get_Attr(bd
->bd_Vector
, VIT_MinHeight
, &tmp
);
831 if (my
< tmp
) my
= tmp
;
834 if (bd
->bd_SelVector
)
836 Get_Attr(bd
->bd_SelVector
, VIT_MinWidth
, &tmp
);
837 if (mx
< tmp
) mx
= tmp
;
838 Get_Attr(bd
->bd_SelVector
, VIT_MinHeight
, &tmp
);
839 if (my
< tmp
) my
= tmp
;
848 * Normal button. When BUTTON_EncloseImage is
849 * specified we make the label enclosed in the frame.
851 mx
= (bd
->bd_Flags
& BDF_ENCLOSE
) ? 0 : 4;
852 my
= (bd
->bd_Flags
& BDF_ENCLOSE
) ? 0 : 2;
856 * Compute dimensions and add our values.
858 return CalcDimensions(cl
, obj
, bmd
, mx
, my
);
863 METHOD(ButtonClassFindKey
, struct bmFindKey
*, bmfk
)
865 if (bmfk
->bmfk_Key
.Qual
& IEQUALIFIER_REPEAT
)
868 return AsmDoSuperMethodA(cl
, obj
, (Msg
)bmfk
);
872 /// Class initialization.
874 * Class function table.
876 STATIC DPFUNC ClassFunc
[] = {
877 { BASE_RENDER
, ButtonClassRender
, },
878 { GM_GOACTIVE
, ButtonClassGoActive
, },
879 { GM_HANDLEINPUT
, ButtonClassHandleInput
, },
881 { OM_SET
, ButtonClassSetUpdate
, },
882 { OM_UPDATE
, ButtonClassSetUpdate
, },
883 { OM_GET
, ButtonClassGet
, },
884 { OM_NEW
, ButtonClassNew
, },
885 { OM_DISPOSE
, ButtonClassDispose
, },
887 { WM_KEYACTIVE
, ButtonClassKeyActive
, },
888 { WM_KEYINPUT
, ButtonClassKeyInput
, },
889 { WM_KEYINACTIVE
, ButtonClassKeyInActive
, },
891 { BASE_DIMENSIONS
, ButtonClassDimensions
, },
892 { BASE_FINDKEY
, ButtonClassFindKey
, },
897 * Simple class initialization.
899 makeproto Class
*InitButtonClass(void)
901 return BGUI_MakeClass(CLASS_SuperClassBGUI
, BGUI_BASE_GADGET
,
902 CLASS_ObjectSize
, sizeof(BD
),
903 CLASS_DFTable
, ClassFunc
,