home *** CD-ROM | disk | FTP | other *** search
- #define TALKTOREXX 1
- #ifdef TALKTOREXX
- /*
- This program is an example of how to add a Rexx implementation to any
- program using the rexxapp.library. The original Freedraw program (without
- REXX) is from Fred Fish Disk 1. The rexxapp.library is based upon a C module
- by Radical Eye Software which was modified and down-coded to a 68000 shared
- library.
- All the REXX stuff is bracketed by "idef 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 increases the
- executable slightly, 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 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. The basic idea of
- this program is to provide some minimal image editing functions which can be
- used to develop images for other programs.
- 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.
-
- Rick Ross 11/14/85
-
- *********************************************************************** */
- char *VERSION = "Freedraw 0.01 by Richard M. Ross";
-
- #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 for calls to OpenLibrary() in order to ensure
- that an appropriate ROM version is available.
- */
-
- #define INTUITION_REV 1L
- #define GRAPHICS_REV 1L
- struct IntuitionBase *IntuitionBase;
- struct GfxBase *GfxBase;
-
- struct Window *myWindow = 0; /* ptr to applications window */
-
- /*
- This is the Window structure declaration.
- Nothing fancy is going on here, but note
- that 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 here 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 this rexx include file only if we access the RexxMsg or RxsLib */
- /*#include <rexx/rxslib.h>*/
-
- /* Where we store the rexxapp.library base */
- struct RexxBase *RexxBase = 0;
-
- /* We'll ship off unknown commands as macros to Rexx, and here's the extension */
- char myExtension[] = "fd";
-
- /* These are the rexxapp lib functions. */
- extern long SetRexxPort();
- extern void FreeRexxPort();
- extern void ReceiveRexx();
- extern struct RexxMsg *SendRexxCmd();
- extern struct RexxMsg *SyncRexxCmd();
- extern struct RexxMsg *ASyncRexxCmd();
- extern void SetupResults();
- extern char *RexxErrMsg; /* This comes from RexxInterface.asm */
-
- /* These are the REXX handlers defined at the bottom of the file */
- void rexxcolor(), rexxbox(), rexxfbox(), rexxline(), rexxtofront(),
- rexxtoback(), rexxexit(), rexxversion(), rexxspawn();
- /* This is the Func (Dispatch) function for received Rexxmsgs */
- BOOL disp();
- /* This is the Error function for the return of Rexxmsgs we send out, and caused an error */
- void RexxError();
- /* This is the Result function for the return of Rexxmsgs we send out, and were handled successfully */
- void RexxResult();
-
- struct CmdEntry {
- char *CmdString;
- APTR CmdHandler;
- };
-
- #define NUMCMDS 10 /* This will be application dependent */
-
- struct RexxData {
- struct MsgPort RexxPort;
- char *Exten;
- APTR Func;
- struct RxsLib *RexxLib; /* defined by the ARexx rxslib.h file */
- APTR Error;
- APTR Result;
- ULONG RexxMask;
- ULONG UserData; /* to be defined by and used by the application */
- /* The command list goes here. It consists of one CmdEntry structure for
- each "command" that the application supports. Note that the number of
- commands (and therefore the size of the RexxData) will depend upon how
- many "commands" the application supports. The list must end with a NULL
- entry.
- */
- struct CmdEntry AsscList[NUMCMDS];
- };
-
- /*
- Here is our initialized RexxData structure (for rexxapp lib)
- */
- struct RexxData myRexxData = {
- {0},
- myExtension,
- (APTR) disp,
- 0,
- (APTR) RexxError,
- (APTR) RexxResult,
- 0,
- 0,
- /*
- Here is our imbedded command association list.
- Commands are all lower case, so we match either upper or lower.
- (This is a requirement of rexxapp.library.)
- */
- { { "color", (APTR)rexxcolor },
- { "box", (APTR)rexxbox },
- { "fbox", (APTR)rexxfbox },
- { "line", (APTR)rexxline },
- { "tofront", (APTR)rexxtofront },
- { "toback", (APTR)rexxtoback },
- { "exit", (APTR)rexxexit },
- { "version", (APTR)rexxversion },
- { "spawn", (APTR)rexxspawn },
- { 0, 0 } }
- };
-
- /* Note that the buffer for the PortName must be 2 bytes more than the name itself.
- THIS IS REQUIRED so that the lib can construct a new name if this one is in use.
- Note that is we run two copies of freedraw simultaneously, the first one's port
- will be "freedraw", and the second one will be "freedraw2".
- */
- char PortName[10] = "freedraw";
-
- #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 );
- }
-
- /**********************************************************************/
- /* The following function is our exit point for the program. It */
- /* closes/frees any allocated resources. */
- /**********************************************************************/
- doclean()
- {
- if (myWindow) CloseWindow( myWindow );
- if (IntuitionBase) CloseLibrary(IntuitionBase);
- if (GfxBase) CloseLibrary(GfxBase);
- #ifdef TALKTOREXX
- if (RexxBase) CloseLibrary(RexxBase);
- #endif
- exit(TRUE);
- }
-
- /******************************************************/
- /* Main Program */
- /* */
- /* This is the main body of the program. */
- /******************************************************/
-
- 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 3 additional locals */
- ULONG rexxbit;
- char firstcommand[256];
- struct RexxMsg *rxmsg;
- #endif
-
- /* attempt to Open Library to access Intuition */
- IntuitionBase = (struct IntuitionBase *)
- OpenLibrary("intuition.library", INTUITION_REV);
- if( IntuitionBase == NULL )
- doclean();
-
- /* attempt to OpenLibrary to access Graphics functions */
- GfxBase = (struct GfxBase *)
- OpenLibrary("graphics.library",GRAPHICS_REV);
- if( GfxBase == NULL )
- doclean();
-
- /* Try to open new window for application */
- if(( myWindow = OpenWindow(&NewWindow) ) == NULL) doclean();
-
- #ifdef TALKTOREXX
- /* Open the rexxapp.library */
- if (!(RexxBase = (struct RexxBase *) OpenLibrary("rexxapp.library",0L)))
- {
- puts("Need the rexxapp.library");
- doclean();
- }
- #endif
-
- /* set initial clipping boundaries
- * from the values found in the window
- * structure for border dimensions
- */
- MinX = myWindow->BorderLeft;
- MinY = myWindow->BorderTop;
- MaxX = myWindow->Width - myWindow->BorderRight - 1;
- MaxY = myWindow->Height - myWindow->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( myWindow, &menu[0] );
-
- /* set initial drw mode and color */
- SetDrMd( myWindow->RPort, JAM1 );
- SetAPen( myWindow->RPort, DrawColor );
-
- #ifdef TALKTOREXX
- /* For rexx, we must open up a Rexx port. */
- if (! (rexxbit = SetRexxPort(PortName, &myRexxData)))
- {
- puts("can't set up RexxPort");
- doclean();
- }
-
- /* Show the portname in the window titlebar */
- SetWindowTitles(myWindow, PortName, 0L);
-
- /*
- For FreeDraw, we're going to send out the user's args on the CLI as a Rexx
- macro invocation, if there was one. We send it out asynchronously; no reason
- not to. This is an example of how your program might invoke a Rexx script.
- */
- firstcommand[0] = 0;
- for (x=1; x<argc; x++)
- {
- strcat(firstcommand, argv[x]);
- strcat(firstcommand, " ");
- }
- if (firstcommand[0])
- {
- /* Send it out. If an error, print out the returned error message */
- if (! (rxmsg = ASyncRexxCmd(firstcommand, &myRexxData)))
- SetWindowTitles(myWindow, RexxErrMsg, 0L);
- }
- #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 << myWindow->UserPort->mp_SigBit) | rexxbit);
- ReceiveRexx(&myRexxData);
- #else
- Wait( 1L << myWindow->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(myWindow->UserPort) )
- {
-
- /* copy some values from the message structure
- * to variables used in the switch statements
- * below
- */
- class = NewMessage->Class;
- code = NewMessage->Code;
- x = myWindow->MouseX;
- y = myWindow->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 myWindow boundaries
- * the user chooses.
- *
- * (not anymore, it don't. -tgr)
-
- if( class == SIZEVERIFY )
- {
- PenDown = FALSE;
- if( RubberBox )
- {
- DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor );
- myWindow->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( 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 = myWindow->BorderLeft;
- MinY = myWindow->BorderTop;
- MaxX = myWindow->Width - myWindow->BorderRight - 1;
- MaxY = myWindow->Height - myWindow->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( myWindow->RPort, JAM1 );
-
- /* and establish initial position to draw */
- Move( myWindow->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( myWindow->RPort, JAM1 );
- RubberBox = FALSE; /* turn off rubberbanding */
-
- /* Restore the condition of the RMBTRAP
- * bit in the myWindow structure's Flags
- * member. Menubutton events will no
- * be received by this loop.
- */
- myWindow->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( myWindow->RPort, (long)x1, (long)y1,
- (long)x2, (long)y2 );
- }
- else
- {
- /* FilledBox not set, so draw hollow box */
- DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, 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( myWindow->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.
- */
- myWindow->Flags |= RMBTRAP;
-
- /* render the initial rubberbox and exit */
- DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, 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 */
- myWindow->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
-
- /* erase (by double XOR'ing) the current
- * rubberbox and exit switch.
- */
- DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, 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( myWindow->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( myWindow->RPort, JAM1 );
- RectFill( myWindow->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, myWindow, DrawColor );
-
- /* reset all the flafg variables */
- PenDown = ClippedLast = RubberBox = FALSE;
-
- /* return possibly diverted menubutton events to Big I */
- myWindow->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( myWindow->RPort, (long)x, (long)y );
- }
- else
- Draw( myWindow->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, myWindow, DrawColor );
-
- /* assign new values to box coords */
- OldBRX = x; OldBRY = y;
-
- /* and draw the new rubberbox */
- DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, 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, but
- don't call it unless you called SetRexxPort() once anyway.
- */
- FreeRexxPort(&myRexxData);
- #endif
-
- ClearMenuStrip( myWindow );
- doclean();
- }
-
- #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 in main() with different actions . . .
-
- First, our locals.
- */
- ULONG currrexxcolor = 1; /* what color is *rexx* drawing in? */
- ULONG args[4]; /* what args did we see to this function? */
- ULONG error; /* was argument parsing successful? */
- char *ResultStr; /* the Result string to return if any */
-
- /* *********************************************************************
- * This function takes a pointer to a pointer to a string, grabs the
- * next number (unsigned), returns it, and advances the pointer to the
- * string to point after the number.
- ********************************************************************* */
- ULONG getnm(where)
- char **where;
- {
- register char *p = *where;
- register ULONG val = 0;
- register ULONG gotone = 0;
-
- while (*p <= ' ' && *p)
- p++;
- while ('0' <= *p && *p <= '9')
- {
- gotone = 1;
- val = 10 * val + *p++ - '0';
- }
- if (gotone == 0) error = 20; /* Indicate an error level of 20 with rexx arguments */
- *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;
- UBYTE n;
- {
- register UBYTE i;
-
- while (*p > ' ' && *p)
- p++;
- for (i=0; i<n; i++)
- args[i] = getnm(&p);
- }
-
- /* *************************************************************************
- * This is our rexx Func (Dispatch) routine. The rexxapp.library calls this
- * when some other program sends us a Rexxmsg that has one of the commands
- * in our command association list. 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 no errors, error will be 0. If our handler has any return
- * Result string, that is placed in ResultStr. We setup the Results codes
- * via SetupResults() and return(TRUE) because we always want the lib to
- * reply. If the parse and everything else was successful, we set Results as
- * 0. Otherwise, we set Results to the value of error to indicate that
- * something failed.
- ************************************************************************* */
- BOOL disp( msg, routine, p, rxdata ) /* NOTE: Don't use register class because */
- struct RexxMsg *msg; /* Manx doesn't know where you put things (no pragma) */
- void (*routine)();
- char *p;
- struct RexxData *rxdata;
- {
- register UBYTE t;
-
- /* Initially, no error or Result string to return */
- error = 0;
- ResultStr = 0;
-
- if (myWindow)
- {
- /* Get the current pen color in case this rexx handler alters it */
- t = myWindow->RPort->FgPen;
- SetAPen(myWindow->RPort, (LONG)currrexxcolor);
-
- /* Call the appropriate handler. The lib has determined which one */
- (*routine)(msg, p, rxdata);
-
- /* restore the color */
- SetAPen(myWindow->RPort, (LONG)t);
-
- /* Check for any errors */
- if (! error)
- {
- /* No errors. Send back Result1 and Result2 = 0. Also return any
- Result string
- */
- SetupResults(0L, 0L, ResultStr, msg, rxdata);
- }
- else
- {
- /* An error! Return Result1 = error. Must not send back a Result string */
- SetupResults(error, 10L, NULL, msg, rxdata);
- }
- /* We want the lib to do the reply right now */
- return(TRUE);
- }
- SetupResults(error, 10L, msg, NULL, rxdata);
- return(TRUE);
- }
-
- /* **********************************************************************
- * This handler sets the current rexx color. (our 'color' handler)
- ********************************************************************** */
- void rexxcolor(msg, p, rxdata)
- struct RexxMsg *msg;
- char *p;
- struct RexxData *rxdata;
- {
- parseargs(p, 1);
- currrexxcolor = args[0];
- }
-
- /* *********************************************************************
- * This function silently clips the x and y values at `n' to the
- * window bounds.
- ********************************************************************* */
- void clipxy(n)
- UBYTE 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, rxdata)
- struct RexxMsg *msg;
- char *p;
- struct RexxData *rxdata;
- {
- parseargs(p, 4);
- clipxy(0);
- clipxy(2);
- DrawBox(args[0], args[1], args[2], args[3], myWindow, currrexxcolor);
- }
-
- /* *********************************************************************
- * This handler grabs four arguments and draws a filled box.
- ********************************************************************** */
- void rexxfbox(msg, p, rxdata)
- struct RexxMsg *msg;
- char *p;
- struct RexxData *rxdata;
- {
- register ULONG 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( myWindow->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, rxdata)
- struct RexxMsg *msg;
- char *p;
- struct RexxData *rxdata;
- {
- parseargs(p, 4);
- clipxy(0);
- clipxy(2);
- Move(myWindow->RPort, (long)args[0], (long)args[1]);
- Draw(myWindow->RPort, (long)args[2], (long)args[3]);
- }
-
- /* *************************************************************************
- * This handler pops the window to front.
- ************************************************************************* */
- void rexxtofront(msg, p, rxdata)
- struct RexxMsg *msg;
- char *p;
- struct RexxData *rxdata;
- {
- WindowToFront(myWindow);
- }
-
- /* *************************************************************************
- * This handler pops the window to back.
- ************************************************************************* */
- void rexxtoback(msg, p, rxdata)
- struct RexxMsg *msg;
- char *p;
- struct RexxData *rxdata;
- {
- WindowToBack(myWindow);
- }
-
- /* *************************************************************************
- * This handler sets the exit flag.
- ************************************************************************* */
- void rexxexit(msg, p, rxdata)
- struct RexxMsg *msg;
- char *p;
- struct RexxData *rxdata;
- {
- KeepGoing = FALSE;
- }
-
- /* *************************************************************************
- * This handler sets ResultStr to the version of the program.
- ************************************************************************* */
- void rexxversion(msg, p, rxdata)
- struct RexxMsg *msg;
- char *p;
- struct RexxData *rxdata;
- {
- ResultStr = VERSION;
- }
-
- /* ***********************************************************************
- * This handler sends the rest of the command asynchronously,
- * allowing us to run macros in parallel.
- *********************************************************************** */
- void rexxspawn(msg, p, rxdata)
- struct RexxMsg *msg;
- char *p;
- struct RexxData *rxdata;
- {
- register struct Rexxmsg *rxmsg;
-
- if (! (rxmsg = ASyncRexxCmd(p, rxdata)))
- SetWindowTitles(myWindow, RexxErrMsg, 0L);
- }
-
- /* ***********************************************************************
- * This function is for when a RexxMsg we send out returns with an error.
- *********************************************************************** */
- void RexxError(error, p, msg, rxdata)
- ULONG error;
- char *p;
- struct RexxMsg *msg;
- struct RexxData *rxdata;
- {
- SetWindowTitles(myWindow, p, 0L);
- }
-
- /* ***********************************************************************
- * This function is for when a RexxMsg we send out returns successfully.
- * Actually, we have nothing to do. We have no function that sends out a
- * RexxMsg and expects a returned Result string or Result1 code. We'll just
- * print out any result string.
- *********************************************************************** */
- void RexxResult(error, p, msg, rxdata)
- ULONG error;
- char *p;
- struct RexxMsg *msg;
- struct RexxData *rxdata;
- {
- if (p)
- {
- SetWindowTitles(myWindow, p, 0L);
- }
- }
-
- #endif
-