home *** CD-ROM | disk | FTP | other *** search
- ///////////////////////////////////////////////////////
- // QCDEMOW.CPP: Quadcode demo program for Windows
- // Written by:
- // Kenneth Van Camp
- // RR #1 Box 1255
- // East Stroudsburg, PA 18301
- // (717)223-8620
- //
- // Functions -
- // main main pgm entry point
- // init_graphics initialize graphics
- // Cursor::Cursor default constructor
- // Cursor::Move move cursor
- // RegionDisplay::Display display region
- // RegionDisplay::Interact user interaction
- // win_yieldfunc yield function for build
- //
- ///////////////////////////////////////////////////////
- #include <windows.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <string.h>
- #include <time.h>
- #include <iostream.h>
- #include "qc.h"
- #include "qcdemow.h"
-
- // Global variables:
- HCURSOR ArrowCursor, // standard arrow cursor
- WaitCursor; // hourglass cursor
- HDC Hdc; // device context for the window
- HWND BuildHdlg, // handle for the Building dialog box
- MainHwnd; // handle for application's main window
- HANDLE Haccel; // handle for application acclerators
- int Shrink = TRUE, // shrink all qc's for plotting?
- XShrinkage = 0, // amount to shrink in X direction
- YShrinkage = 0, // amount to shrink in Y direction
- Xmax = 0, // # pixels in viewport in X direction
- Ymax = 0, // # pixels in viewport in Y direction
- QCsize, // size of a single-division quadcode
- Nquits, // number of quits used to represent region
- RegionNumQC = 0, // number of qc's in region
- BuildCancelled = FALSE; // was the region building cancelled?
- time_t RegionBuildTime = 0;// time to build region
-
- const int SCRRES = 1024; // screen resolution used (logical coords)
-
- // class RegionDisplay: A Region class with graphical
- // display and interaction capabilities.
- class RegionDisplay: public Region
- {
- public:
- RegionDisplay // constructor from outline
- (PointListHeader &vertex_list):
- Region (vertex_list) { } // calls base constr.
- void Display (void); // display on graphics screen
- void Interact (void); // graphic interact function
- }; // class RegionDisplay
-
- RegionDisplay *TheRegion = NULL;
-
- // The following is the perimeter list for the demo region:
- const int Npts = 37;
- const int Ndiv = 128;
- const int Reduce = 1;
- Point Plist[Npts] =
- {
- { 5, 68}, { 28, 68}, { 32, 88}, { 33, 94},
- { 31,110}, { 30,113}, { 35,124}, { 51,125},
- { 63,127}, { 63,119}, { 67,116}, { 59,109},
- { 63,119}, { 63,127}, { 74,126}, { 80,125},
- { 88,112}, { 99,101}, {107, 98}, {113, 96},
- {124, 98}, {122, 94}, {123, 91}, {121, 85},
- {118, 78}, {108, 73}, { 96, 64}, { 85, 58},
- { 81, 50}, { 82, 46}, { 90, 38}, { 83, 25},
- { 72, 21}, { 58, 8}, { 55, 8}, { 54, 40},
- { 5, 40},
- };
- PointListHeader Phdr =
- {
- Npts, Ndiv, Plist
- };
-
-
- // Prototypes for exported functions:
-
- #if defined( __cplusplus )
- extern "C" {
- #endif // __cplusplus
-
- long FAR PASCAL WndProc (HWND, UINT, WPARAM, LPARAM);
- BOOL FAR PASCAL AboutDlgProc (HWND, UINT, WPARAM, LPARAM);
- BOOL FAR PASCAL BuildDlgProc (HWND, UINT, WPARAM, LPARAM);
-
- #if defined( __cplusplus )
- }
- #endif // __cplusplus
-
- // Prototypes for other local functions:
- void redraw_win (int first_time);
- void update_status (int xcursor, int ycursor);
- void set_draw_area (void);
- int win_yieldfunc (int pct_complete);
-
- int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
- LPSTR lpszCmdParam, int nCmdShow)
- {
- static char szAppName[] = "QCDemoW";
- MSG msg;
- WNDCLASS wndclass;
-
- // Initialize the cursor we will use.
- ArrowCursor = LoadCursor (NULL, IDC_ARROW);
- WaitCursor = LoadCursor (NULL, IDC_WAIT);
-
- if (!hPrevInstance)
- {
- wndclass.style = CS_HREDRAW | CS_VREDRAW;
- wndclass.lpfnWndProc = WndProc;
- wndclass.cbClsExtra = 0;
- wndclass.cbWndExtra = 0;
- wndclass.hInstance = hInstance;
- wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
- wndclass.hCursor = ArrowCursor;
- wndclass.hbrBackground = GetStockObject (WHITE_BRUSH);
- wndclass.lpszMenuName = "QCDEMOW";
- wndclass.lpszClassName = szAppName;
-
- RegisterClass (&wndclass);
- }
-
- MainHwnd = CreateWindow (szAppName, // window class name
- "Quadcode Demo (Windows Version)", // window caption
- WS_OVERLAPPEDWINDOW, // window style
- CW_USEDEFAULT, // initial x position
- CW_USEDEFAULT, // initial y position
- CW_USEDEFAULT, // initial x size
- CW_USEDEFAULT, // initial y size
- NULL, // parent window handle
- NULL, // window menu handle
- hInstance, // program instance handle
- NULL); // creation parameters
-
- ShowWindow (MainHwnd, nCmdShow);
- UpdateWindow (MainHwnd);
-
- Haccel = LoadAccelerators (hInstance, "ACCELERATORS_1");
- if (Haccel == NULL)
- MessageBox (MainHwnd, "Can't Load Acelerators", "NOTICE",
- MB_ICONEXCLAMATION | MB_OK);
-
- while (GetMessage (&msg, NULL, 0, 0))
- {
- // Translate accelerator keystrokes, too.
- if (! TranslateAccelerator (MainHwnd, Haccel, &msg))
- {
- TranslateMessage (&msg);
- DispatchMessage (&msg);
- }
- }
- return msg.wParam;
-
- } // WinMain
-
- long FAR PASCAL WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- PAINTSTRUCT ps;
- int ret;
- WORD menu_state; // Current menu state (checked or not)
- char tmpstr[80];
-
- static int first_paint = TRUE, // Is this the first screen paint?
- resized = FALSE; // Was the window just resized?
- static HMENU menu; // Popup menu
- static HANDLE hinstance; // Instance of this program
- static FARPROC about_dlg_proc, // Point to About dialog box procedure
- build_dlg_proc; // Point to Build dialog box procedure
-
- switch (message)
- {
- case WM_CREATE:
- // This occurs when the window is first created.
- // First get the instance of the main program.
- hinstance = ((LPCREATESTRUCT)lParam)->hInstance;
- // Register the dialog procedures:
- about_dlg_proc = MakeProcInstance ((FARPROC)AboutDlgProc,
- hinstance);
- build_dlg_proc = MakeProcInstance ((FARPROC)BuildDlgProc,
- hinstance);
- // Then get the handle for the menu
- menu = GetMenu (hwnd);
- return 0;
-
- case WM_COMMAND:
- // This is a menu selection or accelerator.
- // Ignore any menu commands if the region is not built yet.
- if (RegionNumQC == 0)
- return 0;
- switch ( wParam )
- {
- case QCMNU_EXIT: // File Menu, Exit QCDemoW selection
- case QCACC_EXIT: // Alt-X accelerator
- ret = MessageBox (hwnd, "Are You Sure You Want To Exit?",
- "QCDemoW", MB_OKCANCEL);
- if ( ret == IDOK )
- PostQuitMessage (0);
- return 0;
-
- case QCMNU_ABOUT: // File Menu, About selection
- DialogBox (hinstance, "ABOUT_BOX", hwnd, about_dlg_proc);
- return 0;
-
- case QCMNU_SHRINKAGE: // Options Menu, Shrinkage selection
- case QCACC_SHRINKAGE: // Alt-S accelerator
- // This is a boolean checked item: Reverse previous state.
- if (Shrink)
- {
- Shrink = FALSE;
- menu_state = MF_UNCHECKED;
- }
- else
- {
- Shrink = TRUE;
- menu_state = MF_CHECKED;
- }
- menu_state |= MF_BYCOMMAND;
- CheckMenuItem (menu, wParam, menu_state);
-
- // Invalidate the entire window so a repaint is forced.
- InvalidateRect (hwnd, NULL, TRUE);
- return 0;
-
- default:
- // Unknown menu selection
- sprintf (tmpstr, "Unknown Selection #%d", wParam);
- MessageBox (hwnd, tmpstr, "WARNING",
- MB_ICONEXCLAMATION | MB_OK);
- return 0;
-
- } // switch ( wParam )
- break;
-
- case WM_MOVE:
- // Make sure the window is repainted after a move, so we get
- // a new Hdc for the status box update.
- if (RegionNumQC > 0)
- InvalidateRect (hwnd, NULL, TRUE);
- return 0;
-
- case WM_SIZE:
- // Flag that the window was resized so extents will be
- // recalculated on the next WM_PAINT (which comes automatically
- // following a resize).
- if (RegionNumQC > 0)
- resized = TRUE;
- return 0;
-
- case WM_PAINT:
- if (! first_paint)
- {
- // Ignore any paint commands after the first one, until
- // the region is fully built.
- if (RegionNumQC == 0)
- return 0;
- // Change to the hourglass cursor during standard redraw.
- // (Don't have to put up hourglass on first paint, since
- // the modeless dialog box is displayed.)
- SetCursor (WaitCursor);
- }
-
- // Get the device context to repaint the area.
- Hdc = BeginPaint (hwnd, &ps);
-
- if (first_paint || resized)
- {
- // The first time we paint, and each time the window is resized,
- // save the viewport extent. (These are device coordinates.)
- RECT rect;
- GetClientRect (hwnd, &rect) ;
- Xmax = rect.right;
- Ymax = rect.bottom;
- resized = FALSE;
- }
-
- // Setup the viewport and drawing mode.
- set_draw_area ();
-
- if (Shrink)
- {
- // Make sure the shrinkage is at least one pixel.
- XShrinkage = SCRRES / Xmax + 1;
- YShrinkage = SCRRES / Ymax + 1;
- }
- else
- XShrinkage = YShrinkage = 0;
-
- // On the first paint, have to build the region. Put up a
- // dialog box to inform the user, and build the region.
- if (first_paint)
- {
- first_paint = FALSE;
- BuildHdlg = CreateDialog (hinstance, "BUILD_BOX", hwnd,
- build_dlg_proc);
- redraw_win (TRUE);
- // Close the dialog box. Not an error if it can't be
- // closed, since the user can close it.
- PostMessage (BuildHdlg, WM_CLOSE, 0, 0);
- }
- else
- {
- // After the first paint, just redraw the entire region.
- redraw_win (FALSE);
- }
-
- EndPaint (hwnd, &ps);
-
- // Put the cursor back as the arrow pointer.
- SetCursor (ArrowCursor);
-
- return 0;
-
- case WM_MOUSEMOVE:
- // Don't interpret mouse movements unless region already built.
- if (RegionNumQC > 0)
- {
- // When the mouse moves, we wait until there are no more mouse
- // movement messages in the queue before processing it.
- // That prevents the application from falling too far behind
- // the user.
- MSG nextmsg;
- nextmsg.lParam = lParam; // In case no more in queue.
- while ((ret = PeekMessage (&nextmsg, hwnd, WM_MOUSEMOVE,
- WM_MOUSEMOVE, PM_REMOVE)) != FALSE)
- ;
- // Find the current mouse position.
- POINT pt = MAKEPOINT (nextmsg.lParam);
-
- // Setup the viewport and drawing mode.
- Hdc = GetDC (hwnd);
- if (Hdc == NULL)
- MessageBox (hwnd, "NULL DC", "ERROR",
- MB_OK | MB_ICONEXCLAMATION);
- set_draw_area ();
-
- // Convert device coordinates to logical (window) coordinates.
- DPtoLP (Hdc, &pt, 1); // This doesn't work!
- // pt.x = (float)pt.x * SCRRES / Xmax;
- // pt.y = (float)pt.y * SCRRES / Ymax;
-
- // Update the status box.
- // This should be a message to the status box window,
- // but it isn't implemented as a window yet.
- update_status (pt.x, pt.y);
- }
- return 0;
-
- case WM_DESTROY:
- PostQuitMessage (0);
- return 0;
-
- } // switch
-
- return (DefWindowProc (hwnd, message, wParam, lParam));
-
- } // WndProc
-
- // AboutDlgProc: Dialog box procedure for the "About QCDemoW" selection.
- extern "C"
- BOOL FAR PASCAL AboutDlgProc (HWND hdlg, UINT message, WPARAM wParam,
- LPARAM lParam)
- {
- switch (message)
- {
- case WM_INITDIALOG:
- // Initialize the message with our performance message.
- char tmpstr[80];
- wsprintf (tmpstr, "%d Quadcodes Built in %d Seconds",
- RegionNumQC, RegionBuildTime);
- SetDlgItemText (hdlg, QCTXT_ABOUT, tmpstr);
- return TRUE;
-
- case WM_COMMAND:
- switch (wParam)
- {
- case QCBUT_OKABOUT:
- EndDialog (hdlg, TRUE);
- return TRUE;
- }
- break;
- }
- return FALSE;
- } // AboutDlgProc
-
- // BuildDlgProc: Dialog box procedure for the "Building Region" message.
- // This is a modeless dialog box.
- extern "C"
- BOOL FAR PASCAL BuildDlgProc (HWND hdlg, UINT message, WPARAM wParam,
- LPARAM lParam)
- {
- switch (message)
- {
- case WM_INITDIALOG:
- return TRUE;
-
- case WM_COMMAND:
- switch (wParam)
- {
- case QCBUT_CANCEL:
- // The user decided to cancel the building of the region.
- // This has to kill the whole application.
- #ifdef NEVER
- PostMessage (MainHwnd, WM_DESTROY, 0, 0);
- EndDialog (hdlg, TRUE);
- #endif
- BuildCancelled = TRUE;
- return TRUE;
- }
- break;
-
- case WM_CLOSE:
- DestroyWindow (hdlg);
- return TRUE;
-
- } // switch (message)
- return FALSE;
-
- } // BuildDlgProc
-
- // redraw_win: Redraw the entire region in the graphics window.
- void redraw_win (int first_time)
- {
-
- if (first_time)
- {
- // First draw, so build the quadcode region.
- // Reduce to proper size
- Phdr.ndiv /= Reduce;
- int i;
- for (i = 0; i < Npts; i++)
- {
- Phdr.pointptr[i].i /= Reduce;
- Phdr.pointptr[i].j /= Reduce;
- }
-
- // Set the yield function so user can interrupt.
- SetRegionYieldFunc (win_yieldfunc);
-
- time_t tstart;
- time (&tstart);
-
- // Build the region from a perimeter list
- TheRegion = new RegionDisplay (Phdr);
-
- // Save the time it took to build the region.
- time_t tend;
- time (&tend);
- RegionBuildTime = difftime (tend, tstart);
- RegionNumQC = TheRegion->NumQC();
-
- if (RegionNumQC == 0)
- {
- // Region build was aborted by user.
- PostMessage (MainHwnd, WM_DESTROY, 0, 0);
- return;
- }
- }
-
- // Now redisplay the region.
- TheRegion->Display();
-
- } // redraw_win
-
- // update_status: Update the status box in the upper left corner of the screen.
- void update_status (int xcursor, int ycursor)
- {
- // These are the coordinates of the status box (logical coords):
- const int StatUL = 10, // upper-left corner
- StatLR = 85; // lower-right corner
-
- // Find current mouse position
- int i = ycursor / QCsize;
- int j = xcursor / QCsize;
-
- // Only check if within region limits.
- if (i >= 0 && i < Ndiv && j >= 0 && j < Ndiv)
- {
- QuadCode qc (i, j, Nquits);
- if (TheRegion->InRegion (qc))
- {
- // In region - draw a solid status box.
- HBRUSH blk_brush = GetStockObject (BLACK_BRUSH);
- SelectObject (Hdc, blk_brush);
- Rectangle (Hdc, StatUL, StatUL, StatLR, StatLR);
- }
- else
- {
- // Out of region - draw empty status box.
- HBRUSH wht_brush = GetStockObject (WHITE_BRUSH);
- SelectObject (Hdc, wht_brush);
- Rectangle (Hdc, StatUL, StatUL, StatLR, StatLR);
- }
- } // if i >= 0 ...
-
- } // update_status
-
- // set_draw_area: Setup the viewport and client drawing area for a repaint.
- void set_draw_area (void)
- {
- // Use a viewport sized to the client rectangle, and
- // the window (virtual) size is SCRRES x SCRRES. This makes
- // (0,0) at the upper left of the window and (SCRRES,SCRRES)
- // at the lower right of the window. This is only
- // approximate however, since when drawing in isotropic
- // mode (to preserver the aspect ratio) we do not have
- // the entire window to draw in.
- SetMapMode (Hdc, MM_ISOTROPIC);
- SetViewportExt (Hdc, Xmax, Ymax);
-
- SetWindowExt (Hdc, SCRRES, SCRRES);
- SetWindowOrg (Hdc, 0, 0);
- } // set_draw_area
-
- // RegionDisplay::Display: Display the region on the graphics screen.
- void RegionDisplay::Display (void)
- {
- if (NumQC() == 0)
- return;
-
- // Get a brush so the quadcodes are filled black:
- HBRUSH blk_brush = GetStockObject (BLACK_BRUSH);
- SelectObject (Hdc, blk_brush);
-
- // Calculate the size of a single-division quadcode
- QCsize = SCRRES / Ndiv;
-
- // Do for each quadcode in the region.
- QCNode *qcn;
- for ( qcn = first_qcnode; qcn; qcn = qcn->next)
- {
- COORD i, j;
- int nq;
- qcn->ToIJ (i, j, nq);
- COORD nqc_div = 1L << nq;
- float qcfact = Ndiv / nqc_div;
- int qcxlen = QCsize * qcfact;
- int qcylen = QCsize * qcfact;
- int x = j * qcxlen;
- int y = i * qcylen;
-
- x += XShrinkage;
- y += YShrinkage;
- qcxlen -= 2 * XShrinkage;
- qcylen -= 2 * YShrinkage;
-
- // Minimum quadcode size is 2 screen units.
- qcxlen = max (qcxlen, 2);
- qcylen = max (qcylen, 2);
-
- // Draw the quadcode:
- Rectangle (Hdc, x, y, x + qcxlen, y + qcylen);
- } // for qcn
-
- // Save the maximum number of quits in a quadcode in this region.
- Nquits = MaxQuits();
-
- } // RegionDisplay::Display
-
- ///////////////////////////////////////////////////////
- // win_yieldfunc: A function that is called periodically
- // during region building to yield control to the user
- // or another application. Under Windows, it checks the
- // message queue for a Cancel by the user. This also
- // allows Windows to pass messages to other applications.
- // It returns TRUE if the user aborts, or FALSE otherwise.
-
- int win_yieldfunc (int pct_complete)
- // pct_complete is the percent of region built
- {
- // Before checking for messages, update the status bar.
- // First get the handle of the frame window.
- HWND frame_hwnd = GetDlgItem (BuildHdlg, QCFRAME);
- HDC frame_hdc = GetDC (frame_hwnd);
- RECT rect;
- GetClientRect (frame_hwnd, &rect);
-
- // Get a brush so the frame is filled black:
- HBRUSH blk_brush = GetStockObject (BLACK_BRUSH);
- SelectObject (frame_hdc, blk_brush);
-
- // Calculate the length of the rectangle, proportional to amount done.
- int xmax = ((float)pct_complete * (rect.right - 1) / 100.0);
- Rectangle (frame_hdc, 1, 1, xmax, rect.bottom - 1);
-
- // Now check to see if the user pressed Cancel button.
- MSG nextmsg;
- #ifdef NEVER
- // Don't know why this doesn't work. Should only have to check for
- // commands to dialog box, but this doesn't yield control to Windows
- // and it doesn't catch the mouse click.
- if (PeekMessage (&nextmsg, BuildHdlg, WM_COMMAND, WM_COMMAND, PM_REMOVE))
- {
- if (nextmsg.wParam == QCBUT_CANCEL)
- {
- // User pressed Cancel button
- return TRUE;
- }
- }
-
- return FALSE;
- #endif
-
- if (PeekMessage (&nextmsg, NULL, 0, 0, PM_REMOVE))
- {
- if (! IsDialogMessage (BuildHdlg, &nextmsg))
- {
- if (! TranslateAccelerator (MainHwnd, Haccel, &nextmsg))
- {
- TranslateMessage (&nextmsg);
- DispatchMessage (&nextmsg);
- }
- }
- }
-
- if (BuildCancelled)
- return TRUE;
- else
- return FALSE;
-
- } // win_yieldfunc
-