Leaked source code of windows server 2003
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.

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