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 / idfedit / drawstr.c next >
C/C++ Source or Header  |  1997-10-05  |  47KB  |  1,732 lines

  1.  
  2. /*****************************************************************************
  3. *
  4. *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  5. *  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  6. *  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
  7. *  A PARTICULAR PURPOSE.
  8. *
  9. *  Copyright (C) 1993 - 1997 Microsoft Corporation. All Rights Reserved.
  10. *
  11. *****************************************************************************/
  12.  
  13. /*+ DrawStr.c
  14.  *
  15.  *-=================================================================*/
  16.  
  17. #include <windows.h>
  18. #include <windowsx.h>
  19.  
  20. #include <string.h>
  21. #include <memory.h>
  22. #include <stdlib.h>
  23.  
  24. #include "drawstr.h"
  25. #include "tridee.h"
  26. #include "res.h"
  27. #include "idfedit.h"
  28.  
  29. CONST LOGFONT lfMain = {
  30.     12,                        //int   lfHeight;
  31.     0,                         //int   lfWidth;
  32.     0,                         //int   lfEscapement;
  33.     0,                         //int   lfOrientation;
  34.     FW_DONTCARE,               //int   lfWeight;
  35.     0,                         //BYTE  lfItalic;
  36.     0,                         //BYTE  lfUnderline;
  37.     0,                         //BYTE  lfStrikeOut;
  38.     ANSI_CHARSET,              //BYTE  lfCharSet;
  39.     OUT_DEFAULT_PRECIS,        //BYTE  lfOutPrecision;
  40.     CLIP_DEFAULT_PRECIS,       //BYTE  lfClipPrecision;
  41.     DEFAULT_QUALITY,           //BYTE  lfQuality;
  42.     DEFAULT_PITCH | FF_SWISS,  //BYTE  lfPitchAndFamily;
  43.     "MS Sans Serif",           //BYTE  lfFaceName[LF_FACESIZE];
  44.     };
  45.  
  46. DSPREF dspref = {0};
  47. BOOL   bInEditingMode;
  48.  
  49. #ifdef USE_MDI
  50.  #define DefProc DefMDIChildProc
  51. #else
  52.  #define DefProc DefWindowProc
  53. #endif
  54.  
  55. /*+  AccessFilter
  56.  *
  57.  *   exception filter for access violations
  58.  *
  59.  *   this function is a filter for an except block. It must
  60.  *   return one of the following DWORD values:
  61.  *      EXCEPTION_EXECUTE_HANDLER
  62.  *      EXCEPTION_CONTINUE_SEARCH
  63.  *      EXCEPTION_CONTINUE_EXECUTION
  64.  *
  65.  *-=================================================================*/
  66.  
  67. DWORD AccessFilter (
  68.    DWORD dwExceptCode)
  69. {
  70.    if (dwExceptCode == EXCEPTION_ACCESS_VIOLATION)
  71.       return EXCEPTION_EXECUTE_HANDLER;
  72.    return EXCEPTION_CONTINUE_SEARCH;
  73. }
  74.  
  75. /*+ DrawDsLabels
  76.  *
  77.  *-=================================================================*/
  78.  
  79. VOID WINAPI DrawDsLabels (
  80.    HDC          hDC,
  81.    PDSFIELDTBL  pTable,
  82.    PDSLINEINFO  pLineInfo,
  83.    LPRECT       lpRect,
  84.    POINT        ptOffset)
  85.    {
  86.    WORD        wOldAlign;  // temp, prev state of alignment
  87.    UINT        ii;         // general index variable
  88.    int         cx;         // current x position to draw at
  89.    int         cy;         // current y position to draw at
  90.    int         cyText;
  91.    PDSFIELD    pField;
  92.    struct _dsline * pLine;
  93.    char        sz[100];
  94.  
  95.    // do some simple error checking, if not a valid DC
  96.    // dont go any further.
  97.    //
  98.    if (!hDC)
  99.       return;
  100.  
  101.    // get the text metrics and initialize the max width variable
  102.    //
  103.    cyText = pLineInfo->cyLine;
  104.  
  105.    // setup the current x & y locations for writing text
  106.    //
  107.    cx = lpRect->left - ptOffset.x;
  108.    cy = lpRect->top - ptOffset.y;
  109.  
  110.    // draw each of the labels making a vertical
  111.    // column starting 'cx,cy'.  But be sure not to
  112.    // draw outside of the rectangle 'lpRect'
  113.    //
  114.    wOldAlign = SetTextAlign (hDC, TA_TOP | TA_LEFT);
  115.  
  116.    // clear the background
  117.    //
  118.    ExtTextOut (hDC, cx, cy, ETO_CLIPPED | ETO_OPAQUE, lpRect, "", 0, NULL);
  119.  
  120.    // draw the labels
  121.    //
  122.    for (pLine = &pLineInfo->aLine[ii = 0];
  123.         ii < pLineInfo->nCurLine;
  124.         ++ii, ++pLine, cy += cyText)
  125.       {
  126.       if (cy < lpRect->top - cyText)
  127.          continue;
  128.  
  129.       if (cy > lpRect->bottom)
  130.          break;
  131.  
  132.       pField = pTable[pLine->uStruct].pFields;
  133.       pField += pLine->uField;
  134.  
  135.       wsprintf (sz, pField->psz, pLine->uMember);
  136.  
  137.       if (sz[0] == ' ')
  138.          {
  139.          SetTextAlign (hDC, TA_TOP | TA_RIGHT);
  140.          cx = lpRect->right - 2;
  141.          }
  142.       else
  143.          {
  144.          SetTextAlign (hDC, TA_TOP | TA_LEFT);
  145.          cx = lpRect->left - ptOffset.x + (pLine->uDepth-1) * 16;
  146.          }
  147.  
  148.       // draw the label pointed to by pFields[ii].psz
  149.       // then increment cy by the height of a label
  150.       //
  151.       ExtTextOut (hDC,
  152.                   cx,
  153.                   cy,
  154.                   ETO_CLIPPED,
  155.                   lpRect,
  156.                   sz,
  157.                   lstrlen(sz),
  158.                   NULL);
  159.       }
  160.  
  161.    // restore text alignment and return
  162.    //
  163.    SetTextAlign (hDC, wOldAlign);
  164.  
  165.    return;
  166.    }
  167.  
  168. /*+ GetFieldText
  169.  *
  170.  *-=================================================================*/
  171.  
  172. VOID WINAPI GetFieldText (
  173.    PDSFIELD  pField,
  174.    LPVOID    lpData,
  175.    UINT      uMember,
  176.    LPSTR     pszIn,
  177.    UINT      cchIn,
  178.    PDSBUFF   pds)
  179.    {
  180.    UINT    cb;
  181.    LPBYTE  lp;
  182.  
  183.    pds->ptr = pszIn;
  184.    pds->cch = cchIn;
  185.    if (pds->cch > 10) // allow a bit of slop
  186.       pds->cch -= 10;
  187.    pds->ptr[0] = 0;
  188.  
  189.    __try
  190.       {
  191.       if (pField->fmt & AS_REF)
  192.          {
  193.          lp = *(LPBYTE *)lpData;
  194.          lp += (uMember * pField->siz);
  195.  
  196.          if (dspref.bShowAddresses)
  197.             {
  198.             wsprintf (pds->ptr, "@%08x: ", lpData);
  199.             cb = lstrlen(pds->ptr);
  200.             pds->ptr += cb;
  201.             pds->cch -= cb;
  202.             }
  203.          }
  204.       else
  205.          {
  206.          lp = (LPBYTE)lpData + (uMember * pField->siz);
  207.  
  208.          if (dspref.bShowAddresses)
  209.             {
  210.             wsprintf (pds->ptr, "@%08x: ", lp);
  211.             cb = lstrlen(pds->ptr);
  212.             pds->ptr += cb;
  213.             pds->cch -= cb;
  214.             }
  215.          }
  216.  
  217.  
  218.       if (lp == NULL)
  219.          lstrcpy (pds->ptr, "<null>");
  220.       else
  221.       switch (pField->fmt & 0xFF)
  222.          {
  223.          case AS_NONE:
  224.             //wsprintf (pds->ptr, "%08X = ", lp);
  225.             break;
  226.  
  227.          case AS_SZ:
  228.             strncpy (pds->ptr, (LPTSTR)lp, pds->cch);
  229.             break;
  230.  
  231.          case AS_MODE:
  232.             {
  233.             UINT (*pfnMode)(LPSTR, UINT, DWORD) = (LPVOID)pField->aux;
  234.  
  235.             if (pField->siz == sizeof(DWORD))
  236.                 pfnMode (pds->ptr, pds->cch, *(DWORD *)lp);
  237.             else
  238.                 pfnMode (pds->ptr, pds->cch, (DWORD)lp);
  239.             }
  240.             break;
  241.  
  242.          case AS_XMODE:
  243.             {
  244.             UINT (*pfnMode)(LPSTR, UINT, UINT, UINT, UINT) = (LPVOID)pField->aux;
  245.  
  246.             if (pField->siz == sizeof(DWORD))
  247.                 pfnMode (pds->ptr, pds->cch, *(UINT *)lp, pField->array, WM_GETTEXT);
  248.             else
  249.                 pfnMode (pds->ptr, pds->cch, (UINT)lp, pField->array, WM_GETTEXT);
  250.             }
  251.             break;
  252.  
  253.          case AS_ERROR:
  254.             {
  255.             UINT cb;
  256.             DWORD dwError = *(LPDWORD)lp;
  257.  
  258.             pds->ptr[0] = 0;
  259.             if (dwError)
  260.                 FormatMessage (FORMAT_MESSAGE_IGNORE_INSERTS
  261.                                | FORMAT_MESSAGE_FROM_SYSTEM,
  262.                                0,
  263.                                dwError,
  264.                                0,
  265.                                pds->ptr,
  266.                                pds->cch,
  267.                                NULL);
  268.  
  269.             // get rid of terminating CR/LF if it exists
  270.             //
  271.             cb = lstrlen(pds->ptr);
  272.             if (cb > 2)
  273.                pds->ptr[cb-2] = 0;
  274.             }
  275.             break;
  276.  
  277.          case AS_ACH:
  278.             {
  279.             UINT jj;
  280.             for (jj = 0; jj < pds->cch-1 && jj < pField->siz; ++jj)
  281.                 pds->ptr[jj] = lp[jj] > 31 ? lp[jj] : '.';
  282.             pds->ptr[jj] = 0;
  283.             }
  284.             break;
  285.  
  286.          case AS_DUMP:
  287.             {
  288.             UINT   jj;
  289.             UINT   cb;
  290.  
  291.             for (jj = 0; jj < pField->siz; jj += sizeof(WORD))
  292.                {
  293.                cb = wsprintf (pds->ptr, "%04X ", *(WORD *)(lp+jj));
  294.                if (cb >= pds->cch)
  295.                   {
  296.                   pds->ptr[pds->cch-1] = 0;
  297.                   break;
  298.                   }
  299.  
  300.                pds->cch -= cb;
  301.                pds->ptr += cb;
  302.                }
  303.  
  304.             for (jj = 0; jj < pds->cch-1 && jj < pField->siz; ++jj)
  305.                 pds->ptr[jj] = lp[jj] > 31 ? lp[jj] : '.';
  306.             pds->ptr[jj] = 0;
  307.             }
  308.             break;
  309.  
  310.          case AS_HEX:
  311.             {
  312.             UINT   jj;
  313.             UINT   cb;
  314.  
  315.             if (pField->siz == sizeof(DWORD))
  316.                 pds->ptr += wsprintf (pds->ptr, "%08X", *(DWORD *)lp);
  317.             else
  318.             for (jj = 0; jj < pField->siz; jj += sizeof(WORD))
  319.                {
  320.                cb = wsprintf (pds->ptr, "%04X ", *(WORD *)(lp+jj));
  321.                if (cb >= pds->cch)
  322.                   {
  323.                   pds->ptr[pds->cch-1] = 0;
  324.                   break;
  325.                   }
  326.  
  327.                pds->cch -= cb;
  328.                pds->ptr += cb;
  329.                }
  330.             *pds->ptr = 0;
  331.             }
  332.             break;
  333.  
  334.          case AS_INT:
  335.          case AS_UINT:
  336.             if (sizeof(WORD) == pField->siz)
  337.                wsprintf (pds->ptr, "%d", *(WORD *)lp);
  338.             else if (sizeof(DWORD) == pField->siz)
  339.                wsprintf (pds->ptr, "%d", *(DWORD *)lp);
  340.             else
  341.                {
  342.                int  jj;
  343.                UINT cb;
  344.  
  345.                for (jj = pField->siz-2; jj >= 0; jj -= sizeof(WORD))
  346.                   {
  347.                   cb = wsprintf (pds->ptr, "%d ", *(WORD *)(lp+jj));
  348.                   if (cb >= pds->cch)
  349.                      {
  350.                      pds->ptr[pds->cch-1] = 0;
  351.                      break;
  352.                      }
  353.                   pds->ptr += cb;
  354.                   pds->ptr -= cb;
  355.                   }
  356.                *pds->ptr = 0;
  357.                }
  358.             break;
  359.  
  360.          case AS_HANDLE:
  361.             wsprintf (pds->ptr, "%08X", *(UINT *)lp);
  362.             break;
  363.  
  364.          case AS_BITFIELD:
  365.             lstrcpy (pds->ptr, ((*(UINT *)lp & (1 << pField->aux)) ? "TRUE" : "FALSE"));
  366.             break;
  367.  
  368.          case AS_RECT:
  369.             wsprintf (pds->ptr, "%d,%d,%d,%d", *(LPRECT)lp);
  370.             break;
  371.  
  372.          case AS_POINT:
  373.          case AS_SIZE:
  374.             wsprintf (pds->ptr, "%d,%d", *(LPPOINT)lp);
  375.             break;
  376.  
  377.          case AS_POINTS:
  378.             wsprintf (pds->ptr, "%d,%d", ((SHORT *)lp)[0], ((SHORT *)lp)[1]);
  379.             break;
  380.  
  381.          case AS_FLOAT:
  382.             lstrcpy (pds->ptr, "<float not supported>");
  383.             break;
  384.  
  385.          case AS_BYTES:
  386.             {
  387.             UINT   jj;
  388.             LPTSTR psz = pds->ptr;
  389.  
  390.             for (jj = 0; jj < pField->siz; ++jj)
  391.                {
  392.                wsprintf (psz, "%3d ", *(BYTE *)((LPSTR)lp+jj));
  393.                psz += lstrlen(psz);
  394.                *psz = 0;
  395.                if (psz > (pds->ptr + pds->cch - 10))
  396.                   {
  397.                   *psz++ = '.';
  398.                   *psz++ = '.';
  399.                   *psz++ = '.';
  400.                   *psz++ = 0;
  401.                   break;
  402.                   } 
  403.                }
  404.             }
  405.             break;
  406.          }
  407.       }
  408.    __except (AccessFilter(GetExceptionCode()))
  409.       {
  410.       lstrcpy (pds->ptr, "<no access>");
  411.       }
  412.  
  413.    return;
  414.    }
  415.  
  416. /*+ SetFieldText
  417.  *
  418.  *
  419.  *-=================================================================*/
  420.  
  421. BOOL SetFieldText (
  422.    struct _dsline * pLine,
  423.    PDSFIELD         pField,
  424.    PDSBUFF          pds)
  425. {
  426.    LPBYTE lpv;
  427.  
  428.    lpv = pLine->lpv;
  429.    if (pField->fmt & AS_REF)
  430.      lpv = *(LPBYTE *)lpv;
  431.    lpv += (pLine->uMember * pField->siz);
  432.  
  433.    if (!pds->cch)
  434.       return FALSE;
  435.    pds->ptr[pds->cch-1] = 0;
  436.  
  437.    switch (pField->fmt & 0xFF)
  438.       {
  439.       case AS_SZ:
  440.          strncpy (lpv, pds->ptr, min(pField->siz, pds->cch));
  441.          break;
  442.  
  443.       case AS_BITFIELD:
  444.          {
  445.          LPTSTR psz = pds->ptr;
  446.  
  447.          while (*psz == '\t' && *psz == ' ')
  448.             ++psz;
  449.  
  450.          if ((*psz & ~0x20) == 'T' || (*psz & ~0x20) == 'Y' || *psz == '1')
  451.             *(LPDWORD)lpv |= (1 << pField->aux);
  452.          else if ((*psz & ~0x20) == 'F' || (*psz & ~0x20) == 'N' || *psz == '0')
  453.             *(LPDWORD)lpv &= ~(1 << pField->aux);
  454.          }
  455.          break;
  456.  
  457.       case AS_XMODE:
  458.          {
  459.          UINT (*pfnMode)(LPSTR, UINT, UINT, UINT, UINT) = (LPVOID)pField->aux;
  460.  
  461.          if (pField->siz == sizeof(DWORD))
  462.              pfnMode (pds->ptr, pds->cch, *(UINT *)lpv, pField->array, WM_SETTEXT);
  463.          else
  464.              pfnMode (pds->ptr, pds->cch, (UINT)lpv, pField->array, WM_SETTEXT);
  465.          }
  466.          break;
  467.  
  468.       case AS_UINT:
  469.          {
  470.          LPSTR pszStop = pds->ptr;
  471.          DWORD dw = (DWORD)strtoul (pds->ptr, &pszStop, 10);
  472.          if (pszStop != pds->ptr)
  473.             {
  474.             if (pField->siz == sizeof(DWORD))
  475.                *(LPDWORD)lpv = dw;
  476.             else if (pField->siz == sizeof(WORD))
  477.                *(LPWORD)lpv = LOWORD(dw);
  478.             }
  479.          }
  480.          break;
  481.  
  482.       case AS_INT:
  483.          {
  484.          LPSTR pszStop = pds->ptr;
  485.          LONG  ii = strtol (pds->ptr, &pszStop, 10);
  486.          if (pszStop != pds->ptr)
  487.             {
  488.             if (pField->siz == sizeof(LONG))
  489.                *(LPLONG)lpv = ii;
  490.             else if (pField->siz == sizeof(short))
  491.                *(short int *)lpv = (short int)ii;
  492.             }
  493.          }
  494.          break;
  495.  
  496.       case AS_BYTES:
  497.          {
  498.          UINT   jj;
  499.          LPTSTR psz;
  500.  
  501.          psz = pds->ptr;
  502.          for (jj = 0; jj < pField->siz; ++jj)
  503.             {
  504.             ULONG uu;
  505.             LPTSTR pszStop;
  506.             while (*psz == '\t' || *psz == ' ')
  507.                ++psz;
  508.  
  509.             pszStop = psz;
  510.             uu = strtoul (psz, &pszStop, 10);
  511.             if (pszStop == psz)
  512.                break;
  513.  
  514.             lpv[jj] = (BYTE)uu;
  515.  
  516.             psz = pszStop;
  517.             }
  518.          }
  519.          break;
  520.  
  521.       case AS_HEX:
  522.          {
  523.          DWORD  dw = 0;
  524.          LPTSTR psz;
  525.  
  526.          psz = pds->ptr;
  527.          while (*psz == '\t' || *psz == ' ')
  528.              ++psz;
  529.  
  530.          if (psz[0] == '0' && (psz[1] == 'X' || psz[1] == 'x'))
  531.              psz += 2;
  532.  
  533.          while (*psz)
  534.             {
  535.             if (*psz >= '0' && *psz <= '9')
  536.                dw = (dw << 4) + *psz - '0';
  537.             else if ((*psz >= 'A' && *psz <= 'F') ||
  538.                      (*psz >= 'a' && *psz <= 'f'))
  539.                dw = (dw << 4) + (*psz & ~0x20) - 'A' + 10;
  540.             else
  541.                break;
  542.             ++psz;
  543.             }
  544.  
  545.          if (dw != 0 || (psz > pds->ptr && psz[-1] == '0'))
  546.             {
  547.             if (pField->siz == sizeof(DWORD))
  548.                *(LPDWORD)lpv = dw;
  549.             else if (pField->siz == sizeof(WORD))
  550.                *(LPWORD)lpv = LOWORD(dw);
  551.             }
  552.          }
  553.          break;
  554.       }
  555.  
  556.    return TRUE;
  557. }
  558.  
  559. /*+ DrawDsData
  560.  *
  561.  *-=================================================================*/
  562.  
  563. VOID WINAPI DrawDsData (
  564.    HDC          hDC,
  565.    PDSFIELDTBL  pTable,
  566.    PDSLINEINFO  pLineInfo, //
  567.    LPRECT       lpRect,     // rectangle to clip drawing to
  568.    POINT        ptOffset)   // scrolling offset for upper left corner
  569.    {
  570.    WORD        wOldAlign;  // temp, prev state of alignment
  571.    UINT        ii;         // general index variable
  572.    int         cx;         // current x position to draw at
  573.    int         cy;         // current y position to draw at
  574.    int         cyText;
  575.    PDSFIELD    pField;
  576.    struct _dsline * pLine;
  577.  
  578.    // do some simple error checking, if not a valid DC
  579.    // dont go any further.
  580.    //
  581.    if (!hDC)
  582.       return;
  583.  
  584.    // get the text metrics and initialize the max width variable
  585.    //
  586.    cyText = pLineInfo->cyLine;
  587.  
  588.    // setup the current x & y locations for writing text
  589.    //
  590.    cx = lpRect->left - ptOffset.x;
  591.    cy = lpRect->top - ptOffset.y;
  592.  
  593.    // draw each of the labels making a vertical
  594.    // column starting 'cx,cy'.  But be sure not to
  595.    // draw outside of the rectangle 'lpRect'
  596.    //
  597.    wOldAlign = SetTextAlign (hDC, TA_TOP | TA_LEFT);
  598.  
  599.    // clear the background
  600.    //
  601.    ExtTextOut (hDC, cx, cy, ETO_CLIPPED | ETO_OPAQUE, lpRect, "", 0, NULL);
  602.  
  603.    // draw the data
  604.    //
  605.    for (pLine = &pLineInfo->aLine[ii = 0];
  606.         ii < pLineInfo->nCurLine;
  607.         ++ii, ++pLine, cy += cyText)
  608.       {
  609.       char   sz[1024]; // buffer for formatting text info
  610.       LPBYTE lpv;
  611.       DSBUFF ds;
  612.       UINT   cb;
  613.  
  614.       if (cy < lpRect->top - cyText)
  615.          continue;
  616.       if (cy > lpRect->bottom)
  617.          break;
  618.  
  619.       pField = pTable[pLine->uStruct].pFields;
  620.       pField += pLine->uField;
  621.       lpv = pLine->lpv;
  622.  
  623.       sz[0] = 0;
  624.       GetFieldText (pField, lpv, pLine->uMember, sz, NUMELMS(sz), &ds);
  625.       if (cb = lstrlen (sz))
  626.          ExtTextOut (hDC,
  627.                      cx, cy,
  628.                      ETO_CLIPPED, lpRect, sz, cb, NULL);
  629.       }
  630.  
  631.    // restore text alignment and return
  632.    //
  633.    SetTextAlign (hDC, wOldAlign);
  634.  
  635.    return;
  636.    }
  637.  
  638. /*+ GetDsLabelWidth
  639.  *
  640.  *-=================================================================*/
  641.  
  642. int WINAPI GetDsLabelWidth (
  643.    HDC          hDC,
  644.    PDSFIELDTBL  pTable,
  645.    PDSLINEINFO  pLineInfo)
  646.    {
  647.    int  cxWidth = 0;
  648.    UINT ii;
  649.    struct _dsline * pLine = pLineInfo->aLine;
  650.  
  651.    for (pLine = &pLineInfo->aLine[ii = 0];
  652.         ii < pLineInfo->nCurLine;
  653.         ++ii, ++pLine)
  654.       {
  655.       PDSFIELD pFields = pTable[pLine->uStruct].pFields;
  656.       SIZE     size = {0,0};
  657.  
  658.       GetTextExtentPoint (hDC,
  659.                           pFields[pLine->uField].psz,
  660.                           lstrlen (pFields[pLine->uField].psz),
  661.                           &size);
  662.  
  663.       size.cx += (pLine->uDepth * 16) - 16;
  664.  
  665.       if (cxWidth < size.cx)
  666.          cxWidth = size.cx;
  667.       }
  668.  
  669.    return cxWidth;
  670.    }
  671.  
  672. /*+ AllocDsLineInfo
  673.  *
  674.  *-=================================================================*/
  675.  
  676. PDSLINEINFO WINAPI AllocDsLineInfo (
  677.    UINT nMax)
  678.    {
  679.    PDSLINEINFO pLineInfo;
  680.  
  681.    pLineInfo = GlobalAllocPtr (GHND, sizeof(DSLINEINFO)
  682.                                + sizeof(struct _dsline) * nMax);
  683.    pLineInfo->nMaxLine = nMax;
  684.    pLineInfo->nMaxDepth = 10;
  685.    pLineInfo->nCurLine = 0;
  686.    pLineInfo->nCurDepth = 0;
  687.    return pLineInfo;
  688.    }
  689.  
  690. /*+ BuildDsLineInfo
  691.  *
  692.  *-=================================================================*/
  693.  
  694. VOID WINAPI BuildDsLineInfo (
  695.    PDSFIELDTBL  pTable,
  696.    UINT         uStruct,    //
  697.    LPVOID       lpData,     // pointer to structure to show
  698.    WORD         nMember,
  699.    WORD         nLastMember,
  700.    PDSLINEINFO  pLineInfo)
  701.    {
  702.    UINT      uField;
  703.    PDSFIELD  pField;
  704.    UINT      cbStruct;
  705.  
  706.    if (!pTable)
  707.      return;
  708.    pField = pTable[uStruct].pFields;
  709.    cbStruct = pTable[uStruct].cbSize;
  710.  
  711.  
  712.    if (pLineInfo->nCurDepth >= pLineInfo->nMaxDepth)
  713.       return;
  714.  
  715.    ++pLineInfo->nCurDepth;
  716.  
  717.    do
  718.    {
  719.       // now build the lines
  720.       //
  721.       for (uField = 0; pField->psz != NULL; ++pField, ++uField)
  722.          {
  723.          UINT   ix;
  724.  
  725.          if (pLineInfo->nCurLine >= pLineInfo->nMaxLine)
  726.             break;
  727.  
  728.          ix = 0;
  729.          do {
  730.             struct _dsline * pLine;
  731.             LPBYTE lpv;
  732.  
  733.             if (pLineInfo->nCurLine >= pLineInfo->nMaxLine)
  734.                break;
  735.  
  736.             pLine = &pLineInfo->aLine[pLineInfo->nCurLine];
  737.             ++pLineInfo->nCurLine;
  738.  
  739.             pLine->uStruct = uStruct;
  740.             pLine->uField = uField;
  741.             pLine->uDepth = pLineInfo->nCurDepth;
  742.             pLine->uMember = ix;
  743.             pLine->lpv = (LPVOID)-2;
  744.  
  745.             __try
  746.                {
  747.                lpv = (LPBYTE)lpData + (cbStruct * nMember) + pField->off;
  748.  
  749.                pLine->lpv = lpv;
  750.  
  751.                if (HIWORD(lpv)) // simple validity check...
  752.                   {
  753.                   lpv += (ix * pField->siz);
  754.                   if ((pField->fmt & 0x1FF) == AS_STRUCT)
  755.                       BuildDsLineInfo (pTable, pField->aux, lpv,
  756.                                        (WORD)ix, (WORD)ix, pLineInfo);
  757.                   }
  758.                }
  759.             __except (AccessFilter(GetExceptionCode()))
  760.                {
  761.                }
  762.             } while (++ix < pField->array);
  763.          }
  764.  
  765.    } while (++nMember <= nLastMember);
  766.  
  767.    --pLineInfo->nCurDepth;
  768.    return;
  769.    }
  770.  
  771. /*+ GetViewExtent
  772.  *
  773.  *-=================================================================*/
  774.  
  775. int WINAPI GetViewExtent (
  776.    HDC         hDC,
  777.    PVIEWINIT   pvim,
  778.    PDSLINEINFO pLineInfo,
  779.    LPSIZE      lpItemSize,
  780.    LPSIZE      lpTotalSize)
  781.    {
  782.    TEXTMETRIC tm;
  783.  
  784.    pLineInfo->nCurLine = 0;
  785.    pLineInfo->nCurDepth = 0;
  786.  
  787.    BuildDsLineInfo (pvim->pTable,
  788.                     pvim->uStruct,
  789.                     pvim->lpData,
  790.                     0, 0,
  791.                     pLineInfo);
  792.  
  793.    GetTextMetrics (hDC, &tm);
  794.    pLineInfo->cyLine = tm.tmHeight + tm.tmExternalLeading;
  795.  
  796.    lpItemSize->cx = GetDsLabelWidth (hDC, pvim->pTable, pLineInfo);
  797.    lpItemSize->cy = pLineInfo->cyLine;
  798.  
  799.    lpTotalSize->cx = lpItemSize->cx * 2;
  800.    lpTotalSize->cy = pLineInfo->cyLine * pLineInfo->nCurLine;
  801.  
  802.    return pLineInfo->nCurLine;
  803.    }
  804.  
  805. /*+
  806.  *  ViewWndProc
  807.  *
  808.  *-=================================================================*/
  809.  
  810. // misc manifest constants
  811. //
  812. #define HTLABEL 1
  813. #define HTEDGE  2
  814. #define HTDATA  3
  815.  
  816. typedef struct _viewstate {
  817.    UINT        wLabelWidth;
  818.    SIZE        sTotal;
  819.    SIZE        sLabel;
  820.    SIZE        sScroll;
  821.    POINT       ptVisible;
  822.    //HBRUSH      hBrFace;
  823.    HFONT       hFontLabel;
  824.    HFONT       hFontData;
  825.    HMENU       hMenu;
  826.    WORD        wHit;
  827.    UINT        nHitLine;
  828.    HCURSOR     hCurEdge;
  829.    POINT       ptEdgeBegin;
  830.    int         cxEdgeSlop;
  831.    POINT       ptLastEdge;
  832.    int         nWindowCnt;
  833.    PDSLINEINFO pLineInfo;
  834.    int         cyLine;
  835.    int         cyWnd;
  836.    VIEWINIT    vi;
  837.    } VIEWSTATE, *PVIEWSTATE;
  838.  
  839.  
  840. /*+
  841.  *
  842.  *
  843.  *-=================================================================*/
  844.  
  845. VOID WINAPI UpdateScrollRanges (
  846.    PVIEWSTATE pv,
  847.    HWND       hWnd)
  848.    {
  849.    RECT rc;
  850.  
  851.    pv->sTotal.cy = pv->cyLine * pv->pLineInfo->nCurLine;
  852.  
  853.    GetClientRect (hWnd, &rc);
  854.    pv->cyWnd = (rc.bottom - rc.top);
  855.    pv->cyWnd -= (pv->cyWnd % pv->cyLine);
  856.    pv->sScroll.cy = max (pv->sTotal.cy - pv->cyWnd, 0);
  857.    pv->ptVisible.y = min (pv->sScroll.cy, pv->ptVisible.y);
  858.  
  859.    SetScrollRange (hWnd, SB_VERT, 0, pv->sScroll.cy, FALSE);
  860.    SetScrollPos (hWnd, SB_VERT, pv->ptVisible.y, TRUE);
  861.    }
  862.  
  863. /*+
  864.  *  ViewPrivate
  865.  *
  866.  *-=================================================================*/
  867.  
  868. UINT WINAPI EditInPlace (
  869.    HWND       hWnd,
  870.    PVIEWSTATE pv,
  871.    UINT       nLine);
  872.  
  873. LONG WINAPI ViewPrivate (
  874.    HWND   hWnd,
  875.    UINT   wMsgID,
  876.    WPARAM wParam,
  877.    LPARAM lParam)
  878.    {
  879.    LONG       lRet = 0l;               // return value from this routine
  880.    PVIEWSTATE pv;
  881.  
  882.    pv = (LPVOID) GetWindowLong (hWnd, GWL_USERDATA);
  883.    if (!pv)
  884.       return 0;
  885.  
  886.    switch (wMsgID)
  887.       {
  888.       case VM_GETDATA:
  889.          lRet = (LRESULT)pv->vi.lpData;
  890.          break;
  891.  
  892.       case VM_SETDATA:
  893.          lRet = (LRESULT)pv->vi.lpData;
  894.          pv->vi.lpData = (LPVOID)lParam;
  895.          if (lRet != (LRESULT)pv->vi.lpData)
  896.             {
  897.             RECT rc;
  898.  
  899.             pv->pLineInfo->nCurLine = 0;
  900.             pv->pLineInfo->nCurDepth = 0;
  901.  
  902.             BuildDsLineInfo (pv->vi.pTable,
  903.                              pv->vi.uStruct,
  904.                              pv->vi.lpData,
  905.                              0, 0,
  906.                              pv->pLineInfo);
  907.  
  908.             GetClientRect (hWnd, &rc);
  909.             rc.left = pv->wLabelWidth + 5;
  910.             InvalidateRect (hWnd, &rc, FALSE);
  911.             }
  912.          break;
  913.  
  914.       case VM_INVALIDATE:
  915.          {
  916.          RECT  rc;
  917.          int   yLine;
  918.  
  919.          if (!wParam && !lParam)
  920.             InvalidateRect (hWnd, NULL, FALSE);
  921.  
  922.          GetClientRect (hWnd, &rc);
  923.          yLine = ((int)lParam * pv->cyLine) - pv->ptVisible.y;
  924.          if (yLine >= rc.top && yLine <= rc.bottom)
  925.             {
  926.             rc.left += pv->wLabelWidth + 5;
  927.             rc.top += yLine;
  928.             rc.bottom = rc.top + (pv->cyLine * max(1, wParam));
  929.             InvalidateRect (hWnd, &rc, FALSE);
  930.             }
  931.          }
  932.          break;
  933.  
  934.       case VM_SETSEL:
  935.          {
  936.          UINT nLine = (UINT)lParam;
  937.          BOOL bPrev = (BOOL)wParam;
  938.  
  939.          while (nLine < pv->pLineInfo->nCurLine)
  940.             {
  941.             struct _dsline * pLine = &pv->pLineInfo->aLine[nLine];
  942.             PDSFIELD pField = pv->vi.pTable[pLine->uStruct].pFields + pLine->uField;
  943.             if (pField->fmt & IS_EDIT)
  944.                {
  945.                RECT rc;
  946.                int  yLine;
  947.  
  948.                GetClientRect (hWnd, &rc);
  949.                yLine = (int)(nLine * pv->cyLine) - pv->ptVisible.y;
  950.                if (yLine >= rc.top && (yLine + pv->cyLine) <= rc.bottom)
  951.                   pv->nHitLine = nLine, lRet = 1;
  952.                break;
  953.                }
  954.             if (bPrev && nLine == 0)
  955.                 break;
  956.             nLine = bPrev ? nLine-1 : nLine+1;
  957.             }
  958.  
  959.          }
  960.          break;
  961.  
  962.       case VM_EDITNEXT:
  963.          {
  964.          UINT nLine = pv->nHitLine;
  965.          BOOL bPrev = (BOOL)wParam;
  966.  
  967.          if (bPrev && nLine == 0)
  968.             break;
  969.          nLine = bPrev ? nLine-1 : nLine+1;
  970.  
  971.          if (ViewPrivate (hWnd, VM_SETSEL, bPrev, nLine))
  972.             {
  973.             EditInPlace (hWnd, pv, pv->nHitLine);
  974.             }
  975.          }
  976.       }
  977.  
  978.    return lRet;
  979.    }
  980.  
  981. /*+
  982.  *  
  983.  *
  984.  *-=================================================================*/
  985.  
  986. LRESULT Notify (
  987.    HWND hWnd,
  988.    UINT code)
  989. {
  990.    NMHDR nm;
  991.  
  992.    nm.hwndFrom = hWnd;
  993.    nm.idFrom = GetDlgCtrlID(hWnd);
  994.    nm.code = code;
  995.    return SendMessage (GetParent(hWnd), WM_NOTIFY, nm.idFrom, (LPARAM)(LPVOID)&nm);
  996. }
  997.  
  998. /*+
  999.  *  EditInPlace
  1000.  *
  1001.  *-=================================================================*/
  1002.  
  1003. UINT WINAPI EditInPlace (
  1004.    HWND       hWnd,
  1005.    PVIEWSTATE pv,
  1006.    UINT       nLine)
  1007.    {
  1008.    PDSFIELDTBL  pTable = pv->vi.pTable;
  1009.    PDSLINEINFO  pLineInfo = pv->pLineInfo;
  1010.    struct _dsline * pLine;
  1011.    PDSFIELD         pField;
  1012.    TCHAR        sz[1000];
  1013.    HWND         hWndEdit;
  1014.    RECT         rc;
  1015.    MSG          msg;
  1016.    UINT         uId;
  1017.    DSBUFF       ds;
  1018.  
  1019.    if (nLine >= pLineInfo->nCurLine)
  1020.       return 0;
  1021.  
  1022.    pLine = &pLineInfo->aLine[nLine];
  1023.    pField = pTable[pLine->uStruct].pFields + pLine->uField;
  1024.  
  1025.    GetFieldText (pField, pLine->lpv, pLine->uMember, sz, NUMELMS(sz), &ds);
  1026.  
  1027.    GetClientRect (hWnd, &rc);
  1028.    rc.left += pv->wLabelWidth + 5;
  1029.    rc.top = (nLine * pv->cyLine) - pv->ptVisible.y -2;
  1030.    rc.bottom = rc.top + pv->cyLine + 4;
  1031.  
  1032.    hWndEdit = CreateWindowEx (fdwExStyle | WS_EX_NOPARENTNOTIFY,
  1033.                               "Edit",
  1034.                               sz,
  1035.                               ES_AUTOHSCROLL |
  1036.                               ES_LEFT |
  1037.                               WS_CHILD | WS_BORDER,
  1038.                               rc.left, rc.top,
  1039.                               rc.right - rc.left, rc.bottom - rc.top,
  1040.                               hWnd,
  1041.                               (HMENU)IDE_VALUE,
  1042.                               GetWindowInstance(hWnd),
  1043.                               NULL);
  1044.    if ( ! hWndEdit)
  1045.       return 0;
  1046.  
  1047.    SendMessage (hWndEdit, WM_SETFONT, (WPARAM)pv->hFontData, 0);
  1048.    Edit_SetSel (hWndEdit, 0, NUMELMS(sz)+2);
  1049.    ShowWindow (hWndEdit, SW_SHOWNORMAL);
  1050.    SetFocus (hWndEdit);
  1051.  
  1052.    uId = IDOK;
  1053.    bInEditingMode = TRUE;
  1054.    do {
  1055.       if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
  1056.          {
  1057.          if (msg.hwnd != hWndEdit &&
  1058.              (msg.message == WM_LBUTTONDOWN ||
  1059.               msg.message == WM_RBUTTONDOWN))
  1060.             break;
  1061.  
  1062.          if (msg.message == WM_QUIT)
  1063.             break;
  1064.  
  1065.          if (msg.message == WM_SYSKEYDOWN)
  1066.             break;
  1067.  
  1068.          GetMessage (&msg, NULL, 0, 0);
  1069.          if ((msg.hwnd == hWndEdit) && (msg.message == WM_KEYDOWN))
  1070.             {
  1071.             if (LOWORD(msg.wParam) == VK_RETURN)
  1072.                break;
  1073.             else if (LOWORD(msg.wParam) == VK_TAB)
  1074.                {
  1075.                PostMessage (hWnd, VM_EDITNEXT, (WPARAM)GetKeyState(VK_SHIFT), 0);
  1076.                break;
  1077.                }
  1078.             else if (LOWORD(msg.wParam) == VK_ESCAPE)
  1079.                {
  1080.                uId = IDCANCEL;
  1081.                break;
  1082.                }
  1083.             }
  1084.  
  1085.          TranslateMessage (&msg);
  1086.          DispatchMessage (&msg);
  1087.          }
  1088.       else
  1089.          {
  1090.          //SendMessage (hWnd, WM_ENTERIDLE, 0, 0);
  1091.          WaitMessage();
  1092.          }
  1093.  
  1094.       } while (bInEditingMode && GetFocus() == hWndEdit);
  1095.  
  1096.    bInEditingMode = FALSE;
  1097.    if (uId == IDOK)
  1098.    {
  1099.        GetWindowText (hWndEdit, sz, NUMELMS(sz));
  1100.        ds.ptr = sz;
  1101.        ds.cch = lstrlen(ds.ptr)+1;
  1102.        SetFieldText (pLine, pField, &ds);
  1103.        ViewPrivate (hWnd, VM_INVALIDATE, 0, nLine);
  1104.        Notify (hWnd, VN_CHANGE);
  1105.    }
  1106.    DestroyWindow (hWndEdit);
  1107.  
  1108.    return uId;
  1109. }
  1110.  
  1111. /*+
  1112.  *  CopyLineToClip
  1113.  *
  1114.  *-=================================================================*/
  1115.  
  1116. LONG WINAPI CopyLineToClip (
  1117.    HWND       hWnd,
  1118.    PVIEWSTATE pv,
  1119.    UINT       nLine)
  1120. {
  1121.    PDSFIELDTBL  pTable = pv->vi.pTable;
  1122.    PDSLINEINFO  pLineInfo = pv->pLineInfo;
  1123.    HGLOBAL      hMem;
  1124.    struct _dsline * pLine;
  1125.    PDSFIELD         pField;
  1126.    UINT         cfType;
  1127.  
  1128.    pLine = &pLineInfo->aLine[nLine];
  1129.    pField = pTable[pLine->uStruct].pFields + pLine->uField;
  1130.  
  1131.    switch (pField->fmt & 0xFF)
  1132.       {
  1133.       case AS_BYTES:
  1134.       case AS_DUMP:
  1135.          {
  1136.          LPRIFF pRiff;
  1137.          LPBYTE lpv;
  1138.  
  1139.          lpv = pLine->lpv;
  1140.          if (pField->fmt & AS_REF)
  1141.             lpv = *(LPBYTE *)lpv;
  1142.          lpv += (pLine->uMember * pField->siz);
  1143.  
  1144.          cfType = CF_RIFF;
  1145.          hMem = GlobalAlloc (GHND, pField->siz + sizeof(RIFF));
  1146.          if (!(pRiff = GlobalLock (hMem)))
  1147.             return 0;
  1148.  
  1149.          pRiff->fcc = MAKEFOURCC('B','y','t','e');
  1150.          pRiff->cb = pField->siz;
  1151.          CopyMemory (pRiff+1, lpv, pField->siz);
  1152.          GlobalUnlock (hMem);
  1153.          }
  1154.          break;
  1155.  
  1156.       case AS_XMODE:
  1157.          {
  1158.          UINT (*pfnMode)(LPSTR, UINT, UINT, UINT, UINT) = (LPVOID)pField->aux;
  1159.          LPBYTE lpv;
  1160.  
  1161.          lpv = pLine->lpv;
  1162.          if (pField->fmt & AS_REF)
  1163.             lpv = *(LPBYTE *)lpv;
  1164.          lpv += (pLine->uMember * pField->siz);
  1165.  
  1166.          if (pField->siz == sizeof(DWORD))
  1167.              {
  1168.              if (pfnMode (NULL, (UINT)hWnd, *(UINT *)lpv, pField->array, WM_COPY))
  1169.                 return 0;
  1170.              }
  1171.          else
  1172.              {
  1173.              if (pfnMode (NULL, (UINT)hWnd, (UINT)lpv, pField->array, WM_COPY))
  1174.                 return 0;
  1175.              }
  1176.          }
  1177.          // fall through
  1178.       default:
  1179.          {
  1180.          DSBUFF ds;
  1181.          LPSTR  psz;
  1182.          UINT   cch = 128 * 5 + 10;
  1183.          cfType = CF_TEXT;
  1184.  
  1185.          hMem = GlobalAlloc (GHND, cch);
  1186.          if (!(psz = GlobalLock (hMem)))
  1187.             return 0;
  1188.  
  1189.          // get data for the current line into the global
  1190.          // object.
  1191.          //
  1192.          GetFieldText (pField, pLine->lpv, pLine->uMember, psz, cch, &ds);
  1193.  
  1194.          // truncate the global object to fit the size of the data
  1195.          //
  1196.          GlobalUnlock (hMem);
  1197.          GlobalReAlloc (hMem, lstrlen(psz) + 2, 0);
  1198.          }
  1199.          break;
  1200.       }
  1201.  
  1202.    if (OpenClipboard (hWnd))
  1203.        {
  1204.        EmptyClipboard ();
  1205.        SetClipboardData (cfType, hMem);
  1206.        CloseClipboard ();
  1207.        }
  1208.    else
  1209.        GlobalFree (hMem);
  1210.  
  1211.    return 0;
  1212. }
  1213.  
  1214. /*+
  1215.  *  PasteLineFromClip
  1216.  *
  1217.  *-=================================================================*/
  1218.  
  1219. LONG WINAPI PasteLineFromClip (
  1220.    HWND       hWnd,
  1221.    PVIEWSTATE pv,
  1222.    UINT       nLine)
  1223. {
  1224.    HGLOBAL hMem;
  1225.    PDSFIELDTBL  pTable = pv->vi.pTable;
  1226.    PDSLINEINFO  pLineInfo = pv->pLineInfo;
  1227.    struct _dsline * pLine = &pLineInfo->aLine[nLine];
  1228.    PDSFIELD     pField = pTable[pLine->uStruct].pFields + pLine->uField;
  1229.    LONG lRet = 0;
  1230.  
  1231.    switch (pField->fmt & 0xFF)
  1232.       {
  1233.       case AS_BYTES:
  1234.       case AS_DUMP:
  1235.           if (OpenClipboard (hWnd))
  1236.              {
  1237.              if (hMem = GetClipboardData (CF_RIFF))
  1238.                {
  1239.                LPRIFF pRiff;
  1240.                LPBYTE lpv;
  1241.  
  1242.                lpv = pLine->lpv;
  1243.                if (pField->fmt & AS_REF)
  1244.                   lpv = *(LPBYTE *)lpv;
  1245.                lpv += (pLine->uMember * pField->siz);
  1246.  
  1247.                if (pRiff = GlobalLock (hMem))
  1248.                   {
  1249.                   if (pRiff->fcc == MAKEFOURCC('B','y','t','e') &&
  1250.                       pRiff->cb == pField->siz)
  1251.                      {
  1252.                      CopyMemory (lpv, pRiff+1, pField->siz);
  1253.                      lRet = 2;
  1254.                      }
  1255.                   GlobalUnlock (hMem);
  1256.                   }
  1257.                } 
  1258.             CloseClipboard ();
  1259.             }
  1260.          break;
  1261.  
  1262.       case AS_XMODE:
  1263.          {
  1264.          UINT (*pfnMode)(LPSTR, UINT, UINT, UINT, UINT) = (LPVOID)pField->aux;
  1265.          LPBYTE lpv;
  1266.  
  1267.          lpv = pLine->lpv;
  1268.          if (pField->fmt & AS_REF)
  1269.             lpv = *(LPBYTE *)lpv;
  1270.          lpv += (pLine->uMember * pField->siz);
  1271.  
  1272.          if (pField->siz == sizeof(DWORD))
  1273.              lRet = pfnMode (NULL, (UINT)hWnd, *(UINT *)lpv, pField->array, WM_PASTE);
  1274.          else
  1275.              lRet = pfnMode (NULL, (UINT)hWnd, (UINT)lpv, pField->array, WM_PASTE);
  1276.  
  1277.          // fall through if pfnMode handled the paste operation
  1278.          //
  1279.          if (lRet != 0)
  1280.             break;
  1281.          }
  1282.          // fall through
  1283.       default:
  1284.          if (OpenClipboard (hWnd))
  1285.             {
  1286.             if (hMem = GetClipboardData (CF_TEXT))
  1287.                {
  1288.                DSBUFF ds;
  1289.                ds.ptr = GlobalLock (hMem);
  1290.                if (ds.ptr)
  1291.                   {
  1292.                   ds.cch = lstrlen(ds.ptr)+1;
  1293.                   SetFieldText (pLine, pField, &ds);
  1294.                   lRet = 2;
  1295.                   }
  1296.                }
  1297.             CloseClipboard ();
  1298.             }
  1299.          break;
  1300.       }
  1301.  
  1302.    if (lRet > 0)
  1303.    {
  1304.       ViewPrivate (hWnd, VM_INVALIDATE, 0, nLine);
  1305.       Notify (hWnd, VN_CHANGE);
  1306.    }
  1307.  
  1308.    return lRet;
  1309. }
  1310.  
  1311. /*+
  1312.  *  ViewCommands
  1313.  *
  1314.  *-=================================================================*/
  1315.  
  1316. LONG WINAPI ViewCommands (
  1317.    HWND   hWnd,
  1318.    WPARAM wParam,
  1319.    LPARAM lParam)
  1320.    {
  1321.    LONG       lRet = 0l;               // return value from this routine
  1322.    PVIEWSTATE pv;
  1323.  
  1324.    pv = (LPVOID) GetWindowLong (hWnd, GWL_USERDATA);
  1325.    if (!pv)
  1326.       return 0;
  1327.  
  1328.    switch (GET_WM_COMMAND_ID(wParam,lParam))
  1329.       {
  1330.       case IDM_OBJEDIT:
  1331.           EditInPlace   (hWnd, pv, pv->nHitLine);
  1332.           //EditLineValue (hWnd, pv, pv->nHitLine);
  1333.           break;
  1334.  
  1335.       case IDM_EDITCOPY:
  1336.           CopyLineToClip (hWnd, pv, pv->nHitLine);
  1337.           break;
  1338.  
  1339.       case IDM_EDITPASTE:
  1340.           PasteLineFromClip (hWnd, pv, pv->nHitLine);
  1341.           break;
  1342.       }
  1343.  
  1344.    return lRet;
  1345.    }
  1346.  
  1347. /*+
  1348.  *  ViewWndProc
  1349.  *
  1350.  *-=================================================================*/
  1351.  
  1352. LONG CALLBACK ViewWndProc (
  1353.    HWND   hWnd,
  1354.    UINT   wMsgID,
  1355.    WPARAM wParam,
  1356.    LPARAM lParam)
  1357.    {
  1358.    LONG       lRet = 0l;               // return value from this routine
  1359.    PVIEWSTATE pv;
  1360.  
  1361.    pv = (LPVOID) GetWindowLong (hWnd, GWL_USERDATA);
  1362.  
  1363.    if (wMsgID >= WM_USER && wMsgID < 0x8000)
  1364.       lRet = ViewPrivate (hWnd, wMsgID, wParam, lParam);
  1365.    else
  1366.    switch (wMsgID)
  1367.       {
  1368.       case WM_NCHITTEST:
  1369.          lRet = DefProc (hWnd, wMsgID, wParam, lParam);
  1370.          if (lRet == HTCLIENT)
  1371.             {
  1372.             POINT pt = {MAKEPOINTS(lParam).x, MAKEPOINTS(lParam).y};
  1373.  
  1374.             ScreenToClient (hWnd, &pt);
  1375.  
  1376.             pv->wHit = HTEDGE;
  1377.             if (pt.x <= (int)pv->wLabelWidth -4)
  1378.                pv->wHit = HTLABEL;
  1379.             else if (pt.x >= (int)pv->wLabelWidth +4)
  1380.                pv->wHit = HTDATA;
  1381.             }
  1382.          break;
  1383.  
  1384.      #if 0
  1385.       case WM_SETCURSOR:
  1386.          if (LOWORD (lParam) == HTCLIENT &&
  1387.              pv->wHit == HTEDGE &&
  1388.              pv->hCurEdge != NULL)
  1389.             SetCursor (pv->hCurEdge);
  1390.          else
  1391.             lRet = DefProc (hWnd, wMsgID, wParam, lParam);
  1392.          break;
  1393.      #endif
  1394.  
  1395.       case WM_LBUTTONDBLCLK:
  1396.          {
  1397.          POINT pt = {MAKEPOINTS(lParam).x, MAKEPOINTS(lParam).y};
  1398.          PDSFIELDTBL  pTable = pv->vi.pTable;
  1399.          PDSLINEINFO  pLineInfo = pv->pLineInfo;
  1400.          UINT         nLine = (pt.y + pv->ptVisible.y) / pv->cyLine;
  1401.  
  1402.          lRet = DefProc (hWnd, wMsgID, wParam, lParam);
  1403.  
  1404.          if (nLine < pLineInfo->nCurLine)
  1405.              {
  1406.              struct _dsline * pLine = &pLineInfo->aLine[nLine];
  1407.              PDSFIELD pField = pTable[pLine->uStruct].pFields + pLine->uField;
  1408.  
  1409.              if ((pField->fmt & IS_EDIT) && pv->hMenu)
  1410.                 {
  1411.                 pv->nHitLine = nLine;
  1412.                 SetCapture (hWnd);
  1413.                 }
  1414.             }
  1415.          break;
  1416.          }
  1417.  
  1418.       case WM_LBUTTONUP:
  1419.          {
  1420.          if (GetCapture() == hWnd)
  1421.             {
  1422.             POINT pt = {MAKEPOINTS(lParam).x, MAKEPOINTS(lParam).y};
  1423.             PDSFIELDTBL  pTable = pv->vi.pTable;
  1424.             PDSLINEINFO  pLineInfo = pv->pLineInfo;
  1425.             UINT         nLine = (pt.y + pv->ptVisible.y) / pv->cyLine;
  1426.  
  1427.             ReleaseCapture ();
  1428.  
  1429.             if (nLine == pv->nHitLine)
  1430.                PostMessage (hWnd, WM_COMMAND, IDM_OBJEDIT, 0);
  1431.             }
  1432.          lRet = DefProc (hWnd, wMsgID, wParam, lParam);
  1433.          break;
  1434.          }
  1435.  
  1436.       case WM_LBUTTONDOWN:
  1437.       case WM_RBUTTONDOWN:
  1438.          SetFocus (hWnd);
  1439.          lRet = DefProc (hWnd, wMsgID, wParam, lParam);
  1440.          break;
  1441.  
  1442.       case WM_RBUTTONUP:
  1443.          {
  1444.          POINT pt = {MAKEPOINTS(lParam).x, MAKEPOINTS(lParam).y};
  1445.          PDSFIELDTBL  pTable = pv->vi.pTable;
  1446.          PDSLINEINFO  pLineInfo = pv->pLineInfo;
  1447.          UINT         nLine = (pt.y + pv->ptVisible.y) / pv->cyLine;
  1448.  
  1449.  
  1450.          lRet = DefProc (hWnd, wMsgID, wParam, lParam);
  1451.  
  1452.          if (nLine < pLineInfo->nCurLine)
  1453.              {
  1454.              struct _dsline * pLine = &pLineInfo->aLine[nLine];
  1455.              PDSFIELD pField = pTable[pLine->uStruct].pFields + pLine->uField;
  1456.  
  1457.              //if (pv->wHit == HTLABEL)
  1458.              //   {
  1459.              //   }
  1460.  
  1461.              if ((pField->fmt & IS_EDIT) && pv->hMenu)
  1462.                 {
  1463.                 pv->nHitLine = nLine;
  1464.                 ClientToScreen (hWnd, &pt);
  1465.                 TrackPopupMenu (pv->hMenu,
  1466.                                #if (WINVER >= 0x400)
  1467.                                 TPM_TOPALIGN |
  1468.                                #endif
  1469.                                 TPM_LEFTALIGN | TPM_RIGHTBUTTON,
  1470.                                 pt.x, pt.y,
  1471.                                 0,
  1472.                                 hWnd,
  1473.                                 NULL);
  1474.                 }
  1475.             }
  1476.          break;
  1477.  
  1478.          }
  1479.  
  1480.       case WM_COMMAND:
  1481.          lRet = ViewCommands (hWnd, wParam, lParam);
  1482.          break;
  1483.  
  1484.       case WM_SIZE:
  1485.          lRet = DefProc (hWnd, wMsgID, wParam, lParam);
  1486.          UpdateScrollRanges (pv, hWnd);
  1487.          break;
  1488.  
  1489.       case WM_KEYDOWN:
  1490.          {
  1491.          int  nNewPos = -1;
  1492.  
  1493.          switch (LOWORD(wParam))
  1494.             {
  1495.             case VK_UP:
  1496.                nNewPos = pv->ptVisible.y - pv->cyLine;
  1497.                break;
  1498.  
  1499.             case VK_DOWN:
  1500.                nNewPos = pv->ptVisible.y + pv->cyLine;
  1501.                break;
  1502.  
  1503.             case VK_PRIOR:
  1504.                nNewPos = pv->ptVisible.y - (pv->cyWnd - pv->cyLine);
  1505.                break;
  1506.  
  1507.             case VK_NEXT:
  1508.                nNewPos = pv->ptVisible.y + (pv->cyWnd - pv->cyLine);
  1509.                break;
  1510.             }
  1511.  
  1512.          if (nNewPos != -1)
  1513.             {
  1514.             nNewPos = min (nNewPos, pv->sScroll.cy);
  1515.             nNewPos = max (nNewPos, 0);
  1516.             ScrollWindow (hWnd, 0, pv->ptVisible.y - nNewPos, NULL, NULL);
  1517.             pv->ptVisible.y = nNewPos;
  1518.             SetScrollPos (hWnd, SB_VERT, pv->ptVisible.y, TRUE);
  1519.             }
  1520.          break;
  1521.          }
  1522.  
  1523.      case WM_VSCROLL:
  1524.          {
  1525.          int  nPos;
  1526.          int  nNewPos = -1;
  1527.          WORD wScrollCode;
  1528.  
  1529.          wScrollCode = LOWORD (wParam);
  1530.          nPos        = (int)HIWORD (wParam);
  1531.       
  1532.          switch (wScrollCode)
  1533.             {
  1534.             case SB_LINEUP:
  1535.                nNewPos = pv->ptVisible.y - pv->cyLine;
  1536.                break;
  1537.  
  1538.             case SB_LINEDOWN:
  1539.                nNewPos = pv->ptVisible.y + pv->cyLine;
  1540.                break;
  1541.  
  1542.             case SB_PAGEUP:
  1543.                nNewPos = pv->ptVisible.y - (pv->cyWnd - pv->cyLine);
  1544.                break;
  1545.  
  1546.             case SB_PAGEDOWN:
  1547.                nNewPos = pv->ptVisible.y + (pv->cyWnd - pv->cyLine);
  1548.                break;
  1549.  
  1550.             case SB_THUMBPOSITION:
  1551.                nNewPos = nPos - (nPos % pv->cyLine);
  1552.                break;
  1553.             }
  1554.  
  1555.  
  1556.          if (nNewPos != -1)
  1557.             {
  1558.             nNewPos = min (nNewPos, pv->sScroll.cy);
  1559.             nNewPos = max (nNewPos, 0);
  1560.             ScrollWindow (hWnd, 0, pv->ptVisible.y - nNewPos, NULL, NULL);
  1561.             pv->ptVisible.y = nNewPos;
  1562.             SetScrollPos (hWnd, SB_VERT, pv->ptVisible.y, TRUE);
  1563.             }
  1564.          break;
  1565.          }
  1566.  
  1567.       case WM_ERASEBKGND:
  1568.          {
  1569.          RECT rc;
  1570.          lRet = DefWindowProc (hWnd, wMsgID, wParam, lParam);
  1571.  
  1572.          GetClientRect (hWnd, &rc);
  1573.          //rc.left = pv->wLabelWidth + 3;
  1574.          //TrideeWellShadow ( (HDC)wParam, &rc);
  1575.  
  1576.          SetTextColor ( (HDC)wParam, RGB (0,0,128));
  1577.          //SetBkColor ( (HDC)wParam, GetSysColor (COLOR_BTNFACE));
  1578.  
  1579.          //rc.left = 0;
  1580.          rc.right = pv->wLabelWidth;
  1581.          //TrideeWellShadow ( (HDC)wParam, &rc);
  1582.          if (pv->hFontLabel)
  1583.             SelectObject ((HDC)wParam, pv->hFontLabel);
  1584.  
  1585.          DrawDsLabels ((HDC)wParam,
  1586.                        pv->vi.pTable,
  1587.                        pv->pLineInfo,
  1588.                        &rc,
  1589.                        pv->ptVisible);
  1590.          break;
  1591.          }
  1592.  
  1593.       case WM_PAINT:
  1594.          {
  1595.          PAINTSTRUCT ps;           // structure for BeginPaint
  1596.          HDC         hDC;          // DC to draw info into
  1597.          RECT        rcClip;       // clip rect for drawing
  1598.  
  1599.          // and draw the info into our client area
  1600.          //
  1601.          hDC = BeginPaint (hWnd, &ps);
  1602.          GetClientRect (hWnd, &rcClip);
  1603.          rcClip.left += pv->wLabelWidth + 5;
  1604.  
  1605.          if (pv->hFontData)
  1606.             SelectObject (hDC, pv->hFontData);
  1607.          SetTextColor (hDC, GetSysColor (COLOR_WINDOWTEXT));
  1608.          SetBkColor (hDC, GetSysColor (COLOR_WINDOW));
  1609.  
  1610.          DrawDsData (hDC,
  1611.                      pv->vi.pTable,
  1612.                      pv->pLineInfo,
  1613.                      &rcClip,
  1614.                      pv->ptVisible);
  1615.  
  1616.          EndPaint (hWnd, &ps);
  1617.          break;
  1618.          }
  1619.  
  1620.       case WM_CREATE:
  1621.          {
  1622.          HDC               hDC;
  1623.          char              sz[120];
  1624.          LPCREATESTRUCT    lpCreate = (LPCREATESTRUCT)lParam;
  1625.          POINT             pt = {0,0};
  1626.  
  1627.          pv = LocalAlloc (LPTR, sizeof(VIEWSTATE));
  1628.          if (!pv)
  1629.             return -1;
  1630.          SetWindowLong (hWnd, GWL_USERDATA, (LONG)pv);
  1631.  
  1632.          // init local state information
  1633.          //
  1634.          pv->pLineInfo = AllocDsLineInfo (1000);
  1635.          //pv->hBrFace = TrideeCreate (hWnd);
  1636.           //CreateFontIndirect (&lfMain);
  1637.          pv->hFontLabel = GetStockObject (DEFAULT_GUI_FONT);
  1638.          pv->hFontData  = GetStockObject (ANSI_FIXED_FONT);
  1639.  
  1640.          pv->hMenu = CreatePopupMenu ();
  1641.          //AppendMenuItem (pv->hMenu, &mii);
  1642.          AppendMenu (pv->hMenu, MF_STRING, IDM_OBJEDIT, "&Edit...");
  1643.          AppendMenu (pv->hMenu, MF_STRING, IDM_EDITCOPY, "&Copy");
  1644.          AppendMenu (pv->hMenu, MF_STRING, IDM_EDITPASTE, "&Paste");
  1645.  
  1646.          // get init stuff from last parameter (if possible)
  1647.          //
  1648.         #ifdef USE_MDI
  1649.          {
  1650.          LPMDICREATESTRUCT lpMcs;
  1651.          lpMcs = (LPMDICREATESTRUCT) (lpCreate->lpCreateParams);
  1652.          lpMcs->x = lpMcs->y = CW_USEDEFAULT;
  1653.          lpMcs->cx = lpMcs->cy = CW_USEDEFAULT;
  1654.          if (lpMcs->lParam)
  1655.             pv->vi = *(PVIEWINIT)lpMcs->lParam;
  1656.          }
  1657.         #else
  1658.          if (lpCreate->lpCreateParams)
  1659.             pv->vi = *(PVIEWINIT)(lpCreate->lpCreateParams);
  1660.         #endif
  1661.  
  1662.          hDC = GetDC (hWnd);
  1663.          if (pv->hFontLabel)
  1664.             SelectObject (hDC, pv->hFontLabel);
  1665.  
  1666.          GetViewExtent (hDC,
  1667.                         &pv->vi,
  1668.                         pv->pLineInfo,
  1669.                         &pv->sLabel,
  1670.                         &pv->sTotal);
  1671.  
  1672.          pv->cyLine = pv->pLineInfo->cyLine;
  1673.          pv->wLabelWidth = pv->sLabel.cx + 16;
  1674.          ReleaseDC (hWnd, hDC);
  1675.  
  1676.          pv->hCurEdge = LoadCursor (lpCreate->hInstance,
  1677.                                     MAKEINTRESOURCE (IDC_EDGE));
  1678.  
  1679.          wsprintf (sz, "%s:%08lxx",
  1680.                    pv->vi.pTable[pv->vi.uStruct].pszName,
  1681.                    pv->vi.lpData);
  1682.  
  1683.          SetWindowText (hWnd, sz);
  1684.          
  1685.          break;
  1686.          }
  1687.  
  1688.       case WM_DESTROY:
  1689.          {
  1690.          //TrideeDestroy (hWnd);
  1691.  
  1692.          // delete font if not using stock object
  1693.          //DeleteObject (pv->hFontLabel);
  1694.  
  1695.          break;            // return FALSE;
  1696.          }
  1697.  
  1698.       default:
  1699.          lRet = DefProc (hWnd, wMsgID, wParam, lParam);
  1700.       }
  1701.  
  1702.    return lRet;
  1703.    }
  1704.  
  1705.  
  1706. /*+ DrawDragEdge
  1707.  *
  1708.  *
  1709.  *-=================================================================*/
  1710.  
  1711. VOID WINAPI DrawDragEdge (HWND hWnd, LPPOINT lppt, LPPOINT lpptLastEdge)
  1712.    {
  1713.    HDC  hDC;
  1714.    RECT rc;
  1715.  
  1716.    hDC = GetDC (hWnd);
  1717.  
  1718.    GetClientRect (hWnd, &rc);
  1719.  
  1720.    if (lpptLastEdge)
  1721.       PatBlt (hDC, lpptLastEdge->x, rc.top, 3, rc.bottom - rc.top, PATINVERT);
  1722.  
  1723.    if (lppt)
  1724.       {
  1725.       PatBlt (hDC, lppt->x, rc.top, 3, rc.bottom - rc.top, PATINVERT);
  1726.       if (lpptLastEdge)
  1727.          *lpptLastEdge = *lppt;
  1728.       }
  1729.  
  1730.    ReleaseDC (hWnd, hDC);
  1731.    }
  1732.