#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winlib/winlib.h>

#include "mapplot.h"
#include "map.h"
#include "wdb-ii.h"
#include "window.h"


typedef struct {
       double minLon;
       double maxLon;
       double minLat;
       double maxLat;
} INPUT_COORD;


BOOL CALLBACK InputMinMaxProc(HWND hDlg, UINT msg,
               WPARAM wParam, LPARAM lParam)
{
       static INPUT_COORD coord, *pCoord;
       char tmp[80];

       switch (msg) {
               case WM_INITDIALOG:
                       pCoord = (INPUT_DATA*)lParam;
                       coord = *pCoord;
                       sprintf(tmp, "%.2f", coord.minLon);
                       SetDlgItemText(hDlg, IDC_MINLON, tmp);
                       sprintf(tmp, "%.2f", coord.maxLon);
                       SetDlgItemText(hDlg, IDC_MAXLON, tmp);
                       sprintf(tmp, "%.2f", coord.minLat);
                       SetDlgItemText(hDlg, IDC_MINLAT, tmp);
                       sprintf(tmp, "%.2f", coord.maxLat);
                       SetDlgItemText(hDlg, IDC_MAXLAT, tmp);
                       SetFocus(GetDlgItem(hDlg, IDC_MINLON));
                       return FALSE;

               case WM_COMMAND :
                       switch (LOWORD (wParam)) {
                               case IDOK:
                                       GetDlgItemText(hDlg, IDC_MINLON, tmp, 80);
                                       coord.minLon = atof(tmp);
                                       GetDlgItemText(hDlg, IDC_MAXLON, tmp, 80);
                                       coord.maxLon = atof(tmp);
                                       GetDlgItemText(hDlg, IDC_MINLAT, tmp, 80);
                                       coord.minLat = atof(tmp);
                                       GetDlgItemText(hDlg, IDC_MAXLAT, tmp, 80);
                                       coord.maxLat = atof(tmp);
                                       *pCoord = coord;
                                       EndDialog(hDlg, 1);
                                       return TRUE;

                               case IDCANCEL:
                                       EndDialog (hDlg, 0);
                                       return TRUE ;
                       }
                       break;
       }
       return FALSE;
}


BOOL GetMinMax(VARS *v)
{
       static char input[512];
       INPUT_COORD coord;

       coord.minLon = v->minMax.minLon;
       coord.maxLon = v->minMax.maxLon;
       coord.minLat = v->minMax.minLat;
       coord.maxLat = v->minMax.maxLat;

       if (DialogBoxParam(v->hInst, "MinMaxDlg", v->hwndMain,
                       InputMinMaxProc, (LPARAM)&coord)) {
               v->minMax.minLon = coord.minLon;
               v->minMax.maxLon = coord.maxLon;
               v->minMax.minLat = coord.minLat;
               v->minMax.maxLat = coord.maxLat;
               return TRUE;
       }
       return FALSE;
}


void AdjScrollPos(VARS *v)
{
       SCROLLINFO si;

       si.cbSize = sizeof (si);
       si.fMask = SIF_POS;
       si.nPos  = (int)(v->origLon);
       SetScrollInfo (v->hwndCont, SB_HORZ, &si, TRUE);
       si.nPos  = (int)(-v->origLat);
       SetScrollInfo (v->hwndCont, SB_VERT, &si, TRUE);
}


