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