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.

725 lines
16 KiB

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