4061 lines
115 KiB
C
4061 lines
115 KiB
C
/*++
|
|
|
|
Copyright (c) 1991-1997, Microsoft Corporation All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
charmap.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the main routines for the Charmap utility, an
|
|
interface for selecting special characters.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
|
|
//
|
|
// Include Files.
|
|
//
|
|
|
|
#define WIN31
|
|
#include "windows.h"
|
|
#include <port1632.h>
|
|
#include "charmap.h"
|
|
#include "stdlib.h"
|
|
#include "tchar.h"
|
|
#ifdef UNICODE
|
|
#include "wchar.h"
|
|
#else
|
|
#include "stdio.h"
|
|
#endif
|
|
#include "commctrl.h"
|
|
#include <htmlhelp.h>
|
|
|
|
|
|
|
|
//
|
|
// Macros.
|
|
//
|
|
|
|
#define FMagData(psycm) ((psycm)->xpMagCurr != 0)
|
|
#define abs(x) (((x) >= 0) ? (x) : (-(x)))
|
|
|
|
|
|
|
|
|
|
//
|
|
// Constant Declarations.
|
|
//
|
|
|
|
#define STATUSPOINTSIZE 8 // point size of status bar font
|
|
#define FE_STATUSPOINTSIZE 10 // FE point size of status bar font
|
|
#define DX_BITMAP 20 // width of TT bitmap
|
|
#define DY_BITMAP 12 // height of TT bitmap
|
|
#define BACKGROUND 0x000000FF // bright blue
|
|
#define BACKGROUNDSEL 0x00FF00FF // bright purple
|
|
#define BUTTONFACE 0x00C0C0C0 // bright grey
|
|
#define BUTTONSHADOW 0x00808080 // dark grey
|
|
#define TOOLBARPOINTSIZE 21 // height of toolbar in points
|
|
|
|
|
|
|
|
// Font types
|
|
#define PS_OPENTYPE_FONT 0x0001
|
|
#define TT_OPENTYPE_FONT 0x0002
|
|
#define TRUETYPE_FONT 0x0004
|
|
#define TYPE1_FONT 0x0008
|
|
|
|
//
|
|
// Debug Print Code.
|
|
//
|
|
|
|
#if 0
|
|
TCHAR szDOUT[3] = TEXT("A\n");
|
|
TCHAR szDbgBuf[256];
|
|
#define DOUTL(p) OutputDebugString(TEXT(p))
|
|
#define DOUTCHN(ch) if(0){}else {szDOUT[0] = ch; OutputDebugString(szDOUT);}
|
|
#define DPRINT(p) if(0){}else {wsprintf p; OutputDebugString(szDbgBuf);}
|
|
#else
|
|
#define DOUTL(p)
|
|
#define DOUTCHN(ch)
|
|
#define DPRINT(p)
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//
|
|
// Global Variables.
|
|
//
|
|
|
|
HANDLE hInst;
|
|
|
|
INT cchSymRow = 32; // number of characters across the character grid
|
|
INT cchSymCol = 8; // number of rows in the character grid
|
|
UTCHAR chSymFirst = 32;
|
|
UTCHAR chSymLast = 255;
|
|
UTCHAR chRangeFirst = 32;
|
|
UTCHAR chRangeLast = 255;
|
|
SYCM sycm; // tons of data need to do char grid painting
|
|
WORD wCFRichText = 0; // private clipboard format, rich text format
|
|
HFONT hFontClipboard = NULL; // tells us which font is in the clipboard
|
|
HANDLE hstrClipboard = NULL; // contains the string which is in the clipboard
|
|
BOOL fDelClipboardFont = FALSE; // the clipboard font needs to be deleted
|
|
INT iControl = ID_CHARGRID; // index indicating which control has focus
|
|
HBITMAP hbmFont = NULL; // TT bitmap drawn before font facenames in combo
|
|
LONG lEditSel = 0; // contains the selection range of the EC
|
|
HBRUSH hStaticBrush; // used for static controls during WM_CTLCOLOR
|
|
|
|
//
|
|
// Currently there is no defined interface for querying what character
|
|
// ranges a Unicode font supports. For now, this table only has the subsets
|
|
// that contain characters supported by the Lucida Sans Unicode font
|
|
// uncommented. When we get an API that allows querying the font driver for
|
|
// ranges of Unicode characters supported (and whether or not a font is a
|
|
// Unicode font!) then all entries can be uncommented.
|
|
//
|
|
USUBSET aSubsetData[] =
|
|
{
|
|
{ 0x0020, 0x00ff, IDS_WINDOWS },
|
|
{ 0x0020, 0x00ff, IDS_LATIN1 },
|
|
{ 0x0100, 0x017f, IDS_LATINEXA },
|
|
{ 0x0180, 0x024f, IDS_LATINEXB },
|
|
{ 0x0250, 0x02af, IDS_IPAEX },
|
|
{ 0x02b0, 0x02ff, IDS_SPACINGMODIFIERS },
|
|
{ 0x0300, 0x036f, IDS_COMBININGDIACRITICS },
|
|
{ 0x0370, 0x03cf, IDS_BASICGREEK },
|
|
{ 0x03d0, 0x03ff, IDS_GREEKSYMBOLS },
|
|
{ 0x0400, 0x04ff, IDS_CYRILLIC },
|
|
{ 0x0530, 0x058f, IDS_ARMENIAN },
|
|
{ 0x0590, 0x05ff, IDS_HEBREW },
|
|
{ 0x0600, 0x0652, IDS_BASICARABIC },
|
|
{ 0x0653, 0x06ff, IDS_ARABICEX },
|
|
{ 0x0900, 0x097f, IDS_DEVANAGARI },
|
|
{ 0x0980, 0x09ff, IDS_BENGALI },
|
|
{ 0x0a00, 0x0a7f, IDS_GURMUKHI },
|
|
{ 0x0a80, 0x0aff, IDS_GUJARATI },
|
|
{ 0x0b00, 0x0b7f, IDS_ORIYA },
|
|
{ 0x0b80, 0x0bff, IDS_TAMIL },
|
|
{ 0x0c00, 0x0c7f, IDS_TELUGU },
|
|
{ 0x0c80, 0x0cff, IDS_KANNADA },
|
|
{ 0x0d00, 0x0d7f, IDS_MALAYALAM },
|
|
{ 0x0e00, 0x0e7f, IDS_THAI },
|
|
{ 0x0e80, 0x0eff, IDS_LAO },
|
|
{ 0x10d0, 0x10ff, IDS_BASICGEORGIAN },
|
|
{ 0x10a0, 0x10cf, IDS_GEORGIANEX },
|
|
{ 0x1100, 0x11ff, IDS_HANGULJAMO },
|
|
{ 0x1e00, 0x1eff, IDS_LATINEXADDITIONAL },
|
|
{ 0x1f00, 0x1fff, IDS_GREEKEX },
|
|
{ 0x2000, 0x206f, IDS_GENERALPUNCTUATION },
|
|
{ 0x2070, 0x209f, IDS_SUPERANDSUBSCRIPTS },
|
|
{ 0x20a0, 0x20cf, IDS_CURRENCYSYMBOLS },
|
|
{ 0x20d0, 0x20ff, IDS_COMBININGDIACRITICSFORSYMBOLS },
|
|
{ 0x2100, 0x214f, IDS_LETTERLIKESYMBOLS },
|
|
{ 0x2150, 0x218f, IDS_NUMBERFORMS },
|
|
{ 0x2190, 0x21ff, IDS_ARROWS },
|
|
{ 0x2200, 0x22ff, IDS_MATHEMATICALOPS },
|
|
{ 0x2300, 0x23ff, IDS_MISCTECHNICAL },
|
|
{ 0x2400, 0x243f, IDS_CONTROLPICTURES },
|
|
{ 0x2440, 0x245f, IDS_OPTICALCHAR },
|
|
{ 0x2460, 0x24ff, IDS_ENCLOSEDALPHANUM },
|
|
{ 0x2500, 0x257f, IDS_BOXDRAWING },
|
|
{ 0x2580, 0x259f, IDS_BLOCKELEMENTS },
|
|
{ 0x25a0, 0x25ff, IDS_GEOMETRICSHAPES },
|
|
{ 0x2600, 0x26ff, IDS_MISCDINGBATS },
|
|
{ 0x2700, 0x27bf, IDS_DINGBATS },
|
|
{ 0x3000, 0x303f, IDS_CJKSYMBOLSANDPUNC },
|
|
{ 0x3040, 0x309f, IDS_HIRAGANA },
|
|
{ 0x30a0, 0x30ff, IDS_KATAKANA },
|
|
{ 0x3100, 0x312f, IDS_BOPOMOFO },
|
|
{ 0x3130, 0x318f, IDS_HANGULCOMPATIBILITYJAMO },
|
|
{ 0x3190, 0x319f, IDS_CJKMISC },
|
|
{ 0x3200, 0x32ff, IDS_ENCLOSEDCJKLETTERSANDMONTHS },
|
|
{ 0x3300, 0x33ff, IDS_CJKCOMPATIBILITY },
|
|
{ 0x4e00, 0x9fff, IDS_CJKUNIFIEDIDEOGRAPHS },
|
|
{ 0xac00, 0xd7a3, IDS_HANGUL },
|
|
{ 0xe000, 0xf8ff, IDS_PRIVATEUSEAREA },
|
|
{ 0xf900, 0xfaff, IDS_CJKCOMPATIBILITYIDEOGRAPHS },
|
|
{ 0xfb00, 0xfb4f, IDS_ALPAHPRESENTATIONFORMS },
|
|
{ 0xfb50, 0xfdff, IDS_ARABICPRESENTATIONFORMSA },
|
|
{ 0xfe30, 0xfe4f, IDS_CJKCOMPFORMS },
|
|
{ 0xfe50, 0xfe6f, IDS_SMALLFORMVARIANTS },
|
|
{ 0xfe70, 0xfefe, IDS_ARABICPRESENTATIONFORMSB },
|
|
{ 0xff00, 0xffef, IDS_HALFANDFULLWIDTHFORMS },
|
|
{ 0xfff0, 0xfffd, IDS_SPECIALS }
|
|
};
|
|
INT cSubsets = sizeof(aSubsetData) / sizeof(USUBSET);
|
|
INT iCurSubset = 0; // index of current Unicode subset - default to Latin-1
|
|
|
|
//
|
|
// Useful window handles.
|
|
//
|
|
HWND hwndDialog;
|
|
HWND hwndCharGrid;
|
|
|
|
//
|
|
// Data used to draw the status bar.
|
|
//
|
|
RECT rcStatusLine; // bounding rect for status bar
|
|
RECT rcToolbar[2]; // bounding rects for toolbars
|
|
INT dyStatus; // height of status bar
|
|
INT dyToolbar[2]; // height of tool bars
|
|
INT dxHelpField; // width of help window
|
|
INT dxKeystrokeField; // width of keystroke window
|
|
TCHAR szKeystrokeText[MAX_PATH]; // buffer for keystroke text
|
|
TCHAR szKeystrokeLabel[30]; // buffer for keystroke label
|
|
TCHAR szSpace[15]; // strings for keystroke description
|
|
TCHAR szCtrl[15];
|
|
TCHAR szCtrlAlt[25];
|
|
TCHAR szShiftCtrlAlt[25];
|
|
TCHAR szAlt[15];
|
|
TCHAR szUnicodeLabel[23]; // buffer for Unicode label
|
|
INT iKeystrokeTextStart; // place to start appending text to above
|
|
INT iUnicodeLabelStart; // place to start appending text to above
|
|
HFONT hfontStatus; // font used for text of status bar
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// WinMain
|
|
//
|
|
// Calls initialization function, processes message loop, cleanup.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
INT WinMain(
|
|
HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpCmdLine,
|
|
int nCmdShow)
|
|
{
|
|
MSG msg;
|
|
|
|
if (!InitApplication(hInstance))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Perform initialization for this instance.
|
|
//
|
|
if (!InitInstance(hInstance, nCmdShow))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
//
|
|
// Filter for possible tabs now to implement context sensitive help.
|
|
//
|
|
if (msg.message == WM_KEYDOWN)
|
|
{
|
|
if (!UpdateHelpText(&msg, NULL))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Main message loop.
|
|
//
|
|
if (!IsDialogMessage(hwndDialog, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free up some stuff.
|
|
//
|
|
if (hfontStatus)
|
|
{
|
|
DeleteObject(hfontStatus);
|
|
}
|
|
if (hbmFont)
|
|
{
|
|
DeleteObject(hbmFont);
|
|
}
|
|
|
|
return (msg.wParam);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// InitApplication
|
|
//
|
|
// Initializes window data and registers window class.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL InitApplication(
|
|
HANDLE hInstance)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
//
|
|
// Register a window class that we will use to draw the character
|
|
// grid into.
|
|
//
|
|
wc.style = CS_DBLCLKS;
|
|
wc.lpfnWndProc = CharGridWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = TEXT("CharGridWClass");
|
|
|
|
if (!RegisterClass(&wc))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = DefDlgProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = DLGWINDOWEXTRA;
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDIC_CHARMAP));
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = TEXT("MyDlgClass");
|
|
|
|
if (!RegisterClass(&wc))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// InitInstance
|
|
//
|
|
// Does some initialization and creates main window which is a dialog.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL InitInstance(
|
|
HANDLE hInstance,
|
|
INT nCmdShow)
|
|
{
|
|
INT i;
|
|
CHARSETINFO csi;
|
|
DWORD dw = GetACP();
|
|
LANGID PrimaryLangId = (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())));
|
|
BOOL bFE = ((PrimaryLangId == LANG_JAPANESE) ||
|
|
(PrimaryLangId == LANG_KOREAN) ||
|
|
(PrimaryLangId == LANG_CHINESE));
|
|
|
|
//
|
|
// Save the instance handle in a global variable.
|
|
//
|
|
hInst = hInstance;
|
|
|
|
//
|
|
// This font will be used to paint the status line.
|
|
//
|
|
if (!TranslateCharsetInfo((DWORD*)dw, &csi, TCI_SRCCODEPAGE))
|
|
{
|
|
csi.ciCharset = ANSI_CHARSET;
|
|
}
|
|
hfontStatus = CreateFont( -PointsToHeight(bFE
|
|
? FE_STATUSPOINTSIZE
|
|
: STATUSPOINTSIZE),
|
|
0, 0, 0, 400, 0, 0, 0,
|
|
csi.ciCharset,
|
|
OUT_DEFAULT_PRECIS,
|
|
CLIP_DEFAULT_PRECIS,
|
|
DEFAULT_QUALITY,
|
|
VARIABLE_PITCH,
|
|
TEXT("MS Shell Dlg") );
|
|
|
|
dyStatus = 2 * PointsToHeight(STATUSPOINTSIZE);
|
|
dyToolbar[0] = PointsToHeight(TOOLBARPOINTSIZE);
|
|
dyToolbar[1] = PointsToHeight(TOOLBARPOINTSIZE);
|
|
|
|
//
|
|
// Load the Unicode subset names before initializing the main window.
|
|
//
|
|
for (i = 0; i < cSubsets; i++)
|
|
{
|
|
if (!LoadString( hInst,
|
|
aSubsetData[i].StringResId,
|
|
(LPTSTR)aSubsetData[i].Name,
|
|
LF_SUBSETSIZE))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a main window for this application instance.
|
|
//
|
|
if (!(hwndDialog = CreateDialog( hInstance,
|
|
TEXT("CharMap"),
|
|
NULL,
|
|
CharMapDlgProc )))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Initialize some strings used for the Keystroke status bar field.
|
|
// For international purposes, this string could be length 0.
|
|
//
|
|
LoadString( hInst,
|
|
IDS_KEYSTROKE,
|
|
(LPTSTR)szKeystrokeLabel,
|
|
BTOC(sizeof(szKeystrokeLabel)) );
|
|
if (!LoadString( hInst,
|
|
IDS_UNICODELABEL,
|
|
(LPTSTR)szUnicodeLabel,
|
|
BTOC(sizeof(szUnicodeLabel)) ))
|
|
{
|
|
if (!LoadString( hInst,
|
|
IDS_SPACE,
|
|
(LPTSTR)szSpace,
|
|
BTOC(sizeof(szSpace)) ))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
}
|
|
if (!LoadString( hInst,
|
|
IDS_CTRL,
|
|
(LPTSTR)szCtrl,
|
|
BTOC(sizeof(szCtrl)) ))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
if (!LoadString( hInst,
|
|
IDS_CTRLALT,
|
|
(LPTSTR)szCtrlAlt,
|
|
BTOC(sizeof(szCtrlAlt)) ))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
if (!LoadString( hInst,
|
|
IDS_SHIFTCTRLALT,
|
|
(LPTSTR)szShiftCtrlAlt,
|
|
BTOC(sizeof(szShiftCtrlAlt)) ))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
if (!LoadString( hInst,
|
|
IDS_ALT,
|
|
(LPTSTR)szAlt,
|
|
BTOC(sizeof(szAlt)) ))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Store the index to where we start adding status line text changes.
|
|
//
|
|
iKeystrokeTextStart = lstrlen(szKeystrokeLabel);
|
|
iUnicodeLabelStart = lstrlen(szUnicodeLabel);
|
|
|
|
//
|
|
// Initialize keystroke text, make the window visible,
|
|
// update its client area, and return "success".
|
|
//
|
|
UpdateKeystrokeText(NULL, sycm.fAnsiFont, sycm.chCurr, FALSE);
|
|
ShowWindow(hwndDialog, nCmdShow);
|
|
UpdateWindow(hwndDialog);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ConvertANSIFontToUnicode
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
WCHAR ConvertANSIFontToUnicode(
|
|
HWND hwnd,
|
|
HFONT hFont,
|
|
CHAR ch)
|
|
{
|
|
WORD cp = CP_ACP;
|
|
WCHAR wch;
|
|
HDC hdc;
|
|
|
|
hdc = GetDC(hwnd);
|
|
if (hdc != NULL)
|
|
{
|
|
HFONT hfOld;
|
|
TEXTMETRIC tm;
|
|
CHARSETINFO csi;
|
|
DWORD cs;
|
|
|
|
hfOld = SelectObject(hdc, hFont);
|
|
|
|
if (GetTextMetrics(hdc, &tm))
|
|
{
|
|
cs = MAKELONG(tm.tmCharSet, 0);
|
|
|
|
if (TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
|
|
{
|
|
cp = csi.ciACP;
|
|
}
|
|
else
|
|
{
|
|
DPRINT(( szDbgBuf,
|
|
TEXT("CvtAtoW: TranslateCharsetInfo(cset=%d) returned 0! (GetLastErr=%d), using CP_ACP\n"),
|
|
cs,
|
|
GetLastError() ));
|
|
}
|
|
}
|
|
SelectObject(hdc, hfOld);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
|
|
if (MultiByteToWideChar(cp, 0, &ch, 1, &wch, 1) != 1)
|
|
{
|
|
if (MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1) != 1)
|
|
{
|
|
wch = (WCHAR)(BYTE)ch;
|
|
}
|
|
}
|
|
|
|
DPRINT(( szDbgBuf,
|
|
TEXT("CvtAtoW: 0x%02x '%c' (CP:%d) -> U'%04X'\n"),
|
|
(DWORD)(BYTE)ch,
|
|
ch,
|
|
cp,
|
|
(DWORD)wch ));
|
|
|
|
return (wch);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// EnumChildProc
|
|
//
|
|
// Gets called during init for each child window.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CALLBACK EnumChildProc(
|
|
HWND hwnd,
|
|
LPARAM lParam)
|
|
{
|
|
LONG st;
|
|
TCHAR szClass[MAX_PATH];
|
|
|
|
//
|
|
// Get control class.
|
|
//
|
|
GetClassName(hwnd, szClass, MAX_PATH);
|
|
if (lstrcmpi(szClass, TEXT("button")) == 0 )
|
|
{
|
|
//
|
|
// If it is a button, set the ex style to NOTIFYPARENT.
|
|
//
|
|
st = GetWindowLong(hwnd, GWL_EXSTYLE);
|
|
st = st & ~WS_EX_NOPARENTNOTIFY;
|
|
SetWindowLong(hwnd, GWL_EXSTYLE, st);
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CharMapDlgProc
|
|
//
|
|
// Processes messages for the main window. This window is a dialog box.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
INT_PTR APIENTRY CharMapDlgProc(
|
|
HWND hWnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case ( WM_CTLCOLORSTATIC ) :
|
|
{
|
|
POINT point;
|
|
|
|
SetBkColor((HDC)wParam, GetSysColor(COLOR_BTNFACE));
|
|
UnrealizeObject(hStaticBrush);
|
|
point.x = point.y = 0;
|
|
ClientToScreen(hWnd, &point);
|
|
|
|
return ((INT_PTR)hStaticBrush);
|
|
break;
|
|
}
|
|
case ( WM_INITDIALOG ) :
|
|
{
|
|
RECT rectParent, rectTopRightControl, rect;
|
|
POINT pt;
|
|
INT iSubset;
|
|
HWND hwndCMSB;
|
|
|
|
//
|
|
// Set buttons to send WM_PARENTNOTIFY.
|
|
//
|
|
EnumChildWindows(hWnd, EnumChildProc, (LPARAM)NULL );
|
|
|
|
//
|
|
// Create the character grid with dimensions which just fit
|
|
// inside the space allowed in the dialog. When it processes
|
|
// the WM_CREATE message it will be sized and centered more
|
|
// accurately.
|
|
//
|
|
GetClientRect(hWnd, &rectParent);
|
|
GetWindowRect(GetDlgItem(hWnd, ID_CLOSE), &rectTopRightControl);
|
|
ScreenToClient(hWnd, (LPPOINT)&(rectTopRightControl.left));
|
|
ScreenToClient(hWnd, (LPPOINT)&(rectTopRightControl.right));
|
|
|
|
if (!(hwndCharGrid =
|
|
CreateWindow( TEXT("CharGridWClass"),
|
|
NULL,
|
|
WS_CHILD | WS_VISIBLE | WS_TABSTOP,
|
|
1,
|
|
rectParent.top + dyToolbar[0] + dyToolbar[1],
|
|
rectParent.right - 1,
|
|
rectParent.bottom - rectParent.top -
|
|
dyStatus - dyToolbar[0] - dyToolbar[1] - 1,
|
|
hWnd,
|
|
(HMENU)ID_CHARGRID,
|
|
hInst,
|
|
NULL )))
|
|
{
|
|
DestroyWindow(hWnd);
|
|
break;
|
|
}
|
|
|
|
GetWindowRect(hwndCharGrid, &rect);
|
|
pt.x = rect.right;
|
|
pt.y = rect.top;
|
|
|
|
ScreenToClient(hWnd, &pt);
|
|
|
|
hwndCMSB = CreateWindowEx( 0L,
|
|
TEXT("SCROLLBAR"),
|
|
NULL,
|
|
WS_CHILD | SBS_VERT | WS_VISIBLE |
|
|
WS_TABSTOP,
|
|
pt.x + 1,
|
|
pt.y + 1,
|
|
sycm.dxpBox,
|
|
sycm.dypCM,
|
|
hWnd,
|
|
(HMENU)ID_MAPSCROLL,
|
|
hInst,
|
|
NULL );
|
|
|
|
hStaticBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
|
|
|
|
//
|
|
// Initialize the status line data.
|
|
//
|
|
dxHelpField = 21 * rectParent.right / 32;
|
|
dxKeystrokeField = 9 * rectParent.right / 32;
|
|
rcStatusLine = rectParent;
|
|
rcStatusLine.top = rcStatusLine.bottom - dyStatus;
|
|
|
|
//
|
|
// Initialize the toolbars.
|
|
//
|
|
rcToolbar[0] = rectParent;
|
|
rcToolbar[0].bottom = rcToolbar[0].top + dyToolbar[0];
|
|
|
|
rcToolbar[1] = rcToolbar[0];
|
|
rcToolbar[1].top = rcToolbar[0].bottom + GetSystemMetrics(SM_CYBORDER);
|
|
rcToolbar[1].bottom = rcToolbar[1].top + dyToolbar[1];
|
|
|
|
//
|
|
// Disable Copy button.
|
|
//
|
|
EnableWindow(GetDlgItem(hWnd, ID_COPY), FALSE);
|
|
|
|
//
|
|
// Fill "Subset" list box.
|
|
//
|
|
for (iSubset = 0; iSubset < cSubsets; iSubset++)
|
|
{
|
|
SendDlgItemMessage( hWnd,
|
|
ID_UNICODESUBSET,
|
|
CB_ADDSTRING,
|
|
0,
|
|
(DWORD)aSubsetData[iSubset].Name );
|
|
}
|
|
iCurSubset = SelectInitialSubset(hWnd);
|
|
|
|
//
|
|
// Fall through to WM_FONTCHANGE...
|
|
//
|
|
}
|
|
case ( WM_FONTCHANGE ) :
|
|
{
|
|
HDC hdc = GetDC(hWnd);
|
|
|
|
//
|
|
// Get the fonts from the system and put them in the font
|
|
// selection combo box.
|
|
//
|
|
if (message == WM_FONTCHANGE)
|
|
{
|
|
SaveCurrentFont(hWnd);
|
|
SendDlgItemMessage(hWnd, ID_FONT, CB_RESETCONTENT, 0, 0L);
|
|
}
|
|
|
|
EnumFontFamilies(hdc, NULL, (FONTENUMPROC)FontLoadProc, (LPARAM)hWnd);
|
|
|
|
ReleaseDC(hWnd, hdc);
|
|
|
|
//
|
|
// Setup character dimensions and select this font.
|
|
//
|
|
RecalcCharMap( hWnd,
|
|
&sycm,
|
|
SelectInitialFont(hWnd),
|
|
(message == WM_FONTCHANGE) );
|
|
SetEditCtlFont(hWnd, ID_STRING, sycm.hFont);
|
|
|
|
if (message == WM_INITDIALOG)
|
|
{
|
|
SetFocus(hwndCharGrid);
|
|
|
|
//
|
|
// Fall through to WM_SYSCOLORCHANGE...
|
|
//
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
case ( WM_SYSCOLORCHANGE ) :
|
|
{
|
|
if (hbmFont)
|
|
{
|
|
DeleteObject(hbmFont);
|
|
}
|
|
hbmFont = LoadBitmaps(IDBM_TT);
|
|
DeleteObject(hStaticBrush);
|
|
hStaticBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
|
|
break;
|
|
}
|
|
case ( WM_PARENTNOTIFY ) :
|
|
{
|
|
POINTS points;
|
|
DWORD dwMsgPos;
|
|
POINT point;
|
|
|
|
DPRINT(( szDbgBuf,
|
|
TEXT("WM_PARENTNOTIFY: lParam:0x%08lX, wParam:0x%08lX\n"),
|
|
(DWORD)lParam,
|
|
(DWORD)wParam ));
|
|
|
|
//
|
|
// We process this message to implement the context sensitive
|
|
// help. Downclicks to controls are found here, the help
|
|
// message is updated in the status bar.
|
|
//
|
|
// The parameters with this message are unreliable!
|
|
//
|
|
if (LOWORD(wParam) == WM_LBUTTONDOWN)
|
|
{
|
|
dwMsgPos = GetMessagePos();
|
|
points = MAKEPOINTS(dwMsgPos);
|
|
point.x = points.x;
|
|
point.y = points.y;
|
|
UpdateHelpText(NULL, WindowFromPoint(point));
|
|
}
|
|
|
|
break;
|
|
}
|
|
case ( WM_VSCROLL ) :
|
|
{
|
|
ProcessScrollMsg(hWnd, LOWORD(wParam), HIWORD(wParam));
|
|
break;
|
|
}
|
|
case ( WM_PAINT ) :
|
|
{
|
|
HBRUSH hBrush;
|
|
RECT rcTemp, rectNextButton;
|
|
INT dyBorder, dxBorder;
|
|
PAINTSTRUCT ps;
|
|
HDC hdc;
|
|
|
|
//
|
|
// This code implements painting of the status bar.
|
|
//
|
|
hdc = BeginPaint(hWnd, &ps);
|
|
|
|
rcTemp = rcStatusLine;
|
|
|
|
dyBorder = GetSystemMetrics(SM_CYBORDER);
|
|
dxBorder = GetSystemMetrics(SM_CXBORDER);
|
|
|
|
//
|
|
// Make the whole thing grey.
|
|
//
|
|
if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)))
|
|
{
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
rcTemp.left = rcToolbar[0].left;
|
|
rcTemp.top = rcToolbar[0].top;
|
|
rcTemp.right = rcToolbar[1].right;
|
|
rcTemp.bottom = rcToolbar[1].bottom;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
DeleteObject(hBrush);
|
|
}
|
|
|
|
GetWindowRect(GetDlgItem(hWnd, ID_TOPLEFT), &rectNextButton);
|
|
ScreenToClient(hWnd, (LPPOINT)&(rectNextButton.left));
|
|
ScreenToClient(hWnd, (LPPOINT)&(rectNextButton.right));
|
|
//
|
|
// Solid black line across bottom of toolbar.
|
|
//
|
|
if (hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME)))
|
|
{
|
|
#ifdef USE_MIRRORING
|
|
DWORD dwLayout;
|
|
GetProcessDefaultLayout(&dwLayout);
|
|
if(dwLayout & LAYOUT_RTL)
|
|
{
|
|
//
|
|
// Interchange the right and left values.
|
|
//
|
|
int tmp = rectNextButton.left;
|
|
rectNextButton.left = rectNextButton.right;
|
|
rectNextButton.right = tmp;
|
|
}
|
|
#endif
|
|
rcTemp = rcToolbar[0];
|
|
rcTemp.top = rcTemp.bottom;
|
|
rcTemp.bottom += dyBorder;
|
|
rcTemp.left = rectNextButton.left - 2 - dxBorder;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
rcTemp = rcToolbar[1];
|
|
rcTemp.top = rcTemp.bottom;
|
|
rcTemp.bottom += dyBorder;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
|
|
//
|
|
// Vertical line.
|
|
//
|
|
rcTemp.top = rcToolbar[0].top;
|
|
rcTemp.bottom = rcToolbar[1].bottom;
|
|
rcTemp.left = rectNextButton.left - 2 - dxBorder;
|
|
rcTemp.right = rectNextButton.left - 2;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
DeleteObject(hBrush);
|
|
}
|
|
|
|
if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW)))
|
|
{
|
|
//
|
|
// Status line top.
|
|
//
|
|
rcTemp.left = 8 * dyBorder;
|
|
rcTemp.right = rcTemp.left + dxHelpField;
|
|
rcTemp.top = rcStatusLine.top + dyBorder * 2;
|
|
rcTemp.bottom = rcTemp.top + dyBorder;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
|
|
//
|
|
// Keystroke line top.
|
|
//
|
|
rcTemp.right = rcStatusLine.right - 8 * dyBorder;
|
|
rcTemp.left = rcTemp.right - dxKeystrokeField;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
|
|
//
|
|
// Status line left side.
|
|
//
|
|
rcTemp = rcStatusLine;
|
|
rcTemp.left = 8 * dyBorder;
|
|
rcTemp.right = rcTemp.left + dyBorder;
|
|
rcTemp.top += dyBorder * 2;
|
|
rcTemp.bottom -= dyBorder * 2;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
|
|
//
|
|
// Keystroke line left side.
|
|
//
|
|
rcTemp.left = rcStatusLine.right - 9 * dyBorder - dxKeystrokeField;
|
|
rcTemp.right = rcTemp.left + dyBorder;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
|
|
DeleteObject(hBrush);
|
|
}
|
|
|
|
if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT)))
|
|
{
|
|
//
|
|
// Status line bottom.
|
|
//
|
|
rcTemp.left = 8 * dyBorder;
|
|
rcTemp.right = rcTemp.left + dxHelpField;
|
|
rcTemp.top = rcStatusLine.bottom - 3 * dyBorder;
|
|
rcTemp.bottom = rcTemp.top + dyBorder;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
|
|
//
|
|
// Keystroke line bottom.
|
|
//
|
|
rcTemp.right = rcStatusLine.right - 8 * dyBorder;
|
|
rcTemp.left = rcTemp.right - dxKeystrokeField;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
|
|
//
|
|
// Status line right side.
|
|
//
|
|
rcTemp = rcStatusLine;
|
|
rcTemp.left = 8 * dyBorder + dxHelpField;
|
|
rcTemp.right = rcTemp.left + dyBorder;
|
|
rcTemp.top += dyBorder * 2;
|
|
rcTemp.bottom -= dyBorder * 2;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
|
|
//
|
|
// Keystroke line right side.
|
|
//
|
|
rcTemp.left = rcStatusLine.right - 8 * dyBorder;
|
|
rcTemp.right = rcTemp.left + dyBorder;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
|
|
DeleteObject(hBrush);
|
|
}
|
|
|
|
//
|
|
// Solid black line across top.
|
|
//
|
|
if (hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME)))
|
|
{
|
|
rcTemp = rcStatusLine;
|
|
rcTemp.bottom = rcTemp.top;
|
|
rcTemp.top -= dyBorder;
|
|
FillRect(hdc, &rcTemp, hBrush);
|
|
DeleteObject(hBrush);
|
|
}
|
|
|
|
PaintStatusLine(hdc, TRUE, TRUE);
|
|
|
|
EndPaint(hWnd, &ps);
|
|
|
|
return (TRUE);
|
|
}
|
|
case ( WM_MEASUREITEM ) :
|
|
{
|
|
HDC hDC;
|
|
HFONT hFont;
|
|
TEXTMETRIC tm;
|
|
|
|
hDC = GetDC(NULL);
|
|
hFont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0L);
|
|
if (hFont)
|
|
{
|
|
hFont = SelectObject(hDC, hFont);
|
|
}
|
|
GetTextMetrics(hDC, &tm);
|
|
if (hFont)
|
|
{
|
|
SelectObject(hDC, hFont);
|
|
}
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
((LPMEASUREITEMSTRUCT)lParam)->itemHeight = max(tm.tmHeight, DY_BITMAP);
|
|
break;
|
|
}
|
|
case ( WM_DRAWITEM ) :
|
|
{
|
|
if (((LPDRAWITEMSTRUCT)lParam)->itemID != -1)
|
|
{
|
|
DrawFamilyComboItem((LPDRAWITEMSTRUCT)lParam);
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_ASKCBFORMATNAME ) :
|
|
{
|
|
LoadString(hInst, IDS_RTF, (LPTSTR)lParam, wParam);
|
|
return (TRUE);
|
|
}
|
|
case ( WM_PAINTCLIPBOARD ) :
|
|
{
|
|
LPPAINTSTRUCT lpPS;
|
|
HANDLE hFont;
|
|
LPTSTR lpstrText;
|
|
|
|
if (hstrClipboard)
|
|
{
|
|
//
|
|
// Setup.
|
|
//
|
|
lpPS = (LPPAINTSTRUCT)GlobalLock((HANDLE)lParam);
|
|
lpstrText = (LPTSTR)GlobalLock(hstrClipboard);
|
|
|
|
//
|
|
// Paint.
|
|
//
|
|
hFont = SelectObject(lpPS->hdc, hFontClipboard);
|
|
TextOut(lpPS->hdc, 0, 0, lpstrText, lstrlen(lpstrText));
|
|
SelectObject(lpPS->hdc, hFont);
|
|
|
|
//
|
|
// Cleanup.
|
|
//
|
|
GlobalUnlock(hstrClipboard);
|
|
GlobalUnlock((HANDLE)lParam);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
case ( WM_CLOSE ) :
|
|
{
|
|
DestroyWindow(hWnd);
|
|
return (TRUE);
|
|
}
|
|
case ( WM_COMMAND ) :
|
|
{
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case ( IDCANCEL ) :
|
|
case ( ID_CLOSE ) :
|
|
{
|
|
DestroyWindow(hWnd);
|
|
return (TRUE);
|
|
break;
|
|
}
|
|
case ( ID_SELECT ) :
|
|
{
|
|
WCHAR wch = sycm.chCurr;
|
|
|
|
if (sycm.fAnsiFont)
|
|
{
|
|
wch = ConvertANSIFontToUnicode( hWnd,
|
|
sycm.hFont,
|
|
(char)wch );
|
|
}
|
|
|
|
SendDlgItemMessage(hWnd, ID_STRING, WM_CHAR, (WPARAM)wch, 0L);
|
|
break;
|
|
}
|
|
case ( ID_COPY ) :
|
|
{
|
|
CopyString(hWnd);
|
|
return (TRUE);
|
|
break;
|
|
}
|
|
case ( ID_FONT ) :
|
|
{
|
|
if (HIWORD(wParam) == CBN_SELCHANGE)
|
|
{
|
|
RecalcCharMap( hWnd,
|
|
&sycm,
|
|
(INT)SendDlgItemMessage( hWnd,
|
|
ID_FONT,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0L ),
|
|
TRUE );
|
|
SetEditCtlFont(hWnd, ID_STRING, sycm.hFont);
|
|
}
|
|
else if (HIWORD(wParam) == CBN_SETFOCUS)
|
|
{
|
|
//
|
|
// Necessary if hotkey is used to get to the CB.
|
|
//
|
|
UpdateHelpText(NULL, (HWND)lParam);
|
|
}
|
|
|
|
return (TRUE);
|
|
break;
|
|
}
|
|
case ( ID_UNICODESUBSET ) :
|
|
{
|
|
if (HIWORD(wParam) == CBN_SELCHANGE)
|
|
{
|
|
INT iSubset;
|
|
INT cEntries;
|
|
|
|
iSubset = (INT)SendDlgItemMessage( hWnd,
|
|
ID_UNICODESUBSET,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0 );
|
|
SubSetChanged( hWnd,
|
|
iSubset,
|
|
aSubsetData[iSubset].BeginRange,
|
|
aSubsetData[iSubset].EndRange );
|
|
|
|
cEntries = (INT)SendDlgItemMessage( hWnd,
|
|
ID_UNICODESUBSET,
|
|
CB_GETCOUNT,
|
|
0,
|
|
0 ) - 1;
|
|
|
|
EnableWindow( GetDlgItem(hWnd, ID_PREVSUBSET),
|
|
iSubset > 0 );
|
|
|
|
EnableWindow( GetDlgItem(hWnd, ID_NEXTSUBSET),
|
|
iSubset < cEntries );
|
|
}
|
|
else if (HIWORD(wParam) == CBN_SETFOCUS)
|
|
{
|
|
//
|
|
// Necessary if hotkey is used to get to the CB.
|
|
//
|
|
UpdateHelpText(NULL, (HWND)lParam);
|
|
}
|
|
return (0L);
|
|
break;
|
|
}
|
|
case ( ID_NEXTSUBSET ) :
|
|
{
|
|
INT iCurSelection, iNumEntries;
|
|
|
|
iCurSelection = (INT)SendDlgItemMessage( hWnd,
|
|
ID_UNICODESUBSET,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0 );
|
|
if (iCurSelection == CB_ERR)
|
|
{
|
|
return (0L);
|
|
}
|
|
iNumEntries = (INT)SendDlgItemMessage( hWnd,
|
|
ID_UNICODESUBSET,
|
|
CB_GETCOUNT,
|
|
0,
|
|
0 );
|
|
if (iNumEntries == CB_ERR)
|
|
{
|
|
return (0L);
|
|
}
|
|
if (iCurSelection++ < (iNumEntries - 1))
|
|
{
|
|
if (iCurSelection == 1)
|
|
{
|
|
//
|
|
// Enable Previous button.
|
|
//
|
|
EnableWindow(GetDlgItem(hWnd, ID_PREVSUBSET), TRUE);
|
|
}
|
|
|
|
SendDlgItemMessage( hWnd,
|
|
ID_UNICODESUBSET,
|
|
CB_SETCURSEL,
|
|
iCurSelection,
|
|
0 );
|
|
SubSetChanged( hWnd,
|
|
iCurSelection,
|
|
aSubsetData[iCurSelection].BeginRange,
|
|
aSubsetData[iCurSelection].EndRange );
|
|
if (iCurSelection == (iNumEntries - 1))
|
|
{
|
|
HWND hwndButton;
|
|
|
|
EnableWindow(GetDlgItem(hWnd, ID_NEXTSUBSET), FALSE);
|
|
//
|
|
// Only reset the button style and focus if
|
|
// the "Next" button currently has it.
|
|
//
|
|
if (iControl == ID_NEXTSUBSET)
|
|
{
|
|
SendDlgItemMessage( hwndDialog,
|
|
ID_PREVSUBSET,
|
|
BM_SETSTYLE,
|
|
BS_DEFPUSHBUTTON,
|
|
1 );
|
|
SendDlgItemMessage( hwndDialog,
|
|
ID_NEXTSUBSET,
|
|
BM_SETSTYLE,
|
|
BS_PUSHBUTTON,
|
|
1 );
|
|
hwndButton = GetDlgItem(hWnd, ID_PREVSUBSET);
|
|
SetFocus(hwndButton);
|
|
UpdateHelpText(NULL, hwndButton);
|
|
}
|
|
}
|
|
}
|
|
return (0L);
|
|
break;
|
|
}
|
|
case ( ID_PREVSUBSET ) :
|
|
{
|
|
INT iCurSelection;
|
|
|
|
iCurSelection = (INT)SendDlgItemMessage( hWnd,
|
|
ID_UNICODESUBSET,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0 );
|
|
if (iCurSelection == CB_ERR)
|
|
{
|
|
return (0L);
|
|
}
|
|
if (iCurSelection > 0)
|
|
{
|
|
iCurSelection--;
|
|
|
|
if (iCurSelection == (cSubsets - 2))
|
|
{
|
|
//
|
|
// Enable Next button.
|
|
//
|
|
EnableWindow(GetDlgItem(hWnd, ID_NEXTSUBSET), TRUE);
|
|
}
|
|
|
|
SendDlgItemMessage( hWnd,
|
|
ID_UNICODESUBSET,
|
|
CB_SETCURSEL,
|
|
iCurSelection,
|
|
0 );
|
|
SubSetChanged( hWnd,
|
|
iCurSelection,
|
|
aSubsetData[iCurSelection].BeginRange,
|
|
aSubsetData[iCurSelection].EndRange );
|
|
if (iCurSelection == 0)
|
|
{
|
|
HWND hwndButton;
|
|
|
|
EnableWindow(GetDlgItem(hWnd, ID_PREVSUBSET), FALSE);
|
|
//
|
|
// Only reset the button style and focus if
|
|
// the "Previous" button currently has it.
|
|
//
|
|
if (iControl == ID_PREVSUBSET)
|
|
{
|
|
SendDlgItemMessage( hwndDialog,
|
|
ID_NEXTSUBSET,
|
|
BM_SETSTYLE,
|
|
BS_DEFPUSHBUTTON,
|
|
1 );
|
|
SendDlgItemMessage( hwndDialog,
|
|
ID_PREVSUBSET,
|
|
BM_SETSTYLE,
|
|
BS_PUSHBUTTON,
|
|
1 );
|
|
hwndButton = GetDlgItem(hWnd, ID_NEXTSUBSET);
|
|
SetFocus(hwndButton);
|
|
UpdateHelpText(NULL, hwndButton);
|
|
}
|
|
}
|
|
}
|
|
return (0L);
|
|
break;
|
|
}
|
|
case ( ID_STRING ) :
|
|
{
|
|
if (HIWORD(wParam) == EN_SETFOCUS)
|
|
{
|
|
//
|
|
// Necessary if hotkey is used to get to the EC.
|
|
//
|
|
UpdateHelpText(NULL, (HWND)lParam);
|
|
}
|
|
else if (HIWORD(wParam) == EN_CHANGE)
|
|
{
|
|
//
|
|
// Disable Copy button if there are no chars in EC.
|
|
//
|
|
INT iLength;
|
|
|
|
iLength = GetWindowTextLength((HWND)lParam);
|
|
EnableWindow(GetDlgItem(hWnd, ID_COPY), (BOOL)iLength);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case ( ID_HELP ) :
|
|
{
|
|
DoHelp(hWnd, TRUE);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_DESTROY ) :
|
|
{
|
|
SaveCurrentFont(hWnd);
|
|
SaveCurrentSubset(hWnd);
|
|
DoHelp(hWnd, FALSE);
|
|
DeleteObject(hStaticBrush);
|
|
PostQuitMessage(0);
|
|
break;
|
|
}
|
|
case ( WM_ACTIVATEAPP ) :
|
|
{
|
|
if (wParam)
|
|
{
|
|
SendDlgItemMessage( hWnd,
|
|
ID_STRING,
|
|
EM_SETSEL,
|
|
LOWORD(lEditSel),
|
|
HIWORD(lEditSel) );
|
|
}
|
|
else
|
|
{
|
|
lEditSel = SendDlgItemMessage(hWnd, ID_STRING, EM_GETSEL, 0, 0L);
|
|
SendDlgItemMessage(hWnd, ID_STRING, EM_SETSEL, 0, 0L);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (0L);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CharGridWndProc
|
|
//
|
|
// Processes messages for the character grid window.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
LRESULT APIENTRY CharGridWndProc(
|
|
HWND hWnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
switch (message)
|
|
{
|
|
case ( WM_CREATE ) :
|
|
{
|
|
RECT rect;
|
|
HDC hdcScrn;
|
|
POINT point1, point2;
|
|
|
|
//
|
|
// Setup global.
|
|
//
|
|
hwndCharGrid = hWnd;
|
|
|
|
GetClientRect(hWnd, &rect);
|
|
|
|
//
|
|
// Calculate metrics for the character grid and the
|
|
// magnify window.
|
|
//
|
|
sycm.dxpBox = (rect.right - 1) / (cchSymRow + 2);
|
|
sycm.dypBox = (rect.bottom - 2) / (cchSymCol + 1);
|
|
sycm.dxpCM = sycm.dxpBox * cchSymRow + 1;
|
|
sycm.dypCM = sycm.dypBox * cchSymCol + 1; // space inside for border
|
|
|
|
if ((PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_CHINESE))
|
|
{
|
|
sycm.dxpMag = sycm.dxpBox * 3 + 5;
|
|
}
|
|
else
|
|
{
|
|
sycm.dxpMag = sycm.dxpBox * 2 + 4; // twice the size + 2 bit border
|
|
}
|
|
sycm.dypMag = sycm.dypBox * 2 + 4;
|
|
|
|
sycm.chCurr = chSymFirst;
|
|
sycm.hFontMag = NULL;
|
|
sycm.hFont = NULL;
|
|
sycm.hdcMag = NULL;
|
|
sycm.hbmMag = NULL;
|
|
sycm.ypDest = 0;
|
|
|
|
sycm.fFocusState = sycm.fMouseDn = sycm.fCursorOff = FALSE;
|
|
|
|
//
|
|
// Size the window precisely so the grid fits and is centered.
|
|
//
|
|
MoveWindow( hWnd,
|
|
(rect.right - sycm.dxpCM + 1) / 2,
|
|
(rect.bottom - sycm.dypCM + 1) / 2 +
|
|
((LPCREATESTRUCT)lParam)->y - 2,
|
|
sycm.dxpCM + 2,
|
|
sycm.dypCM + 2,
|
|
FALSE );
|
|
|
|
//
|
|
// Figure out what the offsets are between the dialog
|
|
// and the character grid window.
|
|
//
|
|
point1.x = point1.y = point2.x = point2.y = 0;
|
|
ClientToScreen(hWnd, &point1);
|
|
ClientToScreen(((LPCREATESTRUCT)lParam)->hwndParent, &point2);
|
|
#ifdef USE_MIRRORING
|
|
sycm.xpCM = (abs(point1.x - point2.x)) - (sycm.dxpMag - sycm.dxpBox) / 2;
|
|
#else
|
|
sycm.xpCM = (point1.x - point2.x) - (sycm.dxpMag - sycm.dxpBox) / 2;
|
|
#endif
|
|
sycm.ypCM = (point1.y - point2.y) - (sycm.dypMag - sycm.dypBox) / 2;
|
|
|
|
//
|
|
// Create dc and bitmap for the magnify window.
|
|
//
|
|
if ((hdcScrn = GetWindowDC(hWnd)) != NULL)
|
|
{
|
|
if ((sycm.hdcMag = CreateCompatibleDC(hdcScrn)) != NULL)
|
|
{
|
|
SetTextColor( sycm.hdcMag,
|
|
GetSysColor(COLOR_WINDOWTEXT) );
|
|
SetBkColor( sycm.hdcMag,
|
|
GetSysColor(COLOR_WINDOW) );
|
|
SetBkMode(sycm.hdcMag, OPAQUE);
|
|
if ((sycm.hbmMag =
|
|
CreateCompatibleBitmap( hdcScrn,
|
|
sycm.dxpMag,
|
|
sycm.dypMag * 2 )) == NULL)
|
|
{
|
|
DeleteObject(sycm.hdcMag);
|
|
}
|
|
else
|
|
{
|
|
SelectObject(sycm.hdcMag, sycm.hbmMag);
|
|
}
|
|
}
|
|
ReleaseDC(hWnd, hdcScrn);
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_DESTROY ) :
|
|
{
|
|
if (sycm.fMouseDn)
|
|
{
|
|
ExitMagnify(hWnd, &sycm);
|
|
}
|
|
if (fDelClipboardFont)
|
|
{
|
|
DeleteObject(hFontClipboard);
|
|
}
|
|
if (sycm.hFont != NULL)
|
|
{
|
|
DeleteObject(sycm.hFont);
|
|
}
|
|
if (sycm.hFontMag != NULL)
|
|
{
|
|
DeleteObject(sycm.hFontMag);
|
|
}
|
|
if (sycm.hdcMag != NULL)
|
|
{
|
|
DeleteDC(sycm.hdcMag);
|
|
}
|
|
if (sycm.hbmMag != NULL)
|
|
{
|
|
DeleteObject(sycm.hbmMag);
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_SETFOCUS ) :
|
|
case ( WM_KILLFOCUS ) :
|
|
{
|
|
RestoreSymMag(&sycm);
|
|
DrawSymChOutlineHwnd( &sycm,
|
|
hWnd,
|
|
sycm.chCurr,
|
|
TRUE,
|
|
message == WM_SETFOCUS );
|
|
break;
|
|
}
|
|
case ( WM_LBUTTONDOWN ) :
|
|
{
|
|
RECT rect;
|
|
|
|
DOUTL("WM_LBUTTONDOWN: In\n");
|
|
|
|
//
|
|
// Don't draw anything if there's an update region pending.
|
|
//
|
|
if (GetUpdateRect(hWnd, (LPRECT)&rect, FALSE) != 0)
|
|
{
|
|
DOUTL("WM_LBUTTONDOWN: No upd rect\n");
|
|
break;
|
|
}
|
|
|
|
SetFocus(hWnd);
|
|
SetCapture(hWnd);
|
|
|
|
sycm.fMouseDn = TRUE;
|
|
|
|
if (!FMagData(&sycm))
|
|
{
|
|
DOUTL("WM_LBUTTONDOWN: Drawing sym outline\n");
|
|
DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE);
|
|
}
|
|
|
|
//
|
|
// Fall through to WM_MOUSEMOVE...
|
|
//
|
|
}
|
|
case ( WM_MOUSEMOVE ) :
|
|
{
|
|
DOUTL("WM_MOUSEMOVE: In\n");
|
|
if (sycm.fMouseDn)
|
|
{
|
|
POINT pt;
|
|
UINT chMouseSymbol;
|
|
|
|
DOUTL("WM_MOUSEMOVE: mouse is down\n");
|
|
|
|
pt.x = LOWORD(lParam);
|
|
pt.y = HIWORD(lParam);
|
|
ClientToScreen(hWnd, (LPPOINT)&pt);
|
|
if (WindowFromPoint(pt) == hWnd)
|
|
{
|
|
ScreenToClient(hWnd, (LPPOINT)&pt);
|
|
//
|
|
// Convert back to a 'points'-like thing.
|
|
//
|
|
lParam = MAKELONG((WORD)pt.x, (WORD)pt.y);
|
|
chMouseSymbol = (UINT)ChFromSymLParam(&sycm, lParam);
|
|
if (chMouseSymbol > (UINT)chSymLast)
|
|
{
|
|
//
|
|
// We're outside of current character range (but
|
|
// still within the grid). Restore cursor and
|
|
// leave magnified character.
|
|
//
|
|
if (sycm.fCursorOff)
|
|
{
|
|
sycm.fCursorOff = FALSE;
|
|
ShowCursor(TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We're in the grid and within the range of currently
|
|
// displayed characters, display magnified character.
|
|
//
|
|
DOUTL("WM_MOUSEMOVE: in grid and subrange\n");
|
|
|
|
if (!sycm.fCursorOff)
|
|
{
|
|
sycm.fCursorOff = TRUE;
|
|
ShowCursor(FALSE);
|
|
}
|
|
DOUTL("WM_MOUSEMOVE: movsymsel ");
|
|
DOUTCHN( (UTCHAR)chMouseSymbol );
|
|
MoveSymbolSel(&sycm, (UTCHAR)chMouseSymbol);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Left grid, leave magnified character and restore
|
|
// cursor.
|
|
//
|
|
if (sycm.fCursorOff)
|
|
{
|
|
sycm.fCursorOff = FALSE;
|
|
ShowCursor(TRUE);
|
|
}
|
|
}
|
|
}
|
|
DOUTL("WM_MOUSEMOVE: Leaving\n");
|
|
break;
|
|
}
|
|
case ( WM_CANCELMODE ) :
|
|
case ( WM_LBUTTONUP ) :
|
|
{
|
|
if (sycm.fMouseDn)
|
|
{
|
|
ExitMagnify(hWnd, &sycm);
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_LBUTTONDBLCLK ) :
|
|
{
|
|
WCHAR wch = sycm.chCurr;
|
|
|
|
//
|
|
// Send this character to the entry field.
|
|
//
|
|
if (sycm.fAnsiFont)
|
|
{
|
|
wch = ConvertANSIFontToUnicode(hWnd, sycm.hFont, (char)wch);
|
|
}
|
|
|
|
SendDlgItemMessage(hwndDialog, ID_STRING, WM_CHAR, (WPARAM)wch, 0L);
|
|
break;
|
|
}
|
|
case ( WM_GETDLGCODE ) :
|
|
{
|
|
//
|
|
// Necessary to obtain arrow and tab messages.
|
|
//
|
|
return (DLGC_WANTARROWS | DLGC_WANTCHARS);
|
|
break;
|
|
}
|
|
case ( WM_KEYDOWN ) :
|
|
{
|
|
UTCHAR chNew = sycm.chCurr;
|
|
INT cchMoved;
|
|
|
|
if (sycm.fMouseDn)
|
|
{
|
|
break;
|
|
}
|
|
|
|
switch (wParam)
|
|
{
|
|
case ( VK_LEFT ) :
|
|
{
|
|
if (--chNew < chSymFirst)
|
|
{
|
|
return (0L);
|
|
}
|
|
break;
|
|
}
|
|
case ( VK_UP ) :
|
|
{
|
|
if ((chNew -= cchSymRow) < chSymFirst)
|
|
{
|
|
if (!ScrollMap(GetParent(hWnd), -cchSymRow, TRUE))
|
|
{
|
|
return (0L);
|
|
}
|
|
RestoreSymMag(&sycm);
|
|
}
|
|
break;
|
|
}
|
|
case ( VK_RIGHT ) :
|
|
{
|
|
if (++chNew > chSymLast)
|
|
{
|
|
return (0L);
|
|
}
|
|
break;
|
|
}
|
|
case ( VK_DOWN ) :
|
|
{
|
|
if ((chNew += cchSymRow) > chSymLast)
|
|
{
|
|
if (!ScrollMap(GetParent(hWnd), cchSymRow, TRUE))
|
|
{
|
|
return (0L);
|
|
}
|
|
RestoreSymMag(&sycm);
|
|
}
|
|
break;
|
|
}
|
|
case ( VK_NEXT ) :
|
|
{
|
|
if ((cchMoved =
|
|
ScrollMapPage(GetParent(hWnd), FALSE, TRUE)) == 0)
|
|
{
|
|
return (0L);
|
|
}
|
|
//
|
|
// We scrolled the map! Bump the char so it is
|
|
// still in the window.
|
|
//
|
|
RestoreSymMag(&sycm);
|
|
chNew += cchMoved;
|
|
break;
|
|
}
|
|
case ( VK_PRIOR ) :
|
|
{
|
|
if ((cchMoved =
|
|
ScrollMapPage( GetParent(hWnd), TRUE, TRUE )) == 0)
|
|
{
|
|
return (0L);
|
|
}
|
|
|
|
//
|
|
// We scrolled the map! Bump the char so it is
|
|
// still in the window.
|
|
//
|
|
RestoreSymMag(&sycm);
|
|
chNew += cchMoved;
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
return (0L);
|
|
}
|
|
}
|
|
|
|
if (!FMagData(&sycm))
|
|
{
|
|
DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE);
|
|
}
|
|
MoveSymbolSel(&sycm, (UTCHAR)chNew);
|
|
break;
|
|
}
|
|
case ( WM_CHAR ) :
|
|
{
|
|
WCHAR wch = (WCHAR)wParam;
|
|
char ch;
|
|
|
|
if (sycm.fMouseDn)
|
|
{
|
|
break;
|
|
}
|
|
if (sycm.fAnsiFont)
|
|
{
|
|
if (WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
&wch,
|
|
1,
|
|
&ch,
|
|
1,
|
|
NULL,
|
|
NULL ) != 1)
|
|
{
|
|
break;
|
|
}
|
|
wch = (WCHAR)(BYTE)ch;
|
|
}
|
|
|
|
if ((wch >= chSymFirst) && (wch <= chSymLast))
|
|
{
|
|
if (!FMagData(&sycm))
|
|
{
|
|
DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE);
|
|
}
|
|
MoveSymbolSel(&sycm, (UTCHAR)wch);
|
|
SendDlgItemMessage(hwndDialog, ID_STRING, WM_CHAR, wParam, 0L);
|
|
}
|
|
break;
|
|
}
|
|
case ( WM_PAINT ) :
|
|
{
|
|
HDC hdc;
|
|
PAINTSTRUCT ps;
|
|
|
|
DOUTL("WM_PAINT: In\n");
|
|
|
|
hdc = BeginPaint(hWnd, &ps);
|
|
DOUTL("WM_PAINT: drawing map\n");
|
|
DrawSymbolMap(&sycm, hdc);
|
|
EndPaint(hWnd, &ps);
|
|
|
|
DOUTL("WM_PAINT: Leaving\n");
|
|
return (TRUE);
|
|
}
|
|
default :
|
|
{
|
|
return (DefWindowProc(hWnd, message, wParam, lParam));
|
|
}
|
|
}
|
|
|
|
return (0L);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ProcessScrollMsg
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID ProcessScrollMsg(
|
|
HWND hwndDlg,
|
|
int nCode,
|
|
int nPos)
|
|
{
|
|
UTCHAR chNew = sycm.chCurr;
|
|
HWND hwndGrid = GetDlgItem(hwndDlg, ID_CHARGRID);
|
|
int cchScroll;
|
|
|
|
switch( nCode )
|
|
{
|
|
case ( SB_LINEUP ) :
|
|
{
|
|
cchScroll = -cchSymRow;
|
|
break;
|
|
}
|
|
case ( SB_LINEDOWN ) :
|
|
{
|
|
cchScroll = cchSymRow;
|
|
break;
|
|
}
|
|
case ( SB_PAGEUP ) :
|
|
{
|
|
cchScroll = (int)TRUE;
|
|
break;
|
|
}
|
|
case ( SB_PAGEDOWN ) :
|
|
{
|
|
cchScroll = (int)FALSE;
|
|
break;
|
|
}
|
|
case ( SB_THUMBTRACK ) :
|
|
case ( SB_THUMBPOSITION ) :
|
|
{
|
|
cchScroll = (nPos * cchSymRow + chRangeFirst) - chSymFirst;
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (nCode == SB_PAGEUP || nCode == SB_PAGEDOWN)
|
|
{
|
|
if (!ScrollMapPage(hwndDlg, (BOOL)cchScroll, FALSE))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// ScrollMapPage will do the right thing to sycm.chCurr.
|
|
//
|
|
chNew = sycm.chCurr;
|
|
}
|
|
else
|
|
{
|
|
if (cchScroll == 0 || !ScrollMap(hwndDlg, cchScroll, FALSE))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Keep the current symbol inside the window.
|
|
//
|
|
while (chNew > chSymLast)
|
|
{
|
|
chNew -= cchSymRow;
|
|
}
|
|
|
|
while (chNew < chSymFirst)
|
|
{
|
|
chNew += cchSymRow;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if (!FMagData(&sycm))
|
|
{
|
|
DrawSymChOutlineHwnd(&sycm, hwndGrid, sycm.chCurr, FALSE, FALSE);
|
|
}
|
|
MoveSymbolSel(&sycm, (UTCHAR)chNew);
|
|
#else
|
|
sycm.chCurr = chNew;
|
|
InvalidateRect(hwndGrid, NULL, TRUE);
|
|
#endif
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ScrollMapPage
|
|
//
|
|
// Scrolls the map up or down by a page. See ScrollMap().
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
INT ScrollMapPage(
|
|
HWND hwndDlg,
|
|
BOOL fUp,
|
|
BOOL fRePaint)
|
|
{
|
|
INT cchScroll = cchFullMap;
|
|
|
|
if (fUp)
|
|
{
|
|
cchScroll = -cchScroll;
|
|
}
|
|
|
|
if ((chSymFirst + cchScroll) < chRangeFirst)
|
|
{
|
|
cchScroll = (chRangeFirst - chSymFirst);
|
|
}
|
|
else if ((chSymLast + cchScroll) > chRangeLast)
|
|
{
|
|
cchScroll = (chRangeLast - chSymLast);
|
|
}
|
|
|
|
return (ScrollMap(hwndDlg, cchScroll, fRePaint) ? cchScroll : 0);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ScrollMap
|
|
//
|
|
// Scrolls the map up or down if there are too many chars to fit in the
|
|
// chargrid.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL ScrollMap(
|
|
HWND hwndDlg,
|
|
INT cchScroll,
|
|
BOOL fRePaint)
|
|
{
|
|
HWND hwndSB, hwndCharGrid;
|
|
INT chFirst = chSymFirst + cchScroll;
|
|
INT chLast = chSymLast + cchScroll;
|
|
HDC hdc;
|
|
|
|
if ((chFirst < chRangeFirst) || (chLast > chRangeLast))
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
hwndCharGrid = GetDlgItem(hwndDlg, ID_CHARGRID);
|
|
hwndSB = GetDlgItem(hwndDlg, ID_MAPSCROLL);
|
|
SetScrollPos(hwndSB, SB_CTL, (chFirst - chRangeFirst) / cchSymRow, TRUE);
|
|
|
|
UpdateSymbolRange(hwndDlg, chFirst, chLast);
|
|
|
|
if ((hwndDlg != NULL) && ((hdc = GetDC(hwndDlg)) != NULL))
|
|
{
|
|
LPINT lpdxp;
|
|
HFONT hFont;
|
|
UINT ch;
|
|
|
|
hFont = SelectObject(hdc, sycm.hFont);
|
|
lpdxp = (LPINT)sycm.rgdxp;
|
|
|
|
if (sycm.fAnsiFont)
|
|
{
|
|
GetCharWidth32A(hdc, chSymFirst, chSymLast, lpdxp);
|
|
}
|
|
else
|
|
{
|
|
GetCharWidth32(hdc, chSymFirst, chSymLast, lpdxp);
|
|
}
|
|
|
|
SelectObject(hdc, hFont);
|
|
|
|
for (ch = (UINT) chSymFirst; ch <= (UINT) chSymLast; ch++, lpdxp++)
|
|
{
|
|
*lpdxp = (sycm.dxpBox - *lpdxp) / 2 - 1;
|
|
}
|
|
ReleaseDC(hwndDlg, hdc);
|
|
}
|
|
|
|
if (fRePaint)
|
|
{
|
|
InvalidateRect(hwndCharGrid, NULL, TRUE);
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ChFromSymLParam
|
|
//
|
|
// Determines the character to select from the mouse position (lParam).
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
INT ChFromSymLParam(
|
|
PSYCM psycm,
|
|
LPARAM lParam)
|
|
{
|
|
return (min( cchSymRow - 1,
|
|
max(0, ((INT)LOWORD(lParam) - 1) / psycm->dxpBox) ) +
|
|
min( cchSymCol - 1,
|
|
max(0, ((INT)HIWORD(lParam) - 1) / psycm->dypBox) ) *
|
|
cchSymRow + chSymFirst);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DrawSymChOutlineHwnd
|
|
//
|
|
// Gets a DC for hwnd, calls DrawSymChOutline.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID DrawSymChOutlineHwnd(
|
|
PSYCM psycm,
|
|
HWND hwnd,
|
|
UTCHAR ch,
|
|
BOOL fVisible,
|
|
BOOL fFocus)
|
|
{
|
|
HDC hdc = GetDC(hwnd);
|
|
|
|
DrawSymChOutline(psycm, hdc, ch, fVisible, fFocus);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RecalcCharMap
|
|
//
|
|
// Recalculates fixed character map data (font info, sizes, etc.).
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID RecalcCharMap(
|
|
HWND hwndDlg,
|
|
PSYCM psycm,
|
|
INT iCombo,
|
|
BOOL fRedraw)
|
|
{
|
|
HDC hdc;
|
|
TEXTMETRIC tm;
|
|
UINT ch;
|
|
LPINT lpdxp;
|
|
HFONT hFont;
|
|
LOGFONT LogFont;
|
|
ITEMDATA ItemData;
|
|
LONG iCurSel;
|
|
|
|
//
|
|
// Get rid of the old font handles.
|
|
//
|
|
if (hFontClipboard && (hFontClipboard == psycm->hFont))
|
|
{
|
|
fDelClipboardFont = TRUE;
|
|
}
|
|
if (psycm->hFont && (hFontClipboard != psycm->hFont))
|
|
{
|
|
DeleteObject(psycm->hFont);
|
|
}
|
|
if (psycm->hFontMag)
|
|
{
|
|
DeleteObject(psycm->hFontMag);
|
|
}
|
|
|
|
hdc = GetDC(hwndCharGrid);
|
|
|
|
//
|
|
// Set up the LogFont structure.
|
|
// Make sure it fits in the grid.
|
|
//
|
|
if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_CHINESE)
|
|
{
|
|
LogFont.lfHeight = 16;
|
|
}
|
|
else
|
|
{
|
|
LogFont.lfHeight = psycm->dypBox - 3; // Allow for whitespace.
|
|
}
|
|
//
|
|
// Set these to zero.
|
|
//
|
|
LogFont.lfWidth = LogFont.lfEscapement = LogFont.lfOrientation =
|
|
LogFont.lfWeight = 0;
|
|
LogFont.lfItalic = LogFont.lfUnderline = LogFont.lfStrikeOut =
|
|
LogFont.lfOutPrecision = LogFont.lfClipPrecision =
|
|
LogFont.lfQuality = LogFont.lfPitchAndFamily = 0;
|
|
|
|
//
|
|
// Let the facename and size define the font.
|
|
//
|
|
// LogFont.lfCharSet = DEFAULT_CHARSET;
|
|
|
|
// Work around the GDI bug that assumes the font's default charset
|
|
// is always the system default locale.
|
|
//
|
|
*(DWORD *)&ItemData = SendDlgItemMessage( hwndDlg,
|
|
ID_FONT,
|
|
CB_GETITEMDATA,
|
|
iCombo,
|
|
0L );
|
|
LogFont.lfCharSet = ItemData.CharSet;
|
|
|
|
//
|
|
// Get the facename from the combo box.
|
|
//
|
|
SendDlgItemMessage( hwndDlg,
|
|
ID_FONT,
|
|
CB_GETLBTEXT,
|
|
iCombo,
|
|
(LONG)(LPTSTR)LogFont.lfFaceName );
|
|
|
|
//
|
|
// Enable Block listbox and set defaults appropriately.
|
|
//
|
|
EnableWindow(GetDlgItem(hwndDlg, ID_UNICODESUBSET), TRUE);
|
|
iCurSel = SendDlgItemMessage( hwndDlg,
|
|
ID_UNICODESUBSET,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0L );
|
|
UpdateSymbolSelection( hwndDlg,
|
|
aSubsetData[iCurSel].BeginRange,
|
|
aSubsetData[iCurSel].EndRange );
|
|
//
|
|
// Enable Previous button if not on first subset.
|
|
//
|
|
if (iCurSel > 0)
|
|
{
|
|
EnableWindow(GetDlgItem(hwndDlg, ID_PREVSUBSET), TRUE);
|
|
}
|
|
else
|
|
{
|
|
EnableWindow(GetDlgItem(hwndDlg, ID_PREVSUBSET), FALSE);
|
|
}
|
|
//
|
|
// Enable Next button if not on last subset.
|
|
//
|
|
if (iCurSel < (cSubsets - 1))
|
|
{
|
|
EnableWindow(GetDlgItem(hwndDlg, ID_NEXTSUBSET), TRUE);
|
|
}
|
|
else
|
|
{
|
|
EnableWindow(GetDlgItem(hwndDlg, ID_NEXTSUBSET), FALSE);
|
|
}
|
|
|
|
//
|
|
// The first sub sel is the ANSI code page.
|
|
//
|
|
psycm->fAnsiFont = (iCurSel == 0);
|
|
|
|
//
|
|
// Create the font.
|
|
//
|
|
psycm->hFont = CreateFontIndirect(&LogFont);
|
|
hFont = SelectObject(hdc, psycm->hFont);
|
|
|
|
//
|
|
// Create the magnify font.
|
|
//
|
|
LogFont.lfHeight = psycm->dypMag - 5; // Allow for whitespace.
|
|
psycm->hFontMag = CreateFontIndirect(&LogFont);
|
|
|
|
//
|
|
// Calculate new values and place in window data structure.
|
|
//
|
|
GetTextMetrics(hdc, &tm);
|
|
psycm->xpCh = 2;
|
|
psycm->ypCh = (4 + psycm->dypBox - tm.tmHeight) / 2;
|
|
|
|
lpdxp = (LPINT)psycm->rgdxp;
|
|
|
|
if (psycm->fAnsiFont)
|
|
{
|
|
GetCharWidth32A(hdc, chSymFirst, chSymLast, lpdxp);
|
|
}
|
|
else
|
|
{
|
|
GetCharWidth32(hdc, chSymFirst, chSymLast, lpdxp);
|
|
}
|
|
|
|
SelectObject(hdc, hFont);
|
|
|
|
for (ch = (UINT) chSymFirst; ch <= (UINT) chSymLast; ch++, lpdxp++)
|
|
{
|
|
*lpdxp = (psycm->dxpBox - *lpdxp) / 2 - 1;
|
|
}
|
|
ReleaseDC(hwndCharGrid, hdc);
|
|
|
|
psycm->xpMagCurr = 0; // No magnification data
|
|
|
|
if (fRedraw)
|
|
{
|
|
InvalidateRect(hwndCharGrid, NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DrawSymbolMap
|
|
//
|
|
// Draws all of the pieces of the symbol character map.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID DrawSymbolMap(
|
|
PSYCM psycm,
|
|
HDC hdc)
|
|
{
|
|
BOOL fFocus;
|
|
|
|
DrawSymbolGrid(psycm, hdc);
|
|
DrawSymbolChars(psycm, hdc);
|
|
//
|
|
// We need to force the focus rect to paint if we have the focus
|
|
// since the old focus rect has been drawn over already.
|
|
//
|
|
if (fFocus = psycm->fFocusState)
|
|
{
|
|
psycm->fFocusState = FALSE;
|
|
}
|
|
DrawSymChOutline(psycm, hdc, psycm->chCurr, TRUE, fFocus);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DrawSymbolGrid
|
|
//
|
|
// Draws the symbol character map grid.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID DrawSymbolGrid(
|
|
PSYCM psycm,
|
|
HDC hdc)
|
|
{
|
|
INT cli; // count of lines
|
|
INT xp, yp;
|
|
INT dxpBox = psycm->dxpBox;
|
|
INT dypBox = psycm->dypBox;
|
|
HPEN hpenOld;
|
|
|
|
hpenOld = SelectObject(hdc, CreatePen( PS_SOLID,
|
|
1,
|
|
GetSysColor(COLOR_WINDOWFRAME) ));
|
|
|
|
//
|
|
// Draw horizontal lines.
|
|
//
|
|
xp = psycm->dxpCM + 1;
|
|
yp = 1;
|
|
cli = cchSymCol+1;
|
|
while (cli--)
|
|
{
|
|
MoveToEx(hdc, 1, yp, NULL);
|
|
LineTo(hdc, xp, yp);
|
|
yp += dypBox;
|
|
}
|
|
|
|
//
|
|
// Draw vertical lines.
|
|
//
|
|
yp = psycm->dypCM;
|
|
xp = 1;
|
|
cli = cchSymRow+1;
|
|
while (cli--)
|
|
{
|
|
MoveToEx(hdc, xp, 1, NULL);
|
|
LineTo(hdc, xp, yp);
|
|
xp += dxpBox;
|
|
}
|
|
|
|
DeleteObject(SelectObject(hdc, hpenOld));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DrawSymbolChars
|
|
//
|
|
// Draws the symbol character map.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID DrawSymbolChars(
|
|
PSYCM psycm,
|
|
HDC hdc)
|
|
{
|
|
INT dxpBox = psycm->dxpBox;
|
|
INT dypBox = psycm->dypBox;
|
|
INT cch;
|
|
INT x, y;
|
|
INT yp;
|
|
TCHAR ch;
|
|
HFONT hFontOld;
|
|
RECT rect;
|
|
LPRECT lprect = (LPRECT)▭
|
|
LPINT lpdxp;
|
|
|
|
//
|
|
// Setup the font and colors.
|
|
//
|
|
hFontOld = (HFONT)SelectObject(hdc, psycm->hFont);
|
|
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
|
|
SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
|
|
SetBkMode(hdc, OPAQUE);
|
|
|
|
//
|
|
// Draw characters.
|
|
//
|
|
cch = 1;
|
|
ch = chSymFirst;
|
|
|
|
lpdxp = (LPINT)psycm->rgdxp;
|
|
|
|
rect.top = 2;
|
|
yp = psycm->ypCh;
|
|
rect.bottom = rect.top + dypBox - 1;
|
|
|
|
for (y = 0; y++ < cchSymCol;)
|
|
{
|
|
rect.left = psycm->xpCh;
|
|
rect.right = rect.left + dxpBox - 1;
|
|
for (x = 0; (x++ < cchSymRow) && (ch <= chSymLast);)
|
|
{
|
|
if (psycm->fAnsiFont)
|
|
{
|
|
ExtTextOutA( hdc,
|
|
rect.left + (*lpdxp++),
|
|
yp,
|
|
ETO_OPAQUE | ETO_CLIPPED,
|
|
lprect,
|
|
&(CHAR)ch,
|
|
1,
|
|
NULL );
|
|
}
|
|
else
|
|
{
|
|
ExtTextOutW( hdc,
|
|
rect.left + (*lpdxp++),
|
|
yp,
|
|
ETO_OPAQUE | ETO_CLIPPED,
|
|
lprect,
|
|
&ch,
|
|
1,
|
|
NULL );
|
|
}
|
|
ch++;
|
|
rect.left += dxpBox;
|
|
rect.right += dxpBox;
|
|
}
|
|
yp += dypBox;
|
|
rect.top += dypBox;
|
|
rect.bottom += dypBox;
|
|
}
|
|
|
|
SelectObject(hdc, hFontOld);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DrawSymChOutline
|
|
//
|
|
// Draws an outline around the symbol in the character map. If fVisible,
|
|
// then it draws the outline, otherwise it erases it.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID DrawSymChOutline(
|
|
PSYCM psycm,
|
|
HDC hdc,
|
|
UTCHAR ch,
|
|
BOOL fVisible,
|
|
BOOL fFocus)
|
|
{
|
|
HBRUSH hbrOld;
|
|
RECT rc;
|
|
INT dxpBox = psycm->dxpBox;
|
|
INT dypBox = psycm->dypBox;
|
|
|
|
hbrOld = SelectObject( hdc,
|
|
CreateSolidBrush(GetSysColor( fVisible
|
|
? COLOR_WINDOWFRAME
|
|
: COLOR_WINDOW )) );
|
|
ch -= chSymFirst;
|
|
|
|
rc.left = (ch % cchSymRow) * dxpBox + 2;
|
|
rc.right = rc.left + dxpBox - 1;
|
|
rc.top = (ch / cchSymRow) * dypBox + 2;
|
|
rc.bottom = rc.top + dypBox - 1;
|
|
|
|
//
|
|
// Draw selection rectangle.
|
|
//
|
|
PatBlt(hdc, rc.left, rc.top - 2, dxpBox - 1, 1, PATCOPY);
|
|
PatBlt(hdc, rc.left, rc.bottom + 1, dxpBox - 1, 1, PATCOPY);
|
|
PatBlt(hdc, rc.left - 2, rc.top, 1, dypBox - 1, PATCOPY);
|
|
PatBlt(hdc, rc.right + 1, rc.top, 1, dypBox - 1, PATCOPY);
|
|
|
|
DeleteObject(SelectObject(hdc, GetStockObject(NULL_BRUSH)));
|
|
|
|
//
|
|
// Deal with the focus rectangle.
|
|
//
|
|
if (fFocus != psycm->fFocusState)
|
|
{
|
|
DrawFocusRect(hdc, &rc);
|
|
psycm->fFocusState = fFocus;
|
|
}
|
|
|
|
SelectObject(hdc, hbrOld);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// MoveSymbolSel
|
|
//
|
|
// Changes the current symbol selection. Handles drawing of magnified
|
|
// characters.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID MoveSymbolSel(
|
|
PSYCM psycm,
|
|
UTCHAR chNew)
|
|
{
|
|
HDC hdc;
|
|
HDC hdcMag = psycm->hdcMag;
|
|
RECT rc;
|
|
HFONT hFontOld;
|
|
HFONT hFontMag; // old font in memory dc
|
|
HPEN hpenOld;
|
|
UTCHAR chNorm = chNew - chSymFirst + 32;
|
|
INT dxpMag = psycm->dxpMag; // for quick reference
|
|
INT dypMag = psycm->dypMag;
|
|
INT ypMemSrc = psycm->ypDest;
|
|
INT ypMemDest = ypMemSrc ^ dypMag;
|
|
INT xpCurr = psycm->xpMagCurr;
|
|
INT ypCurr = psycm->ypMagCurr;
|
|
INT xpNew = psycm->xpCM + (psycm->dxpBox * (chNorm % cchSymRow));
|
|
INT ypNew = psycm->ypCM + (psycm->dypBox * ((chNorm / cchSymRow) - 1));
|
|
INT dxpCh; // width of extra character space (used to center char in box)
|
|
INT dypCh;
|
|
SIZE sz;
|
|
|
|
DOUTL("MoveSymbolSel: In\n");
|
|
|
|
if (((chNew == (UTCHAR)psycm->chCurr) && FMagData(psycm)))
|
|
{
|
|
DOUTL("MoveSymbolSel: ch == cur && fMag... exiting\n");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Don't draw a magnified character if the char grid has an update
|
|
// region or is not visible.
|
|
//
|
|
if (!IsWindowVisible(hwndCharGrid) ||
|
|
GetUpdateRect(hwndCharGrid, &rc, FALSE))
|
|
{
|
|
DOUTL("MoveSymbolSel: not vis or upd rect... exiting\n");
|
|
return;
|
|
}
|
|
|
|
hdc = GetDC(hwndDialog);
|
|
|
|
//
|
|
// Setup the magnified font character.
|
|
//
|
|
hFontMag = SelectObject(hdcMag, psycm->hFontMag);
|
|
|
|
if (psycm->fAnsiFont)
|
|
{
|
|
char chANSINew = (char)chNew;
|
|
GetTextExtentPointA(hdcMag, &chANSINew, 1, &sz);
|
|
}
|
|
else
|
|
{
|
|
GetTextExtentPointW(hdcMag, &chNew, 1, &sz);
|
|
}
|
|
|
|
if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_CHINESE)
|
|
{
|
|
dxpCh = (dxpMag - (INT)sz.cx) / 2 - 2;
|
|
dypCh = (dypMag - (INT)sz.cy) / 2 - 2;
|
|
}
|
|
else
|
|
{
|
|
dxpCh = (dxpMag - (INT)sz.cx) / 2 - 1;
|
|
dypCh = (dypMag - (INT)sz.cy) / 2 - 1;
|
|
}
|
|
hpenOld = SelectObject(hdc, CreatePen( PS_SOLID,
|
|
1,
|
|
GetSysColor(COLOR_WINDOWFRAME) ));
|
|
hFontOld = SelectObject(hdc, psycm->hFontMag);
|
|
|
|
//
|
|
// Copy screen data to offscreen bitmap.
|
|
//
|
|
BitBlt(hdcMag, 0, ypMemDest, dxpMag, dypMag, hdc, xpNew, ypNew, SRCCOPY);
|
|
|
|
//
|
|
// Setup DC.
|
|
//
|
|
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
|
|
SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
|
|
SetBkMode(hdc, OPAQUE);
|
|
|
|
if (FMagData(psycm))
|
|
{
|
|
INT xpT = xpNew - xpCurr; // point of overlap in offscreen data
|
|
INT ypT = ypNew - ypCurr;
|
|
INT dxpT = dxpMag - abs(xpT); // size of overlap
|
|
INT dypT = dypMag - abs(ypT);
|
|
|
|
DOUTL("MoveSymbolSel: FMagData\n");
|
|
|
|
if ((dxpT > 0) && (dypT > 0))
|
|
{
|
|
INT xpTmax, ypTmax; // max(0, xpT);
|
|
INT xpTmin, ypTmin; // min(0, xpT);
|
|
INT xpTnmin, ypTnmin; // min(0, -xpT);
|
|
|
|
DOUTL("MoveSymbolSel: dxpT > 0 && dypT > 0\n");
|
|
|
|
if (xpT < 0)
|
|
{
|
|
xpTnmin = - (xpTmin = xpT);
|
|
xpTmax = 0;
|
|
}
|
|
else
|
|
{
|
|
xpTmax = xpT;
|
|
xpTnmin = xpTmin = 0;
|
|
}
|
|
if (ypT < 0)
|
|
{
|
|
ypTnmin = - (ypTmin = ypT);
|
|
ypTmax = 0;
|
|
}
|
|
else
|
|
{
|
|
ypTmax = ypT;
|
|
ypTnmin = ypTmin = 0;
|
|
}
|
|
|
|
rc.left = xpTmax;
|
|
rc.right = xpTmin + dxpMag;
|
|
rc.top = ypTmax + ypMemSrc;
|
|
rc.bottom= ypTmin + dypMag + ypMemSrc;
|
|
|
|
//
|
|
// Copy overlapping offscreen data.
|
|
//
|
|
BitBlt( hdcMag,
|
|
xpTnmin,
|
|
ypTnmin + ypMemDest,
|
|
dxpT,
|
|
dypT,
|
|
hdcMag,
|
|
xpTmax,
|
|
ypTmax + ypMemSrc,
|
|
SRCCOPY );
|
|
|
|
//
|
|
// Print part of char over old screen data.
|
|
//
|
|
if (psycm->fAnsiFont)
|
|
{
|
|
ExtTextOutA( hdcMag,
|
|
xpT + dxpCh,
|
|
ypT + dypCh + ypMemSrc,
|
|
ETO_OPAQUE | ETO_CLIPPED,
|
|
(LPRECT)&rc,
|
|
&(CHAR)chNew,
|
|
1,
|
|
NULL );
|
|
}
|
|
else
|
|
{
|
|
ExtTextOutW( hdcMag,
|
|
xpT + dxpCh,
|
|
ypT + dypCh + ypMemSrc,
|
|
ETO_OPAQUE | ETO_CLIPPED,
|
|
(LPRECT)&rc,
|
|
&chNew,
|
|
1,
|
|
NULL );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Restore old screen data.
|
|
//
|
|
BitBlt(hdc, xpCurr, ypCurr, dxpMag, dypMag, hdcMag, 0, ypMemSrc, SRCCOPY);
|
|
}
|
|
|
|
rc.right = (psycm->xpMagCurr = rc.left = xpNew) + dxpMag - 2;
|
|
rc.bottom = (psycm->ypMagCurr = rc.top = ypNew) + dypMag - 2;
|
|
|
|
//
|
|
// The rectangle.
|
|
//
|
|
MoveToEx(hdc, rc.left, rc.top, NULL);
|
|
LineTo(hdc, rc.left, rc.bottom - 1);
|
|
LineTo(hdc, rc.right - 1, rc.bottom - 1);
|
|
LineTo(hdc, rc.right - 1, rc.top);
|
|
LineTo(hdc, rc.left, rc.top);
|
|
|
|
//
|
|
// The shadow.
|
|
//
|
|
MoveToEx(hdc, rc.right, rc.top + 1, NULL);
|
|
LineTo(hdc, rc.right, rc.bottom);
|
|
LineTo(hdc, rc.left, rc.bottom);
|
|
MoveToEx(hdc, rc.right + 1, rc.top + 2, NULL);
|
|
LineTo(hdc, rc.right + 1, rc.bottom + 1);
|
|
LineTo(hdc, rc.left + 1, rc.bottom + 1);
|
|
|
|
rc.left++;
|
|
rc.top++;
|
|
rc.right--;
|
|
rc.bottom--;
|
|
|
|
//
|
|
// Draw magnified character on screen.
|
|
//
|
|
if (psycm->fAnsiFont)
|
|
{
|
|
ExtTextOutA( hdc,
|
|
xpNew + dxpCh,
|
|
ypNew + dypCh,
|
|
ETO_OPAQUE | ETO_CLIPPED,
|
|
(LPRECT)&rc,
|
|
&(CHAR)chNew,
|
|
1,
|
|
NULL );
|
|
}
|
|
else
|
|
{
|
|
ExtTextOutW( hdc,
|
|
xpNew + dxpCh,
|
|
ypNew + dypCh,
|
|
ETO_OPAQUE | ETO_CLIPPED,
|
|
(LPRECT)&rc,
|
|
&chNew,
|
|
1,
|
|
NULL );
|
|
}
|
|
|
|
psycm->ypDest = ypMemDest;
|
|
|
|
DeleteObject(SelectObject(hdc, hpenOld));
|
|
SelectObject(hdc, hFontOld);
|
|
SelectObject(hdcMag, hFontMag);
|
|
|
|
UpdateKeystrokeText(hdc, psycm->fAnsiFont, chNew, TRUE);
|
|
|
|
ReleaseDC(hwndDialog, hdc);
|
|
|
|
psycm->chCurr = chNew;
|
|
DOUTL("MoveSymbolSel: Leaving\n");
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RestoreSymMag
|
|
//
|
|
// Restores the screen data under the magnifier.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID RestoreSymMag(
|
|
PSYCM psycm)
|
|
{
|
|
if (FMagData(psycm))
|
|
{
|
|
HDC hdc = GetDC(hwndDialog);
|
|
|
|
BitBlt( hdc,
|
|
psycm->xpMagCurr,
|
|
psycm->ypMagCurr,
|
|
psycm->dxpMag,
|
|
psycm->dypMag,
|
|
psycm->hdcMag,
|
|
0,
|
|
psycm->ypDest,
|
|
SRCCOPY );
|
|
|
|
ReleaseDC(hwndDialog, hdc);
|
|
|
|
psycm->xpMagCurr = 0; // flag - no data offscreen (see FMagData)
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FontLoadProc
|
|
//
|
|
// Used by EnumFonts to load our combo box with all the fonts installed
|
|
// in the system.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
INT APIENTRY FontLoadProc(
|
|
LPLOGFONT lpLogFont,
|
|
NEWTEXTMETRICEX* lpTextMetric,
|
|
DWORD nFontType,
|
|
LPARAM lpData)
|
|
{
|
|
INT iPos;
|
|
TCHAR szFace[LF_FACESIZE];
|
|
|
|
//
|
|
// Check for duplicates.
|
|
//
|
|
iPos = (INT)SendDlgItemMessage( (HWND)lpData,
|
|
ID_FONT,
|
|
CB_FINDSTRING,
|
|
(WPARAM)-1,
|
|
(DWORD)&lpLogFont->lfFaceName );
|
|
if (iPos == CB_ERR)
|
|
{
|
|
NotInListYet:
|
|
//
|
|
// Doesn't exist, insert the facename into the combo box.
|
|
//
|
|
iPos = (INT)SendDlgItemMessage( (HWND)lpData,
|
|
ID_FONT,
|
|
CB_ADDSTRING,
|
|
0,
|
|
(DWORD)&lpLogFont->lfFaceName );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Make sure it is not just a substring (want a full match).
|
|
//
|
|
SendDlgItemMessage( (HWND)lpData,
|
|
ID_FONT,
|
|
CB_GETLBTEXT,
|
|
iPos,
|
|
(LONG)(LPTSTR)szFace );
|
|
if (lstrcmpi(szFace, lpLogFont->lfFaceName))
|
|
{
|
|
goto NotInListYet;
|
|
}
|
|
|
|
//
|
|
// Already exists, blow out now if this is not a true type font.
|
|
//
|
|
if (!(nFontType & TRUETYPE_FONTTYPE))
|
|
{
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Store the pertinant font information in the combo item data.
|
|
//
|
|
if ((iPos != CB_ERR) && (iPos != CB_ERRSPACE))
|
|
{
|
|
ITEMDATA ItemData;
|
|
DWORD ntmFlags = lpTextMetric->ntmTm.ntmFlags;
|
|
SHORT sFontType = 0;
|
|
|
|
if (ntmFlags & NTM_PS_OPENTYPE)
|
|
{
|
|
sFontType = PS_OPENTYPE_FONT;
|
|
}
|
|
else if (ntmFlags & NTM_TYPE1)
|
|
{
|
|
sFontType = TYPE1_FONT;
|
|
}
|
|
else if (nFontType & TRUETYPE_FONTTYPE)
|
|
{
|
|
if (ntmFlags & NTM_TT_OPENTYPE)
|
|
sFontType = TT_OPENTYPE_FONT;
|
|
else
|
|
sFontType = TRUETYPE_FONT;
|
|
}
|
|
|
|
ItemData.FontType = sFontType;
|
|
ItemData.CharSet = lpLogFont->lfCharSet;
|
|
ItemData.PitchAndFamily = lpLogFont->lfPitchAndFamily;
|
|
|
|
SendDlgItemMessage( (HWND)lpData,
|
|
ID_FONT,
|
|
CB_SETITEMDATA,
|
|
iPos,
|
|
*(DWORD *)&ItemData );
|
|
}
|
|
|
|
//
|
|
// Continue enumeration.
|
|
//
|
|
return (1);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetEditText
|
|
//
|
|
// Returns HANDLE containing the text in the edit control.
|
|
//
|
|
// NOTE: Caller is responsible for freeing this handle!
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
HANDLE GetEditText(
|
|
HWND hwndDlg)
|
|
{
|
|
INT cchText;
|
|
HWND hwndEditCtl;
|
|
HANDLE hmem;
|
|
LPTSTR lpstrText;
|
|
DWORD dwSel;
|
|
|
|
hwndEditCtl = GetDlgItem(hwndDlg, ID_STRING);
|
|
|
|
cchText = GetWindowTextLength(hwndEditCtl);
|
|
|
|
hmem = GlobalAlloc(0, CTOB((cchText + 1)));
|
|
|
|
lpstrText = (LPTSTR)GlobalLock(hmem);
|
|
|
|
cchText = GetWindowText(hwndEditCtl, lpstrText, cchText+1);
|
|
|
|
dwSel = SendMessage(hwndEditCtl, EM_GETSEL, 0, 0L);
|
|
|
|
if (LOWORD(dwSel) != HIWORD(dwSel))
|
|
{
|
|
//
|
|
// If there is a selection, then only get the selected text.
|
|
//
|
|
*(lpstrText + HIWORD(dwSel)) = TEXT('\0');
|
|
lstrcpy(lpstrText, lpstrText + LOWORD(dwSel));
|
|
}
|
|
|
|
GlobalUnlock(hmem);
|
|
|
|
if (cchText == 0)
|
|
{
|
|
hmem = GlobalFree(hmem);
|
|
}
|
|
|
|
return (hmem);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CopyString
|
|
//
|
|
// Implements the copy function.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID CopyString(
|
|
HWND hwndDlg)
|
|
{
|
|
HANDLE hmem;
|
|
LPTSTR lpstrText;
|
|
|
|
if (hmem = GetEditText(hwndDlg))
|
|
{
|
|
lpstrText = (LPTSTR)GlobalLock(hmem);
|
|
|
|
//
|
|
// Copying string to clipboard.
|
|
//
|
|
if (OpenClipboard(hwndDlg))
|
|
{
|
|
EmptyClipboard();
|
|
SendRTFToClip(hwndDlg, lpstrText);
|
|
#ifdef UNICODE
|
|
SetClipboardData(CF_UNICODETEXT, hmem);
|
|
#else
|
|
SetClipboardData(CF_TEXT, hmem);
|
|
#endif
|
|
CloseClipboard();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If we couldn't open the clipboard, then we need to free memory.
|
|
//
|
|
GlobalUnlock(hmem);
|
|
GlobalFree(hmem);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SendRTFToClip
|
|
//
|
|
// Puts the string in the clipboard using Rich Text Format. This assumes
|
|
// that the clipboard has already been opened.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID SendRTFToClip(
|
|
HWND hwndDlg,
|
|
LPTSTR lpstrText)
|
|
{
|
|
INT iCurrFont;
|
|
ITEMDATA ItemData;
|
|
TCHAR szFaceName[LF_FACESIZE];
|
|
HANDLE hmemRTF, hmemClip;
|
|
LPTSTR lpstrClipString;
|
|
TCHAR achHeaderTmpl[] = TEXT("{\\rtf1\\ansi\\ansicpg%d {\\fonttbl{\\f0\\");
|
|
TCHAR achHeader[sizeof(achHeaderTmpl) / sizeof(TCHAR) + 20];
|
|
TCHAR achMiddle[] = TEXT(";}}\\sectd\\pard\\plain\\f0 ");
|
|
INT cchUC;
|
|
#ifndef UNICODE_RTF
|
|
LPWSTR pszRTFW;
|
|
#endif
|
|
|
|
|
|
#define MAXLENGTHFONTFAMILY 8
|
|
#define ALITTLEEXTRA 10 // covers extra characters + length of font size
|
|
|
|
iCurrFont = (INT)SendDlgItemMessage(hwndDlg, ID_FONT, CB_GETCURSEL, 0, 0L);
|
|
|
|
//
|
|
// Get the item data - contains fonttype, charset, and pitchandfamily.
|
|
//
|
|
*(DWORD *)&ItemData = SendDlgItemMessage( hwndDlg,
|
|
ID_FONT,
|
|
CB_GETITEMDATA,
|
|
iCurrFont,
|
|
0L );
|
|
|
|
//
|
|
// Get the facename from the combo box.
|
|
//
|
|
SendDlgItemMessage( hwndDlg,
|
|
ID_FONT,
|
|
CB_GETLBTEXT,
|
|
iCurrFont,
|
|
(LPARAM)(LPTSTR)szFaceName );
|
|
|
|
wsprintf(achHeader, achHeaderTmpl, (INT)(SHORT)GetACP());
|
|
|
|
//
|
|
// 16 times in case they're all > 7 bits (each chr -> \uc1\uddddddd\'xx)
|
|
// and room for the second byte of DBCS.
|
|
//
|
|
hmemRTF = GlobalAlloc( 0,
|
|
CTOB(lstrlen((LPTSTR)achHeader) +
|
|
MAXLENGTHFONTFAMILY +
|
|
lstrlen(szFaceName) +
|
|
lstrlen((LPTSTR)achMiddle) +
|
|
2 * 16 * lstrlen(lpstrText) +
|
|
ALITTLEEXTRA) );
|
|
if (hmemRTF == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for local storage of clipboard string for owner draw.
|
|
//
|
|
if (hmemClip = GlobalAlloc(0, CTOB(lstrlen(lpstrText) + 1)))
|
|
{
|
|
//
|
|
// Get rid of old ones.
|
|
//
|
|
if (hstrClipboard)
|
|
{
|
|
GlobalFree(hstrClipboard);
|
|
}
|
|
if (fDelClipboardFont)
|
|
{
|
|
fDelClipboardFont = FALSE;
|
|
DeleteObject(hFontClipboard);
|
|
}
|
|
|
|
//
|
|
// Save this stuff away for owner drawing in a clipboard viewer.
|
|
//
|
|
hFontClipboard = sycm.hFont;
|
|
hstrClipboard = hmemClip;
|
|
lstrcpy(GlobalLock(hstrClipboard), lpstrText);
|
|
GlobalUnlock(hstrClipboard);
|
|
}
|
|
else
|
|
{
|
|
GlobalFree(hmemRTF);
|
|
return;
|
|
}
|
|
|
|
lpstrClipString = GlobalLock(hmemRTF);
|
|
#ifndef UNICODE_RTF
|
|
pszRTFW = lpstrClipString;
|
|
#endif
|
|
|
|
lstrcpy(lpstrClipString, achHeader);
|
|
|
|
if (ItemData.CharSet == SYMBOL_CHARSET)
|
|
{
|
|
lstrcat(lpstrClipString, (LPTSTR)TEXT("ftech "));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Top four bits specify family.
|
|
//
|
|
switch (ItemData.PitchAndFamily & 0xf0)
|
|
{
|
|
case ( FF_DECORATIVE ) :
|
|
{
|
|
lstrcat(lpstrClipString, (LPTSTR)TEXT("fdecor "));
|
|
break;
|
|
}
|
|
case ( FF_MODERN ) :
|
|
{
|
|
lstrcat(lpstrClipString, (LPTSTR)TEXT("fmodern "));
|
|
break;
|
|
}
|
|
case ( FF_ROMAN ) :
|
|
{
|
|
lstrcat(lpstrClipString, (LPTSTR)TEXT("froman "));
|
|
break;
|
|
}
|
|
case ( FF_SCRIPT ) :
|
|
{
|
|
lstrcat(lpstrClipString, (LPTSTR)TEXT("fscript "));
|
|
break;
|
|
}
|
|
case ( FF_SWISS ) :
|
|
{
|
|
lstrcat(lpstrClipString, (LPTSTR)TEXT("fswiss "));
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
lstrcat(lpstrClipString, szFaceName);
|
|
|
|
lstrcat(lpstrClipString, (LPTSTR)achMiddle);
|
|
|
|
//
|
|
// We need to do the text character by character, making sure
|
|
// that we output a special sequence \'hh for characters bigger
|
|
// than 7 bits long!
|
|
//
|
|
lpstrClipString = (LPTSTR)(lpstrClipString + lstrlen(lpstrClipString));
|
|
|
|
cchUC = 0;
|
|
|
|
while (*lpstrText)
|
|
{
|
|
if ((UTCHAR)*lpstrText < 128)
|
|
{
|
|
if (*lpstrText == TEXT('\\') ||
|
|
*lpstrText == TEXT('{') ||
|
|
*lpstrText == TEXT('}'))
|
|
{
|
|
//
|
|
// Need to preface these symbols with a '\' since they are
|
|
// special control characters for RTF.
|
|
//
|
|
*lpstrClipString++ = TEXT('\\');
|
|
}
|
|
|
|
*lpstrClipString++ = *lpstrText++;
|
|
}
|
|
else
|
|
{
|
|
unsigned char achTmp[2];
|
|
unsigned char *pTmp = achTmp;
|
|
int cch;
|
|
|
|
cch = WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
lpstrText,
|
|
1,
|
|
pTmp,
|
|
2,
|
|
NULL,
|
|
NULL );
|
|
|
|
//
|
|
// Put in a \uc# to tell Unicode reader how many bytes to skip
|
|
// and the \uN code to indicate the real unicode value.
|
|
//
|
|
if (cch != cchUC )
|
|
{
|
|
cchUC = cch;
|
|
lpstrClipString += wsprintf( lpstrClipString,
|
|
TEXT("\\uc%d"),
|
|
(INT)(SHORT)cchUC );
|
|
}
|
|
|
|
lpstrClipString += wsprintf( lpstrClipString,
|
|
TEXT("\\u%d"),
|
|
(INT)(SHORT)*lpstrText );
|
|
|
|
//
|
|
// Now put the \'xx string in to indicate the actual character.
|
|
//
|
|
lpstrText++;
|
|
while (cch--)
|
|
{
|
|
*lpstrClipString++ = TEXT('\\');
|
|
*lpstrClipString++ = TEXT('\'');
|
|
wsprintf(achMiddle, TEXT("%x"), (INT)*pTmp++);
|
|
*lpstrClipString++ = achMiddle[0];
|
|
*lpstrClipString++ = achMiddle[1];
|
|
}
|
|
}
|
|
}
|
|
*lpstrClipString++ = TEXT('}');
|
|
*lpstrClipString++ = TEXT('\0');
|
|
|
|
if (!wCFRichText)
|
|
{
|
|
TCHAR szRTF[80];
|
|
|
|
LoadString(hInst, IDS_RTF, szRTF, BTOC(sizeof(szRTF)) - 1);
|
|
wCFRichText = RegisterClipboardFormat(szRTF);
|
|
}
|
|
|
|
#ifndef UNICODE_RTF
|
|
{
|
|
//
|
|
// RTF is only defined for ANSI, not for Unicode, therefore
|
|
// we need to convert the buffer before we put it on the
|
|
// clipboard. Eventually, we should add autoconversion code
|
|
// to USER to handle this for us.
|
|
//
|
|
int cch;
|
|
HANDLE hmemRTFA;
|
|
LPSTR pszRTFA;
|
|
|
|
cch = WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
pszRTFW,
|
|
lpstrClipString - pszRTFW,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL );
|
|
|
|
if (cch != 0 &&
|
|
(hmemRTFA = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,cch)) != NULL)
|
|
{
|
|
pszRTFA = GlobalLock(hmemRTFA);
|
|
|
|
WideCharToMultiByte( CP_ACP,
|
|
0,
|
|
pszRTFW,
|
|
lpstrClipString - pszRTFW,
|
|
pszRTFA,
|
|
cch,
|
|
NULL,
|
|
NULL );
|
|
|
|
GlobalUnlock(hmemRTFA);
|
|
GlobalUnlock(hmemRTF);
|
|
GlobalFree(hmemRTF);
|
|
|
|
hmemRTF = hmemRTFA;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Put RTF and OwnerDisplay formats in the clipboard.
|
|
//
|
|
SetClipboardData(wCFRichText, hmemRTF);
|
|
SetClipboardData(CF_OWNERDISPLAY, NULL);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PointsToHeight
|
|
//
|
|
// Calculates the height in pixels of the specified point size for the
|
|
// current display.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
INT PointsToHeight(
|
|
INT iPoints)
|
|
{
|
|
HDC hdc;
|
|
INT iHeight;
|
|
|
|
hdc = GetDC(HWND_DESKTOP);
|
|
iHeight = MulDiv(iPoints, GetDeviceCaps(hdc, LOGPIXELSY), 72);
|
|
ReleaseDC(HWND_DESKTOP, hdc);
|
|
return (iHeight);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UpdateKeystrokeText
|
|
//
|
|
// Calculates and updates the text string displayed in the Keystroke
|
|
// field of the status bar. It repaints the status field if fRedraw is
|
|
// TRUE.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID UpdateKeystrokeText(
|
|
HDC hdc,
|
|
BOOL fANSI,
|
|
UTCHAR chNew,
|
|
BOOL fRedraw)
|
|
{
|
|
TCHAR szUnshifted[CCH_KEYNAME];
|
|
INT vkRes;
|
|
LONG lParam;
|
|
|
|
if (!fANSI)
|
|
{
|
|
lstrcpy(szKeystrokeText, szUnicodeLabel);
|
|
wsprintf( (LPTSTR)(szKeystrokeText + iUnicodeLabelStart),
|
|
TEXT("%04x"),
|
|
chNew );
|
|
}
|
|
else
|
|
{
|
|
lstrcpy(szKeystrokeText, szKeystrokeLabel);
|
|
vkRes = VkKeyScan(chNew);
|
|
//
|
|
// Map the virtual key code into an unshifted character value.
|
|
//
|
|
lParam = MapVirtualKey(LOBYTE(vkRes), 0) << 16;
|
|
GetKeyNameText(lParam, szUnshifted, CCH_KEYNAME - 1);
|
|
|
|
switch (HIBYTE(vkRes))
|
|
{
|
|
case ( 0 ) : // unshifted char
|
|
case ( 1 ) : // character is shifted, just display the shifted char
|
|
{
|
|
if (chNew != TEXT(' '))
|
|
{
|
|
szKeystrokeText[iKeystrokeTextStart] = chNew;
|
|
szKeystrokeText[iKeystrokeTextStart + 1] = TEXT('\0');
|
|
}
|
|
else
|
|
{
|
|
lstrcat(szKeystrokeText, szUnshifted);
|
|
}
|
|
break;
|
|
}
|
|
case ( 2 ) : // character is control character
|
|
{
|
|
lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szCtrl);
|
|
lstrcat(szKeystrokeText, (LPTSTR)szUnshifted);
|
|
break;
|
|
}
|
|
case ( 6 ) : // character is CONTROL+ALT
|
|
{
|
|
lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szCtrlAlt);
|
|
lstrcat(szKeystrokeText, (LPTSTR)szUnshifted);
|
|
break;
|
|
}
|
|
case ( 7 ) : // character is SHIFT+CONTROL+ALT
|
|
{
|
|
lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szShiftCtrlAlt);
|
|
lstrcat(szKeystrokeText, (LPTSTR)szUnshifted);
|
|
break;
|
|
}
|
|
default : // Character created via Alt + Numpad
|
|
{
|
|
lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szAlt);
|
|
wsprintf( (LPTSTR)(szKeystrokeText + lstrlen(szKeystrokeText)),
|
|
TEXT("%d"),
|
|
chNew );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fRedraw)
|
|
{
|
|
PaintStatusLine(hdc, FALSE, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UpdateHelpText
|
|
//
|
|
// Calculates if the Help string needs to be updated, and does so if
|
|
// necessary.
|
|
//
|
|
// If hwndCtrl is not NULL, then it specifies the window handle of the
|
|
// control gaining focus, and lpmsg is ignored.
|
|
//
|
|
// If hwndCtrl is NULL, then lpmsg must point to a valid message structure.
|
|
// If it is a tab character, then we calculate what the next control is
|
|
// that will receive the focus.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL UpdateHelpText(
|
|
LPMSG lpmsg,
|
|
HWND hwndCtrl)
|
|
{
|
|
HDC hdc;
|
|
BOOL fPaintStatus = FALSE;
|
|
BOOL fRet = TRUE;
|
|
|
|
DPRINT((szDbgBuf, TEXT("UpdHlpTxt: lpmsg:0x%08lX, hwnd:0x%08lX\n"), (DWORD)lpmsg, (DWORD)hwndCtrl));
|
|
|
|
if (hwndCtrl != NULL)
|
|
{
|
|
fPaintStatus = TRUE;
|
|
iControl = GetDlgCtrlID(hwndCtrl);
|
|
}
|
|
else if (lpmsg->message == WM_KEYDOWN)
|
|
{
|
|
if (lpmsg->wParam == VK_TAB)
|
|
{
|
|
fPaintStatus = TRUE;
|
|
hwndCtrl = GetNextDlgTabItem( hwndDialog,
|
|
GetDlgItem(hwndDialog, iControl),
|
|
(BOOL)(GetKeyState(VK_SHIFT) & 0x8000) );
|
|
iControl = GetDlgCtrlID(hwndCtrl);
|
|
if (iControl == ID_STRING)
|
|
{
|
|
//
|
|
// Do this ourselves, otherwise default action will select
|
|
// the whole edit control.
|
|
//
|
|
SetFocus(hwndCtrl);
|
|
fRet = FALSE;
|
|
}
|
|
if (iControl == ID_CHARGRID)
|
|
{
|
|
//
|
|
// Set the default button back to "Select". The default
|
|
// might have changed to the "Next" or "Previous" button.
|
|
//
|
|
SendMessage(hwndDialog, DM_SETDEFID, ID_SELECT, 0);
|
|
}
|
|
}
|
|
else if (lpmsg->wParam == VK_F1)
|
|
{
|
|
PostMessage(hwndDialog, WM_COMMAND, ID_HELP, 0L);
|
|
}
|
|
}
|
|
|
|
if (fPaintStatus)
|
|
{
|
|
hdc = GetDC(hwndDialog);
|
|
PaintStatusLine(hdc, TRUE, FALSE);
|
|
ReleaseDC(hwndDialog, hdc);
|
|
}
|
|
|
|
return (fRet);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SubSetChanged
|
|
//
|
|
// Sets the ANSI bit if appropriate and then calls UpdateSymbolSelection
|
|
// and then repaints the window.
|
|
//
|
|
// Repaints Keystroke field if HWND != NULL.
|
|
// Sets sycm->fAnsiFont if 'Windows Chars' is the subset.
|
|
// Redraws the char grid.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID SubSetChanged(
|
|
HWND hwnd,
|
|
INT iSubSet,
|
|
INT ichFirst,
|
|
INT ichLast)
|
|
{
|
|
HDC hdc;
|
|
BOOL fANSI = (iSubSet == 0);
|
|
|
|
if (fANSI != sycm.fAnsiFont)
|
|
{
|
|
sycm.fAnsiFont = fANSI;
|
|
}
|
|
|
|
UpdateSymbolSelection(hwnd, ichFirst, ichLast);
|
|
|
|
if ((hwnd != NULL) && ((hdc = GetDC(hwnd)) != NULL))
|
|
{
|
|
LPINT lpdxp;
|
|
HFONT hFont;
|
|
UINT ch;
|
|
|
|
hFont = SelectObject(hdc, sycm.hFont);
|
|
lpdxp = (LPINT)sycm.rgdxp;
|
|
|
|
if (iSubSet == 0)
|
|
{
|
|
GetCharWidth32A(hdc, chSymFirst, chSymLast, lpdxp);
|
|
}
|
|
else
|
|
{
|
|
GetCharWidth32(hdc, chSymFirst, chSymLast, lpdxp);
|
|
}
|
|
|
|
SelectObject(hdc, hFont);
|
|
|
|
for (ch = (UINT) chSymFirst; ch <= (UINT) chSymLast; ch++, lpdxp++)
|
|
{
|
|
*lpdxp = (sycm.dxpBox - *lpdxp) / 2 - 1;
|
|
}
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
|
|
InvalidateRect(hwndCharGrid, NULL, TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UpdateSymbolSelection
|
|
//
|
|
// Updates the values of the following global values:
|
|
// chRangeFirst
|
|
// chRangeLast
|
|
// Subsets in the Unicode character set have different numbers of
|
|
// characters. We have to do some bounds checking in order to set an
|
|
// appropriate sycm.chCurr value. The "Keystroke" status field is
|
|
// updated.
|
|
//
|
|
// Repaints Keystroke field if HWND != NULL.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID UpdateSymbolSelection(
|
|
HWND hwnd,
|
|
INT FirstChar,
|
|
INT LastChar)
|
|
{
|
|
int iCmd = SW_HIDE;
|
|
HWND hwndSB;
|
|
UINT chFirst, chLast;
|
|
|
|
chRangeFirst = FirstChar;
|
|
chRangeLast = LastChar;
|
|
|
|
chFirst = chRangeFirst;
|
|
|
|
chLast = chFirst + cchFullMap - 1;
|
|
chLast = min(chLast, chRangeLast);
|
|
|
|
hwndSB = GetDlgItem(hwnd, ID_MAPSCROLL);
|
|
|
|
if (chLast != chRangeLast)
|
|
{
|
|
int i;
|
|
|
|
iCmd = SW_SHOW;
|
|
SetScrollPos(hwndSB, SB_CTL, 0, FALSE);
|
|
i = (chRangeLast - chRangeFirst + 1) - cchFullMap;
|
|
|
|
if (i < 0)
|
|
{
|
|
i = 1;
|
|
}
|
|
else
|
|
{
|
|
i = i / cchSymRow;
|
|
}
|
|
|
|
SetScrollRange(hwndSB, SB_CTL, 0, i, FALSE);
|
|
InvalidateRect(hwndSB, NULL, FALSE);
|
|
}
|
|
|
|
ShowWindow(hwndSB, iCmd);
|
|
|
|
UpdateSymbolRange(hwnd, chFirst, chLast);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UpdateSymbolRange
|
|
//
|
|
// Updates the values of the following global values:
|
|
// chSymFirst
|
|
// chSymLast
|
|
// sycm.chCurr
|
|
// Subsets in the Unicode character set have different numbers of
|
|
// characters. We have to do some bounds checking in order to set an
|
|
// appropriate sycm.chCurr value. The "Keystroke" status field is
|
|
// updated.
|
|
//
|
|
// Repaints Keystroke field if HWND != NULL.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID UpdateSymbolRange(
|
|
HWND hwnd,
|
|
INT FirstChar,
|
|
INT LastChar)
|
|
{
|
|
UTCHAR chSymOffset;
|
|
|
|
chSymOffset = sycm.chCurr - chSymFirst;
|
|
|
|
chSymFirst = FirstChar;
|
|
chSymLast = LastChar;
|
|
|
|
sycm.chCurr = chSymOffset + chSymFirst;
|
|
if (sycm.chCurr > chSymLast)
|
|
{
|
|
sycm.chCurr = chSymFirst;
|
|
}
|
|
if (hwnd != NULL)
|
|
{
|
|
HDC hdc;
|
|
|
|
hdc = GetDC(hwnd);
|
|
UpdateKeystrokeText(hdc, sycm.fAnsiFont, sycm.chCurr, TRUE);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
else
|
|
{
|
|
UpdateKeystrokeText(NULL, sycm.fAnsiFont, sycm.chCurr, FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PaintStatusLine
|
|
//
|
|
// Paints the Help and Keystroke fields in the status bar.
|
|
//
|
|
// Repaints Help field if fHelp == TRUE.
|
|
// Repaints Keystroke field if fKeystroke == TRUE.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID PaintStatusLine(
|
|
HDC hdc,
|
|
BOOL fHelp,
|
|
BOOL fKeystroke)
|
|
{
|
|
HFONT hfontOld = NULL;
|
|
RECT rect;
|
|
INT dyBorder;
|
|
TCHAR szHelpText[100];
|
|
|
|
dyBorder = GetSystemMetrics(SM_CYBORDER);
|
|
|
|
if (hfontStatus)
|
|
{
|
|
hfontOld = SelectObject(hdc, hfontStatus);
|
|
}
|
|
|
|
//
|
|
// Set the text and background colors.
|
|
//
|
|
SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
|
|
SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
|
|
|
|
if (fHelp)
|
|
{
|
|
//
|
|
// Now the help text, with a gray background.
|
|
//
|
|
rect.top = rcStatusLine.top + 3 * dyBorder;
|
|
rect.bottom = rcStatusLine.bottom - 3 * dyBorder;
|
|
rect.left = 9 * dyBorder;
|
|
rect.right = rect.left + dxHelpField - 2 * dyBorder;
|
|
|
|
LoadString(hInst, iControl, szHelpText, BTOC(sizeof(szHelpText)) - 1);
|
|
|
|
ExtTextOut( hdc,
|
|
rect.left + dyBorder * 2,
|
|
rect.top,
|
|
ETO_OPAQUE | ETO_CLIPPED,
|
|
&rect,
|
|
szHelpText,
|
|
lstrlen(szHelpText),
|
|
NULL );
|
|
}
|
|
|
|
if (fKeystroke)
|
|
{
|
|
//
|
|
// Now the keystroke text, with a gray background.
|
|
//
|
|
rect.top = rcStatusLine.top + 3 * dyBorder;
|
|
rect.bottom = rcStatusLine.bottom - 3 * dyBorder;
|
|
rect.right = rcStatusLine.right - 9 * dyBorder;
|
|
rect.left = rect.right - dxKeystrokeField + 2 * dyBorder;
|
|
|
|
ExtTextOut( hdc,
|
|
rect.left + dyBorder * 2,
|
|
rect.top,
|
|
ETO_OPAQUE | ETO_CLIPPED,
|
|
&rect,
|
|
szKeystrokeText,
|
|
lstrlen(szKeystrokeText),
|
|
NULL );
|
|
}
|
|
|
|
if (hfontOld)
|
|
{
|
|
SelectObject(hdc, hfontOld);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DrawFamilyComboItem
|
|
//
|
|
// Paints the font facenames and TT bitmap in the font combo box.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL DrawFamilyComboItem(
|
|
LPDRAWITEMSTRUCT lpdis)
|
|
{
|
|
HDC hDC, hdcMem;
|
|
DWORD rgbBack, rgbText;
|
|
TCHAR szFace[LF_FACESIZE];
|
|
HBITMAP hOld;
|
|
INT dy;
|
|
SHORT sFontType;
|
|
|
|
hDC = lpdis->hDC;
|
|
|
|
if (lpdis->itemState & ODS_SELECTED)
|
|
{
|
|
rgbBack = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
|
|
rgbText = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
|
}
|
|
else
|
|
{
|
|
rgbBack = SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
|
|
rgbText = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
|
|
}
|
|
|
|
SendMessage( lpdis->hwndItem,
|
|
CB_GETLBTEXT,
|
|
lpdis->itemID,
|
|
(LONG)(LPTSTR)szFace );
|
|
ExtTextOut( hDC,
|
|
lpdis->rcItem.left + DX_BITMAP,
|
|
lpdis->rcItem.top,
|
|
ETO_OPAQUE | ETO_CLIPPED,
|
|
&lpdis->rcItem,
|
|
szFace,
|
|
lstrlen(szFace),
|
|
NULL );
|
|
|
|
hdcMem = CreateCompatibleDC(hDC);
|
|
if (hdcMem)
|
|
{
|
|
if (hbmFont)
|
|
{
|
|
hOld = SelectObject(hdcMem, hbmFont);
|
|
sFontType = ((ITEMDATA FAR *)&(lpdis->itemData))->FontType;
|
|
|
|
if (sFontType)
|
|
{
|
|
|
|
int xSrc;
|
|
dy = ((lpdis->rcItem.bottom - lpdis->rcItem.top) - DY_BITMAP) / 2;
|
|
|
|
if (sFontType & TRUETYPE_FONT)
|
|
xSrc = 0;
|
|
else if (sFontType & TT_OPENTYPE_FONT)
|
|
xSrc = 2;
|
|
else if(sFontType & PS_OPENTYPE_FONT)
|
|
xSrc = 3;
|
|
else if (sFontType & TYPE1_FONT)
|
|
xSrc = 4;
|
|
|
|
BitBlt( hDC,
|
|
lpdis->rcItem.left,
|
|
lpdis->rcItem.top + dy,
|
|
DX_BITMAP,
|
|
DY_BITMAP,
|
|
hdcMem,
|
|
xSrc * DX_BITMAP,
|
|
lpdis->itemState & ODS_SELECTED ? DY_BITMAP : 0,
|
|
SRCCOPY );
|
|
}
|
|
SelectObject(hdcMem, hOld);
|
|
}
|
|
DeleteDC(hdcMem);
|
|
}
|
|
|
|
SetTextColor(hDC, rgbText);
|
|
SetBkColor(hDC, rgbBack);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LoadBitmaps
|
|
//
|
|
// Loads DIB bitmaps and "fixes up" their color tables so that we get the
|
|
// desired result for the device we are on.
|
|
//
|
|
// This routine requires:
|
|
// - the DIB is a 16 color DIB authored with the standard windows colors
|
|
// - bright blue (00 00 FF) is converted to the background color
|
|
// - light grey (C0 C0 C0) is replaced with the button face color
|
|
// - dark grey (80 80 80) is replaced with the button shadow color
|
|
//
|
|
// This means you can't have any of these colors in your bitmap.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
HBITMAP LoadBitmaps(
|
|
INT id)
|
|
{
|
|
HDC hdc;
|
|
HANDLE h, hRes;
|
|
DWORD *p;
|
|
LPBYTE lpBits;
|
|
LPBITMAPINFOHEADER lpBitmapInfo;
|
|
INT numcolors;
|
|
DWORD rgbSelected, rgbUnselected;
|
|
HBITMAP hbm;
|
|
|
|
rgbSelected = GetSysColor(COLOR_HIGHLIGHT);
|
|
//
|
|
// Flip the colors.
|
|
//
|
|
rgbSelected = RGB( GetBValue(rgbSelected),
|
|
GetGValue(rgbSelected),
|
|
GetRValue(rgbSelected) );
|
|
rgbUnselected = GetSysColor(COLOR_WINDOW);
|
|
//
|
|
// Flip the colors.
|
|
//
|
|
rgbUnselected = RGB( GetBValue(rgbUnselected),
|
|
GetGValue(rgbUnselected),
|
|
GetRValue(rgbUnselected) );
|
|
|
|
h = FindResource(hInst, MAKEINTRESOURCE(id), RT_BITMAP);
|
|
hRes = LoadResource(hInst, h);
|
|
|
|
//
|
|
// Lock the bitmap and get a pointer to the color table.
|
|
//
|
|
lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes);
|
|
|
|
if (!lpBitmapInfo)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
p = (DWORD *)((LPSTR)(lpBitmapInfo) + lpBitmapInfo->biSize);
|
|
|
|
//
|
|
// Search for the Solid Blue entry and replace it with the current
|
|
// background RGB.
|
|
//
|
|
numcolors = 16;
|
|
|
|
while (numcolors-- > 0)
|
|
{
|
|
if (*p == BACKGROUND)
|
|
{
|
|
*p = rgbUnselected;
|
|
}
|
|
else if (*p == BACKGROUNDSEL)
|
|
{
|
|
*p = rgbSelected;
|
|
}
|
|
p++;
|
|
}
|
|
UnlockResource(hRes);
|
|
|
|
//
|
|
// Now create the DIB.
|
|
//
|
|
lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes);
|
|
|
|
//
|
|
// First skip over the header structure.
|
|
//
|
|
lpBits = (LPBYTE)(lpBitmapInfo + 1);
|
|
|
|
//
|
|
// Skip the color table entries, if any.
|
|
//
|
|
lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
|
|
|
|
//
|
|
// Create a color bitmap compatible with the display device.
|
|
//
|
|
hdc = GetDC(NULL);
|
|
hbm = CreateDIBitmap( hdc,
|
|
lpBitmapInfo,
|
|
(DWORD)CBM_INIT,
|
|
lpBits,
|
|
(LPBITMAPINFO)lpBitmapInfo,
|
|
DIB_RGB_COLORS );
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
GlobalUnlock(hRes);
|
|
FreeResource(hRes);
|
|
|
|
return (hbm);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DoHelp
|
|
//
|
|
// Invokes help if fInvokeHelp is true, or dismisses help if fInvokeHelp
|
|
// is FALSE.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID DoHelp(
|
|
HWND hWnd,
|
|
BOOL fInvokeHelp)
|
|
{
|
|
TCHAR szHelp[80];
|
|
|
|
if (LoadString(hInst, IDS_HELP, szHelp, BTOC(sizeof(szHelp)) - 1))
|
|
{
|
|
if (fInvokeHelp)
|
|
{
|
|
// APPCOMPAT: an error in HtmlHelp prevents the unicode version from working
|
|
// This is a HACK to get around the problem. Remove this hack when the problem is fixed.
|
|
HtmlHelpA(GetDesktopWindow(), "charmap.chm", HH_DISPLAY_TOPIC, 0L);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SaveFont
|
|
//
|
|
// Saves the current font facename in win.ini, so that it can be selected
|
|
// the next time charmap comes up.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID SaveCurrentFont(
|
|
HWND hWndDlg)
|
|
{
|
|
TCHAR szFaceName[LF_FACESIZE] = TEXT("");
|
|
|
|
SendDlgItemMessage( hWndDlg,
|
|
ID_FONT,
|
|
CB_GETLBTEXT,
|
|
(WORD)SendDlgItemMessage( hWndDlg,
|
|
ID_FONT,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0L ),
|
|
(LONG)(LPTSTR)szFaceName );
|
|
|
|
WriteProfileString(TEXT("MSCharMap"), TEXT("Font"), (LPTSTR)szFaceName);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SelectInitialFont
|
|
//
|
|
// Selects the initial font by getting a saved facename from win.ini and
|
|
// selecting it in the combo box.
|
|
//
|
|
// Returns index to font selected.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
INT SelectInitialFont(
|
|
HWND hWndDlg)
|
|
{
|
|
TCHAR szFaceName[LF_FACESIZE] = TEXT("");
|
|
INT iIndex;
|
|
|
|
if ((GetProfileString( TEXT("MSCharMap"),
|
|
TEXT("Font"),
|
|
NULL,
|
|
(LPTSTR)szFaceName,
|
|
BTOC(sizeof(szFaceName)) ) == 0) ||
|
|
((iIndex = (INT)SendDlgItemMessage( hWndDlg,
|
|
ID_FONT,
|
|
CB_SELECTSTRING,
|
|
(WPARAM)-1,
|
|
(LONG)(LPTSTR)szFaceName )) == CB_ERR))
|
|
{
|
|
//
|
|
// If there was no profile or the selection failed then try selecting
|
|
// the symbol font, if that fails then select the first one.
|
|
//
|
|
if ((iIndex = (INT)SendDlgItemMessage( hWndDlg,
|
|
ID_FONT,
|
|
CB_SELECTSTRING,
|
|
(WPARAM)-1,
|
|
(LONG)(LPTSTR)TEXT("Symbol") )) == CB_ERR)
|
|
{
|
|
SendDlgItemMessage(hWndDlg, ID_FONT, CB_SETCURSEL, iIndex = 0, 0L);
|
|
}
|
|
}
|
|
|
|
return (iIndex);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SaveCurrentSubset
|
|
//
|
|
// Saves the current subset name in win.ini, so that it can be selected
|
|
// the next time charmap comes up.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID SaveCurrentSubset(
|
|
HWND hWndDlg)
|
|
{
|
|
TCHAR szSubsetName[LF_SUBSETSIZE] = TEXT("");
|
|
|
|
SendDlgItemMessage( hWndDlg,
|
|
ID_UNICODESUBSET,
|
|
CB_GETLBTEXT,
|
|
(WORD)SendDlgItemMessage( hWndDlg,
|
|
ID_UNICODESUBSET,
|
|
CB_GETCURSEL,
|
|
0,
|
|
0L ),
|
|
(LONG)(LPTSTR)szSubsetName );
|
|
|
|
WriteProfileString(TEXT("MSCharMap"), TEXT("Block"), (LPTSTR)szSubsetName);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SelectInitialSubset
|
|
//
|
|
// Selects the initial Unicode subset by getting a saved block name from
|
|
// win.ini.
|
|
//
|
|
// Returns index to subset selected.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
INT SelectInitialSubset(
|
|
HWND hWndDlg)
|
|
{
|
|
TCHAR szSubsetName[LF_SUBSETSIZE] = TEXT("");
|
|
INT iIndex;
|
|
|
|
if ((GetProfileString( TEXT("MSCharMap"),
|
|
TEXT("Block"),
|
|
NULL,
|
|
(LPTSTR)szSubsetName,
|
|
BTOC(sizeof(szSubsetName)) ) == 0) ||
|
|
((iIndex = (INT)SendDlgItemMessage(
|
|
hWndDlg,
|
|
ID_UNICODESUBSET,
|
|
CB_SELECTSTRING,
|
|
(WPARAM)-1,
|
|
(LONG)(LPTSTR)szSubsetName )) == CB_ERR))
|
|
{
|
|
//
|
|
// If there was no profile or the selection failed then try selecting
|
|
// the Basic Latin block, if that fails then select the first one.
|
|
//
|
|
if ((iIndex = (INT)SendDlgItemMessage(
|
|
hWndDlg,
|
|
ID_UNICODESUBSET,
|
|
CB_SELECTSTRING,
|
|
(WPARAM)-1,
|
|
(LONG)(LPTSTR)TEXT("Basic Latin") )) == CB_ERR)
|
|
{
|
|
SendDlgItemMessage( hWndDlg,
|
|
ID_UNICODESUBSET,
|
|
CB_SETCURSEL,
|
|
iIndex = 0,
|
|
0L );
|
|
}
|
|
}
|
|
|
|
chSymFirst = aSubsetData[iIndex].BeginRange;
|
|
chSymLast = aSubsetData[iIndex].EndRange;
|
|
sycm.chCurr = chSymFirst;
|
|
|
|
return (iIndex);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ExitMagnify
|
|
//
|
|
// Releases mouse capture, exits magnify mode, and restores the cursor.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID ExitMagnify(
|
|
HWND hWnd,
|
|
PSYCM psycm)
|
|
{
|
|
//
|
|
// Release capture, remove magnified character, restore cursor.
|
|
//
|
|
ReleaseCapture();
|
|
RestoreSymMag(psycm);
|
|
DrawSymChOutlineHwnd(psycm, hWnd, psycm->chCurr, TRUE, TRUE);
|
|
if (psycm->fCursorOff)
|
|
{
|
|
ShowCursor(TRUE);
|
|
}
|
|
psycm->fMouseDn = psycm->fCursorOff = FALSE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetEditCtlFont
|
|
//
|
|
// Creates a font for the Edit control that visually matches the handle
|
|
// given, but is guaranteed not to be bigger than the size of the edit
|
|
// control.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetEditCtlFont(
|
|
HWND hwndDlg,
|
|
int idCtl,
|
|
HFONT hfont)
|
|
{
|
|
static HFONT hfNew = NULL;
|
|
LOGFONT lfNew;
|
|
HWND hwndCtl = GetDlgItem(hwndDlg, idCtl);
|
|
RECT rc;
|
|
|
|
if (hfNew != NULL)
|
|
{
|
|
DeleteObject(hfNew);
|
|
}
|
|
|
|
GetWindowRect(hwndCtl, &rc);
|
|
|
|
if (GetObject(hfont, sizeof(lfNew), &lfNew) != 0)
|
|
{
|
|
lfNew.lfHeight = rc.bottom - rc.top - 8;
|
|
lfNew.lfWidth = lfNew.lfEscapement = lfNew.lfOrientation =
|
|
lfNew.lfWeight = 0;
|
|
|
|
hfNew = CreateFontIndirect(&lfNew);
|
|
}
|
|
else
|
|
{
|
|
hfNew = hfont;
|
|
}
|
|
|
|
SendMessage(hwndCtl, WM_SETFONT, (WPARAM)hfNew, (LPARAM)TRUE);
|
|
|
|
if (hfNew == hfont)
|
|
{
|
|
hfNew = NULL;
|
|
}
|
|
}
|