/****************************************************************************
*
*    PROGRAM: Demo.c
*
*    PURPOSE: Demonstrates how to manipulate a cursor and select a region.
*
*    PLATFORMS: Chicago, NT
*
*    FUNCTIONS:
*        WinMain() - calls initialization function, processes message loop
*        DemoInit() - initializes window data and registers window
*        DemoWndProc() - processes messages
*        About() - processes messages for "About" dialog box
*
*    COMMENTS:
*        This code is a modified version of the CURSOR.C program.  Instead of
*        using inline code for drawing the shape, the routines from the Select
*        library are called.
*
*    SPECIAL INSTRUCTIONS: N/A
*
*    DISCLAIMER:
*
*        THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
*        ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
*        TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
*        PARTICULAR PURPOSE.
*
*    COPYRIGHT:
*
*        Copyright © 1993, 1994 Microsoft Corporation. All Rights Reserved.
*

****************************************************************************/

#include "windows.h"

#include "demo.h"
#include "select.h"

HANDLE hInst;                  // handle of instance
BOOL bTrack = FALSE;        // indicates if prev. objects have to be tracked
RECT rcRect;

INT nShape = SL_BLOCK;        // nShape to use for rectangle
BOOL bRetainShape = FALSE;    // Retain or destroy shape

/*************************************************************************\
*
*  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
*
*  PURPOSE: Application entry point and message loop.
*
*  INPUT PARAMETERS:  c.f. generic sample
*
\**************************************************************************/