LRESULT CALLBACK EditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
       static VARS *v = NULL;
       static WNDPROC oldProc = NULL;
       SCROLLINFO si;
       char s[80];
       int i;
       static int shift = FALSE;

       if (! v)
               v = (VARS *)GetWindowLong(GetParent(hWnd), 0);

       if (! oldProc)
               oldProc = (WNDPROC)GetWindowLong(hWnd, GWL_USERDATA);

       switch(msg) {
               case WM_SETFOCUS:
                       v->oldFocus = hWnd;
                       break;

               case WM_KEYDOWN:
                       switch (wParam) {
                               case VK_RETURN:
                                       GetWindowText(v->hwndEdit[0], s, 80);
                                       v->origLon = atof(s);
                                       if ((v->origLon < -180.) || (v->origLon > 180.)) {
                                               v->origLon = (v->origLon < -180.) ? -180. : 180.;
                                               sprintf(s, "%.2f", v->origLon);
                                               SetWindowText(v->hwndEdit[0], s);
                                       }

                                       GetWindowText(v->hwndEdit[1], s, 80);
                                       v->origLat = atof(s);
                                       if ((v->origLat < -90.) || (v->origLat > 90.)) {
                                               v->origLat = (v->origLat < -90.) ? -90. : 90.;
                                               sprintf(s, "%.2f", v->origLat);
                                               SetWindowText(v->hwndEdit[1], s);
                                       }

                                       GetWindowText(v->hwndEdit[2], s, 80);
                                       v->zoom = atof(s);
                                       if (v->zoom <= 0.) {
                                               v->zoom = 1.;
                                               sprintf(s, "%.2f", v->zoom);
                                               SetWindowText(v->hwndEdit[2], s);
                                       }

                                       AdjScrollPos(v);
                                       InvalidateRect(v->hwndCont, NULL, FALSE);
                                       UpdateWindow(v->hwndCont);
                                       return 0;

                               case VK_TAB:
                                       for (i = 0; i < 3; i++)  {
                                               if (GetFocus() == v->hwndEdit[i])
                                                       break;
                                       }
                                       if (! shift)
                                               i = (i == 2) ? 0: i + 1;
                                       else
                                               i = (i == 0) ? 2: i - 1;
                                       SetFocus(v->hwndEdit[i]);
                                       return 0;

                               case VK_SHIFT:
                                       shift = TRUE;
                                       return 0;

                               case VK_PRIOR:
                                       v->zoom += 1.;
                                       sprintf(s, "%.2f", v->zoom);
                                       SetWindowText(v->hwndEdit[2], s);
                                       InvalidateRect(v->hwndCont, NULL, FALSE);
                                       return 0;

                               case VK_NEXT:
                                       if ((v->zoom - 1.) > 0.) {
                                               v->zoom -= 1;
                                               sprintf(s, "%.2f", v->zoom);
                                               SetWindowText(v->hwndEdit[2], s);
                                               InvalidateRect(v->hwndCont, NULL, FALSE);
                                       }
                                       return 0;
                       }
                       break;

               case WM_KEYUP:
                       switch (wParam) {
                               case VK_SHIFT:
                                       shift = FALSE;
                                       return 0;
                       }
                       break;
       }

       return CallWindowProc(oldProc, hWnd, msg, wParam, lParam);
}


void CreateChildren(VARS *v, HWND hwnd)
{
       int i;
       HFONT hfnt = GetStockObject(ANSI_VAR_FONT);
       char *title[3] = {"Lon", "Lat", "Zoom"};
       WNDPROC oldProc;

       v->hwndCont = CreateWindowEx(
               WS_EX_CLIENTEDGE, "ContWndClass", (LPCTSTR)NULL,
               WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL,
               0, 0, 0, 0,
               hwnd, NULL, v->hInst, (LPVOID)v);

       for (i = 0; i < 3; i++) {
               v->hwndLabel[i] = CreateWindowEx(
                       0L, "STATIC", title[i],
                       WS_CHILD | WS_VISIBLE | SS_RIGHT,
                       0, 0, 0, 0,
                       hwnd, NULL, v->hInst, NULL);

               SendMessage(v->hwndLabel[i], WM_SETFONT, (WPARAM)hfnt,
                       MAKELPARAM(1, 0));

               v->hwndEdit[i] = CreateWindowEx(
                       WS_EX_CLIENTEDGE, "EDIT", (LPCTSTR)NULL,
                       WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL,
                       0, 0, 0, 0,
                       hwnd, NULL, v->hInst, NULL);

               oldProc = (WNDPROC)GetWindowLong(v->hwndEdit[i], GWL_WNDPROC);
               SetWindowLong(v->hwndEdit[i], GWL_WNDPROC, (LONG)EditProc);
               SetWindowLong(v->hwndEdit[i], GWL_USERDATA, (LONG)oldProc);

               SendMessage(v->hwndEdit[i], WM_SETFONT, (WPARAM)hfnt,
                       MAKELPARAM(1, 0));
       }
}


