home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / audio / mixapp / tlb.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  17KB  |  715 lines

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