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

  1. /*++
  2. Copyright (c) 1991-1997, Microsoft Corporation All rights reserved.
  3. Module Name:
  4. charmap.c
  5. Abstract:
  6. This module contains the main routines for the Charmap utility, an
  7. interface for selecting special characters.
  8. Revision History:
  9. --*/
  10. //
  11. // Include Files.
  12. //
  13. #define WIN31
  14. #include "windows.h"
  15. #include <port1632.h>
  16. #include "charmap.h"
  17. #include "stdlib.h"
  18. #include "tchar.h"
  19. #ifdef UNICODE
  20. #include "wchar.h"
  21. #else
  22. #include "stdio.h"
  23. #endif
  24. #include "commctrl.h"
  25. #include <htmlhelp.h>
  26. //
  27. // Macros.
  28. //
  29. #define FMagData(psycm) ((psycm)->xpMagCurr != 0)
  30. #define abs(x) (((x) >= 0) ? (x) : (-(x)))
  31. //
  32. // Constant Declarations.
  33. //
  34. #define STATUSPOINTSIZE 8 // point size of status bar font
  35. #define FE_STATUSPOINTSIZE 10 // FE point size of status bar font
  36. #define DX_BITMAP 20 // width of TT bitmap
  37. #define DY_BITMAP 12 // height of TT bitmap
  38. #define BACKGROUND 0x000000FF // bright blue
  39. #define BACKGROUNDSEL 0x00FF00FF // bright purple
  40. #define BUTTONFACE 0x00C0C0C0 // bright grey
  41. #define BUTTONSHADOW 0x00808080 // dark grey
  42. #define TOOLBARPOINTSIZE 21 // height of toolbar in points
  43. // Font types
  44. #define PS_OPENTYPE_FONT 0x0001
  45. #define TT_OPENTYPE_FONT 0x0002
  46. #define TRUETYPE_FONT 0x0004
  47. #define TYPE1_FONT 0x0008
  48. //
  49. // Debug Print Code.
  50. //
  51. #if 0
  52. TCHAR szDOUT[3] = TEXT("A\n");
  53. TCHAR szDbgBuf[256];
  54. #define DOUTL(p) OutputDebugString(TEXT(p))
  55. #define DOUTCHN(ch) if(0){}else {szDOUT[0] = ch; OutputDebugString(szDOUT);}
  56. #define DPRINT(p) if(0){}else {wsprintf p; OutputDebugString(szDbgBuf);}
  57. #else
  58. #define DOUTL(p)
  59. #define DOUTCHN(ch)
  60. #define DPRINT(p)
  61. #endif
  62. //
  63. // Global Variables.
  64. //
  65. HANDLE hInst;
  66. INT cchSymRow = 32; // number of characters across the character grid
  67. INT cchSymCol = 8; // number of rows in the character grid
  68. UTCHAR chSymFirst = 32;
  69. UTCHAR chSymLast = 255;
  70. UTCHAR chRangeFirst = 32;
  71. UTCHAR chRangeLast = 255;
  72. SYCM sycm; // tons of data need to do char grid painting
  73. WORD wCFRichText = 0; // private clipboard format, rich text format
  74. HFONT hFontClipboard = NULL; // tells us which font is in the clipboard
  75. HANDLE hstrClipboard = NULL; // contains the string which is in the clipboard
  76. BOOL fDelClipboardFont = FALSE; // the clipboard font needs to be deleted
  77. INT iControl = ID_CHARGRID; // index indicating which control has focus
  78. HBITMAP hbmFont = NULL; // TT bitmap drawn before font facenames in combo
  79. LONG lEditSel = 0; // contains the selection range of the EC
  80. HBRUSH hStaticBrush; // used for static controls during WM_CTLCOLOR
  81. //
  82. // Currently there is no defined interface for querying what character
  83. // ranges a Unicode font supports. For now, this table only has the subsets
  84. // that contain characters supported by the Lucida Sans Unicode font
  85. // uncommented. When we get an API that allows querying the font driver for
  86. // ranges of Unicode characters supported (and whether or not a font is a
  87. // Unicode font!) then all entries can be uncommented.
  88. //
  89. USUBSET aSubsetData[] =
  90. {
  91. { 0x0020, 0x00ff, IDS_WINDOWS },
  92. { 0x0020, 0x00ff, IDS_LATIN1 },
  93. { 0x0100, 0x017f, IDS_LATINEXA },
  94. { 0x0180, 0x024f, IDS_LATINEXB },
  95. { 0x0250, 0x02af, IDS_IPAEX },
  96. { 0x02b0, 0x02ff, IDS_SPACINGMODIFIERS },
  97. { 0x0300, 0x036f, IDS_COMBININGDIACRITICS },
  98. { 0x0370, 0x03cf, IDS_BASICGREEK },
  99. { 0x03d0, 0x03ff, IDS_GREEKSYMBOLS },
  100. { 0x0400, 0x04ff, IDS_CYRILLIC },
  101. { 0x0530, 0x058f, IDS_ARMENIAN },
  102. { 0x0590, 0x05ff, IDS_HEBREW },
  103. { 0x0600, 0x0652, IDS_BASICARABIC },
  104. { 0x0653, 0x06ff, IDS_ARABICEX },
  105. { 0x0900, 0x097f, IDS_DEVANAGARI },
  106. { 0x0980, 0x09ff, IDS_BENGALI },
  107. { 0x0a00, 0x0a7f, IDS_GURMUKHI },
  108. { 0x0a80, 0x0aff, IDS_GUJARATI },
  109. { 0x0b00, 0x0b7f, IDS_ORIYA },
  110. { 0x0b80, 0x0bff, IDS_TAMIL },
  111. { 0x0c00, 0x0c7f, IDS_TELUGU },
  112. { 0x0c80, 0x0cff, IDS_KANNADA },
  113. { 0x0d00, 0x0d7f, IDS_MALAYALAM },
  114. { 0x0e00, 0x0e7f, IDS_THAI },
  115. { 0x0e80, 0x0eff, IDS_LAO },
  116. { 0x10d0, 0x10ff, IDS_BASICGEORGIAN },
  117. { 0x10a0, 0x10cf, IDS_GEORGIANEX },
  118. { 0x1100, 0x11ff, IDS_HANGULJAMO },
  119. { 0x1e00, 0x1eff, IDS_LATINEXADDITIONAL },
  120. { 0x1f00, 0x1fff, IDS_GREEKEX },
  121. { 0x2000, 0x206f, IDS_GENERALPUNCTUATION },
  122. { 0x2070, 0x209f, IDS_SUPERANDSUBSCRIPTS },
  123. { 0x20a0, 0x20cf, IDS_CURRENCYSYMBOLS },
  124. { 0x20d0, 0x20ff, IDS_COMBININGDIACRITICSFORSYMBOLS },
  125. { 0x2100, 0x214f, IDS_LETTERLIKESYMBOLS },
  126. { 0x2150, 0x218f, IDS_NUMBERFORMS },
  127. { 0x2190, 0x21ff, IDS_ARROWS },
  128. { 0x2200, 0x22ff, IDS_MATHEMATICALOPS },
  129. { 0x2300, 0x23ff, IDS_MISCTECHNICAL },
  130. { 0x2400, 0x243f, IDS_CONTROLPICTURES },
  131. { 0x2440, 0x245f, IDS_OPTICALCHAR },
  132. { 0x2460, 0x24ff, IDS_ENCLOSEDALPHANUM },
  133. { 0x2500, 0x257f, IDS_BOXDRAWING },
  134. { 0x2580, 0x259f, IDS_BLOCKELEMENTS },
  135. { 0x25a0, 0x25ff, IDS_GEOMETRICSHAPES },
  136. { 0x2600, 0x26ff, IDS_MISCDINGBATS },
  137. { 0x2700, 0x27bf, IDS_DINGBATS },
  138. { 0x3000, 0x303f, IDS_CJKSYMBOLSANDPUNC },
  139. { 0x3040, 0x309f, IDS_HIRAGANA },
  140. { 0x30a0, 0x30ff, IDS_KATAKANA },
  141. { 0x3100, 0x312f, IDS_BOPOMOFO },
  142. { 0x3130, 0x318f, IDS_HANGULCOMPATIBILITYJAMO },
  143. { 0x3190, 0x319f, IDS_CJKMISC },
  144. { 0x3200, 0x32ff, IDS_ENCLOSEDCJKLETTERSANDMONTHS },
  145. { 0x3300, 0x33ff, IDS_CJKCOMPATIBILITY },
  146. { 0x4e00, 0x9fff, IDS_CJKUNIFIEDIDEOGRAPHS },
  147. { 0xac00, 0xd7a3, IDS_HANGUL },
  148. { 0xe000, 0xf8ff, IDS_PRIVATEUSEAREA },
  149. { 0xf900, 0xfaff, IDS_CJKCOMPATIBILITYIDEOGRAPHS },
  150. { 0xfb00, 0xfb4f, IDS_ALPAHPRESENTATIONFORMS },
  151. { 0xfb50, 0xfdff, IDS_ARABICPRESENTATIONFORMSA },
  152. { 0xfe30, 0xfe4f, IDS_CJKCOMPFORMS },
  153. { 0xfe50, 0xfe6f, IDS_SMALLFORMVARIANTS },
  154. { 0xfe70, 0xfefe, IDS_ARABICPRESENTATIONFORMSB },
  155. { 0xff00, 0xffef, IDS_HALFANDFULLWIDTHFORMS },
  156. { 0xfff0, 0xfffd, IDS_SPECIALS }
  157. };
  158. INT cSubsets = sizeof(aSubsetData) / sizeof(USUBSET);
  159. INT iCurSubset = 0; // index of current Unicode subset - default to Latin-1
  160. //
  161. // Useful window handles.
  162. //
  163. HWND hwndDialog;
  164. HWND hwndCharGrid;
  165. //
  166. // Data used to draw the status bar.
  167. //
  168. RECT rcStatusLine; // bounding rect for status bar
  169. RECT rcToolbar[2]; // bounding rects for toolbars
  170. INT dyStatus; // height of status bar
  171. INT dyToolbar[2]; // height of tool bars
  172. INT dxHelpField; // width of help window
  173. INT dxKeystrokeField; // width of keystroke window
  174. TCHAR szKeystrokeText[MAX_PATH]; // buffer for keystroke text
  175. TCHAR szKeystrokeLabel[30]; // buffer for keystroke label
  176. TCHAR szSpace[15]; // strings for keystroke description
  177. TCHAR szCtrl[15];
  178. TCHAR szCtrlAlt[25];
  179. TCHAR szShiftCtrlAlt[25];
  180. TCHAR szAlt[15];
  181. TCHAR szUnicodeLabel[23]; // buffer for Unicode label
  182. INT iKeystrokeTextStart; // place to start appending text to above
  183. INT iUnicodeLabelStart; // place to start appending text to above
  184. HFONT hfontStatus; // font used for text of status bar
  185. ////////////////////////////////////////////////////////////////////////////
  186. //
  187. // WinMain
  188. //
  189. // Calls initialization function, processes message loop, cleanup.
  190. //
  191. ////////////////////////////////////////////////////////////////////////////
  192. INT WinMain(
  193. HINSTANCE hInstance,
  194. HINSTANCE hPrevInstance,
  195. LPSTR lpCmdLine,
  196. int nCmdShow)
  197. {
  198. MSG msg;
  199. if (!InitApplication(hInstance))
  200. {
  201. return (FALSE);
  202. }
  203. //
  204. // Perform initialization for this instance.
  205. //
  206. if (!InitInstance(hInstance, nCmdShow))
  207. {
  208. return (FALSE);
  209. }
  210. while (GetMessage(&msg, NULL, 0, 0))
  211. {
  212. //
  213. // Filter for possible tabs now to implement context sensitive help.
  214. //
  215. if (msg.message == WM_KEYDOWN)
  216. {
  217. if (!UpdateHelpText(&msg, NULL))
  218. {
  219. continue;
  220. }
  221. }
  222. //
  223. // Main message loop.
  224. //
  225. if (!IsDialogMessage(hwndDialog, &msg))
  226. {
  227. TranslateMessage(&msg);
  228. DispatchMessage(&msg);
  229. }
  230. }
  231. //
  232. // Free up some stuff.
  233. //
  234. if (hfontStatus)
  235. {
  236. DeleteObject(hfontStatus);
  237. }
  238. if (hbmFont)
  239. {
  240. DeleteObject(hbmFont);
  241. }
  242. return (msg.wParam);
  243. }
  244. ////////////////////////////////////////////////////////////////////////////
  245. //
  246. // InitApplication
  247. //
  248. // Initializes window data and registers window class.
  249. //
  250. ////////////////////////////////////////////////////////////////////////////
  251. BOOL InitApplication(
  252. HANDLE hInstance)
  253. {
  254. WNDCLASS wc;
  255. //
  256. // Register a window class that we will use to draw the character
  257. // grid into.
  258. //
  259. wc.style = CS_DBLCLKS;
  260. wc.lpfnWndProc = CharGridWndProc;
  261. wc.cbClsExtra = 0;
  262. wc.cbWndExtra = 0;
  263. wc.hInstance = hInstance;
  264. wc.hIcon = NULL;
  265. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  266. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  267. wc.lpszMenuName = NULL;
  268. wc.lpszClassName = TEXT("CharGridWClass");
  269. if (!RegisterClass(&wc))
  270. {
  271. return (FALSE);
  272. }
  273. wc.style = 0;
  274. wc.lpfnWndProc = DefDlgProc;
  275. wc.cbClsExtra = 0;
  276. wc.cbWndExtra = DLGWINDOWEXTRA;
  277. wc.hInstance = hInstance;
  278. wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDIC_CHARMAP));
  279. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  280. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  281. wc.lpszMenuName = NULL;
  282. wc.lpszClassName = TEXT("MyDlgClass");
  283. if (!RegisterClass(&wc))
  284. {
  285. return (FALSE);
  286. }
  287. }
  288. ////////////////////////////////////////////////////////////////////////////
  289. //
  290. // InitInstance
  291. //
  292. // Does some initialization and creates main window which is a dialog.
  293. //
  294. ////////////////////////////////////////////////////////////////////////////
  295. BOOL InitInstance(
  296. HANDLE hInstance,
  297. INT nCmdShow)
  298. {
  299. INT i;
  300. CHARSETINFO csi;
  301. DWORD dw = GetACP();
  302. LANGID PrimaryLangId = (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())));
  303. BOOL bFE = ((PrimaryLangId == LANG_JAPANESE) ||
  304. (PrimaryLangId == LANG_KOREAN) ||
  305. (PrimaryLangId == LANG_CHINESE));
  306. //
  307. // Save the instance handle in a global variable.
  308. //
  309. hInst = hInstance;
  310. //
  311. // This font will be used to paint the status line.
  312. //
  313. if (!TranslateCharsetInfo((DWORD*)dw, &csi, TCI_SRCCODEPAGE))
  314. {
  315. csi.ciCharset = ANSI_CHARSET;
  316. }
  317. hfontStatus = CreateFont( -PointsToHeight(bFE
  318. ? FE_STATUSPOINTSIZE
  319. : STATUSPOINTSIZE),
  320. 0, 0, 0, 400, 0, 0, 0,
  321. csi.ciCharset,
  322. OUT_DEFAULT_PRECIS,
  323. CLIP_DEFAULT_PRECIS,
  324. DEFAULT_QUALITY,
  325. VARIABLE_PITCH,
  326. TEXT("MS Shell Dlg") );
  327. dyStatus = 2 * PointsToHeight(STATUSPOINTSIZE);
  328. dyToolbar[0] = PointsToHeight(TOOLBARPOINTSIZE);
  329. dyToolbar[1] = PointsToHeight(TOOLBARPOINTSIZE);
  330. //
  331. // Load the Unicode subset names before initializing the main window.
  332. //
  333. for (i = 0; i < cSubsets; i++)
  334. {
  335. if (!LoadString( hInst,
  336. aSubsetData[i].StringResId,
  337. (LPTSTR)aSubsetData[i].Name,
  338. LF_SUBSETSIZE))
  339. {
  340. return (FALSE);
  341. }
  342. }
  343. //
  344. // Create a main window for this application instance.
  345. //
  346. if (!(hwndDialog = CreateDialog( hInstance,
  347. TEXT("CharMap"),
  348. NULL,
  349. CharMapDlgProc )))
  350. {
  351. return (FALSE);
  352. }
  353. //
  354. // Initialize some strings used for the Keystroke status bar field.
  355. // For international purposes, this string could be length 0.
  356. //
  357. LoadString( hInst,
  358. IDS_KEYSTROKE,
  359. (LPTSTR)szKeystrokeLabel,
  360. BTOC(sizeof(szKeystrokeLabel)) );
  361. if (!LoadString( hInst,
  362. IDS_UNICODELABEL,
  363. (LPTSTR)szUnicodeLabel,
  364. BTOC(sizeof(szUnicodeLabel)) ))
  365. {
  366. if (!LoadString( hInst,
  367. IDS_SPACE,
  368. (LPTSTR)szSpace,
  369. BTOC(sizeof(szSpace)) ))
  370. {
  371. return (FALSE);
  372. }
  373. }
  374. if (!LoadString( hInst,
  375. IDS_CTRL,
  376. (LPTSTR)szCtrl,
  377. BTOC(sizeof(szCtrl)) ))
  378. {
  379. return (FALSE);
  380. }
  381. if (!LoadString( hInst,
  382. IDS_CTRLALT,
  383. (LPTSTR)szCtrlAlt,
  384. BTOC(sizeof(szCtrlAlt)) ))
  385. {
  386. return (FALSE);
  387. }
  388. if (!LoadString( hInst,
  389. IDS_SHIFTCTRLALT,
  390. (LPTSTR)szShiftCtrlAlt,
  391. BTOC(sizeof(szShiftCtrlAlt)) ))
  392. {
  393. return (FALSE);
  394. }
  395. if (!LoadString( hInst,
  396. IDS_ALT,
  397. (LPTSTR)szAlt,
  398. BTOC(sizeof(szAlt)) ))
  399. {
  400. return (FALSE);
  401. }
  402. //
  403. // Store the index to where we start adding status line text changes.
  404. //
  405. iKeystrokeTextStart = lstrlen(szKeystrokeLabel);
  406. iUnicodeLabelStart = lstrlen(szUnicodeLabel);
  407. //
  408. // Initialize keystroke text, make the window visible,
  409. // update its client area, and return "success".
  410. //
  411. UpdateKeystrokeText(NULL, sycm.fAnsiFont, sycm.chCurr, FALSE);
  412. ShowWindow(hwndDialog, nCmdShow);
  413. UpdateWindow(hwndDialog);
  414. return (TRUE);
  415. }
  416. ////////////////////////////////////////////////////////////////////////////
  417. //
  418. // ConvertANSIFontToUnicode
  419. //
  420. ////////////////////////////////////////////////////////////////////////////
  421. WCHAR ConvertANSIFontToUnicode(
  422. HWND hwnd,
  423. HFONT hFont,
  424. CHAR ch)
  425. {
  426. WORD cp = CP_ACP;
  427. WCHAR wch;
  428. HDC hdc;
  429. hdc = GetDC(hwnd);
  430. if (hdc != NULL)
  431. {
  432. HFONT hfOld;
  433. TEXTMETRIC tm;
  434. CHARSETINFO csi;
  435. DWORD cs;
  436. hfOld = SelectObject(hdc, hFont);
  437. if (GetTextMetrics(hdc, &tm))
  438. {
  439. cs = MAKELONG(tm.tmCharSet, 0);
  440. if (TranslateCharsetInfo((DWORD *)cs, &csi, TCI_SRCCHARSET))
  441. {
  442. cp = csi.ciACP;
  443. }
  444. else
  445. {
  446. DPRINT(( szDbgBuf,
  447. TEXT("CvtAtoW: TranslateCharsetInfo(cset=%d) returned 0! (GetLastErr=%d), using CP_ACP\n"),
  448. cs,
  449. GetLastError() ));
  450. }
  451. }
  452. SelectObject(hdc, hfOld);
  453. ReleaseDC(hwnd, hdc);
  454. }
  455. if (MultiByteToWideChar(cp, 0, &ch, 1, &wch, 1) != 1)
  456. {
  457. if (MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1) != 1)
  458. {
  459. wch = (WCHAR)(BYTE)ch;
  460. }
  461. }
  462. DPRINT(( szDbgBuf,
  463. TEXT("CvtAtoW: 0x%02x '%c' (CP:%d) -> U'%04X'\n"),
  464. (DWORD)(BYTE)ch,
  465. ch,
  466. cp,
  467. (DWORD)wch ));
  468. return (wch);
  469. }
  470. ////////////////////////////////////////////////////////////////////////////
  471. //
  472. // EnumChildProc
  473. //
  474. // Gets called during init for each child window.
  475. //
  476. ////////////////////////////////////////////////////////////////////////////
  477. BOOL CALLBACK EnumChildProc(
  478. HWND hwnd,
  479. LPARAM lParam)
  480. {
  481. LONG st;
  482. TCHAR szClass[MAX_PATH];
  483. //
  484. // Get control class.
  485. //
  486. GetClassName(hwnd, szClass, MAX_PATH);
  487. if (lstrcmpi(szClass, TEXT("button")) == 0 )
  488. {
  489. //
  490. // If it is a button, set the ex style to NOTIFYPARENT.
  491. //
  492. st = GetWindowLong(hwnd, GWL_EXSTYLE);
  493. st = st & ~WS_EX_NOPARENTNOTIFY;
  494. SetWindowLong(hwnd, GWL_EXSTYLE, st);
  495. }
  496. return (TRUE);
  497. }
  498. ////////////////////////////////////////////////////////////////////////////
  499. //
  500. // CharMapDlgProc
  501. //
  502. // Processes messages for the main window. This window is a dialog box.
  503. //
  504. ////////////////////////////////////////////////////////////////////////////
  505. INT_PTR APIENTRY CharMapDlgProc(
  506. HWND hWnd,
  507. UINT message,
  508. WPARAM wParam,
  509. LPARAM lParam)
  510. {
  511. switch (message)
  512. {
  513. case ( WM_CTLCOLORSTATIC ) :
  514. {
  515. POINT point;
  516. SetBkColor((HDC)wParam, GetSysColor(COLOR_BTNFACE));
  517. UnrealizeObject(hStaticBrush);
  518. point.x = point.y = 0;
  519. ClientToScreen(hWnd, &point);
  520. return ((INT_PTR)hStaticBrush);
  521. break;
  522. }
  523. case ( WM_INITDIALOG ) :
  524. {
  525. RECT rectParent, rectTopRightControl, rect;
  526. POINT pt;
  527. INT iSubset;
  528. HWND hwndCMSB;
  529. //
  530. // Set buttons to send WM_PARENTNOTIFY.
  531. //
  532. EnumChildWindows(hWnd, EnumChildProc, (LPARAM)NULL );
  533. //
  534. // Create the character grid with dimensions which just fit
  535. // inside the space allowed in the dialog. When it processes
  536. // the WM_CREATE message it will be sized and centered more
  537. // accurately.
  538. //
  539. GetClientRect(hWnd, &rectParent);
  540. GetWindowRect(GetDlgItem(hWnd, ID_CLOSE), &rectTopRightControl);
  541. ScreenToClient(hWnd, (LPPOINT)&(rectTopRightControl.left));
  542. ScreenToClient(hWnd, (LPPOINT)&(rectTopRightControl.right));
  543. if (!(hwndCharGrid =
  544. CreateWindow( TEXT("CharGridWClass"),
  545. NULL,
  546. WS_CHILD | WS_VISIBLE | WS_TABSTOP,
  547. 1,
  548. rectParent.top + dyToolbar[0] + dyToolbar[1],
  549. rectParent.right - 1,
  550. rectParent.bottom - rectParent.top -
  551. dyStatus - dyToolbar[0] - dyToolbar[1] - 1,
  552. hWnd,
  553. (HMENU)ID_CHARGRID,
  554. hInst,
  555. NULL )))
  556. {
  557. DestroyWindow(hWnd);
  558. break;
  559. }
  560. GetWindowRect(hwndCharGrid, &rect);
  561. pt.x = rect.right;
  562. pt.y = rect.top;
  563. ScreenToClient(hWnd, &pt);
  564. hwndCMSB = CreateWindowEx( 0L,
  565. TEXT("SCROLLBAR"),
  566. NULL,
  567. WS_CHILD | SBS_VERT | WS_VISIBLE |
  568. WS_TABSTOP,
  569. pt.x + 1,
  570. pt.y + 1,
  571. sycm.dxpBox,
  572. sycm.dypCM,
  573. hWnd,
  574. (HMENU)ID_MAPSCROLL,
  575. hInst,
  576. NULL );
  577. hStaticBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  578. //
  579. // Initialize the status line data.
  580. //
  581. dxHelpField = 21 * rectParent.right / 32;
  582. dxKeystrokeField = 9 * rectParent.right / 32;
  583. rcStatusLine = rectParent;
  584. rcStatusLine.top = rcStatusLine.bottom - dyStatus;
  585. //
  586. // Initialize the toolbars.
  587. //
  588. rcToolbar[0] = rectParent;
  589. rcToolbar[0].bottom = rcToolbar[0].top + dyToolbar[0];
  590. rcToolbar[1] = rcToolbar[0];
  591. rcToolbar[1].top = rcToolbar[0].bottom + GetSystemMetrics(SM_CYBORDER);
  592. rcToolbar[1].bottom = rcToolbar[1].top + dyToolbar[1];
  593. //
  594. // Disable Copy button.
  595. //
  596. EnableWindow(GetDlgItem(hWnd, ID_COPY), FALSE);
  597. //
  598. // Fill "Subset" list box.
  599. //
  600. for (iSubset = 0; iSubset < cSubsets; iSubset++)
  601. {
  602. SendDlgItemMessage( hWnd,
  603. ID_UNICODESUBSET,
  604. CB_ADDSTRING,
  605. 0,
  606. (DWORD)aSubsetData[iSubset].Name );
  607. }
  608. iCurSubset = SelectInitialSubset(hWnd);
  609. //
  610. // Fall through to WM_FONTCHANGE...
  611. //
  612. }
  613. case ( WM_FONTCHANGE ) :
  614. {
  615. HDC hdc = GetDC(hWnd);
  616. //
  617. // Get the fonts from the system and put them in the font
  618. // selection combo box.
  619. //
  620. if (message == WM_FONTCHANGE)
  621. {
  622. SaveCurrentFont(hWnd);
  623. SendDlgItemMessage(hWnd, ID_FONT, CB_RESETCONTENT, 0, 0L);
  624. }
  625. EnumFontFamilies(hdc, NULL, (FONTENUMPROC)FontLoadProc, (LPARAM)hWnd);
  626. ReleaseDC(hWnd, hdc);
  627. //
  628. // Setup character dimensions and select this font.
  629. //
  630. RecalcCharMap( hWnd,
  631. &sycm,
  632. SelectInitialFont(hWnd),
  633. (message == WM_FONTCHANGE) );
  634. SetEditCtlFont(hWnd, ID_STRING, sycm.hFont);
  635. if (message == WM_INITDIALOG)
  636. {
  637. SetFocus(hwndCharGrid);
  638. //
  639. // Fall through to WM_SYSCOLORCHANGE...
  640. //
  641. }
  642. else
  643. {
  644. break;
  645. }
  646. }
  647. case ( WM_SYSCOLORCHANGE ) :
  648. {
  649. if (hbmFont)
  650. {
  651. DeleteObject(hbmFont);
  652. }
  653. hbmFont = LoadBitmaps(IDBM_TT);
  654. DeleteObject(hStaticBrush);
  655. hStaticBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  656. break;
  657. }
  658. case ( WM_PARENTNOTIFY ) :
  659. {
  660. POINTS points;
  661. DWORD dwMsgPos;
  662. POINT point;
  663. DPRINT(( szDbgBuf,
  664. TEXT("WM_PARENTNOTIFY: lParam:0x%08lX, wParam:0x%08lX\n"),
  665. (DWORD)lParam,
  666. (DWORD)wParam ));
  667. //
  668. // We process this message to implement the context sensitive
  669. // help. Downclicks to controls are found here, the help
  670. // message is updated in the status bar.
  671. //
  672. // The parameters with this message are unreliable!
  673. //
  674. if (LOWORD(wParam) == WM_LBUTTONDOWN)
  675. {
  676. dwMsgPos = GetMessagePos();
  677. points = MAKEPOINTS(dwMsgPos);
  678. point.x = points.x;
  679. point.y = points.y;
  680. UpdateHelpText(NULL, WindowFromPoint(point));
  681. }
  682. break;
  683. }
  684. case ( WM_VSCROLL ) :
  685. {
  686. ProcessScrollMsg(hWnd, LOWORD(wParam), HIWORD(wParam));
  687. break;
  688. }
  689. case ( WM_PAINT ) :
  690. {
  691. HBRUSH hBrush;
  692. RECT rcTemp, rectNextButton;
  693. INT dyBorder, dxBorder;
  694. PAINTSTRUCT ps;
  695. HDC hdc;
  696. //
  697. // This code implements painting of the status bar.
  698. //
  699. hdc = BeginPaint(hWnd, &ps);
  700. rcTemp = rcStatusLine;
  701. dyBorder = GetSystemMetrics(SM_CYBORDER);
  702. dxBorder = GetSystemMetrics(SM_CXBORDER);
  703. //
  704. // Make the whole thing grey.
  705. //
  706. if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)))
  707. {
  708. FillRect(hdc, &rcTemp, hBrush);
  709. rcTemp.left = rcToolbar[0].left;
  710. rcTemp.top = rcToolbar[0].top;
  711. rcTemp.right = rcToolbar[1].right;
  712. rcTemp.bottom = rcToolbar[1].bottom;
  713. FillRect(hdc, &rcTemp, hBrush);
  714. DeleteObject(hBrush);
  715. }
  716. GetWindowRect(GetDlgItem(hWnd, ID_TOPLEFT), &rectNextButton);
  717. ScreenToClient(hWnd, (LPPOINT)&(rectNextButton.left));
  718. ScreenToClient(hWnd, (LPPOINT)&(rectNextButton.right));
  719. //
  720. // Solid black line across bottom of toolbar.
  721. //
  722. if (hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME)))
  723. {
  724. #ifdef USE_MIRRORING
  725. DWORD dwLayout;
  726. GetProcessDefaultLayout(&dwLayout);
  727. if(dwLayout & LAYOUT_RTL)
  728. {
  729. //
  730. // Interchange the right and left values.
  731. //
  732. int tmp = rectNextButton.left;
  733. rectNextButton.left = rectNextButton.right;
  734. rectNextButton.right = tmp;
  735. }
  736. #endif
  737. rcTemp = rcToolbar[0];
  738. rcTemp.top = rcTemp.bottom;
  739. rcTemp.bottom += dyBorder;
  740. rcTemp.left = rectNextButton.left - 2 - dxBorder;
  741. FillRect(hdc, &rcTemp, hBrush);
  742. rcTemp = rcToolbar[1];
  743. rcTemp.top = rcTemp.bottom;
  744. rcTemp.bottom += dyBorder;
  745. FillRect(hdc, &rcTemp, hBrush);
  746. //
  747. // Vertical line.
  748. //
  749. rcTemp.top = rcToolbar[0].top;
  750. rcTemp.bottom = rcToolbar[1].bottom;
  751. rcTemp.left = rectNextButton.left - 2 - dxBorder;
  752. rcTemp.right = rectNextButton.left - 2;
  753. FillRect(hdc, &rcTemp, hBrush);
  754. DeleteObject(hBrush);
  755. }
  756. if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW)))
  757. {
  758. //
  759. // Status line top.
  760. //
  761. rcTemp.left = 8 * dyBorder;
  762. rcTemp.right = rcTemp.left + dxHelpField;
  763. rcTemp.top = rcStatusLine.top + dyBorder * 2;
  764. rcTemp.bottom = rcTemp.top + dyBorder;
  765. FillRect(hdc, &rcTemp, hBrush);
  766. //
  767. // Keystroke line top.
  768. //
  769. rcTemp.right = rcStatusLine.right - 8 * dyBorder;
  770. rcTemp.left = rcTemp.right - dxKeystrokeField;
  771. FillRect(hdc, &rcTemp, hBrush);
  772. //
  773. // Status line left side.
  774. //
  775. rcTemp = rcStatusLine;
  776. rcTemp.left = 8 * dyBorder;
  777. rcTemp.right = rcTemp.left + dyBorder;
  778. rcTemp.top += dyBorder * 2;
  779. rcTemp.bottom -= dyBorder * 2;
  780. FillRect(hdc, &rcTemp, hBrush);
  781. //
  782. // Keystroke line left side.
  783. //
  784. rcTemp.left = rcStatusLine.right - 9 * dyBorder - dxKeystrokeField;
  785. rcTemp.right = rcTemp.left + dyBorder;
  786. FillRect(hdc, &rcTemp, hBrush);
  787. DeleteObject(hBrush);
  788. }
  789. if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT)))
  790. {
  791. //
  792. // Status line bottom.
  793. //
  794. rcTemp.left = 8 * dyBorder;
  795. rcTemp.right = rcTemp.left + dxHelpField;
  796. rcTemp.top = rcStatusLine.bottom - 3 * dyBorder;
  797. rcTemp.bottom = rcTemp.top + dyBorder;
  798. FillRect(hdc, &rcTemp, hBrush);
  799. //
  800. // Keystroke line bottom.
  801. //
  802. rcTemp.right = rcStatusLine.right - 8 * dyBorder;
  803. rcTemp.left = rcTemp.right - dxKeystrokeField;
  804. FillRect(hdc, &rcTemp, hBrush);
  805. //
  806. // Status line right side.
  807. //
  808. rcTemp = rcStatusLine;
  809. rcTemp.left = 8 * dyBorder + dxHelpField;
  810. rcTemp.right = rcTemp.left + dyBorder;
  811. rcTemp.top += dyBorder * 2;
  812. rcTemp.bottom -= dyBorder * 2;
  813. FillRect(hdc, &rcTemp, hBrush);
  814. //
  815. // Keystroke line right side.
  816. //
  817. rcTemp.left = rcStatusLine.right - 8 * dyBorder;
  818. rcTemp.right = rcTemp.left + dyBorder;
  819. FillRect(hdc, &rcTemp, hBrush);
  820. DeleteObject(hBrush);
  821. }
  822. //
  823. // Solid black line across top.
  824. //
  825. if (hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME)))
  826. {
  827. rcTemp = rcStatusLine;
  828. rcTemp.bottom = rcTemp.top;
  829. rcTemp.top -= dyBorder;
  830. FillRect(hdc, &rcTemp, hBrush);
  831. DeleteObject(hBrush);
  832. }
  833. PaintStatusLine(hdc, TRUE, TRUE);
  834. EndPaint(hWnd, &ps);
  835. return (TRUE);
  836. }
  837. case ( WM_MEASUREITEM ) :
  838. {
  839. HDC hDC;
  840. HFONT hFont;
  841. TEXTMETRIC tm;
  842. hDC = GetDC(NULL);
  843. hFont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0L);
  844. if (hFont)
  845. {
  846. hFont = SelectObject(hDC, hFont);
  847. }
  848. GetTextMetrics(hDC, &tm);
  849. if (hFont)
  850. {
  851. SelectObject(hDC, hFont);
  852. }
  853. ReleaseDC(NULL, hDC);
  854. ((LPMEASUREITEMSTRUCT)lParam)->itemHeight = max(tm.tmHeight, DY_BITMAP);
  855. break;
  856. }
  857. case ( WM_DRAWITEM ) :
  858. {
  859. if (((LPDRAWITEMSTRUCT)lParam)->itemID != -1)
  860. {
  861. DrawFamilyComboItem((LPDRAWITEMSTRUCT)lParam);
  862. }
  863. break;
  864. }
  865. case ( WM_ASKCBFORMATNAME ) :
  866. {
  867. LoadString(hInst, IDS_RTF, (LPTSTR)lParam, wParam);
  868. return (TRUE);
  869. }
  870. case ( WM_PAINTCLIPBOARD ) :
  871. {
  872. LPPAINTSTRUCT lpPS;
  873. HANDLE hFont;
  874. LPTSTR lpstrText;
  875. if (hstrClipboard)
  876. {
  877. //
  878. // Setup.
  879. //
  880. lpPS = (LPPAINTSTRUCT)GlobalLock((HANDLE)lParam);
  881. lpstrText = (LPTSTR)GlobalLock(hstrClipboard);
  882. //
  883. // Paint.
  884. //
  885. hFont = SelectObject(lpPS->hdc, hFontClipboard);
  886. TextOut(lpPS->hdc, 0, 0, lpstrText, lstrlen(lpstrText));
  887. SelectObject(lpPS->hdc, hFont);
  888. //
  889. // Cleanup.
  890. //
  891. GlobalUnlock(hstrClipboard);
  892. GlobalUnlock((HANDLE)lParam);
  893. }
  894. return (TRUE);
  895. }
  896. case ( WM_CLOSE ) :
  897. {
  898. DestroyWindow(hWnd);
  899. return (TRUE);
  900. }
  901. case ( WM_COMMAND ) :
  902. {
  903. switch (GET_WM_COMMAND_ID(wParam, lParam))
  904. {
  905. case ( IDCANCEL ) :
  906. case ( ID_CLOSE ) :
  907. {
  908. DestroyWindow(hWnd);
  909. return (TRUE);
  910. break;
  911. }
  912. case ( ID_SELECT ) :
  913. {
  914. WCHAR wch = sycm.chCurr;
  915. if (sycm.fAnsiFont)
  916. {
  917. wch = ConvertANSIFontToUnicode( hWnd,
  918. sycm.hFont,
  919. (char)wch );
  920. }
  921. SendDlgItemMessage(hWnd, ID_STRING, WM_CHAR, (WPARAM)wch, 0L);
  922. break;
  923. }
  924. case ( ID_COPY ) :
  925. {
  926. CopyString(hWnd);
  927. return (TRUE);
  928. break;
  929. }
  930. case ( ID_FONT ) :
  931. {
  932. if (HIWORD(wParam) == CBN_SELCHANGE)
  933. {
  934. RecalcCharMap( hWnd,
  935. &sycm,
  936. (INT)SendDlgItemMessage( hWnd,
  937. ID_FONT,
  938. CB_GETCURSEL,
  939. 0,
  940. 0L ),
  941. TRUE );
  942. SetEditCtlFont(hWnd, ID_STRING, sycm.hFont);
  943. }
  944. else if (HIWORD(wParam) == CBN_SETFOCUS)
  945. {
  946. //
  947. // Necessary if hotkey is used to get to the CB.
  948. //
  949. UpdateHelpText(NULL, (HWND)lParam);
  950. }
  951. return (TRUE);
  952. break;
  953. }
  954. case ( ID_UNICODESUBSET ) :
  955. {
  956. if (HIWORD(wParam) == CBN_SELCHANGE)
  957. {
  958. INT iSubset;
  959. INT cEntries;
  960. iSubset = (INT)SendDlgItemMessage( hWnd,
  961. ID_UNICODESUBSET,
  962. CB_GETCURSEL,
  963. 0,
  964. 0 );
  965. SubSetChanged( hWnd,
  966. iSubset,
  967. aSubsetData[iSubset].BeginRange,
  968. aSubsetData[iSubset].EndRange );
  969. cEntries = (INT)SendDlgItemMessage( hWnd,
  970. ID_UNICODESUBSET,
  971. CB_GETCOUNT,
  972. 0,
  973. 0 ) - 1;
  974. EnableWindow( GetDlgItem(hWnd, ID_PREVSUBSET),
  975. iSubset > 0 );
  976. EnableWindow( GetDlgItem(hWnd, ID_NEXTSUBSET),
  977. iSubset < cEntries );
  978. }
  979. else if (HIWORD(wParam) == CBN_SETFOCUS)
  980. {
  981. //
  982. // Necessary if hotkey is used to get to the CB.
  983. //
  984. UpdateHelpText(NULL, (HWND)lParam);
  985. }
  986. return (0L);
  987. break;
  988. }
  989. case ( ID_NEXTSUBSET ) :
  990. {
  991. INT iCurSelection, iNumEntries;
  992. iCurSelection = (INT)SendDlgItemMessage( hWnd,
  993. ID_UNICODESUBSET,
  994. CB_GETCURSEL,
  995. 0,
  996. 0 );
  997. if (iCurSelection == CB_ERR)
  998. {
  999. return (0L);
  1000. }
  1001. iNumEntries = (INT)SendDlgItemMessage( hWnd,
  1002. ID_UNICODESUBSET,
  1003. CB_GETCOUNT,
  1004. 0,
  1005. 0 );
  1006. if (iNumEntries == CB_ERR)
  1007. {
  1008. return (0L);
  1009. }
  1010. if (iCurSelection++ < (iNumEntries - 1))
  1011. {
  1012. if (iCurSelection == 1)
  1013. {
  1014. //
  1015. // Enable Previous button.
  1016. //
  1017. EnableWindow(GetDlgItem(hWnd, ID_PREVSUBSET), TRUE);
  1018. }
  1019. SendDlgItemMessage( hWnd,
  1020. ID_UNICODESUBSET,
  1021. CB_SETCURSEL,
  1022. iCurSelection,
  1023. 0 );
  1024. SubSetChanged( hWnd,
  1025. iCurSelection,
  1026. aSubsetData[iCurSelection].BeginRange,
  1027. aSubsetData[iCurSelection].EndRange );
  1028. if (iCurSelection == (iNumEntries - 1))
  1029. {
  1030. HWND hwndButton;
  1031. EnableWindow(GetDlgItem(hWnd, ID_NEXTSUBSET), FALSE);
  1032. //
  1033. // Only reset the button style and focus if
  1034. // the "Next" button currently has it.
  1035. //
  1036. if (iControl == ID_NEXTSUBSET)
  1037. {
  1038. SendDlgItemMessage( hwndDialog,
  1039. ID_PREVSUBSET,
  1040. BM_SETSTYLE,
  1041. BS_DEFPUSHBUTTON,
  1042. 1 );
  1043. SendDlgItemMessage( hwndDialog,
  1044. ID_NEXTSUBSET,
  1045. BM_SETSTYLE,
  1046. BS_PUSHBUTTON,
  1047. 1 );
  1048. hwndButton = GetDlgItem(hWnd, ID_PREVSUBSET);
  1049. SetFocus(hwndButton);
  1050. UpdateHelpText(NULL, hwndButton);
  1051. }
  1052. }
  1053. }
  1054. return (0L);
  1055. break;
  1056. }
  1057. case ( ID_PREVSUBSET ) :
  1058. {
  1059. INT iCurSelection;
  1060. iCurSelection = (INT)SendDlgItemMessage( hWnd,
  1061. ID_UNICODESUBSET,
  1062. CB_GETCURSEL,
  1063. 0,
  1064. 0 );
  1065. if (iCurSelection == CB_ERR)
  1066. {
  1067. return (0L);
  1068. }
  1069. if (iCurSelection > 0)
  1070. {
  1071. iCurSelection--;
  1072. if (iCurSelection == (cSubsets - 2))
  1073. {
  1074. //
  1075. // Enable Next button.
  1076. //
  1077. EnableWindow(GetDlgItem(hWnd, ID_NEXTSUBSET), TRUE);
  1078. }
  1079. SendDlgItemMessage( hWnd,
  1080. ID_UNICODESUBSET,
  1081. CB_SETCURSEL,
  1082. iCurSelection,
  1083. 0 );
  1084. SubSetChanged( hWnd,
  1085. iCurSelection,
  1086. aSubsetData[iCurSelection].BeginRange,
  1087. aSubsetData[iCurSelection].EndRange );
  1088. if (iCurSelection == 0)
  1089. {
  1090. HWND hwndButton;
  1091. EnableWindow(GetDlgItem(hWnd, ID_PREVSUBSET), FALSE);
  1092. //
  1093. // Only reset the button style and focus if
  1094. // the "Previous" button currently has it.
  1095. //
  1096. if (iControl == ID_PREVSUBSET)
  1097. {
  1098. SendDlgItemMessage( hwndDialog,
  1099. ID_NEXTSUBSET,
  1100. BM_SETSTYLE,
  1101. BS_DEFPUSHBUTTON,
  1102. 1 );
  1103. SendDlgItemMessage( hwndDialog,
  1104. ID_PREVSUBSET,
  1105. BM_SETSTYLE,
  1106. BS_PUSHBUTTON,
  1107. 1 );
  1108. hwndButton = GetDlgItem(hWnd, ID_NEXTSUBSET);
  1109. SetFocus(hwndButton);
  1110. UpdateHelpText(NULL, hwndButton);
  1111. }
  1112. }
  1113. }
  1114. return (0L);
  1115. break;
  1116. }
  1117. case ( ID_STRING ) :
  1118. {
  1119. if (HIWORD(wParam) == EN_SETFOCUS)
  1120. {
  1121. //
  1122. // Necessary if hotkey is used to get to the EC.
  1123. //
  1124. UpdateHelpText(NULL, (HWND)lParam);
  1125. }
  1126. else if (HIWORD(wParam) == EN_CHANGE)
  1127. {
  1128. //
  1129. // Disable Copy button if there are no chars in EC.
  1130. //
  1131. INT iLength;
  1132. iLength = GetWindowTextLength((HWND)lParam);
  1133. EnableWindow(GetDlgItem(hWnd, ID_COPY), (BOOL)iLength);
  1134. }
  1135. break;
  1136. }
  1137. case ( ID_HELP ) :
  1138. {
  1139. DoHelp(hWnd, TRUE);
  1140. break;
  1141. }
  1142. }
  1143. break;
  1144. }
  1145. case ( WM_DESTROY ) :
  1146. {
  1147. SaveCurrentFont(hWnd);
  1148. SaveCurrentSubset(hWnd);
  1149. DoHelp(hWnd, FALSE);
  1150. DeleteObject(hStaticBrush);
  1151. PostQuitMessage(0);
  1152. break;
  1153. }
  1154. case ( WM_ACTIVATEAPP ) :
  1155. {
  1156. if (wParam)
  1157. {
  1158. SendDlgItemMessage( hWnd,
  1159. ID_STRING,
  1160. EM_SETSEL,
  1161. LOWORD(lEditSel),
  1162. HIWORD(lEditSel) );
  1163. }
  1164. else
  1165. {
  1166. lEditSel = SendDlgItemMessage(hWnd, ID_STRING, EM_GETSEL, 0, 0L);
  1167. SendDlgItemMessage(hWnd, ID_STRING, EM_SETSEL, 0, 0L);
  1168. }
  1169. break;
  1170. }
  1171. }
  1172. return (0L);
  1173. }
  1174. ////////////////////////////////////////////////////////////////////////////
  1175. //
  1176. // CharGridWndProc
  1177. //
  1178. // Processes messages for the character grid window.
  1179. //
  1180. ////////////////////////////////////////////////////////////////////////////
  1181. LRESULT APIENTRY CharGridWndProc(
  1182. HWND hWnd,
  1183. UINT message,
  1184. WPARAM wParam,
  1185. LPARAM lParam)
  1186. {
  1187. switch (message)
  1188. {
  1189. case ( WM_CREATE ) :
  1190. {
  1191. RECT rect;
  1192. HDC hdcScrn;
  1193. POINT point1, point2;
  1194. //
  1195. // Setup global.
  1196. //
  1197. hwndCharGrid = hWnd;
  1198. GetClientRect(hWnd, &rect);
  1199. //
  1200. // Calculate metrics for the character grid and the
  1201. // magnify window.
  1202. //
  1203. sycm.dxpBox = (rect.right - 1) / (cchSymRow + 2);
  1204. sycm.dypBox = (rect.bottom - 2) / (cchSymCol + 1);
  1205. sycm.dxpCM = sycm.dxpBox * cchSymRow + 1;
  1206. sycm.dypCM = sycm.dypBox * cchSymCol + 1; // space inside for border
  1207. if ((PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_CHINESE))
  1208. {
  1209. sycm.dxpMag = sycm.dxpBox * 3 + 5;
  1210. }
  1211. else
  1212. {
  1213. sycm.dxpMag = sycm.dxpBox * 2 + 4; // twice the size + 2 bit border
  1214. }
  1215. sycm.dypMag = sycm.dypBox * 2 + 4;
  1216. sycm.chCurr = chSymFirst;
  1217. sycm.hFontMag = NULL;
  1218. sycm.hFont = NULL;
  1219. sycm.hdcMag = NULL;
  1220. sycm.hbmMag = NULL;
  1221. sycm.ypDest = 0;
  1222. sycm.fFocusState = sycm.fMouseDn = sycm.fCursorOff = FALSE;
  1223. //
  1224. // Size the window precisely so the grid fits and is centered.
  1225. //
  1226. MoveWindow( hWnd,
  1227. (rect.right - sycm.dxpCM + 1) / 2,
  1228. (rect.bottom - sycm.dypCM + 1) / 2 +
  1229. ((LPCREATESTRUCT)lParam)->y - 2,
  1230. sycm.dxpCM + 2,
  1231. sycm.dypCM + 2,
  1232. FALSE );
  1233. //
  1234. // Figure out what the offsets are between the dialog
  1235. // and the character grid window.
  1236. //
  1237. point1.x = point1.y = point2.x = point2.y = 0;
  1238. ClientToScreen(hWnd, &point1);
  1239. ClientToScreen(((LPCREATESTRUCT)lParam)->hwndParent, &point2);
  1240. #ifdef USE_MIRRORING
  1241. sycm.xpCM = (abs(point1.x - point2.x)) - (sycm.dxpMag - sycm.dxpBox) / 2;
  1242. #else
  1243. sycm.xpCM = (point1.x - point2.x) - (sycm.dxpMag - sycm.dxpBox) / 2;
  1244. #endif
  1245. sycm.ypCM = (point1.y - point2.y) - (sycm.dypMag - sycm.dypBox) / 2;
  1246. //
  1247. // Create dc and bitmap for the magnify window.
  1248. //
  1249. if ((hdcScrn = GetWindowDC(hWnd)) != NULL)
  1250. {
  1251. if ((sycm.hdcMag = CreateCompatibleDC(hdcScrn)) != NULL)
  1252. {
  1253. SetTextColor( sycm.hdcMag,
  1254. GetSysColor(COLOR_WINDOWTEXT) );
  1255. SetBkColor( sycm.hdcMag,
  1256. GetSysColor(COLOR_WINDOW) );
  1257. SetBkMode(sycm.hdcMag, OPAQUE);
  1258. if ((sycm.hbmMag =
  1259. CreateCompatibleBitmap( hdcScrn,
  1260. sycm.dxpMag,
  1261. sycm.dypMag * 2 )) == NULL)
  1262. {
  1263. DeleteObject(sycm.hdcMag);
  1264. }
  1265. else
  1266. {
  1267. SelectObject(sycm.hdcMag, sycm.hbmMag);
  1268. }
  1269. }
  1270. ReleaseDC(hWnd, hdcScrn);
  1271. }
  1272. break;
  1273. }
  1274. case ( WM_DESTROY ) :
  1275. {
  1276. if (sycm.fMouseDn)
  1277. {
  1278. ExitMagnify(hWnd, &sycm);
  1279. }
  1280. if (fDelClipboardFont)
  1281. {
  1282. DeleteObject(hFontClipboard);
  1283. }
  1284. if (sycm.hFont != NULL)
  1285. {
  1286. DeleteObject(sycm.hFont);
  1287. }
  1288. if (sycm.hFontMag != NULL)
  1289. {
  1290. DeleteObject(sycm.hFontMag);
  1291. }
  1292. if (sycm.hdcMag != NULL)
  1293. {
  1294. DeleteDC(sycm.hdcMag);
  1295. }
  1296. if (sycm.hbmMag != NULL)
  1297. {
  1298. DeleteObject(sycm.hbmMag);
  1299. }
  1300. break;
  1301. }
  1302. case ( WM_SETFOCUS ) :
  1303. case ( WM_KILLFOCUS ) :
  1304. {
  1305. RestoreSymMag(&sycm);
  1306. DrawSymChOutlineHwnd( &sycm,
  1307. hWnd,
  1308. sycm.chCurr,
  1309. TRUE,
  1310. message == WM_SETFOCUS );
  1311. break;
  1312. }
  1313. case ( WM_LBUTTONDOWN ) :
  1314. {
  1315. RECT rect;
  1316. DOUTL("WM_LBUTTONDOWN: In\n");
  1317. //
  1318. // Don't draw anything if there's an update region pending.
  1319. //
  1320. if (GetUpdateRect(hWnd, (LPRECT)&rect, FALSE) != 0)
  1321. {
  1322. DOUTL("WM_LBUTTONDOWN: No upd rect\n");
  1323. break;
  1324. }
  1325. SetFocus(hWnd);
  1326. SetCapture(hWnd);
  1327. sycm.fMouseDn = TRUE;
  1328. if (!FMagData(&sycm))
  1329. {
  1330. DOUTL("WM_LBUTTONDOWN: Drawing sym outline\n");
  1331. DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE);
  1332. }
  1333. //
  1334. // Fall through to WM_MOUSEMOVE...
  1335. //
  1336. }
  1337. case ( WM_MOUSEMOVE ) :
  1338. {
  1339. DOUTL("WM_MOUSEMOVE: In\n");
  1340. if (sycm.fMouseDn)
  1341. {
  1342. POINT pt;
  1343. UINT chMouseSymbol;
  1344. DOUTL("WM_MOUSEMOVE: mouse is down\n");
  1345. pt.x = LOWORD(lParam);
  1346. pt.y = HIWORD(lParam);
  1347. ClientToScreen(hWnd, (LPPOINT)&pt);
  1348. if (WindowFromPoint(pt) == hWnd)
  1349. {
  1350. ScreenToClient(hWnd, (LPPOINT)&pt);
  1351. //
  1352. // Convert back to a 'points'-like thing.
  1353. //
  1354. lParam = MAKELONG((WORD)pt.x, (WORD)pt.y);
  1355. chMouseSymbol = (UINT)ChFromSymLParam(&sycm, lParam);
  1356. if (chMouseSymbol > (UINT)chSymLast)
  1357. {
  1358. //
  1359. // We're outside of current character range (but
  1360. // still within the grid). Restore cursor and
  1361. // leave magnified character.
  1362. //
  1363. if (sycm.fCursorOff)
  1364. {
  1365. sycm.fCursorOff = FALSE;
  1366. ShowCursor(TRUE);
  1367. }
  1368. }
  1369. else
  1370. {
  1371. //
  1372. // We're in the grid and within the range of currently
  1373. // displayed characters, display magnified character.
  1374. //
  1375. DOUTL("WM_MOUSEMOVE: in grid and subrange\n");
  1376. if (!sycm.fCursorOff)
  1377. {
  1378. sycm.fCursorOff = TRUE;
  1379. ShowCursor(FALSE);
  1380. }
  1381. DOUTL("WM_MOUSEMOVE: movsymsel ");
  1382. DOUTCHN( (UTCHAR)chMouseSymbol );
  1383. MoveSymbolSel(&sycm, (UTCHAR)chMouseSymbol);
  1384. }
  1385. }
  1386. else
  1387. {
  1388. //
  1389. // Left grid, leave magnified character and restore
  1390. // cursor.
  1391. //
  1392. if (sycm.fCursorOff)
  1393. {
  1394. sycm.fCursorOff = FALSE;
  1395. ShowCursor(TRUE);
  1396. }
  1397. }
  1398. }
  1399. DOUTL("WM_MOUSEMOVE: Leaving\n");
  1400. break;
  1401. }
  1402. case ( WM_CANCELMODE ) :
  1403. case ( WM_LBUTTONUP ) :
  1404. {
  1405. if (sycm.fMouseDn)
  1406. {
  1407. ExitMagnify(hWnd, &sycm);
  1408. }
  1409. break;
  1410. }
  1411. case ( WM_LBUTTONDBLCLK ) :
  1412. {
  1413. WCHAR wch = sycm.chCurr;
  1414. //
  1415. // Send this character to the entry field.
  1416. //
  1417. if (sycm.fAnsiFont)
  1418. {
  1419. wch = ConvertANSIFontToUnicode(hWnd, sycm.hFont, (char)wch);
  1420. }
  1421. SendDlgItemMessage(hwndDialog, ID_STRING, WM_CHAR, (WPARAM)wch, 0L);
  1422. break;
  1423. }
  1424. case ( WM_GETDLGCODE ) :
  1425. {
  1426. //
  1427. // Necessary to obtain arrow and tab messages.
  1428. //
  1429. return (DLGC_WANTARROWS | DLGC_WANTCHARS);
  1430. break;
  1431. }
  1432. case ( WM_KEYDOWN ) :
  1433. {
  1434. UTCHAR chNew = sycm.chCurr;
  1435. INT cchMoved;
  1436. if (sycm.fMouseDn)
  1437. {
  1438. break;
  1439. }
  1440. switch (wParam)
  1441. {
  1442. case ( VK_LEFT ) :
  1443. {
  1444. if (--chNew < chSymFirst)
  1445. {
  1446. return (0L);
  1447. }
  1448. break;
  1449. }
  1450. case ( VK_UP ) :
  1451. {
  1452. if ((chNew -= cchSymRow) < chSymFirst)
  1453. {
  1454. if (!ScrollMap(GetParent(hWnd), -cchSymRow, TRUE))
  1455. {
  1456. return (0L);
  1457. }
  1458. RestoreSymMag(&sycm);
  1459. }
  1460. break;
  1461. }
  1462. case ( VK_RIGHT ) :
  1463. {
  1464. if (++chNew > chSymLast)
  1465. {
  1466. return (0L);
  1467. }
  1468. break;
  1469. }
  1470. case ( VK_DOWN ) :
  1471. {
  1472. if ((chNew += cchSymRow) > chSymLast)
  1473. {
  1474. if (!ScrollMap(GetParent(hWnd), cchSymRow, TRUE))
  1475. {
  1476. return (0L);
  1477. }
  1478. RestoreSymMag(&sycm);
  1479. }
  1480. break;
  1481. }
  1482. case ( VK_NEXT ) :
  1483. {
  1484. if ((cchMoved =
  1485. ScrollMapPage(GetParent(hWnd), FALSE, TRUE)) == 0)
  1486. {
  1487. return (0L);
  1488. }
  1489. //
  1490. // We scrolled the map! Bump the char so it is
  1491. // still in the window.
  1492. //
  1493. RestoreSymMag(&sycm);
  1494. chNew += cchMoved;
  1495. break;
  1496. }
  1497. case ( VK_PRIOR ) :
  1498. {
  1499. if ((cchMoved =
  1500. ScrollMapPage( GetParent(hWnd), TRUE, TRUE )) == 0)
  1501. {
  1502. return (0L);
  1503. }
  1504. //
  1505. // We scrolled the map! Bump the char so it is
  1506. // still in the window.
  1507. //
  1508. RestoreSymMag(&sycm);
  1509. chNew += cchMoved;
  1510. break;
  1511. }
  1512. default :
  1513. {
  1514. return (0L);
  1515. }
  1516. }
  1517. if (!FMagData(&sycm))
  1518. {
  1519. DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE);
  1520. }
  1521. MoveSymbolSel(&sycm, (UTCHAR)chNew);
  1522. break;
  1523. }
  1524. case ( WM_CHAR ) :
  1525. {
  1526. WCHAR wch = (WCHAR)wParam;
  1527. char ch;
  1528. if (sycm.fMouseDn)
  1529. {
  1530. break;
  1531. }
  1532. if (sycm.fAnsiFont)
  1533. {
  1534. if (WideCharToMultiByte( CP_ACP,
  1535. 0,
  1536. &wch,
  1537. 1,
  1538. &ch,
  1539. 1,
  1540. NULL,
  1541. NULL ) != 1)
  1542. {
  1543. break;
  1544. }
  1545. wch = (WCHAR)(BYTE)ch;
  1546. }
  1547. if ((wch >= chSymFirst) && (wch <= chSymLast))
  1548. {
  1549. if (!FMagData(&sycm))
  1550. {
  1551. DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE);
  1552. }
  1553. MoveSymbolSel(&sycm, (UTCHAR)wch);
  1554. SendDlgItemMessage(hwndDialog, ID_STRING, WM_CHAR, wParam, 0L);
  1555. }
  1556. break;
  1557. }
  1558. case ( WM_PAINT ) :
  1559. {
  1560. HDC hdc;
  1561. PAINTSTRUCT ps;
  1562. DOUTL("WM_PAINT: In\n");
  1563. hdc = BeginPaint(hWnd, &ps);
  1564. DOUTL("WM_PAINT: drawing map\n");
  1565. DrawSymbolMap(&sycm, hdc);
  1566. EndPaint(hWnd, &ps);
  1567. DOUTL("WM_PAINT: Leaving\n");
  1568. return (TRUE);
  1569. }
  1570. default :
  1571. {
  1572. return (DefWindowProc(hWnd, message, wParam, lParam));
  1573. }
  1574. }
  1575. return (0L);
  1576. }
  1577. ////////////////////////////////////////////////////////////////////////////
  1578. //
  1579. // ProcessScrollMsg
  1580. //
  1581. ////////////////////////////////////////////////////////////////////////////
  1582. VOID ProcessScrollMsg(
  1583. HWND hwndDlg,
  1584. int nCode,
  1585. int nPos)
  1586. {
  1587. UTCHAR chNew = sycm.chCurr;
  1588. HWND hwndGrid = GetDlgItem(hwndDlg, ID_CHARGRID);
  1589. int cchScroll;
  1590. switch( nCode )
  1591. {
  1592. case ( SB_LINEUP ) :
  1593. {
  1594. cchScroll = -cchSymRow;
  1595. break;
  1596. }
  1597. case ( SB_LINEDOWN ) :
  1598. {
  1599. cchScroll = cchSymRow;
  1600. break;
  1601. }
  1602. case ( SB_PAGEUP ) :
  1603. {
  1604. cchScroll = (int)TRUE;
  1605. break;
  1606. }
  1607. case ( SB_PAGEDOWN ) :
  1608. {
  1609. cchScroll = (int)FALSE;
  1610. break;
  1611. }
  1612. case ( SB_THUMBTRACK ) :
  1613. case ( SB_THUMBPOSITION ) :
  1614. {
  1615. cchScroll = (nPos * cchSymRow + chRangeFirst) - chSymFirst;
  1616. break;
  1617. }
  1618. default :
  1619. {
  1620. return;
  1621. }
  1622. }
  1623. if (nCode == SB_PAGEUP || nCode == SB_PAGEDOWN)
  1624. {
  1625. if (!ScrollMapPage(hwndDlg, (BOOL)cchScroll, FALSE))
  1626. {
  1627. return;
  1628. }
  1629. //
  1630. // ScrollMapPage will do the right thing to sycm.chCurr.
  1631. //
  1632. chNew = sycm.chCurr;
  1633. }
  1634. else
  1635. {
  1636. if (cchScroll == 0 || !ScrollMap(hwndDlg, cchScroll, FALSE))
  1637. {
  1638. return;
  1639. }
  1640. //
  1641. // Keep the current symbol inside the window.
  1642. //
  1643. while (chNew > chSymLast)
  1644. {
  1645. chNew -= cchSymRow;
  1646. }
  1647. while (chNew < chSymFirst)
  1648. {
  1649. chNew += cchSymRow;
  1650. }
  1651. }
  1652. #if 0
  1653. if (!FMagData(&sycm))
  1654. {
  1655. DrawSymChOutlineHwnd(&sycm, hwndGrid, sycm.chCurr, FALSE, FALSE);
  1656. }
  1657. MoveSymbolSel(&sycm, (UTCHAR)chNew);
  1658. #else
  1659. sycm.chCurr = chNew;
  1660. InvalidateRect(hwndGrid, NULL, TRUE);
  1661. #endif
  1662. }
  1663. ////////////////////////////////////////////////////////////////////////////
  1664. //
  1665. // ScrollMapPage
  1666. //
  1667. // Scrolls the map up or down by a page. See ScrollMap().
  1668. //
  1669. ////////////////////////////////////////////////////////////////////////////
  1670. INT ScrollMapPage(
  1671. HWND hwndDlg,
  1672. BOOL fUp,
  1673. BOOL fRePaint)
  1674. {
  1675. INT cchScroll = cchFullMap;
  1676. if (fUp)
  1677. {
  1678. cchScroll = -cchScroll;
  1679. }
  1680. if ((chSymFirst + cchScroll) < chRangeFirst)
  1681. {
  1682. cchScroll = (chRangeFirst - chSymFirst);
  1683. }
  1684. else if ((chSymLast + cchScroll) > chRangeLast)
  1685. {
  1686. cchScroll = (chRangeLast - chSymLast);
  1687. }
  1688. return (ScrollMap(hwndDlg, cchScroll, fRePaint) ? cchScroll : 0);
  1689. }
  1690. ////////////////////////////////////////////////////////////////////////////
  1691. //
  1692. // ScrollMap
  1693. //
  1694. // Scrolls the map up or down if there are too many chars to fit in the
  1695. // chargrid.
  1696. //
  1697. ////////////////////////////////////////////////////////////////////////////
  1698. BOOL ScrollMap(
  1699. HWND hwndDlg,
  1700. INT cchScroll,
  1701. BOOL fRePaint)
  1702. {
  1703. HWND hwndSB, hwndCharGrid;
  1704. INT chFirst = chSymFirst + cchScroll;
  1705. INT chLast = chSymLast + cchScroll;
  1706. HDC hdc;
  1707. if ((chFirst < chRangeFirst) || (chLast > chRangeLast))
  1708. {
  1709. return (FALSE);
  1710. }
  1711. hwndCharGrid = GetDlgItem(hwndDlg, ID_CHARGRID);
  1712. hwndSB = GetDlgItem(hwndDlg, ID_MAPSCROLL);
  1713. SetScrollPos(hwndSB, SB_CTL, (chFirst - chRangeFirst) / cchSymRow, TRUE);
  1714. UpdateSymbolRange(hwndDlg, chFirst, chLast);
  1715. if ((hwndDlg != NULL) && ((hdc = GetDC(hwndDlg)) != NULL))
  1716. {
  1717. LPINT lpdxp;
  1718. HFONT hFont;
  1719. UINT ch;
  1720. hFont = SelectObject(hdc, sycm.hFont);
  1721. lpdxp = (LPINT)sycm.rgdxp;
  1722. if (sycm.fAnsiFont)
  1723. {
  1724. GetCharWidth32A(hdc, chSymFirst, chSymLast, lpdxp);
  1725. }
  1726. else
  1727. {
  1728. GetCharWidth32(hdc, chSymFirst, chSymLast, lpdxp);
  1729. }
  1730. SelectObject(hdc, hFont);
  1731. for (ch = (UINT) chSymFirst; ch <= (UINT) chSymLast; ch++, lpdxp++)
  1732. {
  1733. *lpdxp = (sycm.dxpBox - *lpdxp) / 2 - 1;
  1734. }
  1735. ReleaseDC(hwndDlg, hdc);
  1736. }
  1737. if (fRePaint)
  1738. {
  1739. InvalidateRect(hwndCharGrid, NULL, TRUE);
  1740. }
  1741. return (TRUE);
  1742. }
  1743. ////////////////////////////////////////////////////////////////////////////
  1744. //
  1745. // ChFromSymLParam
  1746. //
  1747. // Determines the character to select from the mouse position (lParam).
  1748. //
  1749. ////////////////////////////////////////////////////////////////////////////
  1750. INT ChFromSymLParam(
  1751. PSYCM psycm,
  1752. LPARAM lParam)
  1753. {
  1754. return (min( cchSymRow - 1,
  1755. max(0, ((INT)LOWORD(lParam) - 1) / psycm->dxpBox) ) +
  1756. min( cchSymCol - 1,
  1757. max(0, ((INT)HIWORD(lParam) - 1) / psycm->dypBox) ) *
  1758. cchSymRow + chSymFirst);
  1759. }
  1760. ////////////////////////////////////////////////////////////////////////////
  1761. //
  1762. // DrawSymChOutlineHwnd
  1763. //
  1764. // Gets a DC for hwnd, calls DrawSymChOutline.
  1765. //
  1766. ////////////////////////////////////////////////////////////////////////////
  1767. VOID DrawSymChOutlineHwnd(
  1768. PSYCM psycm,
  1769. HWND hwnd,
  1770. UTCHAR ch,
  1771. BOOL fVisible,
  1772. BOOL fFocus)
  1773. {
  1774. HDC hdc = GetDC(hwnd);
  1775. DrawSymChOutline(psycm, hdc, ch, fVisible, fFocus);
  1776. ReleaseDC(hwnd, hdc);
  1777. }
  1778. ////////////////////////////////////////////////////////////////////////////
  1779. //
  1780. // RecalcCharMap
  1781. //
  1782. // Recalculates fixed character map data (font info, sizes, etc.).
  1783. //
  1784. ////////////////////////////////////////////////////////////////////////////
  1785. VOID RecalcCharMap(
  1786. HWND hwndDlg,
  1787. PSYCM psycm,
  1788. INT iCombo,
  1789. BOOL fRedraw)
  1790. {
  1791. HDC hdc;
  1792. TEXTMETRIC tm;
  1793. UINT ch;
  1794. LPINT lpdxp;
  1795. HFONT hFont;
  1796. LOGFONT LogFont;
  1797. ITEMDATA ItemData;
  1798. LONG iCurSel;
  1799. //
  1800. // Get rid of the old font handles.
  1801. //
  1802. if (hFontClipboard && (hFontClipboard == psycm->hFont))
  1803. {
  1804. fDelClipboardFont = TRUE;
  1805. }
  1806. if (psycm->hFont && (hFontClipboard != psycm->hFont))
  1807. {
  1808. DeleteObject(psycm->hFont);
  1809. }
  1810. if (psycm->hFontMag)
  1811. {
  1812. DeleteObject(psycm->hFontMag);
  1813. }
  1814. hdc = GetDC(hwndCharGrid);
  1815. //
  1816. // Set up the LogFont structure.
  1817. // Make sure it fits in the grid.
  1818. //
  1819. if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_CHINESE)
  1820. {
  1821. LogFont.lfHeight = 16;
  1822. }
  1823. else
  1824. {
  1825. LogFont.lfHeight = psycm->dypBox - 3; // Allow for whitespace.
  1826. }
  1827. //
  1828. // Set these to zero.
  1829. //
  1830. LogFont.lfWidth = LogFont.lfEscapement = LogFont.lfOrientation =
  1831. LogFont.lfWeight = 0;
  1832. LogFont.lfItalic = LogFont.lfUnderline = LogFont.lfStrikeOut =
  1833. LogFont.lfOutPrecision = LogFont.lfClipPrecision =
  1834. LogFont.lfQuality = LogFont.lfPitchAndFamily = 0;
  1835. //
  1836. // Let the facename and size define the font.
  1837. //
  1838. // LogFont.lfCharSet = DEFAULT_CHARSET;
  1839. // Work around the GDI bug that assumes the font's default charset
  1840. // is always the system default locale.
  1841. //
  1842. *(DWORD *)&ItemData = SendDlgItemMessage( hwndDlg,
  1843. ID_FONT,
  1844. CB_GETITEMDATA,
  1845. iCombo,
  1846. 0L );
  1847. LogFont.lfCharSet = ItemData.CharSet;
  1848. //
  1849. // Get the facename from the combo box.
  1850. //
  1851. SendDlgItemMessage( hwndDlg,
  1852. ID_FONT,
  1853. CB_GETLBTEXT,
  1854. iCombo,
  1855. (LONG)(LPTSTR)LogFont.lfFaceName );
  1856. //
  1857. // Enable Block listbox and set defaults appropriately.
  1858. //
  1859. EnableWindow(GetDlgItem(hwndDlg, ID_UNICODESUBSET), TRUE);
  1860. iCurSel = SendDlgItemMessage( hwndDlg,
  1861. ID_UNICODESUBSET,
  1862. CB_GETCURSEL,
  1863. 0,
  1864. 0L );
  1865. UpdateSymbolSelection( hwndDlg,
  1866. aSubsetData[iCurSel].BeginRange,
  1867. aSubsetData[iCurSel].EndRange );
  1868. //
  1869. // Enable Previous button if not on first subset.
  1870. //
  1871. if (iCurSel > 0)
  1872. {
  1873. EnableWindow(GetDlgItem(hwndDlg, ID_PREVSUBSET), TRUE);
  1874. }
  1875. else
  1876. {
  1877. EnableWindow(GetDlgItem(hwndDlg, ID_PREVSUBSET), FALSE);
  1878. }
  1879. //
  1880. // Enable Next button if not on last subset.
  1881. //
  1882. if (iCurSel < (cSubsets - 1))
  1883. {
  1884. EnableWindow(GetDlgItem(hwndDlg, ID_NEXTSUBSET), TRUE);
  1885. }
  1886. else
  1887. {
  1888. EnableWindow(GetDlgItem(hwndDlg, ID_NEXTSUBSET), FALSE);
  1889. }
  1890. //
  1891. // The first sub sel is the ANSI code page.
  1892. //
  1893. psycm->fAnsiFont = (iCurSel == 0);
  1894. //
  1895. // Create the font.
  1896. //
  1897. psycm->hFont = CreateFontIndirect(&LogFont);
  1898. hFont = SelectObject(hdc, psycm->hFont);
  1899. //
  1900. // Create the magnify font.
  1901. //
  1902. LogFont.lfHeight = psycm->dypMag - 5; // Allow for whitespace.
  1903. psycm->hFontMag = CreateFontIndirect(&LogFont);
  1904. //
  1905. // Calculate new values and place in window data structure.
  1906. //
  1907. GetTextMetrics(hdc, &tm);
  1908. psycm->xpCh = 2;
  1909. psycm->ypCh = (4 + psycm->dypBox - tm.tmHeight) / 2;
  1910. lpdxp = (LPINT)psycm->rgdxp;
  1911. if (psycm->fAnsiFont)
  1912. {
  1913. GetCharWidth32A(hdc, chSymFirst, chSymLast, lpdxp);
  1914. }
  1915. else
  1916. {
  1917. GetCharWidth32(hdc, chSymFirst, chSymLast, lpdxp);
  1918. }
  1919. SelectObject(hdc, hFont);
  1920. for (ch = (UINT) chSymFirst; ch <= (UINT) chSymLast; ch++, lpdxp++)
  1921. {
  1922. *lpdxp = (psycm->dxpBox - *lpdxp) / 2 - 1;
  1923. }
  1924. ReleaseDC(hwndCharGrid, hdc);
  1925. psycm->xpMagCurr = 0; // No magnification data
  1926. if (fRedraw)
  1927. {
  1928. InvalidateRect(hwndCharGrid, NULL, TRUE);
  1929. }
  1930. }
  1931. ////////////////////////////////////////////////////////////////////////////
  1932. //
  1933. // DrawSymbolMap
  1934. //
  1935. // Draws all of the pieces of the symbol character map.
  1936. //
  1937. ////////////////////////////////////////////////////////////////////////////
  1938. VOID DrawSymbolMap(
  1939. PSYCM psycm,
  1940. HDC hdc)
  1941. {
  1942. BOOL fFocus;
  1943. DrawSymbolGrid(psycm, hdc);
  1944. DrawSymbolChars(psycm, hdc);
  1945. //
  1946. // We need to force the focus rect to paint if we have the focus
  1947. // since the old focus rect has been drawn over already.
  1948. //
  1949. if (fFocus = psycm->fFocusState)
  1950. {
  1951. psycm->fFocusState = FALSE;
  1952. }
  1953. DrawSymChOutline(psycm, hdc, psycm->chCurr, TRUE, fFocus);
  1954. }
  1955. ////////////////////////////////////////////////////////////////////////////
  1956. //
  1957. // DrawSymbolGrid
  1958. //
  1959. // Draws the symbol character map grid.
  1960. //
  1961. ////////////////////////////////////////////////////////////////////////////
  1962. VOID DrawSymbolGrid(
  1963. PSYCM psycm,
  1964. HDC hdc)
  1965. {
  1966. INT cli; // count of lines
  1967. INT xp, yp;
  1968. INT dxpBox = psycm->dxpBox;
  1969. INT dypBox = psycm->dypBox;
  1970. HPEN hpenOld;
  1971. hpenOld = SelectObject(hdc, CreatePen( PS_SOLID,
  1972. 1,
  1973. GetSysColor(COLOR_WINDOWFRAME) ));
  1974. //
  1975. // Draw horizontal lines.
  1976. //
  1977. xp = psycm->dxpCM + 1;
  1978. yp = 1;
  1979. cli = cchSymCol+1;
  1980. while (cli--)
  1981. {
  1982. MoveToEx(hdc, 1, yp, NULL);
  1983. LineTo(hdc, xp, yp);
  1984. yp += dypBox;
  1985. }
  1986. //
  1987. // Draw vertical lines.
  1988. //
  1989. yp = psycm->dypCM;
  1990. xp = 1;
  1991. cli = cchSymRow+1;
  1992. while (cli--)
  1993. {
  1994. MoveToEx(hdc, xp, 1, NULL);
  1995. LineTo(hdc, xp, yp);
  1996. xp += dxpBox;
  1997. }
  1998. DeleteObject(SelectObject(hdc, hpenOld));
  1999. }
  2000. ////////////////////////////////////////////////////////////////////////////
  2001. //
  2002. // DrawSymbolChars
  2003. //
  2004. // Draws the symbol character map.
  2005. //
  2006. ////////////////////////////////////////////////////////////////////////////
  2007. VOID DrawSymbolChars(
  2008. PSYCM psycm,
  2009. HDC hdc)
  2010. {
  2011. INT dxpBox = psycm->dxpBox;
  2012. INT dypBox = psycm->dypBox;
  2013. INT cch;
  2014. INT x, y;
  2015. INT yp;
  2016. TCHAR ch;
  2017. HFONT hFontOld;
  2018. RECT rect;
  2019. LPRECT lprect = (LPRECT)&rect;
  2020. LPINT lpdxp;
  2021. //
  2022. // Setup the font and colors.
  2023. //
  2024. hFontOld = (HFONT)SelectObject(hdc, psycm->hFont);
  2025. SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  2026. SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  2027. SetBkMode(hdc, OPAQUE);
  2028. //
  2029. // Draw characters.
  2030. //
  2031. cch = 1;
  2032. ch = chSymFirst;
  2033. lpdxp = (LPINT)psycm->rgdxp;
  2034. rect.top = 2;
  2035. yp = psycm->ypCh;
  2036. rect.bottom = rect.top + dypBox - 1;
  2037. for (y = 0; y++ < cchSymCol;)
  2038. {
  2039. rect.left = psycm->xpCh;
  2040. rect.right = rect.left + dxpBox - 1;
  2041. for (x = 0; (x++ < cchSymRow) && (ch <= chSymLast);)
  2042. {
  2043. if (psycm->fAnsiFont)
  2044. {
  2045. ExtTextOutA( hdc,
  2046. rect.left + (*lpdxp++),
  2047. yp,
  2048. ETO_OPAQUE | ETO_CLIPPED,
  2049. lprect,
  2050. &(CHAR)ch,
  2051. 1,
  2052. NULL );
  2053. }
  2054. else
  2055. {
  2056. ExtTextOutW( hdc,
  2057. rect.left + (*lpdxp++),
  2058. yp,
  2059. ETO_OPAQUE | ETO_CLIPPED,
  2060. lprect,
  2061. &ch,
  2062. 1,
  2063. NULL );
  2064. }
  2065. ch++;
  2066. rect.left += dxpBox;
  2067. rect.right += dxpBox;
  2068. }
  2069. yp += dypBox;
  2070. rect.top += dypBox;
  2071. rect.bottom += dypBox;
  2072. }
  2073. SelectObject(hdc, hFontOld);
  2074. }
  2075. ////////////////////////////////////////////////////////////////////////////
  2076. //
  2077. // DrawSymChOutline
  2078. //
  2079. // Draws an outline around the symbol in the character map. If fVisible,
  2080. // then it draws the outline, otherwise it erases it.
  2081. //
  2082. ////////////////////////////////////////////////////////////////////////////
  2083. VOID DrawSymChOutline(
  2084. PSYCM psycm,
  2085. HDC hdc,
  2086. UTCHAR ch,
  2087. BOOL fVisible,
  2088. BOOL fFocus)
  2089. {
  2090. HBRUSH hbrOld;
  2091. RECT rc;
  2092. INT dxpBox = psycm->dxpBox;
  2093. INT dypBox = psycm->dypBox;
  2094. hbrOld = SelectObject( hdc,
  2095. CreateSolidBrush(GetSysColor( fVisible
  2096. ? COLOR_WINDOWFRAME
  2097. : COLOR_WINDOW )) );
  2098. ch -= chSymFirst;
  2099. rc.left = (ch % cchSymRow) * dxpBox + 2;
  2100. rc.right = rc.left + dxpBox - 1;
  2101. rc.top = (ch / cchSymRow) * dypBox + 2;
  2102. rc.bottom = rc.top + dypBox - 1;
  2103. //
  2104. // Draw selection rectangle.
  2105. //
  2106. PatBlt(hdc, rc.left, rc.top - 2, dxpBox - 1, 1, PATCOPY);
  2107. PatBlt(hdc, rc.left, rc.bottom + 1, dxpBox - 1, 1, PATCOPY);
  2108. PatBlt(hdc, rc.left - 2, rc.top, 1, dypBox - 1, PATCOPY);
  2109. PatBlt(hdc, rc.right + 1, rc.top, 1, dypBox - 1, PATCOPY);
  2110. DeleteObject(SelectObject(hdc, GetStockObject(NULL_BRUSH)));
  2111. //
  2112. // Deal with the focus rectangle.
  2113. //
  2114. if (fFocus != psycm->fFocusState)
  2115. {
  2116. DrawFocusRect(hdc, &rc);
  2117. psycm->fFocusState = fFocus;
  2118. }
  2119. SelectObject(hdc, hbrOld);
  2120. }
  2121. ////////////////////////////////////////////////////////////////////////////
  2122. //
  2123. // MoveSymbolSel
  2124. //
  2125. // Changes the current symbol selection. Handles drawing of magnified
  2126. // characters.
  2127. //
  2128. ////////////////////////////////////////////////////////////////////////////
  2129. VOID MoveSymbolSel(
  2130. PSYCM psycm,
  2131. UTCHAR chNew)
  2132. {
  2133. HDC hdc;
  2134. HDC hdcMag = psycm->hdcMag;
  2135. RECT rc;
  2136. HFONT hFontOld;
  2137. HFONT hFontMag; // old font in memory dc
  2138. HPEN hpenOld;
  2139. UTCHAR chNorm = chNew - chSymFirst + 32;
  2140. INT dxpMag = psycm->dxpMag; // for quick reference
  2141. INT dypMag = psycm->dypMag;
  2142. INT ypMemSrc = psycm->ypDest;
  2143. INT ypMemDest = ypMemSrc ^ dypMag;
  2144. INT xpCurr = psycm->xpMagCurr;
  2145. INT ypCurr = psycm->ypMagCurr;
  2146. INT xpNew = psycm->xpCM + (psycm->dxpBox * (chNorm % cchSymRow));
  2147. INT ypNew = psycm->ypCM + (psycm->dypBox * ((chNorm / cchSymRow) - 1));
  2148. INT dxpCh; // width of extra character space (used to center char in box)
  2149. INT dypCh;
  2150. SIZE sz;
  2151. DOUTL("MoveSymbolSel: In\n");
  2152. if (((chNew == (UTCHAR)psycm->chCurr) && FMagData(psycm)))
  2153. {
  2154. DOUTL("MoveSymbolSel: ch == cur && fMag... exiting\n");
  2155. return;
  2156. }
  2157. //
  2158. // Don't draw a magnified character if the char grid has an update
  2159. // region or is not visible.
  2160. //
  2161. if (!IsWindowVisible(hwndCharGrid) ||
  2162. GetUpdateRect(hwndCharGrid, &rc, FALSE))
  2163. {
  2164. DOUTL("MoveSymbolSel: not vis or upd rect... exiting\n");
  2165. return;
  2166. }
  2167. hdc = GetDC(hwndDialog);
  2168. //
  2169. // Setup the magnified font character.
  2170. //
  2171. hFontMag = SelectObject(hdcMag, psycm->hFontMag);
  2172. if (psycm->fAnsiFont)
  2173. {
  2174. char chANSINew = (char)chNew;
  2175. GetTextExtentPointA(hdcMag, &chANSINew, 1, &sz);
  2176. }
  2177. else
  2178. {
  2179. GetTextExtentPointW(hdcMag, &chNew, 1, &sz);
  2180. }
  2181. if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_CHINESE)
  2182. {
  2183. dxpCh = (dxpMag - (INT)sz.cx) / 2 - 2;
  2184. dypCh = (dypMag - (INT)sz.cy) / 2 - 2;
  2185. }
  2186. else
  2187. {
  2188. dxpCh = (dxpMag - (INT)sz.cx) / 2 - 1;
  2189. dypCh = (dypMag - (INT)sz.cy) / 2 - 1;
  2190. }
  2191. hpenOld = SelectObject(hdc, CreatePen( PS_SOLID,
  2192. 1,
  2193. GetSysColor(COLOR_WINDOWFRAME) ));
  2194. hFontOld = SelectObject(hdc, psycm->hFontMag);
  2195. //
  2196. // Copy screen data to offscreen bitmap.
  2197. //
  2198. BitBlt(hdcMag, 0, ypMemDest, dxpMag, dypMag, hdc, xpNew, ypNew, SRCCOPY);
  2199. //
  2200. // Setup DC.
  2201. //
  2202. SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  2203. SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  2204. SetBkMode(hdc, OPAQUE);
  2205. if (FMagData(psycm))
  2206. {
  2207. INT xpT = xpNew - xpCurr; // point of overlap in offscreen data
  2208. INT ypT = ypNew - ypCurr;
  2209. INT dxpT = dxpMag - abs(xpT); // size of overlap
  2210. INT dypT = dypMag - abs(ypT);
  2211. DOUTL("MoveSymbolSel: FMagData\n");
  2212. if ((dxpT > 0) && (dypT > 0))
  2213. {
  2214. INT xpTmax, ypTmax; // max(0, xpT);
  2215. INT xpTmin, ypTmin; // min(0, xpT);
  2216. INT xpTnmin, ypTnmin; // min(0, -xpT);
  2217. DOUTL("MoveSymbolSel: dxpT > 0 && dypT > 0\n");
  2218. if (xpT < 0)
  2219. {
  2220. xpTnmin = - (xpTmin = xpT);
  2221. xpTmax = 0;
  2222. }
  2223. else
  2224. {
  2225. xpTmax = xpT;
  2226. xpTnmin = xpTmin = 0;
  2227. }
  2228. if (ypT < 0)
  2229. {
  2230. ypTnmin = - (ypTmin = ypT);
  2231. ypTmax = 0;
  2232. }
  2233. else
  2234. {
  2235. ypTmax = ypT;
  2236. ypTnmin = ypTmin = 0;
  2237. }
  2238. rc.left = xpTmax;
  2239. rc.right = xpTmin + dxpMag;
  2240. rc.top = ypTmax + ypMemSrc;
  2241. rc.bottom= ypTmin + dypMag + ypMemSrc;
  2242. //
  2243. // Copy overlapping offscreen data.
  2244. //
  2245. BitBlt( hdcMag,
  2246. xpTnmin,
  2247. ypTnmin + ypMemDest,
  2248. dxpT,
  2249. dypT,
  2250. hdcMag,
  2251. xpTmax,
  2252. ypTmax + ypMemSrc,
  2253. SRCCOPY );
  2254. //
  2255. // Print part of char over old screen data.
  2256. //
  2257. if (psycm->fAnsiFont)
  2258. {
  2259. ExtTextOutA( hdcMag,
  2260. xpT + dxpCh,
  2261. ypT + dypCh + ypMemSrc,
  2262. ETO_OPAQUE | ETO_CLIPPED,
  2263. (LPRECT)&rc,
  2264. &(CHAR)chNew,
  2265. 1,
  2266. NULL );
  2267. }
  2268. else
  2269. {
  2270. ExtTextOutW( hdcMag,
  2271. xpT + dxpCh,
  2272. ypT + dypCh + ypMemSrc,
  2273. ETO_OPAQUE | ETO_CLIPPED,
  2274. (LPRECT)&rc,
  2275. &chNew,
  2276. 1,
  2277. NULL );
  2278. }
  2279. }
  2280. //
  2281. // Restore old screen data.
  2282. //
  2283. BitBlt(hdc, xpCurr, ypCurr, dxpMag, dypMag, hdcMag, 0, ypMemSrc, SRCCOPY);
  2284. }
  2285. rc.right = (psycm->xpMagCurr = rc.left = xpNew) + dxpMag - 2;
  2286. rc.bottom = (psycm->ypMagCurr = rc.top = ypNew) + dypMag - 2;
  2287. //
  2288. // The rectangle.
  2289. //
  2290. MoveToEx(hdc, rc.left, rc.top, NULL);
  2291. LineTo(hdc, rc.left, rc.bottom - 1);
  2292. LineTo(hdc, rc.right - 1, rc.bottom - 1);
  2293. LineTo(hdc, rc.right - 1, rc.top);
  2294. LineTo(hdc, rc.left, rc.top);
  2295. //
  2296. // The shadow.
  2297. //
  2298. MoveToEx(hdc, rc.right, rc.top + 1, NULL);
  2299. LineTo(hdc, rc.right, rc.bottom);
  2300. LineTo(hdc, rc.left, rc.bottom);
  2301. MoveToEx(hdc, rc.right + 1, rc.top + 2, NULL);
  2302. LineTo(hdc, rc.right + 1, rc.bottom + 1);
  2303. LineTo(hdc, rc.left + 1, rc.bottom + 1);
  2304. rc.left++;
  2305. rc.top++;
  2306. rc.right--;
  2307. rc.bottom--;
  2308. //
  2309. // Draw magnified character on screen.
  2310. //
  2311. if (psycm->fAnsiFont)
  2312. {
  2313. ExtTextOutA( hdc,
  2314. xpNew + dxpCh,
  2315. ypNew + dypCh,
  2316. ETO_OPAQUE | ETO_CLIPPED,
  2317. (LPRECT)&rc,
  2318. &(CHAR)chNew,
  2319. 1,
  2320. NULL );
  2321. }
  2322. else
  2323. {
  2324. ExtTextOutW( hdc,
  2325. xpNew + dxpCh,
  2326. ypNew + dypCh,
  2327. ETO_OPAQUE | ETO_CLIPPED,
  2328. (LPRECT)&rc,
  2329. &chNew,
  2330. 1,
  2331. NULL );
  2332. }
  2333. psycm->ypDest = ypMemDest;
  2334. DeleteObject(SelectObject(hdc, hpenOld));
  2335. SelectObject(hdc, hFontOld);
  2336. SelectObject(hdcMag, hFontMag);
  2337. UpdateKeystrokeText(hdc, psycm->fAnsiFont, chNew, TRUE);
  2338. ReleaseDC(hwndDialog, hdc);
  2339. psycm->chCurr = chNew;
  2340. DOUTL("MoveSymbolSel: Leaving\n");
  2341. }
  2342. ////////////////////////////////////////////////////////////////////////////
  2343. //
  2344. // RestoreSymMag
  2345. //
  2346. // Restores the screen data under the magnifier.
  2347. //
  2348. ////////////////////////////////////////////////////////////////////////////
  2349. VOID RestoreSymMag(
  2350. PSYCM psycm)
  2351. {
  2352. if (FMagData(psycm))
  2353. {
  2354. HDC hdc = GetDC(hwndDialog);
  2355. BitBlt( hdc,
  2356. psycm->xpMagCurr,
  2357. psycm->ypMagCurr,
  2358. psycm->dxpMag,
  2359. psycm->dypMag,
  2360. psycm->hdcMag,
  2361. 0,
  2362. psycm->ypDest,
  2363. SRCCOPY );
  2364. ReleaseDC(hwndDialog, hdc);
  2365. psycm->xpMagCurr = 0; // flag - no data offscreen (see FMagData)
  2366. }
  2367. }
  2368. ////////////////////////////////////////////////////////////////////////////
  2369. //
  2370. // FontLoadProc
  2371. //
  2372. // Used by EnumFonts to load our combo box with all the fonts installed
  2373. // in the system.
  2374. //
  2375. ////////////////////////////////////////////////////////////////////////////
  2376. INT APIENTRY FontLoadProc(
  2377. LPLOGFONT lpLogFont,
  2378. NEWTEXTMETRICEX* lpTextMetric,
  2379. DWORD nFontType,
  2380. LPARAM lpData)
  2381. {
  2382. INT iPos;
  2383. TCHAR szFace[LF_FACESIZE];
  2384. //
  2385. // Check for duplicates.
  2386. //
  2387. iPos = (INT)SendDlgItemMessage( (HWND)lpData,
  2388. ID_FONT,
  2389. CB_FINDSTRING,
  2390. (WPARAM)-1,
  2391. (DWORD)&lpLogFont->lfFaceName );
  2392. if (iPos == CB_ERR)
  2393. {
  2394. NotInListYet:
  2395. //
  2396. // Doesn't exist, insert the facename into the combo box.
  2397. //
  2398. iPos = (INT)SendDlgItemMessage( (HWND)lpData,
  2399. ID_FONT,
  2400. CB_ADDSTRING,
  2401. 0,
  2402. (DWORD)&lpLogFont->lfFaceName );
  2403. }
  2404. else
  2405. {
  2406. //
  2407. // Make sure it is not just a substring (want a full match).
  2408. //
  2409. SendDlgItemMessage( (HWND)lpData,
  2410. ID_FONT,
  2411. CB_GETLBTEXT,
  2412. iPos,
  2413. (LONG)(LPTSTR)szFace );
  2414. if (lstrcmpi(szFace, lpLogFont->lfFaceName))
  2415. {
  2416. goto NotInListYet;
  2417. }
  2418. //
  2419. // Already exists, blow out now if this is not a true type font.
  2420. //
  2421. if (!(nFontType & TRUETYPE_FONTTYPE))
  2422. {
  2423. return (1);
  2424. }
  2425. }
  2426. //
  2427. // Store the pertinant font information in the combo item data.
  2428. //
  2429. if ((iPos != CB_ERR) && (iPos != CB_ERRSPACE))
  2430. {
  2431. ITEMDATA ItemData;
  2432. DWORD ntmFlags = lpTextMetric->ntmTm.ntmFlags;
  2433. SHORT sFontType = 0;
  2434. if (ntmFlags & NTM_PS_OPENTYPE)
  2435. {
  2436. sFontType = PS_OPENTYPE_FONT;
  2437. }
  2438. else if (ntmFlags & NTM_TYPE1)
  2439. {
  2440. sFontType = TYPE1_FONT;
  2441. }
  2442. else if (nFontType & TRUETYPE_FONTTYPE)
  2443. {
  2444. if (ntmFlags & NTM_TT_OPENTYPE)
  2445. sFontType = TT_OPENTYPE_FONT;
  2446. else
  2447. sFontType = TRUETYPE_FONT;
  2448. }
  2449. ItemData.FontType = sFontType;
  2450. ItemData.CharSet = lpLogFont->lfCharSet;
  2451. ItemData.PitchAndFamily = lpLogFont->lfPitchAndFamily;
  2452. SendDlgItemMessage( (HWND)lpData,
  2453. ID_FONT,
  2454. CB_SETITEMDATA,
  2455. iPos,
  2456. *(DWORD *)&ItemData );
  2457. }
  2458. //
  2459. // Continue enumeration.
  2460. //
  2461. return (1);
  2462. }
  2463. ////////////////////////////////////////////////////////////////////////////
  2464. //
  2465. // GetEditText
  2466. //
  2467. // Returns HANDLE containing the text in the edit control.
  2468. //
  2469. // NOTE: Caller is responsible for freeing this handle!
  2470. //
  2471. ////////////////////////////////////////////////////////////////////////////
  2472. HANDLE GetEditText(
  2473. HWND hwndDlg)
  2474. {
  2475. INT cchText;
  2476. HWND hwndEditCtl;
  2477. HANDLE hmem;
  2478. LPTSTR lpstrText;
  2479. DWORD dwSel;
  2480. hwndEditCtl = GetDlgItem(hwndDlg, ID_STRING);
  2481. cchText = GetWindowTextLength(hwndEditCtl);
  2482. hmem = GlobalAlloc(0, CTOB((cchText + 1)));
  2483. lpstrText = (LPTSTR)GlobalLock(hmem);
  2484. cchText = GetWindowText(hwndEditCtl, lpstrText, cchText+1);
  2485. dwSel = SendMessage(hwndEditCtl, EM_GETSEL, 0, 0L);
  2486. if (LOWORD(dwSel) != HIWORD(dwSel))
  2487. {
  2488. //
  2489. // If there is a selection, then only get the selected text.
  2490. //
  2491. *(lpstrText + HIWORD(dwSel)) = TEXT('\0');
  2492. lstrcpy(lpstrText, lpstrText + LOWORD(dwSel));
  2493. }
  2494. GlobalUnlock(hmem);
  2495. if (cchText == 0)
  2496. {
  2497. hmem = GlobalFree(hmem);
  2498. }
  2499. return (hmem);
  2500. }
  2501. ////////////////////////////////////////////////////////////////////////////
  2502. //
  2503. // CopyString
  2504. //
  2505. // Implements the copy function.
  2506. //
  2507. ////////////////////////////////////////////////////////////////////////////
  2508. VOID CopyString(
  2509. HWND hwndDlg)
  2510. {
  2511. HANDLE hmem;
  2512. LPTSTR lpstrText;
  2513. if (hmem = GetEditText(hwndDlg))
  2514. {
  2515. lpstrText = (LPTSTR)GlobalLock(hmem);
  2516. //
  2517. // Copying string to clipboard.
  2518. //
  2519. if (OpenClipboard(hwndDlg))
  2520. {
  2521. EmptyClipboard();
  2522. SendRTFToClip(hwndDlg, lpstrText);
  2523. #ifdef UNICODE
  2524. SetClipboardData(CF_UNICODETEXT, hmem);
  2525. #else
  2526. SetClipboardData(CF_TEXT, hmem);
  2527. #endif
  2528. CloseClipboard();
  2529. }
  2530. else
  2531. {
  2532. //
  2533. // If we couldn't open the clipboard, then we need to free memory.
  2534. //
  2535. GlobalUnlock(hmem);
  2536. GlobalFree(hmem);
  2537. }
  2538. }
  2539. }
  2540. ////////////////////////////////////////////////////////////////////////////
  2541. //
  2542. // SendRTFToClip
  2543. //
  2544. // Puts the string in the clipboard using Rich Text Format. This assumes
  2545. // that the clipboard has already been opened.
  2546. //
  2547. ////////////////////////////////////////////////////////////////////////////
  2548. VOID SendRTFToClip(
  2549. HWND hwndDlg,
  2550. LPTSTR lpstrText)
  2551. {
  2552. INT iCurrFont;
  2553. ITEMDATA ItemData;
  2554. TCHAR szFaceName[LF_FACESIZE];
  2555. HANDLE hmemRTF, hmemClip;
  2556. LPTSTR lpstrClipString;
  2557. TCHAR achHeaderTmpl[] = TEXT("{\\rtf1\\ansi\\ansicpg%d {\\fonttbl{\\f0\\");
  2558. TCHAR achHeader[sizeof(achHeaderTmpl) / sizeof(TCHAR) + 20];
  2559. TCHAR achMiddle[] = TEXT(";}}\\sectd\\pard\\plain\\f0 ");
  2560. INT cchUC;
  2561. #ifndef UNICODE_RTF
  2562. LPWSTR pszRTFW;
  2563. #endif
  2564. #define MAXLENGTHFONTFAMILY 8
  2565. #define ALITTLEEXTRA 10 // covers extra characters + length of font size
  2566. iCurrFont = (INT)SendDlgItemMessage(hwndDlg, ID_FONT, CB_GETCURSEL, 0, 0L);
  2567. //
  2568. // Get the item data - contains fonttype, charset, and pitchandfamily.
  2569. //
  2570. *(DWORD *)&ItemData = SendDlgItemMessage( hwndDlg,
  2571. ID_FONT,
  2572. CB_GETITEMDATA,
  2573. iCurrFont,
  2574. 0L );
  2575. //
  2576. // Get the facename from the combo box.
  2577. //
  2578. SendDlgItemMessage( hwndDlg,
  2579. ID_FONT,
  2580. CB_GETLBTEXT,
  2581. iCurrFont,
  2582. (LPARAM)(LPTSTR)szFaceName );
  2583. wsprintf(achHeader, achHeaderTmpl, (INT)(SHORT)GetACP());
  2584. //
  2585. // 16 times in case they're all > 7 bits (each chr -> \uc1\uddddddd\'xx)
  2586. // and room for the second byte of DBCS.
  2587. //
  2588. hmemRTF = GlobalAlloc( 0,
  2589. CTOB(lstrlen((LPTSTR)achHeader) +
  2590. MAXLENGTHFONTFAMILY +
  2591. lstrlen(szFaceName) +
  2592. lstrlen((LPTSTR)achMiddle) +
  2593. 2 * 16 * lstrlen(lpstrText) +
  2594. ALITTLEEXTRA) );
  2595. if (hmemRTF == NULL)
  2596. {
  2597. return;
  2598. }
  2599. //
  2600. // Allocate memory for local storage of clipboard string for owner draw.
  2601. //
  2602. if (hmemClip = GlobalAlloc(0, CTOB(lstrlen(lpstrText) + 1)))
  2603. {
  2604. //
  2605. // Get rid of old ones.
  2606. //
  2607. if (hstrClipboard)
  2608. {
  2609. GlobalFree(hstrClipboard);
  2610. }
  2611. if (fDelClipboardFont)
  2612. {
  2613. fDelClipboardFont = FALSE;
  2614. DeleteObject(hFontClipboard);
  2615. }
  2616. //
  2617. // Save this stuff away for owner drawing in a clipboard viewer.
  2618. //
  2619. hFontClipboard = sycm.hFont;
  2620. hstrClipboard = hmemClip;
  2621. lstrcpy(GlobalLock(hstrClipboard), lpstrText);
  2622. GlobalUnlock(hstrClipboard);
  2623. }
  2624. else
  2625. {
  2626. GlobalFree(hmemRTF);
  2627. return;
  2628. }
  2629. lpstrClipString = GlobalLock(hmemRTF);
  2630. #ifndef UNICODE_RTF
  2631. pszRTFW = lpstrClipString;
  2632. #endif
  2633. lstrcpy(lpstrClipString, achHeader);
  2634. if (ItemData.CharSet == SYMBOL_CHARSET)
  2635. {
  2636. lstrcat(lpstrClipString, (LPTSTR)TEXT("ftech "));
  2637. }
  2638. else
  2639. {
  2640. //
  2641. // Top four bits specify family.
  2642. //
  2643. switch (ItemData.PitchAndFamily & 0xf0)
  2644. {
  2645. case ( FF_DECORATIVE ) :
  2646. {
  2647. lstrcat(lpstrClipString, (LPTSTR)TEXT("fdecor "));
  2648. break;
  2649. }
  2650. case ( FF_MODERN ) :
  2651. {
  2652. lstrcat(lpstrClipString, (LPTSTR)TEXT("fmodern "));
  2653. break;
  2654. }
  2655. case ( FF_ROMAN ) :
  2656. {
  2657. lstrcat(lpstrClipString, (LPTSTR)TEXT("froman "));
  2658. break;
  2659. }
  2660. case ( FF_SCRIPT ) :
  2661. {
  2662. lstrcat(lpstrClipString, (LPTSTR)TEXT("fscript "));
  2663. break;
  2664. }
  2665. case ( FF_SWISS ) :
  2666. {
  2667. lstrcat(lpstrClipString, (LPTSTR)TEXT("fswiss "));
  2668. break;
  2669. }
  2670. default :
  2671. {
  2672. break;
  2673. }
  2674. }
  2675. }
  2676. lstrcat(lpstrClipString, szFaceName);
  2677. lstrcat(lpstrClipString, (LPTSTR)achMiddle);
  2678. //
  2679. // We need to do the text character by character, making sure
  2680. // that we output a special sequence \'hh for characters bigger
  2681. // than 7 bits long!
  2682. //
  2683. lpstrClipString = (LPTSTR)(lpstrClipString + lstrlen(lpstrClipString));
  2684. cchUC = 0;
  2685. while (*lpstrText)
  2686. {
  2687. if ((UTCHAR)*lpstrText < 128)
  2688. {
  2689. if (*lpstrText == TEXT('\\') ||
  2690. *lpstrText == TEXT('{') ||
  2691. *lpstrText == TEXT('}'))
  2692. {
  2693. //
  2694. // Need to preface these symbols with a '\' since they are
  2695. // special control characters for RTF.
  2696. //
  2697. *lpstrClipString++ = TEXT('\\');
  2698. }
  2699. *lpstrClipString++ = *lpstrText++;
  2700. }
  2701. else
  2702. {
  2703. unsigned char achTmp[2];
  2704. unsigned char *pTmp = achTmp;
  2705. int cch;
  2706. cch = WideCharToMultiByte( CP_ACP,
  2707. 0,
  2708. lpstrText,
  2709. 1,
  2710. pTmp,
  2711. 2,
  2712. NULL,
  2713. NULL );
  2714. //
  2715. // Put in a \uc# to tell Unicode reader how many bytes to skip
  2716. // and the \uN code to indicate the real unicode value.
  2717. //
  2718. if (cch != cchUC )
  2719. {
  2720. cchUC = cch;
  2721. lpstrClipString += wsprintf( lpstrClipString,
  2722. TEXT("\\uc%d"),
  2723. (INT)(SHORT)cchUC );
  2724. }
  2725. lpstrClipString += wsprintf( lpstrClipString,
  2726. TEXT("\\u%d"),
  2727. (INT)(SHORT)*lpstrText );
  2728. //
  2729. // Now put the \'xx string in to indicate the actual character.
  2730. //
  2731. lpstrText++;
  2732. while (cch--)
  2733. {
  2734. *lpstrClipString++ = TEXT('\\');
  2735. *lpstrClipString++ = TEXT('\'');
  2736. wsprintf(achMiddle, TEXT("%x"), (INT)*pTmp++);
  2737. *lpstrClipString++ = achMiddle[0];
  2738. *lpstrClipString++ = achMiddle[1];
  2739. }
  2740. }
  2741. }
  2742. *lpstrClipString++ = TEXT('}');
  2743. *lpstrClipString++ = TEXT('\0');
  2744. if (!wCFRichText)
  2745. {
  2746. TCHAR szRTF[80];
  2747. LoadString(hInst, IDS_RTF, szRTF, BTOC(sizeof(szRTF)) - 1);
  2748. wCFRichText = RegisterClipboardFormat(szRTF);
  2749. }
  2750. #ifndef UNICODE_RTF
  2751. {
  2752. //
  2753. // RTF is only defined for ANSI, not for Unicode, therefore
  2754. // we need to convert the buffer before we put it on the
  2755. // clipboard. Eventually, we should add autoconversion code
  2756. // to USER to handle this for us.
  2757. //
  2758. int cch;
  2759. HANDLE hmemRTFA;
  2760. LPSTR pszRTFA;
  2761. cch = WideCharToMultiByte( CP_ACP,
  2762. 0,
  2763. pszRTFW,
  2764. lpstrClipString - pszRTFW,
  2765. NULL,
  2766. 0,
  2767. NULL,
  2768. NULL );
  2769. if (cch != 0 &&
  2770. (hmemRTFA = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,cch)) != NULL)
  2771. {
  2772. pszRTFA = GlobalLock(hmemRTFA);
  2773. WideCharToMultiByte( CP_ACP,
  2774. 0,
  2775. pszRTFW,
  2776. lpstrClipString - pszRTFW,
  2777. pszRTFA,
  2778. cch,
  2779. NULL,
  2780. NULL );
  2781. GlobalUnlock(hmemRTFA);
  2782. GlobalUnlock(hmemRTF);
  2783. GlobalFree(hmemRTF);
  2784. hmemRTF = hmemRTFA;
  2785. }
  2786. }
  2787. #endif
  2788. //
  2789. // Put RTF and OwnerDisplay formats in the clipboard.
  2790. //
  2791. SetClipboardData(wCFRichText, hmemRTF);
  2792. SetClipboardData(CF_OWNERDISPLAY, NULL);
  2793. }
  2794. ////////////////////////////////////////////////////////////////////////////
  2795. //
  2796. // PointsToHeight
  2797. //
  2798. // Calculates the height in pixels of the specified point size for the
  2799. // current display.
  2800. //
  2801. ////////////////////////////////////////////////////////////////////////////
  2802. INT PointsToHeight(
  2803. INT iPoints)
  2804. {
  2805. HDC hdc;
  2806. INT iHeight;
  2807. hdc = GetDC(HWND_DESKTOP);
  2808. iHeight = MulDiv(iPoints, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  2809. ReleaseDC(HWND_DESKTOP, hdc);
  2810. return (iHeight);
  2811. }
  2812. ////////////////////////////////////////////////////////////////////////////
  2813. //
  2814. // UpdateKeystrokeText
  2815. //
  2816. // Calculates and updates the text string displayed in the Keystroke
  2817. // field of the status bar. It repaints the status field if fRedraw is
  2818. // TRUE.
  2819. //
  2820. ////////////////////////////////////////////////////////////////////////////
  2821. VOID UpdateKeystrokeText(
  2822. HDC hdc,
  2823. BOOL fANSI,
  2824. UTCHAR chNew,
  2825. BOOL fRedraw)
  2826. {
  2827. TCHAR szUnshifted[CCH_KEYNAME];
  2828. INT vkRes;
  2829. LONG lParam;
  2830. if (!fANSI)
  2831. {
  2832. lstrcpy(szKeystrokeText, szUnicodeLabel);
  2833. wsprintf( (LPTSTR)(szKeystrokeText + iUnicodeLabelStart),
  2834. TEXT("%04x"),
  2835. chNew );
  2836. }
  2837. else
  2838. {
  2839. lstrcpy(szKeystrokeText, szKeystrokeLabel);
  2840. vkRes = VkKeyScan(chNew);
  2841. //
  2842. // Map the virtual key code into an unshifted character value.
  2843. //
  2844. lParam = MapVirtualKey(LOBYTE(vkRes), 0) << 16;
  2845. GetKeyNameText(lParam, szUnshifted, CCH_KEYNAME - 1);
  2846. switch (HIBYTE(vkRes))
  2847. {
  2848. case ( 0 ) : // unshifted char
  2849. case ( 1 ) : // character is shifted, just display the shifted char
  2850. {
  2851. if (chNew != TEXT(' '))
  2852. {
  2853. szKeystrokeText[iKeystrokeTextStart] = chNew;
  2854. szKeystrokeText[iKeystrokeTextStart + 1] = TEXT('\0');
  2855. }
  2856. else
  2857. {
  2858. lstrcat(szKeystrokeText, szUnshifted);
  2859. }
  2860. break;
  2861. }
  2862. case ( 2 ) : // character is control character
  2863. {
  2864. lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szCtrl);
  2865. lstrcat(szKeystrokeText, (LPTSTR)szUnshifted);
  2866. break;
  2867. }
  2868. case ( 6 ) : // character is CONTROL+ALT
  2869. {
  2870. lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szCtrlAlt);
  2871. lstrcat(szKeystrokeText, (LPTSTR)szUnshifted);
  2872. break;
  2873. }
  2874. case ( 7 ) : // character is SHIFT+CONTROL+ALT
  2875. {
  2876. lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szShiftCtrlAlt);
  2877. lstrcat(szKeystrokeText, (LPTSTR)szUnshifted);
  2878. break;
  2879. }
  2880. default : // Character created via Alt + Numpad
  2881. {
  2882. lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szAlt);
  2883. wsprintf( (LPTSTR)(szKeystrokeText + lstrlen(szKeystrokeText)),
  2884. TEXT("%d"),
  2885. chNew );
  2886. break;
  2887. }
  2888. }
  2889. }
  2890. if (fRedraw)
  2891. {
  2892. PaintStatusLine(hdc, FALSE, TRUE);
  2893. }
  2894. }
  2895. ////////////////////////////////////////////////////////////////////////////
  2896. //
  2897. // UpdateHelpText
  2898. //
  2899. // Calculates if the Help string needs to be updated, and does so if
  2900. // necessary.
  2901. //
  2902. // If hwndCtrl is not NULL, then it specifies the window handle of the
  2903. // control gaining focus, and lpmsg is ignored.
  2904. //
  2905. // If hwndCtrl is NULL, then lpmsg must point to a valid message structure.
  2906. // If it is a tab character, then we calculate what the next control is
  2907. // that will receive the focus.
  2908. //
  2909. ////////////////////////////////////////////////////////////////////////////
  2910. BOOL UpdateHelpText(
  2911. LPMSG lpmsg,
  2912. HWND hwndCtrl)
  2913. {
  2914. HDC hdc;
  2915. BOOL fPaintStatus = FALSE;
  2916. BOOL fRet = TRUE;
  2917. DPRINT((szDbgBuf, TEXT("UpdHlpTxt: lpmsg:0x%08lX, hwnd:0x%08lX\n"), (DWORD)lpmsg, (DWORD)hwndCtrl));
  2918. if (hwndCtrl != NULL)
  2919. {
  2920. fPaintStatus = TRUE;
  2921. iControl = GetDlgCtrlID(hwndCtrl);
  2922. }
  2923. else if (lpmsg->message == WM_KEYDOWN)
  2924. {
  2925. if (lpmsg->wParam == VK_TAB)
  2926. {
  2927. fPaintStatus = TRUE;
  2928. hwndCtrl = GetNextDlgTabItem( hwndDialog,
  2929. GetDlgItem(hwndDialog, iControl),
  2930. (BOOL)(GetKeyState(VK_SHIFT) & 0x8000) );
  2931. iControl = GetDlgCtrlID(hwndCtrl);
  2932. if (iControl == ID_STRING)
  2933. {
  2934. //
  2935. // Do this ourselves, otherwise default action will select
  2936. // the whole edit control.
  2937. //
  2938. SetFocus(hwndCtrl);
  2939. fRet = FALSE;
  2940. }
  2941. if (iControl == ID_CHARGRID)
  2942. {
  2943. //
  2944. // Set the default button back to "Select". The default
  2945. // might have changed to the "Next" or "Previous" button.
  2946. //
  2947. SendMessage(hwndDialog, DM_SETDEFID, ID_SELECT, 0);
  2948. }
  2949. }
  2950. else if (lpmsg->wParam == VK_F1)
  2951. {
  2952. PostMessage(hwndDialog, WM_COMMAND, ID_HELP, 0L);
  2953. }
  2954. }
  2955. if (fPaintStatus)
  2956. {
  2957. hdc = GetDC(hwndDialog);
  2958. PaintStatusLine(hdc, TRUE, FALSE);
  2959. ReleaseDC(hwndDialog, hdc);
  2960. }
  2961. return (fRet);
  2962. }
  2963. ////////////////////////////////////////////////////////////////////////////
  2964. //
  2965. // SubSetChanged
  2966. //
  2967. // Sets the ANSI bit if appropriate and then calls UpdateSymbolSelection
  2968. // and then repaints the window.
  2969. //
  2970. // Repaints Keystroke field if HWND != NULL.
  2971. // Sets sycm->fAnsiFont if 'Windows Chars' is the subset.
  2972. // Redraws the char grid.
  2973. //
  2974. ////////////////////////////////////////////////////////////////////////////
  2975. VOID SubSetChanged(
  2976. HWND hwnd,
  2977. INT iSubSet,
  2978. INT ichFirst,
  2979. INT ichLast)
  2980. {
  2981. HDC hdc;
  2982. BOOL fANSI = (iSubSet == 0);
  2983. if (fANSI != sycm.fAnsiFont)
  2984. {
  2985. sycm.fAnsiFont = fANSI;
  2986. }
  2987. UpdateSymbolSelection(hwnd, ichFirst, ichLast);
  2988. if ((hwnd != NULL) && ((hdc = GetDC(hwnd)) != NULL))
  2989. {
  2990. LPINT lpdxp;
  2991. HFONT hFont;
  2992. UINT ch;
  2993. hFont = SelectObject(hdc, sycm.hFont);
  2994. lpdxp = (LPINT)sycm.rgdxp;
  2995. if (iSubSet == 0)
  2996. {
  2997. GetCharWidth32A(hdc, chSymFirst, chSymLast, lpdxp);
  2998. }
  2999. else
  3000. {
  3001. GetCharWidth32(hdc, chSymFirst, chSymLast, lpdxp);
  3002. }
  3003. SelectObject(hdc, hFont);
  3004. for (ch = (UINT) chSymFirst; ch <= (UINT) chSymLast; ch++, lpdxp++)
  3005. {
  3006. *lpdxp = (sycm.dxpBox - *lpdxp) / 2 - 1;
  3007. }
  3008. ReleaseDC(hwnd, hdc);
  3009. }
  3010. InvalidateRect(hwndCharGrid, NULL, TRUE);
  3011. }
  3012. ////////////////////////////////////////////////////////////////////////////
  3013. //
  3014. // UpdateSymbolSelection
  3015. //
  3016. // Updates the values of the following global values:
  3017. // chRangeFirst
  3018. // chRangeLast
  3019. // Subsets in the Unicode character set have different numbers of
  3020. // characters. We have to do some bounds checking in order to set an
  3021. // appropriate sycm.chCurr value. The "Keystroke" status field is
  3022. // updated.
  3023. //
  3024. // Repaints Keystroke field if HWND != NULL.
  3025. //
  3026. ////////////////////////////////////////////////////////////////////////////
  3027. VOID UpdateSymbolSelection(
  3028. HWND hwnd,
  3029. INT FirstChar,
  3030. INT LastChar)
  3031. {
  3032. int iCmd = SW_HIDE;
  3033. HWND hwndSB;
  3034. UINT chFirst, chLast;
  3035. chRangeFirst = FirstChar;
  3036. chRangeLast = LastChar;
  3037. chFirst = chRangeFirst;
  3038. chLast = chFirst + cchFullMap - 1;
  3039. chLast = min(chLast, chRangeLast);
  3040. hwndSB = GetDlgItem(hwnd, ID_MAPSCROLL);
  3041. if (chLast != chRangeLast)
  3042. {
  3043. int i;
  3044. iCmd = SW_SHOW;
  3045. SetScrollPos(hwndSB, SB_CTL, 0, FALSE);
  3046. i = (chRangeLast - chRangeFirst + 1) - cchFullMap;
  3047. if (i < 0)
  3048. {
  3049. i = 1;
  3050. }
  3051. else
  3052. {
  3053. i = i / cchSymRow;
  3054. }
  3055. SetScrollRange(hwndSB, SB_CTL, 0, i, FALSE);
  3056. InvalidateRect(hwndSB, NULL, FALSE);
  3057. }
  3058. ShowWindow(hwndSB, iCmd);
  3059. UpdateSymbolRange(hwnd, chFirst, chLast);
  3060. }
  3061. ////////////////////////////////////////////////////////////////////////////
  3062. //
  3063. // UpdateSymbolRange
  3064. //
  3065. // Updates the values of the following global values:
  3066. // chSymFirst
  3067. // chSymLast
  3068. // sycm.chCurr
  3069. // Subsets in the Unicode character set have different numbers of
  3070. // characters. We have to do some bounds checking in order to set an
  3071. // appropriate sycm.chCurr value. The "Keystroke" status field is
  3072. // updated.
  3073. //
  3074. // Repaints Keystroke field if HWND != NULL.
  3075. //
  3076. ////////////////////////////////////////////////////////////////////////////
  3077. VOID UpdateSymbolRange(
  3078. HWND hwnd,
  3079. INT FirstChar,
  3080. INT LastChar)
  3081. {
  3082. UTCHAR chSymOffset;
  3083. chSymOffset = sycm.chCurr - chSymFirst;
  3084. chSymFirst = FirstChar;
  3085. chSymLast = LastChar;
  3086. sycm.chCurr = chSymOffset + chSymFirst;
  3087. if (sycm.chCurr > chSymLast)
  3088. {
  3089. sycm.chCurr = chSymFirst;
  3090. }
  3091. if (hwnd != NULL)
  3092. {
  3093. HDC hdc;
  3094. hdc = GetDC(hwnd);
  3095. UpdateKeystrokeText(hdc, sycm.fAnsiFont, sycm.chCurr, TRUE);
  3096. ReleaseDC(hwnd, hdc);
  3097. }
  3098. else
  3099. {
  3100. UpdateKeystrokeText(NULL, sycm.fAnsiFont, sycm.chCurr, FALSE);
  3101. }
  3102. }
  3103. ////////////////////////////////////////////////////////////////////////////
  3104. //
  3105. // PaintStatusLine
  3106. //
  3107. // Paints the Help and Keystroke fields in the status bar.
  3108. //
  3109. // Repaints Help field if fHelp == TRUE.
  3110. // Repaints Keystroke field if fKeystroke == TRUE.
  3111. //
  3112. ////////////////////////////////////////////////////////////////////////////
  3113. VOID PaintStatusLine(
  3114. HDC hdc,
  3115. BOOL fHelp,
  3116. BOOL fKeystroke)
  3117. {
  3118. HFONT hfontOld = NULL;
  3119. RECT rect;
  3120. INT dyBorder;
  3121. TCHAR szHelpText[100];
  3122. dyBorder = GetSystemMetrics(SM_CYBORDER);
  3123. if (hfontStatus)
  3124. {
  3125. hfontOld = SelectObject(hdc, hfontStatus);
  3126. }
  3127. //
  3128. // Set the text and background colors.
  3129. //
  3130. SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
  3131. SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
  3132. if (fHelp)
  3133. {
  3134. //
  3135. // Now the help text, with a gray background.
  3136. //
  3137. rect.top = rcStatusLine.top + 3 * dyBorder;
  3138. rect.bottom = rcStatusLine.bottom - 3 * dyBorder;
  3139. rect.left = 9 * dyBorder;
  3140. rect.right = rect.left + dxHelpField - 2 * dyBorder;
  3141. LoadString(hInst, iControl, szHelpText, BTOC(sizeof(szHelpText)) - 1);
  3142. ExtTextOut( hdc,
  3143. rect.left + dyBorder * 2,
  3144. rect.top,
  3145. ETO_OPAQUE | ETO_CLIPPED,
  3146. &rect,
  3147. szHelpText,
  3148. lstrlen(szHelpText),
  3149. NULL );
  3150. }
  3151. if (fKeystroke)
  3152. {
  3153. //
  3154. // Now the keystroke text, with a gray background.
  3155. //
  3156. rect.top = rcStatusLine.top + 3 * dyBorder;
  3157. rect.bottom = rcStatusLine.bottom - 3 * dyBorder;
  3158. rect.right = rcStatusLine.right - 9 * dyBorder;
  3159. rect.left = rect.right - dxKeystrokeField + 2 * dyBorder;
  3160. ExtTextOut( hdc,
  3161. rect.left + dyBorder * 2,
  3162. rect.top,
  3163. ETO_OPAQUE | ETO_CLIPPED,
  3164. &rect,
  3165. szKeystrokeText,
  3166. lstrlen(szKeystrokeText),
  3167. NULL );
  3168. }
  3169. if (hfontOld)
  3170. {
  3171. SelectObject(hdc, hfontOld);
  3172. }
  3173. }
  3174. ////////////////////////////////////////////////////////////////////////////
  3175. //
  3176. // DrawFamilyComboItem
  3177. //
  3178. // Paints the font facenames and TT bitmap in the font combo box.
  3179. //
  3180. ////////////////////////////////////////////////////////////////////////////
  3181. BOOL DrawFamilyComboItem(
  3182. LPDRAWITEMSTRUCT lpdis)
  3183. {
  3184. HDC hDC, hdcMem;
  3185. DWORD rgbBack, rgbText;
  3186. TCHAR szFace[LF_FACESIZE];
  3187. HBITMAP hOld;
  3188. INT dy;
  3189. SHORT sFontType;
  3190. hDC = lpdis->hDC;
  3191. if (lpdis->itemState & ODS_SELECTED)
  3192. {
  3193. rgbBack = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
  3194. rgbText = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  3195. }
  3196. else
  3197. {
  3198. rgbBack = SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
  3199. rgbText = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  3200. }
  3201. SendMessage( lpdis->hwndItem,
  3202. CB_GETLBTEXT,
  3203. lpdis->itemID,
  3204. (LONG)(LPTSTR)szFace );
  3205. ExtTextOut( hDC,
  3206. lpdis->rcItem.left + DX_BITMAP,
  3207. lpdis->rcItem.top,
  3208. ETO_OPAQUE | ETO_CLIPPED,
  3209. &lpdis->rcItem,
  3210. szFace,
  3211. lstrlen(szFace),
  3212. NULL );
  3213. hdcMem = CreateCompatibleDC(hDC);
  3214. if (hdcMem)
  3215. {
  3216. if (hbmFont)
  3217. {
  3218. hOld = SelectObject(hdcMem, hbmFont);
  3219. sFontType = ((ITEMDATA FAR *)&(lpdis->itemData))->FontType;
  3220. if (sFontType)
  3221. {
  3222. int xSrc;
  3223. dy = ((lpdis->rcItem.bottom - lpdis->rcItem.top) - DY_BITMAP) / 2;
  3224. if (sFontType & TRUETYPE_FONT)
  3225. xSrc = 0;
  3226. else if (sFontType & TT_OPENTYPE_FONT)
  3227. xSrc = 2;
  3228. else if(sFontType & PS_OPENTYPE_FONT)
  3229. xSrc = 3;
  3230. else if (sFontType & TYPE1_FONT)
  3231. xSrc = 4;
  3232. BitBlt( hDC,
  3233. lpdis->rcItem.left,
  3234. lpdis->rcItem.top + dy,
  3235. DX_BITMAP,
  3236. DY_BITMAP,
  3237. hdcMem,
  3238. xSrc * DX_BITMAP,
  3239. lpdis->itemState & ODS_SELECTED ? DY_BITMAP : 0,
  3240. SRCCOPY );
  3241. }
  3242. SelectObject(hdcMem, hOld);
  3243. }
  3244. DeleteDC(hdcMem);
  3245. }
  3246. SetTextColor(hDC, rgbText);
  3247. SetBkColor(hDC, rgbBack);
  3248. return (TRUE);
  3249. }
  3250. ////////////////////////////////////////////////////////////////////////////
  3251. //
  3252. // LoadBitmaps
  3253. //
  3254. // Loads DIB bitmaps and "fixes up" their color tables so that we get the
  3255. // desired result for the device we are on.
  3256. //
  3257. // This routine requires:
  3258. // - the DIB is a 16 color DIB authored with the standard windows colors
  3259. // - bright blue (00 00 FF) is converted to the background color
  3260. // - light grey (C0 C0 C0) is replaced with the button face color
  3261. // - dark grey (80 80 80) is replaced with the button shadow color
  3262. //
  3263. // This means you can't have any of these colors in your bitmap.
  3264. //
  3265. ////////////////////////////////////////////////////////////////////////////
  3266. HBITMAP LoadBitmaps(
  3267. INT id)
  3268. {
  3269. HDC hdc;
  3270. HANDLE h, hRes;
  3271. DWORD *p;
  3272. LPBYTE lpBits;
  3273. LPBITMAPINFOHEADER lpBitmapInfo;
  3274. INT numcolors;
  3275. DWORD rgbSelected, rgbUnselected;
  3276. HBITMAP hbm;
  3277. rgbSelected = GetSysColor(COLOR_HIGHLIGHT);
  3278. //
  3279. // Flip the colors.
  3280. //
  3281. rgbSelected = RGB( GetBValue(rgbSelected),
  3282. GetGValue(rgbSelected),
  3283. GetRValue(rgbSelected) );
  3284. rgbUnselected = GetSysColor(COLOR_WINDOW);
  3285. //
  3286. // Flip the colors.
  3287. //
  3288. rgbUnselected = RGB( GetBValue(rgbUnselected),
  3289. GetGValue(rgbUnselected),
  3290. GetRValue(rgbUnselected) );
  3291. h = FindResource(hInst, MAKEINTRESOURCE(id), RT_BITMAP);
  3292. hRes = LoadResource(hInst, h);
  3293. //
  3294. // Lock the bitmap and get a pointer to the color table.
  3295. //
  3296. lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes);
  3297. if (!lpBitmapInfo)
  3298. {
  3299. return (FALSE);
  3300. }
  3301. p = (DWORD *)((LPSTR)(lpBitmapInfo) + lpBitmapInfo->biSize);
  3302. //
  3303. // Search for the Solid Blue entry and replace it with the current
  3304. // background RGB.
  3305. //
  3306. numcolors = 16;
  3307. while (numcolors-- > 0)
  3308. {
  3309. if (*p == BACKGROUND)
  3310. {
  3311. *p = rgbUnselected;
  3312. }
  3313. else if (*p == BACKGROUNDSEL)
  3314. {
  3315. *p = rgbSelected;
  3316. }
  3317. p++;
  3318. }
  3319. UnlockResource(hRes);
  3320. //
  3321. // Now create the DIB.
  3322. //
  3323. lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes);
  3324. //
  3325. // First skip over the header structure.
  3326. //
  3327. lpBits = (LPBYTE)(lpBitmapInfo + 1);
  3328. //
  3329. // Skip the color table entries, if any.
  3330. //
  3331. lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
  3332. //
  3333. // Create a color bitmap compatible with the display device.
  3334. //
  3335. hdc = GetDC(NULL);
  3336. hbm = CreateDIBitmap( hdc,
  3337. lpBitmapInfo,
  3338. (DWORD)CBM_INIT,
  3339. lpBits,
  3340. (LPBITMAPINFO)lpBitmapInfo,
  3341. DIB_RGB_COLORS );
  3342. ReleaseDC(NULL, hdc);
  3343. GlobalUnlock(hRes);
  3344. FreeResource(hRes);
  3345. return (hbm);
  3346. }
  3347. ////////////////////////////////////////////////////////////////////////////
  3348. //
  3349. // DoHelp
  3350. //
  3351. // Invokes help if fInvokeHelp is true, or dismisses help if fInvokeHelp
  3352. // is FALSE.
  3353. //
  3354. ////////////////////////////////////////////////////////////////////////////
  3355. VOID DoHelp(
  3356. HWND hWnd,
  3357. BOOL fInvokeHelp)
  3358. {
  3359. TCHAR szHelp[80];
  3360. if (LoadString(hInst, IDS_HELP, szHelp, BTOC(sizeof(szHelp)) - 1))
  3361. {
  3362. if (fInvokeHelp)
  3363. {
  3364. // APPCOMPAT: an error in HtmlHelp prevents the unicode version from working
  3365. // This is a HACK to get around the problem. Remove this hack when the problem is fixed.
  3366. HtmlHelpA(GetDesktopWindow(), "charmap.chm", HH_DISPLAY_TOPIC, 0L);
  3367. }
  3368. }
  3369. }
  3370. ////////////////////////////////////////////////////////////////////////////
  3371. //
  3372. // SaveFont
  3373. //
  3374. // Saves the current font facename in win.ini, so that it can be selected
  3375. // the next time charmap comes up.
  3376. //
  3377. ////////////////////////////////////////////////////////////////////////////
  3378. VOID SaveCurrentFont(
  3379. HWND hWndDlg)
  3380. {
  3381. TCHAR szFaceName[LF_FACESIZE] = TEXT("");
  3382. SendDlgItemMessage( hWndDlg,
  3383. ID_FONT,
  3384. CB_GETLBTEXT,
  3385. (WORD)SendDlgItemMessage( hWndDlg,
  3386. ID_FONT,
  3387. CB_GETCURSEL,
  3388. 0,
  3389. 0L ),
  3390. (LONG)(LPTSTR)szFaceName );
  3391. WriteProfileString(TEXT("MSCharMap"), TEXT("Font"), (LPTSTR)szFaceName);
  3392. }
  3393. ////////////////////////////////////////////////////////////////////////////
  3394. //
  3395. // SelectInitialFont
  3396. //
  3397. // Selects the initial font by getting a saved facename from win.ini and
  3398. // selecting it in the combo box.
  3399. //
  3400. // Returns index to font selected.
  3401. //
  3402. ////////////////////////////////////////////////////////////////////////////
  3403. INT SelectInitialFont(
  3404. HWND hWndDlg)
  3405. {
  3406. TCHAR szFaceName[LF_FACESIZE] = TEXT("");
  3407. INT iIndex;
  3408. if ((GetProfileString( TEXT("MSCharMap"),
  3409. TEXT("Font"),
  3410. NULL,
  3411. (LPTSTR)szFaceName,
  3412. BTOC(sizeof(szFaceName)) ) == 0) ||
  3413. ((iIndex = (INT)SendDlgItemMessage( hWndDlg,
  3414. ID_FONT,
  3415. CB_SELECTSTRING,
  3416. (WPARAM)-1,
  3417. (LONG)(LPTSTR)szFaceName )) == CB_ERR))
  3418. {
  3419. //
  3420. // If there was no profile or the selection failed then try selecting
  3421. // the symbol font, if that fails then select the first one.
  3422. //
  3423. if ((iIndex = (INT)SendDlgItemMessage( hWndDlg,
  3424. ID_FONT,
  3425. CB_SELECTSTRING,
  3426. (WPARAM)-1,
  3427. (LONG)(LPTSTR)TEXT("Symbol") )) == CB_ERR)
  3428. {
  3429. SendDlgItemMessage(hWndDlg, ID_FONT, CB_SETCURSEL, iIndex = 0, 0L);
  3430. }
  3431. }
  3432. return (iIndex);
  3433. }
  3434. ////////////////////////////////////////////////////////////////////////////
  3435. //
  3436. // SaveCurrentSubset
  3437. //
  3438. // Saves the current subset name in win.ini, so that it can be selected
  3439. // the next time charmap comes up.
  3440. //
  3441. ////////////////////////////////////////////////////////////////////////////
  3442. VOID SaveCurrentSubset(
  3443. HWND hWndDlg)
  3444. {
  3445. TCHAR szSubsetName[LF_SUBSETSIZE] = TEXT("");
  3446. SendDlgItemMessage( hWndDlg,
  3447. ID_UNICODESUBSET,
  3448. CB_GETLBTEXT,
  3449. (WORD)SendDlgItemMessage( hWndDlg,
  3450. ID_UNICODESUBSET,
  3451. CB_GETCURSEL,
  3452. 0,
  3453. 0L ),
  3454. (LONG)(LPTSTR)szSubsetName );
  3455. WriteProfileString(TEXT("MSCharMap"), TEXT("Block"), (LPTSTR)szSubsetName);
  3456. }
  3457. ////////////////////////////////////////////////////////////////////////////
  3458. //
  3459. // SelectInitialSubset
  3460. //
  3461. // Selects the initial Unicode subset by getting a saved block name from
  3462. // win.ini.
  3463. //
  3464. // Returns index to subset selected.
  3465. //
  3466. ////////////////////////////////////////////////////////////////////////////
  3467. INT SelectInitialSubset(
  3468. HWND hWndDlg)
  3469. {
  3470. TCHAR szSubsetName[LF_SUBSETSIZE] = TEXT("");
  3471. INT iIndex;
  3472. if ((GetProfileString( TEXT("MSCharMap"),
  3473. TEXT("Block"),
  3474. NULL,
  3475. (LPTSTR)szSubsetName,
  3476. BTOC(sizeof(szSubsetName)) ) == 0) ||
  3477. ((iIndex = (INT)SendDlgItemMessage(
  3478. hWndDlg,
  3479. ID_UNICODESUBSET,
  3480. CB_SELECTSTRING,
  3481. (WPARAM)-1,
  3482. (LONG)(LPTSTR)szSubsetName )) == CB_ERR))
  3483. {
  3484. //
  3485. // If there was no profile or the selection failed then try selecting
  3486. // the Basic Latin block, if that fails then select the first one.
  3487. //
  3488. if ((iIndex = (INT)SendDlgItemMessage(
  3489. hWndDlg,
  3490. ID_UNICODESUBSET,
  3491. CB_SELECTSTRING,
  3492. (WPARAM)-1,
  3493. (LONG)(LPTSTR)TEXT("Basic Latin") )) == CB_ERR)
  3494. {
  3495. SendDlgItemMessage( hWndDlg,
  3496. ID_UNICODESUBSET,
  3497. CB_SETCURSEL,
  3498. iIndex = 0,
  3499. 0L );
  3500. }
  3501. }
  3502. chSymFirst = aSubsetData[iIndex].BeginRange;
  3503. chSymLast = aSubsetData[iIndex].EndRange;
  3504. sycm.chCurr = chSymFirst;
  3505. return (iIndex);
  3506. }
  3507. ////////////////////////////////////////////////////////////////////////////
  3508. //
  3509. // ExitMagnify
  3510. //
  3511. // Releases mouse capture, exits magnify mode, and restores the cursor.
  3512. //
  3513. ////////////////////////////////////////////////////////////////////////////
  3514. VOID ExitMagnify(
  3515. HWND hWnd,
  3516. PSYCM psycm)
  3517. {
  3518. //
  3519. // Release capture, remove magnified character, restore cursor.
  3520. //
  3521. ReleaseCapture();
  3522. RestoreSymMag(psycm);
  3523. DrawSymChOutlineHwnd(psycm, hWnd, psycm->chCurr, TRUE, TRUE);
  3524. if (psycm->fCursorOff)
  3525. {
  3526. ShowCursor(TRUE);
  3527. }
  3528. psycm->fMouseDn = psycm->fCursorOff = FALSE;
  3529. }
  3530. ////////////////////////////////////////////////////////////////////////////
  3531. //
  3532. // SetEditCtlFont
  3533. //
  3534. // Creates a font for the Edit control that visually matches the handle
  3535. // given, but is guaranteed not to be bigger than the size of the edit
  3536. // control.
  3537. //
  3538. ////////////////////////////////////////////////////////////////////////////
  3539. void SetEditCtlFont(
  3540. HWND hwndDlg,
  3541. int idCtl,
  3542. HFONT hfont)
  3543. {
  3544. static HFONT hfNew = NULL;
  3545. LOGFONT lfNew;
  3546. HWND hwndCtl = GetDlgItem(hwndDlg, idCtl);
  3547. RECT rc;
  3548. if (hfNew != NULL)
  3549. {
  3550. DeleteObject(hfNew);
  3551. }
  3552. GetWindowRect(hwndCtl, &rc);
  3553. if (GetObject(hfont, sizeof(lfNew), &lfNew) != 0)
  3554. {
  3555. lfNew.lfHeight = rc.bottom - rc.top - 8;
  3556. lfNew.lfWidth = lfNew.lfEscapement = lfNew.lfOrientation =
  3557. lfNew.lfWeight = 0;
  3558. hfNew = CreateFontIndirect(&lfNew);
  3559. }
  3560. else
  3561. {
  3562. hfNew = hfont;
  3563. }
  3564. SendMessage(hwndCtl, WM_SETFONT, (WPARAM)hfNew, (LPARAM)TRUE);
  3565. if (hfNew == hfont)
  3566. {
  3567. hfNew = NULL;
  3568. }
  3569. }