4 ** Copyright (C) 1995,96,97 Bernardo Innocenti
6 ** Special custom BOOPSI classes.
9 #include <exec/memory.h>
10 #include <utility/tagitem.h>
11 #include <graphics/gfxbase.h>
12 #include <devices/inputevent.h>
14 #include <intuition/intuition.h>
15 #include <intuition/classes.h>
16 #include <intuition/classusr.h>
17 #include <intuition/gadgetclass.h>
18 #include <intuition/icclass.h>
19 #include <intuition/imageclass.h>
21 #include <proto/exec.h>
22 #include <proto/graphics.h>
23 #include <proto/intuition.h>
24 #include <proto/utility.h>
26 #include "CustomClasses.h"
27 #include "XModulePriv.h"
30 /* Per object instance data */
31 struct ScrollButtonData
33 /* The number of ticks we still have to wait
34 * before sending any notification.
41 /* Function prototypes */
43 static LIBCALL ULONG ScrollButtonDispatcher (
45 REG(a2, struct Gadget *g),
46 REG(a1, struct gpInput *gpi));
48 static ULONG HOOKCALL VImageDispatcher (
50 REG(a2, struct Image *im),
51 REG(a1, struct opSet *ops));
53 static void NotifyAttrChanges (Object *o, struct GadgetInfo *gi, ULONG flags, Tag attr1, ...);
54 static void DrawPlayImage (struct RastPort *rp, UWORD width, UWORD heigth);
55 static void DrawStopImage (struct RastPort *rp, UWORD width, UWORD heigth);
56 static void DrawForwardImage (struct RastPort *rp, UWORD width, UWORD heigth);
57 static void DrawRewindImage (struct RastPort *rp, UWORD width, UWORD heigth);
58 static void DrawPickImage (struct RastPort *rp, UWORD width, UWORD height);
59 static void DrawVImage (struct impDraw *imp, struct Image *im, struct BitMap *bm);
63 /* tagcall stub for OM_NOTIFY */
64 static void NotifyAttrChanges (Object *o, struct GadgetInfo *gi, ULONG flags, Tag attr1, ...)
66 DoSuperMethod (OCLASS(o), o, OM_NOTIFY, &attr1, gi, flags);
73 ** Parts of the code have been inspired by ScrollerWindow 0.3 demo
74 ** Copyright © 1994 Christoph Feck, TowerSystems.
76 ** Subclass of buttongclass. The ROM class has two problems, which make
77 ** it not quite usable for scrollarrows. The first problem is the missing
78 ** delay. Once the next INTUITICK gets send by input.device, the ROM
79 ** class already sends a notification. The other problem is that it also
80 ** notifies us, when the button finally gets released (which is necessary
81 ** for command buttons).
83 ** We define a new class with the GM_GOACTIVE and GM_HANDLEINPUT method
84 ** overloaded to work around these problems.
87 static LIBCALL ULONG ScrollButtonDispatcher (
89 REG(a2, struct Gadget *g),
90 REG(a1, struct gpInput *gpi))
92 /* ScrollButton Class Dispatcher entrypoint.
93 * Handle BOOPSI messages.
96 struct ScrollButtonData *bd = (struct ScrollButtonData *) INST_DATA(cl, g);
98 switch (gpi->MethodID)
101 /* May define an attribute to make delay configurable */
104 /* Notify our target that we have initially hit. */
105 NotifyAttrChanges ((Object *)g, gpi->gpi_GInfo, 0,
109 /* Send more input */
115 ULONG retval = GMR_MEACTIVE;
118 /* This also works with classic (non-boopsi) images. */
119 if (PointInImage ((gpi->gpi_Mouse.X << 16) + (gpi->gpi_Mouse.Y), g->GadgetRender))
122 selected = GFLG_SELECTED;
125 if (gpi->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE && gpi->gpi_IEvent->ie_Code == SELECTUP)
127 /* Gadgetup, time to go */
128 retval = GMR_NOREUSE;
129 /* Unselect the gadget on our way out... */
132 else if (gpi->gpi_IEvent->ie_Class == IECLASS_TIMER)
134 /* We got a tick. Decrement counter, and if 0, send notify. */
136 if (bd->TickCounter) bd->TickCounter--;
139 NotifyAttrChanges ((Object *) g, gpi->gpi_GInfo, 0,
145 if ((g->Flags & GFLG_SELECTED) != selected)
147 /* Update changes in gadget render */
148 g->Flags ^= GFLG_SELECTED;
149 if (rp = ObtainGIRPort (gpi->gpi_GInfo))
151 DoMethod ((Object *) g, GM_RENDER, gpi->gpi_GInfo, rp, GREDRAW_UPDATE);
159 /* Super class handles everything else */
160 return (DoSuperMethodA (cl, (Object *)g, (Msg) gpi));
166 GLOBALCALL Class *InitScrollButtonClass (void)
170 if (class = MakeClass (NULL, BUTTONGCLASS, NULL, sizeof(struct ScrollButtonData), 0))
171 class->cl_Dispatcher.h_Entry = (ULONG (*)()) ScrollButtonDispatcher;
178 GLOBALCALL BOOL FreeScrollButtonClass (Class *cl)
180 return (FreeClass (cl));
185 static ULONG HOOKCALL VImageDispatcher (
187 REG(a2, struct Image *im),
188 REG(a1, struct opSet *ops))
190 /* VImage Class Dispatcher entrypoint.
191 * Handle BOOPSI messages.
194 switch (ops->MethodID)
198 /* Create the image structure */
199 if (im = (struct Image *)DoSuperMethodA (cl, (Object *)im, (Msg) ops))
203 /* struct DrawInfo *dri = (struct DrawInfo *)GetTagData (GA_DrawInfo, NULL, ops->ops_AttrList);
205 which = GetTagData (SYSIA_Which, 0, ops->ops_AttrList);
210 if (GfxBase->LibNode.lib_Version >= 39)
211 #endif /* !OS30_ONLY */
212 rp.BitMap = AllocBitMap (im->Width, im->Height, 1, BMF_CLEAR, NULL);
216 if (rp.BitMap = AllocMem (sizeof (struct BitMap), MEMF_PUBLIC))
218 InitBitMap (rp.BitMap, 1, im->Width, im->Height);
219 if (!(rp.BitMap->Planes[0] = AllocMem (RASSIZE(im->Width, im->Height), MEMF_CHIP | MEMF_CLEAR)))
221 FreeMem (rp.BitMap, sizeof (struct BitMap));
226 #endif /* !OS30_ONLY */
231 struct TmpRas tmpras;
232 struct AreaInfo areainfo;
233 WORD areabuffer[(5 * 10 + 1) / 2];
235 if (planeptr = AllocRaster (im->Width, im->Height))
237 InitTmpRas (&tmpras, planeptr, RASSIZE(im->Width, im->Height));
238 InitArea (&areainfo, areabuffer, 10);
241 rp.AreaInfo = &areainfo;
246 DrawPlayImage (&rp, im->Width, im->Height);
250 DrawStopImage (&rp, im->Width, im->Height);
254 DrawForwardImage (&rp, im->Width, im->Height);
258 DrawRewindImage (&rp, im->Width, im->Height);
262 DrawPickImage (&rp, im->Width, im->Height);
266 /* Just to be sure... */
270 FreeRaster (planeptr, im->Width, im->Height);
273 /* This way our image will complement better */
274 rp.BitMap->Planes[1] = (UBYTE *)0;
275 rp.BitMap->Depth = 2;
278 /* Failing to allocate the TmpRas will cause the
279 * image to be blank, but no error will be
283 /* Store the BitMap pointer here for later usage */
284 im->ImageData = (UWORD *)rp.BitMap;
286 return (ULONG)im; /* Return new image object */
296 DrawVImage ((struct impDraw *)ops, im, (struct BitMap *)im->ImageData);
301 /* Restore original depth! */
302 ((struct BitMap *)im->ImageData)->Depth = 1;
305 if (GfxBase->LibNode.lib_Version >= 39)
306 #endif /* !OS30_ONLY */
307 FreeBitMap ((struct BitMap *)im->ImageData);
311 FreeMem (((struct BitMap *)im->ImageData)->Planes[0], RASSIZE(im->Width, im->Height));
312 FreeMem (((struct BitMap *)im->ImageData), sizeof (struct BitMap));
314 #endif /* !OS30_ONLY */
316 /* Now let our superclass free it's istance */
317 /* Note: I'm falling through here! */
320 /* Our Super class handles everything else */
321 return (DoSuperMethodA (cl, (Object *)im, (Msg) ops));
327 GLOBALCALL Class *InitVImageClass (void)
331 if (class = MakeClass (NULL, IMAGECLASS, NULL, 0, 0))
332 class->cl_Dispatcher.h_Entry = (ULONG (*)()) VImageDispatcher;
339 GLOBALCALL BOOL FreeVImageClass (Class *cl)
341 return (FreeClass (cl));
346 static void DrawPlayImage (struct RastPort *rp, UWORD width, UWORD height)
348 UWORD ymin = height / 4,
349 ymax = (height * 3) / 4,
352 ymin -= (ymax - ymin) & 1; /* Force odd heigth for better arrow aspect */
353 ymid = (ymin + ymax) / 2;
355 RectFill (rp, 1, ymin, (width / 4) - 1, ymax);
357 AreaMove (rp, width / 3, ymin);
358 AreaDraw (rp, width - 2, ymid);
359 AreaDraw (rp, width / 3, ymax);
366 static void DrawStopImage (struct RastPort *rp, UWORD width, UWORD height)
368 RectFill (rp, width / 4, height / 4, (width * 3) / 4, (height * 3) / 4);
373 static void DrawForwardImage (struct RastPort *rp, UWORD width, UWORD height)
375 UWORD ymin = height / 4,
376 ymax = (height * 3) / 4,
379 ymin -= (ymax - ymin) & 1; /* Force odd heigth for better arrow aspect */
380 ymid = (ymin + ymax) / 2;
382 AreaMove (rp, 1, ymin);
383 AreaDraw (rp, width / 2, ymid);
384 AreaDraw (rp, 1, ymax);
386 AreaMove (rp, width / 2, ymin);
387 AreaDraw (rp, width - 2, ymid);
388 AreaDraw (rp, width / 2, ymax);
395 static void DrawRewindImage (struct RastPort *rp, UWORD width, UWORD height)
397 UWORD ymin = height / 4,
398 ymax = (height * 3) / 4,
401 ymin -= (ymax - ymin) & 1; /* Force odd heigth for better arrow aspect */
402 ymid = (ymin + ymax) / 2;
404 AreaMove (rp, width - 2, ymin);
405 AreaDraw (rp, width / 2, ymid);
406 AreaDraw (rp, width - 2, ymax);
408 AreaMove (rp, width / 2 - 1, ymin);
409 AreaDraw (rp, 1, ymid);
410 AreaDraw (rp, width / 2 - 1, ymax);
416 static void DrawPickImage (struct RastPort *rp, UWORD width, UWORD height)
425 * #######<--arrowymin
429 * #######<--arrowymax+1
432 UWORD tailymin = height / 6,
433 tailxmin = (width * 2) / 5,
434 tailxmax = (width * 3) / 5,
435 arrowymin = (height * 2) / 5,
436 arrowymax = (height * 4) / 5,
437 arrowxmin = width / 5,
438 arrowxmax = (width * 4) / 5;
440 AreaMove (rp, tailxmin, tailymin);
441 AreaDraw (rp, tailxmax, tailymin);
442 AreaDraw (rp, tailxmax, arrowymin);
443 AreaDraw (rp, arrowxmax, arrowymin);
444 AreaDraw (rp, (arrowxmin + arrowxmax) / 2, arrowymax);
445 AreaDraw (rp, arrowxmin, arrowymin);
446 AreaDraw (rp, tailxmin, arrowymin);
449 if (arrowymax < height - 1) arrowymax++;
451 Move (rp, arrowxmin, arrowymax);
452 Draw (rp, arrowxmax, arrowymax);
457 static void DrawVImage (struct impDraw *imp, struct Image *im, struct BitMap *bm)
460 BltBitMapRastPort (bm, 0, 0, imp->imp_RPort,
461 imp->imp_Offset.X, imp->imp_Offset.Y, im->Width, im->Height,
462 (imp->imp_State == IDS_SELECTED) ? 0x030 : 0x0C0);
467 GLOBALCALL struct Gadget *CreateUpButton (ULONG id, struct Gadget *target, LONG *map, LONG Place)
469 struct Gadget *UpButton;
470 struct Image *UpImage;
472 if (!(UpImage = NewImageObject (UPIMAGE)))
475 if (!(UpButton = (struct Gadget *)NewObject (ScrollButtonClass, NULL,
477 GA_RelBottom, - (UpImage->Height * 2) - SizeHeight + 1,
478 (Place == SCROLLERPLACE_LEFT) ? GA_Left : GA_RelRight,
479 (Place == SCROLLERPLACE_LEFT) ? 0 : (- SizeWidth + 1),
480 /* ^--- perhaps using UpImage->Width would be better... */
482 (Place == SCROLLERPLACE_LEFT) ? GA_LeftBorder : GA_RightBorder, TRUE,
484 /* No need for GA_Width/Height. buttongclass is smart :) */
489 DisposeObject (UpImage);
496 GLOBALCALL struct Gadget *CreateDnButton (ULONG id, struct Gadget *target, LONG *map, LONG Place)
498 struct Gadget *DnButton;
499 struct Image *DnImage;
502 if (!(DnImage = NewImageObject (DOWNIMAGE)))
505 if (!(DnButton = (struct Gadget *)NewObject (ScrollButtonClass, NULL,
507 GA_RelBottom, - DnImage->Height - SizeHeight + 1,
508 (Place == SCROLLERPLACE_LEFT) ? GA_Left : GA_RelRight,
509 (Place == SCROLLERPLACE_LEFT) ? 0 : (- SizeWidth + 1),
510 (Place == SCROLLERPLACE_LEFT) ? GA_LeftBorder : GA_RightBorder, TRUE,
511 /* No need for GA_Width/Height. buttongclass is smart :) */
516 DisposeObject (DnImage);
523 GLOBALCALL struct Gadget *CreateSxButton (ULONG id, struct Gadget *target, LONG *map)
525 struct Gadget *SxButton;
526 struct Image *SxImage;
529 if (!(SxImage = NewImageObject (LEFTIMAGE)))
532 if (!(SxButton = (struct Gadget *)NewObject (ScrollButtonClass, NULL,
534 GA_RelBottom, - SxImage->Height + 1,
535 GA_RelRight, - SizeWidth - (SxImage->Width * 2) + 1,
536 GA_BottomBorder, TRUE,
537 /* No need for GA_Width/Height. buttongclass is smart :) */
542 DisposeObject (SxImage);
549 GLOBALCALL struct Gadget *CreateDxButton (ULONG id, struct Gadget *target, LONG *map)
551 struct Gadget *DxButton;
552 struct Image *DxImage;
555 if (!(DxImage = NewImageObject (RIGHTIMAGE)))
558 if (!(DxButton = (struct Gadget *)NewObject (ScrollButtonClass, NULL,
560 GA_RelBottom, - DxImage->Height + 1,
561 GA_RelRight, - SizeWidth - DxImage->Width + 1,
562 GA_BottomBorder, TRUE,
563 /* No need for GA_Width/Height. buttongclass is smart :) */
568 DisposeObject (DxImage);
575 GLOBALCALL struct Gadget *CreateVSlider (ULONG id, struct Gadget *target, LONG *map, LONG ButtonsSpacing, LONG Place)
579 horizpos = (Place == SCROLLERPLACE_LEFT) ? Scr->WBorLeft : (- SizeWidth + 5);
581 return ((struct Gadget *)NewObject (NULL, PROPGCLASS,
584 (Place == SCROLLERPLACE_LEFT) ? GA_Left : GA_RelRight, horizpos,
585 GA_Width, SizeWidth - 8,
586 GA_RelHeight, - OffY - Scr->WBorBottom - SizeHeight
588 (Place == SCROLLERPLACE_LEFT) ? GA_LeftBorder : GA_RightBorder, TRUE,
592 /* Borderless sliders do only look good with newlook screens */
593 PGA_Borderless, ((DrawInfo->dri_Flags & DRIF_NEWLOOK) && DrawInfo->dri_Depth != 1),
603 GLOBALCALL struct Gadget *CreateHSlider (ULONG id, struct Gadget *target, LONG *map, LONG ButtonsSpacing)
605 struct Gadget *HSlider;
607 if (!(HSlider = (struct Gadget *)NewObject (NULL, PROPGCLASS,
610 GA_RelBottom, - SizeHeight + ((SizeHeight > 15) ? 4 : 3),
611 GA_RelWidth, - OffX - SizeWidth
613 GA_Height, SizeHeight - ((SizeHeight > 15) ? 6 : 4),
614 GA_BottomBorder, TRUE,
617 PGA_Borderless, ((DrawInfo->dri_Flags & DRIF_NEWLOOK) && DrawInfo->dri_Depth != 1),
618 PGA_Freedom, FREEHORIZ,