#include "demo.h" /***************************************************************************/ /* Here is the beginning of our simple new class... */ /***************************************************************************/ /* ** This class is the same as within Class1.c except that it features ** a pen attribute. */ struct MyData { struct MUI_PenSpec penspec; LONG pen; BOOL penchange; }; #define MYATTR_PEN 0x8022 /* tag value for the new attribute. */ SAVEDS ULONG mNew(struct IClass *cl,Object *obj,Msg msg) { struct MyData *data; struct TagItem *tags,*tag; if (!(obj = (Object *)DoSuperMethodA(cl,obj,msg))) return(0); data = INST_DATA(cl,obj); /* parse initial taglist */ for (tags=((struct opSet *)msg)->ops_AttrList;tag=NextTagItem(&tags);) { switch (tag->ti_Tag) { case MYATTR_PEN: if (tag->ti_Data) data->penspec = *((struct MUI_PenSpec *)tag->ti_Data); break; } } return((ULONG)obj); } SAVEDS ULONG mDispose(struct IClass *cl,Object *obj,Msg msg) { /* OM_NEW didnt allocates something, just do nothing here... */ return(DoSuperMethodA(cl,obj,msg)); } /* ** OM_SET method, we need to see if someone changed the penspec attribute. */ SAVEDS ULONG mSet(struct IClass *cl,Object *obj,Msg msg) { struct MyData *data = INST_DATA(cl,obj); struct TagItem *tags,*tag; for (tags=((struct opSet *)msg)->ops_AttrList;tag=NextTagItem(&tags);) { switch (tag->ti_Tag) { case MYATTR_PEN: if (tag->ti_Data) { data->penspec = *((struct MUI_PenSpec *)tag->ti_Data); data->penchange = TRUE; MUI_Redraw(obj,MADF_DRAWOBJECT); /* redraw ourselves completely */ } break; } } return(DoSuperMethodA(cl,obj,msg)); } /* ** OM_GET method, see if someone wants to read the color. */ static ULONG mGet(struct IClass *cl,Object *obj,Msg msg) { struct MyData *data = INST_DATA(cl,obj); ULONG *store = ((struct opGet *)msg)->opg_Storage; switch (((struct opGet *)msg)->opg_AttrID) { case MYATTR_PEN: *store = (ULONG)&data->penspec; return(TRUE); } return(DoSuperMethodA(cl,obj,msg)); } SAVEDS ULONG mSetup(struct IClass *cl,Object *obj,Msg msg) { struct MyData *data = INST_DATA(cl,obj); if (!DoSuperMethodA(cl,obj,msg)) return(FALSE); data->pen = MUI_ObtainPen(muiRenderInfo(obj),&data->penspec,0); return(TRUE); } SAVEDS ULONG mCleanup(struct IClass *cl,Object *obj,Msg msg) { struct MyData *data = INST_DATA(cl,obj); MUI_ReleasePen(muiRenderInfo(obj),data->pen); return(DoSuperMethodA(cl,obj,msg)); } SAVEDS ULONG mAskMinMax(struct IClass *cl,Object *obj,struct MUIP_AskMinMax *msg) { /* ** let our superclass first fill in what it thinks about sizes. ** this will e.g. add the size of frame and inner spacing. */ DoSuperMethodA(cl,obj,msg); /* ** now add the values specific to our object. note that we ** indeed need to *add* these values, not just set them! */ msg->MinMaxInfo->MinWidth += 100; msg->MinMaxInfo->DefWidth += 120; msg->MinMaxInfo->MaxWidth += 500; msg->MinMaxInfo->MinHeight += 40; msg->MinMaxInfo->DefHeight += 90; msg->MinMaxInfo->MaxHeight += 300; return(0); } /* ** Draw method is called whenever MUI feels we should render ** our object. This usually happens after layout is finished ** or when we need to refresh in a simplerefresh window. ** Note: You may only render within the rectangle ** _mleft(obj), _mtop(obj), _mwidth(obj), _mheight(obj). */ SAVEDS ULONG mDraw(struct IClass *cl,Object *obj,struct MUIP_Draw *msg) { struct MyData *data = INST_DATA(cl,obj); int i; /* ** let our superclass draw itself first, area class would ** e.g. draw the frame and clear the whole region. What ** it does exactly depends on msg->flags. */ DoSuperMethodA(cl,obj,msg); /* ** if MADF_DRAWOBJECT isn't set, we shouldn't draw anything. ** MUI just wanted to update the frame or something like that. */ if (!(msg->flags & MADF_DRAWOBJECT)) return(0); /* ** test if someone changed our pen */ if (data->penchange) { data->penchange = FALSE; MUI_ReleasePen(muiRenderInfo(obj),data->pen); data->pen = MUI_ObtainPen(muiRenderInfo(obj),&data->penspec,0); } /* ** ok, everything ready to render... ** Note that we *must* use the MUIPEN() macro before actually ** using pens from MUI_ObtainPen() in rendering calls. */ SetAPen(_rp(obj),MUIPEN(data->pen)); for (i=_mleft(obj);i<=_mright(obj);i+=5) { Move(_rp(obj),_mleft(obj),_mtop(obj)); Draw(_rp(obj),i,_mbottom(obj)); Move(_rp(obj),_mright(obj),_mtop(obj)); Draw(_rp(obj),i,_mbottom(obj)); } return(0); } /* ** Here comes the dispatcher for our custom class. We only need to ** care about MUIM_AskMinMax and MUIM_Draw in this simple case. ** Unknown/unused methods are passed to the superclass immediately. */ SAVEDS ASM ULONG MyDispatcher(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg) { switch (msg->MethodID) { case OM_NEW : return(mNew (cl,obj,(APTR)msg)); case OM_DISPOSE : return(mDispose (cl,obj,(APTR)msg)); case OM_SET : return(mSet (cl,obj,(APTR)msg)); case OM_GET : return(mGet (cl,obj,(APTR)msg)); case MUIM_AskMinMax: return(mAskMinMax(cl,obj,(APTR)msg)); case MUIM_Setup : return(mSetup (cl,obj,(APTR)msg)); case MUIM_Cleanup : return(mCleanup (cl,obj,(APTR)msg)); case MUIM_Draw : return(mDraw (cl,obj,(APTR)msg)); } return(DoSuperMethodA(cl,obj,msg)); } /***************************************************************************/ /* Thats all there is about it. Now lets see how things are used... */ /***************************************************************************/ int main(int argc,char *argv[]) { Object *app,*window,*MyObj,*pen; struct MUI_CustomClass *mcc; struct MUI_PenSpec *startpen; init(); /* Create the new custom class with a call to MUI_CreateCustomClass(). */ /* Caution: This function returns not a struct IClass, but a */ /* struct MUI_CustomClass which contains a struct IClass to be */ /* used with NewObject() calls. */ /* Note well: MUI creates the dispatcher hook for you, you may */ /* *not* use its h_Data field! If you need custom data, use the */ /* cl_UserData of the IClass structure! */ if (!(mcc = MUI_CreateCustomClass(NULL,MUIC_Area,NULL,sizeof(struct MyData),MyDispatcher))) fail(NULL,"Could not create custom class."); app = ApplicationObject, MUIA_Application_Title , "Class2", MUIA_Application_Version , "$VER: Class2 19.5 (12.02.97)", MUIA_Application_Copyright , "©1993, Stefan Stuntz", MUIA_Application_Author , "Stefan Stuntz", MUIA_Application_Description, "Demonstrate the use of custom classes.", MUIA_Application_Base , "CLASS2", SubWindow, window = WindowObject, MUIA_Window_Title, "Another Custom Class", MUIA_Window_ID , MAKE_ID('C','L','S','2'), WindowContents, VGroup, Child, TextObject, TextFrame, MUIA_Background, MUII_TextBack, MUIA_Text_Contents, "\33cThis is a custom class with attributes.\nClick on the button at the bottom of\nthe window to adjust the color.", End, Child, MyObj = NewObject(mcc->mcc_Class,NULL, TextFrame, MUIA_Background, MUII_BACKGROUND, TAG_DONE), Child, HGroup, MUIA_Weight, 10, Child, FreeLabel("Custom Class Color:"), Child, pen = PoppenObject, MUIA_CycleChain, 1, MUIA_Window_Title, "Custom Class Color", End, End, End, End, End; if (!app) fail(app,"Failed to create Application."); DoMethod(window,MUIM_Notify,MUIA_Window_CloseRequest,TRUE, app,2,MUIM_Application_ReturnID,MUIV_Application_ReturnID_Quit); DoMethod(pen,MUIM_Notify,MUIA_Pendisplay_Spec,MUIV_EveryTime, MyObj,3,MUIM_Set,MYATTR_PEN,MUIV_TriggerValue); DoMethod(pen,MUIM_Pendisplay_SetMUIPen,MPEN_HALFSHINE); get(pen,MUIA_Pendisplay_Spec,&startpen); set(MyObj,MYATTR_PEN,startpen); /* ** This is the ideal input loop for an object oriented MUI application. ** Everything is encapsulated in classes, no return ids need to be used, ** we just check if the program shall terminate. ** Note that MUIM_Application_NewInput expects sigs to contain the result ** from Wait() (or 0). This makes the input loop significantly faster. */ set(window,MUIA_Window_Open,TRUE); { ULONG sigs = 0; while (DoMethod(app,MUIM_Application_NewInput,&sigs) != MUIV_Application_ReturnID_Quit) { if (sigs) { sigs = Wait(sigs | SIGBREAKF_CTRL_C); if (sigs & SIGBREAKF_CTRL_C) break; } } } set(window,MUIA_Window_Open,FALSE); /* ** Shut down... */ MUI_DisposeObject(app); /* dispose all objects. */ MUI_DeleteCustomClass(mcc); /* delete the custom class. */ fail(NULL,NULL); /* exit, app is already disposed. */ }