Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4060 lines
115 KiB

/*++
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)&rect;
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;
}
}