home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_03_02 / 3n02018a < prev    next >
Text File  |  1991-12-16  |  17KB  |  541 lines

  1. /* fader.c - main code for fader custom control */
  2.  
  3. #include <windows.h>
  4. #include "fader.h"
  5.  
  6. #define NO_DRAG              0    /* Values of FADER_THUMBSTATE */
  7. #define DRAG                 1
  8.  
  9. #define FADER_THUMB_OFFSET   2    /* Distance in pixels from edge */
  10.  
  11. /* Window extra bytes */
  12. #define FADER_RANGE          0    /* logical range values returned */
  13. #define FADER_VALUE          4    /* Current logical value */
  14. #define FADER_THUMBSTATE     6    /* DRAG or NO_DRAG */
  15. #define FADER_WNDEXTRA       8    /* Total # of window extra bytes */
  16.  
  17. HANDLE hGlobFaderInstance = NULL;
  18. char szGlobControlName[] = "Fader";
  19.  
  20. /* Forward declarations for completeness */
  21.  
  22. static BOOL NEAR PASCAL RegisterControlClass (HANDLE hInstance);
  23. LONG FAR PASCAL FaderWndFn (HWND hWnd, WORD wMsg,
  24.             WORD wParam, LONG lParam);
  25. int GetThumbHeight(int iTotalHeight);
  26. void GetFaderThumbRect(HWND hWnd, LPRECT pRc, LPRECT pThumbRect,
  27.             int iCurPos);
  28. int  XlatPosPhysicalToLogical(LONG lLogRange, int iPhysMax,
  29.             int iPhysMin, int iCurPos);
  30. int  XlatPosLogicalToPhysical(LONG lLogRange, int iPhysMax,
  31.             int iPhysMin, int iLogPos);
  32. static void DrawCaret(HDC hDC, LPRECT lprc);
  33. static void PaintFader(HWND hWnd);
  34.  
  35. /* These are DLL initialization and control functions */
  36.  
  37. BOOL FAR PASCAL LibMain (HANDLE hModule, WORD wDataSeg,
  38.    WORD wHeapSize, LPSTR lpszCmdLine)
  39. {
  40.    hGlobFaderInstance = hModule;
  41.    if (wHeapSize != 0)  /* Moveable DS */
  42.       UnlockData(0);
  43.    return RegisterControlClass(hModule);
  44. }
  45.  
  46.  
  47. int FAR PASCAL WEP (int nSystemExit)
  48. {
  49.    UnregisterClass(szGlobControlName, hGlobFaderInstance);
  50.    return 1;                 /* never fails */
  51. }
  52.  
  53.  
  54. /* This function can be static if you only plan to use it
  55.    in a DLL */
  56.  
  57. BOOL NEAR PASCAL RegisterControlClass (HANDLE hInstance)
  58. {
  59.    WNDCLASS wc;
  60.  
  61.    wc.style         = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW;
  62.    wc.lpfnWndProc   = FaderWndFn;
  63.    wc.cbClsExtra    = 0;
  64.    wc.cbWndExtra    = FADER_WNDEXTRA;
  65.    wc.hInstance     = hInstance;
  66.    wc.hIcon         = NULL;
  67.    wc.hCursor       = LoadCursor(NULL, IDC_SIZENS);
  68.    wc.hbrBackground = COLOR_WINDOW + 1;
  69.    wc.lpszMenuName  = NULL;
  70.    wc.lpszClassName = szGlobControlName;
  71.    return RegisterClass(&wc);
  72. }
  73.  
  74.  
  75. /* This function is handy for sending the FDRN_... messages
  76.    back to the parent.  Note that FDRN_THUMBTRACK is disabled
  77.    unless FDRS_TRACK is enabled */
  78.  
  79. static LONG NEAR PASCAL NotifyParent (HWND hWnd,
  80.    WORD wNotifyCode)
  81. {
  82.    BOOL bSend=TRUE;
  83.  
  84.    if (wNotifyCode == FDRN_THUMBTRACK)
  85.       bSend = (BOOL) (GetWindowLong(hWnd, GWL_STYLE) & FDRS_TRACK);
  86.  
  87.    if (bSend)
  88.       return SendMessage(GetParent(hWnd), WM_COMMAND,
  89.              GetWindowWord(hWnd, GWW_ID),
  90.              MAKELONG(hWnd, wNotifyCode));
  91.    else
  92.       return 0;
  93. }
  94.  
  95.  
  96. /* This is the main "window function" procedure, it is called
  97.    sometimes by the SDK Dialog box editor */
  98.  
  99. LONG FAR PASCAL FaderWndFn (HWND hWnd, WORD wMsg,
  100.    WORD wParam, LONG lParam)
  101. {
  102.    LONG lResult = 0;
  103.    HDC hDC;
  104.    POINT pt;
  105.    RECT rc;
  106.    int iLogPos;
  107.    int iOldLogPos;
  108.    int iPhyPos;
  109.    int iMaxLog;
  110.    int iMinLog;
  111.    RECT thumb_rect;
  112.    LONG lLogRange;
  113.    int iThumbHalf;
  114.    HANDLE hNewBrush, hOldBrush;
  115.  
  116.    switch (wMsg) {
  117.       case WM_CREATE:
  118.          SendMessage(hWnd, FDRM_SETRANGE, 0, MAKELONG(0, 100));
  119.          SendMessage(hWnd, FDRM_SETLOGVALUE, 0, 0);
  120.          break;
  121.  
  122.       case WM_GETDLGCODE: /* interface query by dialog manager */
  123.          lResult = DLGC_WANTARROWS;
  124.          break;
  125.  
  126.       case WM_PAINT:
  127.          PaintFader(hWnd);
  128.          break;
  129.  
  130.       case WM_SETFOCUS: /* receiving the keyboard focus */
  131.       case WM_KILLFOCUS: /* losing the keyboard focus */
  132.             /* calculate update region */
  133.             GetClientRect(hWnd, &rc);
  134.             iLogPos = GetWindowWord(hWnd, FADER_VALUE);
  135.             GetFaderThumbRect(hWnd, (LPRECT)&rc, (LPRECT)&thumb_rect,
  136.                iLogPos);
  137.             if (thumb_rect.left == rc.left)
  138.                break;
  139.  
  140.             /* force a repaint */
  141.             hDC = GetDC( hWnd );
  142.             if (hDC) {
  143.                /* define appropriate brush & text colors */
  144.                if (hNewBrush = (HBRUSH)SendMessage( GetParent(hWnd),
  145.                   WM_CTLCOLOR, hDC, MAKELONG(hWnd,CTLCOLOR_BTN) ) )
  146.                   hOldBrush = SelectObject(hDC,hNewBrush);
  147.                else
  148.                   hOldBrush = NULL;
  149.  
  150.                /* draw caret */
  151.                DrawCaret(hDC, (LPRECT)&thumb_rect);
  152.  
  153.                /* restore original brush */
  154.                if ( hNewBrush ) {
  155.                   SelectObject( hDC, hOldBrush );
  156.                   DeleteObject( hNewBrush );
  157.                   }
  158.  
  159.                /* release display context */
  160.                ReleaseDC( hWnd, hDC );
  161.                }
  162.          break;
  163.  
  164.       case WM_KEYDOWN:    /* process virtual key code */
  165.          GetClientRect(hWnd, &rc);
  166.          iLogPos = (int)GetWindowWord(hWnd, FADER_VALUE);
  167.          iOldLogPos = iLogPos;
  168.          lLogRange = GetWindowLong(hWnd, FADER_RANGE);
  169.          iMaxLog = HIWORD(lLogRange);
  170.          iMinLog = LOWORD(lLogRange);
  171.  
  172.          switch (wParam) {
  173.             case VK_HOME : /* home key */
  174.                iLogPos = iMinLog;
  175.                break;
  176.  
  177.             case VK_END : /* end key */
  178.                iLogPos = iMaxLog;
  179.                break;
  180.  
  181.             case VK_LEFT : /* cursor left key */
  182.             case VK_DOWN : /* cursor down key */
  183.                if (iLogPos < iMaxLog)
  184.                   iLogPos++;
  185.                break;
  186.  
  187.             case VK_UP : /* cursor up key */
  188.             case VK_RIGHT : /* cursor right key */
  189.                if (iLogPos > iMinLog)
  190.                   iLogPos--;
  191.                break;
  192.  
  193.             case VK_PRIOR : /* page up key */
  194.                iLogPos -= (iMaxLog - iMinLog) / 8;
  195.                if (iLogPos < iMinLog)
  196.                   iLogPos = iMinLog;
  197.                break;
  198.  
  199.             case VK_NEXT : /* page down key */
  200.                iLogPos += (iMaxLog - iMinLog) / 8;
  201.                if (iLogPos > iMaxLog)
  202.                   iLogPos = iMaxLog;
  203.                break;
  204.  
  205.             default : /* something else */
  206.                break;
  207.             }
  208.  
  209.          if (iLogPos != iOldLogPos) /* did it change? */
  210.             {
  211.             SendMessage(hWnd, FDRM_SETLOGVALUE, iLogPos, 0);
  212.             NotifyParent(hWnd, FDRN_THUMBTRACK);
  213.  
  214.             /* Invalidate old position */
  215.             GetFaderThumbRect(hWnd, (LPRECT)&rc,
  216.                  (LPRECT)&thumb_rect, iOldLogPos);
  217.             InvalidateRect(hWnd, (LPRECT)&thumb_rect, TRUE);
  218.  
  219.             /* Invalidate new position */
  220.             GetFaderThumbRect(hWnd, (LPRECT)&rc,
  221.                 (LPRECT)&thumb_rect, iLogPos);
  222.             InvalidateRect(hWnd, (LPRECT)&thumb_rect, TRUE);
  223.             }
  224.          break;
  225.  
  226.       case WM_LBUTTONDOWN:
  227.          GetClientRect(hWnd, &rc);
  228.          iLogPos = GetWindowWord(hWnd, FADER_VALUE);
  229.          GetFaderThumbRect(hWnd, (LPRECT)&rc, (LPRECT)&thumb_rect, iLogPos);
  230.          pt = MAKEPOINT(lParam);
  231.          /* is the mouse in the "hot" rectangle? */
  232.          if ((thumb_rect.top <= pt.y) && (thumb_rect.bottom >= pt.y) &&
  233.             (thumb_rect.left <= pt.x) && (thumb_rect.right  >= pt.x)) {
  234.             SetWindowWord(hWnd, FADER_THUMBSTATE, DRAG);
  235.             hDC = GetDC(hWnd);
  236.             InvertRect(hDC, (LPRECT)&thumb_rect);
  237.             ReleaseDC(hWnd, hDC);
  238.  
  239.             NotifyParent(hWnd, FDRN_THUMBTRACK);
  240.             /* grab focus if necessary */
  241.             if ( GetFocus() != hWnd )
  242.                 SetFocus( hWnd );
  243.             /* Lock mouse on to this window */
  244.             SetCapture(hWnd);
  245.             }
  246.          break;
  247.  
  248.       case WM_MOUSEMOVE:
  249.       case WM_LBUTTONUP:
  250.          /* Nothing to do if not in drag! */
  251.          if ((wMsg == WM_MOUSEMOVE) &&
  252.              (GetWindowWord(hWnd, FADER_THUMBSTATE) != DRAG) ) {
  253.             lResult = DefWindowProc(hWnd, wMsg, wParam, lParam);
  254.             break;
  255.             }
  256.  
  257.          /* set the new current position and ask for redraw */
  258.          pt = MAKEPOINT(lParam);
  259.          GetClientRect(hWnd, &rc);
  260.          iLogPos = GetWindowWord(hWnd, FADER_VALUE);
  261.          lLogRange = GetWindowLong(hWnd, FADER_RANGE);
  262.  
  263.          /* Invalidate old position */
  264.          GetFaderThumbRect(hWnd, (LPRECT)&rc, (LPRECT)&thumb_rect, iLogPos);
  265.          InvalidateRect(hWnd, (LPRECT)&thumb_rect, TRUE);
  266.  
  267.          iPhyPos = pt.y;
  268.          iThumbHalf = GetThumbHeight(rc.bottom)/2;
  269.          if (iPhyPos < iThumbHalf)
  270.             iPhyPos = iThumbHalf;
  271.          if (iPhyPos > rc.bottom-iThumbHalf)
  272.             iPhyPos = rc.bottom-iThumbHalf;
  273.  
  274.          iLogPos = XlatPosPhysicalToLogical(lLogRange,
  275.             rc.bottom-iThumbHalf, rc.top+iThumbHalf, iPhyPos);
  276.          GetFaderThumbRect(hWnd, (LPRECT)&rc, (LPRECT)&thumb_rect, iLogPos);
  277.          InvalidateRect(hWnd, (LPRECT)&thumb_rect, TRUE);
  278.  
  279.          SetWindowWord(hWnd, FADER_VALUE, iLogPos);
  280.          NotifyParent(hWnd, FDRN_THUMBTRACK);
  281.  
  282.          if (wMsg == WM_LBUTTONUP) {
  283.             SetWindowWord(hWnd, FADER_THUMBSTATE, NO_DRAG);
  284.             NotifyParent(hWnd, FDRN_ENDFADER);
  285.             ReleaseCapture();
  286.             }
  287.          break;
  288.  
  289.       case FDRM_SETRANGE:
  290.          GetClientRect(hWnd, &rc);
  291.          InvalidateRect(hWnd, (LPRECT)&rc, TRUE);
  292.          SetWindowLong(hWnd, FADER_RANGE, lParam);
  293.          break;
  294.  
  295.       case FDRM_GETRANGE:
  296.          lResult = GetWindowLong(hWnd, FADER_RANGE);
  297.          break;
  298.  
  299.       case FDRM_SETLOGVALUE:
  300.          GetClientRect(hWnd, &rc);
  301.          InvalidateRect(hWnd, (LPRECT)&rc, TRUE);
  302.          SetWindowWord(hWnd, FADER_VALUE, wParam);
  303.          break;
  304.  
  305.       case FDRM_GETLOGVALUE:
  306.          lResult = GetWindowWord(hWnd, FADER_VALUE);
  307.          break;
  308.  
  309.       case FDRM_GETPHYSVALUE:
  310.          GetClientRect(hWnd, &rc);
  311.          iThumbHalf = GetThumbHeight(rc.bottom)/2;
  312.          lLogRange = GetWindowLong(hWnd, FADER_RANGE);
  313.          iLogPos = GetWindowWord(hWnd, FADER_VALUE);
  314.          lResult = (long) XlatPosLogicalToPhysical(lLogRange,
  315.             rc.bottom-iThumbHalf, rc.top+iThumbHalf, iLogPos);
  316.          break;
  317.  
  318.       case FDRM_SETPHYSVALUE:
  319.          GetClientRect(hWnd, &rc);
  320.          iThumbHalf = GetThumbHeight(rc.bottom)/2;
  321.          lLogRange = GetWindowLong(hWnd, FADER_RANGE);
  322.          iLogPos = XlatPosPhysicalToLogical(lLogRange,
  323.             rc.bottom-iThumbHalf, rc.top+iThumbHalf, wParam);
  324.          SetWindowWord(hWnd, FADER_VALUE, iLogPos);
  325.          InvalidateRect(hWnd, NULL, TRUE);
  326.          break;
  327.  
  328.       default:
  329.          lResult = DefWindowProc(hWnd, wMsg, wParam, lParam);
  330.          break;
  331.    }
  332.    return(lResult);
  333. }
  334.  
  335.  
  336.  
  337. /* This is a "helper" function which draws the entire fader */
  338.  
  339. static void PaintFader(HWND hWnd)
  340. {
  341.    PAINTSTRUCT ps;
  342.    HANDLE  hOldPen;
  343.    HANDLE hNewBrush, hOldBrush;
  344.    HANDLE hMyParent;
  345.    RECT thumb_rect;
  346.    int x_center, y_coord;
  347.    int iLogPos;
  348.    int iPhyPos;
  349.    int iThumbHalf;
  350.    LONG lLogRange;
  351.    HDC hDC;
  352.    RECT rc;
  353.  
  354.    /* Default system color is COLOR_BTNFACE  from WNDCLASS structure */
  355.    hDC = BeginPaint(hWnd, &ps);
  356.  
  357.    GetClientRect(hWnd, &rc);
  358.  
  359.    hOldPen = SelectObject( hDC,
  360.        CreatePen(PS_SOLID,1,GetSysColor(COLOR_WINDOWFRAME)) );
  361.  
  362.    /* define appropriate brush & text colors */
  363.    hMyParent = GetParent(hWnd);
  364.    if (hNewBrush = (HBRUSH)SendMessage( hMyParent, WM_CTLCOLOR,
  365.       ps.hdc, MAKELONG(hWnd,CTLCOLOR_FADER) ) )
  366.       hOldBrush = SelectObject(ps.hdc,hNewBrush);
  367.    else
  368.       hOldBrush = NULL;
  369.  
  370.    /* Draws with horizontal symmetry */
  371.    x_center = rc.right / 2;
  372.  
  373.    /* draw fader slot (clockwise) */
  374.    MoveTo(hDC, x_center, 1);
  375.    LineTo(hDC, x_center+1, 2);
  376.    LineTo(hDC, x_center+1, rc.bottom-2);
  377.    LineTo(hDC, x_center, rc.bottom-1);
  378.    LineTo(hDC, x_center-1, rc.bottom-2);
  379.    LineTo(hDC, x_center-1, 2);
  380.    LineTo(hDC, x_center, 1);
  381.  
  382.    /* draw gridlines (top to bottom, left to right) */
  383.    for (y_coord=3; y_coord < rc.bottom-3; y_coord+=3) {
  384.       /* Left half first */
  385.       MoveTo(hDC, 1, y_coord);
  386.       LineTo(hDC, x_center-1, y_coord);
  387.       /* Then right half */
  388.       MoveTo(hDC, x_center+2, y_coord);
  389.       LineTo(hDC, rc.right-1, y_coord);
  390.       }
  391.  
  392.    /* draw filled box and then dividing line */
  393.    iThumbHalf = GetThumbHeight(rc.bottom)/2;
  394.    iLogPos = GetWindowWord(hWnd, FADER_VALUE);
  395.    lLogRange = GetWindowLong(hWnd, FADER_RANGE);
  396.    iPhyPos =  XlatPosLogicalToPhysical(lLogRange, rc.bottom-iThumbHalf,
  397.             rc.top+iThumbHalf, iLogPos);
  398.  
  399.    GetFaderThumbRect(hWnd, (LPRECT)&rc, (LPRECT)&thumb_rect, iLogPos);
  400.  
  401.    /* restore original brush */
  402.    DeleteObject( SelectObject(hDC,hOldBrush) );
  403.  
  404.    /* now go to 3D button face brush */
  405.    hOldBrush = SelectObject( hDC,
  406.       CreateSolidBrush(GetSysColor(COLOR_BTNFACE)) );
  407.  
  408.    Rectangle(hDC, thumb_rect.left, thumb_rect.top,
  409.             thumb_rect.right, thumb_rect.bottom);
  410.  
  411.    DeleteObject( SelectObject(hDC,hOldBrush) );
  412.    if (iThumbHalf > 2)  /* Big enough for 3D paint */
  413.       {
  414.       DeleteObject( SelectObject(hDC,hOldPen) );
  415.       hOldPen = SelectObject( hDC,
  416.          CreatePen(PS_SOLID,1,GetSysColor(COLOR_WINDOW)) );
  417.       MoveTo(hDC, thumb_rect.left+1, thumb_rect.bottom-1);
  418.       LineTo(hDC, thumb_rect.left+1, thumb_rect.top+1);
  419.       LineTo(hDC, thumb_rect.right-1, thumb_rect.top+1);
  420.       DeleteObject( SelectObject(hDC,hOldPen) );
  421.  
  422.       hOldPen = SelectObject( hDC,
  423.          CreatePen(PS_SOLID,1,GetSysColor(COLOR_BTNSHADOW)) );
  424.       MoveTo(hDC, thumb_rect.right-1, thumb_rect.top+1);
  425.       LineTo(hDC, thumb_rect.right-1, thumb_rect.bottom-1);
  426.       LineTo(hDC, thumb_rect.left+1, thumb_rect.bottom-1);
  427.       }
  428.    /* restore original pen */
  429.    DeleteObject( SelectObject(hDC,hOldPen) );
  430.    DeleteObject( SelectObject(hDC,hOldBrush) );
  431.  
  432.  
  433.    EndPaint(hWnd, &ps);
  434. }
  435.  
  436.  
  437.  
  438. /* Thumb height is magically 1/8th of window height */
  439.  
  440. int GetThumbHeight(int iTotalHeight)
  441. {
  442.    return max(iTotalHeight/8, 2);
  443. }
  444.  
  445.  
  446. /* The fader button is always 1/8th the heighth of the window
  447.    and 1/2 the width of the window */
  448.  
  449. void GetFaderThumbRect(HWND hWnd, LPRECT pRc,
  450.      LPRECT pThumbRect, int iLogPos)
  451. {
  452.    int x_center;
  453.    int iPhyPos;
  454.    int iThumbHalf;
  455.    LONG lLogRange;
  456.  
  457.    lLogRange = GetWindowLong(hWnd, FADER_RANGE);
  458.    iThumbHalf = GetThumbHeight(pRc->bottom) / 2;
  459.    iPhyPos = XlatPosLogicalToPhysical(lLogRange,
  460.       pRc->bottom - iThumbHalf, pRc->top + iThumbHalf,
  461.       iLogPos);
  462.    x_center = pRc->right / 2;
  463.    pThumbRect->left   = x_center / 2;
  464.    pThumbRect->top    = iPhyPos - iThumbHalf;
  465.    pThumbRect->right  = (3 * x_center) / 2;
  466.    pThumbRect->bottom = iPhyPos + iThumbHalf;
  467. }
  468.  
  469.  
  470. /* This "helper" function maps from pixel coordinates to
  471.    logical positions */
  472.  
  473. int XlatPosPhysicalToLogical(LONG lLogRange, int iPhysMax,
  474.             int iPhysMin, int iPhyPos)
  475. {
  476.    int iLogMin;
  477.    int iLogMax;
  478.    int iResult;
  479.    double dScale;
  480.  
  481.    iLogMax = HIWORD(lLogRange);
  482.    iLogMin = LOWORD(lLogRange);
  483.    dScale = (double)(iPhysMax - iPhyPos) /
  484.             (double)(iPhysMax - iPhysMin);
  485.    iResult = (int) ((double)iLogMin + (iLogMax-iLogMin)*(1-dScale));
  486.    return iResult;
  487. }
  488.  
  489.  
  490. /* This "helper" function maps from logical positions to
  491.    physical pixel coordinates */
  492.  
  493. int XlatPosLogicalToPhysical(LONG lLogRange, int iPhysMax,
  494.             int iPhysMin, int iLogPos)
  495. {
  496.    int iLogMin;
  497.    int iLogMax;
  498.    int iResult;
  499.    double dScale;
  500.  
  501.    iLogMax = HIWORD(lLogRange);
  502.    iLogMin = LOWORD(lLogRange);
  503.  
  504.    dScale = (double)(iLogMax - iLogPos) /
  505.             (double)(iLogMax - iLogMin);
  506.    iResult = (int) ((double)iPhysMin + (iPhysMax-iPhysMin)*(1-dScale));
  507.    return iResult;
  508. }
  509.  
  510.  
  511.  
  512. /* The "caret" is a way of highlighting the controls which are
  513.    active and inactive.  Note that a ones-complement is used so we
  514.    don't need to know the previous state */
  515.  
  516. void DrawCaret(HDC hDC, LPRECT lprc)
  517. {
  518.    HBRUSH      hOldBrush;
  519.    int iWidth;
  520.    int iHeight;
  521.  
  522.    if (lprc->bottom - lprc->top < 4)
  523.       return;
  524.  
  525.    /* initialize display context */
  526.    hOldBrush = (HBRUSH)SelectObject( hDC,
  527.       GetStockObject(GRAY_BRUSH) );
  528.  
  529.    /* draw caret */
  530.    iWidth = lprc->right - lprc->left;
  531.    iHeight = lprc->bottom - lprc->top;
  532.  
  533.    PatBlt( hDC, lprc->left+1, lprc->top+1, iWidth-2, 3, PATINVERT );
  534.    PatBlt( hDC, lprc->right-4, lprc->top+1, 3, iHeight-2, PATINVERT );
  535.    PatBlt( hDC, lprc->left+1, lprc->bottom-4, iWidth-2, 3, PATINVERT );
  536.    PatBlt( hDC, lprc->left+1, lprc->top+1, 3, iHeight-2, PATINVERT );
  537.  
  538.    /* restore display context */
  539.    SelectObject( hDC, hOldBrush );
  540. }
  541.