;/* RKMButClass.c - Example Boopsi gadget for RKRM:Libraries ; Execute me to compile me with Lattice 5.10b LC -b1 -d0 -cfistq -v -y -j73 RKMButClass.c Blink FROM LIB:c.o,RKMButClass.o TO TestBut LIBRARY LIB:LC.lib,LIB:Amiga.lib quit */ #include <exec/types.h> #include <intuition/intuition.h> #include <intuition/classes.h> #include <intuition/classusr.h> #include <intuition/imageclass.h> #include <intuition/gadgetclass.h> #include <intuition/cghooks.h> #include <intuition/icclass.h> #include <utility/tagitem.h> #include <utility/hooks.h> #include <clib/exec_protos.h> #include <clib/intuition_protos.h> #include <clib/graphics_protos.h> #include <clib/utility_protos.h> #include <clib/alib_protos.h> #include <clib/alib_stdio_protos.h> #include <graphics/gfxmacros.h> #ifdef LATTICE int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */ int chkabort(void) { return(0); } #endif UBYTE *vers = "\0$VER: TestBut 37.1"; /***********************************************************/ /**************** Class specifics ****************/ /***********************************************************/ #define RKMBUT_Pulse (TAG_USER + 1) struct ButINST { LONG midX, midY; /* Coordinates of middle of gadget */ }; /* ButINST has one flag: */ #define ERASE_ONLY 0x00000001 /* Tells rendering routine to */ /* only erase the gadget, not */ /* rerender a new one. This */ /* lets the gadget erase it- */ /* self before it rescales. */ /* The functions in this module */ Class *initRKMButGadClass(void); BOOL freeRKMButGadClass(Class *); ULONG dispatchRKMButGad(Class *, Object *, Msg); void NotifyPulse(Class *, Object *, ULONG, LONG, struct gpInput *); ULONG RenderRKMBut(Class *, struct Gadget *, struct gpRender *); void geta4(void); void MainLoop(ULONG, ULONG); /*************************************************************************************************/ /* The main() function connects an RKMButClass object to a Boopsi integer gadget, which displays */ /* the RKMButClass gadget's RKMBUT_Pulse value. The code scales and move the gadget while it is */ /* in place. */ /*************************************************************************************************/ struct TagItem pulse2int[] = { {RKMBUT_Pulse, STRINGA_LongVal}, {TAG_END,} }; #define INTWIDTH 40 #define INTHEIGHT 20 struct Library *IntuitionBase, *UtilityBase, *GfxBase; struct Window *w; Class *rkmbutcl; struct Gadget *integer, *but; struct IntuiMessage *msg; void main(void) { if (IntuitionBase = OpenLibrary("intuition.library", 37L)) { if (UtilityBase = OpenLibrary("utility.library", 37L)) { if (GfxBase = OpenLibrary("graphics.library", 37L)) { if (w = OpenWindowTags(NULL, WA_Flags, WFLG_DEPTHGADGET | WFLG_DRAGBAR | WFLG_CLOSEGADGET | WFLG_SIZEGADGET, WA_IDCMP, IDCMP_CLOSEWINDOW, WA_Width, 640, WA_Height, 200, TAG_END)) { WindowLimits(w, 450, 200, 640, 200); if (rkmbutcl = initRKMButGadClass()) { if (integer = (struct Gadget *)NewObject(NULL, "strgclass", GA_ID, 1L, GA_Top, (w->BorderTop) + 5L, GA_Left, (w->BorderLeft) + 5L, GA_Width, INTWIDTH, GA_Height, INTHEIGHT, STRINGA_LongVal, 0L, STRINGA_MaxChars, 5L, TAG_END)) { if (but = (struct Gadget *)NewObject(rkmbutcl, NULL, GA_ID, 2L, GA_Top, (w->BorderTop) + 5L, GA_Left, integer->LeftEdge + integer->Width + 5L, GA_Width, 40L, GA_Height, INTHEIGHT, GA_Previous, integer, ICA_MAP, pulse2int, ICA_TARGET, integer, TAG_END)) { AddGList(w, integer, -1, -1, NULL); RefreshGList(integer, w, NULL, -1); SetWindowTitles(w, "<-- Click to resize gadget Height", NULL); MainLoop(TAG_DONE, 0L); SetWindowTitles(w, "<-- Click to resize gadget Width", NULL); MainLoop(GA_Height, 100L); SetWindowTitles(w, "<-- Click to resize gadget Y position", NULL); MainLoop(GA_Width, 100L); SetWindowTitles(w, "<-- Click to resize gadget X position", NULL); MainLoop(GA_Top, but->TopEdge + 20); SetWindowTitles(w, "<-- Click to quit", NULL); MainLoop(GA_Left, but->LeftEdge + 20); RemoveGList(w, integer, -1); DisposeObject(but); } DisposeObject(integer); } freeRKMButGadClass(rkmbutcl); } CloseWindow(w); } CloseLibrary(GfxBase); } CloseLibrary(UtilityBase); } CloseLibrary(IntuitionBase); } } void MainLoop(ULONG attr, ULONG value) { ULONG done = FALSE; SetGadgetAttrs(but, w, NULL, attr, value, TAG_DONE); while (done == FALSE) { WaitPort((struct MsgPort *)w->UserPort); while (msg = (struct IntuiMessage *) GetMsg((struct MsgPort *)w->UserPort)) { if (msg->Class == IDCMP_CLOSEWINDOW) { done = TRUE; } ReplyMsg(msg); } } } /***********************************************************/ /** Make the class and set up the dispatcher's hook **/ /***********************************************************/ Class *initRKMButGadClass(void) { Class *cl = NULL; extern ULONG HookEntry(); /* defined in amiga.lib */ if ( cl = MakeClass( NULL, "gadgetclass", NULL, sizeof ( struct ButINST ), 0 )) { /* initialize the cl_Dispatcher Hook */ cl->cl_Dispatcher.h_Entry = HookEntry; cl->cl_Dispatcher.h_SubEntry = dispatchRKMButGad; } return ( cl ); } /***********************************************************/ /****************** Free the class ****************/ /***********************************************************/ BOOL freeRKMButGadClass( Class *cl ) { return (FreeClass(cl)); } /***********************************************************/ /********** The RKMBut class dispatcher *********/ /***********************************************************/ ULONG dispatchRKMButGad(Class *cl, Object *o, Msg msg) { struct ButINST *inst; ULONG retval = FALSE; Object *object; /* SAS/C and Manx function to make sure register A4 contains a pointer to global data */ geta4(); switch (msg->MethodID) { case OM_NEW: /* First, pass up to superclass */ if (object = (Object *)DoSuperMethodA(cl, o, msg)) { struct Gadget *g = (struct Gadget *)object; /* Initial local instance data */ inst = INST_DATA(cl, object); inst->midX = g->LeftEdge + ( (g->Width) / 2); inst->midY = g->TopEdge + ( (g->Height) / 2); retval = (ULONG)object; } break; case GM_HITTEST: /* Since this is a rectangular gadget this */ /* method always returns GMR_GADGETHIT. */ retval = GMR_GADGETHIT; break; case GM_GOACTIVE: inst = INST_DATA(cl, o); /* Only become active if the GM_GOACTIVE */ /* was triggered by direct user input. */ if (((struct gpInput *)msg)->gpi_IEvent) { /* This gadget is now active, change */ /* visual state to selected and render. */ ((struct Gadget *)o)->Flags |= GFLG_SELECTED; RenderRKMBut(cl, (struct Gadget *)o, (struct gpRender *)msg); retval = GMR_MEACTIVE; } else /* The GM_GOACTIVE was not */ /* triggered by direct user input. */ retval = GMR_NOREUSE; break; case GM_RENDER: retval = RenderRKMBut(cl, (struct Gadget *)o, (struct gpRender *)msg); break; case GM_HANDLEINPUT: /* While it is active, this gadget sends its superclass an */ /* OM_NOTIFY pulse for every IECLASS_TIMER event that goes by */ /* (about one every 10th of a second). Any object that is */ /* connected to this gadget will get A LOT of OM_UPDATE messages. */ { struct Gadget *g = (struct Gadget *)o; struct gpInput *gpi = (struct gpInput *)msg; struct InputEvent *ie = gpi->gpi_IEvent; inst = INST_DATA(cl, o); retval = GMR_MEACTIVE; if (ie->ie_Class == IECLASS_RAWMOUSE) { switch (ie->ie_Code) { case SELECTUP: /* The user let go of the gadget so return GMR_NOREUSE */ /* to deactivate and to tell Intuition not to reuse */ /* this Input Event as we have already processed it. */ /*If the user let go of the gadget while the mouse was */ /*over it, mask GMR_VERIFY into the return value so */ /*Intuition will send a Release Verify (GADGETUP). */ if ( ((gpi->gpi_Mouse).X < g->LeftEdge) || ((gpi->gpi_Mouse).X > g->LeftEdge + g->Width) || ((gpi->gpi_Mouse).Y < g->TopEdge) || ((gpi->gpi_Mouse).Y > g->TopEdge + g->Height) ) retval = GMR_NOREUSE | GMR_VERIFY; else retval = GMR_NOREUSE; /* Since the gadget is going inactive, send a final */ /* notification to the ICA_TARGET. */ NotifyPulse(cl , o, 0L, inst->midX, (struct gp_Input *)msg); break; case MENUDOWN: /* The user hit the menu button. Go inactive and let */ /* Intuition reuse the menu button event so Intuition can */ /* pop up the menu bar. */ retval = GMR_REUSE; /* Since the gadget is going inactive, send a final */ /* notification to the ICA_TARGET. */ NotifyPulse(cl , o, 0L, inst->midX, (struct gp_Input *)msg); break; default: retval = GMR_MEACTIVE; } } else if (ie->ie_Class == IECLASS_TIMER) /* If the gadget gets a timer event, it sends an interim OM_NOTIFY */ NotifyPulse(cl, o, OPUF_INTERIM, inst->midX, gpi); /* to its superclass. */ } break; case GM_GOINACTIVE: /* Intuition said to go inactive. Clear the GFLG_SELECTED */ /* bit and render using unselected imagery. */ ((struct Gadget *)o)->Flags &= ~GFLG_SELECTED; RenderRKMBut(cl, (struct Gadget *)o, (struct gpRender *)msg); break; case OM_SET:/* Although this class doesn't have settable attributes, this gadget class */ /* does have scaleable imagery, so it needs to find out when its size and/or */ /* position has changed so it can erase itself, THEN scale, and rerender. */ if ( FindTagItem(GA_Width, ((struct opSet *)msg)->ops_AttrList) || FindTagItem(GA_Height, ((struct opSet *)msg)->ops_AttrList) || FindTagItem(GA_Top, ((struct opSet *)msg)->ops_AttrList) || FindTagItem(GA_Left, ((struct opSet *)msg)->ops_AttrList) ) { struct RastPort *rp; struct Gadget *g = (struct Gadget *)o; WORD x,y,w,h; x = g->LeftEdge; y = g->TopEdge; w = g->Width; h = g->Height; inst = INST_DATA(cl, o); retval = DoSuperMethodA(cl, o, msg); /* Get pointer to RastPort for gadget. */ if (rp = ObtainGIRPort( ((struct opSet *)msg)->ops_GInfo) ) { UWORD *pens = ((struct opSet *)msg)->ops_GInfo->gi_DrInfo->dri_Pens; SetAPen(rp, pens[BACKGROUNDPEN]); SetDrMd(rp, JAM1); /* Erase the old gadget. */ RectFill(rp, x, y, x+w, y+h); inst->midX = g->LeftEdge + ( (g->Width) / 2); /* Recalculate where the */ inst->midY = g->TopEdge + ( (g->Height) / 2); /* center of the gadget is. */ /* Rerender the gadget. */ DoMethod(o, GM_RENDER, ((struct opSet *)msg)->ops_GInfo, rp, GREDRAW_REDRAW); ReleaseGIRPort(rp); } } else retval = DoSuperMethodA(cl, o, msg); break; default: /* rkmmodelclass does not recognize the methodID, let the superclass's */ /* dispatcher take a look at it. */ retval = DoSuperMethodA(cl, o, msg); break; } return(retval); } /*************************************************************************************************/ /************** Build an OM_NOTIFY message for RKMBUT_Pulse and send it to the superclass. *******/ /*************************************************************************************************/ void NotifyPulse(Class *cl, Object *o, ULONG flags, LONG mid, struct gpInput *gpi) { struct TagItem tt[3]; tt[0].ti_Tag = RKMBUT_Pulse; tt[0].ti_Data = mid - ((gpi->gpi_Mouse).X + ((struct Gadget *)o)->LeftEdge); tt[1].ti_Tag = GA_ID; tt[1].ti_Data = ((struct Gadget *)o)->GadgetID; tt[2].ti_Tag = TAG_DONE; DoSuperMethod(cl, o, OM_NOTIFY, tt, gpi->gpi_GInfo, flags); } /*************************************************************************************************/ /******************************* Erase and rerender the gadget. ******************************/ /*************************************************************************************************/ ULONG RenderRKMBut(Class *cl, struct Gadget *g, struct gpRender *msg) { struct ButINST *inst = INST_DATA(cl, (Object *)g); struct RastPort *rp; ULONG retval = TRUE; UWORD *pens = msg->gpr_GInfo->gi_DrInfo->dri_Pens; if (msg->MethodID == GM_RENDER) /* If msg is truly a GM_RENDER message (not a gpInput that */ /* looks like a gpRender), use the rastport within it... */ rp = msg->gpr_RPort; else /* ...Otherwise, get a rastport using ObtainGIRPort(). */ rp = ObtainGIRPort(msg->gpr_GInfo); if (rp) { UWORD back, shine, shadow, w, h, x, y; if (g->Flags & GFLG_SELECTED) /* If the gadget is selected, reverse the meanings of the */ { /* pens. */ back = pens[FILLPEN]; shine = pens[SHADOWPEN]; shadow = pens[SHINEPEN]; } else { back = pens[BACKGROUNDPEN]; shine = pens[SHINEPEN]; shadow = pens[SHADOWPEN]; } SetDrMd(rp, JAM1); SetAPen(rp, back); /* Erase the old gadget. */ RectFill(rp, g->LeftEdge, g->TopEdge, g->LeftEdge + g->Width, g->TopEdge + g->Height); SetAPen(rp, shadow); /* Draw shadow edge. */ Move(rp, g->LeftEdge + 1, g->TopEdge + g->Height); Draw(rp, g->LeftEdge + g->Width, g->TopEdge + g->Height); Draw(rp, g->LeftEdge + g->Width, g->TopEdge + 1); w = g->Width / 4; /* Draw Arrows - Sorry, no frills imagery */ h = g->Height / 2; x = g->LeftEdge + (w/2); y = g->TopEdge + (h/2); Move(rp, x, inst->midY); Draw(rp, x + w, y); Draw(rp, x + w, y + (g->Height) - h); Draw(rp, x, inst->midY); x = g->LeftEdge + (w/2) + g->Width / 2; Move(rp, x + w, inst->midY); Draw(rp, x, y); Draw(rp, x, y + (g->Height) - h); Draw(rp, x + w, inst->midY); SetAPen(rp, shine); /* Draw shine edge. */ Move(rp, g->LeftEdge, g->TopEdge + g->Height - 1); Draw(rp, g->LeftEdge, g->TopEdge); Draw(rp, g->LeftEdge + g->Width - 1, g->TopEdge); if (msg->MethodID != GM_RENDER) /* If we allocated a rastport, give it back. */ ReleaseGIRPort(rp); } else retval = FALSE; return(retval); }