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.

726 lines
15 KiB

  1. //==========================================================================;
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  4. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  5. // TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
  6. // A PARTICULAR PURPOSE.
  7. //
  8. // Copyright (C) 1993 - 1997 Microsoft Corporation. All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. // zyztlb.c
  13. //
  14. // Description:
  15. //
  16. //
  17. // History:
  18. // 5/18/93
  19. //
  20. //==========================================================================;
  21. #include <windows.h>
  22. #include <windowsx.h>
  23. #include <stdlib.h>
  24. #include "appport.h"
  25. #include "zyztlb.h"
  26. #include "debug.h"
  27. //==========================================================================;
  28. //
  29. //
  30. //
  31. //
  32. //==========================================================================;
  33. //--------------------------------------------------------------------------;
  34. //
  35. // int GetRealTextMetrics
  36. //
  37. // Description:
  38. // This function gets the textmetrics of the font currently selected
  39. // into the hdc. It returns the average char width as the return value.
  40. //
  41. // This function computes the average character width correctly by
  42. // using GetTextExtent() on the string "abc...xzyABC...XYZ" which works
  43. // out much better for proportional fonts. This is also necessary
  44. // for correct alignment between dialog and client units.
  45. //
  46. // Note that this function returns the same TEXTMETRIC values that
  47. // GetTextMetrics() does, it simply has a different return value.
  48. //
  49. // Arguments:
  50. // HDC hdc:
  51. //
  52. // LPTEXTMETRIC ptm:
  53. //
  54. // Return (int):
  55. //
  56. // History:
  57. // 05/11/93
  58. //
  59. //--------------------------------------------------------------------------;
  60. int FNGLOBAL GetRealTextMetrics
  61. (
  62. HDC hdc,
  63. LPTEXTMETRIC ptm
  64. )
  65. {
  66. TCHAR achAlphabet[26 * 2]; // upper and lower case
  67. SIZE sSize;
  68. UINT u;
  69. int nAveWidth;
  70. //
  71. // get the text metrics of the current font. note that GetTextMetrics
  72. // gets the incorrect nAveCharWidth value for proportional fonts.
  73. //
  74. GetTextMetrics(hdc, ptm);
  75. nAveWidth = ptm->tmAveCharWidth;
  76. //
  77. // if it's not a variable pitch font GetTextMetrics was correct
  78. // so just return.
  79. //
  80. if (ptm->tmPitchAndFamily & FIXED_PITCH)
  81. {
  82. //
  83. //
  84. //
  85. for (u = 0; u < 26; u++)
  86. {
  87. achAlphabet[u] = (TCHAR)(u + (UINT)'a');
  88. achAlphabet[u + 26] = (TCHAR)(u + (UINT)'A');
  89. }
  90. //
  91. // round up
  92. //
  93. GetTextExtentPoint(hdc, achAlphabet, SIZEOF(achAlphabet), &sSize);
  94. nAveWidth = ((sSize.cx / 26) + 1) / 2;
  95. }
  96. //
  97. // return the calculated average char width
  98. //
  99. return (nAveWidth);
  100. } // GetRealTextMetrics()
  101. //==========================================================================;
  102. //
  103. //
  104. //
  105. //
  106. //==========================================================================;
  107. //--------------------------------------------------------------------------;
  108. //
  109. // BOOL TlbPaint
  110. //
  111. // Description:
  112. //
  113. //
  114. // Arguments:
  115. // PZYZTABBEDLISTBOX ptlb:
  116. //
  117. // HWND hwnd:
  118. //
  119. // HDC hdc:
  120. //
  121. // Return (BOOL):
  122. //
  123. // History:
  124. // 05/17/93
  125. //
  126. //--------------------------------------------------------------------------;
  127. BOOL FNGLOBAL TlbPaint
  128. (
  129. PZYZTABBEDLISTBOX ptlb,
  130. HWND hwnd,
  131. HDC hdc
  132. )
  133. {
  134. RECT rc;
  135. HFONT hfont;
  136. COLORREF crBk;
  137. COLORREF crText;
  138. int nHeight;
  139. //
  140. //
  141. //
  142. hfont = GetWindowFont(ptlb->hlb);
  143. if (NULL == hfont)
  144. hfont = GetStockFont(SYSTEM_FONT);
  145. hfont = SelectObject(hdc, hfont);
  146. crBk = SetBkColor(hdc, GetSysColor(COLOR_ACTIVECAPTION));
  147. crText = SetTextColor(hdc, GetSysColor(COLOR_CAPTIONTEXT));
  148. //
  149. // compute bounding rect for title only
  150. //
  151. rc = ptlb->rc;
  152. nHeight = min(ptlb->nFontHeight, rc.bottom - rc.top);
  153. rc.bottom = rc.top + nHeight;
  154. ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE, &rc, NULL, 0, NULL);
  155. TabbedTextOut(hdc, rc.left, rc.top,
  156. ptlb->pszTitleText,
  157. ptlb->cchTitleText,
  158. ptlb->uTabStops,
  159. ptlb->panTitleTabs, 0);
  160. //
  161. // restore the dc
  162. //
  163. SetBkColor(hdc, crBk);
  164. SetTextColor(hdc, crText);
  165. SelectObject(hdc, hfont);
  166. return (TRUE);
  167. } // TlbPaint()
  168. //--------------------------------------------------------------------------;
  169. //
  170. // BOOL TlbMove
  171. //
  172. // Description:
  173. //
  174. //
  175. // Arguments:
  176. // PZYZTABBEDLISTBOX ptlb:
  177. //
  178. // PRECT prc:
  179. //
  180. // BOOL fRedraw:
  181. //
  182. // Return (BOOL):
  183. //
  184. // History:
  185. // 05/16/93
  186. //
  187. //--------------------------------------------------------------------------;
  188. BOOL FNGLOBAL TlbMove
  189. (
  190. PZYZTABBEDLISTBOX ptlb,
  191. PRECT prc,
  192. BOOL fRedraw
  193. )
  194. {
  195. RECT rc;
  196. int nHeight;
  197. HWND hwnd;
  198. hwnd = GetParent(ptlb->hlb);
  199. //
  200. // invalidate only the region occupied by the current title bar. this
  201. // will make sure that area gets repainted. the listbox portion will
  202. // be invalidated correctly by the SetWindowPos() function below..
  203. //
  204. rc = ptlb->rc;
  205. nHeight = min(ptlb->nFontHeight, rc.bottom - rc.top);
  206. rc.bottom = rc.top + nHeight;
  207. InvalidateRect(hwnd, &rc, TRUE);
  208. //
  209. // now move the listbox--we modify values in the rect structure, so
  210. // copy to local storage
  211. //
  212. rc = *prc;
  213. //
  214. // leave room at the top of the bounding rect for the title text
  215. //
  216. nHeight = min(ptlb->nFontHeight, rc.bottom - rc.top);
  217. rc.top += nHeight;
  218. SetWindowPos(ptlb->hlb, NULL, rc.left, rc.top, rc.right - rc.left,
  219. rc.bottom - rc.top, SWP_NOZORDER);
  220. //
  221. // save the new location and invalidate the area so it is repainted
  222. //
  223. ptlb->rc = *prc;
  224. InvalidateRect(hwnd, prc, TRUE);
  225. if (fRedraw)
  226. {
  227. UpdateWindow(hwnd);
  228. }
  229. return (TRUE);
  230. } // TlbMove()
  231. //--------------------------------------------------------------------------;
  232. //
  233. // BOOL TlbRecalcTabs
  234. //
  235. // Description:
  236. //
  237. //
  238. // Arguments:
  239. // PZYZTABBEDLISTBOX ptlb:
  240. //
  241. // Return (BOOL):
  242. //
  243. // History:
  244. // 05/18/93
  245. //
  246. //--------------------------------------------------------------------------;
  247. BOOL FNLOCAL TlbRecalcTabs
  248. (
  249. PZYZTABBEDLISTBOX ptlb
  250. )
  251. {
  252. static TCHAR szGonzoThing[] = TEXT("M");
  253. int anTabsList[TLB_MAX_TAB_STOPS];
  254. HDC hdc;
  255. HFONT hfont;
  256. TEXTMETRIC tm;
  257. int nAveCharWidth;
  258. UINT u;
  259. int nWidth;
  260. int nPrevTabTitle;
  261. int nPrevTabList;
  262. SIZE sSize;
  263. //
  264. //
  265. //
  266. hdc = GetDC(NULL);
  267. {
  268. //
  269. // get the average char width and height of the current font so we
  270. // can compute tabs correctly. note that GetTextMetrics is pretty
  271. // bogus when it comes to the average char width--it normally gives
  272. // you the width of the character 'x'. what it should be is the
  273. // average width of all capitals and lower case letters..
  274. //
  275. hfont = GetWindowFont(ptlb->hlb);
  276. if (NULL == hfont)
  277. hfont = GetStockFont(SYSTEM_FONT);
  278. hfont = SelectObject(hdc, hfont);
  279. #if 0
  280. GetTextMetrics(hdc, &tm);
  281. nAveCharWidth = tm.tmAveCharWidth;
  282. #else
  283. nAveCharWidth = GetRealTextMetrics(hdc, &tm);
  284. #endif
  285. ptlb->nFontHeight = tm.tmHeight;
  286. //
  287. //
  288. //
  289. GetTextExtentPoint(hdc, szGonzoThing, 1, &sSize);
  290. //
  291. //
  292. //
  293. hfont = SelectObject(hdc, hfont);
  294. }
  295. ReleaseDC(NULL, hdc);
  296. //
  297. // calculate the width of each column
  298. //
  299. nPrevTabTitle = 0;
  300. nPrevTabList = 0;
  301. for (u = 0; u < ptlb->uTabStops; u++)
  302. {
  303. // nWidth = nAveCharWidth * ptlb->panTabs[u] + nAveCharWidth * 2;
  304. nWidth = sSize.cx * ptlb->panTabs[u] + (sSize.cx * 2);
  305. //
  306. // set tabstop for title text--this is in client units
  307. // for TabbedTextOut in TlbPaint
  308. //
  309. ptlb->panTitleTabs[u] = nPrevTabTitle + nWidth;
  310. nPrevTabTitle = ptlb->panTitleTabs[u];
  311. //
  312. // set tabstop for listbox--this is in dialog units
  313. //
  314. anTabsList[u] = nPrevTabList + MulDiv(nWidth, 4, nAveCharWidth);
  315. nPrevTabList = anTabsList[u];
  316. }
  317. //
  318. // now setup the tabstops in the listbox
  319. //
  320. ListBox_SetTabStops(ptlb->hlb, ptlb->uTabStops, anTabsList);
  321. return (TRUE);
  322. } // TlbRecalcTabs()
  323. //--------------------------------------------------------------------------;
  324. //
  325. // HFONT TlbSetFont
  326. //
  327. // Description:
  328. //
  329. //
  330. // Arguments:
  331. // PZYZTABBEDLISTBOX ptlb:
  332. //
  333. // HFONT hfont:
  334. //
  335. // BOOL fRedraw:
  336. //
  337. // Return (HFONT):
  338. //
  339. // History:
  340. // 05/16/93
  341. //
  342. //--------------------------------------------------------------------------;
  343. HFONT FNGLOBAL TlbSetFont
  344. (
  345. PZYZTABBEDLISTBOX ptlb,
  346. HFONT hfont,
  347. BOOL fRedraw
  348. )
  349. {
  350. HFONT hfontOld;
  351. //
  352. //
  353. //
  354. hfontOld = GetWindowFont(ptlb->hlb);
  355. SetWindowFont(ptlb->hlb, hfont, FALSE);
  356. TlbRecalcTabs(ptlb);
  357. TlbMove(ptlb, &ptlb->rc, fRedraw);
  358. return (hfontOld);
  359. } // TlbSetFont()
  360. //--------------------------------------------------------------------------;
  361. //
  362. // BOOL TlbSetTitleAndTabs
  363. //
  364. // Description:
  365. // This function sets the title text and tab stops for a Tabbed List
  366. // Box (TLB). The pszTitleFormat specifies the title text for each
  367. // column along with the tabstop position for each column. The format
  368. // of this string is as follows:
  369. //
  370. // <columnname1>\t<tab1>!<columnname2>
  371. //
  372. // TCHAR szTlbThings[] = TEXT("Index\t6!Code\t5!Name");
  373. //
  374. //
  375. // Arguments:
  376. // PZYZTABBEDLISTBOX ptlb:
  377. //
  378. // PTSTR pszTitleFormat:
  379. //
  380. // BOOL fRedraw:
  381. //
  382. // Return (BOOL):
  383. //
  384. // History:
  385. // 05/18/93
  386. //
  387. //--------------------------------------------------------------------------;
  388. BOOL FNGLOBAL TlbSetTitleAndTabs
  389. (
  390. PZYZTABBEDLISTBOX ptlb,
  391. PTSTR pszTitleFormat,
  392. BOOL fRedraw
  393. )
  394. {
  395. TCHAR szTitleText[TLB_MAX_TITLE_CHARS];
  396. int anTabs[TLB_MAX_TAB_STOPS];
  397. PTSTR pch;
  398. PTSTR pchTitleText;
  399. UINT uTabStops;
  400. UINT cchTitleText;
  401. HWND hwnd;
  402. //
  403. // parse the title format counting tab stops and actual size of title
  404. // text
  405. //
  406. uTabStops = 0;
  407. pchTitleText = szTitleText;
  408. for (pch = pszTitleFormat; '\0' != *pch; )
  409. {
  410. TCHAR ch;
  411. //
  412. // scan to tab
  413. //
  414. while ('\0' != (ch = *pch))
  415. {
  416. *pchTitleText++ = *pch++;
  417. if ('\t' == ch)
  418. break;
  419. }
  420. if ('\0' == ch)
  421. break;
  422. //
  423. // grab the next tab stop value
  424. //
  425. anTabs[uTabStops] = atoi(pch);
  426. uTabStops++;
  427. //
  428. // skip to start of next column name
  429. //
  430. while ('!' != *pch++)
  431. ;
  432. }
  433. //
  434. // terminate the converted title text
  435. //
  436. *pchTitleText = '\0';
  437. cchTitleText = lstrlen(szTitleText);
  438. //
  439. // free the memory used for the previous tab stops and title text
  440. //
  441. if (NULL != ptlb->panTabs)
  442. {
  443. LocalFree((HLOCAL)ptlb->panTabs);
  444. ptlb->uTabStops = 0;
  445. ptlb->panTabs = NULL;
  446. ptlb->panTitleTabs = NULL;
  447. }
  448. if (NULL != ptlb->pszTitleText)
  449. {
  450. LocalFree((HLOCAL)ptlb->pszTitleText);
  451. ptlb->cchTitleText = 0;
  452. ptlb->pszTitleText = NULL;
  453. }
  454. //
  455. // allocate new space for tab stops. there are two different tab
  456. // arrays:
  457. //
  458. // panTabs: original tab values as passed by caller. these are
  459. // virtual tab locations represented as number of characters. we
  460. // need to keep these values for recomputing the real tabs when
  461. // the font changes.
  462. //
  463. // panTitleTabs: these values are computed by TlbRecalcTabs and
  464. // are actual tab positions in client coordinates for the title
  465. // text (needed for TabbedTextOut in TlbPaint).
  466. //
  467. // the tabs for the listbox are computed and set in TlbRecalcTabs
  468. //
  469. if (0 != uTabStops)
  470. {
  471. ptlb->panTabs = (PINT)LocalAlloc(LPTR, (uTabStops * sizeof(int)) * 2);
  472. if (NULL == ptlb->panTabs)
  473. return (FALSE);
  474. ptlb->uTabStops = uTabStops;
  475. ptlb->panTitleTabs = ptlb->panTabs + uTabStops;
  476. memcpy(ptlb->panTabs, anTabs, uTabStops * sizeof(int));
  477. }
  478. //
  479. // allocate space for the converted title text (stripped of the tab
  480. // spacing values). this string is passed directly to TabbedTextOut
  481. // in TlbPaint.
  482. //
  483. if (0 != cchTitleText)
  484. {
  485. ptlb->pszTitleText = (PTSTR)LocalAlloc(LPTR, (cchTitleText + 1) * sizeof(TCHAR));
  486. if (NULL == ptlb->pszTitleText)
  487. return (FALSE);
  488. ptlb->cchTitleText = cchTitleText;
  489. lstrcpy(ptlb->pszTitleText, szTitleText);
  490. }
  491. //
  492. //
  493. //
  494. TlbRecalcTabs(ptlb);
  495. //
  496. // force a complete repaint of the title text and listbox--redraw
  497. // immediately if we are supposed to
  498. //
  499. hwnd = GetParent(ptlb->hlb);
  500. InvalidateRect(hwnd, &ptlb->rc, TRUE);
  501. if (fRedraw)
  502. {
  503. UpdateWindow(hwnd);
  504. }
  505. return TRUE;
  506. } // TlbSetTitleAndTabs()
  507. //--------------------------------------------------------------------------;
  508. //
  509. // PZYZTABBEDLISTBOX TlbDestroy
  510. //
  511. // Description:
  512. //
  513. //
  514. // Arguments:
  515. // PZYZTABBEDLISTBOX ptlb:
  516. //
  517. // Return (PZYZTABBEDLISTBOX):
  518. //
  519. // History:
  520. // 05/16/93
  521. //
  522. //--------------------------------------------------------------------------;
  523. PZYZTABBEDLISTBOX FNGLOBAL TlbDestroy
  524. (
  525. PZYZTABBEDLISTBOX ptlb
  526. )
  527. {
  528. HWND hwnd;
  529. int nHeight;
  530. //
  531. // get rid of the listbox
  532. //
  533. if (NULL != ptlb->hlb)
  534. {
  535. DestroyWindow(ptlb->hlb);
  536. //
  537. // invalidate area where title text was so it will be clean
  538. //
  539. nHeight = min(ptlb->nFontHeight, ptlb->rc.bottom - ptlb->rc.top);
  540. ptlb->rc.bottom = ptlb->rc.top + nHeight;
  541. hwnd = GetParent(ptlb->hlb);
  542. InvalidateRect(hwnd, &ptlb->rc, TRUE);
  543. //
  544. // free the memory used for tab stops and title text
  545. //
  546. if (NULL != ptlb->panTabs)
  547. LocalFree((HLOCAL)ptlb->panTabs);
  548. if (NULL != ptlb->pszTitleText)
  549. LocalFree((HLOCAL)ptlb->pszTitleText);
  550. }
  551. LocalFree((HLOCAL)ptlb);
  552. return (NULL);
  553. } // TlbDestroy()
  554. //--------------------------------------------------------------------------;
  555. //
  556. // PZYZTABBEDLISTBOX TlbCreate
  557. //
  558. // Description:
  559. //
  560. //
  561. // Arguments:
  562. // HWND hwnd:
  563. //
  564. // int nId:
  565. //
  566. // PRECT prc:
  567. //
  568. // Return (PZYZTABBEDLISTBOX):
  569. //
  570. // History:
  571. // 05/16/93
  572. //
  573. //--------------------------------------------------------------------------;
  574. PZYZTABBEDLISTBOX FNGLOBAL TlbCreate
  575. (
  576. HWND hwnd,
  577. int nId,
  578. PRECT prc
  579. )
  580. {
  581. #define TLB_DEF_STYLE (WS_VISIBLE|WS_CHILD|WS_VSCROLL|WS_BORDER| \
  582. LBS_NOTIFY|LBS_NOINTEGRALHEIGHT|LBS_USETABSTOPS)
  583. static TCHAR szNull[] = TEXT("");
  584. static TCHAR szListBox[] = TEXT("ListBox");
  585. PZYZTABBEDLISTBOX ptlb;
  586. HINSTANCE hinst;
  587. //
  588. // create a new instance data structure..
  589. //
  590. ptlb = (PZYZTABBEDLISTBOX)LocalAlloc(LPTR, sizeof(*ptlb));
  591. if (NULL == ptlb)
  592. return (NULL);
  593. //
  594. // create the listbox
  595. //
  596. hinst = GetWindowInstance(hwnd);
  597. ptlb->hlb = CreateWindow(szListBox, szNull, TLB_DEF_STYLE,
  598. 0, 0, 0, 0, hwnd, (HMENU)nId, hinst, NULL);
  599. if (NULL == ptlb->hlb)
  600. {
  601. TlbDestroy(ptlb);
  602. return (NULL);
  603. }
  604. TlbRecalcTabs(ptlb);
  605. if (NULL != prc)
  606. {
  607. ptlb->rc = *prc;
  608. TlbMove(ptlb, prc, FALSE);
  609. }
  610. return (ptlb);
  611. } // TlbCreate()