;/* 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);
}