;/* RKMModel.c - A simple custom modelclass subclass. LC -cfist -b1 -y -v -j73 rkmmodel.c 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/intuition_protos.h> #include <clib/utility_protos.h> #include <clib/alib_protos.h> #include <clib/alib_stdio_protos.h> extern struct Library *IntuitionBase, *UtilityBase; /*************************************************************************************************/ /**************** The attributes defined by this class *****************************************/ /*************************************************************************************************/ #define RKMMOD_CurrVal (TAG_USER + 1) /* This attribute is the current value of the model.*******/ /**********************************************************/ #define RKMMOD_Up (TAG_USER + 2) /* These two are fake attributes that rkmmodelclass *******/ #define RKMMOD_Down (TAG_USER + 3) /* uses as pulse values to increment/decrement the *******/ /* rkmmodel's RKMMOD_CurrVal attribute. *******/ /**********************************************************/ #define RKMMOD_Limit (TAG_USER + 4) /* This attribute contains the upper bound of the *******/ /* rkmmodel's RKMMOD_CurrVal. The rkmmodel has a *******/ /* static lower bound of zero. *******/ /*************************************************************************************************/ #define DEFAULTVALLIMIT 100L /* If the programmer doesn't set */ /* RKMMOD_Limit, it defaults to this. */ struct RKMModData { ULONG currval; /* The instance data for this class. */ ULONG vallimit; }; /*************************************************************************************************/ /************************** The functions in this module ********************************/ /*************************************************************************************************/ void geta4(void); /***************/ Class *initRKMModClass(void); /***************/ BOOL freeRKMModClass(Class *); /***************/ ULONG dispatchRKMModel(Class *, Object *, Msg); /***************/ void NotifyCurrVal(Class *, Object *, struct opUpdate *, struct RKMModData *); /***************/ /*************************************************************************************************/ /*************************************************************************************************/ /******************************** Initialize the class **************************************/ /*************************************************************************************************/ Class *initRKMModClass(void) /* Make the class and set */ { /* up the dispatcher's hook. */ Class *cl; extern ULONG HookEntry(); /* <------- defined in amiga.lib. */ if ( cl = MakeClass( NULL, "modelclass", NULL, sizeof ( struct RKMModData ), 0 )) { cl->cl_Dispatcher.h_Entry = HookEntry; /* initialize the */ cl->cl_Dispatcher.h_SubEntry = dispatchRKMModel; /* cl_Dispatcher */ /* Hook. */ } return ( cl ); } /*************************************************************************************************/ /********************************* Free the class ***************************************/ /*************************************************************************************************/ BOOL freeRKMModClass( Class *cl ) { return (FreeClass(cl)); } /*************************************************************************************************/ /******************************** The class Dispatcher ***********************************/ /*************************************************************************************************/ ULONG dispatchRKMModel(Class *cl, Object *o, Msg msg) { struct RKMModData *mmd; APTR retval = NULL; /* A generic return value used by this class's methods. The */ /* meaning of this field depends on the method. For example, */ /* OM_GET uses this a a boolean return value, while OM_NEW */ /* uses it as a pointer to the new object. */ geta4(); /* SAS/C and Manx function - makes sure A4 contains global data pointer. */ switch (msg->MethodID) { case OM_NEW: /* Pass message onto superclass first so it can set aside the memory */ /* for the object and take care of superclass instance data. */ if (retval = (APTR)DoSuperMethodA(cl, o, msg)) { /************************************************************************/ /* For the OM_NEW method, the object pointer passed to the dispatcher */ /* does not point to an object (how could it? The object doesn't exist */ /* yet.) DoSuperMethodA() returns a pointer to a newly created */ /* object. INST_DATA() is a macro defined in <intuition/classes.h> */ /* that returns a pointer to the object's instance data that is local */ /* to this class. For example, the instance data local to this class */ /* is the RKMModData structure defined above. */ /************************************************************************/ mmd = INST_DATA(cl, retval); mmd->currval = GetTagData(RKMMOD_CurrVal, 0L, /* initialize object's attributes. */ ((struct opSet *)msg)->ops_AttrList); mmd->vallimit = GetTagData(RKMMOD_Limit, DEFAULTVALLIMIT, ((struct opSet *)msg)->ops_AttrList); } break; case OM_SET: case OM_UPDATE: mmd = INST_DATA(cl, o); DoSuperMethodA(cl, o, msg); /* Let the superclasses set their attributes first. */ { struct TagItem *tstate, *ti; /* grab some temp variables off of the stack. */ ti = ((struct opSet *)msg)->ops_AttrList; tstate = ti; /* Step through all of the attribute/value pairs in the list. Use the */ /* utility.library tag functions to do this so they can properly process */ /* special tag IDs like TAG_SKIP, TAG_IGNORE, etc. */ while (ti = NextTagItem(&tstate)) /* Step through all of the attribute/value */ { /* pairs in the list. Use the utility.library tag functions */ /* to do this so they can properly process special tag IDs */ /* like TAG_SKIP, TAG_IGNORE, etc. */ switch (ti->ti_Tag) { case RKMMOD_CurrVal: if ((ti->ti_Data) > mmd->vallimit) ti->ti_Data = mmd->vallimit; mmd->currval = ti->ti_Data; NotifyCurrVal(cl, o, msg, mmd); retval = (APTR)1L; /* Changing RKMMOD_CurrVal can cause a visual */ break; /* change to gadgets in the rkmmodel's broadcast */ /* list. The rkmmodel has to tell the applica- */ /* tion by returning a value besides zero. */ case RKMMOD_Up: mmd->currval++; /* Make sure the current value is not greater than value limit. */ if ((mmd->currval) > mmd->vallimit) mmd->currval = mmd->vallimit; NotifyCurrVal(cl, o, msg, mmd); retval = (APTR)1L; /* Changing RKMMOD_Up can cause a visual */ break; /* change to gadgets in the rkmmodel's broadcast */ /* list. The rkmmodel has to tell the applica- */ /* tion by returning a value besides zero. */ case RKMMOD_Down: mmd->currval--; /* Make sure currval didn't go negative. */ if ((LONG)(mmd->currval) == -1L) mmd->currval = 0L; NotifyCurrVal(cl, o, msg, mmd); retval = (APTR)1L; /* Changing RKMMOD_Down can cause a visual */ break; /* change to gadgets in the rkmmodel's broadcast */ /* list. The rkmmodel has to tell the applica- */ /* tion by returning a value besides zero. */ case RKMMOD_Limit: mmd->vallimit = ti->ti_Data; /* Set the limit. Note that this does */ break; /* not do bounds checking on the */ /* current RKMModData.currval value. */ } } } break; case OM_GET: /* The only attribute that is "gettable" in this */ mmd = INST_DATA(cl, o); /* class or its superclasses is RKMMOD_CurrVal. */ if ((((struct opGet *)msg)->opg_AttrID) == RKMMOD_CurrVal) { *(((struct opGet *)msg)->opg_Storage) = mmd->currval; retval = (Object *)TRUE; } else retval = (APTR)DoSuperMethodA(cl, o, msg); break; default: /* rkmmodelclass does not recognize the methodID, so let the superclass's */ /* dispatcher take a look at it. */ retval = (APTR)DoSuperMethodA(cl, o, msg); break; } return((ULONG)retval); } void NotifyCurrVal(Class *cl, Object *o, struct opUpdate *msg, struct RKMModData *mmd) { struct TagItem tt[2]; tt[0].ti_Tag = RKMMOD_CurrVal; /* make a tag list. */ tt[0].ti_Data = mmd->currval; tt[1].ti_Tag = TAG_DONE; /* If the RKMMOD_CurrVal changes, we want everyone to know about */ DoSuperMethod(cl, o, /* it. Theoretically, the class is supposed to send itself a */ OM_NOTIFY, /* OM_NOTIFY message. Because this class lets its superclass */ tt, /* handle the OM_NOTIFY message, it skips the middleman and */ msg->opu_GInfo, /* sends the OM_NOTIFY directly to its superclass. */ ((msg->MethodID == OM_UPDATE) ? (msg->opu_Flags) : 0L)); /* If this is an OM_UPDATE */ /* method, make sure the part the OM_UPDATE message adds to the */ /* OM_SET message gets added. That lets the dispatcher handle */ } /* OM_UPDATE and OM_SET in the same case. */