home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 20 / AACD20.BIN / AACD / Programming / AmiSlate-Source / AmiSource-c / tools.c < prev   
Encoding:
C/C++ Source or Header  |  1995-08-13  |  40.7 KB  |  1,474 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <intuition/intuition.h>
  4. #include <intuition/intuitionbase.h>
  5. #include <exec/types.h>
  6. #include <libraries/dos.h>            /* contains RETURN_OK, RETURN_WARN #def's */
  7. #include <clib/exec_protos.h>
  8. #include <clib/intuition_protos.h>
  9. #include <clib/graphics_protos.h>
  10. #include <clib/dos_protos.h>
  11. #include <string.h>
  12. #include <graphics/gfxbase.h>
  13.  
  14. #include "AmiSlate.h"
  15. #include "DrawRexx_aux.h"
  16. #include "drawrexx.h"
  17. #include "Remote.h"
  18. #include "DrawLang.h"
  19. #include "tools.h"
  20. #include "palette.h"
  21. #include "flood.h"
  22.  
  23. #define INTUI_V36_NAMES_ONLY
  24.  
  25. #define INVALID_POS    -1
  26. #define DELETE 127
  27. #define BACKSPACE 8
  28.  
  29. #define POLYBOXTOP    55
  30. #define POLYBOXLEFT    32
  31. #define POLYBOXWIDTH     4
  32. #define POLYBOXHEIGHT     4
  33.  
  34. extern struct Library *IntuitionBase = NULL;
  35. extern struct GfxBase *GraphicsBase  = NULL;
  36. extern struct Window *DrawWindow;
  37. extern struct BitMap ToolBoxBitMap, ToolBoxHBitMap;
  38. extern struct Screen *Scr;
  39. extern __chip UWORD waitPointer[];
  40. extern FILE *fpIn;
  41.  
  42. extern struct PaintInfo PState;
  43.  
  44. extern int Not[2] = {TRUE, FALSE};             /* NOT lookup array */
  45. extern int XPos, YPos;
  46. extern int nWinOldHeight, nWinOldWidth;
  47. extern BOOL BSafeFloods;
  48. extern BOOL BNetConnect;
  49. extern BOOL BIgnoreResizeEvent;
  50.  
  51. /* Private local variables */
  52. static int XBeginLine = -1, YBeginLine = -1, XEraseTo = -1, YEraseTo = -1;
  53. static int XCircleCenter = -1, YCircleCenter = -1, XCircleRadius = -1, YCircleRadius = -1;
  54. static int XBeginSquare = -1, YBeginSquare = -1, XEraseSquareTo = -1, YEraseSquareTo = -1;
  55. static int XBeginPoly = -1, YBeginPoly = -1, XLastPoly = -1, YLastPoly = -1, XErasePoly = -1, YErasePoly = -1;
  56. static int XPen = -1, YPen = -1;
  57. static BOOL BPenLastIn = FALSE;
  58.  
  59. /* Enable/disable drawing based on BCanDraw */
  60. void EnableDraw(BOOL BCanDraw)
  61. {
  62.     if (BCanDraw == FALSE)
  63.     {
  64.         if (PState.BPenDown == TRUE) 
  65.         {
  66.             BreakAction(PState.uwMode);
  67.             PState.BPenDown = FALSE;
  68.         }
  69.     }
  70.     else
  71.         {
  72.         /* Reset polygon tool */
  73.                 XLastPoly = -1; YLastPoly = -1;
  74.         XBeginPoly = -1;  YBeginPoly = -1;
  75.                 XErasePoly = -1; YErasePoly = -1;
  76.             
  77.         /* UnMark toolbox gadget to show we're out of the polygon "mode" */
  78.         if (PState.uwMode == MODE_POLY) 
  79.             SetAPen(DrawWindow->RPort, 3);
  80.             else
  81.             SetAPen(DrawWindow->RPort, 0);
  82.                 
  83.         Rectangle(nGetToolBoxLeft()+POLYBOXLEFT, nGetToolBoxTop()+POLYBOXTOP, nGetToolBoxLeft()+POLYBOXLEFT+POLYBOXWIDTH, nGetToolBoxTop()+POLYBOXTOP+POLYBOXHEIGHT, TRUE);
  84.     }                                    
  85.     PState.BDrawEnabled = BCanDraw;
  86.     return;
  87. }
  88.  
  89. int nGetDrawWindowBottom(void)
  90. {
  91.     return(DrawWindow->Height - DrawWindow->BorderBottom - 26);
  92. }
  93.  
  94. /* Fixes Co-ordinates so that 0,0 is actually the left top corner of the
  95.    drawing area instead of the left top corner of the window */
  96. void FixCoords(int *X, int *Y)
  97. {
  98.     *X += DrawWindow->BorderLeft+1;
  99.     *Y += DrawWindow->BorderTop+1;
  100. }
  101.  
  102. /* Undoes FixCoords */
  103. void UnFixCoords(int *X, int *Y)
  104. {
  105.     *X -= DrawWindow->BorderLeft+1;
  106.     *Y -= DrawWindow->BorderTop+1;
  107. }
  108.  
  109.  
  110.  
  111. BOOL FixPos(int *X, int *Y)
  112. {
  113.   int nReturnVal = TRUE;
  114.   
  115.   if (*X <= DrawWindow->BorderLeft)
  116.   {
  117.      *X = DrawWindow->BorderLeft + 1;
  118.      nReturnVal = FALSE;
  119.   }
  120.   if (*Y <= DrawWindow->BorderTop)    
  121.   {
  122.         *Y = DrawWindow->BorderTop + 1;
  123.         nReturnVal = FALSE;
  124.   }
  125.                                
  126.   if (*X >= (DrawWindow->Width-DrawWindow->BorderRight-PState.nToolBoxWidth-2))   
  127.   {
  128.      *X = DrawWindow->Width-DrawWindow->BorderRight-PState.nToolBoxWidth - 3;
  129.      nReturnVal = FALSE;
  130.   }
  131.   if (*Y >= (DrawWindow->Height - DrawWindow->BorderBottom-25))    
  132.   {
  133.      *Y = (DrawWindow->Height - DrawWindow->BorderBottom-26);
  134.      nReturnVal = FALSE;
  135.   }
  136.   return(nReturnVal);
  137. }
  138.  
  139.  
  140.  
  141. /* Attempts to resize the window.  Calls DrawResizedWindow to handle the
  142.    actual graphics redraw; this function is here mostly to handle synchronization
  143.    between two clients.  */
  144. BOOL ReSizeWindow(int nWidth, int nHeight, BOOL BCausedLocally)
  145. {
  146.     /* Only do this semaphore-stuff if we're connected, of course! */
  147.     if (BNetConnect == FALSE)
  148.     {
  149.         PState.uwWidth = nWidth;        /* 2 lines test code! */
  150.         PState.uwHeight = nHeight;
  151.         DrawResizedWindow(nWidth, nHeight, BCausedLocally);
  152.         return(TRUE);
  153.     }
  154.     
  155.     if (BCausedLocally == TRUE)
  156.     {
  157.         switch(PState.nSizeState)
  158.         {
  159.             /* Passive:  We're waiting for a remote resize.  Don't do anything now. */
  160.             case SIZEMODE_PASSIVE: 
  161.                 return(FALSE);    
  162.                 break;
  163.  
  164.             /* Normal:  Tell the other guy to prepare for a resize.  Don't do anything til he's ready */                    
  165.             case SIZEMODE_NORMAL:
  166.                 PState.nSizeState = SIZEMODE_ACTIVE;    /* We'll do our best! */
  167.                 /* Get the other guy's attention */
  168.                 OutputAction(FROM_IDCMP, COMMAND, COMMAND_SIZELOCK, NOP_PAD, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);    
  169.                 PState.uwWidth = nWidth;    /* test - record co-ordinates to use */
  170.                 PState.uwHeight = nHeight;
  171.                 return(TRUE);        /* Wait for the okay */
  172.             
  173.             /* We're already waiting for an okay, so don't do anything; it'll be overwritten any-hway! */
  174.             case SIZEMODE_ACTIVE:
  175.                 return(TRUE);    
  176.                 break;
  177.                 
  178.             default:
  179.                 Printf("ReSizeWindow:  Bad nSizeState (1)\n");
  180.                 break;
  181.         }
  182.     }
  183.     else
  184.     {
  185.         switch(PState.nSizeState)
  186.         {
  187.             /* This is what we were waiting for.  Resize to their specifications. */
  188.             case SIZEMODE_PASSIVE:
  189.                 PState.nSizeState = SIZEMODE_NORMAL;    /* we should be ok now */
  190.                 DrawResizedWindow(nWidth, nHeight, BCausedLocally);
  191.                 return(TRUE);
  192.                 break;
  193.             
  194.             /* We weren't warned!  This shouldn't ever happen.  Go with it, but give a warning message. */    
  195.             case SIZEMODE_NORMAL:
  196.                 SetWindowTitle("Warning--Unlocked resizing!!!!");
  197.                 DrawResizedWindow(nWidth, nHeight, BCausedLocally);
  198.                 return(TRUE);
  199.                 break;
  200.                 
  201.             /* In this case, we got pre-empted while waiting to send our size data.
  202.                The easiest way to deal with this is to knuckle under, and go with what
  203.                the other guy wants, forgetting our original resize.  */
  204.             case SIZEMODE_ACTIVE:
  205.                 PState.nSizeState = SIZEMODE_NORMAL;
  206.                 OutputAction(FROM_IDCMP, COMMAND, COMMAND_SIZEUNLOCK, NOP_PAD, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);    
  207.                 DrawResizedWindow(nWidth, nHeight, BCausedLocally);
  208.                 return(TRUE);
  209.                 break;
  210.                 
  211.             default:
  212.                 Printf("ReSizeWindow: Bad nSizeState (2)\n");
  213.                 break;
  214.         }
  215.     }
  216.     return(FALSE);
  217. }    
  218.     
  219.  
  220.  
  221.  
  222.  
  223.  
  224. BOOL DrawResizedWindow(int nWidth, int nHeight, BOOL BCausedLocally)
  225. {
  226.     int nCWidth= DrawWindow->Width, nCHeight= DrawWindow->Height;
  227.     static LONG lsizeX, lsizeY, lCode1FromWhom;
  228.     static const lType = REXX_REPLY_RESIZE;
  229.     static const char szResizeMessage[30];    
  230.  
  231.     if ((nCWidth != nWidth)||(nCHeight != nHeight))
  232.     {
  233.         BIgnoreResizeEvent = TRUE;    /* Keep us from responding to our own resize as if the user had done it */
  234.         ChangeWindowBox(DrawWindow, DrawWindow->LeftEdge, DrawWindow->TopEdge, nWidth, nHeight);
  235.         Delay(15);    /* This is apparently necessary to make the functions below redraw to the NEW values */
  236.     }
  237.     
  238.     EraseToolBox(nWinOldWidth,nWinOldHeight);
  239.     EraseChatLines(nWinOldWidth, nWinOldHeight);
  240.           nWinOldWidth = DrawWindow->Width;
  241.            nWinOldHeight = DrawWindow->Height;
  242.     DrawToolBox();
  243.     DrawChatLines();
  244.  
  245.     sprintf(szResizeMessage,"Resize: X=%i Y=%i",DrawWindow->Width, DrawWindow->Height);
  246.     SetWindowTitle(szResizeMessage);
  247.     
  248.            /* If Rexx was waiting on this, tell it that a resize happened */
  249.         if (PState.uwRexxWaitMask & REXX_REPLY_RESIZE)
  250.         {
  251.             lsizeX = DrawWindow->Width;
  252.              lsizeY = DrawWindow->Height;
  253.         
  254.         if (BCausedLocally == TRUE) lCode1FromWhom = 0L; else lCode1FromWhom = 1L;
  255.         
  256.         ((struct rxd_waitevent *) *(&RexxState.array))->res.code1= &lCode1FromWhom;
  257.            ((struct rxd_waitevent *) *(&RexxState.array))->res.type = &lType;
  258.            ((struct rxd_waitevent *) *(&RexxState.array))->res.x    = &lsizeX;
  259.            ((struct rxd_waitevent *) *(&RexxState.array))->res.y    = &lsizeY;
  260.     
  261.         SetStandardRexxReturns();
  262.         }
  263.     
  264.  
  265.      /* If we didn't resize to what we wanted to, simulate another resize on
  266.        back to adjust! */
  267.     if ((DrawWindow->Width != nWidth)||(DrawWindow->Height != nHeight))
  268.         ReSizeWindow(DrawWindow->Width, DrawWindow->Height, TRUE);
  269.  
  270.     return(TRUE);
  271. }
  272.  
  273.  
  274.  
  275.  
  276.  
  277. /* ---------------- FUNCTIONS FOR CHAT LINES ---------------- */
  278. void EraseChatLines(int nWidth, int nHeight)
  279. {
  280.     int nToolBoxLeft;
  281.     int nBottomOfWindow;
  282.     int nChatLineHeight = 10;
  283.     
  284.     if (nWidth < 0)
  285.    {
  286.        nWidth = PState.nDefaultWidth;
  287.        nHeight = PState.nDefaultHeight;
  288.    }
  289.    /* nToolBoxLeft, nBottomOfWindow are SPECIALLY CALCULATED here because
  290.       they are based on the PREVIOUS values of the window size... nWidth
  291.       and nHeight.  */
  292.    nToolBoxLeft = nWidth - DrawWindow->BorderRight - PState.nToolBoxWidth + 1;  
  293.     nBottomOfWindow = nHeight - DrawWindow->BorderBottom - 1;
  294.  
  295.     /* These two if's keep us from drawing lines off the border of the win */
  296.     if ((DrawWindow->Height - DrawWindow->BorderBottom - 1) < nBottomOfWindow)
  297.              nBottomOfWindow = DrawWindow->Height - DrawWindow->BorderBottom - 1;
  298.     if (nGetToolBoxLeft() < nToolBoxLeft) nToolBoxLeft = nGetToolBoxLeft();
  299.     
  300.     SetAPen(DrawWindow->RPort,0);
  301.     
  302.     /* Erase lines */
  303.     Rectangle(DrawWindow->BorderLeft+1,
  304.                  nBottomOfWindow-(nChatLineHeight*2)-4,
  305.                  nToolBoxLeft-2, 
  306.                  nBottomOfWindow, TRUE);     
  307.     return;
  308. }
  309.  
  310.  
  311.  
  312. void DrawChatLines(void)
  313. {
  314.     int nToolBoxLeft = nGetToolBoxLeft();
  315.     int nBottomOfWindow = DrawWindow->Height-DrawWindow->BorderBottom-1;
  316.     int nChatLineHeight = 10;
  317.  
  318.     /* Clear the area */
  319.     SetAPen(DrawWindow->RPort,0);
  320.     Rectangle(DrawWindow->BorderLeft+1, nBottomOfWindow-(nChatLineHeight*2)-3,
  321.                  nToolBoxLeft-3, nBottomOfWindow-1, TRUE);
  322.         
  323.     SetAPen(DrawWindow->RPort,1);
  324.     
  325.     /* Draw lower, "local" window */
  326.     Rectangle(DrawWindow->BorderLeft+1, nBottomOfWindow-1,
  327.                  nToolBoxLeft-3, nBottomOfWindow-nChatLineHeight-1, FALSE);
  328.                  
  329.     /* Draw upper, "remote" window */
  330.     Rectangle(DrawWindow->BorderLeft+1, nBottomOfWindow-nChatLineHeight-3,
  331.                  nToolBoxLeft-3, nBottomOfWindow-(nChatLineHeight*2)-3, FALSE);
  332.                  
  333.     return;
  334. }
  335.     
  336.  
  337.  
  338. void DisplayKeyPress(char nChar, BOOL BEchoToRemote)
  339. {
  340.     int nToolBoxLeft = nGetToolBoxLeft();
  341.     int nTextHeight = 12;
  342.     int nBotOfGad = DrawWindow->Height - DrawWindow->BorderBottom - 4;
  343.     LONG DestCode = DEST_FILE;
  344.     
  345.     /* If caused locally, echo--only if we're not already echoing everything,
  346.        because we're reading from a file  */
  347.     if ((BEchoToRemote == TRUE)&&(fpIn == NULL))
  348.         OutputAction(FROM_IDCMP, MODE_DTEXT, nChar, NOP_PAD, NOP_PAD, NOP_PAD, (DestCode|DEST_PEER));
  349.         
  350.      if ((nChar != DELETE)&&(nChar != BACKSPACE))
  351.     {
  352.         if ((nChar < ' ')||(nChar > '|')) nChar = ' ';
  353.         /* StuffNewChar(nChar,sLocalBuffer); */
  354.         SetAPen(DrawWindow->RPort,1);
  355.         Move(DrawWindow->RPort,nGetToolBoxLeft()-nTextHeight-2, nBotOfGad-((BEchoToRemote==FALSE)*nTextHeight));
  356.         ScrollRaster(DrawWindow->RPort,8,0,DrawWindow->BorderLeft+4,
  357.                             nBotOfGad-nTextHeight+5-((BEchoToRemote==FALSE)*nTextHeight), 
  358.                             nGetToolBoxLeft()-4,
  359.                             nBotOfGad+1-((BEchoToRemote==FALSE)*nTextHeight));
  360.         Text(DrawWindow->RPort,&nChar,1);    
  361.     }
  362.     else
  363.     {
  364.         SetAPen(DrawWindow->RPort,0);
  365.         RectFill(DrawWindow->RPort,nGetToolBoxLeft()-13, 
  366.                                 nBotOfGad-nTextHeight+5-((BEchoToRemote==FALSE)*nTextHeight), 
  367.                                 nGetToolBoxLeft()-4, 
  368.                                 nBotOfGad+1-((BEchoToRemote==FALSE)*nTextHeight));
  369.         SetAPen(DrawWindow->RPort,PState.uwFColor);
  370.         ScrollRaster(DrawWindow->RPort,-8,0,DrawWindow->BorderLeft+4,
  371.                                 nBotOfGad-nTextHeight+5-((BEchoToRemote==FALSE)*nTextHeight), 
  372.                                 nGetToolBoxLeft()-4,
  373.                                 nBotOfGad+1-((BEchoToRemote==FALSE)*nTextHeight));
  374.     }        
  375.     return;
  376. }
  377.  
  378.  
  379.  
  380. /* ---------------- FUNCTIONS FOR MODE_DOT ------------------ */
  381. /* What to do in MODE_DOT when the user pushes the left mouse button */
  382. /* returns true if cursor is in window, else false */
  383. static BOOL Mode_Dot_MouseDown(void)
  384. {
  385.     Mode_Dot_MouseMove();        /* That's it, really */
  386. }
  387.  
  388. /* What to do in MODE_DOT when the user moves the mouse */
  389. /* returns true if cursor is in window, else false */
  390. static BOOL Mode_Dot_MouseMove(void)
  391. {
  392.     BOOL BInWindow = FixPos(&XPos, &YPos);
  393.  
  394.     SetAPen(DrawWindow->RPort,PState.uwFColor); 
  395.     
  396.     if (BInWindow == TRUE) 
  397.     {
  398.             WritePixel(DrawWindow->RPort,XPos,YPos);
  399.             OutputAction(FROM_IDCMP, MODE_DOT, XPos, YPos, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  400.     }
  401.     return(TRUE);
  402. }
  403.  
  404. /* What to do in MODE_DOT when the user releases the mouse button */
  405. /* returns true if cursor is in window, else false */
  406. static BOOL Mode_Dot_MouseUp(void)
  407. {
  408.     return(TRUE);
  409. }
  410.  
  411.  
  412. static BOOL Mode_Dot_Break(BOOL BResume)
  413. {
  414.     /* nothing needs to be done here */
  415.     return(TRUE);
  416. }
  417.  
  418.  
  419.  
  420. /* ---------------- FUNCTIONS FOR MODE_PEN ------------------ */
  421.  
  422. /* What to do in MODE_PEN when the user pushes the left mouse button */
  423. /* returns true if cursor is in window, else false */
  424. static BOOL Mode_Pen_MouseDown(void)
  425. {
  426.     if ((BPenLastIn = FixPos(&XPos, &YPos)) == TRUE) 
  427.     {
  428.         Move(DrawWindow->RPort, XPos, YPos);
  429.         XPen = XPos;
  430.         YPen = YPos;
  431.         OutputAction(FROM_IDCMP, MODE_PEN, XPos, YPos, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  432.         SetAPen(DrawWindow->RPort,PState.uwFColor); 
  433.         WritePixel(DrawWindow->RPort, XPos, YPos);
  434.         return(TRUE);
  435.     }
  436.     return(FALSE);
  437. }
  438.  
  439. /* What to do in MODE_PEN when the user moves the mouse */
  440. /* returns true if cursor is in window, else false */
  441. static BOOL Mode_Pen_MouseMove(void)
  442. {
  443.     BOOL BInWindow = FixPos(&XPos, &YPos);
  444.  
  445.     SetAPen(DrawWindow->RPort,PState.uwFColor); 
  446.     
  447.     if (BInWindow == TRUE) 
  448.     {
  449.         if (BPenLastIn == TRUE) 
  450.         {
  451.             Move(DrawWindow->RPort,XPen, YPen);
  452.             Draw(DrawWindow->RPort,XPos, YPos);
  453.             OutputAction(FROM_IDCMP, MODE_PEN, XPos, YPos, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  454.         }        
  455.         else
  456.         {
  457.             FixPos(&XPen, &YPen);
  458.             Move(DrawWindow->RPort,XPen,YPen);
  459.             Draw(DrawWindow->RPort,XPos,YPos);
  460.             OutputAction(FROM_IDCMP, MODE_PEN, XPen, YPen, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  461.             OutputAction(FROM_IDCMP, MODE_PEN, XPos, YPos, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  462.         }        
  463.         BPenLastIn = TRUE;
  464.     }
  465.     else
  466.     {
  467.        if (BPenLastIn == TRUE)
  468.        {
  469.            Move(DrawWindow->RPort,XPen, YPen);
  470.             Draw(DrawWindow->RPort,XPos, YPos);    
  471.             OutputAction(FROM_IDCMP, MODE_PEN, XPos,        YPos,    NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);   
  472.             OutputAction(FROM_IDCMP, MODE_PEN, STOP_STRING, NOP_PAD, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  473.         }
  474.        BPenLastIn = FALSE;
  475.     }
  476.     
  477.     XPen = XPos;
  478.     YPen = YPos;
  479.     return(TRUE);
  480. }
  481.  
  482.  
  483.  
  484.  
  485.  
  486. /* What to do in MODE_PEN when the user releases the mouse button */
  487. /* returns true if cursor is in window, else false */
  488. static BOOL Mode_Pen_MouseUp(void)
  489. {
  490.     OutputAction(FROM_IDCMP, MODE_PEN, STOP_STRING, STOP_STRING, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  491.     XPos = INVALID_POS;
  492.     YPos = INVALID_POS;
  493.      return(TRUE);
  494. }
  495.  
  496.  
  497.  
  498.  
  499. /* When interrupted, we need to save the current draw position in order
  500.    to to start from there again when we continue */
  501. static BOOL Mode_Pen_Break(BOOL BResume)
  502. {
  503.     if (BResume == TRUE) Move(DrawWindow->RPort, XPen, YPen);
  504.     return(TRUE);
  505. }
  506.  
  507.  
  508.  
  509.  
  510.  
  511. /* ---------------- FUNCTIONS FOR MODE_LINE ------------------ */
  512.  
  513. /* What to do in MODE_LINE when the user pushes the left mouse button */
  514. /* returns true if cursor is in window, else false */
  515. static BOOL Mode_Line_MouseDown(void)
  516. {
  517.     FixPos(&XPos, &YPos);
  518.     XBeginLine = XPos;
  519.     YBeginLine = YPos;
  520.     XEraseTo = XPos;
  521.     YEraseTo = YPos;
  522.     
  523.     /* Set Color, XOR drawing so as not to destroy underlying pic */
  524.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  525.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  526.     
  527.     WritePixel(DrawWindow->RPort,XPos,YPos);
  528.  
  529.     SetDrMd(DrawWindow->RPort, JAM1);
  530.  
  531.     return(TRUE);
  532. }
  533.  
  534.  
  535.  
  536. /* What to do in MODE_LINE when the user moves the mouse */
  537. /* returns true if cursor is in window, else false */
  538. static BOOL Mode_Line_MouseMove(void)
  539. {
  540.     FixPos(&XPos, &YPos);
  541.     
  542.     /* Set Color, XOR drawing so as not to destroy underlying pic */
  543.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  544.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  545.     
  546.     /* Erase old line */
  547.     Move(DrawWindow->RPort, XBeginLine, YBeginLine);
  548.     Draw(DrawWindow->RPort, XEraseTo, YEraseTo);
  549.     
  550.     /* Draw new one */
  551.     Move(DrawWindow->RPort, XBeginLine, YBeginLine);
  552.        Draw(DrawWindow->RPort, XPos, YPos);
  553.    
  554.        /* Prepare for next erase */
  555.        XEraseTo = XPos;
  556.        YEraseTo = YPos;
  557.        
  558.     SetDrMd(DrawWindow->RPort, JAM1);
  559.     return(TRUE);
  560. }
  561.  
  562.  
  563.  
  564. /* What to do in MODE_LINE when the user releases the mouse button */
  565. /* returns true if cursor is in window, else false */
  566. static BOOL Mode_Line_MouseUp(void)
  567. {
  568.     /* Set Color */
  569.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  570.  
  571.     FixPos(&XPos, &YPos);
  572.         
  573.     /* Draw final line */
  574.     Move(DrawWindow->RPort, XBeginLine, YBeginLine);
  575.    Draw(DrawWindow->RPort, XPos, YPos);
  576.  
  577.     OutputAction(FROM_IDCMP, MODE_LINE, XBeginLine, YBeginLine, XPos, YPos, DEST_PEER|DEST_FILE);
  578.    
  579.      return(TRUE);
  580. }
  581.  
  582.  
  583. /* When interrupted, we need to save the current draw position in order
  584.    to to start from there again when we continue */
  585. static BOOL Mode_Line_Break(BOOL BResume)
  586. {    
  587.  
  588.     /* In both cases here, the action is the same.  XOR will erase
  589.        the line when it's there, and restore it when it's not. */
  590.            
  591.     /* Set Color, XOR drawing so as not to destroy underlying pic */
  592.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  593.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  594.  
  595.     /* Erase/Restore line */
  596.     Move(DrawWindow->RPort, XBeginLine, YBeginLine);
  597.     Draw(DrawWindow->RPort, XEraseTo, YEraseTo);
  598.  
  599.     SetDrMd(DrawWindow->RPort, JAM1);    
  600.  
  601.     return(TRUE);
  602. }
  603.  
  604.  
  605.  
  606.  
  607.  
  608.  
  609.  
  610. /* ---------------- FUNCTIONS FOR MODE_CIRCLE ------------------ */
  611.  
  612. /* What to do in MODE_CIRCLE when the user pushes the left mouse button */
  613. /* returns true if cursor is in window, else false */
  614. static BOOL Mode_Circle_MouseDown(void)
  615. {
  616.     FixPos(&XPos, &YPos);
  617.     XCircleCenter = XPos;
  618.     YCircleCenter = YPos;
  619.     XCircleRadius = 0;
  620.     YCircleRadius = 0;
  621.     
  622.     /* Set Color, XOR drawing so as not to destroy underlying pic */
  623.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  624.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  625.     WritePixel(DrawWindow->RPort,XPos,YPos);    
  626.     SetDrMd(DrawWindow->RPort, JAM1);    
  627.  
  628.     /* Experimental--shorten mousemove queue! */
  629.     SetMouseQueue(DrawWindow,2);
  630.     return(TRUE);
  631. }
  632.  
  633.  
  634.  
  635. /* What to do in MODE_CIRCLE when the user moves the mouse */
  636. /* returns true if cursor is in window, else false */
  637. static BOOL Mode_Circle_MouseMove(void)
  638. {    
  639.     int XMin, XMax, YMin, YMax, XTestRadius, YTestRadius;
  640.     
  641.     FixPos(&XPos, &YPos);
  642.  
  643.     XTestRadius = abs(XPos - XCircleCenter);
  644.     YTestRadius = abs(YPos - YCircleCenter);
  645.  
  646.     /* Make sure no part of circle extends past canvas */
  647.     
  648.     XMin = XCircleCenter - XTestRadius;
  649.     if (FixPos(&XMin, &YPos) == FALSE) XTestRadius = XCircleCenter - XMin;
  650.     
  651.     YMin = YCircleCenter - YTestRadius;
  652.     if (FixPos(&XPos, &YMin) == FALSE) YTestRadius = YCircleCenter - YMin;
  653.     
  654.     XMax = XCircleCenter + XTestRadius;
  655.     if ((FixPos(&XMax, &YPos) == FALSE)&&((XMax - XCircleCenter) < XTestRadius)) 
  656.                 XTestRadius = (XMax - XCircleCenter);
  657.                 
  658.     YMax = YCircleCenter + YTestRadius;
  659.     if ((FixPos(&XPos, &YMax) == FALSE)&&((YMax - YCircleCenter) < YTestRadius))
  660.                 YTestRadius = (YMax - YCircleCenter);
  661.     
  662.     /* Set Color, XOR drawing so as not to destroy underlying pic */
  663.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  664.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  665.     
  666.     /* Erase old circle */
  667.     Ellipse(XCircleCenter, YCircleCenter, XCircleRadius, YCircleRadius, ((PState.uwMode & MODE_FILLED) != FALSE));
  668.     
  669.     XCircleRadius = XTestRadius;
  670.     YCircleRadius = YTestRadius;
  671.     
  672.     /* Draw new one */
  673.     Ellipse(XCircleCenter, YCircleCenter, XCircleRadius, YCircleRadius, ((PState.uwMode & MODE_FILLED) != FALSE));
  674.      
  675.     SetDrMd(DrawWindow->RPort, JAM1);
  676.     return(TRUE);
  677. }
  678.  
  679.  
  680.  
  681. /* What to do in MODE_CIRCLE when the user releases the mouse button */
  682. /* returns true if cursor is in window, else false */
  683. static BOOL Mode_Circle_MouseUp(void)
  684. {
  685.     /* Set Color */
  686.     SetAPen(DrawWindow->RPort,PState.uwFColor);
  687.     
  688.     /* Draw final circle */
  689.     Ellipse(XCircleCenter, YCircleCenter, XCircleRadius, YCircleRadius, ((PState.uwMode & MODE_FILLED) != FALSE));
  690.  
  691.     OutputAction(FROM_IDCMP, PState.uwMode, XCircleCenter, YCircleCenter, XCircleRadius, YCircleRadius, DEST_PEER|DEST_FILE);
  692.  
  693.     /* Experimental - restore queue to normal length */
  694.     SetMouseQueue(DrawWindow,5);
  695.     
  696.      return(TRUE);
  697. }
  698.  
  699.  
  700.  
  701.  
  702.  
  703.  
  704. static BOOL Mode_Circle_Break(BOOL BResume)
  705. {
  706.     /* Again both actions are the same.  XOR will erase and then
  707.        redraw. */
  708.  
  709.     /* Set Color, XOR drawing so as not to destroy underlying pic */
  710.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  711.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  712.  
  713.     /* Erase old circle */
  714.     Ellipse(XCircleCenter, YCircleCenter, XCircleRadius, YCircleRadius, ((PState.uwMode & MODE_FILLED) != FALSE));
  715.  
  716.     SetDrMd(DrawWindow->RPort, JAM1);    
  717.  
  718.     return(TRUE);
  719. }
  720.  
  721.  
  722.  
  723.  
  724. /* ---------------- FUNCTIONS FOR MODE_POLY ------------------ */
  725. /* Resets Polygon tool to original state.  */
  726. void ResetPolygonTool(void)
  727. {
  728.     XBeginPoly = -1;
  729.     YBeginPoly = -1;
  730. }
  731.  
  732. /* What to do in MODE_POLY when the user pushes the left mouse button */
  733. /* returns true if cursor is in window, else false */
  734. static BOOL Mode_Poly_MouseDown(void)
  735. {
  736.     if (FixPos(&XPos, &YPos) == FALSE) return(FALSE);    
  737.  
  738.     if ((XBeginPoly == -1)&&(YBeginPoly == -1))
  739.     {    
  740.         /* Begin Polygon! */
  741.         XBeginPoly = XPos;    /* First point in polygon */
  742.         YBeginPoly = YPos;
  743.         XLastPoly  = XPos;  /* Last point drawn to */
  744.         YLastPoly  = YPos;
  745.         XErasePoly = XPos;
  746.         YErasePoly = YPos;
  747.  
  748.         /* Set Color, XOR drawing so as not to destroy underlying pic */
  749.         SetAPen(DrawWindow->RPort,PState.uwFColor);     
  750.         SetDrMd(DrawWindow->RPort, COMPLEMENT);
  751.         WritePixel(DrawWindow->RPort,XBeginPoly,YBeginPoly);
  752.         SetDrMd(DrawWindow->RPort, JAM1);
  753.     }
  754.     else
  755.     {
  756.         /* Set Color, XOR drawing so as not to destroy underlying pic */
  757.         SetAPen(DrawWindow->RPort,PState.uwFColor);     
  758.         SetDrMd(DrawWindow->RPort, COMPLEMENT);
  759.         Move(DrawWindow->RPort, XLastPoly, YLastPoly);
  760.         Draw(DrawWindow->RPort, XPos,      YPos);
  761.         XErasePoly = XPos;
  762.         YErasePoly = YPos;
  763.         SetDrMd(DrawWindow->RPort, JAM1);
  764.     }
  765.     
  766.     /* Mark toolbox gadget to show we're in the polygon "mode" */
  767.     SetAPen(DrawWindow->RPort, 1);
  768.     Rectangle(nGetToolBoxLeft()+POLYBOXLEFT, nGetToolBoxTop()+POLYBOXTOP, nGetToolBoxLeft()+POLYBOXLEFT+POLYBOXWIDTH, nGetToolBoxTop()+POLYBOXTOP+POLYBOXHEIGHT, TRUE);
  769.     
  770.     return(TRUE);
  771. }
  772.  
  773.  
  774.  
  775. /* What to do in MODE_POLY when the user moves the mouse */
  776. /* returns true if cursor is in window, else false */
  777. static BOOL Mode_Poly_MouseMove(void)
  778. {
  779.     FixPos(&XPos, &YPos);
  780.     
  781.     /* Set Color, XOR drawing so as not to destroy underlying pic */
  782.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  783.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  784.     
  785.     /* Erase old line */
  786.     Move(DrawWindow->RPort, XLastPoly, YLastPoly);
  787.     Draw(DrawWindow->RPort, XErasePoly, YErasePoly);
  788.  
  789.     /* Draw new one */
  790.     Move(DrawWindow->RPort, XLastPoly, YLastPoly);
  791.     Draw(DrawWindow->RPort, XPos, YPos);
  792.  
  793.     /* Prepare for next erase */
  794.     XErasePoly = XPos;
  795.     YErasePoly = YPos;
  796.    
  797.     SetDrMd(DrawWindow->RPort, JAM1);
  798.     return(TRUE);
  799. }
  800.  
  801.  
  802.  
  803. /* What to do in MODE_POLY when the user releases the mouse button */
  804. /* returns true if cursor is in window, else false */
  805. static BOOL Mode_Poly_MouseUp(void)
  806. {    
  807.     FixPos(&XPos, &YPos);
  808.  
  809.     /* Erase temporary line */
  810.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  811.     Move(DrawWindow->RPort, XLastPoly, YLastPoly);
  812.     Draw(DrawWindow->RPort, XPos, YPos);
  813.     SetDrMd(DrawWindow->RPort, JAM1);
  814.         
  815.     /* End polygon if we are on the last point or the first point */
  816.      if ((XBeginPoly != XLastPoly)&&(YBeginPoly != YLastPoly))
  817.      {
  818.          if ((abs(XPos-XLastPoly) <= 2)&&(abs(YPos-YLastPoly) <= 2))
  819.         {
  820.             /* Reset polygon */
  821.             XPos = XLastPoly;  YPos = YLastPoly;
  822.             XBeginPoly = -1;  YBeginPoly = -1;
  823.  
  824.             /* UnMark toolbox gadget to show we're out of the polygon "mode" */
  825.             SetAPen(DrawWindow->RPort, 3);
  826.             Rectangle(nGetToolBoxLeft()+POLYBOXLEFT, nGetToolBoxTop()+POLYBOXTOP, nGetToolBoxLeft()+POLYBOXLEFT+POLYBOXWIDTH, nGetToolBoxTop()+POLYBOXTOP+POLYBOXHEIGHT, TRUE);
  827.         }
  828.         else
  829.          if ((abs(XPos-XBeginPoly) <= 2)&&(abs(YPos-YBeginPoly) <= 2))
  830.         {
  831.             /* Reset polygon */
  832.             XPos = XBeginPoly;  YPos = YBeginPoly;
  833.             XBeginPoly = -1;  YBeginPoly = -1;
  834.  
  835.             /* UnMark toolbox gadget to show we're out of the polygon "mode" */
  836.             SetAPen(DrawWindow->RPort, 3);
  837.             Rectangle(nGetToolBoxLeft()+POLYBOXLEFT, nGetToolBoxTop()+POLYBOXTOP, nGetToolBoxLeft()+POLYBOXLEFT+POLYBOXWIDTH, nGetToolBoxTop()+POLYBOXTOP+POLYBOXHEIGHT, TRUE);
  838.         }
  839.     }
  840.  
  841.     /* Set Color */
  842.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  843.     
  844.     /* Draw final line */
  845.     Move(DrawWindow->RPort, XLastPoly, YLastPoly);
  846.     Draw(DrawWindow->RPort, XPos, YPos);
  847.     OutputAction(FROM_IDCMP, MODE_LINE, XLastPoly, YLastPoly, XPos, YPos, DEST_PEER|DEST_FILE);      
  848.  
  849.     /* Update last vertex drawn to */
  850.     XLastPoly = XPos;
  851.     YLastPoly = YPos;
  852.      return(TRUE);
  853. }
  854.  
  855.  
  856.  
  857.  
  858. /* When interrupted, we need to save the current draw position in order
  859.    to to start from there again when we continue */
  860. static BOOL Mode_Poly_Break(BOOL BResume)
  861. {    
  862.  
  863.     /* In both cases here, the action is the same.  XOR will erase
  864.        the line when it's there, and restore it when it's not. */
  865.            
  866.     /* Set Color, XOR drawing so as not to destroy underlying pic */
  867.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  868.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  869.  
  870.     /* Erase/Restore line */
  871.     Move(DrawWindow->RPort, XLastPoly, YLastPoly);
  872.     Draw(DrawWindow->RPort, XErasePoly, YErasePoly);
  873.  
  874.     SetDrMd(DrawWindow->RPort, JAM1);    
  875.  
  876.     return(TRUE);
  877. }
  878.  
  879.  
  880.  
  881.  
  882.  
  883.  
  884.  
  885.  
  886. /* ---------------- FUNCTIONS FOR MODE_SQUARE ------------------ */
  887. /* What to do in MODE_SQUARE when the user pushes the left mouse button */
  888. /* returns true if cursor is in window, else false */
  889. static BOOL Mode_Square_MouseDown(void)
  890. {
  891.     FixPos(&XPos, &YPos);
  892.     XBeginSquare = XPos;
  893.     YBeginSquare = YPos;
  894.     XEraseSquareTo = XPos;
  895.     YEraseSquareTo = YPos;
  896.     
  897.     /* Set Color, XOR drawing so as not to destroy underlying pic */
  898.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  899.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  900.     
  901.     WritePixel(DrawWindow->RPort,XPos,YPos);
  902.     SetDrMd(DrawWindow->RPort, JAM1);
  903.  
  904.     return(TRUE);
  905. }
  906.  
  907. /* What to do in MODE_SQUARE when the user moves the mouse */
  908. /* returns true if cursor is in window, else false */
  909. static BOOL Mode_Square_MouseMove(void)
  910. {
  911.     int *X1, *X2, *X3, *Y1, *Y2, *Y3;
  912.  
  913.     FixPos(&XPos, &YPos);
  914.     
  915.     X1 = &XBeginSquare;         /* X Co-ordinate of top left corner */
  916.     X2 = &XEraseSquareTo;   /* Y Co-ordinate of top left corner */
  917.     X3 = &XPos;
  918.     
  919.     Y1 = &YBeginSquare;         /* X Co-ordinate of bottom right corner */
  920.     Y2 = &YEraseSquareTo;   /* Y Co-ordinate of bottom right corner */
  921.     Y3 = &YPos;
  922.     
  923.     /* Make sure those are right */
  924.     if (*X1 > *X2) SwapPointers(&X1, &X2);
  925.     if (*Y1 > *Y2) SwapPointers(&Y1, &Y2);
  926.     
  927.     /* Set Color, XOR drawing so as not to destroy underlying pic */
  928.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  929.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  930.         
  931.     /* Erase old square */
  932.     Rectangle(*X1, *Y1, *X2, *Y2, ((PState.uwMode & MODE_FILLED) != FALSE));
  933.  
  934.     /* Reset ?1 */
  935.     X1 = &XBeginSquare;         /* X Co-ordinate of top left corner */
  936.     Y1 = &YBeginSquare;         /* X Co-ordinate of bottom right corner */
  937.  
  938.     /* Make sure the others are right */
  939.     if (*X1 > *X3) SwapPointers(&X1, &X3);
  940.     if (*Y1 > *Y3) SwapPointers(&Y1, &Y3);
  941.         
  942.     /* Draw new one */
  943.     Rectangle(*X1, *Y1, *X3, *Y3, ((PState.uwMode & MODE_FILLED) != FALSE));
  944.    
  945.        /* Prepare for next erase */
  946.        XEraseSquareTo = XPos;
  947.        YEraseSquareTo = YPos;
  948.    
  949.     SetDrMd(DrawWindow->RPort, JAM1);
  950.     return(TRUE);
  951. }
  952.  
  953.  
  954.  
  955.  
  956. /* What to do in MODE_SQUARE when the user releases the mouse button */
  957. /* returns true if cursor is in window, else false */
  958. static BOOL Mode_Square_MouseUp(void)
  959. {
  960.     int *X1, *X2, *Y1, *Y2;
  961.     
  962.     FixPos(&XPos, &YPos);
  963.     
  964.     X1 = &XBeginSquare;         /* X Co-ordinate of top left corner */
  965.     X2 = &XPos;                   /* Y Co-ordinate of top left corner */
  966.     
  967.     Y1 = &YBeginSquare;         /* X Co-ordinate of bottom right corner */
  968.     Y2 = &YPos;                  /* Y Co-ordinate of bottom right corner */
  969.     
  970.     /* Make sure those are right */
  971.     if (*X1 > *X2) SwapPointers(&X1, &X2);
  972.     if (*Y1 > *Y2) SwapPointers(&Y1, &Y2);
  973.         
  974.     /* Set Color */
  975.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  976.  
  977.     /* Draw final square */
  978.     Rectangle(*X1, *Y1, *X2, *Y2, ((PState.uwMode & MODE_FILLED) != FALSE));
  979.  
  980.     OutputAction(FROM_IDCMP, PState.uwMode, *X1, *Y1, *X2, *Y2, DEST_PEER|DEST_FILE);
  981.      return(TRUE);
  982. }
  983.  
  984.  
  985.  
  986. static BOOL Mode_Square_Break(BOOL BResume)
  987. {
  988.     int *X1, *X2, *Y1, *Y2;
  989.  
  990.     /* Another case of XOR doing the work for us */
  991.         
  992.     X1 = &XBeginSquare;         /* X Co-ordinate of top left corner */
  993.     X2 = &XEraseSquareTo;   /* Y Co-ordinate of top left corner */
  994.     
  995.     Y1 = &YBeginSquare;         /* X Co-ordinate of bottom right corner */
  996.     Y2 = &YEraseSquareTo;   /* Y Co-ordinate of bottom right corner */
  997.     
  998.     /* Make sure those are right */
  999.     if (*X1 > *X2) SwapPointers(&X1, &X2);
  1000.     if (*Y1 > *Y2) SwapPointers(&Y1, &Y2);
  1001.     
  1002.     /* Set Color, XOR drawing so as not to destroy underlying pic */
  1003.     SetAPen(DrawWindow->RPort,PState.uwFColor);     
  1004.     SetDrMd(DrawWindow->RPort, COMPLEMENT);
  1005.         
  1006.     /* Erase old square */
  1007.     Rectangle(*X1, *Y1, *X2, *Y2, ((PState.uwMode & MODE_FILLED) != FALSE));
  1008.  
  1009.     SetDrMd(DrawWindow->RPort, JAM1);
  1010.  
  1011.     return(TRUE);
  1012. }
  1013.  
  1014.  
  1015.  
  1016. /* Make a filled or empty ellipse based on BFilled */
  1017. void Ellipse(int x, int y, int rx, int ry, BOOL BFilled)
  1018. {
  1019.     if (BFilled == FALSE)
  1020.     {
  1021.         DrawEllipse(DrawWindow->RPort, x, y, rx, ry);
  1022.     }
  1023.     else
  1024.     {
  1025.         AreaEllipse(DrawWindow->RPort, x, y, rx, ry);
  1026.         AreaEnd(DrawWindow->RPort);
  1027.     }
  1028.     return;
  1029. }
  1030.  
  1031.  
  1032. /* Draw the next uwPixels pixels of a raster bitmap in the 
  1033.    RGB color uwColorCode.  If the MSB of uwColorCode is set,
  1034.    use XOR mode instead. */
  1035. void DrawRasterChunk(UWORD uwPixels, UWORD uwColorCode, struct SlateRaster *srast, int *nOptPen)
  1036. {
  1037.     /* Static to speed up function? */
  1038.     static int nPen,nLeft,nRight,nTop,nBottom,nCurrentY,nCurrentX,nLines,nTemp,nTopLines,nTempTop,nTempBot;
  1039.  
  1040.     if (uwPixels <= 0) return;    /* no need to do anything here! */    
  1041.  
  1042.     /* Set initial values */
  1043.     nPen = 1;    /* lame default */
  1044.     nLeft = srast->nRX;
  1045.     nRight  = srast->nRX + srast->nRWidth  - 1;
  1046.     nTop  = srast->nRY;
  1047.     nBottom = srast->nRY + srast->nRHeight - 1;
  1048.     nCurrentY = (srast->nRCurrentOffset / srast->nRWidth) + srast->nRY;
  1049.     nCurrentX = (srast->nRCurrentOffset % srast->nRWidth) + srast->nRX;
  1050.     nTopLines = 0;
  1051.     
  1052.     /* Figure out which color to use */
  1053.     if (srast == &PState.RexxRaster)   
  1054.         OutputAction(FROM_REXX, MODE_RASTER, uwPixels, uwColorCode, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  1055.     else if (srast == &PState.LocalRaster)  
  1056.         OutputAction(FROM_IDCMP, MODE_RASTER, uwPixels, uwColorCode, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  1057.  
  1058.     /* local XOR requested? */
  1059.     if (uwColorCode & 0x4000) 
  1060.     {
  1061.         uwColorCode &= ~(0x4000);    /* strip XOR bit */
  1062.         SetDrMd(DrawWindow->RPort, COMPLEMENT);
  1063.     }
  1064.     else
  1065.     {
  1066.         if (nOptPen == NULL)
  1067.         {
  1068.             SetAPen(DrawWindow->RPort,
  1069.                 MatchPalette(((uwColorCode >> 8) & 0x000F), 
  1070.                      ((uwColorCode >> 4) & 0x000F), 
  1071.                       (uwColorCode       & 0x000F), FALSE, NULL, NULL));
  1072.         }
  1073.         else
  1074.         {
  1075.             SetAPen(DrawWindow->RPort,*nOptPen);
  1076.         }
  1077.     }
  1078.     
  1079.     /* Make sure drawn raster area is on canvas!*/
  1080.     FixPos(&nLeft,  &nTop);
  1081.     FixPos(&nRight, &nBottom);
  1082.  
  1083.     /* No need to do more than one rasterful? */
  1084.     if (uwPixels >= (srast->nRWidth * srast->nRHeight))
  1085.     {
  1086.         /* Blot out the whole raster! */
  1087.         Rectangle(nLeft, nTop, nRight, nBottom, TRUE);
  1088.                 
  1089.         /* Then add the remainder to nRCurrentOffset */
  1090.         srast->nRCurrentOffset += (uwPixels % (srast->nRWidth * srast->nRHeight));
  1091.     }
  1092.     else if ((uwPixels+nCurrentX-1) <= (srast->nRX + srast->nRWidth))  /* Does the line of pixels not extend past the end of this row? */
  1093.     {
  1094.         nTemp = nCurrentX + uwPixels - 1;
  1095.         if (nTemp > nRight) nTemp = nRight; /* clip! */
  1096.         /* Draw a line from current pos to end of pixel row */
  1097.         if ((nCurrentY <= nBottom)&&(nCurrentX <= nRight))
  1098.         {
  1099.             Move(DrawWindow->RPort, nCurrentX,  nCurrentY);
  1100.             Draw(DrawWindow->RPort, nTemp, nCurrentY);
  1101.         }    
  1102.         srast->nRCurrentOffset += uwPixels;
  1103.     }
  1104.     else
  1105.     {
  1106.         /* Draw a line from current pos to the end of the current raster line */
  1107.         if ((nCurrentX <= nRight)&&(nCurrentY <= nBottom)&&(nCurrentY >= nTop))
  1108.         {
  1109.             Move(DrawWindow->RPort, nCurrentX,  nCurrentY);
  1110.             Draw(DrawWindow->RPort, nRight, nCurrentY);
  1111.         }
  1112.         nTemp = (srast->nRX + srast->nRWidth) - nCurrentX;
  1113.         if (uwPixels >= nTemp) uwPixels -= nTemp; else uwPixels = 0;
  1114.         srast->nRCurrentOffset += nTemp;
  1115.         
  1116.         nCurrentY++;        /* sort of a carriage return ;) */
  1117.         if (nCurrentY >= (srast->nRY + srast->nRHeight)) nCurrentY = srast->nRY;
  1118.         nCurrentX = srast->nRX;
  1119.         
  1120.         /* any middle lines can be drawn as a rectangle (or possibly, two rectangles) */
  1121.         nLines = (uwPixels / srast->nRWidth);
  1122.  
  1123.         if (nLines > 0)
  1124.         {
  1125.             nTopLines = (nCurrentY + nLines) - (srast->nRY + srast->nRHeight);
  1126.             if (nTopLines > 0) nLines -= nTopLines; 
  1127.             
  1128.             if ((nLeft < nRight)&&(nCurrentY <= nBottom)&&(nLines > 0))
  1129.             {
  1130.                 nTemp = nCurrentY + nLines - 1;
  1131.                 if (nTemp > nBottom) nTemp = nBottom;
  1132.                 if (nTemp < nTop)    nTemp = nTop;
  1133.                 Rectangle(nLeft, nCurrentY, nRight, nTemp, TRUE);
  1134.             }
  1135.             uwPixels -= (nLines * srast->nRWidth);
  1136.             srast->nRCurrentOffset += (nLines * srast->nRWidth);
  1137.             nCurrentY += nLines;
  1138.             
  1139.             if (nTopLines > 0)
  1140.             {
  1141.                 /* Start at top again */
  1142.                 nTempTop = srast->nRY;
  1143.                 nTempBot = nTempTop + nTopLines - 1;
  1144.             
  1145.                 if (nTempTop < nTop)  nTempTop = nTop;
  1146.                 if (nTempBot > nBottom) nTempBot = nBottom;
  1147.                 if (nTempBot >= nTop) Rectangle(nLeft, nTempTop, nRight, nTempBot, TRUE);
  1148.                     
  1149.                 nTemp = (nTopLines * srast->nRWidth);
  1150.                 uwPixels -= nTemp;
  1151.                 srast->nRCurrentOffset += nTemp;
  1152.                 nCurrentY = srast->nRY + nTopLines;
  1153.             }
  1154.         }
  1155.         
  1156.         /* Now we should just have the remainder left over--draw one more line */
  1157.         if ((uwPixels > 0)&&(nCurrentY <= nBottom)&&(nCurrentY >= nTop))
  1158.         {
  1159.             nTemp = (nCurrentX + uwPixels - 1);    /* the leftovers! */
  1160.             Move(DrawWindow->RPort, nCurrentX, nCurrentY);
  1161.             FixPos(&nTemp, &nCurrentY);
  1162.             Draw(DrawWindow->RPort, nTemp, nCurrentY);
  1163.         }
  1164.         srast->nRCurrentOffset += uwPixels;
  1165.     }
  1166.     srast->nRCurrentOffset = srast->nRCurrentOffset % (srast->nRWidth * srast->nRHeight);
  1167.  
  1168.     SetDrMd(DrawWindow->RPort, JAM1);
  1169.  
  1170.     return;
  1171. }
  1172.  
  1173.  
  1174. /* Transmit the whole drawing canvas via Rasters */
  1175. void TransmitDrawCanvas(void)
  1176. {
  1177.     int x1=0, y1=0, x2=65535, y2=65535;
  1178.     int nCurrentPen, nTemp, nCount = 0;
  1179.  
  1180.     SetWindowTitle("Transmitting Canvas Bitmap, please wait.");
  1181.        SetPointer(DrawWindow, waitPointer, 16, 16, -6, 0);
  1182.                 
  1183.     /* Get drawing canvas boundaries */
  1184.     FixPos(&x1, &y1);
  1185.     FixPos(&x2, &y2);
  1186.         
  1187.     /* Set up our raster appropriately */
  1188.     PState.LocalRaster.nRX = x1;
  1189.     PState.LocalRaster.nRY = y1;
  1190.     PState.LocalRaster.nRWidth = x2 - x1 + 1;
  1191.     PState.LocalRaster.nRHeight = y2 - y1 + 1;
  1192.     PState.LocalRaster.nRCurrentOffset = 0;
  1193.     
  1194.     /* Send the info to our remote pal */
  1195.     OutputAction(FROM_IDCMP, COMMAND, COMMAND_SETRASTER, NOP_PAD, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  1196.  
  1197.     /* Get initial color */
  1198.     nCurrentPen = ReadPixel(DrawWindow->RPort, PState.LocalRaster.nRX, PState.LocalRaster.nRY);
  1199.  
  1200.     /* Scan through picture, sending on every color change */
  1201.     for (y1=PState.LocalRaster.nRY; y1<=y2; y1++)
  1202.       for (x1=PState.LocalRaster.nRX; x1<=x2; x1++)
  1203.       {
  1204.         nTemp = ReadPixel(DrawWindow->RPort, x1, y1);
  1205.  
  1206.         if (nTemp != nCurrentPen)
  1207.         {
  1208.             DrawRasterChunk(nCount, RGBComponents(nCurrentPen), &PState.LocalRaster, &nCurrentPen);
  1209.             nCurrentPen = nTemp;
  1210.             nCount = 1;
  1211.         }
  1212.         else
  1213.             nCount++;
  1214.       }    
  1215.  
  1216.     /* One final chunk */
  1217.     DrawRasterChunk(nCount, RGBComponents(nCurrentPen), &PState.LocalRaster,&nCurrentPen);
  1218.  
  1219.     SetWindowTitle("Transmission complete.");
  1220.     ClearPointer(DrawWindow);
  1221.  
  1222.     /* Restore the RexxRaster in case it was in use */
  1223.     OutputAction(FROM_REXX, COMMAND, COMMAND_SETRASTER, NOP_PAD, NOP_PAD, NOP_PAD, DEST_PEER|DEST_FILE);
  1224.  
  1225.  
  1226.     return;
  1227. }
  1228.     
  1229.  
  1230. /* Makes a filled or empty Rectangle based on BFilled */
  1231. void Rectangle(int x1, int y1, int x2, int y2, BOOL BFilled)
  1232. {
  1233.     int *X1, *X2, *Y1, *Y2;
  1234.  
  1235.    if (BFilled == TRUE)
  1236.     {
  1237.         X1 = &x1;     
  1238.         X2 = &x2;   
  1239.         Y1 = &y1;
  1240.         Y2 = &y2;
  1241.     
  1242.         /* Make sure those are right */
  1243.         if (*X1 > *X2) SwapPointers(&X1, &X2);
  1244.         if (*Y1 > *Y2) SwapPointers(&Y1, &Y2);
  1245.  
  1246.        RectFill(DrawWindow->RPort, *X1, *Y1, *X2, *Y2);
  1247.     }
  1248.    else
  1249.    {
  1250.        Move(DrawWindow->RPort, x1, y1);
  1251.        Draw(DrawWindow->RPort, x2, y1);
  1252.        Draw(DrawWindow->RPort, x2, y2);
  1253.        Draw(DrawWindow->RPort, x1, y2);
  1254.        Draw(DrawWindow->RPort, x1, y1);
  1255.    }
  1256.    return;
  1257. }
  1258.  
  1259.  
  1260.  
  1261.  
  1262. /* ---------------- FUNCTIONS FOR MODE_FLOOD ------------------ */
  1263.  
  1264. /* What to do in MODE_FLOOD when the user pushes the left mouse button */
  1265. /* returns true if cursor is in window, else false */
  1266. static BOOL Mode_Flood_MouseDown(void)
  1267. {
  1268.    ULONG ulFillThisColor = 0;
  1269.            
  1270.     if (FixPos(&XPos, &YPos) == TRUE) 
  1271.     {
  1272.         ulFillThisColor = ReadPixel(DrawWindow->RPort,XPos,YPos);
  1273.         
  1274.         if (ulFillThisColor != PState.uwFColor)
  1275.         {
  1276.             SetAPen(DrawWindow->RPort,PState.uwFColor);
  1277.  
  1278.                SetPointer(DrawWindow, waitPointer, 16, 16, -6, 0);
  1279.            
  1280.             if (BSafeFloods == TRUE)
  1281.                 {
  1282.                    /* Send flood info as a series of horizontal lines */
  1283.                 FloodFill(XPos, YPos, ulFillThisColor, 0, 0, 0, DEST_PEER|DEST_FILE);
  1284.             }
  1285.             else
  1286.             {
  1287.                 /* Send flood info as simple co-ordinates */
  1288.                 OutputAction(FROM_IDCMP, MODE_FLOOD, XPos, YPos, ulFillThisColor, NOP_PAD, DEST_PEER|DEST_FILE);
  1289.                 FloodFill(XPos, YPos, ulFillThisColor, 0, 0, 0, 0L);
  1290.             }        
  1291.             ClearPointer(DrawWindow);
  1292.             return(TRUE);
  1293.         }
  1294.     }
  1295.     return(FALSE);
  1296. }
  1297.  
  1298.  
  1299.  
  1300.  
  1301.  
  1302.  
  1303. /* What to do in MODE_FLOOD when the user moves the mouse */
  1304. /* --basically, nothing--we're not that sort of tool! */
  1305. static BOOL Mode_Flood_MouseMove(void)
  1306. {
  1307.     return(FALSE);
  1308. }
  1309.  
  1310.  
  1311.  
  1312.  
  1313.  
  1314. /* What to do in MODE_PEN when the user releases the mouse button */
  1315. /* do nothing */
  1316. static BOOL Mode_Flood_MouseUp(void)
  1317. {
  1318.      return(FALSE);
  1319. }
  1320.  
  1321.  
  1322.  
  1323.  
  1324. /* When interrupted, we need to save the current draw position in order
  1325.    to to start from there again when we continue */
  1326. static BOOL Mode_Flood_Break(BOOL BResume)
  1327. {
  1328.     /* Nothing--flood fills are discrete operations! */
  1329.     return(TRUE);
  1330. }
  1331.  
  1332.  
  1333.  
  1334.  
  1335.  
  1336.  
  1337. /* ---------MOUSE ACTION DISTRIBUTION FUNCTIONS-------- */
  1338. BOOL MouseDownAction(int nMode)
  1339. {
  1340.     static LONG downX, downY;
  1341.     int ndownX, ndownY;
  1342.     const static LONG lType = REXX_REPLY_MOUSEDOWN;
  1343.     
  1344.     if (PState.uwRexxWaitMask & REXX_REPLY_MOUSEDOWN)
  1345.     {
  1346.         ndownX = XPos;        /* Record beginning co-ordinates for ARexx client */
  1347.         ndownY = YPos;
  1348.         if (FixPos(&ndownX, &ndownY) == TRUE)
  1349.         {
  1350.             UnFixCoords(&ndownX, &ndownY);
  1351.             downX = ndownX;
  1352.             downY = ndownY;
  1353.             ((struct rxd_waitevent *) *(&RexxState.array))->res.type = &lType;
  1354.             ((struct rxd_waitevent *) *(&RexxState.array))->res.x = &downX;
  1355.             ((struct rxd_waitevent *) *(&RexxState.array))->res.y = &downY;
  1356.             SetStandardRexxReturns();
  1357.         }
  1358.     }
  1359.  
  1360.     if (PState.BDrawEnabled == FALSE) return(FALSE);
  1361.      PState.BPenDown = TRUE;
  1362.     switch(nMode & ~(MODE_FILLED))
  1363.     {
  1364.         case MODE_DOT:    Mode_Dot_MouseDown();      break;
  1365.         case MODE_PEN:    Mode_Pen_MouseDown();      break;
  1366.         case MODE_LINE:   Mode_Line_MouseDown();     break;
  1367.         case MODE_CIRCLE: Mode_Circle_MouseDown();   break;                
  1368.         case MODE_SQUARE: Mode_Square_MouseDown();   break;
  1369.         case MODE_POLY:   Mode_Poly_MouseDown();     break;
  1370.         case MODE_FLOOD:  Mode_Flood_MouseDown();    break;
  1371.         default: Printf("MouseDownAction:  Bad mode!\n"); break;
  1372.     }
  1373.     return(TRUE);
  1374. }
  1375.  
  1376.  
  1377.  
  1378.  
  1379.  
  1380. BOOL MouseMoveAction(int nMode)
  1381. {
  1382.     if (PState.BDrawEnabled == FALSE) return(FALSE);
  1383.     switch(nMode & ~(MODE_FILLED))
  1384.     {
  1385.         case MODE_DOT:    Mode_Dot_MouseMove();     break;
  1386.         case MODE_PEN:    Mode_Pen_MouseMove();     break;
  1387.         case MODE_LINE:   Mode_Line_MouseMove();    break;
  1388.         case MODE_CIRCLE: Mode_Circle_MouseMove();  break;
  1389.          case MODE_SQUARE: Mode_Square_MouseMove();  break;
  1390.         case MODE_POLY:   Mode_Poly_MouseMove();    break;
  1391.         case MODE_FLOOD:  Mode_Flood_MouseMove();   break;       
  1392.         default: Printf("MouseMoveAction:  Bad mode!\n");  break;
  1393.     }
  1394.     return(TRUE);
  1395. }            
  1396.  
  1397.  
  1398.  
  1399.  
  1400. BOOL MouseUpAction(int nMode)
  1401. {
  1402.     static LONG upX, upY;
  1403.     const static LONG lType = REXX_REPLY_MOUSEUP;
  1404.     int nupX, nupY;
  1405.     
  1406.     if (PState.uwRexxWaitMask & REXX_REPLY_MOUSEUP)
  1407.     {
  1408.         nupX = XPos;        /* Record ending co-ordinates for ARexx client */
  1409.         nupY = YPos;
  1410.         if (FixPos(&nupX, &nupY) == TRUE)
  1411.         {
  1412.             UnFixCoords(&nupX, &nupY);
  1413.             upX = nupX;
  1414.             upY = nupY;
  1415.             ((struct rxd_waitevent *) *(&RexxState.array))->res.type = &lType;
  1416.             ((struct rxd_waitevent *) *(&RexxState.array))->res.x = &upX;
  1417.             ((struct rxd_waitevent *) *(&RexxState.array))->res.y = &upY;
  1418.             SetStandardRexxReturns();
  1419.         }
  1420.     }
  1421.  
  1422.     if (PState.BDrawEnabled == FALSE) return(FALSE);
  1423.      PState.BPenDown = FALSE;
  1424.  
  1425.     switch(nMode & ~(MODE_FILLED))
  1426.     {
  1427.         case MODE_DOT:      Mode_Dot_MouseUp();     break;
  1428.         case MODE_PEN:    Mode_Pen_MouseUp();     break;
  1429.         case MODE_LINE:   Mode_Line_MouseUp();    break;
  1430.         case MODE_CIRCLE: Mode_Circle_MouseUp();  break;                 
  1431.         case MODE_SQUARE: Mode_Square_MouseUp();  break;
  1432.         case MODE_POLY:   Mode_Poly_MouseUp();    break;
  1433.         case MODE_FLOOD:  Mode_Flood_MouseUp();   break;        
  1434.         default: Printf("MouseUpAction:  Bad mode!\n"); break;
  1435.     }
  1436.     return(TRUE);
  1437. }
  1438.  
  1439.  
  1440.  
  1441. BOOL BreakAction(int nMode)
  1442. {
  1443.     switch(nMode & ~(MODE_FILLED))
  1444.     {
  1445.         case MODE_DOT:      Mode_Dot_Break(FALSE);     break;
  1446.         case MODE_PEN:    Mode_Pen_Break(FALSE);     break;
  1447.         case MODE_LINE:   Mode_Line_Break(FALSE);    break;
  1448.         case MODE_CIRCLE: Mode_Circle_Break(FALSE);  break;                 
  1449.         case MODE_SQUARE: Mode_Square_Break(FALSE);  break;
  1450.         case MODE_POLY:   Mode_Poly_Break(FALSE);    break;
  1451.         case MODE_FLOOD:  Mode_Flood_Break(FALSE);   break;        
  1452.         default: Printf("BreakAction:  Bad mode! [%i]\n",nMode); break;
  1453.     }
  1454.     return(TRUE);
  1455. }
  1456.  
  1457.  
  1458. BOOL ResumeAction(int nMode)
  1459. {
  1460.     switch(nMode & ~(MODE_FILLED))
  1461.     {
  1462.         case MODE_DOT:      Mode_Dot_Break(TRUE);       break;
  1463.         case MODE_PEN:    Mode_Pen_Break(TRUE);       break;
  1464.         case MODE_LINE:   Mode_Line_Break(TRUE);      break;
  1465.         case MODE_CIRCLE: Mode_Circle_Break(TRUE);    break;                 
  1466.         case MODE_SQUARE: Mode_Square_Break(TRUE);    break;
  1467.         case MODE_POLY:   Mode_Poly_Break(TRUE);      break;
  1468.         case MODE_FLOOD:  Mode_Flood_Break(TRUE);     break;        
  1469.         default: Printf("BreakAction:  Bad mode!\n"); break;
  1470.     }
  1471.     return(TRUE);
  1472. }
  1473.  
  1474.