void ResizeChildren(VARS *v)
{
       RECT rect;
       int i, offs = 5;

       GetClientRect(v->hwndMain, &rect);

       MoveWindow(v->hwndCont,
               0, 0, rect.right, rect.bottom - (v->statusHeight + 42),
               TRUE);

       for (i = 0; i < 3; i++) {
               MoveWindow(v->hwndLabel[i],
                               offs, rect.bottom - v->statusHeight - 32 + 3,
                               40, 24, TRUE);

               MoveWindow(v->hwndEdit[i],
                               offs + 50, rect.bottom - v->statusHeight - 32,
                               50, 24, TRUE);
               offs += 130;
       }
}


LRESULT CALLBACK ContWndProc(HWND hwnd, UINT msg, WPARAM wParam,
               LPARAM lParam)
{
       int iVertPos, iHorzPos;
       HDC hdc;
       PAINTSTRUCT ps;
       SCROLLINFO si;
       RECT rect;
       static VARS *v;
       HWND hwndParent;
       POINT mousePt, origPt;
       double latRad, lonRad;
       int i;
       BOOL r;
       char tmp[80];

       switch (msg) {
               case WM_CREATE:
                       v = (VARS*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
                       v->hwndCont = hwnd;
                       AdjScrollPos(v);
                       break;

               case WM_VSCROLL:
                       // Get all the vertical scroll bar information

                       si.cbSize = sizeof(si);
                       si.fMask  = SIF_ALL;
                       GetScrollInfo (hwnd, SB_VERT, &si);

                       // Save the position for comparison later on

                       iVertPos = si.nPos;

                       switch (LOWORD (wParam)) {
                               case SB_TOP:
                                       si.nPos = si.nMin;
                                       break;

                               case SB_BOTTOM:
                                       si.nPos = si.nMax;
                                       break;

                               case SB_LINEUP:
                                       si.nPos -= 1;
                                       break;

                               case SB_LINEDOWN:
                                       si.nPos += 1;
                                       break;

                               case SB_PAGEUP:
                                       si.nPos -= si.nPage;
                                       break;

                               case SB_PAGEDOWN:
                                       si.nPos += si.nPage;
                                       break;

                               case SB_THUMBTRACK:
                                       v->origLat = -((double)si.nTrackPos);
                                       sprintf(tmp, "%.2f", v->origLat);
                                       SetWindowText(v->hwndEdit[1], tmp);
                                       return 0;

                               case SB_THUMBPOSITION:
                                       si.nPos = (short int)HIWORD(wParam);
                                       break;

                               default:
                                       break;
                       }
                       // Set the position and then retrieve it.  Due to adjustments
                       // by Windows it may not be the same as the value set.

                       si.fMask = SIF_POS;
                       SetScrollInfo (hwnd, SB_VERT, &si, TRUE);
                       GetScrollInfo (hwnd, SB_VERT, &si);

                       // If the position has changed, scroll the window

                       if (si.nPos != iVertPos) {
                               v->origLat = -((double)si.nPos);
                               sprintf(tmp, "%.2f", v->origLat);
                               SetWindowText(v->hwndEdit[1], tmp);
                               InvalidateRect(hwnd, NULL, FALSE);
                       }
                       break;

               case WM_HSCROLL:
                       // Get all the horizontal scroll bar information

                       si.cbSize = sizeof (si);
                       si.fMask  = SIF_ALL;

                       // Save the position for comparison later on

                       GetScrollInfo (hwnd, SB_HORZ, &si);
                       iHorzPos = si.nPos;

                       switch (LOWORD (wParam)) {
                               case SB_LINELEFT:
                                       si.nPos -= 1;
                                       break;

                               case SB_LINERIGHT:
                                       si.nPos += 1;
                                       break;

                               case SB_PAGELEFT:
                                       si.nPos -= si.nPage;
                                       break;

                               case SB_PAGERIGHT:
                                       si.nPos += si.nPage;
                                       break;

                               case SB_THUMBTRACK:
                                       v->origLon = (double)si.nTrackPos;
                                       sprintf(tmp, "%.2f", v->origLon);
                                       SetWindowText(v->hwndEdit[0], tmp);
                                       return 0;

                               case SB_THUMBPOSITION:
                                       si.nPos = (short int)HIWORD(wParam);
                                       break;

                               default:
                                       break;
                       }
                       // Set the position and then retrieve it.  Due to adjustments
                       // by Windows it may not be the same as the value set

                       si.fMask = SIF_POS;
                       SetScrollInfo (hwnd, SB_HORZ, &si, TRUE);
                       GetScrollInfo (hwnd, SB_HORZ, &si);

                       // If the position has changed, scroll the window

                       if (si.nPos != iHorzPos) {
                               v->origLon = (double)si.nPos;
                               sprintf(tmp, "%.2f", v->origLon);
                               SetWindowText(v->hwndEdit[0], tmp);
                               InvalidateRect(hwnd, NULL, FALSE);
                       }
                       break;

               case WM_LBUTTONDOWN:
                       hdc = GetDC(hwnd);
                       SetupWorld(v, hdc);

                       mousePt.x = LOWORD(lParam);
                       mousePt.y = HIWORD(lParam);
                       DPtoLP(hdc, &mousePt, 1);

                       if (v->project == PLATE_CARREE) {
                               v->origLon = (double)mousePt.x / 100.;
                               v->origLat = (double)mousePt.y / 100.;
                       } else {
                               if (v->InvTrans[v->project]((double)mousePt.x / v->scale,
                                               (double)mousePt.y / v->scale,
                                               &lonRad, &latRad)) {
                                       ReleaseDC(hwnd, hdc);
                                       break;
                               }
                               v->origLon = lonRad * R2D;
                               v->origLat = latRad * R2D;
                       }

                       sprintf(tmp, "%.2f", v->origLon);
                       SetWindowText(v->hwndEdit[0], tmp);
                       sprintf(tmp, "%.2f", v->origLat);
                       SetWindowText(v->hwndEdit[1], tmp);

                       ReleaseDC(hwnd, hdc);
                       InvalidateRect(hwnd, NULL, FALSE);
                       break;

               case WM_PAINT:
                       si.fMask  = SIF_RANGE | SIF_PAGE;
                       si.cbSize = sizeof(si);

                       // Set vertical scroll bar range and page size
                       si.nMin   = -89;
                       si.nPage  = (int)(89. / v->zoom);
                       si.nMax   = 89 + (si.nPage - 1);
                       SetScrollInfo (v->hwndCont, SB_VERT, &si, TRUE);

                       // Set horizontal scroll bar range and page size
                       si.nMin   = -180;
                       si.nPage  = (int)(180. / v->zoom);
                       si.nMax   = 180 + (si.nPage - 1);
                       SetScrollInfo(v->hwndCont, SB_HORZ, &si, TRUE);

                       // Show scroll bars in case they were hidden
                       ShowScrollBar(v->hwndCont, SB_VERT, TRUE);
                       ShowScrollBar(v->hwndCont, SB_HORZ, TRUE);

                       // Make sure edit boxes are redrawn before painting the map
                       for (i = 0; i < 3; i++) {
                               InvalidateRect(v->hwndLabel[i], NULL, TRUE);
                               UpdateWindow(v->hwndLabel[i]);
                               InvalidateRect(v->hwndEdit[i], NULL, TRUE);
                               UpdateWindow(v->hwndEdit[i]);
                       }

                       hdc = BeginPaint(hwnd, &ps);
                       DrawMap(v, hdc);
                       EndPaint(hwnd, &ps);
                       return 0;

               default:
                       return DefWindowProc(hwnd, msg, wParam, lParam);
       }
       return 0;
}


BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT msg,
               WPARAM wParam, LPARAM lParam)
{
       switch (msg) {
               case WM_INITDIALOG:
                       return TRUE;

               case WM_COMMAND :
                       switch (LOWORD (wParam)) {
                               case IDOK:
                               case IDCANCEL:
                                       EndDialog (hDlg, 0);
                                       return TRUE ;
                       }
                       break;
       }
       return FALSE;
}


LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam,
               LPARAM lParam)
{
       static VARS *v;
       HDC hdc;
       PAINTSTRUCT ps;
       RECT rect;
       int i, offs = 5;
       BOOL r;
       HFONT hfnt;
       WNDPROC oldProc;
       static CHOOSECOLOR cc ;
       static COLORREF crCustColors[16];
       char tmp[80];

       int iVertPos, iHorzPos;
       WORD id, wScrollNotify;
       static int cxClient, cyClient, iMaxWidth;
       SCROLLINFO si;
       char *p;

       switch (msg) {
               case WM_CREATE:
                       v = (VARS *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
                       SetWindowLong(hwnd, 0, (LONG)v);

                       v->hwndStatus = CreateStatusWnd(v->hInst, hwnd, 2);
                       GetWindowRect(v->hwndStatus, &rect);
                       v->statusHeight = rect.bottom - rect.top;

                       CreateChildren(v, hwnd);

                       sprintf(tmp, "%.2f", v->origLon);
                       SetWindowText(v->hwndEdit[0], tmp);
                       sprintf(tmp, "%.2f", v->origLat);
                       SetWindowText(v->hwndEdit[1], tmp);
                       sprintf(tmp, "%.2f", v->zoom);
                       SetWindowText(v->hwndEdit[2], tmp);

                       SetFocus(v->hwndEdit[0]);
                       return 0;

               case WM_SIZE:
                       ResizeChildren(v);
                       SendMessage(v->hwndStatus, WM_SIZE, wParam, lParam);
                       SetStatusParts(v->hwndStatus, 2);
                       return 0;

               case WM_COMMAND:
                       id = LOWORD(wParam);

                       switch (id) {
                               case IDM_OPEN_WDB:
                                       AddWDBIIMap(v);
                                       return 0;

                               case IDM_EXIT:
                                       PostQuitMessage(0);
                                       return 0;

                               case IDM_RESET:
                                       if (! v->wdbIIMaps)
                                               return 0;
                                       DeleteWDBIIMaps(v);
                                       InvalidateRect(v->hwndCont, NULL, FALSE);
                                       UpdateWindow(v->hwndCont);
                                       return 0;

                               case IDM_PLATE_CARREE:
                               case IDM_MERCATOR:
                               case IDM_ROBINSON:
                               case IDM_HAMMER:
                               case IDM_ORTHO:
                                       CheckMenuItem(v->hMenu, IDM_PLATE_CARREE,
                                               MF_UNCHECKED);
                                       CheckMenuItem(v->hMenu, IDM_MERCATOR,
                                               MF_UNCHECKED);
                                       CheckMenuItem(v->hMenu, IDM_ROBINSON,
                                               MF_UNCHECKED);
                                       CheckMenuItem(v->hMenu, IDM_HAMMER,
                                               MF_UNCHECKED);
                                       CheckMenuItem(v->hMenu, IDM_ORTHO,
                                               MF_UNCHECKED);
                                       CheckMenuItem(v->hMenu, id, MF_CHECKED);
                                       v->project = id - 30000;
                                       InvalidateRect(v->hwndCont, NULL, FALSE);
                                       UpdateWindow(v->hwndCont);
                                       return 0;

                               case IDM_SHW_GRID_SIZE:
                                       sprintf(tmp, "%d", v->gridDeg);
                                       if (! (p = GetInput(hwnd, "Grid Size", tmp, 250)))
                                               return 0;
                                       v->gridDeg = atoi(p);
                                       if (v->gridDeg <= 0)
                                               v->gridDeg = 1;
                                       InvalidateRect(v->hwndCont, NULL, FALSE);
                                       UpdateWindow(v->hwndCont);
                                       return 0;

                               case IDM_SHW_MINMAX:
                                       if (GetMinMax(v)) {
                                               InvalidateRect(v->hwndCont, NULL, FALSE);
                                               UpdateWindow(v->hwndCont);
                                       }
                                       return 0;

                               case IDM_SHW_COAST:
                               case IDM_SHW_COUNTRY:
                               case IDM_SHW_STATE:
                               case IDM_SHW_ISLAND:
                               case IDM_SHW_LAKE:
                               case IDM_SHW_RIVER:
                               case IDM_SHW_GRID:
                               case IDM_SHW_DEGREES:
                                       if (GetMenuState(v->hMenu, id, MF_BYCOMMAND) & MF_CHECKED) {
                                               CheckMenuItem(v->hMenu, id, MF_UNCHECKED);
                                               v->shwFeatures &= ~(1 << (id - 200));
                                       } else {
                                               CheckMenuItem(v->hMenu, id, MF_CHECKED);
                                               v->shwFeatures |= (1 << (id - 200));
                                       }
                                       InvalidateRect(v->hwndCont, NULL, FALSE);
                                       UpdateWindow(v->hwndCont);
                                       return 0;

                               case IDM_SHW_WDB_BDY1:
                               case IDM_SHW_WDB_BDY2:
                               case IDM_SHW_WDB_BDY3:
                                       if (GetMenuState(v->hMenu, id, MF_BYCOMMAND) & MF_CHECKED) {
                                               CheckMenuItem(v->hMenu, id, MF_UNCHECKED);
                                               v->wdbShwBdyFeatures[id - 300] = 0;
                                       } else {
                                               CheckMenuItem(v->hMenu, id, MF_CHECKED);
                                               v->wdbShwBdyFeatures[id - 300] = 1;
                                       }

                                       if (v->wdbIIMode && WDBIILoaded(v, "bdy")) {
                                               InvalidateRect(v->hwndCont, NULL, FALSE);
                                               UpdateWindow(v->hwndCont);
                                       }
                                       return 0;

                               case IDM_SHW_WDB_CIL1:
                               case IDM_SHW_WDB_CIL2:
                               case IDM_SHW_WDB_CIL3:
                               case IDM_SHW_WDB_CIL4:
                               case IDM_SHW_WDB_CIL6:
                               case IDM_SHW_WDB_CIL7:
                               case IDM_SHW_WDB_CIL8:
                               case IDM_SHW_WDB_CIL9:
                               case IDM_SHW_WDB_CIL10:
                               case IDM_SHW_WDB_CIL13:
                               case IDM_SHW_WDB_CIL14:
                               case IDM_SHW_WDB_CIL15:
                                       if (GetMenuState(v->hMenu, id, MF_BYCOMMAND) & MF_CHECKED) {
                                               CheckMenuItem(v->hMenu, id, MF_UNCHECKED);
                                               v->wdbShwCilFeatures[id - 400] = 0;
                                       } else {
                                               CheckMenuItem(v->hMenu, id, MF_CHECKED);
                                               v->wdbShwCilFeatures[id - 400] = 1;
                                       }
                                       if (v->wdbIIMode && WDBIILoaded(v, "cil")) {
                                               InvalidateRect(v->hwndCont, NULL, FALSE);
                                               UpdateWindow(v->hwndCont);
                                       }
                                       return 0;

                               case IDM_SHW_WDB_RIV1:
                               case IDM_SHW_WDB_RIV2:
                               case IDM_SHW_WDB_RIV3:
                               case IDM_SHW_WDB_RIV4:
                               case IDM_SHW_WDB_RIV5:
                               case IDM_SHW_WDB_RIV6:
                               case IDM_SHW_WDB_RIV7:
                               case IDM_SHW_WDB_RIV8:
                               case IDM_SHW_WDB_RIV10:
                               case IDM_SHW_WDB_RIV11:
                               case IDM_SHW_WDB_RIV12:
                                       if (GetMenuState(v->hMenu, id, MF_BYCOMMAND) & MF_CHECKED) {
                                               CheckMenuItem(v->hMenu, id, MF_UNCHECKED);
                                               v->wdbShwRivFeatures[id - 500] = 0;
                                       } else {
                                               CheckMenuItem(v->hMenu, id, MF_CHECKED);
                                               v->wdbShwRivFeatures[id - 500] = 1;
                                       }
                                       if (v->wdbIIMode && WDBIILoaded(v, "riv")) {
                                               InvalidateRect(v->hwndCont, NULL, FALSE);
                                               UpdateWindow(v->hwndCont);
                                       }
                                       return 0;

                               case IDM_CLR_COAST:
                               case IDM_CLR_COUNTRY:
                               case IDM_CLR_STATE:
                               case IDM_CLR_ISLAND:
                               case IDM_CLR_LAKE:
                               case IDM_CLR_RIVER:
                               case IDM_CLR_BKGRND:
                               case IDM_CLR_GRID:
                                       cc.lStructSize    = sizeof (CHOOSECOLOR);
                                       cc.hwndOwner      = hwnd;
                                       cc.hInstance      = (HWND)v->hInst;
                                       cc.rgbResult      = v->colors[id - 600];
                                       cc.lpCustColors   = crCustColors;
                                       cc.Flags          = CC_RGBINIT | CC_FULLOPEN;
                                       cc.lCustData      = 0;
                                       cc.lpfnHook       = NULL;
                                       cc.lpTemplateName = NULL;
                                       if (ChooseColor(&cc)) {
                                               v->colors[id - 600] = cc.rgbResult;
                                               InvalidateRect(v->hwndCont, NULL, FALSE);
                                               UpdateWindow(v->hwndCont);
                                       }
                                       return 0;

                               case IDM_CLR_RESET:
                                       memcpy(v->colors, v->defColors, sizeof(v->defColors));
                                       InvalidateRect(v->hwndCont, NULL, FALSE);
                                       UpdateWindow(v->hwndCont);
                                       return 0;
/*
                               case ID_SB_PAGEUP:
                               case ID_SB_PAGEDOWN:
                               case ID_SB_TOP:
                               case ID_SB_BOTTOM:
                                       switch (id) {
                                       case ID_SB_PAGEUP:
                                       wScrollNotify = SB_PAGEUP;
                                               break;
                                       case ID_SB_PAGEDOWN:
                                       wScrollNotify = SB_PAGEDOWN;
                                       break;
                               case ID_SB_TOP:
                                       wScrollNotify = SB_TOP;
                                                       break;
                                               case ID_SB_BOTTOM:
                                                       wScrollNotify = SB_BOTTOM;
                                       break;
                       }

                                       SendMessage(v->hwndCont, WM_VSCROLL,
                                       MAKELONG(wScrollNotify, 0), 0L);
                                       return 0;
*/
                               case IDM_ABOUT:
                                       DialogBox (v->hInst, "AboutBox", v->hwndMain,
                                                       AboutDlgProc);
                                       return 0;

                               default:
                                       break;
                       }
                       break;

               case WM_ACTIVATE:
                       if (LOWORD(wParam) != WA_INACTIVE) {
                               if (v->oldFocus)
                                       SetFocus(v->oldFocus);
                       }
                       return 0;

               case WM_DESTROY:
                       DoExitStuff(v);
                       PostQuitMessage(0);
                       return 0;
       }

       return DefWindowProc(hwnd, msg, wParam, lParam);
}