[CHARMAP]
[reactos.git] / reactos / base / applications / charmap / map.c
index 679153d..8cbda5a 100644 (file)
-/*\r
- * PROJECT:     ReactOS Character Map\r
- * LICENSE:     GPL - See COPYING in the top level directory\r
- * FILE:        base/applications/charmap/map.c\r
- * PURPOSE:     class implementation for painting glyph region\r
- * COPYRIGHT:   Copyright 2007 Ged Murphy <gedmurphy@reactos.org>\r
- *\r
- */\r
-\r
-#include <precomp.h>\r
-\r
-static const TCHAR szMapWndClass[] = TEXT("FontMapWnd");\r
-static const TCHAR szLrgCellWndClass[] = TEXT("LrgCellWnd");\r
-\r
-static VOID\r
-TagFontToCell(PCELL pCell,\r
-              TCHAR ch)\r
-{\r
-    pCell->ch = ch;\r
-}\r
-\r
-\r
-static VOID\r
-SetGrid(PMAP infoPtr)\r
-{\r
-    INT x, y;\r
-\r
-    for (y = 0; y < YCELLS; y++)\r
-    for (x = 0; x < XCELLS; x++)\r
-    {\r
-        infoPtr->Cells[y][x].CellExt.left = x * infoPtr->CellSize.cx + 1;\r
-        infoPtr->Cells[y][x].CellExt.top = y * infoPtr->CellSize.cy + 1;\r
-        infoPtr->Cells[y][x].CellExt.right = (x + 1) * infoPtr->CellSize.cx + 2;\r
-        infoPtr->Cells[y][x].CellExt.bottom = (y + 1) * infoPtr->CellSize.cy + 2;\r
-\r
-        CopyRect(&infoPtr->Cells[y][x].CellInt,\r
-                 &infoPtr->Cells[y][x].CellExt);\r
-\r
-        InflateRect(&infoPtr->Cells[y][x].CellInt,\r
-                    -1,\r
-                    -1);\r
-    }\r
-}\r
-\r
-static VOID\r
-DrawActiveCell(PMAP infoPtr,\r
-               HDC hdc)\r
-{\r
-    Rectangle(hdc,\r
-              infoPtr->pActiveCell->CellInt.left,\r
-              infoPtr->pActiveCell->CellInt.top,\r
-              infoPtr->pActiveCell->CellInt.right,\r
-              infoPtr->pActiveCell->CellInt.bottom);\r
-\r
-}\r
-\r
-\r
-static VOID\r
-DrawGrid(PMAP infoPtr,\r
-         HDC hdc)\r
-{\r
-    INT x, y;\r
-\r
-    for (y = 0; y < YCELLS; y++)\r
-    for (x = 0; x < XCELLS; x++)\r
-    {\r
-        Rectangle(hdc,\r
-                  infoPtr->Cells[y][x].CellExt.left,\r
-                  infoPtr->Cells[y][x].CellExt.top,\r
-                  infoPtr->Cells[y][x].CellExt.right,\r
-                  infoPtr->Cells[y][x].CellExt.bottom);\r
-    }\r
-\r
-    if (infoPtr->pActiveCell)\r
-        DrawActiveCell(infoPtr,\r
-                       hdc);\r
-}\r
-\r
-\r
-static VOID\r
-FillGrid(PMAP infoPtr,\r
-         HDC hdc)\r
-{\r
-    HFONT hOldFont;\r
-    TCHAR ch;\r
-    INT x, y;\r
-\r
-    hOldFont = SelectObject(hdc,\r
-                            infoPtr->hFont);\r
-\r
-    for (y = 0; y < YCELLS; y++)\r
-    for (x = 0; x < XCELLS; x++)\r
-    {\r
-        ch = (TCHAR)((256 * infoPtr->iPage) + (XCELLS * y) + x);\r
-\r
-        TagFontToCell(&infoPtr->Cells[y][x], ch);\r
-\r
-        DrawText(hdc,\r
-                 &ch,\r
-                 1,\r
-                 &infoPtr->Cells[y][x].CellInt,\r
-                 DT_CENTER | DT_VCENTER | DT_SINGLELINE);\r
-    }\r
-\r
-    SelectObject(hdc,\r
-                 hOldFont);\r
-}\r
-\r
-\r
-static BOOL\r
-CreateLargeCell(PMAP infoPtr)\r
-{\r
-    RECT rLarge;\r
-\r
-    CopyRect(&rLarge,\r
-             &infoPtr->pActiveCell->CellExt);\r
-\r
-    MapWindowPoints(infoPtr->hMapWnd,\r
-                    infoPtr->hParent,\r
-                    (LPPOINT)&rLarge,\r
-                    2);\r
-\r
-    InflateRect(&rLarge,\r
-                XLARGE - XCELLS,\r
-                YLARGE - YCELLS);\r
-\r
-    infoPtr->hLrgWnd = CreateWindowEx(0,\r
-                                      szLrgCellWndClass,\r
-                                      NULL,\r
-                                      WS_CHILDWINDOW | WS_VISIBLE,\r
-                                      rLarge.left,\r
-                                      rLarge.top,\r
-                                      rLarge.right - rLarge.left,\r
-                                      rLarge.bottom - rLarge.top,\r
-                                      infoPtr->hParent,\r
-                                      NULL,\r
-                                      hInstance,\r
-                                      infoPtr);\r
-    if (!infoPtr->hLrgWnd)\r
-        return FALSE;\r
-\r
-    return TRUE;\r
-}\r
-\r
-\r
-static VOID\r
-MoveLargeCell(PMAP infoPtr)\r
-{\r
-    RECT rLarge;\r
-\r
-    CopyRect(&rLarge,\r
-             &infoPtr->pActiveCell->CellExt);\r
-\r
-    MapWindowPoints(infoPtr->hMapWnd,\r
-                    infoPtr->hParent,\r
-                    (LPPOINT)&rLarge,\r
-                    2);\r
-\r
-    InflateRect(&rLarge,\r
-                XLARGE - XCELLS,\r
-                YLARGE - YCELLS);\r
-\r
-    MoveWindow(infoPtr->hLrgWnd,\r
-               rLarge.left,\r
-               rLarge.top,\r
-               rLarge.right - rLarge.left,\r
-               rLarge.bottom - rLarge.top,\r
-               TRUE);\r
-\r
-    InvalidateRect(infoPtr->hLrgWnd,\r
-                   NULL,\r
-                   TRUE);\r
-}\r
-\r
-\r
-static VOID\r
-SetFont(PMAP infoPtr,\r
-        LPTSTR lpFontName)\r
-{\r
-    HDC hdc;\r
-\r
-    if (infoPtr->hFont)\r
-        DeleteObject(infoPtr->hFont);\r
-\r
-    ZeroMemory(&infoPtr->CurrentFont,\r
-               sizeof(LOGFONT));\r
-\r
-    hdc = GetDC(infoPtr->hMapWnd);\r
-    infoPtr->CurrentFont.lfHeight = GetDeviceCaps(hdc,\r
-                                                  LOGPIXELSY) / 5;\r
-    ReleaseDC(infoPtr->hMapWnd, hdc);\r
-\r
-    infoPtr->CurrentFont.lfCharSet =  DEFAULT_CHARSET;\r
-    lstrcpy(infoPtr->CurrentFont.lfFaceName,\r
-            lpFontName);\r
-\r
-    infoPtr->hFont = CreateFontIndirect(&infoPtr->CurrentFont);\r
-\r
-    InvalidateRect(infoPtr->hMapWnd,\r
-                   NULL,\r
-                   TRUE);\r
-}\r
-\r
-\r
-static LRESULT\r
-NotifyParentOfSelection(PMAP infoPtr,\r
-                        UINT code,\r
-                        TCHAR ch)\r
-{\r
-    LRESULT Ret = 0;\r
-\r
-    if (infoPtr->hParent != NULL)\r
-    {\r
-        MAPNOTIFY mnmh;\r
-\r
-        mnmh.hdr.hwndFrom = infoPtr->hMapWnd;\r
-        mnmh.hdr.idFrom = GetWindowLongPtr(infoPtr->hMapWnd,\r
-                                           GWLP_ID);\r
-        mnmh.hdr.code = code;\r
-\r
-        mnmh.ch = ch;\r
-\r
-        Ret = SendMessage(infoPtr->hParent,\r
-                          WM_NOTIFY,\r
-                          (WPARAM)mnmh.hdr.idFrom,\r
-                          (LPARAM)&mnmh);\r
-    }\r
-\r
-    return Ret;\r
-}\r
-\r
-\r
-static VOID\r
-OnClick(PMAP infoPtr,\r
-        WORD ptx,\r
-        WORD pty)\r
-{\r
-    POINT pt;\r
-    INT x, y;\r
-\r
-    pt.x = ptx;\r
-    pt.y = pty;\r
-\r
-    for (x = 0; x < XCELLS; x++)\r
-    for (y = 0; y < YCELLS; y++)\r
-    {\r
-        if (PtInRect(&infoPtr->Cells[y][x].CellInt,\r
-                     pt))\r
-        {\r
-            /* if the cell is not already active */\r
-            if (!infoPtr->Cells[y][x].bActive)\r
-            {\r
-                /* set previous active cell to inactive */\r
-                if (infoPtr->pActiveCell)\r
-                {\r
-                    /* invalidate normal cells, required when\r
-                     * moving a small active cell via keyboard */\r
-                    if (!infoPtr->pActiveCell->bLarge)\r
-                    {\r
-                        InvalidateRect(infoPtr->hMapWnd,\r
-                                       &infoPtr->pActiveCell->CellInt,\r
-                                       TRUE);\r
-                    }\r
-\r
-                    infoPtr->pActiveCell->bActive = FALSE;\r
-                    infoPtr->pActiveCell->bLarge = FALSE;\r
-                }\r
-\r
-                /* set new cell to active */\r
-                infoPtr->pActiveCell = &infoPtr->Cells[y][x];\r
-                infoPtr->pActiveCell->bActive = TRUE;\r
-                infoPtr->pActiveCell->bLarge = TRUE;\r
-                if (infoPtr->hLrgWnd)\r
-                    MoveLargeCell(infoPtr);\r
-                else\r
-                    CreateLargeCell(infoPtr);\r
-            }\r
-            else\r
-            {\r
-                /* flick between large and small */\r
-                if (infoPtr->pActiveCell->bLarge)\r
-                {\r
-                    DestroyWindow(infoPtr->hLrgWnd);\r
-                    infoPtr->hLrgWnd = NULL;\r
-                }\r
-                else\r
-                {\r
-                    CreateLargeCell(infoPtr);\r
-                }\r
-\r
-                infoPtr->pActiveCell->bLarge = (infoPtr->pActiveCell->bLarge) ? FALSE : TRUE;\r
-            }\r
-\r
-            break;\r
-        }\r
-    }\r
-}\r
-\r
-\r
-static BOOL\r
-OnCreate(PMAP infoPtr,\r
-         HWND hwnd,\r
-         HWND hParent)\r
-{\r
-    RECT rc;\r
-    BOOL Ret = FALSE;\r
-\r
-    infoPtr = HeapAlloc(GetProcessHeap(),\r
-                        0,\r
-                        sizeof(MAP));\r
-    if (infoPtr)\r
-    {\r
-        SetLastError(0);\r
-        SetWindowLongPtr(hwnd,\r
-                         0,\r
-                         (DWORD_PTR)infoPtr);\r
-        if (GetLastError() == 0)\r
-        {\r
-            ZeroMemory(infoPtr,\r
-                       sizeof(MAP));\r
-\r
-            infoPtr->hMapWnd = hwnd;\r
-            infoPtr->hParent = hParent;\r
-\r
-            GetClientRect(hwnd, &rc);\r
-            infoPtr->ClientSize.cx = rc.right;\r
-            infoPtr->ClientSize.cy = rc.bottom;\r
-            infoPtr->CellSize.cx = infoPtr->ClientSize.cx / XCELLS;\r
-            infoPtr->CellSize.cy = infoPtr->ClientSize.cy / YCELLS;\r
-\r
-            infoPtr->pActiveCell = NULL;\r
-\r
-            SetGrid(infoPtr);\r
-\r
-            SetScrollRange(hwnd, SB_VERT, 0, 255, FALSE);\r
-            SetScrollPos(hwnd, SB_VERT, 0, TRUE);\r
-\r
-            Ret = TRUE;\r
-        }\r
-    }\r
-\r
-    return Ret;\r
-}\r
-\r
-\r
-static VOID\r
-OnVScroll(PMAP infoPtr,\r
-          INT Value,\r
-          INT Pos)\r
-{\r
-    switch (Value)\r
-    {\r
-        case SB_LINEUP:\r
-            infoPtr->iPage -=  1;\r
-            break;\r
-\r
-        case SB_LINEDOWN:\r
-            infoPtr->iPage +=  1;\r
-            break;\r
-\r
-        case SB_PAGEUP:\r
-            infoPtr->iPage -= 16;\r
-            break;\r
-\r
-        case SB_PAGEDOWN:\r
-            infoPtr->iPage += 16;\r
-            break;\r
-\r
-        case SB_THUMBPOSITION:\r
-            infoPtr->iPage = Pos;\r
-            break;\r
-\r
-       default:\r
-            break;\r
-       }\r
-\r
-    infoPtr->iPage = max(0,\r
-                         min(infoPtr->iPage,\r
-                             255));\r
-\r
-    SetScrollPos(infoPtr->hMapWnd,\r
-                 SB_VERT,\r
-                 infoPtr->iPage,\r
-                 TRUE);\r
-\r
-    InvalidateRect(infoPtr->hMapWnd,\r
-                   NULL,\r
-                   TRUE);\r
-}\r
-\r
-\r
-static VOID\r
-OnPaint(PMAP infoPtr,\r
-        WPARAM wParam)\r
-{\r
-    PAINTSTRUCT ps;\r
-    HDC hdc;\r
-\r
-\r
-    if (wParam != 0)\r
-    {\r
-        if (!GetUpdateRect(infoPtr->hMapWnd,\r
-                           &ps.rcPaint,\r
-                           TRUE))\r
-        {\r
-            return;\r
-        }\r
-        hdc = (HDC)wParam;\r
-    }\r
-    else\r
-    {\r
-        hdc = BeginPaint(infoPtr->hMapWnd,\r
-                         &ps);\r
-        if (hdc == NULL)\r
-        {\r
-            return;\r
-        }\r
-    }\r
-\r
-    DrawGrid(infoPtr,\r
-             hdc);\r
-\r
-    FillGrid(infoPtr,\r
-             hdc);\r
-\r
-    if (wParam == 0)\r
-    {\r
-        EndPaint(infoPtr->hMapWnd,\r
-                 &ps);\r
-    }\r
-}\r
-\r
-\r
-LRESULT CALLBACK\r
-MapWndProc(HWND hwnd,\r
-           UINT uMsg,\r
-           WPARAM wParam,\r
-           LPARAM lParam)\r
-{\r
-    PMAP infoPtr;\r
-    LRESULT Ret = 0;\r
-\r
-    infoPtr = (PMAP)GetWindowLongPtr(hwnd,\r
-                                     0);\r
-\r
-    switch (uMsg)\r
-    {\r
-        case WM_CREATE:\r
-        {\r
-            if (!OnCreate(infoPtr,\r
-                          hwnd,\r
-                          ((LPCREATESTRUCTW)lParam)->hwndParent))\r
-            {\r
-                return (LRESULT)-1;\r
-            }\r
-\r
-            break;\r
-        }\r
-\r
-        case WM_LBUTTONDOWN:\r
-        {\r
-            OnClick(infoPtr,\r
-                    LOWORD(lParam),\r
-                    HIWORD(lParam));\r
-\r
-            break;\r
-        }\r
-\r
-        case WM_LBUTTONDBLCLK:\r
-        {\r
-            NotifyParentOfSelection(infoPtr,\r
-                                    FM_SETCHAR,\r
-                                    infoPtr->pActiveCell->ch);\r
-\r
-\r
-            break;\r
-        }\r
-\r
-        case WM_VSCROLL:\r
-        {\r
-            OnVScroll(infoPtr,\r
-                      LOWORD(wParam),\r
-                      HIWORD(wParam));\r
-\r
-            break;\r
-        }\r
-\r
-        case FM_SETFONT:\r
-        {\r
-            LPTSTR lpFontName = (LPTSTR)lParam;\r
-\r
-            SetFont(infoPtr,\r
-                    lpFontName);\r
-\r
-            HeapFree(GetProcessHeap(),\r
-                     0,\r
-                     lpFontName);\r
-\r
-            break;\r
-        }\r
-\r
-        case FM_GETCHAR:\r
-        {\r
-            if (!infoPtr->pActiveCell) return 0;\r
-            return infoPtr->pActiveCell->ch;\r
-        }\r
-\r
-        case WM_PAINT:\r
-        {\r
-            OnPaint(infoPtr,\r
-                    wParam);\r
-            break;\r
-        }\r
-\r
-        case WM_DESTROY:\r
-        {\r
-            DeleteObject(infoPtr->hFont);\r
-            HeapFree(GetProcessHeap(),\r
-                     0,\r
-                     infoPtr);\r
-            SetWindowLongPtr(hwnd,\r
-                             0,\r
-                             (DWORD_PTR)NULL);\r
-            break;\r
-        }\r
-\r
-        default:\r
-        {\r
-            Ret = DefWindowProc(hwnd,\r
-                                uMsg,\r
-                                wParam,\r
-                                lParam);\r
-            break;\r
-        }\r
-    }\r
-\r
-    return Ret;\r
-}\r
-\r
-\r
-BOOL\r
-RegisterMapClasses(HINSTANCE hInstance)\r
-{\r
-    WNDCLASS wc = {0};\r
-\r
-    wc.style = CS_DBLCLKS;\r
-    wc.lpfnWndProc = MapWndProc;\r
-    wc.cbWndExtra = sizeof(PMAP);\r
-    wc.hInstance = hInstance;\r
-    wc.hCursor = LoadCursor(NULL,\r
-                            (LPTSTR)IDC_ARROW);\r
-    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);\r
-    wc.lpszClassName = szMapWndClass;\r
-\r
-    if (RegisterClass(&wc))\r
-    {\r
-        wc.lpfnWndProc = LrgCellWndProc;\r
-        wc.cbWndExtra = 0;\r
-        wc.lpszClassName = szLrgCellWndClass;\r
-\r
-        return RegisterClass(&wc) != 0;\r
-    }\r
-\r
-    return FALSE;\r
-}\r
-\r
-VOID\r
-UnregisterMapClasses(HINSTANCE hInstance)\r
-{\r
-    UnregisterClass(szMapWndClass,\r
-                    hInstance);\r
-\r
-    UnregisterClass(szLrgCellWndClass,\r
-                    hInstance);\r
-}\r
+/*
+ * PROJECT:     ReactOS Character Map
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        base/applications/charmap/map.c
+ * PURPOSE:     class implementation for painting glyph region
+ * COPYRIGHT:   Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
+ *
+ */
+
+#include <precomp.h>
+
+static const WCHAR szMapWndClass[] = L"FontMapWnd";
+static const WCHAR szLrgCellWndClass[] = L"LrgCellWnd";
+
+static
+VOID
+TagFontToCell(PCELL pCell,
+              WCHAR ch)
+{
+    pCell->ch = ch;
+}
+
+
+static
+VOID
+SetGrid(PMAP infoPtr)
+{
+    INT x, y;
+
+    for (y = 0; y < YCELLS; y++)
+    for (x = 0; x < XCELLS; x++)
+    {
+        infoPtr->Cells[y][x].CellExt.left = x * infoPtr->CellSize.cx + 1;
+        infoPtr->Cells[y][x].CellExt.top = y * infoPtr->CellSize.cy + 1;
+        infoPtr->Cells[y][x].CellExt.right = (x + 1) * infoPtr->CellSize.cx + 2;
+        infoPtr->Cells[y][x].CellExt.bottom = (y + 1) * infoPtr->CellSize.cy + 2;
+
+        CopyRect(&infoPtr->Cells[y][x].CellInt,
+                 &infoPtr->Cells[y][x].CellExt);
+
+        InflateRect(&infoPtr->Cells[y][x].CellInt,
+                    -1,
+                    -1);
+    }
+}
+
+static
+VOID
+DrawActiveCell(PMAP infoPtr,
+               HDC hdc)
+{
+    Rectangle(hdc,
+              infoPtr->pActiveCell->CellInt.left,
+              infoPtr->pActiveCell->CellInt.top,
+              infoPtr->pActiveCell->CellInt.right,
+              infoPtr->pActiveCell->CellInt.bottom);
+
+}
+
+
+static
+VOID
+DrawGrid(PMAP infoPtr,
+         HDC hdc)
+{
+    INT x, y;
+
+    for (y = 0; y < YCELLS; y++)
+    for (x = 0; x < XCELLS; x++)
+    {
+        Rectangle(hdc,
+                  infoPtr->Cells[y][x].CellExt.left,
+                  infoPtr->Cells[y][x].CellExt.top,
+                  infoPtr->Cells[y][x].CellExt.right,
+                  infoPtr->Cells[y][x].CellExt.bottom);
+    }
+
+    if (infoPtr->pActiveCell)
+        DrawActiveCell(infoPtr,
+                       hdc);
+}
+
+
+static
+VOID
+FillGrid(PMAP infoPtr,
+         HDC hdc)
+{
+    HFONT hOldFont;
+    WCHAR ch;
+    INT x, y;
+
+    hOldFont = SelectObject(hdc,
+                            infoPtr->hFont);
+
+    for (y = 0; y < YCELLS; y++)
+    for (x = 0; x < XCELLS; x++)
+    {
+        ch = (WCHAR)((XCELLS * (y + infoPtr->iYStart)) + x);
+
+        TagFontToCell(&infoPtr->Cells[y][x], ch);
+
+        DrawTextW(hdc,
+                  &ch,
+                  1,
+                  &infoPtr->Cells[y][x].CellInt,
+                  DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+    }
+
+    SelectObject(hdc,
+                 hOldFont);
+}
+
+
+static
+BOOL
+CreateLargeCell(PMAP infoPtr)
+{
+    RECT rLarge;
+
+    CopyRect(&rLarge,
+             &infoPtr->pActiveCell->CellExt);
+
+    MapWindowPoints(infoPtr->hMapWnd,
+                    infoPtr->hParent,
+                    (VOID*)&rLarge,
+                    2);
+
+    InflateRect(&rLarge,
+                XLARGE - XCELLS,
+                YLARGE - YCELLS);
+
+    infoPtr->hLrgWnd = CreateWindowExW(0,
+                                       szLrgCellWndClass,
+                                       NULL,
+                                       WS_CHILDWINDOW | WS_VISIBLE,
+                                       rLarge.left,
+                                       rLarge.top,
+                                       rLarge.right - rLarge.left,
+                                       rLarge.bottom - rLarge.top,
+                                       infoPtr->hParent,
+                                       NULL,
+                                       hInstance,
+                                       infoPtr);
+    if (!infoPtr->hLrgWnd)
+        return FALSE;
+
+    return TRUE;
+}
+
+
+static
+VOID
+MoveLargeCell(PMAP infoPtr)
+{
+    RECT rLarge;
+
+    CopyRect(&rLarge,
+             &infoPtr->pActiveCell->CellExt);
+
+    MapWindowPoints(infoPtr->hMapWnd,
+                    infoPtr->hParent,
+                    (VOID*)&rLarge,
+                    2);
+
+    InflateRect(&rLarge,
+                XLARGE - XCELLS,
+                YLARGE - YCELLS);
+
+    MoveWindow(infoPtr->hLrgWnd,
+               rLarge.left,
+               rLarge.top,
+               rLarge.right - rLarge.left,
+               rLarge.bottom - rLarge.top,
+               TRUE);
+
+    InvalidateRect(infoPtr->hLrgWnd,
+                   NULL,
+                   TRUE);
+}
+
+
+static
+VOID
+SetFont(PMAP infoPtr,
+        LPWSTR lpFontName)
+{
+    HDC hdc;
+
+    if (infoPtr->hFont)
+        DeleteObject(infoPtr->hFont);
+
+    ZeroMemory(&infoPtr->CurrentFont,
+               sizeof(LOGFONTW));
+
+    hdc = GetDC(infoPtr->hMapWnd);
+    infoPtr->CurrentFont.lfHeight = GetDeviceCaps(hdc,
+                                                  LOGPIXELSY) / 5;
+    ReleaseDC(infoPtr->hMapWnd, hdc);
+
+    infoPtr->CurrentFont.lfCharSet =  DEFAULT_CHARSET;
+    wcscpy(infoPtr->CurrentFont.lfFaceName,
+           lpFontName);
+
+    infoPtr->hFont = CreateFontIndirectW(&infoPtr->CurrentFont);
+
+    InvalidateRect(infoPtr->hMapWnd,
+                   NULL,
+                   TRUE);
+}
+
+
+static
+LRESULT
+NotifyParentOfSelection(PMAP infoPtr,
+                        UINT code,
+                        WCHAR ch)
+{
+    LRESULT Ret = 0;
+
+    if (infoPtr->hParent != NULL)
+    {
+        DWORD dwIdc = GetWindowLongPtr(infoPtr->hMapWnd, GWLP_ID);
+        /*
+         * Push directly into the event queue instead of waiting
+         * the parent to be unlocked.
+         * High word of LPARAM is still available for future needs...
+         */
+        Ret = PostMessage(infoPtr->hParent,
+                          WM_COMMAND,
+                          MAKELPARAM((WORD)dwIdc, (WORD)code),
+                          (LPARAM)LOWORD(ch));
+    }
+
+    return Ret;
+}
+
+
+static
+VOID
+OnClick(PMAP infoPtr,
+        WORD ptx,
+        WORD pty)
+{
+    POINT pt;
+    INT x, y;
+
+    pt.x = ptx;
+    pt.y = pty;
+
+    for (x = 0; x < XCELLS; x++)
+    for (y = 0; y < YCELLS; y++)
+    {
+        if (PtInRect(&infoPtr->Cells[y][x].CellInt,
+                     pt))
+        {
+            /* if the cell is not already active */
+            if (!infoPtr->Cells[y][x].bActive)
+            {
+                /* set previous active cell to inactive */
+                if (infoPtr->pActiveCell)
+                {
+                    /* invalidate normal cells, required when
+                     * moving a small active cell via keyboard */
+                    if (!infoPtr->pActiveCell->bLarge)
+                    {
+                        InvalidateRect(infoPtr->hMapWnd,
+                                       &infoPtr->pActiveCell->CellInt,
+                                       TRUE);
+                    }
+
+                    infoPtr->pActiveCell->bActive = FALSE;
+                    infoPtr->pActiveCell->bLarge = FALSE;
+                }
+
+                /* set new cell to active */
+                infoPtr->pActiveCell = &infoPtr->Cells[y][x];
+                infoPtr->pActiveCell->bActive = TRUE;
+                infoPtr->pActiveCell->bLarge = TRUE;
+                if (infoPtr->hLrgWnd)
+                    MoveLargeCell(infoPtr);
+                else
+                    CreateLargeCell(infoPtr);
+            }
+            else
+            {
+                /* flick between large and small */
+                if (infoPtr->pActiveCell->bLarge)
+                {
+                    DestroyWindow(infoPtr->hLrgWnd);
+                    infoPtr->hLrgWnd = NULL;
+                }
+                else
+                {
+                    CreateLargeCell(infoPtr);
+                }
+
+                infoPtr->pActiveCell->bLarge = (infoPtr->pActiveCell->bLarge) ? FALSE : TRUE;
+            }
+
+            break;
+        }
+    }
+}
+
+
+static
+BOOL
+OnCreate(PMAP infoPtr,
+         HWND hwnd,
+         HWND hParent)
+{
+    RECT rc;
+    BOOL Ret = FALSE;
+
+    infoPtr = HeapAlloc(GetProcessHeap(),
+                        0,
+                        sizeof(MAP));
+    if (infoPtr)
+    {
+        SetLastError(0);
+        SetWindowLongPtrW(hwnd,
+                          0,
+                          (DWORD_PTR)infoPtr);
+        if (GetLastError() == 0)
+        {
+            ZeroMemory(infoPtr,
+                       sizeof(MAP));
+
+            infoPtr->hMapWnd = hwnd;
+            infoPtr->hParent = hParent;
+
+            GetClientRect(hwnd, &rc);
+            infoPtr->ClientSize.cx = rc.right;
+            infoPtr->ClientSize.cy = rc.bottom;
+            infoPtr->CellSize.cx = infoPtr->ClientSize.cx / XCELLS;
+            infoPtr->CellSize.cy = infoPtr->ClientSize.cy / YCELLS;
+
+            infoPtr->pActiveCell = NULL;
+
+            SetGrid(infoPtr);
+
+            SetScrollRange(hwnd, SB_VERT, 0, 255, FALSE);
+            SetScrollPos(hwnd, SB_VERT, 0, TRUE);
+
+            Ret = TRUE;
+        }
+    }
+
+    return Ret;
+}
+
+
+static
+VOID
+OnVScroll(PMAP infoPtr,
+          INT Value,
+          INT Pos)
+{
+    INT iYDiff, iOldYStart = infoPtr->iYStart;
+
+    switch (Value)
+    {
+        case SB_LINEUP:
+            infoPtr->iYStart -=  1;
+            break;
+
+        case SB_LINEDOWN:
+            infoPtr->iYStart +=  1;
+            break;
+
+        case SB_PAGEUP:
+            infoPtr->iYStart -= YCELLS;
+            break;
+
+        case SB_PAGEDOWN:
+            infoPtr->iYStart += YCELLS;
+            break;
+
+        case SB_THUMBTRACK:
+            infoPtr->iYStart = Pos;
+            break;
+
+       default:
+            break;
+       }
+
+    infoPtr->iYStart = max(0,
+                         min(infoPtr->iYStart, 255*16));
+
+    iYDiff = iOldYStart - infoPtr->iYStart;
+    if (iYDiff)
+    {
+        SetScrollPos(infoPtr->hMapWnd,
+                     SB_VERT,
+                     infoPtr->iYStart,
+                     TRUE);
+
+        if (abs(iYDiff) < YCELLS)
+        {
+            RECT rect;
+            GetClientRect(infoPtr->hMapWnd, &rect);
+            rect.top += 2;
+            rect.bottom -= 2;
+            ScrollWindowEx(infoPtr->hMapWnd,
+                           0,
+                           iYDiff * infoPtr->CellSize.cy,
+                           &rect,
+                           &rect,
+                           NULL,
+                           NULL,
+                           SW_INVALIDATE);
+        }
+        else
+        {
+            InvalidateRect(infoPtr->hMapWnd,
+                           NULL,
+                           TRUE);
+        }
+    }
+}
+
+
+static
+VOID
+OnPaint(PMAP infoPtr,
+        WPARAM wParam)
+{
+    PAINTSTRUCT ps;
+    HDC hdc;
+
+
+    if (wParam != 0)
+    {
+        if (!GetUpdateRect(infoPtr->hMapWnd,
+                           &ps.rcPaint,
+                           TRUE))
+        {
+            return;
+        }
+        hdc = (HDC)wParam;
+    }
+    else
+    {
+        hdc = BeginPaint(infoPtr->hMapWnd,
+                         &ps);
+        if (hdc == NULL)
+        {
+            return;
+        }
+    }
+
+    DrawGrid(infoPtr,
+             hdc);
+
+    FillGrid(infoPtr,
+             hdc);
+
+    if (wParam == 0)
+    {
+        EndPaint(infoPtr->hMapWnd,
+                 &ps);
+    }
+}
+
+
+LRESULT
+CALLBACK
+MapWndProc(HWND hwnd,
+           UINT uMsg,
+           WPARAM wParam,
+           LPARAM lParam)
+{
+    PMAP infoPtr;
+    LRESULT Ret = 0;
+
+    infoPtr = (PMAP)GetWindowLongPtrW(hwnd,
+                                      0);
+
+    switch (uMsg)
+    {
+        case WM_CREATE:
+        {
+            if (!OnCreate(infoPtr,
+                          hwnd,
+                          ((LPCREATESTRUCTW)lParam)->hwndParent))
+            {
+                return (LRESULT)-1;
+            }
+
+            break;
+        }
+
+        case WM_LBUTTONDOWN:
+        {
+            OnClick(infoPtr,
+                    LOWORD(lParam),
+                    HIWORD(lParam));
+
+            break;
+        }
+
+        case WM_LBUTTONDBLCLK:
+        {
+            NotifyParentOfSelection(infoPtr,
+                                    FM_SETCHAR,
+                                    infoPtr->pActiveCell->ch);
+
+
+            break;
+        }
+
+        case WM_VSCROLL:
+        {
+            OnVScroll(infoPtr,
+                      LOWORD(wParam),
+                      HIWORD(wParam));
+
+            break;
+        }
+
+        case FM_SETFONT:
+            SetFont(infoPtr, (LPWSTR)lParam);
+            break;
+
+        case FM_GETCHAR:
+        {
+            if (!infoPtr->pActiveCell) return 0;
+            return infoPtr->pActiveCell->ch;
+        }
+
+        case FM_GETHFONT:
+            return (LRESULT)infoPtr->hFont;
+
+        case WM_PAINT:
+        {
+            OnPaint(infoPtr,
+                    wParam);
+            break;
+        }
+
+        case WM_DESTROY:
+        {
+            DeleteObject(infoPtr->hFont);
+            HeapFree(GetProcessHeap(),
+                     0,
+                     infoPtr);
+            SetWindowLongPtrW(hwnd,
+                              0,
+                              (DWORD_PTR)NULL);
+            break;
+        }
+
+        default:
+        {
+            Ret = DefWindowProcW(hwnd,
+                                 uMsg,
+                                 wParam,
+                                 lParam);
+            break;
+        }
+    }
+
+    return Ret;
+}
+
+
+BOOL
+RegisterMapClasses(HINSTANCE hInstance)
+{
+    WNDCLASSW wc = {0};
+
+    wc.style = CS_DBLCLKS;
+    wc.lpfnWndProc = MapWndProc;
+    wc.cbWndExtra = sizeof(PMAP);
+    wc.hInstance = hInstance;
+    wc.hCursor = LoadCursorW(NULL,
+                            (LPWSTR)IDC_ARROW);
+    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+    wc.lpszClassName = szMapWndClass;
+
+    if (RegisterClassW(&wc))
+    {
+        wc.lpfnWndProc = LrgCellWndProc;
+        wc.cbWndExtra = 0;
+        wc.lpszClassName = szLrgCellWndClass;
+
+        return RegisterClassW(&wc) != 0;
+    }
+
+    return FALSE;
+}
+
+VOID
+UnregisterMapClasses(HINSTANCE hInstance)
+{
+    UnregisterClassW(szMapWndClass,
+                    hInstance);
+
+    UnregisterClassW(szLrgCellWndClass,
+                    hInstance);
+}