home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 19
/
AACD19.BIN
/
CDTools
/
ClassAct
/
Examples
/
Layout
/
LayoutExample.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-07-09
|
15KB
|
515 lines
/*************************************************************************
* ClassAct Comprehensive Demo Program
* Copyright © 1995 Osma Ahvenlampi
*
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <intuition/icclass.h>
#include <libraries/gadtools.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h>
#include <graphics/gfxmacros.h>
#include <utility/tagitem.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/diskfont.h>
#include <proto/utility.h>
#include <proto/wb.h>
#include <proto/icon.h>
#include <classact.h>
#include <classact_lib.h>
#include <clib/classact_lib_protos.h>
void __stdargs kprintf(const char *, ...);
/* a simple button */
#define Button(a) ButtonObject, GA_Text, a, ButtonEnd
#define DButton(a) ButtonObject, GA_Text, a, GA_Disabled, TRUE, ButtonEnd
/**************************************************************************
* Some label arrays for the gadgets in this demo.
*/
static STRPTR objtypes[] =
{
"Exec",
"Image",
"Sound",
"Menu",
"Icon",
"Dock",
"Access",
NULL
};
static STRPTR objnames[] =
{
"ToolManager",
"ScreenMode",
"WBPattern",
NULL
};
/*************************************************************************
* 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_ObjType = 1, G_ObjList, G_Top, G_Up, G_Down, G_Bottom,
G_Sort, G_New, G_Edit, G_Copy, G_Remove, G_Help, G_Save, G_Use,
G_Test, G_Cancel, G_MAX } GadgetIDs;
struct Gadget *GL[G_MAX+1];
/*************************************************************************
* ReadArgs
*/
#define TEMPLATE "S=SIMPLEREFRESH/S,NC=NOCAREREFRESH/S,ND=NDEFER/S"
LONG ARG[3];
typedef enum { A_Simple, A_NoCare, A_NoDefer } Args;
/*************************************************************************
* 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;
LONG i = Msg->am_NumArgs;
struct List *l = Hook->h_Data;
struct Node *n;
UBYTE name[256];
GetAttr( WINDOW_Window, Window, (ULONG *)&Win );
/* Detach the list for modifications.
*/
SetGadgetAttrs( GL[G_ObjList], Win, NULL, LISTBROWSER_Labels, ~0, TAG_END );
while (i--)
{
/* Add the name of the icon to the listview. ListBrowser can copy the
* text into an internal buffer and thus let us not worry about the
* pointer validity.
*/
NameFromLock( arg->wa_Lock, name, sizeof(name) );
AddPart( name, arg->wa_Name, sizeof(name) );
if (n = AllocListBrowserNode( 1, LBNCA_CopyText, TRUE, LBNCA_Text, name, TAG_END ))
AddTail( l, n );
arg++;
}
/* Reattach the list */
SetGadgetAttrs( GL[G_ObjList], Win, NULL, LISTBROWSER_Labels, l, TAG_END );
}
/*************************************************************************
* Main Program
*/
int
main(void)
{
struct List *objlist;
struct List *typelist;
struct RDArgs *args;
struct MsgPort *appport;
if (!ButtonBase) /* force it open */
return 30;
if (!(args = ReadArgs(TEMPLATE, ARG, NULL)))
return 20;
Printf("%seferred %s refresh %s\n", ARG[A_NoDefer] ? "Non-d" : "D", ARG[A_Simple] ? "Simple" : "Smart", ARG[A_NoCare] ? "(NoCare)" : "");
objlist = BrowserNodesA( objnames );
typelist = ChooserLabelsA( objtypes );
/* 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();
if (objlist && typelist && appport)
{
struct Gadget *MainLayout;
Object *Window;
struct Hook apphook;
apphook.h_Entry = (ULONG (* )())AppMsgFunc;
apphook.h_SubEntry = NULL;
apphook.h_Data = objlist;
/* 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,
/* About window refreshes:
* Because WindowClass and LayoutClass can, when used together, change the
* normal Intuition practise of refreshing gadgets in the input.device context,
* some rules about the refresh system change.
* Deferred refresh works in both smart and simple refresh windows, but
* if nocarerefresh is used, Intuition does not retain the damage regions
* and any window damage will force the whole window to be refreshed.
* This demo allows you to try combinations of refresh types.
* In the normal case you can ignore this and let WindowClass and the user
* decide what kind of refreshes they want. Nocare refresh can be
* combined with smart refresh to provide a fast, but somewhat more memory
* hungry refresh method. Simple refresh can save some memory but it's
* slower.
*/
WA_SimpleRefresh, ARG[A_Simple],
WA_NoCareRefresh, ARG[A_NoCare],
WA_SmartRefresh, !ARG[A_Simple],
WA_Title, "ClassAct layout.gadget Example (ToolManager preferences mockup)",
WA_ScreenTitle, "ClassAct Copyright 1995 Phantom Development LLC.",
/* Turn on gadget help in the window
*/
WINDOW_GadgetHelp, TRUE,
/* 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,
/* 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( "LayoutExample" ),
WINDOW_IconTitle, "ClassAct Example",
/* Below is the layout of the window
*/
WINDOW_ParentGroup, MainLayout = VGroupObject,
LAYOUT_SpaceOuter, TRUE,
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, !ARG[A_NoDefer],
/* A 1-of-n chooser using the labels list we made from the label array earlier
*/
StartMember, GL[G_ObjType] = ChooserObject,
CHOOSER_Labels, typelist,
EndMember,
MemberLabel("_Object Type"),
/* Objects can be given arbitary weights within groups, and layout.gadget
* will distribute space relative to the total weight of the group.
* Here we set the button column to 0 weight which means minimum space.
* Thus the listview gets all available extra space.
*/
StartHGroup, BAligned,
StartMember, GL[G_ObjList] = ListBrowserObject,
LISTBROWSER_Labels, objlist,
LISTBROWSER_ShowSelected, TRUE,
EndMember,
StartVGroup,
StartMember, GL[G_Top] = DButton("Top"),
StartMember, GL[G_Up] = DButton("Up"),
StartMember, GL[G_Down] = DButton("Down"),
StartMember, GL[G_Bottom] = DButton("Bottom"),
StartMember, GL[G_Sort] = Button("So_rt"),
EndGroup,
CHILD_WeightedWidth, 0,
/* One way to keep the buttons constant size is to set the
* group to stay at minimum size with a weight of 0. We could
* also set the weight of each of the buttons to 0. That way
* extra space would be distributed between the buttons
* instead of all below. This looks better.
*/
CHILD_WeightedHeight, 0,
EndGroup,
/* two rows of buttons. EvenSized instructs layout.gadget that it
* should make sure the minimum size of each matches, so that we
* get four neat columns.
* Again the weight is set to 0. When the window is resized, all
* space is given to the listview.
*/
StartHGroup, EvenSized,
StartMember, GL[G_New] = Button("_New..."),
StartMember, GL[G_Edit] = DButton("_Edit..."),
StartMember, GL[G_Copy] = DButton("Co_py"),
StartMember, GL[G_Remove] = DButton("Remove"),
EndGroup,
CHILD_WeightedHeight, 0,
StartHGroup, EvenSized,
StartMember, GL[G_Save] = Button("_Save"),
StartMember, GL[G_Use] = Button("_Use"),
StartMember, GL[G_Test] = Button("_Test"),
StartMember, GL[G_Cancel] = Button("_Cancel"),
EndGroup,
CHILD_WeightedHeight, 0,
StartMember, GL[G_Help] = ButtonObject,
GA_ReadOnly, TRUE,
GA_Text, "Welcome to ClassAct demo!",
EndMember,
CHILD_WeightedHeight, 0,
EndGroup,
EndWindow;
if (Window)
{
/* Window pointer cache.
*/
struct Window *Win;
/* Finish the gadgetarray initialisation. Set gadget IDs and release verify.
* This is one way of avoiding boring repetition in the layout description
* taglist itself.
*/
{
LONG i = 1;
do SetAttrs(GL[i], GA_ID, i, GA_RelVerify, TRUE, TAG_END);
while (GL[++i]);
}
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_ObjList:
/* User clicked on the listview
*/
{
static ULONG ids[] = { G_Top, G_Up, G_Down, G_Bottom, G_Edit, G_Copy, G_Remove, 0 };
ULONG i, dis = FALSE;
if (code == ~0) /* no node was selected */
dis = TRUE;
for ( i = 0 ; ids[i] ; i++ )
{
SetGadgetAttrs( GL[ids[i]], Win, NULL, GA_Disabled, dis, TAG_END );
RefreshGList( GL[ids[i]], Win, NULL, 1 );
}
break;
}
}
break;
case WMHI_GADGETHELP:
{
STRPTR helptext;
/* A gadget help message informs the application about the gadget
* under the mouse pointer. The code WORD is set to the value the
* gadget returned. Result code contains the ID of the gadget,
* or NULL (not in the window) or WMHI_GADGETMASK (not over a gadget).
*/
switch(result & WMHI_GADGETMASK)
{
case G_ObjType:
helptext = "Choose object type";
break;
case G_ObjList:
helptext = "Choose object to modify";
break;
case G_Top:
helptext = "Move object to top";
break;
case G_Up:
helptext = "Move object upwards";
break;
case G_Down:
helptext = "Move object downwards";
break;
case G_Bottom:
helptext = "Move object to bottom";
break;
case G_Sort:
helptext = "Sort object list";
break;
case G_New:
helptext = "Create new object";
break;
case G_Edit:
helptext = "Edit object";
break;
case G_Copy:
helptext = "Make a new copy of object";
break;
case G_Remove:
helptext = "Delete the object";
break;
case G_Help:
helptext = "Hey there ;)";
break;
case G_Save:
helptext = "Save settings";
break;
case G_Use:
helptext = "Use these settings";
break;
case G_Test:
helptext = "Test these settings";
break;
case G_Cancel:
helptext = "Cancel changes";
break;
default:
helptext = "";
break;
}
if (SetGadgetAttrs( GL[G_Help], Win, NULL, GA_Text, helptext, TAG_END ))
RefreshGList(GL[G_Help], Win, NULL, 1);
}
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;
}
}
/* Close the window and dispose of all attached gadgets
*/
DisposeObject( Window );
}
}
}
if (appport)
DeleteMsgPort(appport);
/* NULL is valid input for these helper functions, so no need to check.
*/
FreeChooserLabels( typelist );
FreeBrowserNodes( objlist );
FreeArgs(args);
}