/*
**  DRAGSIZE.C
**
**  Drag size bar code
**
*/

#include "priv.h"

#pragma hdrstop


typedef struct tagDRAGSIZEINFO
{
    DWORD_PTR lpData;
    BOOL bDragging;
    POINT ptNow;
    HFONT hFont;
} DRAGSIZEINFO, *PDRAGSIZEINFO;

static TCHAR szDragSizeClass[] = DRAGSIZECLASSNAME;

LRESULT NEAR PASCAL InitDragSizeWnd(HWND hWnd, LPCREATESTRUCT lpCreate)
{
    PDRAGSIZEINFO pDragSizeInfo;

    /* Create the status info struct; abort if it does not exist,
    ** otherwise save it in the window structure
    */
    pDragSizeInfo = ALLOCWINDOWPOINTER(PDRAGSIZEINFO, sizeof(DRAGSIZEINFO));
    if (!pDragSizeInfo)
    {
        return(-1);
    }
    SETWINDOWPOINTER(hWnd, PDRAGSIZEINFO, pDragSizeInfo);
    pDragSizeInfo->lpData = (DWORD_PTR)lpCreate->lpCreateParams;
    pDragSizeInfo->bDragging = FALSE;

    return(0);
}


/* Track the mouse and send messages to the parent whenever it moves.
*/
void NEAR PASCAL DragSize(HWND hWnd, PDRAGSIZEINFO pDragSizeInfo, POINT ptStart)
{
    MSG msg;
    HWND hwndParent;
        LONG wID;

    if (!pDragSizeInfo || pDragSizeInfo->bDragging)
    {
        return;
    }

    pDragSizeInfo->bDragging = TRUE;
    pDragSizeInfo->ptNow     = ptStart;

    SetCapture(hWnd);

    hwndParent = GetParent(hWnd);
        wID = GETWINDOWID(hWnd);

        SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(wID, DSN_BEGINDRAG), (LPARAM)hWnd);

    for ( ; ; )
    {
        if (GetCapture() != hWnd)
        {
EndAbort:
            /* Abort the process.
            */
            pDragSizeInfo->ptNow = ptStart;
                        SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(wID, DSN_DRAGGING), (LPARAM)hWnd);
            goto EndAdjust;
        }

        if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            continue;
        }

        switch (msg.message)
        {
        case WM_KEYDOWN:
            switch (msg.wParam)
            {
            case VK_ESCAPE:
AbortAdjust:
                SetCapture(NULL);
                goto EndAbort;

            default:
                break;
            }
            break;

        case WM_KEYUP:
        case WM_CHAR:
            break;

        case WM_LBUTTONDOWN:
            /* This shouldn't happen.
            */
            goto AbortAdjust;

        case WM_MOUSEMOVE:
            LPARAM2POINT( msg.lParam, &(pDragSizeInfo->ptNow) );
            
            TraceMsg(TF_GENERAL, "DragSize: ptNow = (%d, %d)\n", pDragSizeInfo->ptNow.x, pDragSizeInfo->ptNow.y);
            
            SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(wID, DSN_DRAGGING), (LPARAM)hWnd);
            break;

        case WM_LBUTTONUP:
            /* All done.
            */
            SetCapture(NULL);
            goto EndAdjust;

        case WM_RBUTTONDOWN:
            goto AbortAdjust;

        default:
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            break;
        }
    }

EndAdjust:
        SendMessage(hwndParent, WM_COMMAND, MAKEWPARAM(wID, DSN_ENDDRAG), (LPARAM)hWnd);
    pDragSizeInfo->bDragging = FALSE;
}


