/**************************************************************************** PROGRAM: CharMap PURPOSE: Utility providing users an easy interface for selecting special characters. COMMENTS: Created by MikeSch (7-16-91) Partially derived from WinWord 2.0 Insert.Symbol dialog. ****************************************************************************/ #define WIN31 #include "windows.h" #include #include "charmap.h" #include "stdlib.h" #include "tchar.h" #ifdef UNICODE #include "wchar.h" #else #include "stdio.h" #endif #include "commctrl.h" /* * Macros */ #define FMagData(psycm) ((psycm)->xpMagCurr != 0) #define abs(x) (((x) >= 0) ? (x) : (-(x))) /* * Useful constants. */ #define STATUSPOINTSIZE 8 // 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 // Font types #define PS_OPENTYPE_FONT 0x0001 #define TT_OPENTYPE_FONT 0x0002 #define TRUETYPE_FONT 0x0004 #define TYPE1_FONT 0x0008 /* * Globals. */ 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; SYCM sycm; // Tons of data need to do char grid painting. UINT 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 // // 04 Dec 92 - GregoryW // 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_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}, // not supported { 0x0530, 0x058f, IDS_ARMENIAN}, { 0x0590, 0x05ff, IDS_HEBREW}, // not supported { 0x0600, 0x0652, IDS_BASICARABIC}, // not supported { 0x0653, 0x06ff, IDS_ARABICEX}, // not supported { 0x0900, 0x097f, IDS_DEVANAGARI}, // not supported { 0x0980, 0x09ff, IDS_BENGALI}, // not supported { 0x0a00, 0x0a7f, IDS_GURMUKHI}, // not supported { 0x0a80, 0x0aff, IDS_GUJARATI}, // not supported { 0x0b00, 0x0b7f, IDS_ORIYA}, // not supported { 0x0b80, 0x0bff, IDS_TAMIL}, // not supported { 0x0c00, 0x0c7f, IDS_TELUGU}, // not supported { 0x0c80, 0x0cff, IDS_KANNADA}, // not supported { 0x0d00, 0x0d7f, IDS_MALAYALAM}, // not supported { 0x0e00, 0x0e7f, IDS_THAI}, // not supported { 0x0e80, 0x0eff, IDS_LAO}, // not supported { 0x10d0, 0x10ff, IDS_BASICGEORGIAN}, // not supported { 0x10a0, 0x10cf, IDS_GEORGIANEX}, // not supported { 0x1100, 0x11ff, IDS_HANGULJAMO}, // not supported { 0x1e00, 0x1eff, IDS_LATINEXADDITIONAL}, // not supported { 0x1f00, 0x1fff, IDS_GREEKEX}, // not supported { 0x2000, 0x206f, IDS_GENERALPUNCTUATION}, // not supported { 0x2070, 0x209f, IDS_SUPERANDSUBSCRIPTS}, { 0x20a0, 0x20cf, IDS_CURRENCYSYMBOLS}, // not supported { 0x20d0, 0x20ff, IDS_COMBININGDIACRITICSFORSYMBOLS}, { 0x2100, 0x214f, IDS_LETTERLIKESYMBOLS}, // not supported { 0x2150, 0x218f, IDS_NUMBERFORMS}, { 0x2190, 0x21ff, IDS_ARROWS}, { 0x2200, 0x22ff, IDS_MATHEMATICALOPS}, // not supported { 0x2300, 0x23ff, IDS_MISCTECHNICAL}, // not supported { 0x2400, 0x243f, IDS_CONTROLPICTURES}, // not supported { 0x2440, 0x245f, IDS_OPTICALCHAR}, // not supported { 0x2460, 0x24ff, IDS_ENCLOSEDALPHANUM}, // not supported { 0x2500, 0x257f, IDS_BOXDRAWING}, // not supported { 0x2580, 0x259f, IDS_BLOCKELEMENTS}, // not supported { 0x25a0, 0x25ff, IDS_GEOMETRICSHAPES}, // not supported { 0x2600, 0x26ff, IDS_MISCDINGBATS}, // not supported { 0x2700, 0x27bf, IDS_DINGBATS}, // not supported { 0x3000, 0x303f, IDS_CJKSYMBOLSANDPUNC}, // not supported { 0x3040, 0x309f, IDS_HIRAGANA}, // not supported { 0x30a0, 0x30ff, IDS_KATAKANA}, // not supported { 0x3100, 0x312f, IDS_BOPOMOFO}, // not supported { 0x3130, 0x318f, IDS_HANGULCOMPATIBILITYJAMO}, // not supported { 0x3190, 0x319f, IDS_CJKMISC}, // not supported { 0x3200, 0x32ff, IDS_ENCLOSEDCJKLETTERSANDMONTHS}, // not supported { 0x3300, 0x33ff, IDS_CJKCOMPATIBILITY}, // not supported { 0x3400, 0x3d2d, IDS_HANGUL}, // not supported { 0x3d2e, 0x44b7, IDS_HANGULSUPPA}, // not supported { 0x44b8, 0x4dff, IDS_HANGULSUPPB}, // not supported { 0x4e00, 0x9fff, IDS_CJKUNIFIEDIDEOGRAPHS}, // not supported { 0xe000, 0xf8ff, IDS_PRIVATEUSEAREA}, // not supported { 0xf900, 0xfaff, IDS_CJKCOMPATIBILITYIDEOGRAPHS}, // not supported { 0xfb00, 0xfb4f, IDS_ALPAHPRESENTATIONFORMS}, // not supported { 0xfb50, 0xfdff, IDS_ARABICPRESENTATIONFORMSA}, // not supported { 0xfe30, 0xfe4f, IDS_CJKCOMPFORMS}, // not supported { 0xfe50, 0xfe6f, IDS_SMALLFORMVARIANTS}, // not supported { 0xfe70, 0xfefe, IDS_ARABICPRESENTATIONFORMSB}, // not supported { 0xff00, 0xffef, IDS_HALFANDFULLWIDTHFORMS}, // not supported { 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[30]; // 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. /**************************************************************************** FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int) PURPOSE: calls initialization function, processes message loop, cleanup. COMMENTS: ****************************************************************************/ INT PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; if (!InitApplication(hInstance)) return (FALSE); InitCommonControls(); // 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 (int)(msg.wParam); } /**************************************************************************** FUNCTION: InitApplication(HANDLE) PURPOSE: Initializes window data and registers window class COMMENTS: ****************************************************************************/ 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); return TRUE; } /**************************************************************************** FUNCTION: InitInstance(HANDLE, int) PURPOSE: Does some initialization and creates main window which is a dialog. COMMENTS: ****************************************************************************/ BOOL InitInstance(HANDLE hInstance, INT nCmdShow) { INT i; // Save the instance handle in a global variable. hInst = hInstance; // This font will be used to paint the status line. hfontStatus = CreateFont(-PointsToHeight(STATUSPOINTSIZE), 0, 0, 0, 400, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, TEXT("Helv")); dyStatus = 2 * PointsToHeight(STATUSPOINTSIZE); dyToolbar[0] = 28; /* defined by UI gods */ dyToolbar[1] = 28; /* defined by UI gods */ // 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, 50) ) 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.chCurr, FALSE); ShowWindow(hwndDialog, nCmdShow); UpdateWindow(hwndDialog); return (TRUE); } /**************************************************************************** FUNCTION: CharMapDlgProc(HWND, UINT, WPARAM, LPARAM) PURPOSE: Processes messages for the main window. COMMENTS: 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; INT iSubset; /* * 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; } hStaticBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); // Initialize the status line data. dxHelpField = 22 * rectParent.right / 32; dxKeystrokeField = 8 * 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, (LPARAM)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)); SendDlgItemMessage(hWnd, ID_STRING, WM_SETFONT, (WPARAM)sycm.hFont, (DWORD)TRUE); 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; /* * 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. */ // BUG - The parameters with this message are unreliable! if (wParam == WM_LBUTTONDOWN) { dwMsgPos = GetMessagePos(); points = MAKEPOINTS(dwMsgPos); point.x = points.x; point.y = points.y; UpdateHelpText(NULL, WindowFromPoint(point)); } } 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))) { 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, (UINT)wParam); return (TRUE); case WM_PAINTCLIPBOARD: { LPPAINTSTRUCT lpPS; HANDLE hFont; LPTSTR lpstrText; if (hstrClipboard) { // Setup. lpPS = (LPPAINTSTRUCT)GlobalLock((HANDLE)lParam); lpstrText = (LPTSTR)GlobalLock(hstrClipboard); // Lets 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: SendDlgItemMessage(hWnd, ID_STRING, WM_CHAR, (WPARAM)sycm.chCurr, 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); SendDlgItemMessage(hWnd, ID_STRING, WM_SETFONT, (WPARAM)sycm.hFont, (DWORD)TRUE); } 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; iSubset = (INT)SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_GETCURSEL, 0, 0); UpdateSymbolSelection( hWnd, aSubsetData[iSubset].BeginRange, aSubsetData[iSubset].EndRange ); InvalidateRect(hwndCharGrid, NULL, TRUE); } else if (HIWORD(wParam) == CBN_SETFOCUS) { // Necessary if hotkey is used to get to the CB. UpdateHelpText(NULL, (HWND)lParam); } return 0; break; case ID_NEXTSUBSET: { INT iCurSelection, iNumEntries; iCurSelection = (INT)SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_GETCURSEL, 0, 0); if (iCurSelection == CB_ERR) { return 0; } iNumEntries = (INT)SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_GETCOUNT, 0, 0); if (iNumEntries == CB_ERR) { return 0; } if (iCurSelection++ < (iNumEntries - 1)) { if (iCurSelection == 1) { // Enable Previous button EnableWindow(GetDlgItem(hWnd, ID_PREVSUBSET), TRUE); } SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_SETCURSEL, iCurSelection, 0); UpdateSymbolSelection( hWnd, aSubsetData[iCurSelection].BeginRange, aSubsetData[iCurSelection].EndRange ); InvalidateRect(hwndCharGrid, NULL, TRUE); 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 0; break; case ID_PREVSUBSET: { INT iCurSelection; iCurSelection = (INT)SendDlgItemMessage( hWnd, ID_UNICODESUBSET, CB_GETCURSEL, 0, 0); if (iCurSelection == CB_ERR) { return 0; } 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); UpdateSymbolSelection( hWnd, aSubsetData[iCurSelection].BeginRange, aSubsetData[iCurSelection].EndRange ); InvalidateRect(hwndCharGrid, NULL, TRUE); 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 0; 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 = (LONG)SendDlgItemMessage(hWnd, ID_STRING, EM_GETSEL, 0, 0L); SendDlgItemMessage(hWnd, ID_STRING, EM_SETSEL, 0, 0L); } break; } return (FALSE); } /**************************************************************************** FUNCTION: CharGridWndProc(HWND, UINT, WPARAM, LPARAM) PURPOSE: Processes messages for the character grid window. COMMENTS: ****************************************************************************/ 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 + 1); sycm.dypBox = (rect.bottom-2) / (cchSymCol + 1); sycm.dxpCM = sycm.dxpBox * cchSymRow+1; sycm.dypCM = sycm.dypBox * cchSymCol+1; // space inside for border 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); sycm.xpCM = (point1.x - point2.x) - (sycm.dxpMag - sycm.dxpBox) / 2; 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; // Don't draw anything if there's an update region pending. if (GetUpdateRect(hWnd, (LPRECT)&rect, FALSE) != 0) break; SetFocus(hWnd); SetCapture(hWnd); sycm.fMouseDn = TRUE; if (!FMagData(&sycm)) DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE); } // Fall through to WM_MOUSEMOVE case WM_MOUSEMOVE: if (sycm.fMouseDn) { POINT pt; UTCHAR chMouseSymbol; 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 = (UTCHAR)ChFromSymLParam(&sycm, lParam); if (chMouseSymbol > 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. // if (!sycm.fCursorOff) { sycm.fCursorOff = TRUE; ShowCursor(FALSE); } MoveSymbolSel(&sycm, chMouseSymbol); } } else { // Left grid, leave magnified character and restore cursor. if (sycm.fCursorOff) { sycm.fCursorOff = FALSE; ShowCursor(TRUE); } } } break; case WM_CANCELMODE: case WM_LBUTTONUP: if (sycm.fMouseDn) ExitMagnify(hWnd, &sycm); break; case WM_LBUTTONDBLCLK: // Send this character to the entry field. SendDlgItemMessage(hwndDialog, ID_STRING, WM_CHAR, (WPARAM)sycm.chCurr, 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; if (sycm.fMouseDn) break; switch (wParam) { case VK_LEFT: if (--chNew < chSymFirst) return 0L; break; case VK_UP: if ((chNew -= (UTCHAR)cchSymRow) < chSymFirst) return 0L; break; case VK_RIGHT: if (++chNew > chSymLast) return 0L; break; case VK_DOWN: if ((chNew += (UTCHAR)cchSymRow) > chSymLast) return 0L; break; default: return 0L; } /* switch (wParam) */ if (!FMagData(&sycm)) DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE); MoveSymbolSel(&sycm, (UTCHAR)chNew); } break; case WM_CHAR: if (sycm.fMouseDn) break; if (wParam >= chSymFirst && wParam <= chSymLast) { if (!FMagData(&sycm)) DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE); MoveSymbolSel(&sycm, (UTCHAR) wParam); SendDlgItemMessage(hwndDialog, ID_STRING, WM_CHAR, (WPARAM)sycm.chCurr, 0L); } break; case WM_PAINT: { HDC hdc; PAINTSTRUCT ps; hdc = BeginPaint(hWnd, &ps); DrawSymbolMap(&sycm, hdc); EndPaint(hWnd, &ps); return (TRUE); } default: /* Passes it on if unproccessed */ return (DefWindowProc(hWnd, message, wParam, lParam)); } return 0L; } /**************************************************************************** FUNCTION: ChFromSymLParam(PSYCM, LPARAM) PURPOSE: Determine the character to select from the mouse position (lParam) COMMENTS: ****************************************************************************/ 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; } /**************************************************************************** FUNCTION: DrawSymChOutlineHwnd(PSYCM, HWND, UTCHAR, BOOL, BOOL); PURPOSE: Gets a DC for hwnd, calls DrawSymChOutline. COMMENTS: ****************************************************************************/ 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); } /**************************************************************************** FUNCTION: RecalcCharMap(HWND, PSYCM, int, BOOL); PURPOSE: Recalculate fixed character map data (font info, sizes, etc.) COMMENTS: ****************************************************************************/ VOID RecalcCharMap( HWND hwndDlg, PSYCM psycm, INT iCombo, BOOL fRedraw) { HDC hdc; TEXTMETRIC tm; UINT ch; LPINT lpdxp; HFONT hFont; LOGFONT LogFont; // 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. LogFont.lfHeight = psycm->dypBox - 3; // Allow for whitespace. // Set these guys to zero. LogFont.lfWidth = LogFont.lfEscapement = LogFont.lfOrientation = LogFont.lfWeight = 0; // Set these at zero too. 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 = ANSI_CHARSET; // Get the facename from the combo box. SendDlgItemMessage(hwndDlg, ID_FONT, CB_GETLBTEXT, iCombo, (LPARAM)(LPTSTR)LogFont.lfFaceName); /* * 27 Oct 92 GregoryW * For now we don't have a way to determine if this is a * Unicode font or an ANSI font. The best we can do is * look at the face name to see if it is the one Unicode * font we recognize. */ if (!lstrcmpi(LogFont.lfFaceName, TEXT("Lucida Sans Unicode"))) { LONG iCurSel; psycm->fAnsiFont = FALSE; // Enable Block listbox and set defaults appropriately. EnableWindow(GetDlgItem(hwndDlg, ID_UNICODESUBSET), TRUE); iCurSel = (LONG)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); } } else { // put back the ANSI defaults and disable Unicode Block listbox psycm->fAnsiFont = TRUE; UpdateSymbolSelection(hwndDlg, 32, 255); EnableWindow(GetDlgItem(hwndDlg, ID_UNICODESUBSET), FALSE); EnableWindow(GetDlgItem(hwndDlg, ID_NEXTSUBSET), FALSE); EnableWindow(GetDlgItem(hwndDlg, ID_PREVSUBSET), FALSE); } // 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; GetCharWidth(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); } /**************************************************************************** FUNCTION: DrawSymbolMap(PSYCM, HDC); PURPOSE: Draw all of the pieces of the symbol character map COMMENTS: ****************************************************************************/ 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); } void MoveTo(HDC hdc, int x, int y){ MoveToEx(hdc, x, y, NULL); } /**************************************************************************** FUNCTION: DrawSymbolGrid(PSYCM, HDC); PURPOSE: Draw the symbol character map grid. COMMENTS: ****************************************************************************/ 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--) { MoveTo(hdc, 1, yp); LineTo(hdc, xp, yp); yp += dypBox; } // Draw vertical lines. yp = psycm->dypCM; xp = 1; cli = cchSymRow+1; while (cli--) { MoveTo(hdc, xp, 1); LineTo(hdc, xp, yp); xp += dxpBox; } DeleteObject(SelectObject(hdc, hpenOld)); } /**************************************************************************** FUNCTION: DrawSymbolChars(PSYCM, HDC); PURPOSE: Draw the symbol character map. COMMENTS: ****************************************************************************/ 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); } /**************************************************************************** FUNCTION: DrawSymChOutline(PSYCM, HDC, UTCHAR, BOOL, BOOL); PURPOSE: Draw an outline around the symbol in the character map COMMENTS: If fVisible, draw outline else erase 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); } /**************************************************************************** FUNCTION: MoveSymbolSel(PSYCM, UTCHAR); PURPOSE: Change the current symbol selection. Handles drawing of magnified characters. COMMENTS: ****************************************************************************/ 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; if (((chNew == (UTCHAR)psycm->chCurr) && FMagData(psycm))) 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)) return; hdc = GetDC(hwndDialog); // Setup the magnified font character. hFontMag = SelectObject(hdcMag, psycm->hFontMag); { SIZE sz; GetTextExtentPoint(hdcMag, &chNew, 1, &sz); 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); if ((dxpT > 0) && (dypT > 0)) { INT xpTmax, ypTmax; // max(0, xpT); INT xpTmin, ypTmin; // min(0, xpT); INT xpTnmin, ypTnmin; // min(0, -xpT); 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. MoveTo(hdc, rc.left, rc.top); 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. MoveTo(hdc, rc.right, rc.top + 1); LineTo(hdc, rc.right, rc.bottom); LineTo(hdc, rc.left, rc.bottom); MoveTo(hdc, rc.right + 1, rc.top + 2); 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, chNew, TRUE); ReleaseDC(hwndDialog, hdc); psycm->chCurr = chNew; } /**************************************************************************** FUNCTION: RestoreSymMag(PSYCM); PURPOSE: Restore the screen data under the magnifier. COMMENTS: ****************************************************************************/ 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) } } /**************************************************************************** FUNCTION: FontLoadProc(LPLOGFONT, NEWTEXTMETRICEX*, short, LPTSTR); PURPOSE: Used by EnumFonts to load our combo box with all the fonts installed in the system. COMMENTS: ****************************************************************************/ 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, (LPARAM)&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, (LPARAM)&lpLogFont->lfFaceName); } else { // make sure it is not just a substring (want a full match) SendDlgItemMessage((HWND)lpData, ID_FONT, CB_GETLBTEXT, iPos, (LPARAM)(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); } /**************************************************************************** FUNCTION: GetEditText(HWND); PURPOSE: Returns HANDLE containing the text in the edit control. COMMENTS: Caller is responsible for freeing this handle! ****************************************************************************/ HANDLE GetEditText( HWND hwndDlg) { INT cchText; HWND hwndEditCtl; HANDLE hmem; LPTSTR lpstrText; LRESULT 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); } /**************************************************************************** FUNCTION: CopyString(HWND); PURPOSE: Implement the Copy function. COMMENTS: ****************************************************************************/ 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); } } } /**************************************************************************** FUNCTION: SendRTFToClip(HWND, LPTSTR); PURPOSE: Put the string in the clipboard using Rich Text Format. COMMENTS: 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 achHeader[] = TEXT("{\\rtf1\\ansi {\\fonttbl{\\f0\\"); TCHAR achMiddle[] = TEXT(";}}\\sectd\\pard\\plain\\f0 "); #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 = (DWORD)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); hmemRTF = GlobalAlloc(0, CTOB(lstrlen((LPTSTR)achHeader) + MAXLENGTHFONTFAMILY + lstrlen(szFaceName) + lstrlen((LPTSTR)achMiddle) + 4 * lstrlen(lpstrText) + // 4 times in case they're all > 7 bits 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 guys. 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); 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)); 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 { *lpstrClipString++ = TEXT('\\'); *lpstrClipString++ = TEXT('\''); #ifdef BUG // //PERF - GregoryW 23/10/92 need a Unicode version of itoa... // _itoa(*(UTCHAR FAR *)lpstrText++, achMiddle, 16); #else wsprintf(achMiddle, TEXT("%x"), (INT)*lpstrText); lpstrText++; #endif *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); } // Put RTF and OwnerDisplay formats in the clipboard. SetClipboardData(wCFRichText, hmemRTF); SetClipboardData(CF_OWNERDISPLAY, NULL); } /**************************************************************************** FUNCTION: PointsToHeight(int); PURPOSE: Calculates the height in pixels of the specified point size for the current display. COMMENTS: ****************************************************************************/ 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); } /**************************************************************************** FUNCTION: UpdateKeystrokeText(HDC, UTCHAR, BOOL); PURPOSE: Calculates and updates the text string displayed in the Keystroke field of the status bar. COMMENTS: Repaints status field if fRedraw == TRUE. ****************************************************************************/ VOID UpdateKeystrokeText( HDC hdc, UTCHAR chNew, BOOL fRedraw) { TCHAR szUnshifted[2]; SHORT vkRes; #ifdef UNICODE if (chNew > 255) { lstrcpy(szKeystrokeText, szUnicodeLabel); wsprintf((LPTSTR)(szKeystrokeText + iUnicodeLabelStart), TEXT("U+%04x"), chNew); } else { #endif lstrcpy(szKeystrokeText, szKeystrokeLabel); if (chNew == TEXT(' ')) { lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szSpace); } else { vkRes = VkKeyScan(chNew); /* * Map the virtual key code into an unshifted character value */ szUnshifted[0] = (TCHAR)MapVirtualKey(LOBYTE(vkRes), 2); szUnshifted[1] = TEXT('\0'); switch(HIBYTE(vkRes)) { case 0: // Unshifted char. case 1: // Character is shifted, just display the shifted char. szKeystrokeText[iKeystrokeTextStart] = chNew; szKeystrokeText[iKeystrokeTextStart + 1] = TEXT('\0'); 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; } } #ifdef UNICODE } #endif if (fRedraw) PaintStatusLine(hdc, FALSE, TRUE); } /**************************************************************************** FUNCTION: UpdateHelpText(LPMSG, HWND); PURPOSE: Calculates if the Help string needs to be updated, and does so if necessary. COMMENTS: 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; 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); } /**************************************************************************** FUNCTION: UpdateSymbolSelection(HWND, INT, INT); PURPOSE: 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. COMMENTS: Repaints Keystroke field if HWND != NULL. ****************************************************************************/ VOID UpdateSymbolSelection( HWND hwnd, INT FirstChar, INT LastChar) { UTCHAR chSymOffset; chSymOffset = sycm.chCurr - chSymFirst; chSymFirst = (UTCHAR)FirstChar; chSymLast = (UTCHAR)LastChar; sycm.chCurr = chSymOffset + chSymFirst; if (sycm.chCurr > chSymLast) { sycm.chCurr = chSymFirst; } if (hwnd != NULL) { HDC hdc; hdc = GetDC(hwnd); UpdateKeystrokeText(hdc, sycm.chCurr, TRUE); ReleaseDC(hwnd, hdc); } else { UpdateKeystrokeText(NULL, sycm.chCurr, FALSE); } } /**************************************************************************** FUNCTION: PaintStatusLine(HDC, BOOL, BOOL); PURPOSE: Paints the Help and Keystroke fields in the status bar. COMMENTS: Repaints Help field if fHelp == TRUE, repaints the 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); } /**************************************************************************** FUNCTION: DrawFamilyComboItem(LPDRAWITEMSTRUCT) PURPOSE: Paints the font facenames and TT bitmap in the font combo box. COMMENTS: ****************************************************************************/ 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, (LPARAM)(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; } /**************************************************************************** FUNCTION: LoadBitmaps(int) PURPOSE: This routine loads DIB bitmaps, and "fixes up" their color tables so that we get the desired result for the device we are on. COMMENTS: 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; DWORD FAR *p; LPBYTE lpBits; HANDLE hRes; LPBITMAPINFOHEADER lpBitmapInfo; INT numcolors; DWORD rgbSelected; DWORD 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 FAR *)((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; } /**************************************************************************** FUNCTION: DoHelp(HWND, BOOL) PURPOSE: This routine invokes help if BOOL is true, or dismisses help if BOOL is false. COMMENTS: ****************************************************************************/ VOID DoHelp(HWND hWnd, BOOL fInvokeHelp) { TCHAR szHelp[80]; if (LoadString(hInst, IDS_HELP, szHelp, BTOC(sizeof(szHelp)) - 1)) { if (fInvokeHelp) WinHelp(hWnd, (LPTSTR)szHelp, HELP_INDEX, 0L); else WinHelp(hWnd, (LPTSTR)szHelp, HELP_QUIT, 0L); } } /**************************************************************************** FUNCTION: SaveFont(HWND) PURPOSE: Used to save the current font facename in win.ini, so that it can be selected the next time charmap comes up. COMMENTS: ****************************************************************************/ VOID SaveCurrentFont(HWND hWndDlg) { TCHAR szFaceName[LF_FACESIZE] = TEXT(""); SendDlgItemMessage(hWndDlg, ID_FONT, CB_GETLBTEXT, (WORD)SendDlgItemMessage(hWndDlg, ID_FONT, CB_GETCURSEL, 0, 0L), (LPARAM)(LPTSTR)szFaceName); WriteProfileString(TEXT("MSCharMap"), TEXT("Font"), (LPTSTR)szFaceName); } /**************************************************************************** FUNCTION: SelectInitialFont(HWND) PURPOSE: Used to select the initial font by getting a saved facename from win.ini and selecting it in the combo box. COMMENTS: 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, (LPARAM)(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, (LPARAM)(LPTSTR)TEXT("Symbol"))) == CB_ERR) SendDlgItemMessage(hWndDlg, ID_FONT, CB_SETCURSEL, iIndex = 0, 0L); } return(iIndex); } /**************************************************************************** FUNCTION: SaveCurrentSubset(HWND) PURPOSE: Used to save the current subset name in win.ini, so that it can be selected the next time charmap comes up. COMMENTS: ****************************************************************************/ VOID SaveCurrentSubset(HWND hWndDlg) { TCHAR szSubsetName[LF_SUBSETSIZE] = TEXT(""); SendDlgItemMessage(hWndDlg, ID_UNICODESUBSET, CB_GETLBTEXT, (WORD)SendDlgItemMessage(hWndDlg, ID_UNICODESUBSET, CB_GETCURSEL, 0, 0L), (LPARAM)(LPTSTR)szSubsetName); WriteProfileString(TEXT("MSCharMap"), TEXT("Block"), (LPTSTR)szSubsetName); } /**************************************************************************** FUNCTION: SelectInitialSubset(HWND) PURPOSE: Used to select the initial Unicode subset by getting a saved block name from win.ini. COMMENTS: 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, (LPARAM)(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, (LPARAM)(LPTSTR)TEXT("Basic Latin") )) == CB_ERR) SendDlgItemMessage(hWndDlg, ID_UNICODESUBSET, CB_SETCURSEL, iIndex = 0, 0L); } chSymFirst = (UTCHAR)aSubsetData[iIndex].BeginRange; chSymLast = (UTCHAR)aSubsetData[iIndex].EndRange; sycm.chCurr = chSymFirst; return iIndex; } /**************************************************************************** FUNCTION: ExitMagnify(HWND, SYCM) PURPOSE: Used to release mouse capture, exit magnify mode, and restore the cursor. COMMENTS: ****************************************************************************/ 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; }