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

2695 lines
89 KiB

  1. /****************************************************************************
  2. PROGRAM: CharMap
  3. PURPOSE: Utility providing users an easy interface for selecting special
  4. characters.
  5. COMMENTS:
  6. Created by MikeSch (7-16-91)
  7. Partially derived from WinWord 2.0 Insert.Symbol dialog.
  8. ****************************************************************************/
  9. #define WIN31
  10. #include "windows.h"
  11. #include <port1632.h>
  12. #include "charmap.h"
  13. #include "stdlib.h"
  14. #include "tchar.h"
  15. #ifdef UNICODE
  16. #include "wchar.h"
  17. #else
  18. #include "stdio.h"
  19. #endif
  20. #include "commctrl.h"
  21. /*
  22. * Macros
  23. */
  24. #define FMagData(psycm) ((psycm)->xpMagCurr != 0)
  25. #define abs(x) (((x) >= 0) ? (x) : (-(x)))
  26. /*
  27. * Useful constants.
  28. */
  29. #define STATUSPOINTSIZE 8 // Point size of status bar font.
  30. #define DX_BITMAP 20 // Width of TT bitmap.
  31. #define DY_BITMAP 12 // Height of TT bitmap.
  32. #define BACKGROUND 0x000000FF // bright blue
  33. #define BACKGROUNDSEL 0x00FF00FF // bright purple
  34. #define BUTTONFACE 0x00C0C0C0 // bright grey
  35. #define BUTTONSHADOW 0x00808080 // dark grey
  36. // Font types
  37. #define PS_OPENTYPE_FONT 0x0001
  38. #define TT_OPENTYPE_FONT 0x0002
  39. #define TRUETYPE_FONT 0x0004
  40. #define TYPE1_FONT 0x0008
  41. /*
  42. * Globals.
  43. */
  44. HANDLE hInst;
  45. INT cchSymRow = 32; // Number of characters across the character grid.
  46. INT cchSymCol = 8; // Number of rows in the character grid.
  47. UTCHAR chSymFirst = 32;
  48. UTCHAR chSymLast = 255;
  49. SYCM sycm; // Tons of data need to do char grid painting.
  50. UINT wCFRichText = 0; // Private clipboard format, rich text format.
  51. HFONT hFontClipboard = NULL; // Tells us which font is in the clipboard.
  52. HANDLE hstrClipboard = NULL; // Contains the string which is in the clipboard.
  53. BOOL fDelClipboardFont = FALSE; // The clipboard font needs to be deleted.
  54. INT iControl = ID_CHARGRID; // Index indicating which control has focus.
  55. HBITMAP hbmFont = NULL; // TT bitmap drawn before font facenames in combo.
  56. LONG lEditSel = 0; // Contains the selection range of the EC.
  57. HBRUSH hStaticBrush; // Used for static controls during WM_CTLCOLOR
  58. //
  59. // 04 Dec 92 - GregoryW
  60. // Currently there is no defined
  61. // interface for querying what character ranges a Unicode font
  62. // supports. For now this table only has the subsets that contain
  63. // characters supported by the Lucida Sans Unicode font uncommented.
  64. // When we get an API that allows querying the font driver for
  65. // ranges of Unicode characters supported (and whether or not a font
  66. // is a Unicode font!) then all entries can be uncommented.
  67. //
  68. USUBSET aSubsetData[] = {{ 0x0020, 0x00ff, IDS_LATIN1},
  69. { 0x0100, 0x017f, IDS_LATINEXA},
  70. { 0x0180, 0x024f, IDS_LATINEXB},
  71. { 0x0250, 0x02af, IDS_IPAEX},
  72. { 0x02b0, 0x02ff, IDS_SPACINGMODIFIERS},
  73. { 0x0300, 0x036f, IDS_COMBININGDIACRITICS},
  74. { 0x0370, 0x03cf, IDS_BASICGREEK},
  75. { 0x03d0, 0x03ff, IDS_GREEKSYMBOLS},
  76. { 0x0400, 0x04ff, IDS_CYRILLIC},
  77. // not supported { 0x0530, 0x058f, IDS_ARMENIAN},
  78. { 0x0590, 0x05ff, IDS_HEBREW},
  79. // not supported { 0x0600, 0x0652, IDS_BASICARABIC},
  80. // not supported { 0x0653, 0x06ff, IDS_ARABICEX},
  81. // not supported { 0x0900, 0x097f, IDS_DEVANAGARI},
  82. // not supported { 0x0980, 0x09ff, IDS_BENGALI},
  83. // not supported { 0x0a00, 0x0a7f, IDS_GURMUKHI},
  84. // not supported { 0x0a80, 0x0aff, IDS_GUJARATI},
  85. // not supported { 0x0b00, 0x0b7f, IDS_ORIYA},
  86. // not supported { 0x0b80, 0x0bff, IDS_TAMIL},
  87. // not supported { 0x0c00, 0x0c7f, IDS_TELUGU},
  88. // not supported { 0x0c80, 0x0cff, IDS_KANNADA},
  89. // not supported { 0x0d00, 0x0d7f, IDS_MALAYALAM},
  90. // not supported { 0x0e00, 0x0e7f, IDS_THAI},
  91. // not supported { 0x0e80, 0x0eff, IDS_LAO},
  92. // not supported { 0x10d0, 0x10ff, IDS_BASICGEORGIAN},
  93. // not supported { 0x10a0, 0x10cf, IDS_GEORGIANEX},
  94. // not supported { 0x1100, 0x11ff, IDS_HANGULJAMO},
  95. // not supported { 0x1e00, 0x1eff, IDS_LATINEXADDITIONAL},
  96. // not supported { 0x1f00, 0x1fff, IDS_GREEKEX},
  97. // not supported { 0x2000, 0x206f, IDS_GENERALPUNCTUATION},
  98. // not supported { 0x2070, 0x209f, IDS_SUPERANDSUBSCRIPTS},
  99. { 0x20a0, 0x20cf, IDS_CURRENCYSYMBOLS},
  100. // not supported { 0x20d0, 0x20ff, IDS_COMBININGDIACRITICSFORSYMBOLS},
  101. { 0x2100, 0x214f, IDS_LETTERLIKESYMBOLS},
  102. // not supported { 0x2150, 0x218f, IDS_NUMBERFORMS},
  103. { 0x2190, 0x21ff, IDS_ARROWS},
  104. { 0x2200, 0x22ff, IDS_MATHEMATICALOPS},
  105. // not supported { 0x2300, 0x23ff, IDS_MISCTECHNICAL},
  106. // not supported { 0x2400, 0x243f, IDS_CONTROLPICTURES},
  107. // not supported { 0x2440, 0x245f, IDS_OPTICALCHAR},
  108. // not supported { 0x2460, 0x24ff, IDS_ENCLOSEDALPHANUM},
  109. // not supported { 0x2500, 0x257f, IDS_BOXDRAWING},
  110. // not supported { 0x2580, 0x259f, IDS_BLOCKELEMENTS},
  111. // not supported { 0x25a0, 0x25ff, IDS_GEOMETRICSHAPES},
  112. // not supported { 0x2600, 0x26ff, IDS_MISCDINGBATS},
  113. // not supported { 0x2700, 0x27bf, IDS_DINGBATS},
  114. // not supported { 0x3000, 0x303f, IDS_CJKSYMBOLSANDPUNC},
  115. // not supported { 0x3040, 0x309f, IDS_HIRAGANA},
  116. // not supported { 0x30a0, 0x30ff, IDS_KATAKANA},
  117. // not supported { 0x3100, 0x312f, IDS_BOPOMOFO},
  118. // not supported { 0x3130, 0x318f, IDS_HANGULCOMPATIBILITYJAMO},
  119. // not supported { 0x3190, 0x319f, IDS_CJKMISC},
  120. // not supported { 0x3200, 0x32ff, IDS_ENCLOSEDCJKLETTERSANDMONTHS},
  121. // not supported { 0x3300, 0x33ff, IDS_CJKCOMPATIBILITY},
  122. // not supported { 0x3400, 0x3d2d, IDS_HANGUL},
  123. // not supported { 0x3d2e, 0x44b7, IDS_HANGULSUPPA},
  124. // not supported { 0x44b8, 0x4dff, IDS_HANGULSUPPB},
  125. // not supported { 0x4e00, 0x9fff, IDS_CJKUNIFIEDIDEOGRAPHS},
  126. // not supported { 0xe000, 0xf8ff, IDS_PRIVATEUSEAREA},
  127. // not supported { 0xf900, 0xfaff, IDS_CJKCOMPATIBILITYIDEOGRAPHS},
  128. // not supported { 0xfb00, 0xfb4f, IDS_ALPAHPRESENTATIONFORMS},
  129. // not supported { 0xfb50, 0xfdff, IDS_ARABICPRESENTATIONFORMSA},
  130. // not supported { 0xfe30, 0xfe4f, IDS_CJKCOMPFORMS},
  131. // not supported { 0xfe50, 0xfe6f, IDS_SMALLFORMVARIANTS},
  132. // not supported { 0xfe70, 0xfefe, IDS_ARABICPRESENTATIONFORMSB},
  133. // not supported { 0xff00, 0xffef, IDS_HALFANDFULLWIDTHFORMS},
  134. // not supported { 0xfff0, 0xfffd, IDS_SPECIALS}
  135. };
  136. INT cSubsets = sizeof(aSubsetData) / sizeof(USUBSET);
  137. INT iCurSubset = 0; // index of current Unicode subset - default to Latin-1
  138. // Useful window handles.
  139. HWND hwndDialog;
  140. HWND hwndCharGrid;
  141. // Data used to draw the status bar.
  142. RECT rcStatusLine; // Bounding rect for status bar.
  143. RECT rcToolbar[2]; // Bounding rects for toolbars.
  144. INT dyStatus; // Height of status bar.
  145. INT dyToolbar[2]; // Height of tool bars.
  146. INT dxHelpField; // Width of help window.
  147. INT dxKeystrokeField; // Width of keystroke window.
  148. TCHAR szKeystrokeText[30]; // Buffer for keystroke text.
  149. TCHAR szKeystrokeLabel[30]; // Buffer for keystroke label.
  150. TCHAR szSpace[15]; // Strings for keystroke description.
  151. TCHAR szCtrl[15];
  152. TCHAR szCtrlAlt[25];
  153. TCHAR szShiftCtrlAlt[25];
  154. TCHAR szAlt[15];
  155. TCHAR szUnicodeLabel[23]; // Buffer for Unicode label.
  156. INT iKeystrokeTextStart; // Place to start appending text to above.
  157. INT iUnicodeLabelStart; // Place to start appending text to above.
  158. HFONT hfontStatus; // Font used for text of status bar.
  159. /****************************************************************************
  160. FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
  161. PURPOSE: calls initialization function, processes message loop, cleanup.
  162. COMMENTS:
  163. ****************************************************************************/
  164. INT PASCAL WinMain(
  165. HINSTANCE hInstance,
  166. HINSTANCE hPrevInstance,
  167. LPSTR lpCmdLine,
  168. int nCmdShow)
  169. {
  170. MSG msg;
  171. if (!InitApplication(hInstance))
  172. return (FALSE);
  173. InitCommonControls();
  174. // Perform initialization for this instance.
  175. if (!InitInstance(hInstance, nCmdShow)) {
  176. return (FALSE);
  177. }
  178. while (GetMessage(&msg,
  179. NULL,
  180. 0,
  181. 0))
  182. {
  183. // Filter for possible tabs now to implement context sensitive help.
  184. if (msg.message == WM_KEYDOWN)
  185. if (!UpdateHelpText(&msg, NULL))
  186. continue;
  187. // Main message loop.
  188. if (!IsDialogMessage(hwndDialog, &msg)) {
  189. TranslateMessage(&msg);
  190. DispatchMessage(&msg);
  191. }
  192. }
  193. // Free up some stuff.
  194. if (hfontStatus)
  195. DeleteObject(hfontStatus);
  196. if (hbmFont)
  197. DeleteObject(hbmFont);
  198. return (int)(msg.wParam);
  199. }
  200. /****************************************************************************
  201. FUNCTION: InitApplication(HANDLE)
  202. PURPOSE: Initializes window data and registers window class
  203. COMMENTS:
  204. ****************************************************************************/
  205. BOOL InitApplication(HANDLE hInstance)
  206. {
  207. WNDCLASS wc;
  208. /*
  209. * Register a window class that we will use to draw the character grid
  210. * into.
  211. */
  212. wc.style = CS_DBLCLKS;
  213. wc.lpfnWndProc = CharGridWndProc;
  214. wc.cbClsExtra = 0;
  215. wc.cbWndExtra = 0;
  216. wc.hInstance = hInstance;
  217. wc.hIcon = NULL;
  218. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  219. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  220. wc.lpszMenuName = NULL;
  221. wc.lpszClassName = TEXT("CharGridWClass");
  222. if (!RegisterClass(&wc))
  223. return (FALSE);
  224. wc.style = 0;
  225. wc.lpfnWndProc = DefDlgProc;
  226. wc.cbClsExtra = 0;
  227. wc.cbWndExtra = DLGWINDOWEXTRA;
  228. wc.hInstance = hInstance;
  229. wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDIC_CHARMAP));
  230. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  231. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  232. wc.lpszMenuName = NULL;
  233. wc.lpszClassName = TEXT("MyDlgClass");
  234. if (!RegisterClass(&wc))
  235. return (FALSE);
  236. return TRUE;
  237. }
  238. /****************************************************************************
  239. FUNCTION: InitInstance(HANDLE, int)
  240. PURPOSE: Does some initialization and creates main window which is a
  241. dialog.
  242. COMMENTS:
  243. ****************************************************************************/
  244. BOOL InitInstance(HANDLE hInstance, INT nCmdShow)
  245. {
  246. INT i;
  247. // Save the instance handle in a global variable.
  248. hInst = hInstance;
  249. // This font will be used to paint the status line.
  250. hfontStatus = CreateFont(-PointsToHeight(STATUSPOINTSIZE), 0, 0, 0, 400, 0, 0, 0,
  251. ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  252. DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, TEXT("Helv"));
  253. dyStatus = 2 * PointsToHeight(STATUSPOINTSIZE);
  254. dyToolbar[0] = 28; /* defined by UI gods */
  255. dyToolbar[1] = 28; /* defined by UI gods */
  256. // Load the Unicode subset names before initializing the main window.
  257. for (i = 0; i < cSubsets; i++) {
  258. if (!LoadString(
  259. hInst,
  260. aSubsetData[i].StringResId,
  261. (LPTSTR)aSubsetData[i].Name,
  262. 50)
  263. )
  264. return (FALSE);
  265. }
  266. // Create a main window for this application instance.
  267. if (!(hwndDialog = CreateDialog(hInstance, TEXT("CharMap"), NULL,
  268. CharMapDlgProc)))
  269. return (FALSE);
  270. /*
  271. * Initialize some strings used for the Keystroke status bar field.
  272. */
  273. // For international purposes, this string could be length 0.
  274. LoadString(
  275. hInst,
  276. IDS_KEYSTROKE,
  277. (LPTSTR)szKeystrokeLabel,
  278. BTOC(sizeof(szKeystrokeLabel))
  279. );
  280. if (!LoadString(
  281. hInst,
  282. IDS_UNICODELABEL,
  283. (LPTSTR)szUnicodeLabel,
  284. BTOC(sizeof(szUnicodeLabel))
  285. ))
  286. if (!LoadString(
  287. hInst,
  288. IDS_SPACE,
  289. (LPTSTR)szSpace,
  290. BTOC(sizeof(szSpace))
  291. ))
  292. return (FALSE);
  293. if (!LoadString(
  294. hInst,
  295. IDS_CTRL,
  296. (LPTSTR)szCtrl,
  297. BTOC(sizeof(szCtrl))
  298. ))
  299. return (FALSE);
  300. if (!LoadString(
  301. hInst,
  302. IDS_CTRLALT,
  303. (LPTSTR)szCtrlAlt,
  304. BTOC(sizeof(szCtrlAlt))
  305. ))
  306. return (FALSE);
  307. if (!LoadString(
  308. hInst,
  309. IDS_SHIFTCTRLALT,
  310. (LPTSTR)szShiftCtrlAlt,
  311. BTOC(sizeof(szShiftCtrlAlt))
  312. ))
  313. return (FALSE);
  314. if (!LoadString(
  315. hInst,
  316. IDS_ALT,
  317. (LPTSTR)szAlt,
  318. BTOC(sizeof(szAlt))
  319. ))
  320. return (FALSE);
  321. // Store the index to where we start adding status line text changes.
  322. iKeystrokeTextStart = lstrlen(szKeystrokeLabel);
  323. iUnicodeLabelStart = lstrlen(szUnicodeLabel);
  324. /*
  325. * Initialize keystroke text, make the window visible,
  326. * update its client area, and return "success".
  327. */
  328. UpdateKeystrokeText(NULL, sycm.chCurr, FALSE);
  329. ShowWindow(hwndDialog, nCmdShow);
  330. UpdateWindow(hwndDialog);
  331. return (TRUE);
  332. }
  333. /****************************************************************************
  334. FUNCTION: CharMapDlgProc(HWND, UINT, WPARAM, LPARAM)
  335. PURPOSE: Processes messages for the main window.
  336. COMMENTS: This window is a dialog box.
  337. ****************************************************************************/
  338. INT_PTR APIENTRY CharMapDlgProc(
  339. HWND hWnd,
  340. UINT message,
  341. WPARAM wParam,
  342. LPARAM lParam)
  343. {
  344. switch (message) {
  345. case WM_CTLCOLORSTATIC:
  346. {
  347. POINT point;
  348. SetBkColor((HDC)wParam, GetSysColor(COLOR_BTNFACE));
  349. UnrealizeObject(hStaticBrush);
  350. point.x = point.y = 0;
  351. ClientToScreen(hWnd, &point);
  352. return((INT_PTR)hStaticBrush);
  353. break;
  354. }
  355. case WM_INITDIALOG:
  356. {
  357. RECT rectParent, rectTopRightControl;
  358. INT iSubset;
  359. /*
  360. * Create the character grid with dimensions which just fit inside
  361. * the space allowed in the dialog. When it processes the
  362. * WM_CREATE message it will be sized and centered more accurately.
  363. */
  364. GetClientRect(hWnd, &rectParent);
  365. GetWindowRect(GetDlgItem(hWnd, ID_CLOSE), &rectTopRightControl);
  366. ScreenToClient(hWnd, (LPPOINT)&(rectTopRightControl.left));
  367. ScreenToClient(hWnd, (LPPOINT)&(rectTopRightControl.right));
  368. if (!(hwndCharGrid =
  369. CreateWindow(
  370. TEXT("CharGridWClass"),
  371. NULL,
  372. WS_CHILD | WS_VISIBLE | WS_TABSTOP,
  373. 1,
  374. rectParent.top + dyToolbar[0] + dyToolbar[1],
  375. rectParent.right - 1,
  376. rectParent.bottom - rectParent.top - dyStatus - dyToolbar[0] - dyToolbar[1] - 1,
  377. hWnd,
  378. (HMENU) ID_CHARGRID,
  379. hInst,
  380. NULL
  381. ))) {
  382. DestroyWindow(hWnd);
  383. break;
  384. }
  385. hStaticBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  386. // Initialize the status line data.
  387. dxHelpField = 22 * rectParent.right / 32;
  388. dxKeystrokeField = 8 * rectParent.right / 32;
  389. rcStatusLine = rectParent;
  390. rcStatusLine.top = rcStatusLine.bottom - dyStatus;
  391. // Initialize the toolbars
  392. rcToolbar[0] = rectParent;
  393. rcToolbar[0].bottom = rcToolbar[0].top + dyToolbar[0];
  394. rcToolbar[1] = rcToolbar[0];
  395. rcToolbar[1].top = rcToolbar[0].bottom + GetSystemMetrics(SM_CYBORDER);
  396. rcToolbar[1].bottom = rcToolbar[1].top + dyToolbar[1];
  397. // Disable Copy button.
  398. EnableWindow(GetDlgItem(hWnd, ID_COPY), FALSE);
  399. /* fill "Subset" list box */
  400. for (iSubset = 0; iSubset < cSubsets; iSubset++) {
  401. SendDlgItemMessage(
  402. hWnd,
  403. ID_UNICODESUBSET,
  404. CB_ADDSTRING,
  405. 0,
  406. (LPARAM)aSubsetData[iSubset].Name
  407. );
  408. }
  409. iCurSubset = SelectInitialSubset(hWnd);
  410. }
  411. /* fall through to WM_FONTCHANGE */
  412. case WM_FONTCHANGE:
  413. {
  414. HDC hdc = GetDC(hWnd);
  415. /*
  416. * Get the fonts from the system and put them in the font selection
  417. * combo box.
  418. */
  419. if (message == WM_FONTCHANGE) {
  420. SaveCurrentFont(hWnd);
  421. SendDlgItemMessage(hWnd, ID_FONT, CB_RESETCONTENT, 0, 0L);
  422. }
  423. EnumFontFamilies(hdc, NULL, (FONTENUMPROC)FontLoadProc, (LPARAM)hWnd);
  424. ReleaseDC(hWnd, hdc);
  425. // Setup character dimensions and select this font.
  426. RecalcCharMap(hWnd, &sycm, SelectInitialFont(hWnd),
  427. (message == WM_FONTCHANGE));
  428. SendDlgItemMessage(hWnd, ID_STRING, WM_SETFONT,
  429. (WPARAM)sycm.hFont, (DWORD)TRUE);
  430. if (message == WM_INITDIALOG)
  431. SetFocus(hwndCharGrid);
  432. /* fall through to WM_SYSCOLORCHANGE */
  433. else
  434. break;
  435. }
  436. case WM_SYSCOLORCHANGE:
  437. if (hbmFont)
  438. DeleteObject(hbmFont);
  439. hbmFont = LoadBitmaps(IDBM_TT);
  440. DeleteObject(hStaticBrush);
  441. hStaticBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  442. break;
  443. case WM_PARENTNOTIFY:
  444. {
  445. POINTS points;
  446. DWORD dwMsgPos;
  447. POINT point;
  448. /*
  449. * We process this message to implement the context sensitive
  450. * help. Downclicks to controls are found here, the help
  451. * message is updated in the status bar.
  452. */
  453. // BUG - The parameters with this message are unreliable!
  454. if (wParam == WM_LBUTTONDOWN) {
  455. dwMsgPos = GetMessagePos();
  456. points = MAKEPOINTS(dwMsgPos);
  457. point.x = points.x;
  458. point.y = points.y;
  459. UpdateHelpText(NULL, WindowFromPoint(point));
  460. }
  461. }
  462. break;
  463. case WM_PAINT:
  464. {
  465. HBRUSH hBrush;
  466. RECT rcTemp, rectNextButton;
  467. INT dyBorder, dxBorder;
  468. PAINTSTRUCT ps;
  469. HDC hdc;
  470. /*
  471. * This code implements painting of the status bar.
  472. */
  473. hdc = BeginPaint(hWnd, &ps);
  474. rcTemp = rcStatusLine;
  475. dyBorder = GetSystemMetrics(SM_CYBORDER);
  476. dxBorder = GetSystemMetrics(SM_CXBORDER);
  477. // Make the whole thing grey.
  478. if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE))) {
  479. FillRect(hdc, &rcTemp, hBrush);
  480. rcTemp.left = rcToolbar[0].left;
  481. rcTemp.top = rcToolbar[0].top;
  482. rcTemp.right = rcToolbar[1].right;
  483. rcTemp.bottom = rcToolbar[1].bottom;
  484. FillRect(hdc, &rcTemp, hBrush);
  485. DeleteObject(hBrush);
  486. }
  487. GetWindowRect(GetDlgItem(hWnd, ID_TOPLEFT), &rectNextButton);
  488. ScreenToClient(hWnd, (LPPOINT)&(rectNextButton.left));
  489. ScreenToClient(hWnd, (LPPOINT)&(rectNextButton.right));
  490. // solid black line across bottom of toolbar
  491. if (hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME))) {
  492. rcTemp = rcToolbar[0];
  493. rcTemp.top = rcTemp.bottom;
  494. rcTemp.bottom += dyBorder;
  495. rcTemp.left = rectNextButton.left - 2 - dxBorder;
  496. FillRect(hdc, &rcTemp, hBrush);
  497. rcTemp = rcToolbar[1];
  498. rcTemp.top = rcTemp.bottom;
  499. rcTemp.bottom += dyBorder;
  500. FillRect(hdc, &rcTemp, hBrush);
  501. // vertical line
  502. rcTemp.top = rcToolbar[0].top;
  503. rcTemp.bottom = rcToolbar[1].bottom;
  504. rcTemp.left = rectNextButton.left - 2 - dxBorder;
  505. rcTemp.right = rectNextButton.left - 2;
  506. FillRect(hdc, &rcTemp, hBrush);
  507. DeleteObject(hBrush);
  508. }
  509. if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW))) {
  510. // Status line top.
  511. rcTemp.left = 8 * dyBorder;
  512. rcTemp.right = rcTemp.left + dxHelpField;
  513. rcTemp.top = rcStatusLine.top + dyBorder * 2;
  514. rcTemp.bottom = rcTemp.top + dyBorder;
  515. FillRect(hdc, &rcTemp, hBrush);
  516. // Keystroke line top.
  517. rcTemp.right = rcStatusLine.right - 8 * dyBorder;
  518. rcTemp.left = rcTemp.right - dxKeystrokeField;
  519. FillRect(hdc, &rcTemp, hBrush);
  520. // Status line left side.
  521. rcTemp = rcStatusLine;
  522. rcTemp.left = 8 * dyBorder;
  523. rcTemp.right = rcTemp.left + dyBorder;
  524. rcTemp.top += dyBorder * 2;
  525. rcTemp.bottom -= dyBorder * 2;
  526. FillRect(hdc, &rcTemp, hBrush);
  527. // Keystroke line left side.
  528. rcTemp.left = rcStatusLine.right - 9 * dyBorder - dxKeystrokeField;
  529. rcTemp.right = rcTemp.left + dyBorder;
  530. FillRect(hdc, &rcTemp, hBrush);
  531. DeleteObject(hBrush);
  532. }
  533. if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT))) {
  534. // Status line bottom.
  535. rcTemp.left = 8 * dyBorder;
  536. rcTemp.right = rcTemp.left + dxHelpField;
  537. rcTemp.top = rcStatusLine.bottom - 3 * dyBorder;
  538. rcTemp.bottom = rcTemp.top + dyBorder;
  539. FillRect(hdc, &rcTemp, hBrush);
  540. // Keystroke line bottom.
  541. rcTemp.right = rcStatusLine.right - 8 * dyBorder;
  542. rcTemp.left = rcTemp.right - dxKeystrokeField;
  543. FillRect(hdc, &rcTemp, hBrush);
  544. // Status line right side.
  545. rcTemp = rcStatusLine;
  546. rcTemp.left = 8 * dyBorder + dxHelpField;
  547. rcTemp.right = rcTemp.left + dyBorder;
  548. rcTemp.top += dyBorder * 2;
  549. rcTemp.bottom -= dyBorder * 2;
  550. FillRect(hdc, &rcTemp, hBrush);
  551. // Keystroke line right side.
  552. rcTemp.left = rcStatusLine.right - 8 * dyBorder;
  553. rcTemp.right = rcTemp.left + dyBorder;
  554. FillRect(hdc, &rcTemp, hBrush);
  555. DeleteObject(hBrush);
  556. }
  557. // solid black line across top
  558. if (hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME))) {
  559. rcTemp = rcStatusLine;
  560. rcTemp.bottom = rcTemp.top;
  561. rcTemp.top -= dyBorder;
  562. FillRect(hdc, &rcTemp, hBrush);
  563. DeleteObject(hBrush);
  564. }
  565. PaintStatusLine(hdc, TRUE, TRUE);
  566. EndPaint(hWnd, &ps);
  567. return (TRUE);
  568. }
  569. case WM_MEASUREITEM:
  570. {
  571. HDC hDC;
  572. HFONT hFont;
  573. TEXTMETRIC tm;
  574. hDC = GetDC(NULL);
  575. hFont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0L);
  576. if (hFont)
  577. hFont = SelectObject(hDC, hFont);
  578. GetTextMetrics(hDC, &tm);
  579. if (hFont)
  580. SelectObject(hDC, hFont);
  581. ReleaseDC(NULL, hDC);
  582. ((LPMEASUREITEMSTRUCT)lParam)->itemHeight = max(tm.tmHeight, DY_BITMAP);
  583. break;
  584. }
  585. case WM_DRAWITEM:
  586. if (((LPDRAWITEMSTRUCT)lParam)->itemID != -1)
  587. DrawFamilyComboItem((LPDRAWITEMSTRUCT)lParam);
  588. break;
  589. case WM_ASKCBFORMATNAME:
  590. LoadString(hInst, IDS_RTF, (LPTSTR)lParam, (UINT)wParam);
  591. return (TRUE);
  592. case WM_PAINTCLIPBOARD:
  593. {
  594. LPPAINTSTRUCT lpPS;
  595. HANDLE hFont;
  596. LPTSTR lpstrText;
  597. if (hstrClipboard) {
  598. // Setup.
  599. lpPS = (LPPAINTSTRUCT)GlobalLock((HANDLE)lParam);
  600. lpstrText = (LPTSTR)GlobalLock(hstrClipboard);
  601. // Lets paint.
  602. hFont = SelectObject(lpPS->hdc, hFontClipboard);
  603. TextOut(lpPS->hdc, 0, 0, lpstrText,
  604. lstrlen(lpstrText));
  605. SelectObject(lpPS->hdc, hFont);
  606. // Cleanup.
  607. GlobalUnlock(hstrClipboard);
  608. GlobalUnlock((HANDLE)lParam);
  609. }
  610. return (TRUE);
  611. }
  612. case WM_CLOSE:
  613. DestroyWindow(hWnd);
  614. return (TRUE);
  615. case WM_COMMAND:
  616. switch(GET_WM_COMMAND_ID(wParam, lParam)) {
  617. case IDCANCEL:
  618. case ID_CLOSE:
  619. DestroyWindow(hWnd);
  620. return (TRUE);
  621. break;
  622. case ID_SELECT:
  623. SendDlgItemMessage(hWnd, ID_STRING, WM_CHAR,
  624. (WPARAM)sycm.chCurr, 0L);
  625. break;
  626. case ID_COPY:
  627. CopyString(hWnd);
  628. return (TRUE);
  629. break;
  630. case ID_FONT:
  631. if (HIWORD(wParam) == CBN_SELCHANGE) {
  632. RecalcCharMap(hWnd, &sycm,
  633. (INT)SendDlgItemMessage(hWnd, ID_FONT,
  634. CB_GETCURSEL, 0, 0L),
  635. TRUE);
  636. SendDlgItemMessage(hWnd, ID_STRING, WM_SETFONT,
  637. (WPARAM)sycm.hFont, (DWORD)TRUE);
  638. } else if (HIWORD(wParam) == CBN_SETFOCUS) {
  639. // Necessary if hotkey is used to get to the CB.
  640. UpdateHelpText(NULL, (HWND)lParam);
  641. }
  642. return (TRUE);
  643. break;
  644. case ID_UNICODESUBSET:
  645. if (HIWORD(wParam) == CBN_SELCHANGE) {
  646. INT iSubset;
  647. iSubset = (INT)SendDlgItemMessage(
  648. hWnd,
  649. ID_UNICODESUBSET,
  650. CB_GETCURSEL,
  651. 0, 0);
  652. UpdateSymbolSelection(
  653. hWnd,
  654. aSubsetData[iSubset].BeginRange,
  655. aSubsetData[iSubset].EndRange
  656. );
  657. InvalidateRect(hwndCharGrid, NULL, TRUE);
  658. } else if (HIWORD(wParam) == CBN_SETFOCUS) {
  659. // Necessary if hotkey is used to get to the CB.
  660. UpdateHelpText(NULL, (HWND)lParam);
  661. }
  662. return 0;
  663. break;
  664. case ID_NEXTSUBSET:
  665. {
  666. INT iCurSelection, iNumEntries;
  667. iCurSelection = (INT)SendDlgItemMessage(
  668. hWnd,
  669. ID_UNICODESUBSET,
  670. CB_GETCURSEL,
  671. 0, 0);
  672. if (iCurSelection == CB_ERR) {
  673. return 0;
  674. }
  675. iNumEntries = (INT)SendDlgItemMessage(
  676. hWnd,
  677. ID_UNICODESUBSET,
  678. CB_GETCOUNT,
  679. 0, 0);
  680. if (iNumEntries == CB_ERR) {
  681. return 0;
  682. }
  683. if (iCurSelection++ < (iNumEntries - 1)) {
  684. if (iCurSelection == 1) {
  685. // Enable Previous button
  686. EnableWindow(GetDlgItem(hWnd, ID_PREVSUBSET), TRUE);
  687. }
  688. SendDlgItemMessage(
  689. hWnd,
  690. ID_UNICODESUBSET,
  691. CB_SETCURSEL,
  692. iCurSelection, 0);
  693. UpdateSymbolSelection(
  694. hWnd,
  695. aSubsetData[iCurSelection].BeginRange,
  696. aSubsetData[iCurSelection].EndRange
  697. );
  698. InvalidateRect(hwndCharGrid, NULL, TRUE);
  699. if (iCurSelection == (iNumEntries - 1)) {
  700. HWND hwndButton;
  701. EnableWindow(GetDlgItem(hWnd, ID_NEXTSUBSET), FALSE);
  702. //
  703. // Only reset the button style and focus if
  704. // the "Next" button currently has it.
  705. //
  706. if (iControl == ID_NEXTSUBSET) {
  707. SendDlgItemMessage(hwndDialog, ID_PREVSUBSET,
  708. BM_SETSTYLE, BS_DEFPUSHBUTTON, 1);
  709. SendDlgItemMessage(hwndDialog, ID_NEXTSUBSET,
  710. BM_SETSTYLE, BS_PUSHBUTTON, 1);
  711. hwndButton = GetDlgItem(hWnd, ID_PREVSUBSET);
  712. SetFocus(hwndButton);
  713. UpdateHelpText(NULL, hwndButton);
  714. }
  715. }
  716. }
  717. }
  718. return 0;
  719. break;
  720. case ID_PREVSUBSET:
  721. {
  722. INT iCurSelection;
  723. iCurSelection = (INT)SendDlgItemMessage(
  724. hWnd,
  725. ID_UNICODESUBSET,
  726. CB_GETCURSEL,
  727. 0, 0);
  728. if (iCurSelection == CB_ERR) {
  729. return 0;
  730. }
  731. if (iCurSelection > 0) {
  732. iCurSelection--;
  733. if (iCurSelection == (cSubsets - 2)) {
  734. // Enable Next button
  735. EnableWindow(GetDlgItem(hWnd, ID_NEXTSUBSET), TRUE);
  736. }
  737. SendDlgItemMessage(
  738. hWnd,
  739. ID_UNICODESUBSET,
  740. CB_SETCURSEL,
  741. iCurSelection, 0);
  742. UpdateSymbolSelection(
  743. hWnd,
  744. aSubsetData[iCurSelection].BeginRange,
  745. aSubsetData[iCurSelection].EndRange
  746. );
  747. InvalidateRect(hwndCharGrid, NULL, TRUE);
  748. if (iCurSelection == 0) {
  749. HWND hwndButton;
  750. EnableWindow(GetDlgItem(hWnd, ID_PREVSUBSET), FALSE);
  751. //
  752. // Only reset the button style and focus if
  753. // the "Previous" button currently has it.
  754. //
  755. if (iControl == ID_PREVSUBSET) {
  756. SendDlgItemMessage(hwndDialog, ID_NEXTSUBSET,
  757. BM_SETSTYLE, BS_DEFPUSHBUTTON, 1);
  758. SendDlgItemMessage(hwndDialog, ID_PREVSUBSET,
  759. BM_SETSTYLE, BS_PUSHBUTTON, 1);
  760. hwndButton = GetDlgItem(hWnd, ID_NEXTSUBSET);
  761. SetFocus(hwndButton);
  762. UpdateHelpText(NULL, hwndButton);
  763. }
  764. }
  765. }
  766. }
  767. return 0;
  768. break;
  769. case ID_STRING:
  770. if (HIWORD(wParam) == EN_SETFOCUS) {
  771. // Necessary if hotkey is used to get to the EC.
  772. UpdateHelpText(NULL, (HWND)lParam);
  773. } else if (HIWORD(wParam) == EN_CHANGE) {
  774. // Disable Copy button if there are no chars in EC.
  775. INT iLength;
  776. iLength = GetWindowTextLength((HWND)lParam);
  777. EnableWindow(GetDlgItem(hWnd, ID_COPY), (BOOL)iLength);
  778. }
  779. break;
  780. case ID_HELP:
  781. DoHelp(hWnd, TRUE);
  782. break;
  783. }
  784. break;
  785. case WM_DESTROY:
  786. SaveCurrentFont(hWnd);
  787. SaveCurrentSubset(hWnd);
  788. DoHelp(hWnd, FALSE);
  789. DeleteObject(hStaticBrush);
  790. PostQuitMessage(0);
  791. break;
  792. case WM_ACTIVATEAPP:
  793. if (wParam) {
  794. SendDlgItemMessage(hWnd, ID_STRING, EM_SETSEL, LOWORD(lEditSel), HIWORD(lEditSel));
  795. } else {
  796. lEditSel = (LONG)SendDlgItemMessage(hWnd, ID_STRING, EM_GETSEL, 0, 0L);
  797. SendDlgItemMessage(hWnd, ID_STRING, EM_SETSEL, 0, 0L);
  798. }
  799. break;
  800. }
  801. return (FALSE);
  802. }
  803. /****************************************************************************
  804. FUNCTION: CharGridWndProc(HWND, UINT, WPARAM, LPARAM)
  805. PURPOSE: Processes messages for the character grid window.
  806. COMMENTS:
  807. ****************************************************************************/
  808. LRESULT APIENTRY CharGridWndProc(
  809. HWND hWnd,
  810. UINT message,
  811. WPARAM wParam,
  812. LPARAM lParam)
  813. {
  814. switch (message) {
  815. case WM_CREATE:
  816. {
  817. RECT rect;
  818. HDC hdcScrn;
  819. POINT point1, point2;
  820. // Setup global.
  821. hwndCharGrid = hWnd;
  822. GetClientRect(hWnd, &rect);
  823. /*
  824. * Calculate metrics for the character grid and the
  825. * magnify window.
  826. */
  827. sycm.dxpBox = (rect.right-1) / (cchSymRow + 1);
  828. sycm.dypBox = (rect.bottom-2) / (cchSymCol + 1);
  829. sycm.dxpCM = sycm.dxpBox * cchSymRow+1;
  830. sycm.dypCM = sycm.dypBox * cchSymCol+1; // space inside for border
  831. sycm.dxpMag = sycm.dxpBox * 2 + 4; // twice the size + 2 bit border
  832. sycm.dypMag = sycm.dypBox * 2 + 4;
  833. sycm.chCurr = chSymFirst;
  834. sycm.hFontMag = NULL;
  835. sycm.hFont = NULL;
  836. sycm.hdcMag = NULL;
  837. sycm.hbmMag = NULL;
  838. sycm.ypDest = 0;
  839. sycm.fFocusState = sycm.fMouseDn = sycm.fCursorOff = FALSE;
  840. // Size the window precisely so the grid fits and is centered.
  841. MoveWindow(hWnd, (rect.right - sycm.dxpCM + 1) / 2,
  842. (rect.bottom - sycm.dypCM + 1) / 2 + ((LPCREATESTRUCT)lParam)->y - 2,
  843. sycm.dxpCM + 2,
  844. sycm.dypCM + 2,
  845. FALSE);
  846. /*
  847. * Figure out what the offsets are between the dialog
  848. * and the character grid window.
  849. */
  850. point1.x = point1.y = point2.x = point2.y = 0;
  851. ClientToScreen(hWnd, &point1);
  852. ClientToScreen(((LPCREATESTRUCT)lParam)->hwndParent, &point2);
  853. sycm.xpCM = (point1.x - point2.x) - (sycm.dxpMag - sycm.dxpBox) / 2;
  854. sycm.ypCM = (point1.y - point2.y) - (sycm.dypMag - sycm.dypBox) / 2;
  855. // Create dc and bitmap for the magnify window.
  856. if ((hdcScrn = GetWindowDC(hWnd)) != NULL)
  857. {
  858. if ((sycm.hdcMag = CreateCompatibleDC(hdcScrn)) != NULL)
  859. {
  860. SetTextColor(sycm.hdcMag,
  861. GetSysColor(COLOR_WINDOWTEXT));
  862. SetBkColor(sycm.hdcMag,
  863. GetSysColor(COLOR_WINDOW));
  864. SetBkMode(sycm.hdcMag, OPAQUE);
  865. if ((sycm.hbmMag = CreateCompatibleBitmap(hdcScrn,
  866. sycm.dxpMag, sycm.dypMag*2)) == NULL)
  867. {
  868. DeleteObject(sycm.hdcMag);
  869. }
  870. else
  871. {
  872. SelectObject(sycm.hdcMag, sycm.hbmMag);
  873. }
  874. }
  875. ReleaseDC(hWnd, hdcScrn);
  876. }
  877. }
  878. break;
  879. case WM_DESTROY:
  880. if (sycm.fMouseDn)
  881. ExitMagnify(hWnd, &sycm);
  882. if (fDelClipboardFont)
  883. DeleteObject(hFontClipboard);
  884. if (sycm.hFont != NULL)
  885. DeleteObject(sycm.hFont);
  886. if (sycm.hFontMag != NULL)
  887. DeleteObject(sycm.hFontMag);
  888. if (sycm.hdcMag != NULL)
  889. DeleteDC(sycm.hdcMag);
  890. if (sycm.hbmMag != NULL)
  891. DeleteObject(sycm.hbmMag);
  892. break;
  893. case WM_SETFOCUS:
  894. case WM_KILLFOCUS:
  895. RestoreSymMag(&sycm);
  896. DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, TRUE, message == WM_SETFOCUS);
  897. break;
  898. case WM_LBUTTONDOWN:
  899. {
  900. RECT rect;
  901. // Don't draw anything if there's an update region pending.
  902. if (GetUpdateRect(hWnd, (LPRECT)&rect, FALSE) != 0)
  903. break;
  904. SetFocus(hWnd);
  905. SetCapture(hWnd);
  906. sycm.fMouseDn = TRUE;
  907. if (!FMagData(&sycm))
  908. DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE);
  909. }
  910. // Fall through to WM_MOUSEMOVE
  911. case WM_MOUSEMOVE:
  912. if (sycm.fMouseDn) {
  913. POINT pt;
  914. UTCHAR chMouseSymbol;
  915. pt.x = LOWORD(lParam);
  916. pt.y = HIWORD(lParam);
  917. ClientToScreen(hWnd, (LPPOINT)&pt);
  918. if (WindowFromPoint(pt) == hWnd) {
  919. ScreenToClient(hWnd, (LPPOINT)&pt);
  920. // convert back to a 'points'-like thing
  921. lParam = MAKELONG((WORD)pt.x, (WORD)pt.y);
  922. chMouseSymbol = (UTCHAR)ChFromSymLParam(&sycm, lParam);
  923. if (chMouseSymbol > chSymLast) {
  924. //
  925. // We're outside of current character range (but still
  926. // within the grid). Restore cursor and leave
  927. // magnified character.
  928. //
  929. if (sycm.fCursorOff) {
  930. sycm.fCursorOff = FALSE;
  931. ShowCursor(TRUE);
  932. }
  933. } else {
  934. //
  935. // We're in the grid and within the range of currently
  936. // displayed characters, display magnified character.
  937. //
  938. if (!sycm.fCursorOff) {
  939. sycm.fCursorOff = TRUE;
  940. ShowCursor(FALSE);
  941. }
  942. MoveSymbolSel(&sycm, chMouseSymbol);
  943. }
  944. } else {
  945. // Left grid, leave magnified character and restore cursor.
  946. if (sycm.fCursorOff) {
  947. sycm.fCursorOff = FALSE;
  948. ShowCursor(TRUE);
  949. }
  950. }
  951. }
  952. break;
  953. case WM_CANCELMODE:
  954. case WM_LBUTTONUP:
  955. if (sycm.fMouseDn)
  956. ExitMagnify(hWnd, &sycm);
  957. break;
  958. case WM_LBUTTONDBLCLK:
  959. // Send this character to the entry field.
  960. SendDlgItemMessage(hwndDialog, ID_STRING, WM_CHAR,
  961. (WPARAM)sycm.chCurr, 0L);
  962. break;
  963. case WM_GETDLGCODE:
  964. // Necessary to obtain arrow and tab messages.
  965. return (DLGC_WANTARROWS | DLGC_WANTCHARS);
  966. break;
  967. case WM_KEYDOWN:
  968. {
  969. UTCHAR chNew = sycm.chCurr;
  970. if (sycm.fMouseDn)
  971. break;
  972. switch (wParam)
  973. {
  974. case VK_LEFT:
  975. if (--chNew < chSymFirst)
  976. return 0L;
  977. break;
  978. case VK_UP:
  979. if ((chNew -= (UTCHAR)cchSymRow) < chSymFirst)
  980. return 0L;
  981. break;
  982. case VK_RIGHT:
  983. if (++chNew > chSymLast)
  984. return 0L;
  985. break;
  986. case VK_DOWN:
  987. if ((chNew += (UTCHAR)cchSymRow) > chSymLast)
  988. return 0L;
  989. break;
  990. default:
  991. return 0L;
  992. } /* switch (wParam) */
  993. if (!FMagData(&sycm))
  994. DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE);
  995. MoveSymbolSel(&sycm, (UTCHAR)chNew);
  996. }
  997. break;
  998. case WM_CHAR:
  999. if (sycm.fMouseDn)
  1000. break;
  1001. if (wParam >= chSymFirst && wParam <= chSymLast) {
  1002. if (!FMagData(&sycm))
  1003. DrawSymChOutlineHwnd(&sycm, hWnd, sycm.chCurr, FALSE, FALSE);
  1004. MoveSymbolSel(&sycm, (UTCHAR) wParam);
  1005. SendDlgItemMessage(hwndDialog, ID_STRING, WM_CHAR,
  1006. (WPARAM)sycm.chCurr, 0L);
  1007. }
  1008. break;
  1009. case WM_PAINT:
  1010. {
  1011. HDC hdc;
  1012. PAINTSTRUCT ps;
  1013. hdc = BeginPaint(hWnd, &ps);
  1014. DrawSymbolMap(&sycm, hdc);
  1015. EndPaint(hWnd, &ps);
  1016. return (TRUE);
  1017. }
  1018. default: /* Passes it on if unproccessed */
  1019. return (DefWindowProc(hWnd, message, wParam, lParam));
  1020. }
  1021. return 0L;
  1022. }
  1023. /****************************************************************************
  1024. FUNCTION: ChFromSymLParam(PSYCM, LPARAM)
  1025. PURPOSE: Determine the character to select from the mouse
  1026. position (lParam)
  1027. COMMENTS:
  1028. ****************************************************************************/
  1029. INT ChFromSymLParam(
  1030. PSYCM psycm,
  1031. LPARAM lParam)
  1032. {
  1033. return min(cchSymRow-1, max(0, ((INT) LOWORD(lParam)-1) / psycm->dxpBox))
  1034. + min(cchSymCol-1, max(0, ((INT) HIWORD(lParam)-1) / psycm->dypBox))
  1035. * cchSymRow + chSymFirst;
  1036. }
  1037. /****************************************************************************
  1038. FUNCTION: DrawSymChOutlineHwnd(PSYCM, HWND, UTCHAR, BOOL, BOOL);
  1039. PURPOSE: Gets a DC for hwnd, calls DrawSymChOutline.
  1040. COMMENTS:
  1041. ****************************************************************************/
  1042. VOID DrawSymChOutlineHwnd(
  1043. PSYCM psycm,
  1044. HWND hwnd,
  1045. UTCHAR ch,
  1046. BOOL fVisible,
  1047. BOOL fFocus)
  1048. {
  1049. HDC hdc = GetDC(hwnd);
  1050. DrawSymChOutline(psycm, hdc, ch, fVisible, fFocus);
  1051. ReleaseDC(hwnd, hdc);
  1052. }
  1053. /****************************************************************************
  1054. FUNCTION: RecalcCharMap(HWND, PSYCM, int, BOOL);
  1055. PURPOSE: Recalculate fixed character map data (font info, sizes, etc.)
  1056. COMMENTS:
  1057. ****************************************************************************/
  1058. VOID RecalcCharMap(
  1059. HWND hwndDlg,
  1060. PSYCM psycm,
  1061. INT iCombo,
  1062. BOOL fRedraw)
  1063. {
  1064. HDC hdc;
  1065. TEXTMETRIC tm;
  1066. UINT ch;
  1067. LPINT lpdxp;
  1068. HFONT hFont;
  1069. LOGFONT LogFont;
  1070. // Get rid of the old font handles.
  1071. if (hFontClipboard && hFontClipboard == psycm->hFont)
  1072. fDelClipboardFont = TRUE;
  1073. if (psycm->hFont && hFontClipboard != psycm->hFont)
  1074. DeleteObject(psycm->hFont);
  1075. if (psycm->hFontMag)
  1076. DeleteObject(psycm->hFontMag);
  1077. hdc = GetDC(hwndCharGrid);
  1078. /*
  1079. * Set up the LogFont structure.
  1080. */
  1081. // Make sure it fits in the grid.
  1082. LogFont.lfHeight = psycm->dypBox - 3; // Allow for whitespace.
  1083. // Set these guys to zero.
  1084. LogFont.lfWidth = LogFont.lfEscapement = LogFont.lfOrientation =
  1085. LogFont.lfWeight = 0;
  1086. // Set these at zero too.
  1087. LogFont.lfItalic = LogFont.lfUnderline = LogFont.lfStrikeOut =
  1088. LogFont.lfOutPrecision = LogFont.lfClipPrecision =
  1089. LogFont.lfQuality = LogFont.lfPitchAndFamily = 0;
  1090. // Let the facename and size define the font.
  1091. LogFont.lfCharSet = ANSI_CHARSET;
  1092. // Get the facename from the combo box.
  1093. SendDlgItemMessage(hwndDlg, ID_FONT, CB_GETLBTEXT, iCombo,
  1094. (LPARAM)(LPTSTR)LogFont.lfFaceName);
  1095. /*
  1096. * 27 Oct 92 GregoryW
  1097. * For now we don't have a way to determine if this is a
  1098. * Unicode font or an ANSI font. The best we can do is
  1099. * look at the face name to see if it is the one Unicode
  1100. * font we recognize.
  1101. */
  1102. if (!lstrcmpi(LogFont.lfFaceName, TEXT("Lucida Sans Unicode"))) {
  1103. LONG iCurSel;
  1104. psycm->fAnsiFont = FALSE;
  1105. // Enable Block listbox and set defaults appropriately.
  1106. EnableWindow(GetDlgItem(hwndDlg, ID_UNICODESUBSET), TRUE);
  1107. iCurSel = (LONG)SendDlgItemMessage(
  1108. hwndDlg,
  1109. ID_UNICODESUBSET,
  1110. CB_GETCURSEL,
  1111. 0,
  1112. 0L
  1113. );
  1114. UpdateSymbolSelection(
  1115. hwndDlg,
  1116. aSubsetData[iCurSel].BeginRange,
  1117. aSubsetData[iCurSel].EndRange
  1118. );
  1119. // Enable Previous button if not on first subset.
  1120. if (iCurSel > 0) {
  1121. EnableWindow(GetDlgItem(hwndDlg, ID_PREVSUBSET), TRUE);
  1122. } else {
  1123. EnableWindow(GetDlgItem(hwndDlg, ID_PREVSUBSET), FALSE);
  1124. }
  1125. // Enable Next button if not on last subset.
  1126. if (iCurSel < (cSubsets - 1)) {
  1127. EnableWindow(GetDlgItem(hwndDlg, ID_NEXTSUBSET), TRUE);
  1128. } else {
  1129. EnableWindow(GetDlgItem(hwndDlg, ID_NEXTSUBSET), FALSE);
  1130. }
  1131. } else {
  1132. // put back the ANSI defaults and disable Unicode Block listbox
  1133. psycm->fAnsiFont = TRUE;
  1134. UpdateSymbolSelection(hwndDlg, 32, 255);
  1135. EnableWindow(GetDlgItem(hwndDlg, ID_UNICODESUBSET), FALSE);
  1136. EnableWindow(GetDlgItem(hwndDlg, ID_NEXTSUBSET), FALSE);
  1137. EnableWindow(GetDlgItem(hwndDlg, ID_PREVSUBSET), FALSE);
  1138. }
  1139. // Create the font.
  1140. psycm->hFont = CreateFontIndirect(&LogFont);
  1141. hFont = SelectObject(hdc, psycm->hFont);
  1142. // Create the magnify font.
  1143. LogFont.lfHeight = psycm->dypMag - 5; // Allow for whitespace.
  1144. psycm->hFontMag = CreateFontIndirect(&LogFont);
  1145. /*
  1146. * Calculate new values and place in window data structure.
  1147. */
  1148. GetTextMetrics(hdc, &tm);
  1149. psycm->xpCh = 2;
  1150. psycm->ypCh = (4 + psycm->dypBox - tm.tmHeight) / 2;
  1151. lpdxp = (LPINT) psycm->rgdxp;
  1152. GetCharWidth(hdc, chSymFirst, chSymLast, lpdxp);
  1153. SelectObject(hdc, hFont);
  1154. for (ch = (UINT) chSymFirst; ch <= (UINT) chSymLast; ch++, lpdxp++)
  1155. {
  1156. *lpdxp = (psycm->dxpBox - *lpdxp) / 2 - 1;
  1157. }
  1158. ReleaseDC(hwndCharGrid, hdc);
  1159. psycm->xpMagCurr = 0; // No magnification data
  1160. if (fRedraw)
  1161. InvalidateRect(hwndCharGrid, NULL, TRUE);
  1162. }
  1163. /****************************************************************************
  1164. FUNCTION: DrawSymbolMap(PSYCM, HDC);
  1165. PURPOSE: Draw all of the pieces of the symbol character map
  1166. COMMENTS:
  1167. ****************************************************************************/
  1168. VOID DrawSymbolMap(
  1169. PSYCM psycm,
  1170. HDC hdc)
  1171. {
  1172. BOOL fFocus;
  1173. DrawSymbolGrid(psycm, hdc);
  1174. DrawSymbolChars(psycm, hdc);
  1175. /*
  1176. * We need to force the focus rect to paint if we have the focus
  1177. * since the old focus rect has been drawn over already.
  1178. */
  1179. if (fFocus = psycm->fFocusState)
  1180. psycm->fFocusState = FALSE;
  1181. DrawSymChOutline(psycm, hdc, psycm->chCurr, TRUE, fFocus);
  1182. }
  1183. void MoveTo(HDC hdc, int x, int y){
  1184. MoveToEx(hdc, x, y, NULL);
  1185. }
  1186. /****************************************************************************
  1187. FUNCTION: DrawSymbolGrid(PSYCM, HDC);
  1188. PURPOSE: Draw the symbol character map grid.
  1189. COMMENTS:
  1190. ****************************************************************************/
  1191. VOID DrawSymbolGrid(
  1192. PSYCM psycm,
  1193. HDC hdc)
  1194. {
  1195. INT cli; /* Count of lines */
  1196. INT xp, yp;
  1197. INT dxpBox = psycm->dxpBox;
  1198. INT dypBox = psycm->dypBox;
  1199. HPEN hpenOld;
  1200. hpenOld = SelectObject(hdc, CreatePen(PS_SOLID, 1,
  1201. GetSysColor(COLOR_WINDOWFRAME)));
  1202. // Draw horizontal lines.
  1203. xp = psycm->dxpCM + 1;
  1204. yp = 1;
  1205. cli = cchSymCol+1;
  1206. while (cli--)
  1207. {
  1208. MoveTo(hdc, 1, yp);
  1209. LineTo(hdc, xp, yp);
  1210. yp += dypBox;
  1211. }
  1212. // Draw vertical lines.
  1213. yp = psycm->dypCM;
  1214. xp = 1;
  1215. cli = cchSymRow+1;
  1216. while (cli--)
  1217. {
  1218. MoveTo(hdc, xp, 1);
  1219. LineTo(hdc, xp, yp);
  1220. xp += dxpBox;
  1221. }
  1222. DeleteObject(SelectObject(hdc, hpenOld));
  1223. }
  1224. /****************************************************************************
  1225. FUNCTION: DrawSymbolChars(PSYCM, HDC);
  1226. PURPOSE: Draw the symbol character map.
  1227. COMMENTS:
  1228. ****************************************************************************/
  1229. VOID DrawSymbolChars(
  1230. PSYCM psycm,
  1231. HDC hdc)
  1232. {
  1233. INT dxpBox = psycm->dxpBox;
  1234. INT dypBox = psycm->dypBox;
  1235. INT cch;
  1236. INT x, y;
  1237. INT yp;
  1238. TCHAR ch;
  1239. HFONT hFontOld;
  1240. RECT rect;
  1241. LPRECT lprect = (LPRECT) &rect;
  1242. LPINT lpdxp;
  1243. // Setup the font and colors.
  1244. hFontOld = (HFONT) SelectObject(hdc, psycm->hFont);
  1245. SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  1246. SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  1247. SetBkMode(hdc, OPAQUE);
  1248. // Draw characters.
  1249. cch = 1;
  1250. ch = chSymFirst;
  1251. lpdxp = (LPINT) psycm->rgdxp;
  1252. rect.top = 2;
  1253. yp = psycm->ypCh;
  1254. rect.bottom = rect.top + dypBox - 1;
  1255. for (y = 0; y++ < cchSymCol;)
  1256. {
  1257. rect.left = psycm->xpCh;
  1258. rect.right = rect.left + dxpBox - 1;
  1259. for (x = 0; x++ < cchSymRow && ch <= chSymLast;)
  1260. {
  1261. if (psycm->fAnsiFont) {
  1262. ExtTextOutA(hdc, rect.left + (*lpdxp++), yp,
  1263. ETO_OPAQUE | ETO_CLIPPED, lprect, &(CHAR)ch, 1, NULL);
  1264. } else
  1265. ExtTextOutW(hdc, rect.left + (*lpdxp++), yp,
  1266. ETO_OPAQUE | ETO_CLIPPED, lprect, &ch, 1, NULL);
  1267. ch++;
  1268. rect.left += dxpBox;
  1269. rect.right += dxpBox;
  1270. }
  1271. yp += dypBox;
  1272. rect.top += dypBox;
  1273. rect.bottom += dypBox;
  1274. }
  1275. SelectObject(hdc, hFontOld);
  1276. }
  1277. /****************************************************************************
  1278. FUNCTION: DrawSymChOutline(PSYCM, HDC, UTCHAR, BOOL, BOOL);
  1279. PURPOSE: Draw an outline around the symbol in the character map
  1280. COMMENTS: If fVisible, draw outline else erase it.
  1281. ****************************************************************************/
  1282. VOID DrawSymChOutline(
  1283. PSYCM psycm,
  1284. HDC hdc,
  1285. UTCHAR ch,
  1286. BOOL fVisible,
  1287. BOOL fFocus)
  1288. {
  1289. HBRUSH hbrOld;
  1290. RECT rc;
  1291. INT dxpBox = psycm->dxpBox;
  1292. INT dypBox = psycm->dypBox;
  1293. hbrOld = SelectObject(hdc,
  1294. CreateSolidBrush(GetSysColor(fVisible ?
  1295. COLOR_WINDOWFRAME :
  1296. COLOR_WINDOW)));
  1297. ch -= chSymFirst;
  1298. rc.left = (ch % cchSymRow) * dxpBox +2;
  1299. rc.right = rc.left + dxpBox -1;
  1300. rc.top = (ch / cchSymRow) * dypBox +2;
  1301. rc.bottom = rc.top + dypBox -1;
  1302. // Draw selection rectangle.
  1303. PatBlt( hdc, rc.left, rc.top-2, dxpBox-1, 1, PATCOPY);
  1304. PatBlt( hdc, rc.left, rc.bottom+1, dxpBox-1, 1, PATCOPY);
  1305. PatBlt( hdc, rc.left-2, rc.top, 1, dypBox-1, PATCOPY);
  1306. PatBlt( hdc, rc.right+1, rc.top, 1, dypBox-1, PATCOPY);
  1307. DeleteObject(SelectObject(hdc, GetStockObject(NULL_BRUSH)));
  1308. // Deal with the focus rectangle.
  1309. if (fFocus != psycm->fFocusState) {
  1310. DrawFocusRect(hdc, &rc);
  1311. psycm->fFocusState = fFocus;
  1312. }
  1313. SelectObject(hdc, hbrOld);
  1314. }
  1315. /****************************************************************************
  1316. FUNCTION: MoveSymbolSel(PSYCM, UTCHAR);
  1317. PURPOSE: Change the current symbol selection. Handles drawing of
  1318. magnified characters.
  1319. COMMENTS:
  1320. ****************************************************************************/
  1321. VOID MoveSymbolSel(
  1322. PSYCM psycm,
  1323. UTCHAR chNew)
  1324. {
  1325. HDC hdc;
  1326. HDC hdcMag = psycm->hdcMag;
  1327. RECT rc;
  1328. HFONT hFontOld;
  1329. HFONT hFontMag; // old font in memory dc
  1330. HPEN hpenOld;
  1331. UTCHAR chNorm = chNew - chSymFirst + 32;
  1332. INT dxpMag = psycm->dxpMag; // for quick reference
  1333. INT dypMag = psycm->dypMag;
  1334. INT ypMemSrc = psycm->ypDest;
  1335. INT ypMemDest = ypMemSrc ^ dypMag;
  1336. INT xpCurr = psycm->xpMagCurr;
  1337. INT ypCurr = psycm->ypMagCurr;
  1338. INT xpNew = psycm->xpCM + (psycm->dxpBox * (chNorm % cchSymRow));
  1339. INT ypNew = psycm->ypCM + (psycm->dypBox * ((chNorm / cchSymRow) - 1));
  1340. INT dxpCh; // width of extra character space (used to center char in box)
  1341. INT dypCh;
  1342. if (((chNew == (UTCHAR)psycm->chCurr) && FMagData(psycm)))
  1343. return;
  1344. /*
  1345. * Don't draw a magnified character if the char grid has an update
  1346. * region or is not visible.
  1347. */
  1348. if (!IsWindowVisible(hwndCharGrid) || GetUpdateRect(hwndCharGrid, &rc, FALSE))
  1349. return;
  1350. hdc = GetDC(hwndDialog);
  1351. // Setup the magnified font character.
  1352. hFontMag = SelectObject(hdcMag, psycm->hFontMag);
  1353. { SIZE sz;
  1354. GetTextExtentPoint(hdcMag, &chNew, 1, &sz);
  1355. dxpCh = (dxpMag - (INT)sz.cx) / 2 - 1;
  1356. dypCh = (dypMag - (INT)sz.cy) / 2 - 1;
  1357. }
  1358. hpenOld = SelectObject(hdc, CreatePen(PS_SOLID, 1,
  1359. GetSysColor(COLOR_WINDOWFRAME)));
  1360. hFontOld = SelectObject(hdc, psycm->hFontMag);
  1361. // Copy screen data to offscreen bitmap.
  1362. BitBlt(hdcMag, 0, ypMemDest, dxpMag, dypMag, hdc, xpNew, ypNew, SRCCOPY);
  1363. // Setup DC.
  1364. SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  1365. SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  1366. SetBkMode(hdc, OPAQUE);
  1367. if (FMagData(psycm))
  1368. {
  1369. INT xpT = xpNew - xpCurr; // point of overlap in offscreen data
  1370. INT ypT = ypNew - ypCurr;
  1371. INT dxpT = dxpMag - abs(xpT); // size of overlap
  1372. INT dypT = dypMag - abs(ypT);
  1373. if ((dxpT > 0) && (dypT > 0))
  1374. {
  1375. INT xpTmax, ypTmax; // max(0, xpT);
  1376. INT xpTmin, ypTmin; // min(0, xpT);
  1377. INT xpTnmin, ypTnmin; // min(0, -xpT);
  1378. if (xpT < 0)
  1379. {
  1380. xpTnmin = - (xpTmin = xpT);
  1381. xpTmax = 0;
  1382. }
  1383. else
  1384. {
  1385. xpTmax = xpT;
  1386. xpTnmin = xpTmin = 0;
  1387. }
  1388. if (ypT < 0)
  1389. {
  1390. ypTnmin = - (ypTmin = ypT);
  1391. ypTmax = 0;
  1392. }
  1393. else
  1394. {
  1395. ypTmax = ypT;
  1396. ypTnmin = ypTmin = 0;
  1397. }
  1398. rc.left = xpTmax;
  1399. rc.right = xpTmin + dxpMag;
  1400. rc.top = ypTmax + ypMemSrc;
  1401. rc.bottom= ypTmin + dypMag + ypMemSrc;
  1402. // Copy overlapping offscreen data.
  1403. BitBlt(hdcMag, xpTnmin, ypTnmin + ypMemDest, dxpT, dypT,
  1404. hdcMag, xpTmax, ypTmax + ypMemSrc, SRCCOPY);
  1405. // Print part of char over old screen data.
  1406. if (psycm->fAnsiFont) {
  1407. ExtTextOutA(hdcMag, xpT + dxpCh, ypT + dypCh + ypMemSrc,
  1408. ETO_OPAQUE | ETO_CLIPPED, (LPRECT) &rc, &(CHAR)chNew, 1, NULL);
  1409. } else
  1410. ExtTextOutW(hdcMag, xpT + dxpCh, ypT + dypCh + ypMemSrc,
  1411. ETO_OPAQUE | ETO_CLIPPED, (LPRECT) &rc, &chNew, 1, NULL);
  1412. }
  1413. // Restore old screen data.
  1414. BitBlt(hdc, xpCurr, ypCurr, dxpMag, dypMag, hdcMag, 0, ypMemSrc, SRCCOPY);
  1415. }
  1416. rc.right = (psycm->xpMagCurr = rc.left = xpNew) + dxpMag - 2;
  1417. rc.bottom = (psycm->ypMagCurr = rc.top = ypNew) + dypMag - 2;
  1418. // The rectangle.
  1419. MoveTo(hdc, rc.left, rc.top);
  1420. LineTo(hdc, rc.left, rc.bottom - 1);
  1421. LineTo(hdc, rc.right - 1, rc.bottom - 1);
  1422. LineTo(hdc, rc.right - 1, rc.top);
  1423. LineTo(hdc, rc.left, rc.top);
  1424. // The shadow.
  1425. MoveTo(hdc, rc.right, rc.top + 1);
  1426. LineTo(hdc, rc.right, rc.bottom);
  1427. LineTo(hdc, rc.left, rc.bottom);
  1428. MoveTo(hdc, rc.right + 1, rc.top + 2);
  1429. LineTo(hdc, rc.right + 1, rc.bottom + 1);
  1430. LineTo(hdc, rc.left + 1, rc.bottom + 1);
  1431. rc.left++;
  1432. rc.top++;
  1433. rc.right--;
  1434. rc.bottom--;
  1435. // Draw magnified character on screen.
  1436. if (psycm->fAnsiFont) {
  1437. ExtTextOutA(hdc, xpNew + dxpCh, ypNew + dypCh,
  1438. ETO_OPAQUE | ETO_CLIPPED, (LPRECT) &rc, &(CHAR)chNew, 1, NULL);
  1439. } else
  1440. ExtTextOutW(hdc, xpNew + dxpCh, ypNew + dypCh,
  1441. ETO_OPAQUE | ETO_CLIPPED, (LPRECT) &rc, &chNew, 1, NULL);
  1442. psycm->ypDest = ypMemDest;
  1443. DeleteObject(SelectObject(hdc, hpenOld));
  1444. SelectObject(hdc, hFontOld);
  1445. SelectObject(hdcMag, hFontMag);
  1446. UpdateKeystrokeText(hdc, chNew, TRUE);
  1447. ReleaseDC(hwndDialog, hdc);
  1448. psycm->chCurr = chNew;
  1449. }
  1450. /****************************************************************************
  1451. FUNCTION: RestoreSymMag(PSYCM);
  1452. PURPOSE: Restore the screen data under the magnifier.
  1453. COMMENTS:
  1454. ****************************************************************************/
  1455. VOID RestoreSymMag(
  1456. PSYCM psycm)
  1457. {
  1458. if (FMagData(psycm))
  1459. {
  1460. HDC hdc = GetDC(hwndDialog);
  1461. BitBlt(hdc, psycm->xpMagCurr, psycm->ypMagCurr,
  1462. psycm->dxpMag, psycm->dypMag,
  1463. psycm->hdcMag, 0, psycm->ypDest, SRCCOPY);
  1464. ReleaseDC(hwndDialog, hdc);
  1465. psycm->xpMagCurr = 0; // flag - no data offscreen (see FMagData)
  1466. }
  1467. }
  1468. /****************************************************************************
  1469. FUNCTION: FontLoadProc(LPLOGFONT, NEWTEXTMETRICEX*, short, LPTSTR);
  1470. PURPOSE: Used by EnumFonts to load our combo box with all the fonts
  1471. installed in the system.
  1472. COMMENTS:
  1473. ****************************************************************************/
  1474. INT APIENTRY FontLoadProc(LPLOGFONT lpLogFont,
  1475. NEWTEXTMETRICEX* lpTextMetric,
  1476. DWORD nFontType,
  1477. LPARAM lpData)
  1478. {
  1479. INT iPos;
  1480. TCHAR szFace[LF_FACESIZE];
  1481. // Check for duplicates.
  1482. iPos = (INT)SendDlgItemMessage((HWND)lpData, ID_FONT, CB_FINDSTRING, (WPARAM)-1,
  1483. (LPARAM)&lpLogFont->lfFaceName);
  1484. if (iPos == CB_ERR) {
  1485. NotInListYet:
  1486. // Doesn't exist, insert the facename into the combo box.
  1487. iPos = (INT)SendDlgItemMessage((HWND)lpData, ID_FONT,
  1488. CB_ADDSTRING, 0,
  1489. (LPARAM)&lpLogFont->lfFaceName);
  1490. } else {
  1491. // make sure it is not just a substring (want a full match)
  1492. SendDlgItemMessage((HWND)lpData, ID_FONT, CB_GETLBTEXT, iPos, (LPARAM)(LPTSTR)szFace);
  1493. if (lstrcmpi(szFace, lpLogFont->lfFaceName))
  1494. goto NotInListYet;
  1495. // Already exists, blow out now if this is not a true type font.
  1496. if (!(nFontType & TRUETYPE_FONTTYPE))
  1497. return (1);
  1498. }
  1499. /*
  1500. * Store the pertinant font information in the combo item data.
  1501. */
  1502. if ((iPos != CB_ERR) && (iPos != CB_ERRSPACE)) {
  1503. ITEMDATA ItemData;
  1504. DWORD ntmFlags = lpTextMetric->ntmTm.ntmFlags;
  1505. SHORT sFontType = 0;
  1506. if (ntmFlags & NTM_PS_OPENTYPE)
  1507. {
  1508. sFontType = PS_OPENTYPE_FONT;
  1509. }
  1510. else if (ntmFlags & NTM_TYPE1)
  1511. {
  1512. sFontType = TYPE1_FONT;
  1513. }
  1514. else if (nFontType & TRUETYPE_FONTTYPE)
  1515. {
  1516. if (ntmFlags & NTM_TT_OPENTYPE)
  1517. {
  1518. sFontType = TT_OPENTYPE_FONT;
  1519. }
  1520. else
  1521. sFontType = TRUETYPE_FONT;
  1522. }
  1523. ItemData.FontType = sFontType;
  1524. ItemData.CharSet = lpLogFont->lfCharSet;
  1525. ItemData.PitchAndFamily = lpLogFont->lfPitchAndFamily;
  1526. SendDlgItemMessage((HWND)lpData, ID_FONT, CB_SETITEMDATA, iPos,
  1527. *(DWORD *)&ItemData);
  1528. }
  1529. // Continue enumeration.
  1530. return (1);
  1531. }
  1532. /****************************************************************************
  1533. FUNCTION: GetEditText(HWND);
  1534. PURPOSE: Returns HANDLE containing the text in the edit control.
  1535. COMMENTS: Caller is responsible for freeing this handle!
  1536. ****************************************************************************/
  1537. HANDLE GetEditText(
  1538. HWND hwndDlg)
  1539. {
  1540. INT cchText;
  1541. HWND hwndEditCtl;
  1542. HANDLE hmem;
  1543. LPTSTR lpstrText;
  1544. LRESULT dwSel;
  1545. hwndEditCtl = GetDlgItem(hwndDlg, ID_STRING);
  1546. cchText = GetWindowTextLength(hwndEditCtl);
  1547. hmem = GlobalAlloc(0, CTOB((cchText + 1)));
  1548. lpstrText = (LPTSTR)GlobalLock(hmem);
  1549. cchText = GetWindowText(hwndEditCtl, lpstrText, cchText+1);
  1550. dwSel = SendMessage(hwndEditCtl, EM_GETSEL, 0, 0L);
  1551. if (LOWORD(dwSel) != HIWORD(dwSel)) {
  1552. // If there is a selection, then only get the selected text.
  1553. *(lpstrText + HIWORD(dwSel)) = TEXT('\0');
  1554. lstrcpy(lpstrText, lpstrText + LOWORD(dwSel));
  1555. }
  1556. GlobalUnlock(hmem);
  1557. if (cchText == 0)
  1558. hmem = GlobalFree(hmem);
  1559. return (hmem);
  1560. }
  1561. /****************************************************************************
  1562. FUNCTION: CopyString(HWND);
  1563. PURPOSE: Implement the Copy function.
  1564. COMMENTS:
  1565. ****************************************************************************/
  1566. VOID CopyString(
  1567. HWND hwndDlg)
  1568. {
  1569. HANDLE hmem;
  1570. LPTSTR lpstrText;
  1571. if (hmem = GetEditText(hwndDlg)) {
  1572. lpstrText = (LPTSTR)GlobalLock(hmem);
  1573. // Copying string to clipboard.
  1574. if (OpenClipboard(hwndDlg)) {
  1575. EmptyClipboard();
  1576. SendRTFToClip(hwndDlg, lpstrText);
  1577. #ifdef UNICODE
  1578. SetClipboardData(CF_UNICODETEXT, hmem);
  1579. #else
  1580. SetClipboardData(CF_TEXT, hmem);
  1581. #endif
  1582. CloseClipboard();
  1583. } else {
  1584. // If we couldn't open the clipboard, then we need to free memory.
  1585. GlobalUnlock(hmem);
  1586. GlobalFree(hmem);
  1587. }
  1588. }
  1589. }
  1590. /****************************************************************************
  1591. FUNCTION: SendRTFToClip(HWND, LPTSTR);
  1592. PURPOSE: Put the string in the clipboard using Rich Text Format.
  1593. COMMENTS: Assumes that the clipboard has already been opened.
  1594. ****************************************************************************/
  1595. VOID SendRTFToClip(
  1596. HWND hwndDlg,
  1597. LPTSTR lpstrText)
  1598. {
  1599. INT iCurrFont;
  1600. ITEMDATA ItemData;
  1601. TCHAR szFaceName[LF_FACESIZE];
  1602. HANDLE hmemRTF, hmemClip;
  1603. LPTSTR lpstrClipString;
  1604. TCHAR achHeader[] = TEXT("{\\rtf1\\ansi {\\fonttbl{\\f0\\");
  1605. TCHAR achMiddle[] = TEXT(";}}\\sectd\\pard\\plain\\f0 ");
  1606. #define MAXLENGTHFONTFAMILY 8
  1607. #define ALITTLEEXTRA 10 // Covers extra characters + length of font size.
  1608. iCurrFont = (INT)SendDlgItemMessage(hwndDlg, ID_FONT, CB_GETCURSEL, 0, 0L);
  1609. // Get the item data - contains fonttype, charset, and pitchandfamily.
  1610. *(DWORD *)&ItemData = (DWORD)SendDlgItemMessage(hwndDlg, ID_FONT, CB_GETITEMDATA,
  1611. iCurrFont, 0L);
  1612. // Get the facename from the combo box.
  1613. SendDlgItemMessage(hwndDlg, ID_FONT, CB_GETLBTEXT, iCurrFont,
  1614. (LPARAM)(LPTSTR)szFaceName);
  1615. hmemRTF = GlobalAlloc(0, CTOB(lstrlen((LPTSTR)achHeader) +
  1616. MAXLENGTHFONTFAMILY +
  1617. lstrlen(szFaceName) +
  1618. lstrlen((LPTSTR)achMiddle) +
  1619. 4 * lstrlen(lpstrText) + // 4 times in case they're all > 7 bits
  1620. ALITTLEEXTRA));
  1621. if (hmemRTF == NULL)
  1622. return;
  1623. // Allocate memory for local storage of clipboard string for owner draw.
  1624. if (hmemClip = GlobalAlloc(0, CTOB(lstrlen(lpstrText) + 1))) {
  1625. // Get rid of old guys.
  1626. if (hstrClipboard)
  1627. GlobalFree(hstrClipboard);
  1628. if (fDelClipboardFont) {
  1629. fDelClipboardFont = FALSE;
  1630. DeleteObject(hFontClipboard);
  1631. }
  1632. // Save this stuff away for owner drawing in a clipboard viewer.
  1633. hFontClipboard = sycm.hFont;
  1634. hstrClipboard = hmemClip;
  1635. lstrcpy(GlobalLock(hstrClipboard), lpstrText);
  1636. GlobalUnlock(hstrClipboard);
  1637. } else {
  1638. GlobalFree(hmemRTF);
  1639. return;
  1640. }
  1641. lpstrClipString = GlobalLock(hmemRTF);
  1642. lstrcpy(lpstrClipString, achHeader);
  1643. if (ItemData.CharSet == SYMBOL_CHARSET) {
  1644. lstrcat(lpstrClipString, (LPTSTR)TEXT("ftech "));
  1645. } else {
  1646. // top four bits specify family
  1647. switch (ItemData.PitchAndFamily & 0xf0) {
  1648. case FF_DECORATIVE:
  1649. lstrcat(lpstrClipString, (LPTSTR)TEXT("fdecor "));
  1650. break;
  1651. case FF_MODERN:
  1652. lstrcat(lpstrClipString, (LPTSTR)TEXT("fmodern "));
  1653. break;
  1654. case FF_ROMAN:
  1655. lstrcat(lpstrClipString, (LPTSTR)TEXT("froman "));
  1656. break;
  1657. case FF_SCRIPT:
  1658. lstrcat(lpstrClipString, (LPTSTR)TEXT("fscript "));
  1659. break;
  1660. case FF_SWISS:
  1661. lstrcat(lpstrClipString, (LPTSTR)TEXT("fswiss "));
  1662. break;
  1663. default:
  1664. break;
  1665. }
  1666. }
  1667. lstrcat(lpstrClipString, szFaceName);
  1668. lstrcat(lpstrClipString, (LPTSTR)achMiddle);
  1669. /*
  1670. * We need to do the text character by character, making sure
  1671. * that we output a special sequence \'hh for characters bigger
  1672. * than 7 bits long!
  1673. */
  1674. lpstrClipString = (LPTSTR)(lpstrClipString + lstrlen(lpstrClipString));
  1675. while (*lpstrText) {
  1676. if ((UTCHAR)*lpstrText < 128) {
  1677. if (*lpstrText == TEXT('\\') || *lpstrText == TEXT('{') || *lpstrText == TEXT('}'))
  1678. /*
  1679. * Need to preface these symbols with a '\' since they are
  1680. * special control characters for RTF.
  1681. */
  1682. *lpstrClipString++ = TEXT('\\');
  1683. *lpstrClipString++ = *lpstrText++;
  1684. } else {
  1685. *lpstrClipString++ = TEXT('\\');
  1686. *lpstrClipString++ = TEXT('\'');
  1687. #ifdef BUG
  1688. //
  1689. //PERF - GregoryW 23/10/92 need a Unicode version of itoa...
  1690. //
  1691. _itoa(*(UTCHAR FAR *)lpstrText++, achMiddle, 16);
  1692. #else
  1693. wsprintf(achMiddle, TEXT("%x"), (INT)*lpstrText);
  1694. lpstrText++;
  1695. #endif
  1696. *lpstrClipString++ = achMiddle[0];
  1697. *lpstrClipString++ = achMiddle[1];
  1698. }
  1699. }
  1700. *lpstrClipString++ = TEXT('}');
  1701. *lpstrClipString = TEXT('\0');
  1702. if (!wCFRichText) {
  1703. TCHAR szRTF[80];
  1704. LoadString(hInst, IDS_RTF, szRTF, BTOC(sizeof(szRTF)) - 1);
  1705. wCFRichText = RegisterClipboardFormat(szRTF);
  1706. }
  1707. // Put RTF and OwnerDisplay formats in the clipboard.
  1708. SetClipboardData(wCFRichText, hmemRTF);
  1709. SetClipboardData(CF_OWNERDISPLAY, NULL);
  1710. }
  1711. /****************************************************************************
  1712. FUNCTION: PointsToHeight(int);
  1713. PURPOSE: Calculates the height in pixels of the specified point
  1714. size for the current display.
  1715. COMMENTS:
  1716. ****************************************************************************/
  1717. INT PointsToHeight(INT iPoints)
  1718. {
  1719. HDC hdc;
  1720. INT iHeight;
  1721. hdc = GetDC(HWND_DESKTOP);
  1722. iHeight = MulDiv(iPoints, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  1723. ReleaseDC(HWND_DESKTOP, hdc);
  1724. return(iHeight);
  1725. }
  1726. /****************************************************************************
  1727. FUNCTION: UpdateKeystrokeText(HDC, UTCHAR, BOOL);
  1728. PURPOSE: Calculates and updates the text string displayed in the
  1729. Keystroke field of the status bar.
  1730. COMMENTS: Repaints status field if fRedraw == TRUE.
  1731. ****************************************************************************/
  1732. VOID UpdateKeystrokeText(
  1733. HDC hdc,
  1734. UTCHAR chNew,
  1735. BOOL fRedraw)
  1736. {
  1737. TCHAR szUnshifted[2];
  1738. SHORT vkRes;
  1739. #ifdef UNICODE
  1740. if (chNew > 255) {
  1741. lstrcpy(szKeystrokeText, szUnicodeLabel);
  1742. wsprintf((LPTSTR)(szKeystrokeText + iUnicodeLabelStart), TEXT("U+%04x"), chNew);
  1743. } else {
  1744. #endif
  1745. lstrcpy(szKeystrokeText, szKeystrokeLabel);
  1746. if (chNew == TEXT(' ')) {
  1747. lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szSpace);
  1748. } else {
  1749. vkRes = VkKeyScan(chNew);
  1750. /*
  1751. * Map the virtual key code into an unshifted character value
  1752. */
  1753. szUnshifted[0] = (TCHAR)MapVirtualKey(LOBYTE(vkRes), 2);
  1754. szUnshifted[1] = TEXT('\0');
  1755. switch(HIBYTE(vkRes)) {
  1756. case 0: // Unshifted char.
  1757. case 1: // Character is shifted, just display the shifted char.
  1758. szKeystrokeText[iKeystrokeTextStart] = chNew;
  1759. szKeystrokeText[iKeystrokeTextStart + 1] = TEXT('\0');
  1760. break;
  1761. case 2: // Character is control character.
  1762. lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szCtrl);
  1763. lstrcat(szKeystrokeText, (LPTSTR)szUnshifted);
  1764. break;
  1765. case 6: // Character is CONTROL+ALT.
  1766. lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szCtrlAlt);
  1767. lstrcat(szKeystrokeText, (LPTSTR)szUnshifted);
  1768. break;
  1769. case 7: // Character is SHIFT+CONTROL+ALT.
  1770. lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szShiftCtrlAlt);
  1771. lstrcat(szKeystrokeText, (LPTSTR)szUnshifted);
  1772. break;
  1773. default: // Character created via Alt + Numpad
  1774. lstrcpy((LPTSTR)(szKeystrokeText + iKeystrokeTextStart), szAlt);
  1775. wsprintf((LPTSTR)(szKeystrokeText + lstrlen(szKeystrokeText)), TEXT("%d"), chNew);
  1776. break;
  1777. }
  1778. }
  1779. #ifdef UNICODE
  1780. }
  1781. #endif
  1782. if (fRedraw)
  1783. PaintStatusLine(hdc, FALSE, TRUE);
  1784. }
  1785. /****************************************************************************
  1786. FUNCTION: UpdateHelpText(LPMSG, HWND);
  1787. PURPOSE: Calculates if the Help string needs to be updated, and does
  1788. so if necessary.
  1789. COMMENTS: If hwndCtrl is not NULL, then it specifies the window handle
  1790. of the control gaining focus, and lpmsg is ignored.
  1791. If hwndCtrl is NULL, then lpmsg must point to a valid message
  1792. structure. If it is a tab character, then we calculate
  1793. what the next control is that will receive the focus.
  1794. ****************************************************************************/
  1795. BOOL UpdateHelpText(
  1796. LPMSG lpmsg,
  1797. HWND hwndCtrl)
  1798. {
  1799. HDC hdc;
  1800. BOOL fPaintStatus = FALSE;
  1801. BOOL fRet = TRUE;
  1802. if (hwndCtrl != NULL) {
  1803. fPaintStatus = TRUE;
  1804. iControl = GetDlgCtrlID(hwndCtrl);
  1805. } else if (lpmsg->message == WM_KEYDOWN) {
  1806. if (lpmsg->wParam == VK_TAB) {
  1807. fPaintStatus = TRUE;
  1808. hwndCtrl = GetNextDlgTabItem(hwndDialog,
  1809. GetDlgItem(hwndDialog, iControl),
  1810. (BOOL)(GetKeyState(VK_SHIFT) & 0x8000));
  1811. iControl = GetDlgCtrlID(hwndCtrl);
  1812. if (iControl == ID_STRING) {
  1813. /*
  1814. * Do this ourselves, otherwise default action will select
  1815. * the whole edit control.
  1816. */
  1817. SetFocus(hwndCtrl);
  1818. fRet = FALSE;
  1819. }
  1820. if (iControl == ID_CHARGRID) {
  1821. /*
  1822. * Set the default button back to "Select". The default
  1823. * might have changed to the "Next" or "Previous" button.
  1824. */
  1825. SendMessage(hwndDialog, DM_SETDEFID, ID_SELECT, 0);
  1826. }
  1827. } else if (lpmsg->wParam == VK_F1) {
  1828. PostMessage(hwndDialog, WM_COMMAND, ID_HELP, 0L);
  1829. }
  1830. }
  1831. if (fPaintStatus) {
  1832. hdc = GetDC(hwndDialog);
  1833. PaintStatusLine(hdc, TRUE, FALSE);
  1834. ReleaseDC(hwndDialog, hdc);
  1835. }
  1836. return (fRet);
  1837. }
  1838. /****************************************************************************
  1839. FUNCTION: UpdateSymbolSelection(HWND, INT, INT);
  1840. PURPOSE: Updates the values of the following global values:
  1841. chSymFirst
  1842. chSymLast
  1843. sycm.chCurr
  1844. Subsets in the Unicode character set have different numbers
  1845. of characters. We have to do some bounds checking in order
  1846. to set an appropriate sycm.chCurr value. The "Keystroke"
  1847. status field is updated.
  1848. COMMENTS: Repaints Keystroke field if HWND != NULL.
  1849. ****************************************************************************/
  1850. VOID UpdateSymbolSelection(
  1851. HWND hwnd,
  1852. INT FirstChar,
  1853. INT LastChar)
  1854. {
  1855. UTCHAR chSymOffset;
  1856. chSymOffset = sycm.chCurr - chSymFirst;
  1857. chSymFirst = (UTCHAR)FirstChar;
  1858. chSymLast = (UTCHAR)LastChar;
  1859. sycm.chCurr = chSymOffset + chSymFirst;
  1860. if (sycm.chCurr > chSymLast) {
  1861. sycm.chCurr = chSymFirst;
  1862. }
  1863. if (hwnd != NULL) {
  1864. HDC hdc;
  1865. hdc = GetDC(hwnd);
  1866. UpdateKeystrokeText(hdc, sycm.chCurr, TRUE);
  1867. ReleaseDC(hwnd, hdc);
  1868. } else {
  1869. UpdateKeystrokeText(NULL, sycm.chCurr, FALSE);
  1870. }
  1871. }
  1872. /****************************************************************************
  1873. FUNCTION: PaintStatusLine(HDC, BOOL, BOOL);
  1874. PURPOSE: Paints the Help and Keystroke fields in the status bar.
  1875. COMMENTS: Repaints Help field if fHelp == TRUE, repaints the Keystroke
  1876. field if fKeystroke == TRUE.
  1877. ****************************************************************************/
  1878. VOID PaintStatusLine(
  1879. HDC hdc,
  1880. BOOL fHelp,
  1881. BOOL fKeystroke)
  1882. {
  1883. HFONT hfontOld = NULL;
  1884. RECT rect;
  1885. INT dyBorder;
  1886. TCHAR szHelpText[100];
  1887. dyBorder = GetSystemMetrics(SM_CYBORDER);
  1888. if (hfontStatus)
  1889. hfontOld = SelectObject(hdc, hfontStatus);
  1890. // set the text and background colors
  1891. SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
  1892. SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
  1893. if (fHelp) {
  1894. // now the help text, with a gray background
  1895. rect.top = rcStatusLine.top + 3 * dyBorder;
  1896. rect.bottom = rcStatusLine.bottom - 3 * dyBorder;
  1897. rect.left = 9 * dyBorder;
  1898. rect.right = rect.left + dxHelpField - 2 * dyBorder;
  1899. LoadString(hInst, iControl, szHelpText, BTOC(sizeof(szHelpText)) - 1);
  1900. ExtTextOut(hdc, rect.left + dyBorder * 2, rect.top,
  1901. ETO_OPAQUE | ETO_CLIPPED, &rect, szHelpText,
  1902. lstrlen(szHelpText), NULL);
  1903. }
  1904. if (fKeystroke) {
  1905. // now the keystroke text, with a gray background
  1906. rect.top = rcStatusLine.top + 3 * dyBorder;
  1907. rect.bottom = rcStatusLine.bottom - 3 * dyBorder;
  1908. rect.right = rcStatusLine.right - 9 * dyBorder;
  1909. rect.left = rect.right - dxKeystrokeField + 2 * dyBorder;
  1910. ExtTextOut(hdc, rect.left + dyBorder * 2, rect.top,
  1911. ETO_OPAQUE | ETO_CLIPPED, &rect, szKeystrokeText,
  1912. lstrlen(szKeystrokeText), NULL);
  1913. }
  1914. if (hfontOld)
  1915. SelectObject(hdc, hfontOld);
  1916. }
  1917. /****************************************************************************
  1918. FUNCTION: DrawFamilyComboItem(LPDRAWITEMSTRUCT)
  1919. PURPOSE: Paints the font facenames and TT bitmap in the font combo box.
  1920. COMMENTS:
  1921. ****************************************************************************/
  1922. BOOL DrawFamilyComboItem(
  1923. LPDRAWITEMSTRUCT lpdis)
  1924. {
  1925. HDC hDC, hdcMem;
  1926. DWORD rgbBack, rgbText;
  1927. TCHAR szFace[LF_FACESIZE];
  1928. HBITMAP hOld;
  1929. INT dy;
  1930. SHORT sFontType;
  1931. hDC = lpdis->hDC;
  1932. if (lpdis->itemState & ODS_SELECTED) {
  1933. rgbBack = SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
  1934. rgbText = SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
  1935. } else {
  1936. rgbBack = SetBkColor(hDC, GetSysColor(COLOR_WINDOW));
  1937. rgbText = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  1938. }
  1939. SendMessage(lpdis->hwndItem, CB_GETLBTEXT, lpdis->itemID, (LPARAM)(LPTSTR)szFace);
  1940. ExtTextOut(hDC, lpdis->rcItem.left + DX_BITMAP, lpdis->rcItem.top, ETO_OPAQUE | ETO_CLIPPED, &lpdis->rcItem, szFace, lstrlen(szFace), NULL);
  1941. hdcMem = CreateCompatibleDC(hDC);
  1942. if (hdcMem) {
  1943. if (hbmFont) {
  1944. hOld = SelectObject(hdcMem, hbmFont);
  1945. sFontType = ((ITEMDATA FAR *)&(lpdis->itemData))->FontType;
  1946. if (sFontType)
  1947. {
  1948. int xSrc;
  1949. dy = ((lpdis->rcItem.bottom - lpdis->rcItem.top) - DY_BITMAP) / 2;
  1950. if (sFontType & TRUETYPE_FONT)
  1951. xSrc = 0;
  1952. else if (sFontType & TT_OPENTYPE_FONT)
  1953. xSrc = 2;
  1954. else if (sFontType & PS_OPENTYPE_FONT)
  1955. xSrc = 3;
  1956. else if (sFontType & TYPE1_FONT)
  1957. xSrc = 4;
  1958. BitBlt(hDC, lpdis->rcItem.left, lpdis->rcItem.top + dy, DX_BITMAP, DY_BITMAP, hdcMem,
  1959. xSrc*DX_BITMAP, lpdis->itemState & ODS_SELECTED ? DY_BITMAP : 0, SRCCOPY);
  1960. }
  1961. SelectObject(hdcMem, hOld);
  1962. }
  1963. DeleteDC(hdcMem);
  1964. }
  1965. SetTextColor(hDC, rgbText);
  1966. SetBkColor(hDC, rgbBack);
  1967. return TRUE;
  1968. }
  1969. /****************************************************************************
  1970. FUNCTION: LoadBitmaps(int)
  1971. PURPOSE: This routine loads DIB bitmaps, and "fixes up" their color tables
  1972. so that we get the desired result for the device we are on.
  1973. COMMENTS: This routine requires:
  1974. - The DIB is a 16 color DIB authored with the standard windows colors.
  1975. - bright blue (00 00 FF) is converted to the background color.
  1976. - light grey (C0 C0 C0) is replaced with the button face color.
  1977. - dark grey (80 80 80) is replaced with the button shadow color.
  1978. This means you can't have any of these colors in your bitmap.
  1979. ****************************************************************************/
  1980. HBITMAP LoadBitmaps(INT id)
  1981. {
  1982. HDC hdc;
  1983. HANDLE h;
  1984. DWORD FAR *p;
  1985. LPBYTE lpBits;
  1986. HANDLE hRes;
  1987. LPBITMAPINFOHEADER lpBitmapInfo;
  1988. INT numcolors;
  1989. DWORD rgbSelected;
  1990. DWORD rgbUnselected;
  1991. HBITMAP hbm;
  1992. rgbSelected = GetSysColor(COLOR_HIGHLIGHT);
  1993. // Flip the colors.
  1994. rgbSelected = RGB(GetBValue(rgbSelected),
  1995. GetGValue(rgbSelected),
  1996. GetRValue(rgbSelected));
  1997. rgbUnselected = GetSysColor(COLOR_WINDOW);
  1998. // Flip the colors.
  1999. rgbUnselected = RGB(GetBValue(rgbUnselected),
  2000. GetGValue(rgbUnselected),
  2001. GetRValue(rgbUnselected));
  2002. h = FindResource(hInst, MAKEINTRESOURCE(id), RT_BITMAP);
  2003. hRes = LoadResource(hInst, h);
  2004. /* Lock the bitmap and get a pointer to the color table. */
  2005. lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes);
  2006. if (!lpBitmapInfo)
  2007. return FALSE;
  2008. p = (DWORD FAR *)((LPSTR)(lpBitmapInfo) + lpBitmapInfo->biSize);
  2009. /* Search for the Solid Blue entry and replace it with the current
  2010. * background RGB.
  2011. */
  2012. numcolors = 16;
  2013. while (numcolors-- > 0) {
  2014. if (*p == BACKGROUND)
  2015. *p = rgbUnselected;
  2016. else if (*p == BACKGROUNDSEL)
  2017. *p = rgbSelected;
  2018. p++;
  2019. }
  2020. UnlockResource(hRes);
  2021. /* Now create the DIB. */
  2022. lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes);
  2023. /* First skip over the header structure */
  2024. lpBits = (LPBYTE)(lpBitmapInfo + 1);
  2025. /* Skip the color table entries, if any */
  2026. lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
  2027. /* Create a color bitmap compatible with the display device */
  2028. hdc = GetDC(NULL);
  2029. hbm = CreateDIBitmap(hdc, lpBitmapInfo, (DWORD)CBM_INIT, lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS);
  2030. ReleaseDC(NULL, hdc);
  2031. GlobalUnlock(hRes);
  2032. FreeResource(hRes);
  2033. return hbm;
  2034. }
  2035. /****************************************************************************
  2036. FUNCTION: DoHelp(HWND, BOOL)
  2037. PURPOSE: This routine invokes help if BOOL is true, or dismisses help
  2038. if BOOL is false.
  2039. COMMENTS:
  2040. ****************************************************************************/
  2041. VOID DoHelp(HWND hWnd, BOOL fInvokeHelp)
  2042. {
  2043. TCHAR szHelp[80];
  2044. if (LoadString(hInst, IDS_HELP, szHelp, BTOC(sizeof(szHelp)) - 1)) {
  2045. if (fInvokeHelp)
  2046. WinHelp(hWnd, (LPTSTR)szHelp, HELP_INDEX, 0L);
  2047. else
  2048. WinHelp(hWnd, (LPTSTR)szHelp, HELP_QUIT, 0L);
  2049. }
  2050. }
  2051. /****************************************************************************
  2052. FUNCTION: SaveFont(HWND)
  2053. PURPOSE: Used to save the current font facename in win.ini, so that
  2054. it can be selected the next time charmap comes up.
  2055. COMMENTS:
  2056. ****************************************************************************/
  2057. VOID SaveCurrentFont(HWND hWndDlg)
  2058. {
  2059. TCHAR szFaceName[LF_FACESIZE] = TEXT("");
  2060. SendDlgItemMessage(hWndDlg, ID_FONT, CB_GETLBTEXT,
  2061. (WORD)SendDlgItemMessage(hWndDlg, ID_FONT, CB_GETCURSEL,
  2062. 0, 0L),
  2063. (LPARAM)(LPTSTR)szFaceName);
  2064. WriteProfileString(TEXT("MSCharMap"), TEXT("Font"), (LPTSTR)szFaceName);
  2065. }
  2066. /****************************************************************************
  2067. FUNCTION: SelectInitialFont(HWND)
  2068. PURPOSE: Used to select the initial font by getting a saved facename
  2069. from win.ini and selecting it in the combo box.
  2070. COMMENTS: Returns index to font selected.
  2071. ****************************************************************************/
  2072. INT SelectInitialFont(HWND hWndDlg)
  2073. {
  2074. TCHAR szFaceName[LF_FACESIZE] = TEXT("");
  2075. INT iIndex;
  2076. if ((GetProfileString(TEXT("MSCharMap"), TEXT("Font"), NULL, (LPTSTR)szFaceName,
  2077. BTOC(sizeof(szFaceName))) == 0) ||
  2078. ((iIndex = (INT)SendDlgItemMessage(hWndDlg, ID_FONT, CB_SELECTSTRING, (WPARAM)-1,
  2079. (LPARAM)(LPTSTR)szFaceName)) == CB_ERR)) {
  2080. /*
  2081. * If there was no profile or the selection failed then try selecting
  2082. * the symbol font, if that fails then select the first one.
  2083. */
  2084. if ((iIndex = (INT)SendDlgItemMessage(hWndDlg, ID_FONT, CB_SELECTSTRING,
  2085. (WPARAM)-1, (LPARAM)(LPTSTR)TEXT("Symbol"))) == CB_ERR)
  2086. SendDlgItemMessage(hWndDlg, ID_FONT, CB_SETCURSEL, iIndex = 0, 0L);
  2087. }
  2088. return(iIndex);
  2089. }
  2090. /****************************************************************************
  2091. FUNCTION: SaveCurrentSubset(HWND)
  2092. PURPOSE: Used to save the current subset name in win.ini, so that
  2093. it can be selected the next time charmap comes up.
  2094. COMMENTS:
  2095. ****************************************************************************/
  2096. VOID SaveCurrentSubset(HWND hWndDlg)
  2097. {
  2098. TCHAR szSubsetName[LF_SUBSETSIZE] = TEXT("");
  2099. SendDlgItemMessage(hWndDlg, ID_UNICODESUBSET, CB_GETLBTEXT,
  2100. (WORD)SendDlgItemMessage(hWndDlg, ID_UNICODESUBSET, CB_GETCURSEL,
  2101. 0, 0L),
  2102. (LPARAM)(LPTSTR)szSubsetName);
  2103. WriteProfileString(TEXT("MSCharMap"), TEXT("Block"), (LPTSTR)szSubsetName);
  2104. }
  2105. /****************************************************************************
  2106. FUNCTION: SelectInitialSubset(HWND)
  2107. PURPOSE: Used to select the initial Unicode subset by getting a saved
  2108. block name from win.ini.
  2109. COMMENTS: Returns index to subset selected.
  2110. ****************************************************************************/
  2111. INT SelectInitialSubset(HWND hWndDlg)
  2112. {
  2113. TCHAR szSubsetName[LF_SUBSETSIZE] = TEXT("");
  2114. INT iIndex;
  2115. if (
  2116. (GetProfileString(
  2117. TEXT("MSCharMap"),
  2118. TEXT("Block"),
  2119. NULL,
  2120. (LPTSTR)szSubsetName,
  2121. BTOC(sizeof(szSubsetName))
  2122. ) == 0)
  2123. || ((iIndex = (INT)SendDlgItemMessage(
  2124. hWndDlg,
  2125. ID_UNICODESUBSET,
  2126. CB_SELECTSTRING,
  2127. (WPARAM)-1,
  2128. (LPARAM)(LPTSTR)szSubsetName
  2129. )) == CB_ERR)) {
  2130. /*
  2131. * If there was no profile or the selection failed then try selecting
  2132. * the Basic Latin block, if that fails then select the first one.
  2133. */
  2134. if ((iIndex = (INT)SendDlgItemMessage(
  2135. hWndDlg,
  2136. ID_UNICODESUBSET,
  2137. CB_SELECTSTRING,
  2138. (WPARAM)-1,
  2139. (LPARAM)(LPTSTR)TEXT("Basic Latin")
  2140. )) == CB_ERR)
  2141. SendDlgItemMessage(hWndDlg, ID_UNICODESUBSET, CB_SETCURSEL, iIndex = 0, 0L);
  2142. }
  2143. chSymFirst = (UTCHAR)aSubsetData[iIndex].BeginRange;
  2144. chSymLast = (UTCHAR)aSubsetData[iIndex].EndRange;
  2145. sycm.chCurr = chSymFirst;
  2146. return iIndex;
  2147. }
  2148. /****************************************************************************
  2149. FUNCTION: ExitMagnify(HWND, SYCM)
  2150. PURPOSE: Used to release mouse capture, exit magnify mode,
  2151. and restore the cursor.
  2152. COMMENTS:
  2153. ****************************************************************************/
  2154. VOID ExitMagnify(
  2155. HWND hWnd,
  2156. PSYCM psycm)
  2157. {
  2158. // Release capture, remove magnified character, restore cursor.
  2159. ReleaseCapture();
  2160. RestoreSymMag(psycm);
  2161. DrawSymChOutlineHwnd(psycm, hWnd, psycm->chCurr, TRUE, TRUE);
  2162. if (psycm->fCursorOff)
  2163. ShowCursor(TRUE);
  2164. psycm->fMouseDn = psycm->fCursorOff = FALSE;
  2165. }