/* Ask the parent to paint the window.
*/
void NEAR PASCAL PaintDragSizeWnd(HWND hWnd, PDRAGSIZEINFO pDragSizeInfo)
{
    PAINTSTRUCT ps;
    DRAWITEMSTRUCT dis;
    HDC hDC;
    HFONT hOldFont = NULL;

    if (!pDragSizeInfo)
    {
        return;
    }

    hDC = BeginPaint(hWnd, &ps);

    if (pDragSizeInfo->hFont)
    {
        hOldFont = (HFONT) SelectObject(hDC, pDragSizeInfo->hFont);
    }

    /* Fill in the DRAWITEMSTRUCT.  Note that some of the fields are
    ** undefined.
    */
    dis.CtlID    = GetDlgCtrlID(hWnd);
    dis.hwndItem = hWnd;
    dis.hDC      = hDC;
    GetClientRect(hWnd, &dis.rcItem);
    dis.itemData = pDragSizeInfo->lpData;

    SendMessage(GetParent(hWnd), WM_DRAWITEM, GetDlgCtrlID(hWnd),
        (LPARAM)(LPDRAWITEMSTRUCT)&dis);

    if (hOldFont)
    {
        SelectObject(hDC, hOldFont);
    }

    EndPaint(hWnd, &ps);
}


LRESULT CALLBACK DragSizeWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
#define lpCreate ((LPCREATESTRUCT)lParam)

    PDRAGSIZEINFO pDragSizeInfo;

    pDragSizeInfo = GETWINDOWPOINTER(hWnd, PDRAGSIZEINFO);

    switch (uMessage)
    {
    case WM_NCCREATE:
                SendMessage(lpCreate->hwndParent, WM_COMMAND,
                        MAKEWPARAM((SHORT)(lpCreate->hMenu), DSN_NCCREATE), (LPARAM)hWnd);
        break;

    case WM_CREATE:
        InitDragSizeWnd(hWnd, (LPCREATESTRUCT)lParam);
        break;

    case WM_DESTROY:
        if (pDragSizeInfo)
        {
            FREEWINDOWPOINTER(pDragSizeInfo);
            SETWINDOWPOINTER(hWnd, PDRAGSIZEINFO, NULL);
        }
        break;

        case WM_LBUTTONDOWN: {
                    POINT pt;
                    LPARAM2POINT( lParam, &pt );
                    DragSize(hWnd, pDragSizeInfo, pt);
                }
                break;

    case WM_PAINT:
        PaintDragSizeWnd(hWnd, pDragSizeInfo);
        return(0);

    case WM_SETFONT:
        if (!pDragSizeInfo)
        {
            return(1L);
        }
        pDragSizeInfo->hFont = (HFONT)wParam;

        if (LOWORD(lParam))
        {
            InvalidateRect(hWnd, NULL, TRUE);
            UpdateWindow(hWnd);
        }
        return(0L);

    case WM_GETFONT:
        if (!pDragSizeInfo)
        {
                        return(LRESULT)(NULL);
        }
        return(MAKELRESULT(pDragSizeInfo->hFont, 0));

        case DSM_DRAGPOS: {
                    LPPOINT lppt = (LPPOINT)lParam;

                    if (!pDragSizeInfo || !pDragSizeInfo->bDragging || lppt == NULL)
                    {
                            return(-1L);
                    }

                    *lppt = pDragSizeInfo->ptNow;

                    return(0);
                }
        break;

    default:
        break;
    }

    return(DefWindowProc(hWnd, uMessage, wParam, lParam));
}


BOOL FAR PASCAL InitDragSizeClass(void)
{
    WNDCLASS rClass;

    if (GetClassInfo(HINST_THISDLL, szDragSizeClass, &rClass))
    {
        return(TRUE);
    }

    rClass.style         = 0;
    rClass.lpfnWndProc   = DragSizeWndProc;
    rClass.cbClsExtra    = 0;
    rClass.cbWndExtra    = sizeof(PDRAGSIZEINFO);
    rClass.hInstance     = HINST_THISDLL;
    rClass.hIcon         = NULL;
    rClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
    rClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
    rClass.lpszMenuName  = NULL;
    rClass.lpszClassName = szDragSizeClass;

    return(RegisterClass(&rClass));
}


HWND WINAPI CreateDragSizeWindow(LONG style, int x, int y, int wid, int hgt, HWND hwndParent, LONG wID)
{
    /* Create a default window and return
    */
    return(CreateWindow(szDragSizeClass, g_szNULL, style,
        x, y, wid, hgt, hwndParent, (HMENU)IntToPtr(wID), HINST_THISDLL, NULL));
}
