Updated to latest source.
[AROS-Contrib.git] / bgui / propclass.c
blobcd55197269e333136db27949c4b397ed4bc9d4ca
1 /*
2 * @(#) $Header$
4 * BGUI library
5 * propclass.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.4 2004/06/16 20:16:48 verhaegs
15 * Use METHODPROTO, METHOD_END and REGFUNCPROTOn where needed.
17 * Revision 42.3 2000/08/17 15:09:18 chodorowski
18 * Fixed compiler warnings.
20 * Revision 42.2 2000/05/15 19:27:02 stegerg
21 * another hundreds of REG() macro replacements in func headers/protos.
23 * Revision 42.1 2000/05/14 23:32:48 stegerg
24 * changed over 200 function headers which all use register
25 * parameters (oh boy ...), because the simple REG() macro
26 * doesn't work with AROS. And there are still hundreds
27 * of headers left to be fixed :(
29 * Many of these functions would also work with stack
30 * params, but since i have fixed every single one
31 * I encountered up to now, I guess will have to do
32 * the same for the rest.
34 * Revision 42.0 2000/05/09 22:09:56 mlemos
35 * Bumped to revision 42.0 before handing BGUI to AROS team
37 * Revision 41.11 2000/05/09 19:54:55 mlemos
38 * Merged with the branch Manuel_Lemos_fixes.
40 * Revision 41.10.2.5 2000/01/30 20:41:12 mlemos
41 * Fixed bug of not adding the arrows size to the minimum and nominal
42 * dimensions of the gadget.
44 * Revision 41.10.2.4 1998/12/06 21:40:53 mlemos
45 * Ensured that when the parent view and window are passed to the arrow
46 * gadgets on their creation.
48 * Revision 41.10.2.3 1998/11/13 18:21:53 mlemos
49 * Reverted the workaround patch that set the screen pointer in the BaseInfo
50 * structure as the real problem was fixed AllocBaseInfo function.
52 * Revision 41.10.2.2 1998/11/03 10:45:28 mlemos
53 * Added workaround to avoid enforcer hits cause by ROM propclass looking at
54 * the GadgetInfo Screen pointer inside GM_RENDER method.
56 * Revision 41.10.2.1 1998/10/01 04:38:52 mlemos
57 * Fixed bug of sending interim notifications after adjusting the knob.
59 * Revision 41.10 1998/02/25 21:12:53 mlemos
60 * Bumping to 41.10
62 * Revision 1.1 1998/02/25 17:09:29 mlemos
63 * Ian sources
68 /// Class definitions.
70 #include "include/classdefs.h"
73 * Object instance data.
75 typedef struct {
76 ULONG pd_Flags; /* see below */
77 Object *pd_Prop; /* prop gadget object */
78 Object *pd_Knob; /* prop gadget knob */
79 Object *pd_Arrow1; /* up/left arrow */
80 Object *pd_Arrow2; /* down/right arrow */
81 LONG pd_Top; /* prop to position */
82 LONG pd_Total; /* prop total range */
83 LONG pd_Visible; /* prop visible portion */
84 LONG pd_Min; /* minimum level */
85 LONG pd_Max; /* maximum level */
86 LONG pd_Level; /* current level */
87 LONG pd_Reset1; /* Initial top value */
88 LONG pd_Reset2; /* Initial top level */
89 UWORD pd_ArrowSize; /* size of arrows */
90 UWORD pd_RptTicks; /* repeat treshold */
91 } PD;
93 #define PDF_ARROWS (1<<0) /* prop has arrows */
94 #define PDF_NEWLOOK (1<<1) /* prop must be "NewLook" */
95 #define PDF_PROPHORIZ (1<<2) /* prop moves horizontally */
96 #define PDF_PROPACTIVE (1<<3) /* prop is active */
97 #define PDF_LEFT_UP (1<<4) /* left/up gadget active */
98 #define PDF_RIGHT_DOWN (1<<5) /* right/down active */
99 #define PDF_RESET (1<<6) /* Reset to pd_Initial */
100 #define PDF_SLIDER (1<<7) /* Slider mode. */
101 #define PDF_READY (1<<8) /* Created and ready. */
106 * Calculate arrow and prop positions.
108 STATIC VOID CalcPropMuck(Class *cl, Object *obj, struct BaseInfo *bi)
110 PD *pd = INST_DATA(cl, obj);
111 BC *bc = BASE_DATA(obj);
112 int size = pd->pd_ArrowSize;
113 ULONG kw, kh;
114 struct IBox arrow1, arrow2;
117 * Check for arrows and where they are placed.
119 if (pd->pd_Flags & PDF_ARROWS)
122 * Copy the hitbox to the destinations
124 arrow1 = arrow2 = bc->bc_HitBox;
127 * FREEHORIZ will get the arrows
128 * on the right side. FREEVERT will
129 * get them below.
131 if (pd->pd_Flags & PDF_PROPHORIZ)
133 arrow1.Left += bc->bc_HitBox.Width;
134 arrow2.Left = arrow1.Left + size;
135 arrow1.Width = arrow2.Width = size;
137 else
139 arrow1.Top += bc->bc_HitBox.Height;
140 arrow2.Top = arrow1.Top + size;
141 arrow1.Height = arrow2.Height = size;
143 SetGadgetBounds(pd->pd_Arrow1, &arrow1);
144 SetGadgetBounds(pd->pd_Arrow2, &arrow2);
148 * Setup the slider.
151 if (pd->pd_Flags & PDF_SLIDER)
153 if (pd->pd_Flags & PDF_PROPHORIZ) pd->pd_Top = pd->pd_Level - pd->pd_Min;
154 else pd->pd_Top = pd->pd_Max - pd->pd_Level;
158 * Set it up.
160 DoSetMethodNG(pd->pd_Prop, GA_Left, bc->bc_InnerBox.Left, GA_Top, bc->bc_InnerBox.Top,
161 GA_Width, bc->bc_InnerBox.Width, GA_Height, bc->bc_InnerBox.Height,
162 PGA_Top, pd->pd_Top, PGA_Total, pd->pd_Total,
163 PGA_Visible, pd->pd_Visible, TAG_DONE);
165 if (pd->pd_Knob)
167 kw = bc->bc_InnerBox.Width;
168 kh = bc->bc_InnerBox.Height;
170 if ((pd->pd_Total > 0) && (pd->pd_Total > pd->pd_Visible))
172 if (pd->pd_Flags & PDF_PROPHORIZ)
174 kw = (kw * (ULONG)pd->pd_Visible) / pd->pd_Total;
175 if (kw < 4) kw = 4;
177 else
179 kh = (kh * (ULONG)pd->pd_Visible) / pd->pd_Total;
180 if (kh < 4) kh = 4;
183 DoSetMethodNG(pd->pd_Knob, IA_Width, kw, IA_Height, kh, TAG_DONE);
187 /// OM_NEW
189 * Create a shiny new object.
191 METHOD(PropClassNew, struct opSet *, ops)
193 PD *pd;
194 BC *bc;
195 struct TagItem *tags;
196 ULONG rc;
197 BOOL horiz;
199 tags = DefTagList(BGUI_PROP_GADGET, ops->ops_AttrList);
202 * First we let the superclass get us an object.
204 if (rc = NewSuperObject(cl, obj, tags))
207 * Obtain instance data.
209 pd = INST_DATA(cl, rc);
210 bc = BASE_DATA(rc);
212 if (!bc->bc_Frame) goto failure;
215 * Make sure we are GACT_RELVERIFY.
217 GADGET(rc)->Activation |= GACT_RELVERIFY;
220 * Setup defaults.
222 pd->pd_Visible = 1;
223 pd->pd_Total = 1;
224 pd->pd_Flags = GetTagData(PGA_Slider, FALSE, tags) ? PDF_SLIDER|PDF_PROPHORIZ : PDF_ARROWS;
225 pd->pd_Max = 15;
227 AsmCoerceMethod(cl, (Object *)rc, OM_SET, tags, NULL);
229 horiz = pd->pd_Flags & PDF_PROPHORIZ;
232 * Arrows?
234 if (pd->pd_Flags & PDF_ARROWS)
236 pd->pd_Arrow1 = BGUI_NewObject(BGUI_BUTTON_GADGET,
237 VIT_BuiltIn, horiz ? BUILTIN_ARROW_LEFT : BUILTIN_ARROW_UP,
238 BT_ParentView,bc->bc_View,
239 BT_ParentWindow,bc->bc_Window,
240 TAG_DONE);
242 pd->pd_Arrow2 = BGUI_NewObject(BGUI_BUTTON_GADGET,
243 VIT_BuiltIn, horiz ? BUILTIN_ARROW_RIGHT : BUILTIN_ARROW_DOWN,
244 BT_ParentView,bc->bc_View,
245 BT_ParentWindow,bc->bc_Window,
246 TAG_DONE);
248 if (!(pd->pd_Arrow1 && pd->pd_Arrow2)) goto failure;
251 if (pd->pd_Prop = NewObject(NULL, PropGClass,
252 GA_RelVerify, TRUE,
253 PGA_Borderless, TRUE,
254 PGA_Freedom, horiz ? FREEHORIZ : FREEVERT,
255 TAG_MORE, tags))
258 pd->pd_Knob = BGUI_NewObject(BGUI_FRAME_IMAGE,
259 FRM_Type, FRTYPE_FUZZ_RIDGE,
260 //FRM_FrameWidth, 2,
261 //FRM_FrameHeight, 2,
262 FRM_ThinFrame, TRUE,
263 FRM_BackFill, SHINE_RASTER,
264 IMAGE_InBorder, GADGET(rc)->Activation & BORDERMASK,
265 TAG_END);
270 * No disabled.
272 DoSetMethodNG(pd->pd_Prop, GA_Disabled, FALSE, TAG_END);
274 if (pd->pd_Knob)
276 DoSetMethodNG(pd->pd_Prop, GA_Image, pd->pd_Knob, GA_SelectRender, pd->pd_Knob, TAG_DONE);
280 * We target the IDCMP port (when allowed).
282 if (!GetTagData(PGA_DontTarget, FALSE, tags))
283 DoSuperSetMethodNG(cl, (Object *)rc, ICA_TARGET, ICTARGET_IDCMP, TAG_END);
285 pd->pd_Flags |= PDF_READY;
288 * So far, so good....
290 FreeTagItems(tags);
291 return rc;
293 failure:
295 * Shit! Something screwed up...
297 AsmCoerceMethod(cl, (Object *)rc, OM_DISPOSE);
299 FreeTagItems(tags);
300 return NULL;
302 METHOD_END
304 /// OM_SET, OM_UPDATE
306 * Change some attributes.
308 METHOD(PropClassSetUpdate, struct opUpdate *, opu)
310 PD *pd = INST_DATA(cl, obj);
311 BC *bc = BASE_DATA(obj);
312 struct TagItem *tstate = opu->opu_AttrList, *tag;
313 ULONG data, type, redraw = 0, ho, vo;
314 LONG tmp, val, omin, omax, olev, oldtop, oldtot, oldvis;
315 BOOL fc = !(pd->pd_Flags & PDF_READY);
316 WORD dis = GADGET(obj)->Flags & GFLG_DISABLED;
319 * First we let the superclass do it's thing.
321 AsmDoSuperMethodA(cl, obj, (Msg)opu);
324 * Make sure we stay GACT_RELVERIFY.
326 GADGET(obj)->Activation |= GACT_RELVERIFY;
328 if (pd->pd_Flags & PDF_SLIDER)
330 omin = pd->pd_Min;
331 omax = pd->pd_Max;
332 olev = pd->pd_Level;
334 else
336 oldtop = pd->pd_Top;
337 oldtot = pd->pd_Total;
338 oldvis = pd->pd_Visible;
342 * Let's see if we need to change
343 * some known attributes ourselves.
345 while (tag = NextTagItem(&tstate))
347 data = tag->ti_Data;
348 switch (tag->ti_Tag)
350 case PGA_Top:
351 pd->pd_Top = data;
352 break;
354 case PGA_Total:
355 pd->pd_Total = data;
356 break;
358 case PGA_Visible:
359 pd->pd_Visible = data;
360 break;
362 case PGA_Freedom:
363 if (data == FREEHORIZ) pd->pd_Flags |= PDF_PROPHORIZ;
364 else pd->pd_Flags &= ~PDF_PROPHORIZ;
365 break;
367 case PGA_Arrows:
368 if (data) pd->pd_Flags |= PDF_ARROWS;
369 else pd->pd_Flags &= ~PDF_ARROWS;
370 break;
372 case PGA_ArrowSize:
373 pd->pd_ArrowSize = data;
374 break;
376 case SLIDER_Level:
377 pd->pd_Level = data;
378 break;
380 case SLIDER_Min:
381 pd->pd_Min = data;
382 break;
384 case SLIDER_Max:
385 pd->pd_Max = data;
386 break;
388 case PGA_XenFrame:
389 if (data) data = FRTYPE_XEN_BUTTON;
390 else data = FRTYPE_BUTTON;
391 goto set_frametype;
393 case PGA_NoFrame:
394 case SLIDER_NoFrame:
395 if (data) data = FRTYPE_NONE;
396 else data = FRTYPE_BUTTON;
398 case FRM_Type:
399 set_frametype:
400 DoMultiSet(FRM_Type, data, 3, bc->bc_Frame, pd->pd_Arrow1, pd->pd_Arrow2);
401 fc = TRUE;
402 break;
404 case PGA_ThinFrame:
405 case SLIDER_ThinFrame:
406 case FRM_ThinFrame:
407 DoMultiSet(FRM_ThinFrame, data, 3, bc->bc_Frame, pd->pd_Arrow1, pd->pd_Arrow2);
408 fc = TRUE;
409 break;
411 case GA_TopBorder:
412 case GA_BottomBorder:
413 case GA_LeftBorder:
414 case GA_RightBorder:
415 DoMultiSet(tag->ti_Tag, data, 4, pd->pd_Arrow1, pd->pd_Arrow2, pd->pd_Knob, pd->pd_Prop);
417 if (data)
419 DoSetMethodNG(bc->bc_Frame, FRM_Type, FRTYPE_BORDER, FRM_EdgesOnly, TRUE, TAG_DONE);
421 DoSetMethodNG(pd->pd_Arrow1, BT_FrameObject, NULL,
422 SYSIA_Which, (pd->pd_Flags & PDF_PROPHORIZ) ? LEFTIMAGE : UPIMAGE, TAG_DONE);
424 DoSetMethodNG(pd->pd_Arrow2, BT_FrameObject, NULL,
425 SYSIA_Which, (pd->pd_Flags & PDF_PROPHORIZ) ? RIGHTIMAGE : DOWNIMAGE, TAG_DONE);
427 fc = TRUE;
428 break;
430 case BT_ParentWindow:
431 case BT_ParentView:
432 DoMultiSet(tag->ti_Tag, data, 3, pd->pd_Arrow1, pd->pd_Arrow2, pd->pd_Knob);
433 break;
437 if (pd->pd_Flags & PDF_SLIDER)
440 * Stupidity tests.
442 if (pd->pd_Min > pd->pd_Max)
444 tmp = pd->pd_Min;
445 pd->pd_Min = pd->pd_Max;
446 pd->pd_Max = tmp;
450 * Calculate the absolute difference between min and max.
452 pd->pd_Total = pd->pd_Max - pd->pd_Min + 1;
453 pd->pd_Visible = 1;
455 val = pd->pd_Level;
457 else
459 pd->pd_Min = 0;
460 pd->pd_Max = max(pd->pd_Total - pd->pd_Visible, 0);
462 val = pd->pd_Top;
465 if (val < pd->pd_Min) val = pd->pd_Min;
466 else if (val > pd->pd_Max) val = pd->pd_Max;
468 if (pd->pd_Flags & PDF_SLIDER)
470 pd->pd_Level = val;
473 * Check if any of these values changed.
475 if ((pd->pd_Min != omin) || (pd->pd_Max != omax) || (pd->pd_Level != olev))
476 redraw = GREDRAW_UPDATE;
478 else
480 pd->pd_Top = val;
483 * Check if any of these values changed.
485 if ((pd->pd_Top != oldtop) || (pd->pd_Total != oldtot) || (pd->pd_Visible != oldvis))
486 redraw = GREDRAW_UPDATE;
489 if (fc)
491 Get_Attr(bc->bc_Frame, FRM_Type, &data);
492 switch (data)
494 case FRTYPE_NONE:
495 ho = vo = 0;
496 case FRTYPE_BORDER:
497 if (GADGET(obj)->Activation & (GACT_LEFTBORDER|GACT_RIGHTBORDER)) { ho = 4; vo = 1; };
498 if (GADGET(obj)->Activation & (GACT_TOPBORDER|GACT_BOTTOMBORDER)) { ho = 2; vo = 2; };
499 DoSetMethodNG(bc->bc_Frame, FRM_Type, FRTYPE_NONE, TAG_DONE);
500 break;
501 default:
502 Get_Attr(bc->bc_Frame, FRM_ThinFrame, &data);
503 vo = 1;
504 ho = data ? 1 : 2;
505 break;
507 DoSuperSetMethodNG(cl, obj, BT_LeftOffset, ho, BT_RightOffset, ho,
508 BT_TopOffset, vo, BT_BottomOffset, vo, TAG_DONE);
510 redraw = GREDRAW_REDRAW;
514 if (pd->pd_Flags & PDF_READY)
517 * Disable state changed?
519 if ((GADGET(obj)->Flags & GFLG_DISABLED) != dis)
520 redraw = GREDRAW_REDRAW;
523 * Re-render the gadget.
525 if (redraw) DoRenderMethod(obj, opu->opu_GInfo, redraw);
528 * Notify our target if the
529 * top value changed.
531 if (pd->pd_Flags & PDF_SLIDER)
533 type = (pd->pd_Level != olev) ? SLIDER_Level : 0;
535 else
537 type = (pd->pd_Top != oldtop) ? PGA_Top : 0;
540 if (type) DoNotifyMethod(obj, opu->opu_GInfo, opu->MethodID == OM_UPDATE ? opu->opu_Flags : 0,
541 GA_ID, GADGET(obj)->GadgetID, type, val, TAG_DONE);
543 return 1;
545 METHOD_END
547 /// BASE_RENDER
549 * Render the gadget.
551 METHOD(PropClassRender, struct bmRender *, bmr)
553 PD *pd = INST_DATA(cl, obj);
554 BC *bc = BASE_DATA(obj);
555 struct BaseInfo *bi = bmr->bmr_BInfo;
556 struct RastPort *rp = bi->bi_RPort;
559 * Render the baseclass.
561 AsmDoSuperMethodA(cl, obj, (Msg)bmr);
564 * Setup the object.
566 CalcPropMuck(cl, obj, bi);
569 * Complete re-render?
571 if (bmr->bmr_Flags == GREDRAW_REDRAW)
574 * Render the arrow images.
576 if (pd->pd_Flags & PDF_ARROWS)
578 AsmDoMethod(pd->pd_Arrow1, GM_RENDER, bi, rp, GREDRAW_REDRAW);
579 AsmDoMethod(pd->pd_Arrow2, GM_RENDER, bi, rp, GREDRAW_REDRAW);
583 * Then the slider body.
585 AsmDoMethod(pd->pd_Prop, GM_RENDER, bi, rp, GREDRAW_REDRAW);
587 else
590 * Any arrow active?
592 if (pd->pd_Flags & PDF_LEFT_UP)
593 AsmDoMethod(pd->pd_Arrow1, GM_RENDER, bi, rp, GREDRAW_REDRAW);
594 else if (pd->pd_Flags & PDF_RIGHT_DOWN)
595 AsmDoMethod(pd->pd_Arrow2, GM_RENDER, bi, rp, GREDRAW_REDRAW);
598 * Only re-render the slider when it isn't active.
600 if (!(pd->pd_Flags & PDF_PROPACTIVE))
601 AsmDoMethod(pd->pd_Prop, GM_RENDER, bi, rp, GREDRAW_UPDATE);
605 * Ghost the gadget hitbox when it is disabled.
607 if (GADGET(obj)->Flags & GFLG_DISABLED)
609 BDisableBox(bi, &bc->bc_HitBox);
610 if (pd->pd_Arrow1) BDisableBox(bi, GADGETBOX(pd->pd_Arrow1));
611 if (pd->pd_Arrow2) BDisableBox(bi, GADGETBOX(pd->pd_Arrow2));
613 return 1;
615 METHOD_END
617 /// OM_GET
619 * They want to know something.
621 METHOD(PropClassGet, struct opGet *, opg)
623 PD *pd = INST_DATA(cl, obj);
624 ULONG rc = 1;
625 ULONG *store = opg->opg_Storage;
627 switch (opg->opg_AttrID)
629 case PGA_Freedom:
630 STORE (pd->pd_Flags & PDF_PROPHORIZ) ? FREEHORIZ : FREEVERT;
631 break;
633 case PGA_Top:
634 STORE pd->pd_Top;
635 break;
637 case SLIDER_Level:
638 STORE pd->pd_Level;
639 break;
641 case SLIDER_Min:
642 STORE pd->pd_Min;
643 break;
645 case SLIDER_Max:
646 STORE pd->pd_Max;
647 break;
649 default:
650 rc = AsmDoSuperMethodA(cl, obj, (Msg)opg);
651 break;
653 return rc;
655 METHOD_END
657 /// GM_HITTEST
659 * Where we hit and if so, what was hit.
661 METHOD(PropClassHitTest, struct gpHitTest *, gph)
663 PD *pd = INST_DATA(cl, obj);
664 BC *bc = BASE_DATA(obj);
665 ULONG rc = 0;
668 * Calculate absolute click position.
670 WORD l = GADGETBOX(obj)->Left + gph->gpht_Mouse.X;
671 WORD t = GADGETBOX(obj)->Top + gph->gpht_Mouse.Y;
673 if (PointInBox(&bc->bc_HitBox, l, t))
676 * Did they click inside the
677 * proportional gadget?
679 rc = ForwardMsg(obj, pd->pd_Prop, (Msg)gph);
681 if (rc == GMR_GADGETHIT) pd->pd_Flags |= PDF_PROPACTIVE;
684 if (!rc && pd->pd_Arrow1)
687 * Clicked in the left/up arrow?
689 rc = ForwardMsg(obj, pd->pd_Arrow1, (Msg)gph);
691 if (rc == GMR_GADGETHIT) pd->pd_Flags |= PDF_LEFT_UP;
694 if (!rc && pd->pd_Arrow2)
697 * Clicked in the down/right arrow?
699 rc = ForwardMsg(obj, pd->pd_Arrow2, (Msg)gph);
701 if (rc == GMR_GADGETHIT) pd->pd_Flags |= PDF_RIGHT_DOWN;
704 if (rc == GMR_GADGETHIT)
706 pd->pd_Reset1 = pd->pd_Top;
707 pd->pd_Reset2 = pd->pd_Level;
709 return rc;
711 METHOD_END
714 //STATIC ASM VOID NotifyChange(REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct gpInput *gpi, REG(d0) ULONG flags)
715 STATIC ASM REGFUNC4(VOID, NotifyChange,
716 REGPARAM(A0, Class *, cl),
717 REGPARAM(A2, Object *, obj),
718 REGPARAM(A1, struct gpInput *, gpi),
719 REGPARAM(D0, ULONG, flags))
721 PD *pd = INST_DATA(cl, obj);
722 ULONG type;
723 LONG val, oldval = (pd->pd_Flags & PDF_SLIDER) ? pd->pd_Level : pd->pd_Top;
726 * Obtain top-value.
728 Get_Attr(pd->pd_Prop, PGA_Top, &val);
730 if (pd->pd_Flags & PDF_SLIDER)
733 * Make it a level.
735 if (pd->pd_Flags & PDF_PROPHORIZ) val = pd->pd_Min + val;
736 else val = pd->pd_Max - val;
738 pd->pd_Level = val;
739 type = SLIDER_Level;
741 else
743 pd->pd_Top = val;
744 type = PGA_Top;
748 * Notify.
750 if ((flags == OPUF_INTERIM) && (val == oldval)) return;
752 DoNotifyMethod(obj, gpi->gpi_GInfo, flags, GA_ID, GADGET(obj)->GadgetID, type, val, TAG_DONE);
754 REGFUNC_END
757 * Adjust knob position in
758 * whatever direction necessary.
760 //STATIC ASM VOID AdjustKnob(REG(a0) Class *cl, REG(a2) Object *obj, REG(a1) struct gpInput *gpi)
761 STATIC ASM REGFUNC3(VOID, AdjustKnob,
762 REGPARAM(A0, Class *, cl),
763 REGPARAM(A2, Object *, obj),
764 REGPARAM(A1, struct gpInput *, gpi))
766 PD *pd = INST_DATA(cl, obj);
767 LONG top, total = max(pd->pd_Total - pd->pd_Visible, 0);
769 Get_Attr(pd->pd_Prop, PGA_Top, &top);
771 if (pd->pd_Flags & PDF_LEFT_UP)
773 top--;
775 else if (pd->pd_Flags & PDF_RIGHT_DOWN)
777 top++;
780 if ((top >= 0) && (top <= total))
782 DoSetMethod(pd->pd_Prop, gpi->gpi_GInfo, PGA_Top, top, TAG_DONE);
783 NotifyChange(cl, obj, gpi, 0L);
786 REGFUNC_END
788 /// GM_GOACTIVE
790 METHOD(PropClassGoActive, struct gpInput *, gpi)
792 PD *pd = INST_DATA(cl, obj);
793 Object *arrow;
794 ULONG rc = GMR_NOREUSE;
797 * We do not go active when we are disabled or was activated
798 * by Activate gadget.
800 if ((GADGET(obj)->Flags & GFLG_DISABLED) || (!gpi->gpi_IEvent))
802 pd->pd_Flags &= ~(PDF_PROPACTIVE|PDF_LEFT_UP|PDF_RIGHT_DOWN);
803 return rc;
807 * Let the superclass have a go...
809 AsmDoSuperMethodA(cl, obj, (Msg)gpi);
812 * Is the proportional gadget active?
814 if (pd->pd_Flags & PDF_PROPACTIVE)
817 * If so adjust the click
818 * coordinates and route the
819 * message to the proportional gadget.
821 rc = ForwardMsg(obj, pd->pd_Prop, (Msg)gpi);
823 if (rc & GMR_VERIFY) NotifyChange(cl, obj, gpi, 0);
825 else if (pd->pd_Flags & (PDF_LEFT_UP|PDF_RIGHT_DOWN))
828 * Clear timer threshold.
830 pd->pd_RptTicks = 0;
833 * Adjust knob and notify when the knob position changed.
835 AdjustKnob(cl, obj, gpi);
838 * Route the message to the button gadget.
840 arrow = (pd->pd_Flags & PDF_LEFT_UP) ? pd->pd_Arrow1 : pd->pd_Arrow2;
841 rc = ForwardMsg(obj, arrow, (Msg)gpi);
843 return rc;
845 METHOD_END
847 /// GM_HANDLEINPUT
849 * Handle user input.
851 METHOD(PropClassHandleInput, struct gpInput *, gpi)
853 PD *pd = INST_DATA(cl, obj);
854 Object *arrow;
855 WORD l, t, sel = 0;
856 ULONG rc = GMR_MEACTIVE;
859 * Calculate absolute click position.
861 l = GADGETBOX(obj)->Left + gpi->gpi_Mouse.X;
862 t = GADGETBOX(obj)->Top + gpi->gpi_Mouse.Y;
865 * Is the proportional gadget active?
867 if (pd->pd_Flags & PDF_PROPACTIVE)
870 * Right mouse button pressed?
872 if (gpi->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE && gpi->gpi_IEvent->ie_Code == MENUDOWN)
875 * Yep. Say we need to reset to
876 * the initial value.
878 pd->pd_Flags |= PDF_RESET;
879 return GMR_NOREUSE;
882 * If so adjust the click
883 * coordinates and rout the
884 * message to the proportional gadget.
886 rc = ForwardMsg(obj, pd->pd_Prop, (Msg)gpi);
888 NotifyChange(cl, obj, gpi, (rc == GMR_MEACTIVE) ? OPUF_INTERIM : 0);
890 else
892 arrow = (pd->pd_Flags & PDF_LEFT_UP) ? pd->pd_Arrow1 : pd->pd_Arrow2;
895 * Check if the mouse is
896 * still over the active arrow.
898 if (PointInBox(GADGETBOX(arrow), l, t))
899 sel = GFLG_SELECTED;
902 * Evaluate input.
904 if (gpi->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE)
906 switch (gpi->gpi_IEvent->ie_Code)
908 case SELECTUP:
910 * They released the left
911 * mouse button.
913 rc = GMR_NOREUSE | GMR_VERIFY;
916 * Unselect the arrow.
918 sel = 0;
919 break;
921 case MENUDOWN:
923 * Terminate when they press the menubutton.
925 sel = 0;
926 pd->pd_Flags |= PDF_RESET;
927 rc = GMR_NOREUSE;
928 break;
931 else if (gpi->gpi_IEvent->ie_Class == IECLASS_TIMER)
934 * On every timer event we
935 * increase or decrease the knob
936 * position.
938 if (sel)
941 * We delay with adjusting the knob position for a little while just
942 * like the key-repeat threshold. Probably should use the system prefs
943 * for determing the delay but this is _so_ much easier.
945 if (pd->pd_RptTicks > 3)
948 * Adjust knob and notify when the knob position changed.
950 AdjustKnob(cl, obj, gpi);
952 else
955 * Increase repeat treshold.
957 pd->pd_RptTicks++;
963 * When the selected state
964 * changed show it visually.
966 if ((GADGET(arrow)->Flags & GFLG_SELECTED) != sel)
969 * Flip selected bit and re-render.
971 GADGET(arrow)->Flags ^= GFLG_SELECTED;
972 DoRenderMethod(arrow, gpi->gpi_GInfo, GREDRAW_REDRAW);
975 return rc;
977 METHOD_END
979 /// GM_GOINACTIVE
981 * Abort activity.
983 METHOD(PropClassGoInActive, struct gpGoInactive *, ggi)
985 PD *pd = INST_DATA(cl, obj);
986 ULONG rc;
989 * Is the proportional gadget
990 * active?
992 if (pd->pd_Flags & PDF_PROPACTIVE)
995 * If so route the message to
996 * the proportional gadget and
997 * mark it as not active.
999 AsmDoMethodA(pd->pd_Prop, (Msg)ggi);
1003 * Un-activate our arrows and let the super
1004 * class see what it can do with this message.
1006 pd->pd_Flags &= ~(PDF_LEFT_UP|PDF_RIGHT_DOWN|PDF_PROPACTIVE);
1007 rc = AsmDoSuperMethodA(cl, obj, (Msg)ggi);
1010 * Reset to the initial value when necessary.
1012 if (pd->pd_Flags & PDF_RESET)
1014 DoSetMethod(obj, ggi->gpgi_GInfo, PGA_Top, pd->pd_Reset1, SLIDER_Level, pd->pd_Reset2, TAG_DONE);
1015 pd->pd_Flags &= ~PDF_RESET;
1017 return rc;
1019 METHOD_END
1021 /// BASE_DIMENSIONS
1023 * Find out our minumum size.
1025 METHOD(PropClassDimensions, struct bmDimensions *, bmd)
1027 PD *pd = INST_DATA(cl, obj);
1028 BC *bc = BASE_DATA(obj);
1029 BOOL vborder = GADGET(obj)->Activation & (GACT_LEFTBORDER|GACT_RIGHTBORDER);
1030 BOOL hborder = GADGET(obj)->Activation & (GACT_TOPBORDER|GACT_BOTTOMBORDER);
1031 BOOL horiz = pd->pd_Flags & PDF_PROPHORIZ;
1032 int arrowsize = pd->pd_ArrowSize;
1033 ULONG rc;
1035 if (pd->pd_Flags & PDF_ARROWS)
1037 if (!arrowsize)
1039 if (vborder) arrowsize = 11;
1040 else if (hborder) arrowsize = 16;
1041 else arrowsize = horiz ? 10 : 9;
1043 pd->pd_ArrowSize = arrowsize;
1045 DoSetMethodNG(bc->bc_Frame, horiz ? FRM_OuterOffsetRight : FRM_OuterOffsetBottom, arrowsize << 1, TAG_DONE);
1049 * Add these to the superclass results.
1051 rc = CalcDimensions(cl, obj, bmd, 8+(horiz ? arrowsize*2 : 0), 8+(horiz ? 0 : arrowsize*2 ));
1053 if (vborder) bmd->bmd_Extent->be_Min.Width = bmd->bmd_Extent->be_Nom.Width = 18;
1054 if (hborder) bmd->bmd_Extent->be_Min.Height = bmd->bmd_Extent->be_Nom.Height = 10;
1056 return rc;
1058 METHOD_END
1060 /// OM_DISPOSE
1062 * Dispose of ourselves.
1064 METHOD(PropClassDispose, Msg, msg)
1066 PD *pd = INST_DATA(cl, obj);
1069 * Dispose of the allocated objects.
1071 if (pd->pd_Arrow1) DisposeObject(pd->pd_Arrow1);
1072 if (pd->pd_Arrow2) DisposeObject(pd->pd_Arrow2);
1073 if (pd->pd_Prop ) DisposeObject(pd->pd_Prop);
1074 if (pd->pd_Knob ) DisposeObject(pd->pd_Knob);
1076 return AsmDoSuperMethodA(cl, obj, msg);
1078 METHOD_END
1080 /// WM_KEYACTIVE
1082 * We are activated by the keyboard.
1084 METHOD(PropClassKeyActive, struct wmKeyInput *, wmki)
1086 PD *pd = ( PD * )INST_DATA( cl, obj );
1087 UWORD qual = wmki->wmki_IEvent->ie_Qualifier, code = wmki->wmki_IEvent->ie_Code;
1088 BOOL sl = pd->pd_Flags & PDF_SLIDER;
1089 LONG otop = sl ? pd->pd_Level : pd->pd_Top, ntop = otop;
1090 LONG inc = pd->pd_Visible - 1;
1092 if (inc < 1) inc = 1;
1095 * Shifted key?
1097 if (qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
1099 if (ntop > pd->pd_Min) ntop -= inc;
1100 if (ntop < pd->pd_Min) ntop = pd->pd_Min;
1102 else
1104 if (ntop < pd->pd_Max) ntop += inc;
1105 if (ntop > pd->pd_Max) ntop = pd->pd_Max;
1109 * Did the top position change?
1111 if ((ntop != otop) && !(code & IECODE_UP_PREFIX))
1114 * Let the slider know about this change.
1116 DoSetMethod(obj, wmki->wmki_GInfo, sl ? SLIDER_Level : PGA_Top, ntop, TAG_END);
1118 * Skip the ID because the notification
1119 * will handle the change.
1123 * Tell then to ignore this message.
1125 *(wmki->wmki_ID) = WMHI_IGNORE;
1127 return WMKF_VERIFY;
1129 METHOD_END
1132 /// Class initialization,
1134 * Class function table.
1136 STATIC DPFUNC ClassFunc[] = {
1137 BASE_RENDER, (FUNCPTR)PropClassRender,
1138 BASE_DIMENSIONS, (FUNCPTR)PropClassDimensions,
1140 OM_NEW, (FUNCPTR)PropClassNew,
1141 OM_SET, (FUNCPTR)PropClassSetUpdate,
1142 OM_UPDATE, (FUNCPTR)PropClassSetUpdate,
1143 OM_GET, (FUNCPTR)PropClassGet,
1144 OM_DISPOSE, (FUNCPTR)PropClassDispose,
1145 GM_HITTEST, (FUNCPTR)PropClassHitTest,
1146 GM_HANDLEINPUT, (FUNCPTR)PropClassHandleInput,
1147 GM_GOACTIVE, (FUNCPTR)PropClassGoActive,
1148 GM_GOINACTIVE, (FUNCPTR)PropClassGoInActive,
1149 WM_KEYACTIVE, (FUNCPTR)PropClassKeyActive,
1150 DF_END, NULL
1154 * Class initialization.
1156 makeproto Class *InitPropClass(void)
1158 return BGUI_MakeClass(CLASS_SuperClassBGUI, BGUI_BASE_GADGET,
1159 CLASS_ObjectSize, sizeof(PD),
1160 CLASS_DFTable, ClassFunc,
1161 TAG_DONE);