home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
disks
/
disk450.lzh
/
MinRexx
/
freedraw.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-03
|
42KB
|
1,130 lines
#ifdef TALKTOREXX
/*
* This program is an example of how to add a Rexx port to a given
* program. I thought it particularly appropriate to grab a program
* off Fred Fish Disk 1. All the REXX stuff is bracketed by `ifdef
* TALKTOREXX', so you can identify it easily. If you compile with
* TALKTOREXX unset, you will get the default program with no REXX
* port.
*
* The REXX port on this program adds another 3K to the executable
* size, but a lot of functionality comes with that. You can draw
* from Rexx, spawn macros from Rexx, etc. But go to the next
* TALKTOREXX for more information.
*
* To run a rexx macro on startup, simply give that rexx macro as
* part of the command line, as in
*
* freedraw sample
*
* or
*
* freedraw bspline 20 100 20 20 280 20 280 100
*
* All modifications are by Radical Eye Software, and all modifications
* are placed in the public domain.
*/
#endif
/************************************************************************/
/*** FreeDraw - PD graphics for Amiga ***/
/*** ***/
/*** This is an extremely simple graphics editor which works in ***/
/*** the windowing environment of the Amiga. It is very limited ***/
/*** in features, but I hope to add a lot more, and I would be ***/
/*** happy to receive assistance from anyone who wants to give it. ***/
/*** The basic idea of this program is to provide some minimal ***/
/*** image editing functions which can be used to develop images ***/
/*** for other programs. I know there will be a lot of Paint type ***/
/*** type programs avaialable soon, but what are we supposed to use ***/
/*** now? The most important features to add now will probably be ***/
/*** those related to "cut and paste", disk srtorage and retrieval, ***/
/*** and "single-pixel" editing like Mac's "fatbits". ***/
/*** I intend to use the IFF standard for the image storage and ***/
/*** retrieval and will be coding a "Files" menu soon. The work ***/
/*** required for "cut and paste" should be almost trivial, but I ***/
/*** still may not get to it for a while. Fatbits editing from one ***/
/*** window to another involves some manipulations of the RastPorts ***/
/*** which still elude me, as I have only recently begun to use the ***/
/*** Amiga and don't yet understand some important details of these ***/
/*** structures. This would be a great item for one of the genius ***/
/*** members of the Amiga programming community to provide. ***/
/*** There are only two menu topics in this version, so using it ***/
/*** is really quite easy. Boxes are not allowed to be drawn in ***/
/*** areas outside of the window where border gadgets are located, ***/
/*** and the pen-draw mode also clips to these same boundaries. If ***/
/*** you have begun to draw a box by clicking the left button while ***/
/*** the cursor is located in the FreeDraw window, then you can ***/
/*** cancel that box by clicking the right button. In the pen mode ***/
/*** pressing and holding the left button will draw. Colors are ***/
/*** selected by simply releasing the menu button over the desired ***/
/*** color in the Color menu. The erase feature always clears the ***/
/*** window to the currently selected color. ***/
/*** This is no gem of programming style, but you're getting it ***/
/*** for the right price so be patient with its design flaws. New ***/
/*** versions will appear here on BIX as soon as I can get them in ***/
/*** shape for release. I apologize to anyone who objects to my ***/
/*** lack of coding grace, but I just want to get the project off ***/
/*** the ground, and improvements will be forthcoming. There are ***/
/*** a lot of comments, but I didn't know what needed to be made ***/
/*** clear so I just commented everything. ***/
/*** ***/
/*** If you like the idea of a PD graphics program and would be ***/
/*** interested in doing some development work, then please write ***/
/*** me at the address listed below, or call if you prefer. I do ***/
/*** want to know if there is any interest in such a project, so ***/
/*** I will be glad to discuss any ideas you might have. Also, as ***/
/*** I do not currently use CompuServe or any other major nets, I ***/
/*** would appreciate if someone would post this listing there. ***/
/*** I hope somebody enjoys this. Have Fun. ***/
/*** Rick Ross 11/14/85 ***/
/*** ***/
/*** My address: ***/
/*** Richard M. Ross, Jr. ***/
/*** Eidetic Imaging ***/
/*** 740 N. 22nd Street ***/
/*** Philadelphia, PA 19130 ***/
/*** ***/
/*** Phone - (215) 236-7388 ***/
/************************************************************************/
char *VERSION = "Freedraw 0.01 by Richard M. Ross" ;
/* compiler directives to fetch the necessary header files */
#include <exec/types.h>
#include <exec/exec.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfx.h>
#include <graphics/regions.h>
#include <graphics/copper.h>
#include <graphics/gels.h>
#include <graphics/gfxbase.h>
#include <devices/keymap.h>
#include <hardware/blit.h>
/* These definitions are used by intuition for
* calls to OpenLibrary() in order to ensure
* that an appropriate ROM revision is
* available.
*/
#define INTUITION_REV 1L
#define GRAPHICS_REV 1L
/* Intuition always wants to see these declarations */
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
/* This is the Window structure declaration.
* Nothing fancy is going on here, but note
* the Flags and IDCMPFlags members of the
* structure define which messages will be
* sent by Intuition. I haven't used them all
* and if you want to change the settings you
* should probably do it her instead of using
* ModifyIDCMP later.
*/
struct NewWindow NewWindow = {
10,
10,
600,
180,
0,
1,
CLOSEWINDOW | MOUSEMOVE | MOUSEBUTTONS | MENUPICK
| NEWSIZE | INACTIVEWINDOW,
WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWDRAG
| WINDOWDEPTH | WINDOWSIZING | REPORTMOUSE,
NULL,
NULL,
(UBYTE *)"AMIGA FreeDraw 0.01",
NULL,
NULL,
100, 35,
-1, -1,
WBENCHSCREEN,
};
#ifdef TALKTOREXX
/*
* We need our include file.
*/
#include "minrexx.h"
/*
* These are the REXX functions defined at the bottom of the file.
*/
void rexxcolor(), rexxbox(), rexxfbox(), rexxline(), rexxtofront(),
rexxtoback(), rexxexit(), rexxversion(), rexxspawn() ;
void disp() ;
/*
* Here is our command association list. Note that in this case,
* we are setting the userdata field to be a function to call.
* Dispatch will still take place through disp(), so common head
* and tail stuff can go there.
*
* Commands are all lower case, so we match either upper or lower.
* (This is a requirement of minrexx.)
*/
struct rexxCommandList rcl[] = {
{ "color", &rexxcolor },
{ "box", &rexxbox },
{ "fbox", &rexxfbox },
{ "line", &rexxline },
{ "tofront", &rexxtofront },
{ "toback", &rexxtoback },
{ "exit", &rexxexit },
{ "version", &rexxversion },
{ "spawn", &rexxspawn },
{ NULL, NULL } } ;
#endif
/*******************************************************************/
/* DrawBox - Simple routine to draw an unfilled rectangle */
/* It accepts the coordinates of the top-left and lower-right */
/* points of the rectangle, a pointer to the Window structure, */
/* and the color in which to render the rectangle. The current */
/* FgPen color of the window is preserved thru the call. No */
/* clipping is done. */
/*******************************************************************/
void DrawBox( tlx, tly, brx, bry, window, color )
SHORT tlx, tly; /* top-left x,y coordinates */
SHORT brx, bry; /* lower-right x,y coordinates */
struct Window *window; /* pointer to target window */
BYTE color; /* color to use for render */
{
BYTE OldColor = window->RPort->FgPen; /* save window's FgPen */
SetAPen( window->RPort, (long)color ); /* set draw color for box */
Move(window->RPort, (long)tlx, (long)tly); /* move to top-left point */
Draw(window->RPort, (long)brx, (long)tly); /* and draw to each of the */
Draw(window->RPort, (long)brx, (long)bry); /* four corners of the box */
Draw(window->RPort, (long)tlx, (long)bry);
Draw(window->RPort, (long)tlx, (long)tly);
SetAPen( window->RPort, (long)OldColor ); /* restore old FgPen */
}
/*********************************************************/
/* Color Select Menu */
/* */
/* This is where the menu for color selection is */
/* defined. It should be flexible enough to allow for */
/* increased palette sizes, but this version is only */
/* for the 4-color mode of the WorkBench screen. */
/*********************************************************/
/* A few definitions are needed here.
* Note that MAXPAL should be increased
* to allow for palette larger than
* four colors.
*/
#define ITEMSTUFF (ITEMENABLED | HIGHBOX)
#define CW 40
#define CH 25
#define MAXPAL 4
/* declare enough storage for required
* number of menu items and associated
* images. This menu will be using
* graphics renditions of menu items,
* so the Image structures must be
* declared. This menu is modeled after
* the one found in the IconEd source.
*/
struct MenuItem coloritem[MAXPAL];
struct Image colorimage[MAXPAL];
/* array of palette sizes to correspond with
* depth of window in bit-planes
*/
SHORT palette[] = { 2, 4, 8, 16, 32 };
/*****************************************************************/
/* The following function initializes the structure arrays */
/* needed to provide the Color menu topic. */
/*****************************************************************/
InitColorItems( depth )
SHORT depth; /* number of bit-planes in window */
{
SHORT n, colors;
colors = palette[depth-1];
for( n=0; n<colors; n++ ) /* loop for max number of items */
{
coloritem[n].NextItem = &coloritem[n+1];
coloritem[n].ItemFill = (APTR)&colorimage[n];
/* the next two items might be changed for
* when bit-planes is greater than 2
*/
coloritem[n].LeftEdge = 2 + CW * (n % 4);
coloritem[n].TopEdge = CH * (n / 4);
coloritem[n].Width = CW;
coloritem[n].Height = CH;
coloritem[n].Flags = ITEMSTUFF;
coloritem[n].MutualExclude = 0;
coloritem[n].SelectFill = NULL;
coloritem[n].Command = 0;
coloritem[n].SubItem = NULL;
coloritem[n].NextSelect = 0;
colorimage[n].LeftEdge = 1;
colorimage[n].TopEdge = 1;
colorimage[n].Width = CW-2;
colorimage[n].Height = CH-2;
colorimage[n].Depth = depth;
colorimage[n].ImageData = NULL;
colorimage[n].PlanePick = 0;
colorimage[n].PlaneOnOff = n;
}
coloritem[colors-1].NextItem = NULL; /* needed for last item in list */
return( 0 );
}
/*****************************************************/
/* Draw Mode Menu */
/* */
/* Here are the code and data declarations for */
/* the DrawMode menu. Current choices are limited */
/* to Erase, Filled Box, Hollow Box, and PenDraw. */
/*****************************************************/
/* define maximum number of menu items */
#define DMODEMAX 4
/* declare storage space for menu items and
* their associated IntuiText structures
*/
struct MenuItem DModeItem[DMODEMAX];
struct IntuiText DModeText[DMODEMAX];
/*****************************************************************/
/* The following function initializes the structure arrays */
/* needed to provide the DrawMode menu topic. */
/*****************************************************************/
InitDModeItems()
{
short n;
/* initialize each meu item and IntuiText with loop */
for( n=0; n<DMODEMAX; n++ )
{
DModeItem[n].NextItem = &DModeItem[n+1];
DModeItem[n].LeftEdge = 0;
DModeItem[n].TopEdge = 10 * n;
DModeItem[n].Width = 112;
DModeItem[n].Height = 10;
DModeItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX;
DModeItem[n].MutualExclude = 0;
DModeItem[n].ItemFill = (APTR)&DModeText[n];
DModeItem[n].SelectFill = NULL;
DModeItem[n].Command = 0;
DModeItem[n].SubItem = NULL;
DModeItem[n].NextSelect = 0;
DModeText[n].FrontPen = 0;
DModeText[n].BackPen = 1;
DModeText[n].DrawMode = JAM2; /* render in fore and background */
DModeText[n].LeftEdge = 0;
DModeText[n].TopEdge = 1;
DModeText[n].ITextFont = NULL;
DModeText[n].NextText = NULL;
}
DModeItem[DMODEMAX-1].NextItem = NULL;
/* initialize text for specific menu items */
DModeText[0].IText = (UBYTE *)"Erase All";
DModeText[1].IText = (UBYTE *)"Hollow Box";
DModeText[2].IText = (UBYTE *)"Filled Box";
DModeText[3].IText = (UBYTE *)"Pen Draw";
return( 0 );
}
/***************************************************/
/* Menu Definition */
/* */
/* This section of code is where the simple */
/* menu definition goes. For now it supports */
/* only Color and Drawmode selection, but new */
/* choices can easily be added by creating */
/* structures and initializations functions */
/* similar to those provided above. */
/***************************************************/
/* current number of available menu topics */
#define MAXMENU 2
/* declaration of menu structure array for
* number of current topics. Intuition
* will use the address of this array to
* set and clear the menus associated with
* the window.
*/
struct Menu menu[MAXMENU];
/**********************************************************************/
/* The following function initializes the Menu structure array with */
/* appropriate values for our simple menu strip. Review the manual */
/* if you need to know what each value means. */
/**********************************************************************/
InitMenu()
{
menu[0].NextMenu = &menu[1];
menu[0].LeftEdge = 10;
menu[0].TopEdge = 0;
menu[0].Width = 50;
menu[0].Height = 10;
menu[0].Flags = MENUENABLED;
menu[0].MenuName = "Color"; /* text for menu-bar display */
menu[0].FirstItem = &coloritem[0]; /* pointer to first item in list */
menu[1].NextMenu = NULL;
menu[1].LeftEdge = 65;
menu[1].TopEdge = 0;
menu[1].Width = 85;
menu[1].Height = 10;
menu[1].Flags = MENUENABLED;
menu[1].MenuName = "DrawMode"; /* text for menu-bar display */
menu[1].FirstItem = &DModeItem[0]; /* pointer to first item in list */
return( 0 );
}
/******************************************************/
/* Main Program */
/* */
/* This is the main body of the program. */
/******************************************************/
struct Window *Window; /* ptr to applications window */
SHORT MinX, MinY, MaxX, MaxY; /* clipping boundary variables */
SHORT KeepGoing = TRUE; /* main loop control value */
main(argc, argv)
int argc ;
char *argv[] ;
{
struct Library *OpenLibrary() ;
struct Window *OpenWindow() ;
struct Message *GetMsg() ;
struct IntuiMessage *NewMessage; /* msg structure for GetMsg() */
BYTE DrawColor = 1; /* initial drawing color */
SHORT OldBRX = 30, OldBRY = 30; /* point coords used for boxes */
SHORT TLX = 20, TLY = 20; /* initial top-left point coords */
ULONG class; /* used in message monitor loop */
USHORT code; /* used in message monitor loop */
SHORT x, y, x1, y1, x2, y2; /* various coordinate variables */
USHORT MenuNum, ItemNum;
/* The following is a set of declarations
* for a number of flag values used by the
* program. These would perhaps be better
* coded as a bit-field for all the flags,
* but I'm lazy, and this is easier.
*/
SHORT MouseMoved = FALSE; /* indicates new mouse position ready */
SHORT ClipIt = FALSE; /* are new point coords out of bounds? */
SHORT ClippedLast = FALSE; /* was last PenDraw operation clipped? */
SHORT PenMode = FALSE; /* indicates PenDraw mode is set */
SHORT PenDown = FALSE; /* if mouse moved, then should it draw? */
SHORT RubberBox = FALSE; /* are we currently rubberbanding a box? */
SHORT FilledBox = FALSE; /* should boxes be filled when drawn? */
#ifdef TALKTOREXX
/*
* If we are talking to REXX, we need these two additional locals.
*/
long rexxbit ;
char firstcommand[256] ;
#endif
/* attempt to Open Library to access Intuition */
IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library", INTUITION_REV);
if( IntuitionBase == NULL )
exit(FALSE);
/* attempt to OpenLibrary to access Graphics functions */
GfxBase = (struct GfxBase *)
OpenLibrary("graphics.library",GRAPHICS_REV);
if( GfxBase == NULL )
exit(FALSE);
/* Try to open new window for application */
if(( Window = OpenWindow(&NewWindow) ) == NULL)
exit(FALSE);
/* set initial clipping boundaries
* from the values found in the window
* structure for border dimensions
*/
MinX = Window->BorderLeft;
MinY = Window->BorderTop;
MaxX = Window->Width - Window->BorderRight - 1;
MaxY = Window->Height - Window->BorderBottom - 1;
InitColorItems( 2 ); /* initialize Color menu arrays */
InitDModeItems(); /* initialize DrawMode menu arrays */
InitMenu(); /* initialize the menu structures */
/* Now, having initialized the various arrays
* of structures required for menu generation
* we can tell Intuition to make our menus
* available to the user when this window
* is active.
*/
SetMenuStrip( Window, &menu[0] );
/* set initial drw mode and color */
SetDrMd( Window->RPort, JAM1 );
SetAPen( Window->RPort, DrawColor );
#ifdef TALKTOREXX
/*
* For rexx, we open up a Rexx port, and send out the first command,
* if there was one. We send it out asynchronously; no reason not to.
*/
rexxbit = upRexxPort("freedraw", rcl, "fd", &disp) ;
firstcommand[0] = 0 ;
for (x=1; x<argc; x++) {
strcat(firstcommand, argv[x]) ;
strcat(firstcommand, " ") ;
}
if (firstcommand[0]) {
asyncRexxCmd(firstcommand) ;
}
#endif
/* Everything the program needs is now
* initialized and put in place. The
* program enters the following loop
* and processes message continuously as
* they are received from Intuition.
* I guess this loop is the real workhorse
* of the program. By the way, the loop
* control variable KeepGoing remains TRUE
* until a CLOSEWINDOW message is received.
* At that point it goes FALSE, and the
* program cleans up and exits.
*/
while( KeepGoing )
{
/* stay here until a message is received from Intuition */
#ifdef TALKTOREXX
/*
* If we're working with Rexx, we wait on the Rexx bit as well.
* Then, we handle any Rexx messages.
*/
Wait( (1L << Window->UserPort->mp_SigBit) | rexxbit);
dispRexxPort() ;
#else
Wait( 1L << Window->UserPort->mp_SigBit);
#endif
MouseMoved = FALSE; /* clear this flag each time thru loop */
/* since more than one message may be waiting
* a reply at this point, a loop is used to
* process all that have come in until no more
* are ready. Msg received is assigned to
* NewMessage from the GetMsg() function. This
* value will be NULL if no message is ready,
* and control passes out of the loop at that time
*/
while( NewMessage=(struct IntuiMessage *)GetMsg(Window->UserPort) )
{
/* copy some values from the message structure
* to variables used in the switch statements
* below
*/
class = NewMessage->Class;
code = NewMessage->Code;
x = Window->MouseX;
y = Window->MouseY;
/* SIZEVERIFY is a very high priority message
* in our loop and requires some immediate
* servicing. Any outstanding draw operations
* are immediately cancelled, and the DrawMode
* is nulled. This prevents any attempts to
* render outside whatever new Window boundaries
* the user chooses.
*
* (not anymore, it don't. -tgr)
if( class == SIZEVERIFY )
{
PenDown = FALSE;
if( RubberBox )
{
DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
RubberBox = FALSE;
}
}
*/
/* we have all the information needed from
* the message, so we can now safely reply
* to it without losing data
*/
ReplyMsg( (struct Message *)NewMessage );
/* Examine point coords from message received
* and set the clipping flag if out of bounds.
* If user was drawing in PenMode when message
* was received, then the ClippedLast flag
* should also be set to indicate this to the
* next draw operation.
*/
if(ClipIt = ( x < MinX || x > MaxX || y < MinY || y > MaxY ))
if( PenDown )
ClippedLast = TRUE;
/* enter switch on type of message received */
switch( class )
{
case MOUSEMOVE:
/* Don't really do anything with this one
* until any other, more important, messages
* are received and processed.
*/
MouseMoved = TRUE;
break;
case NEWSIZE:
/* set new clipping boundaries */
MinX = Window->BorderLeft;
MinY = Window->BorderTop;
MaxX = Window->Width - Window->BorderRight - 1;
MaxY = Window->Height - Window->BorderBottom - 1;
break;
case CLOSEWINDOW:
/* User is ready to quit, so indicate
* that execution should terminate
* with next iteration of the loop.
*/
KeepGoing = FALSE;
break;
case MOUSEBUTTONS:
/* A number of things could have happened
* here, and further examination of data
* received from message is needed to
* determine what action should be taken.
* The code variable holds important info
* about what actually caused the message
* to be sent in the first place.
*/
switch ( code )
{
case SELECTUP:
/* User was holding down the left button
* and just released it. The PenMode
* flag variables are set accordingly.
* The pen can no longer be down, and
* ClippedLast is reset for next time.
*/
PenDown = ClippedLast = FALSE;
break;
case SELECTDOWN:
/* User has pressed the left button, and
* several differnt actions may need to
* be taken. If the ClipIt value is TRUE,
* then no action should be taken at all.
*/
if( ClipIt )
break;
/* If user is currently in PenMode, then
* set up to draw when MOUSEMOVED messages
* are received until a subsequent SELECTUP
* message comes in.
*/
if( PenMode )
{
PenDown = TRUE;
ClippedLast = FALSE;
/* make sure to set appropriate mode */
SetDrMd( Window->RPort, JAM1 );
/* and establish initial position to draw */
Move( Window->RPort, (long)x, (long)y );
break;
}
/* If user is currently rubberbanding a box,
* then a SELECTDOWN message means it is time
* to stop rubberbanding and actually draw it.
* The following code will be executed if
* this is the case, and it will determine if
* a filled box is needed before rendering.
*/
if( RubberBox )
{
/* set draw mode back to JAM1 since
* it is now currently set to COMPLEMENT
*/
SetDrMd( Window->RPort, JAM1 );
RubberBox = FALSE; /* turn off rubberbanding */
/* Restore the condition of the RMBTRAP
* bit in the Window structure's Flags
* member. Menubutton events will no
* be received by this loop.
*/
Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
/* RectFill is not condusive to the smooth
* execution of programs iit arguments are
* out of order, sot his code sorts them
* in preparation for the call.
*/
if( FilledBox )
{
/* first sort the x-coords */
if( TLX < OldBRX ) {
x1 = TLX; x2 = OldBRX; }
else {
x1 = OldBRX; x2 = TLX; }
/* then sort the y-coords */
if( TLY < OldBRY ) {
y1 = TLY; y2 = OldBRY; }
else {
y1 = OldBRY; y2 = TLY; }
/* now generate the filled rectangle */
RectFill( Window->RPort, (long)x1, (long)y1,
(long)x2, (long)y2 );
}
else
{
/* FilledBox not set, so draw hollow box */
DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
}
break;
}
/* If execution comes here, then PenMode was
* not set and user was not rubberbanding.
* SELECTDOWN therefore indicates to start the
* rubberbanding process at this point. The
* initial coords are set to the values we
* received when the GetMsg() was executed.
*/
TLX = OldBRX = x; TLY = OldBRY = y;
/* set to render in XOR mode */
SetDrMd( Window->RPort, COMPLEMENT );
/* set flag to indicate we are now rubberbanding */
RubberBox = TRUE;
/* This instruction indicates to Intuition
* that we now wish to receive a message
* each time the Menubutton is pressed.
* This is how we hijack the right button
* for temporary use as a Cancel button
* instead of a Menubutton.
*/
Window->Flags |= RMBTRAP;
/* render the initial rubberbox and exit */
DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
break;
case MENUDOWN:
/* WE only receive this message class if
* the RMBTRAP flag bit has been set, so
* it always means that we should cancel
* the box which is currently rubberbanding.
*/
/* turn the flag off */
RubberBox = FALSE;
/* restore control of menubutton to Intuition */
Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
/* erase (by double XOR'ing) the current
* rubberbox and exit switch.
*/
DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
break;
default:
/* Something unimportant happened, so just
* continue thru the GetMsg() loop.
*/
continue;
}
break;
case MENUPICK:
/* A menu event has taken place and is
* ready to be processed. Examine the
* code variable received from the message
* to determine what action should be taken.
* The first check is for MENUNULL, which
* means that nothing should be done at all.
*/
if( code != MENUNULL )
{
/* get menu and item numbers from code */
MenuNum = MENUNUM( code );
ItemNum = ITEMNUM( code );
/* determine appropriate action by menu number */
switch ( MenuNum )
{
case 0:
/* Menu 0 is the Color menu. The
* item number indicates which new
* color to set.
*/
DrawColor = ItemNum;
SetAPen( Window->RPort, (long)DrawColor );
break;
case 1:
/* Menu 1 is the DrawMode menu. The item
* number indicates what to do.
* NOTE: Since we cannot have received
* this message if we were rubberbanding,
* then there is no need to clean up before
* changing drawing modes.
*/
switch ( ItemNum )
{
case 0:
/* Erase window to current color */
SetDrMd( Window->RPort, JAM1 );
RectFill( Window->RPort, (long)MinX, (long)MinY,
(long)MaxX, (long)MaxY);
break;
case 1:
/* set flag variables for hollow box */
PenMode = FALSE;
FilledBox = FALSE;
break;
case 2:
/* set flag variables for filled box */
PenMode = FALSE;
FilledBox = TRUE;
break;
case 3:
/* set flag variables for PenMode */
PenMode = TRUE;
break;
default:
/* don't do anything */
break;
}
break;
default:
/* Menu number unrecognized, do nothing */
break;
}
}
break;
case INACTIVEWINDOW:
/* User has de-selected our window, so a
* little bit of cleaning up may be needed
* to prevent untoward events when he comes
* back to it.
*/
/* erase any outstanding rubberbox */
if( RubberBox )
DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
/* reset all the flafg variables */
PenDown = ClippedLast = RubberBox = FALSE;
/* return possibly diverted menubutton events to Big I */
Window->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
break;
default:
/* message class was unrecognized, so do nothing */
break;
}
} /* this brace ends the while(NewMessage) loop way back when */
/* There are no more messages waiting at the
* IDCMP port, so we can now proceed to
* process any MOUSEMOVED message we may
* have received.
*/
if( MouseMoved && !ClipIt)
{
/* the mouse did move, and we don't need to clip */
/* check first if we are drawing in PenMode */
if( PenDown )
{
/* We have to examine if we clipped the
* last PenMode draw operation. If we did,
* then this is the first move back into
* window boundaries, so we mov instead of
* drawing.
*/
if( ClippedLast )
{
ClippedLast = FALSE; /* reset this flag now */
Move( Window->RPort, (long)x, (long)y );
}
else
Draw( Window->RPort, (long)x, (long)y ); /* draw to x,y coords */
}
else
{
/* We weren't in PenMode, but we still might
* be rubberbanding a box. If so, then we
* should erase the current rubberbox and
* draw a new one with the new mouse coords.
*/
if( RubberBox )
{
/* erase the old rubberbox - draw mode is COMPLEMENT */
DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
/* assign new values to box coords */
OldBRX = x; OldBRY = y;
/* and draw the new rubberbox */
DrawBox( TLX, TLY, OldBRX, OldBRY, Window, DrawColor );
}
}
}
}
/* It must be time to quit, so we have to clean
* up and exit.
*/
#ifdef TALKTOREXX
/*
* With Rexx, we need to bring the port down. You might make this
* part of exit() for programs that have multiple paths to exit.
*/
dnRexxPort() ;
#endif
ClearMenuStrip( Window );
CloseWindow( Window );
exit(TRUE);
}
#ifdef TALKTOREXX
/*
* Now we get into the actual code necessary for our REXX port; functions
* that do the real work. Note that this program was not structured
* particularly nicely for Rexx; I had to write each of these functions.
* Many programs have these subroutines already in place; they are called
* as part of the event loop. This progam, however, just has one big
* switch statement with different actions . . .
*
* First, our locals.
*/
int currrexxcolor = 1 ; /* what color is *rexx* drawing in? */
int args[4] ; /* what args did we see to this function? */
int parsed ; /* was argument parsing successful? */
int userreplied ; /* has the current message been replied to yet? */
/*
* This function takes a pointer to a pointer to a string, grabs the
* next number, returns it, and advances the pointer to the string to
* point after the number.
*/
int getnm(where)
char **where ;
{
register char *p = *where ;
register int val = 0 ;
int gotone = 0 ;
while (*p <= ' ' && *p)
p++ ;
while ('0' <= *p && *p <= '9') {
gotone = 1 ;
val = 10 * val + *p++ - '0' ;
}
if (gotone == 0)
parsed = 0 ;
*where = p ;
return(val) ;
}
/*
* This function trys to find `n' numeric arguments in the command
* string, and stuffs them into the args array.
*/
void parseargs(p, n)
char *p ;
int n ;
{
register int i ;
while (*p > ' ' && *p)
p++ ;
for (i=0; i<n; i++)
args[i] = getnm(&p) ;
}
/*
* This is our main dispatch function. We check to make sure a Window
* currently exists. Then, we store away the `current color' and change
* it to Rexx's current color, call our handler function, and then restore
* the color. If our handler replied, we return a 1 to indicate that.
* If the parse and everything else was successful, we return a 0.
* Otherwise, we return a failure of 20 to indicate that the arguments
* were messed up.
*/
void disp(msg, dat, p)
register struct RexxMsg *msg ;
register struct rexxCommandList *dat ;
char *p ;
{
register int t ;
parsed = 1 ;
if (Window) {
userreplied = 0 ;
t = Window->RPort->FgPen ;
SetAPen(Window->RPort, (long)currrexxcolor) ;
((int (*)())(dat->userdata))(msg, p) ;
SetAPen(Window->RPort, (long)t) ;
if (! parsed)
replyRexxCmd(msg, (long)parsed, 0L, NULL) ;
return ;
}
replyRexxCmd(msg, 20L, 10L, NULL) ;
}
/*
* This handler sets the current rexx color.
*/
void rexxcolor(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 1) ;
currrexxcolor = args[0] ;
}
/*
* This function silently clips the x and y values at `n' to the
* window bounds.
*/
void clipxy(n)
int n ;
{
if (args[n] < MinX)
args[n] = MinX ;
if (args[n] > MaxX)
args[n] = MaxX ;
n++ ;
if (args[n] < MinY)
args[n] = MinY ;
if (args[n] > MaxY)
args[n] = MaxY ;
}
/*
* This handler grabs four arguments and draws a box.
*/
void rexxbox(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 4) ;
clipxy(0) ;
clipxy(2) ;
DrawBox(args[0], args[1], args[2], args[3], Window, currrexxcolor) ;
}
/*
* This handler grabs four arguments and draws a filled box.
*/
void rexxfbox(msg, p)
struct RexxMsg *msg ;
char *p ;
{
register int t ;
parseargs(p, 4) ;
clipxy(0) ;
clipxy(2) ;
if (args[0] > args[2]) {
t = args[0] ; args[0] = args[2] ; args[2] = t ;
}
if (args[1] > args[3]) {
t = args[1] ; args[1] = args[3] ; args[3] = t ;
}
RectFill( Window->RPort, (long)args[0], (long)args[1],
(long)args[2], (long)args[3]) ;
}
/*
* This handler grabs four arguments and draws a line.
*/
void rexxline(msg, p)
struct RexxMsg *msg ;
char *p ;
{
parseargs(p, 4) ;
clipxy(0) ;
clipxy(2) ;
Move(Window->RPort, (long)args[0], (long)args[1]) ;
Draw(Window->RPort, (long)args[2], (long)args[3]) ;
}
/*
* This handler pops the window to front.
*/
void rexxtofront(msg, p)
struct RexxMsg *msg ;
char *p ;
{
WindowToFront(Window) ;
}
/*
* This handler pops the window to back.
*/
void rexxtoback(msg, p)
struct RexxMsg *msg ;
char *p ;
{
WindowToBack(Window) ;
}
/*
* This handler sets the exit flag.
*/
void rexxexit(msg, p)
struct RexxMsg *msg ;
char *p ;
{
KeepGoing = 0 ;
}
/*
* This handler returns the version of the program.
*/
void rexxversion(msg, p)
struct RexxMsg *msg ;
char *p ;
{
userreplied = 1 ;
replyRexxCmd(msg, 0L, 0L, VERSION) ;
}
/*
* This handler sends the rest of the command asynchronously,
* allowing us to run macros in parallel.
*/
void rexxspawn(msg, p)
struct RexxMsg *msg ;
char *p ;
{
while (*p <= ' ' && *p)
p++ ;
asyncRexxCmd(p) ;
}
#endif