[CHARMAP] Functionality Improvements and Bug Fixes (#2560)
[reactos.git] / base / applications / charmap / map.c
index 7b2d783..334980b 100644 (file)
@@ -10,6 +10,7 @@
 #include "precomp.h"
 
 #include <stdlib.h>
+#include <winnls.h>
 
 static const WCHAR szMapWndClass[] = L"FontMapWnd";
 static const WCHAR szLrgCellWndClass[] = L"LrgCellWnd";
@@ -40,6 +41,7 @@ SetGrid(PMAP infoPtr)
     }
 }
 
+
 static
 VOID
 DrawActiveCell(PMAP infoPtr,
@@ -111,6 +113,8 @@ FillGrid(PMAP infoPtr,
     for (y = 0; y < YCELLS; y++)
     for (x = 0; x < XCELLS; x++)
     {
+        if (i >= infoPtr->NumValidGlyphs) break;
+
         ch = (WCHAR)infoPtr->ValidGlyphs[i];
 
         Cell = &infoPtr->Cells[y][x];
@@ -206,6 +210,38 @@ MoveLargeCell(PMAP infoPtr)
 }
 
 
+static
+VOID
+GetPossibleCharacters(WCHAR* ch, INT chLen, INT codePageIdx)
+{
+    INT i, j;
+
+    memset(ch, 0, sizeof(ch[0]) * chLen);
+
+    if (codePageIdx <= 0 || codePageIdx > SIZEOF(codePages))
+    {
+        /* this is unicode, so just load up the first MAX_GLYPHS characters
+           start at 0x21 to bypass whitespace characters */
+        INT len = min(MAX_GLYPHS, chLen);
+        for (i = 0x21, j = 0; i < len; i++)
+            ch[j++] = (WCHAR)i;
+    }
+    else
+    {
+        /* This is a codepage, so use NLS to translate the first 256 characters */
+        CHAR multiByteString[256] = { 0 };
+        for (i = 0x21; i < SIZEOF(multiByteString); i++)
+            multiByteString[i] = (CHAR)i;
+
+        if (!MultiByteToWideChar(codePages[codePageIdx - 1], 0, multiByteString, sizeof(multiByteString), ch, chLen))
+        {
+            /* Failed for some reason, so clear the array */
+            memset(ch, 0, sizeof(ch[0]) * chLen);
+        }
+    }
+}
+
+
 static
 VOID
 SetFont(PMAP infoPtr,
@@ -230,9 +266,9 @@ SetFont(PMAP infoPtr,
     infoPtr->CurrentFont.lfHeight = GetDeviceCaps(hdc, LOGPIXELSY) / 5;
 
     infoPtr->CurrentFont.lfCharSet =  DEFAULT_CHARSET;
-    wcsncpy(infoPtr->CurrentFont.lfFaceName,
-            lpFontName,
-            sizeof(infoPtr->CurrentFont.lfFaceName) / sizeof(infoPtr->CurrentFont.lfFaceName[0]));
+    lstrcpynW(infoPtr->CurrentFont.lfFaceName,
+              lpFontName,
+              SIZEOF(infoPtr->CurrentFont.lfFaceName));
 
     infoPtr->hFont = CreateFontIndirectW(&infoPtr->CurrentFont);
 
@@ -240,14 +276,17 @@ SetFont(PMAP infoPtr,
                    NULL,
                    TRUE);
 
+    if (infoPtr->pActiveCell) 
+        infoPtr->pActiveCell->bActive = FALSE;
     infoPtr->pActiveCell = &infoPtr->Cells[0][0];
+    infoPtr->pActiveCell->bActive = TRUE;
 
     // Get all the valid glyphs in this font
 
     SelectObject(hdc, infoPtr->hFont);
 
-    for (i = 0; i < MAX_GLYPHS; i++)
-        ch[i] = (WCHAR)i;
+    // Get the code page associated with the selected 'character set'
+    GetPossibleCharacters(ch, MAX_GLYPHS, infoPtr->CharMap);
 
     if (GetGlyphIndicesW(hdc,
                          ch,
@@ -256,9 +295,9 @@ SetFont(PMAP infoPtr,
                          GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
     {
         j = 0;
-        for (i = ' ' + 1; i < MAX_GLYPHS; i++)
+        for (i = 0; i < MAX_GLYPHS; i++)
         {
-            if (out[i] != 0xffff)
+            if (out[i] != 0xffff && out[i] != 0x0000 && ch[i] != 0x0000)
             {
                 infoPtr->ValidGlyphs[j] = ch[i];
                 j++;
@@ -312,10 +351,27 @@ OnClick(PMAP infoPtr,
         WORD ptx,
         WORD pty)
 {
-    INT x, y;
-
-    x = ptx / max(1, infoPtr->CellSize.cx);
-    y = pty / max(1, infoPtr->CellSize.cy);
+    INT x, y, i;
+
+    /*
+     * Find the cell the mouse pointer is over.
+     * Since each cell is the same size, this can be done quickly using CellSize.
+     * Clamp to XCELLS - 1 and YCELLS - 1 because the map can sometimes be slightly
+     * larger than infoPtr.CellSize * XCELLS , due to the map size being a non integer 
+     * multiple of infoPtr.CellSize .
+     */
+    x = min(XCELLS - 1, ptx / max(1, infoPtr->CellSize.cx));
+    y = min(YCELLS - 1, pty / max(1, infoPtr->CellSize.cy));
+
+    /* Make sure the mouse is within a valid glyph */
+    i = XCELLS * infoPtr->iYStart + y * XCELLS + x;
+    if (i >= infoPtr->NumValidGlyphs)
+    {
+        if (infoPtr->pActiveCell) 
+            infoPtr->pActiveCell->bActive = FALSE;
+        infoPtr->pActiveCell = NULL;
+        return;
+    }
 
     /* if the cell is not already active */
     if (!infoPtr->Cells[y][x].bActive)
@@ -447,6 +503,15 @@ OnVScroll(PMAP infoPtr,
         if (abs(iYDiff) < YCELLS)
         {
             RECT rect;
+
+            /* Invalidate the rect around the active cell since a new cell will become active */
+            if (infoPtr->pActiveCell && infoPtr->pActiveCell->bActive)
+            {
+                InvalidateRect(infoPtr->hMapWnd, 
+                               &infoPtr->pActiveCell->CellExt, 
+                               TRUE);
+            }
+            
             GetClientRect(infoPtr->hMapWnd, &rect);
             rect.top += 2;
             rect.bottom -= 2;
@@ -524,6 +589,7 @@ MapWndProc(HWND hwnd,
 {
     PMAP infoPtr;
     LRESULT Ret = 0;
+    WCHAR lfFaceName[LF_FACESIZE];
 
     infoPtr = (PMAP)GetWindowLongPtrW(hwnd,
                                       0);
@@ -564,6 +630,9 @@ MapWndProc(HWND hwnd,
 
         case WM_LBUTTONDBLCLK:
         {
+            if (!infoPtr->pActiveCell) 
+                break;
+
             NotifyParentOfSelection(infoPtr,
                                     FM_SETCHAR,
                                     infoPtr->pActiveCell->ch);
@@ -588,6 +657,14 @@ MapWndProc(HWND hwnd,
             break;
         }
 
+        case FM_SETCHARMAP:
+            infoPtr->CharMap = LOWORD(wParam);
+            wcsncpy(lfFaceName,
+                    infoPtr->CurrentFont.lfFaceName,
+                    SIZEOF(lfFaceName));
+            SetFont(infoPtr, lfFaceName);
+            break;
+
         case FM_SETFONT:
             SetFont(infoPtr, (LPWSTR)lParam);
             break;