int APIENTRY WinMain(HANDLE hInstance,
             HANDLE hPrevInstance,
             LPSTR lpCmdLine,
             int nCmdShow)
{

    HWND hWnd;
    MSG msg;

    UNREFERENCED_PARAMETER(lpCmdLine);

    if (!hPrevInstance)
    if (!DemoInit(hInstance))
        return (0);

    hInst = hInstance;

    hWnd = CreateWindow("Demo",
    "Demo Sample Application",
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    NULL,
    NULL,
    hInstance,
    NULL);

    if (!hWnd)
    return (0);

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    while (GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    return (msg.wParam);
}

/****************************************************************************
*
*    FUNCTION: DemoInit(HANDLE)
*
*    PURPOSE: Initializes window data and registers window class
*
*    INPUT PARAMETERS: Handle to the current instance
*
****************************************************************************/

BOOL DemoInit(HANDLE hInstance)
{
    WNDCLASS WndClass;
    BOOL bSuccess;

    memset((PWNDCLASS)&WndClass, 0, sizeof(WNDCLASS));
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.lpszMenuName = (LPSTR) "Menu";
    WndClass.lpszClassName = (LPSTR) "Demo";
    WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
    WndClass.hInstance = hInstance;
    WndClass.style = 0;
    WndClass.lpfnWndProc = (WNDPROC)DemoWndProc;
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;

    bSuccess = RegisterClass((PWNDCLASS)&WndClass);
    if (!bSuccess)
    MessageBeep(0);
    return (bSuccess);
}

/****************************************************************************
*
*    FUNCTION: DemoWndProc(HWND, unsigned, WORD, LONG)
*
*    PURPOSE:  Processes window messages
*
*    MESSAGES:
*
*        WM_SYSCOMMAND - system menu (About dialog box)
*        WM_CREATE     - create window
*        WM_DESTROY    - destroy window
*        WM_LBUTTONDOWN - left mouse button
*        WM_MOUSEMOVE   - mouse movement
*        WM_LBUTTONUP   - left button released
*
*        WM_COMMAND messages:
*            IDM_BOX    - use inverted box for selecting a region
*            IDM_BLOCK  - use empty box for selecting a region
*            IDM_RETAIN - retain/delete selection on button release
*
*    COMMENTS:
*
*        When the left mouse button is pressed, btrack is set to TRUE so that
*        the code for WM_MOUSEMOVE will keep track of the mouse and update the
*        box accordingly.  Once the button is released, btrack is set to
*        FALSE, and the current position is saved.  Holding the SHIFT key
*        while pressing the left button will extend the current box rather
*        then erasing it and starting a new one.  The exception is when the
*        retain shape option is enabled.  With this option, the rectangle is
*        zeroed whenever the mouse is released so that it can not be erased or
*        extended.
*
****************************************************************************/

LONG APIENTRY DemoWndProc(
    HWND hWnd,
    UINT message,
    UINT wParam,
    LONG lParam)
{
    FARPROC lpProcAbout;
    HMENU hMenu;

    switch (message) {

    case WM_COMMAND:

        // LOWORD added for portability

        switch (LOWORD(wParam)) {
        case IDM_BOX:
            nShape = SL_BOX;
            hMenu = GetMenu(hWnd);
            CheckMenuItem(hMenu, IDM_BOX, MF_CHECKED);
            CheckMenuItem(hMenu, IDM_BLOCK, MF_UNCHECKED);
            break;

        case IDM_BLOCK:
            nShape = SL_BLOCK;
            hMenu = GetMenu(hWnd);
            CheckMenuItem(hMenu, IDM_BOX, MF_UNCHECKED);
            CheckMenuItem(hMenu, IDM_BLOCK, MF_CHECKED);
            break;

        case IDM_RETAIN:
            if (bRetainShape) {
            hMenu = GetMenu(hWnd);
            CheckMenuItem(hMenu, IDM_RETAIN, MF_UNCHECKED);
            bRetainShape = FALSE;
            }
            else {
            hMenu = GetMenu(hWnd);
            CheckMenuItem(hMenu, IDM_RETAIN, MF_CHECKED);
            bRetainShape = TRUE;
            }
            break;

        case IDM_ABOUT:
            lpProcAbout = MakeProcInstance((FARPROC)About, hInst);
            DialogBox(hInst, "AboutBox", hWnd, (DLGPROC)lpProcAbout);
            FreeProcInstance(lpProcAbout);
            break;

        }
        break;

    case WM_LBUTTONDOWN:

        bTrack = TRUE;               /* user has pressed the left button */

        /* If you don't want the shape cleared, you must clear the rcRect
         * coordinates before calling StartSelection
         */

        if (bRetainShape)
        SetRectEmpty(&rcRect);

        StartSelection(hWnd, MAKEMPOINT(lParam), &rcRect,
        (wParam & MK_SHIFT) ? SL_EXTEND | nShape : nShape);
        break;

    case WM_MOUSEMOVE:
        if (bTrack)
        UpdateSelection(hWnd, MAKEMPOINT(lParam), &rcRect, nShape);
        break;

    case WM_LBUTTONUP:
       if (bTrack) 
           EndSelection(MAKEMPOINT(lParam), &rcRect);
     bTrack = FALSE;
        break;

   case WM_SIZE:
      switch (wParam) {
     case SIZEICONIC:

        /* If we aren't in retain mode we want to clear the 
         * current rectangle now! 
         */
        if (!bRetainShape)
           SetRectEmpty(&rcRect);
      }
      break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return (0);
}

/****************************************************************************
*
*    FUNCTION: About(HWND, unsigned, WORD, LONG)
*
*    PURPOSE:  Processes messages for "About" dialog box
*
*    MESSAGES:
*
*        WM_INITDIALOG - initialize dialog box
*        WM_COMMAND    - Input received
*
****************************************************************************/

BOOL APIENTRY About(
    HWND hDlg,
    UINT message,
    UINT wParam,
    LONG lParam)
{
    switch (message) {
    case WM_INITDIALOG:
        return (TRUE);

    case WM_COMMAND:
        // LOWORD added for portability
        if (LOWORD(wParam) == IDOK
         || LOWORD(wParam) == IDCANCEL) {
        EndDialog(hDlg, TRUE);
        return (TRUE);
        }
        return (TRUE);
    }
    return (FALSE);
    UNREFERENCED_PARAMETER(lParam);
}
