/************************************************************************* * ClassAct Comprehensive Demo Program * Copyright © 1995 Osma Ahvenlampi * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* get LayerHook.lha from Aminet for this */ #include /************************************************************************* * Backfill options * We're using the public domain LayerHook here. */ struct BackFillOptions Options = { 256,256, // !!! 0,0, TRUE,FALSE, 0,0, TRUE }; struct BackFillInfo BF1, BF2, *Backfill; UBYTE name[256]; /************************************************************************* * Gadget list * This wouldn't be strictly necessary, but it's an easy way of keeping * the gadget pointers for when we need to access the gadgets. */ typedef enum { G_Backfill = 1, G_Datatype, G_MAX } GadgetIDs; struct Gadget *GL[G_MAX+1]; /************************************************************************* * App message hook. * Workbench App messages can be caught with a callback hook such as this. * We'll not worry about the app message type in this hook. Objects dropped * on the window or on the icon (while iconified) will be added to the * listview. */ void __asm __saveds AppMsgFunc( register __a0 struct Hook *Hook, register __a2 Object *Window, register __a1 struct AppMessage *Msg ) { struct Window *Win; struct WBArg *arg = Msg->am_ArgList; Object *dt; GetAttr( WINDOW_Window, Window, (ULONG *)&Win ); NameFromLock( arg->wa_Lock, name, sizeof(name) ); AddPart( name, arg->wa_Name, sizeof(name) ); dt = NewDTObject( name, DTA_GroupID, GID_PICTURE, ICA_TARGET, ICTARGET_IDCMP, TAG_END ); if (dt) { SetGadgetAttrs( (struct Gadget *)Hook->h_Data, Win, NULL, LAYOUT_ModifyChild, GL[G_Datatype], CHILD_ReplaceObject, dt, TAG_END ); GL[G_Datatype] = (struct Gadget *)dt; RethinkLayout( (struct Gadget *)Hook->h_Data, Win, NULL, FALSE ); } } struct Hook apphook; /************************************************************************* * IDCMP hook */ void __asm __saveds IDCMPFunc( register __a0 struct Hook *Hook, register __a2 Object *Window, register __a1 struct IntuiMessage *Msg ) { struct Window *Win; GetAttr( WINDOW_Window, Window, (ULONG *)&Win ); if (Msg->Class == IDCMP_IDCMPUPDATE) { if ( GetTagData( DTA_Sync, FALSE, Msg->IAddress ) ) { RefreshGList( (struct Gadget *)Hook->h_Data, Win, NULL, 1 ); } } } struct Hook idcmphook; /************************************************************************* * This function creates our gadgets for the window. */ Object *CreateLayout(void) { return VGroupObject, Offset(32,32,32,32), LAYOUT_BevelStyle, BVS_THIN, /* this tag instructs layout.gadget to defer GM_LAYOUT and GM_RENDER and ask * the windowclass to do them. This lessens the load on input.device */ LAYOUT_DeferLayout, TRUE, /* this gives us a backfill */ CLASSACT_BackFill, Backfill, /* this dummy object will be replaced with a datatype when we have a picture */ StartMember, apphook.h_Data = idcmphook.h_Data = LayoutObject, VCentered, HCentered, LAYOUT_BevelStyle, BVS_THIN, LAYOUT_BevelState, IDS_SELECTED, LAYOUT_SpaceOuter, TRUE, /* We need to install this clearing backfill hook because * most of the datatypes really screw up rendering if the * background isn't color 0. */ LAYOUT_BackFill, LAYERS_BACKFILL, StartImage, GL[G_Datatype] = LabelObject, LABEL_Text, "Please drop picture icons on this window", EndImage, CHILD_MinHeight, 128, EndMember, StartMember, GL[G_Backfill] = ButtonObject, GA_Text, "Use as a backfill", GA_ID, G_Backfill, GA_RelVerify, TRUE, EndMember, CHILD_WeightedHeight, 0, EndGroup; } /************************************************************************* * Main Program */ int main(void) { struct MsgPort *appport; struct Screen *Scr; if (!ButtonBase) /* force it open */ return 30; /* By providing a message port you enable windowclass to handle iconification * and appwindows. This port can shared by all the windows of your application. */ appport = CreateMsgPort(); Scr = LockPubScreen(NULL); if (appport && Scr) { Object *Window; apphook.h_Entry = (ULONG (* )())AppMsgFunc; apphook.h_SubEntry = NULL; idcmphook.h_Entry = (ULONG (* )())IDCMPFunc; idcmphook.h_SubEntry = NULL; /* Create a Window object with a Layout. When Window is asked to open itself, * it will calculate how much space the Layout needs and size itself accordingly. */ Window = WindowObject, /* these tags describe the window */ WA_IDCMP, IDCMP_RAWKEY, WA_Top, 20, WA_Left, 20, WA_SizeGadget, TRUE, WA_DepthGadget, TRUE, WA_DragBar, TRUE, WA_CloseGadget, TRUE, WA_Activate, TRUE, WA_Title, "ClassAct backfill/datatype example", WA_ScreenTitle, "ClassAct Copyright 1995 Phantom Development LLC.", /* Add an iconification gadget. If you have this, you must listen to * WMHI_ICONIFY. */ WINDOW_IconifyGadget, TRUE, /* This message port lets windowclass handle the icon and appwindow. */ WINDOW_AppPort, appport, WINDOW_AppWindow, TRUE, WINDOW_AppMsgHook, &apphook, /* This sets up windowclass to relay IDCMPUPDATE messages to the * application's hook. */ WINDOW_IDCMPHook, &idcmphook, WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE, /* The windowclass will automatically free the DiskObject used when * iconifying the window. If you do not provide a valid DiskObject, * windowclass will try to use env:sys/def_window.info or the default * project icon. */ WINDOW_Icon, GetDiskObject( "BackfillExample" ), WINDOW_IconTitle, "ClassAct Example", /* Below is the layout of the window */ WINDOW_Layout, CreateLayout(), EndWindow; if (Window) { /* Window pointer cache. */ struct Window *Win; BOOL changebackfill = FALSE; if (Win = CA_OpenWindow( Window )) { ULONG wsig, asig = 1L << appport->mp_SigBit; BOOL done = FALSE; /* Now that the window has been opened, we can get the signal mask * of its user port. If the program supported iconification and didn't * use a shared IDCMP port between all windows, this signal bit * would have to be re-queried before each Wait(). */ GetAttr( WINDOW_SigMask, Window, &wsig ); while (done == FALSE) { ULONG sig = Wait(wsig | asig | SIGBREAKF_CTRL_C); ULONG result; UWORD code; if (sig & (wsig | asig)) { /* Messages waiting at the window's IDCMP port. Loop at WM_HANDLEINPUT * until all have been processed. */ while ((result = CA_HandleInput(Window,&code)) != WMHI_LASTMSG) { /* The return code of this method is two-part. The upper word describes the * class of the message (gadgetup, menupick, closewindow, iconify, etc), * and the lower word is a class-defined ID, currently in use in the * gadgetup and menupick return codes. * Switch on the class, then on the ID. */ switch(result & WMHI_CLASSMASK) { case WMHI_GADGETUP: /* OK, got a gadgetup from something. Lets find out what the something is. * The code WORD to which a pointer was passed to WM_HANDLEINPUT has been * set to the Code value from the IDCMP_GADGETUP, in case we need it. */ switch(result & WMHI_GADGETMASK) { case G_Backfill: changebackfill = TRUE; break; } break; case WMHI_CLOSEWINDOW: /* The window close gadget was hit. Time to die... */ done = TRUE; break; case WMHI_ICONIFY: /* Window requests that it be iconified. Handle this event as * soon as possible. The window is not iconified automatically to * give you a chance to make note that the window pointer will be * invalid before the window closes. It also allows you to free * resources only needed when the window is open, if you wish to. */ if (CA_Iconify( Window )) Win = NULL; break; case WMHI_UNICONIFY: /* The window should be reopened. If you had free'd something * on iconify, now is the time to re-allocate it, before calling * CA_OpenWindow. */ Win = CA_OpenWindow( Window ); break; } } } else if (sig & SIGBREAKF_CTRL_C) { done = TRUE; } if (changebackfill) { Object *layout; /* This is a quick&dirty demo using an unmodified LayerHook (on Aminet). * This hook can not change its source bitmap on the fly. * Becaue of this, we have to do a bit of a juggling act to * replace the current backfill. */ if (Backfill == &BF1) { Backfill = NULL; if (LoadBackgroundImage( &BF2, name, Scr, &Options )) { Backfill = &BF2; } } else { Backfill = NULL; if (LoadBackgroundImage( &BF1, name, Scr, &Options )) { Backfill = &BF1; } } if (layout = CreateLayout()) { SetAttrs(Window, WINDOW_Layout, layout, TAG_END); /* backfill changed, it's not safe to dispose the old * one. */ UnloadBackgroundImage((Backfill == &BF1) ? &BF2 : &BF1); } else { /* layout failed */ UnloadBackgroundImage(Backfill); } changebackfill = FALSE; } } /* Close the window and dispose of all attached gadgets */ DisposeObject( Window ); } } } if (appport) DeleteMsgPort(appport); if (Scr) UnlockPubScreen(NULL,Scr); }