home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / w3_prog / ddjwin.arj / STATE.ASC < prev    next >
Text File  |  1991-11-14  |  17KB  |  407 lines

  1. _PROGRAMMING WINDOWS USING STATE TABLES_
  2. by Michael A. Bertrand and William R. Welch
  3.  
  4. [LISTING ONE]
  5.  
  6. /***********DRAW.H : header file for DRAW.C **************************/
  7.  
  8. #define WAITING  0   /* the possible values for variable iState in  */
  9. #define DRAWING  1   /* Tool() are WAITING and DRAWING              */
  10.  
  11. /*  These constants are the possible values for iMenuChoice, the variable
  12.  *  recording the user's menu choice. The old menu choice must be stored
  13.  *  so the check mark can be removed from the menu when a new menu choice
  14.  *  is made. Do not change. */
  15. #define IDM_RECT        100
  16. #define IDM_ROUND_RECT  101
  17. #define IDM_ELLIPSE     102
  18. #define IDM_LINE        103
  19. #define IDM_ABOUT       104
  20.  
  21. /* These constants are the possible values for iFigType, the variable
  22.  *  recording the current FIGURE, as chosen through the menu. The value is
  23.  *  also stored in the iType field in faList[] and is used to determine
  24.  *  which drawing function is called upon from DrawFig[], the array of
  25.  *  pointers to functions; since these values are indices into an array,
  26.  *  starting at 0, they may not be changed. */
  27. #define FT_RECT         (IDM_RECT       - IDM_RECT)
  28. #define FT_ROUND_RECT   (IDM_ROUND_RECT - IDM_RECT)
  29. #define FT_ELLIPSE      (IDM_ELLIPSE    - IDM_RECT)
  30. #define FT_LINE         (IDM_LINE       - IDM_RECT)
  31.  
  32. /* maximum number of FIGUREs in faList[] */
  33. #define MAX_FIGS 1000
  34.   
  35. /* FIGUREs in faList[]: rectangle, rounded rectangle, ellipse, line */
  36. typedef struct
  37. { int  iType;
  38.   RECT rsCoord;
  39. } FIGURE;
  40.  
  41. /* global variables */
  42. FIGURE faList[MAX_FIGS];   /* List of FIGUREs */
  43. int    iListSize;          /* tally number of displayed FIGUREs */
  44. HANDLE hInst;              /* current instance */
  45. RECT   rClient;            /* client area in scr coords for ClipCursor() */
  46.  
  47. /* function prototypes */
  48. long FAR  PASCAL WndProc(HWND hWnd, unsigned iMessage, WORD wParam, 
  49.                                                            LONG lParam);
  50. void NEAR PASCAL Tool(HWND hWnd, unsigned iMessage, LONG lParam,int iFigType);
  51. BOOL FAR  PASCAL DrawRoundRect(HDC hDC, int x1, int y1, int x2, int y2);
  52. BOOL FAR  PASCAL DrawLine(HDC hDC, int x1, int y1, int x2, int y2);
  53. BOOL FAR  PASCAL AboutDraw(HWND hDlg, unsigned message, WORD wParam, 
  54.                                                         LONG lParam);
  55. /* DrawFig[] is an array of pointers to FAR PASCAL functions, each with parms 
  56.  * (HDC,int,int,int,int) and returning BOOL. Note Rectangle() and Ellipse() are
  57.  * MS Windows GDI calls, while DrawRoundRect() and DrawLine() are our calls. */
  58. BOOL (FAR PASCAL *DrawFig[4])(HDC hDC, int x1, int y1, int x2, int y2)
  59.      = {Rectangle, DrawRoundRect, Ellipse, DrawLine};
  60.  
  61.  
  62.  
  63.  
  64. [LISTING TWO]
  65.  
  66. /******* DRAW.C by Michael A. Bertrand and William R. Welch. *******/
  67.  
  68. #include <windows.h>
  69. #include "draw.h"
  70.  
  71. int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine,
  72.                                                                   int nCmdShow)
  73.   /*    hInstance     : current instance handle
  74.    *    hPrevInstance : previous instance handle
  75.    *    lpszCmdLine   : current command line
  76.    *    nCmdShow      : display either window or icon
  77.    */
  78. { static char szAppName [] = "Draw";
  79.   static char szIconName[] = "DrawIcon";
  80.   static char szMenuName[] = "DrawMenu";
  81.  
  82.   HWND        hWnd;       /* handle to WinMain's window */
  83.   MSG         msg;        /* message dispached to window */
  84.   WNDCLASS    wc;         /* for registering window */
  85.  
  86.   /* Save instance handle in global var so can use for "About" dialog box. */
  87.   hInst = hInstance;
  88.  
  89.   if (!hPrevInstance)              /* Register application window class. */
  90.   { wc.style         = CS_HREDRAW | CS_VREDRAW;
  91.     wc.lpfnWndProc   = WndProc;   /* function to get window's messages */
  92.     wc.cbClsExtra    = 0;
  93.     wc.cbWndExtra    = 0;
  94.     wc.hInstance     = hInstance;
  95.     wc.hIcon         = LoadIcon(hInstance, szIconName);
  96.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  97.     wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  98.     wc.lpszMenuName  = szMenuName;  /* menu resource in RC file */
  99.     wc.lpszClassName = szAppName;   /* name used in call to CreateWindow() */
  100.     if (!RegisterClass(&wc))
  101.       return(FALSE);
  102.     }
  103.                                 /* Initialize specific instance. */
  104.     hWnd = CreateWindow(szAppName,              /* window class */
  105.                         szAppName,              /* window caption */
  106.                         WS_OVERLAPPEDWINDOW,    /* normal window style */
  107.                         CW_USEDEFAULT,          /* initial x-position */
  108.                         CW_USEDEFAULT,          /* initial y-position */
  109.                         CW_USEDEFAULT,          /* initial x-size */
  110.                         CW_USEDEFAULT,          /* initial y-size */
  111.                         NULL,                   /* parent window handle */
  112.                         NULL,                   /* window menu handle */
  113.                         hInstance,              /* program instance handle */
  114.                         NULL);                  /* create parameters */
  115.  
  116.   ShowWindow(hWnd, nCmdShow);   /* display the window */
  117.   UpdateWindow(hWnd);           /* update client area; send WM_PAINT */
  118.  
  119.   /*  Read msgs from app que and dispatch them to appropriate win function.
  120.    *  Continues until GetMessage() returns NULL when it receives WM_QUIT. */
  121.   while (GetMessage(&msg, NULL, NULL, NULL))
  122.   {  TranslateMessage(&msg);     /* process char input from keyboard */
  123.      DispatchMessage(&msg);      /* pass message to window function  */
  124.   }
  125.   return(msg.wParam);
  126. }
  127. /****************************************************************/
  128. long FAR PASCAL WndProc(HWND hWnd,unsigned iMessage, WORD wParam, LONG lParam)
  129.   /*  IN:   hWnd     : handle to window                                
  130.    *        iMessage : message type                                    
  131.    *        wParam   : drawing tool selected from menu (when WM_COMMAND msg)
  132.    *        lParam   : mouse coords (x == loword, y == hiword) */
  133. { static int  iMenuChoice = IDM_RECT;    /* default menu choice */ 
  134.   static int  iFigType    = FT_RECT;     /* default figure type */
  135.   HDC         hDC;           /* must generate our own handle to DC to draw */
  136.   HMENU       hMenu;         /* handle for drop down menu */
  137.   PAINTSTRUCT ps;            /* needed when receive WM_PAINT message */
  138.   int         ndx;           /* to traverse faList[] when draw it */
  139.   FARPROC     lpProcAbout;   /* pointer to "AboutDraw" function */
  140.   POINT       pt;            /* for ClientToScreen() */
  141.  
  142.   switch(iMessage)
  143.   {  case WM_SIZE:  /*convert client coords to scrn coords for ClipCursor()*/
  144.          pt.x = pt.y = 0;
  145.          ClientToScreen(hWnd, &pt);
  146.          rClient.left = pt.x;
  147.          rClient.top  = pt.y;
  148.          pt.x = LOWORD(lParam);
  149.          pt.y = HIWORD(lParam);
  150.          ClientToScreen(hWnd, &pt);
  151.          rClient.right  = pt.x;
  152.          rClient.bottom = pt.y;      
  153.          break;
  154.     case WM_COMMAND:
  155.       switch(wParam)
  156.       {  case IDM_RECT:
  157.          case IDM_ROUND_RECT:
  158.          case IDM_ELLIPSE:
  159.          case IDM_LINE:
  160.           /* New FIGURE chosen by user : uncheck old choice and check new
  161.            * choice on menu; reset iMenuChoice according to user choice. */
  162.           hMenu = GetMenu(hWnd);
  163.           CheckMenuItem(hMenu, iMenuChoice, MF_UNCHECKED);
  164.           CheckMenuItem(hMenu, iMenuChoice = wParam, MF_CHECKED);
  165.           /* User has chosen new FIGURE : set iFigType accordingly. */
  166.           iFigType = iMenuChoice - IDM_RECT;
  167.           break;  /* case IDM_LINE ... */
  168.         case IDM_ABOUT:
  169.           /* "About" chosen by user : call "AboutDraw" function. */
  170.           lpProcAbout = MakeProcInstance(AboutDraw, hInst);
  171.           DialogBox (hInst, "AboutDraw", hWnd, lpProcAbout);
  172.           FreeProcInstance(lpProcAbout);
  173.           break; /* IDM_ABOUT */
  174.         }  /* switch(wParam) */
  175.       break;  /* WM_COMMAND */
  176.     case WM_LBUTTONDOWN:
  177.     case WM_MOUSEMOVE:
  178.     case WM_LBUTTONUP:
  179.       /* Mouse events passed on to Tool() for processing. */
  180.       Tool(hWnd, iMessage, lParam, iFigType);
  181.       break;  /* WM_LBUTTONDOWN... */
  182.     case WM_PAINT:
  183.       /* Repaint window when resized. */
  184.       hDC = BeginPaint(hWnd, &ps);
  185.       /* Draw list of FIGUREs. */
  186.       for (ndx = 0; ndx < iListSize; ndx++)
  187.         DrawFig[faList[ndx].iType](hDC, faList[ndx].rsCoord.left,
  188.                                         faList[ndx].rsCoord.top,
  189.                                         faList[ndx].rsCoord.right,
  190.                                         faList[ndx].rsCoord.bottom);
  191.       EndPaint(hWnd, &ps);
  192.       break;  /* WM_PAINT */
  193.     case WM_DESTROY:
  194.       /* Destroy window when application terminated. */
  195.       PostQuitMessage(0);
  196.       break;  /* WM_DESTROY */
  197.     default:
  198.       return(DefWindowProc(hWnd, iMessage, wParam, lParam));
  199.   }  /* switch(iMessage) */
  200.   return(0L);
  201. }
  202. /****************************************************************/
  203. void NEAR PASCAL Tool(HWND hWnd, unsigned iMessage, LONG lParam, int iFigType)
  204.   /*       Process mouse event and draw.
  205.    *  IN:  hWnd     : handle to window                                
  206.    *       iMessage : mouse event (WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_LBUTTONUP)
  207.    *       lParam   : mouse coords (x == loword, y == hiword)
  208.    */
  209. { static int  x1, y1;     /* coordinates of button-down point */
  210.   static int  x2, y2;     /* coordinates of mouse */
  211.   static int  iState;     /* WAITING or DRAWING */
  212.   HDC         hDC;        /* must generate our own handle to DC to draw */
  213.   switch(iMessage)
  214.   {  case WM_LBUTTONDOWN:
  215.       /* Protect array from overflow : if array full, notify and out. */
  216.       if (iListSize == MAX_FIGS)
  217.       { MessageBox(hWnd,"Figure array full","Note",MB_ICONEXCLAMATION|MB_OK);
  218.         break;  /* WM_LBUTTONDOWN */
  219.       }
  220.       /* If not drawing, reset iState and store button-down point. */
  221.       if (iState == WAITING)
  222.       { ClipCursor(&rClient);        /* restrict cursor */
  223.         iState = DRAWING;            /* starting drag */
  224.         x1 = x2 = LOWORD(lParam);    /* store user point in statics */
  225.         y1 = y2 = HIWORD(lParam);
  226.       }
  227.       break;  /* WM_LBUTTONDOWN */
  228.      case WM_MOUSEMOVE:
  229.       /* If drawing, erase old figure and draw new one at mouse. */
  230.       if (iState == DRAWING)
  231.       { hDC = GetDC(hWnd);
  232.         SetROP2(hDC, R2_NOTXORPEN);                 /* draw in XOR */
  233.         DrawFig[iFigType](hDC, x1, y1, x2, y2);     /* erase old */
  234.         x2 = LOWORD(lParam);                        /* get 2nd user pt */
  235.         y2 = HIWORD(lParam);
  236.         DrawFig[iFigType](hDC, x1, y1, x2, y2);     /* draw new */
  237.         ReleaseDC(hWnd, hDC);
  238.       }
  239.       break;  /* WM_MOUSEMOVE */
  240.      case WM_LBUTTONUP:
  241.       /* If drawing, write in COPY mode and store in faList[]. */
  242.       if (iState == DRAWING)
  243.       { ClipCursor(NULL);            /* no longer restrict cursor */
  244.         iState = WAITING;            /* ending draw */
  245.         hDC = GetDC(hWnd);
  246.         SetROP2(hDC, R2_COPYPEN);    /* COPY pen for final FIGURE */
  247.         DrawFig[iFigType](hDC, x1, y1, x2, y2);  /* draw FIGURE */
  248.         ReleaseDC(hWnd, hDC);
  249.         faList[iListSize].iType = iFigType;      /* put FIGURE in faList[] */
  250.         faList[iListSize].rsCoord.left   = x1;
  251.         faList[iListSize].rsCoord.top    = y1;
  252.         faList[iListSize].rsCoord.right  = x2;
  253.         faList[iListSize].rsCoord.bottom = y2;
  254.         iListSize++;       /* bump tally, since just added figure to list */
  255.       }
  256.       break;  /* WM_LBUTTONUP */
  257.     }  /* switch(iMessage) */
  258. }
  259. /****************************************************************/      
  260. BOOL FAR PASCAL DrawRoundRect(HDC hDC, int x1, int y1, int x2, int y2)
  261.   /*  IN:   hDC    : display context in which to draw
  262.    *        x1, y1 : coordinates of first corner
  263.    *        x2, y2 : coordinates of second corner
  264.    *  RET:  returns BOOL for consistency with GDI's Rectangle() and Ellipse()
  265.    *  NOTE: GDI's RoundRect() is used to draw, but RoundRect() requires x-
  266.    *        and y-diameters of ellipse used for rounding. This routine sets
  267.    *        the common diameter equal to half the smallest side, then calls
  268.    *        RoundRect(). Array DrawFig[] contains a pointer to this function.
  269.    */
  270. { int dx, dy;        /* sides of rectangle, as positive values */
  271.   int diameter;      /* diameter of circle used for rounding */
  272.  
  273.   dx = (x1 < x2) ? (x2 - x1) : (x1 - x2);   /* x-side of rect (positive) */
  274.   dy = (y1 < y2) ? (y2 - y1) : (y1 - y2);   /* y-side of rect (positive) */
  275.   diameter = (dx < dy) ? dx/2 : dy/2;       /* half smallest side */
  276.   RoundRect(hDC, x1, y1, x2, y2, diameter, diameter);  /* call GDI */
  277.   return(TRUE);
  278. }
  279. /****************************************************************/
  280. BOOL FAR PASCAL DrawLine(HDC hDC, int x1, int y1, int x2, int y2)
  281.   /*
  282.    *   IN:   hDC    : display context in which to draw
  283.    *         x1, y1 : coordinates of first endpoint
  284.    *         x2, y2 : coordinates of second endpoint
  285.    *   RET:  returns BOOL for consistency w/GDI's Rectangle() and Ellipse().
  286.    *   NOTE: Array DrawFig[] contains a pointer to this function.
  287.   */
  288. { MoveTo(hDC, x1, y1);  /* MoveTo() and LineTo() are GDI calls. */
  289.   LineTo(hDC, x2, y2);
  290.   return(TRUE);
  291. }
  292. /****************************************************************/
  293. BOOL FAR PASCAL AboutDraw(HWND hDlg,unsigned iMessage,WORD wParam,LONG lParam)
  294.   /*    Application's "About" dialog box function.
  295.    *  IN:   hDlg     : handle to dialog box
  296.    *        iMessage : message type                                    
  297.    *        wParam   : auxiliary message info (act on IDOK, IDCANCEL)
  298.    *        lParam   : unused
  299.    *  RET:  Return TRUE if processed appropriate message, FALSE otherwise.
  300.    */
  301. {  switch (iMessage)
  302.    {  case WM_INITDIALOG:       /* initialize dialog box */
  303.          return (TRUE);
  304.       case WM_COMMAND:          /* received a command */
  305.          /* IDOK if OK box selected; IDCANCEL if system menu close command */
  306.         if (wParam == IDOK || wParam == IDCANCEL)
  307.         {   EndDialog(hDlg, TRUE);  /* exit dialog box */
  308.             return(TRUE);           /* did proccess message */
  309.         }
  310.         break;  /* WM_COMMAND */
  311.    }  /* switch (iMessage) */
  312.    return (FALSE);               /* did not process message */
  313. }
  314.  
  315.  
  316.  
  317.  
  318. [LISTING THREE]
  319.  
  320. #*************** DRAW : Make file for DRAW.C ***************************
  321. # To make program : NMAKE DRAW
  322. # Linker and Resource Compiler: draw.exe depends on draw.obj draw.def draw.res
  323. # Linker options as follows :
  324. # /A:16 : align on paragraphs
  325. # /CO   : add symbol information to EXE for CodeView
  326. # /NOD  : don't search default libs (use only those in link response file)
  327.  
  328. draw.exe: draw.obj draw.def draw.res
  329.     link /A:16 /CO /NOD draw,,, libw slibcew, draw.def
  330.     rc draw.res
  331.  
  332. # Microsoft C Compiler : draw.obj contingent on draw.c, draw.h
  333. # Compiler options as follows :
  334. # -c  : compile only
  335. # -Gs : remove stack probe before function calls
  336. # -Gw : for MS Windows
  337. # -Od : disable code optimization to help with debugging
  338. # -W3 : highest warning level (flags ANSI incompatibilities)
  339. # -AS : small model
  340. # -Zp : pack structures (required by MS Windows)
  341. # -Zi : add symbol information to OBJ for CodeView
  342. draw.obj: draw.c draw.h
  343.     cl -c -Gsw -Od -W3 -AS -Zpi draw.c
  344.  
  345. # Resource Compiler : draw.res contingent on draw.rc, draw.h
  346. draw.res: draw.rc draw.h
  347.     rc -r -v draw.rc
  348.  
  349.  
  350.  
  351.  
  352. [LISTING FOUR]
  353.  
  354. ;;**************DRAW.DEF : Definition file for DRAW.C**************
  355. NAME         DRAW
  356. DESCRIPTION  'MS Windows Draw Program (c) 1990 M. Bertrand & W. Welch'
  357. EXETYPE      WINDOWS
  358. STUB         'WINSTUB.EXE'
  359. CODE         MOVEABLE PRELOAD
  360. DATA         MOVEABLE PRELOAD SINGLE
  361. HEAPSIZE     1024
  362. STACKSIZE    4096
  363. EXPORTS      WndProc
  364.              AboutDraw
  365.  
  366.  
  367.  
  368. [LISTING FIVE]
  369.  
  370. /************ DRAW.RC : resource file for DRAW.C *******************/
  371.  
  372. #include "windows.h"
  373. #include "draw.h"
  374.  
  375. DrawIcon ICON DRAW.ICO
  376.  
  377. DrawMenu MENU
  378. BEGIN
  379.   POPUP "&Tool"
  380.   BEGIN
  381.     MENUITEM "&Rectangle",         IDM_RECT, CHECKED
  382.     MENUITEM "R&ounded rectangle", IDM_ROUND_RECT
  383.     MENUITEM "&Ellipse",           IDM_ELLIPSE
  384.     MENUITEM "&Line",              IDM_LINE
  385.     MENUITEM Separator
  386.     MENUITEM "&About Draw...",     IDM_ABOUT
  387.   END
  388. END
  389.  
  390. /*  "AboutDraw" dialog box contains 3 types of controls :
  391.  *    CTEXT to display centered text at x-coordinates 8, 24, 40, 56
  392.  *    ICON to display DRAW's icon at coords relative (20,20)
  393.  *    DEFPUSHBUTTON to display 32x14 OK push button at coords (60,74) 
  394.  */
  395. AboutDraw DIALOG 30, 30, 150, 94
  396. CAPTION "About Draw"
  397. STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
  398. BEGIN
  399.   CTEXT "Microsoft Windows"                         -1,  0,  8, 152,  8
  400.   CTEXT "Draw"                                      -1,  0, 24, 152,  8
  401.   CTEXT "Copyright (c) 1990"                        -1,  0, 40, 152,  8
  402.   CTEXT "Michael A. Bertrand and William R. Welch"  -1,  0, 56, 152,  8
  403.   ICON  "DrawIcon"                                  -1, 20, 20,  19, 26
  404.   DEFPUSHBUTTON "&OK" IDOK, 60, 74, 32, 14,   WS_GROUP
  405. END
  406.  
  407.