home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / k / knob.zip / ROTARY.C < prev    next >
C/C++ Source or Header  |  1992-11-17  |  16KB  |  606 lines

  1. /*
  2.     Rotary.c
  3.  
  4.     This is sample app to show how to implement
  5.     non-rectangular controls.
  6.  
  7.     12-Aug-91   Created by NigelT
  8.  
  9. */
  10. // COPYRIGHT:
  11. //
  12. //   (C) Copyright Microsoft Corp. 1992.  All rights reserved.
  13. //
  14. //   You have a royalty-free right to use, modify, reproduce and
  15. //   distribute the Sample Files (and/or any modified version) in
  16. //   any way you find useful, provided that you agree that
  17. //   Microsoft has no warranty obligations or liability for any
  18. //   Sample Application Files which are modified.
  19. #include <windows.h>
  20. #include <math.h>
  21. #include "Rotary.h"
  22. #define IDC_CONTROL 1           // child id
  23.  
  24. // ROP codes
  25. #define DSa     0x008800C6L
  26. #define DSx     0x00660046L
  27.  
  28. // colors
  29. #define rgbBlack RGB(0,0,0)
  30. #define rgbWhite RGB(255,255,255)
  31.  
  32. /* usefull global things */
  33.  
  34. HANDLE hInst;                   /* global instance handle */
  35.  
  36. char *szAppName = "Rotary";
  37.  
  38. HWND hMainWnd;                  /* handle of main window */
  39.  
  40. HWND hwndControl;
  41.  
  42. BOOL bCaptured;
  43.  
  44. WORD wControl = (MIN_UNITS + MAX_UNITS) / 2;
  45.  
  46.  
  47. // local functions
  48.  
  49.  
  50. WORD CalcPos (WORD wMin, WORD wMax, int iXcenter, int iYcenter, int iXmouse,
  51.               int iYmouse);
  52. void CalcPoint (WORD wMin, WORD wMax, WORD wPos, int iXcenter, int iYcenter,
  53.                 int iRad, LPPOINT lpPt);
  54. void DrawStaticControl (HWND hWnd);
  55. long FAR PASCAL RotaryWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM
  56.                                lParam);
  57. long FAR PASCAL MainWndProc (HWND, UINT, WPARAM, LPARAM);
  58. BOOL InitFirstInstance (HANDLE);
  59. HBITMAP GrabBackground (HWND hWnd);
  60. BOOL TransBlt (HDC hdcD, int x, int y, int dx, int dy, HDC hdcS, int x0, int y0
  61.                );
  62.  
  63.  
  64. /***************** Main entry point routine *************************/
  65.  
  66.  
  67. int PASCAL WinMain (hInstance, hPrevInstance, lpszCmdLine, cmdShow)
  68. HANDLE hInstance, hPrevInstance;
  69. LPSTR lpszCmdLine;
  70. int cmdShow;
  71. {
  72.    MSG msg;
  73.  
  74.    hInst = hInstance;          /* save our instance handle */
  75.    if (!hPrevInstance)
  76.    {
  77.       if (!InitFirstInstance(hInstance))
  78.       {
  79.          return 1;
  80.       }
  81.    }
  82.  
  83.    /* create a window for the application */
  84.    hMainWnd = CreateWindow(szAppName,          /* class name */ szAppName,              /* caption text */
  85.                            WS_OVERLAPPEDWINDOW,    /* window style */
  86.                            CW_USEDEFAULT, 0, 200, 250, (HWND)NULL,             /* handle of parent window */
  87.                            (HMENU)NULL,            /* menu handle (default class) */
  88.                            hInstance,              /* handle to window instance */
  89.                            (LPSTR)NULL             /* no params to pass on */);
  90.    if (!hMainWnd)
  91.    {
  92.       return 1;
  93.    }
  94.    ShowWindow(hMainWnd, cmdShow); /* display window as open or icon */
  95.    UpdateWindow(hMainWnd);     /* paint it */
  96.  
  97.    // initialize the rotary control windows
  98.  
  99.    // show the window so it can grab the background
  100.    ShowWindow(hwndControl, SW_NORMAL);
  101.  
  102.    // set the text, min and max values
  103.    rcSetUnits(hwndControl, "Units");
  104.    rcSetMin(hwndControl, MIN_UNITS);
  105.    rcSetMax(hwndControl, MAX_UNITS);
  106.  
  107.    // set the current positions                      
  108.    rcSetPos(hwndControl, wControl);
  109.  
  110.    /* Process messages for us */
  111.    while (GetMessage(&msg, NULL, 0, 0))
  112.    {
  113.       TranslateMessage(&msg);
  114.       DispatchMessage(&msg);
  115.    }
  116.    return (msg.wParam);
  117. }
  118.  
  119. /************* main window message handler ******************************/
  120.  
  121.  
  122. long FAR PASCAL MainWndProc (hWnd, message, wParam, lParam)
  123. HWND hWnd;
  124. UINT message;
  125. WPARAM wParam;
  126. LPARAM lParam;
  127. {
  128.    PAINTSTRUCT ps;             /* paint structure */
  129.  
  130.    /* process any messages we want */
  131.  
  132.    switch (message)
  133.       {
  134.    case WM_CREATE:
  135.       hwndControl = CreateWindow("rotary_control", "Control", WS_CHILD, 20, 20,
  136.                                  ROTARY_WIDTH, ROTARY_HEIGHT, hWnd, IDC_CONTROL
  137.                                  , hInst, (LPSTR)NULL);
  138.       break;
  139.  
  140.    case WM_SIZE:
  141.       break;
  142.  
  143.    case WM_PAINT:
  144.       BeginPaint(hWnd, &ps);
  145.       EndPaint(hWnd, &ps);
  146.       break;
  147.  
  148.    case WM_DESTROY:
  149.       PostQuitMessage(0);
  150.       break;
  151.  
  152.    default:
  153.       return DefWindowProc(hWnd, message, wParam, lParam);
  154.       break;
  155.       }
  156.    return NULL;
  157. }
  158.  
  159.  
  160. BOOL InitFirstInstance (hInstance)
  161. HANDLE hInstance;
  162. {
  163.    WNDCLASS wc;
  164.  
  165.    /* define the class of window we want to register */
  166.  
  167.    wc.lpszClassName = szAppName;
  168.    wc.style = CS_HREDRAW | CS_VREDRAW;
  169.    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  170.    wc.hIcon = LoadIcon(hInstance, "Icon");
  171.    wc.lpszMenuName = NULL;
  172.    wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
  173.    wc.hInstance = hInstance;
  174.    wc.lpfnWndProc = MainWndProc;
  175.    wc.cbClsExtra = 0;
  176.    wc.cbWndExtra = 0;
  177.    if (!RegisterClass(&wc))
  178.    {
  179.       return FALSE; /* Initialisation failed */
  180.    }
  181.  
  182.    // register a class for the rotary controls
  183.    wc.lpszClassName = "rotary_control";
  184.    wc.style = 0;
  185.    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  186.    wc.hIcon = NULL;
  187.    wc.lpszMenuName = NULL;
  188.    wc.hbrBackground = NULL;
  189.    wc.hInstance = hInstance;
  190.    wc.lpfnWndProc = RotaryWndProc;
  191.    wc.cbClsExtra = 0;
  192.    wc.cbWndExtra = sizeof(NPRINFO);
  193.    if (!RegisterClass(&wc))
  194.    {
  195.       return FALSE; /* Initialisation failed */
  196.    }
  197.    return TRUE;
  198. }
  199.  
  200.  
  201. WORD CalcPos (WORD wMin, WORD wMax, int iXcenter, int iYcenter, int iXmouse,
  202.               int iYmouse)
  203. {
  204.    int dx, dy;
  205.    WORD wPos;
  206.    double a, min, max;
  207.  
  208.    // compute the x and y offsets
  209.  
  210.    dx = iXmouse - iXcenter;
  211.    dy = iYmouse - iYcenter;
  212.  
  213.    // check for stupid case
  214.    if ((dx == 0) && (dy == 0))
  215.    {
  216.       dx = 1;
  217.       dy = 1; // force a position that works
  218.    }
  219.  
  220.    // get the angle in degrees
  221.    a = (57.3 * atan2((double)dy, (double)dx));
  222.    if ((a > 45.0) && (a <= 90.))
  223.    {
  224.       a = 45.0;
  225.    }
  226.    else if ((a > 90.0) && (a < 135.0))
  227.    {
  228.       a = 135.0;
  229.    }
  230.    a -= 135.0;
  231.    if (a < 0.0)
  232.       a += 360.0;
  233.  
  234.    // compute the control value
  235.    min = (double)wMin;
  236.    max = (double)wMax;
  237.    wPos = (WORD)(min + ((max - min) * a / 270.0));
  238.    return wPos;
  239. }
  240.  
  241.  
  242. void CalcPoint (WORD wMin, WORD wMax, WORD wPos, int iXcenter, int iYcenter,
  243.                 int iRad, LPPOINT lpPt)
  244. {
  245.    double a;
  246.  
  247.    a = 2.36 + 4.71 * (double)(wPos - wMin) / (double)(wMax - wMin);
  248.    lpPt->x = iXcenter + (int)((double)iRad * cos(a));
  249.    lpPt->y = iYcenter + (int)((double)iRad * sin(a));
  250. }
  251.  
  252.  
  253. void DrawControl (HWND hWnd)
  254. {
  255.    HBITMAP hbmOld, hbmOff, hbmOldOff;
  256.    HDC hDC, hdcMem, hdcOff;
  257.    RECT rcClient;
  258.    char text[40];
  259.    HPEN hpenOld, hpenDot;
  260.    HBRUSH hbrOld, hbrDot;
  261.    POINT pt;
  262.    NPRINFO npInfo;
  263.  
  264.    npInfo = (NPRINFO)GetWindowWord(hWnd, 0);
  265.    if (!npInfo->hbmBkGnd)
  266.    {
  267.       return;
  268.    }
  269.    hDC = GetDC(hWnd);
  270.    GetClientRect(hWnd, &rcClient);
  271.  
  272.    // create an off screen dc and a bitmap big enough
  273.    hdcOff = CreateCompatibleDC(hDC);
  274.    hbmOff = CreateCompatibleBitmap(hDC, rcClient.right - rcClient.left,
  275.                                    rcClient.bottom - rcClient.top);
  276.    hbmOldOff = SelectObject(hdcOff, hbmOff);
  277.  
  278.    // blit the background image to the offscreen dc
  279.    hdcMem = CreateCompatibleDC(hDC);
  280.    hbmOld = SelectObject(hdcMem, npInfo->hbmBkGnd);
  281.    BitBlt(hdcOff, rcClient.left, rcClient.top, rcClient.right - rcClient.left,
  282.           rcClient.bottom - rcClient.top, hdcMem, 0, 0, SRCCOPY);
  283.    SelectObject(hdcMem, hbmOld);
  284.    DeleteDC(hdcMem);
  285.  
  286.    // Draw the control value at the bottom
  287.    wsprintf(text, "%d %s", npInfo->wPos, (LPSTR)npInfo->szUnits);
  288.    SetBkMode(hdcOff, TRANSPARENT);
  289.    SetTextColor(hdcOff, BLUE);
  290.    DrawText(hdcOff, text, -1, &rcClient, DT_SINGLELINE | DT_BOTTOM | DT_CENTER)
  291.    ;
  292.  
  293.    // compute the angle of the dot
  294.    CalcPoint(npInfo->wMin, npInfo->wMax, npInfo->wPos, (rcClient.left +
  295.              rcClient.right) / 2, (rcClient.top + rcClient.bottom) / 2, 20, &pt
  296.              );
  297.    hpenDot = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
  298.    hbrDot = CreateSolidBrush(RGB(255, 0, 0));
  299.    hpenOld = SelectObject(hdcOff, hpenDot);
  300.    hbrOld = SelectObject(hdcOff, hbrDot);
  301.    Ellipse(hdcOff, pt.x - 2, pt.y - 2, pt.x + 2, pt.y + 2);
  302.    SelectObject(hdcOff, hpenOld);
  303.    SelectObject(hdcOff, hbrOld);
  304.    DeleteObject(hpenDot);
  305.    DeleteObject(hbrDot);
  306.  
  307.    // blit the offscreen dc stuff to the screen dc
  308.    BitBlt(hDC, rcClient.left, rcClient.top, rcClient.right - rcClient.left,
  309.           rcClient.bottom - rcClient.top, hdcOff, 0, 0, SRCCOPY);
  310.  
  311.    // tidy up the off screen stuff
  312.    SelectObject(hdcOff, hbmOldOff);
  313.    DeleteObject(hbmOff);
  314.    DeleteDC(hdcOff);
  315.    ReleaseDC(hWnd, hDC);
  316. }
  317.  
  318.  
  319. long FAR PASCAL RotaryWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM
  320.                                lParam)
  321. {
  322.    PAINTSTRUCT ps;
  323.    RECT rcWnd;
  324.    WORD w, xc, yc;
  325.    NPRINFO npInfo;
  326.  
  327.    npInfo = (NPRINFO)GetWindowWord(hWnd, 0);
  328.    switch (message)
  329.       {
  330.    case WM_CREATE:
  331.       npInfo = (NPRINFO)LocalAlloc(LPTR, sizeof(RINFO));
  332.       if (npInfo)
  333.       {
  334.          SetWindowWord(hWnd, 0, (WORD)npInfo);
  335.          npInfo->wMin = 0;
  336.          npInfo->wMax = 255;
  337.          npInfo->wPos = 128;
  338.          lstrcpy(npInfo->szUnits, "");
  339.       }
  340.       break;
  341.  
  342.    case WM_COMMAND:
  343.       break;
  344.  
  345.    case WM_LBUTTONDOWN:
  346.       if (!bCaptured)
  347.       {
  348.          SetCapture(hWnd);
  349.          bCaptured = TRUE;
  350.       }
  351.    // fall through
  352.  
  353.    case WM_MOUSEMOVE:
  354.       if (bCaptured)
  355.       {
  356.          // get the coords of the center of the control
  357.          GetClientRect(hWnd, &rcWnd);
  358.          xc = (rcWnd.left + rcWnd.right) / 2;
  359.          yc = (rcWnd.top + rcWnd.bottom) / 2;
  360.          w = CalcPos(npInfo->wMin, npInfo->wMax, xc, yc, LOWORD(lParam), HIWORD
  361.                      (lParam));
  362.          npInfo->wPos = w;
  363.          DrawControl(hWnd);
  364.          SendMessage(GetParent(hWnd), RCN_DRAG, GetWindowWord(hWnd, GWW_ID),
  365.                      MAKELONG(hWnd, w));
  366.       }
  367.       break;
  368.  
  369.    case WM_LBUTTONUP:
  370.       if (bCaptured)
  371.       {
  372.          ReleaseCapture();
  373.          bCaptured = FALSE;
  374.          SendMessage(GetParent(hWnd), RCN_RELEASE, GetWindowWord(hWnd, GWW_ID),
  375.                      MAKELONG(hWnd, npInfo->wPos));
  376.       }
  377.       break;
  378.  
  379.    case RC_SETMIN:
  380.       npInfo->wMin = wParam;
  381.       w = npInfo->wPos;
  382.       if (w < wParam)
  383.       {
  384.          npInfo->wPos = wParam;
  385.       }
  386.       //      DrawControl(hWnd);
  387.       break;
  388.  
  389.    case RC_SETMAX:
  390.       npInfo->wMax = wParam;
  391.       w = npInfo->wPos;
  392.       if (w > wParam)
  393.       {
  394.          npInfo->wPos = wParam;
  395.       }
  396.       //      DrawControl(hWnd);
  397.       break;
  398.  
  399.    case RC_SETPOS:
  400.       npInfo->wPos = wParam;
  401.       DrawControl(hWnd);
  402.       break;
  403.  
  404.    case RC_GETPOS:
  405.       return MAKELONG(npInfo->wPos, 0);
  406.       break;
  407.  
  408.    case RC_SETUNITS:
  409.       lstrcpy(npInfo->szUnits, (LPSTR)lParam);
  410.       break;
  411.  
  412.    case WM_PAINT:
  413.       BeginPaint(hWnd, &ps);
  414.       DrawControl(hWnd);
  415.       EndPaint(hWnd, &ps);
  416.       break;
  417.  
  418.    case WM_SHOWWINDOW:
  419.       // a good time to grab the background
  420.       if (!npInfo->hbmBkGnd)
  421.       {
  422.          npInfo->hbmBkGnd = GrabBackground(hWnd);
  423.          DrawStaticControl(hWnd);
  424.       }
  425.       break;
  426.  
  427.    case WM_ERASEBKGND:
  428.       return TRUE; // say we erased it
  429.       break;
  430.  
  431.    case WM_DESTROY:
  432.       if (npInfo->hbmBkGnd)
  433.          DeleteObject(npInfo->hbmBkGnd);
  434.       LocalFree((HANDLE)npInfo);
  435.       break;
  436.  
  437.    default:
  438.       return DefWindowProc(hWnd, message, wParam, lParam);
  439.       break;
  440.       }
  441.    return NULL;
  442. }
  443.  
  444.  
  445. //
  446. // Draw the bits of the control which don't vary on top of the
  447. // background bitmap
  448. //
  449.  
  450.  
  451. void DrawStaticControl (HWND hWnd)
  452. {
  453.    NPRINFO npInfo;
  454.    HDC hdcOffScr, hdcControl, hDC;
  455.    HBITMAP hbmOldBkGnd, hbmOldControl, hbmControl;
  456.    BITMAP bm;
  457.    RECT rcClient;
  458.    int x, y;
  459.    char text[40];
  460.  
  461.    npInfo = (NPRINFO)GetWindowWord(hWnd, 0);
  462.    hDC = GetDC(hWnd);
  463.    hdcOffScr = CreateCompatibleDC(hDC);
  464.  
  465.    // select the raw background bmp into the dc
  466.    hbmOldBkGnd = SelectObject(hdcOffScr, npInfo->hbmBkGnd);
  467.  
  468.    // draw the control and title on top of it
  469.  
  470.    // load the bitmap we need
  471.    hbmControl = LoadBitmap(hInst, MAKEINTRESOURCE(IDR_CONTROL));
  472.    if (!hbmControl)
  473.    {
  474.       return;
  475.    }
  476.  
  477.    // get the size of the bitmap so we can center it
  478.    GetObject(hbmControl, sizeof(bm), (LPSTR)&bm);
  479.  
  480.    // get the window size
  481.    GetClientRect(hWnd, &rcClient);
  482.    x = (rcClient.right - rcClient.left - bm.bmWidth) / 2 + rcClient.left;
  483.    y = (rcClient.bottom - rcClient.top - bm.bmHeight) / 2 + rcClient.top;
  484.  
  485.    // draw the control
  486.    hdcControl = CreateCompatibleDC(hdcOffScr);
  487.    hbmOldControl = SelectObject(hdcControl, hbmControl);
  488.    SetBkColor(hdcOffScr, RGB(0,0,255)); // transparency color is BLUE
  489.    TransBlt(hdcOffScr, x, y, bm.bmWidth, bm.bmHeight, hdcControl, 0, 0);
  490.    SelectObject(hdcControl, hbmOldControl);
  491.    DeleteDC(hdcControl);
  492.    DeleteObject(hbmControl);
  493.  
  494.    // Now put the caption at the top
  495.    GetWindowText(hWnd, text, sizeof(text));
  496.    SetBkMode(hdcOffScr, TRANSPARENT);
  497.    SetTextColor(hdcOffScr, BLUE);
  498.    DrawText(hdcOffScr, text, -1, &rcClient, DT_TOP | DT_CENTER);
  499.    SelectObject(hdcOffScr, hbmOldBkGnd);
  500.    DeleteDC(hdcOffScr);
  501.    ReleaseDC(hWnd, hDC);
  502. }
  503.  
  504. /**************************************************************************
  505.  
  506.     grab the background to a window
  507.  
  508. **************************************************************************/
  509.  
  510.  
  511. HBITMAP GrabBackground (HWND hWnd)
  512. {
  513.    HDC hdcParent, hdcOffScr;
  514.    HBITMAP hbmOld, hbm;
  515.    RECT rc;
  516.    POINT pt;
  517.  
  518.    GetClientRect(hWnd, &rc);
  519.    hdcParent = GetDC(GetParent(hWnd));
  520.    hdcOffScr = CreateCompatibleDC(hdcParent);
  521.    hbm = CreateCompatibleBitmap(hdcParent, rc.right - rc.left, rc.bottom - rc.
  522.                                 top);
  523.    hbmOld = SelectObject(hdcOffScr, hbm);
  524.  
  525.    // grab a chunk of the main window dc
  526.    pt.x = rc.left;
  527.    pt.y = rc.top;
  528.    ClientToScreen(hWnd, &pt);
  529.    ScreenToClient(GetParent(hWnd), &pt);
  530.    BitBlt(hdcOffScr, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdcParent,
  531.           pt.x, pt.y, SRCCOPY);
  532.    SelectObject(hdcOffScr, hbmOld);
  533.    DeleteDC(hdcOffScr);
  534.    ReleaseDC(GetParent(hWnd), hdcParent);
  535.    return hbm;
  536. }
  537.  
  538. /*
  539.  *
  540.  * TransBlt() Transparent bitblt that uses the current
  541.  *            background color of the DC as the transparent color.
  542.  *
  543.  */
  544.  
  545.  
  546. BOOL TransBlt (HDC hdcD, int x, int y, int dx, int dy, HDC hdcS, int x0, int y0
  547.                )
  548. {
  549.    DWORD rgbBk, rgbFg;
  550.    DWORD rgbBkS;
  551.    HBITMAP hbmMask;
  552.    HDC hdcMask;
  553.    HBITMAP hbmT;
  554.    BOOL f = FALSE;
  555.  
  556.    //
  557.    //  Get the current DC color's
  558.    //
  559.  
  560.    rgbBk = GetBkColor(hdcD);
  561.    rgbFg = GetTextColor(hdcD);
  562.    rgbBkS = GetBkColor(hdcS);
  563.    SetTextColor(hdcD, rgbBlack);
  564.  
  565.    //
  566.    //  make a memory DC for use in color conversion
  567.    //
  568.    hdcMask = CreateCompatibleDC(hdcS);
  569.    if (!hdcMask)
  570.       return FALSE;
  571.  
  572.    //
  573.    // create a mask bitmap and associated DC
  574.    //
  575.    hbmMask = CreateBitmap(dx, dy, 1, 1, NULL);
  576.    if (!hbmMask)
  577.       goto errorDC;
  578.  
  579.    // select the mask bitmap into the mono DC
  580.    hbmT = SelectObject(hdcMask, hbmMask);
  581.  
  582.    // do a color to mono bitblt to build the mask
  583.    // generate 1's where the source is equal to the background, else 0's
  584.    SetBkColor(hdcS, rgbBk);
  585.    BitBlt(hdcMask, 0, 0, dx, dy, hdcS, x0, y0, SRCCOPY);
  586.  
  587.    // do a MaskBlt to copy the bitmap to the dest
  588.    SetBkColor(hdcD, rgbWhite);
  589.    BitBlt(hdcD, x, y, dx, dy, hdcS, x0, y0, DSx);
  590.    BitBlt(hdcD, x, y, dx, dy, hdcMask, 0, 0, DSa);
  591.    BitBlt(hdcD, x, y, dx, dy, hdcS, x0, y0, DSx);
  592.    f = TRUE;
  593.    SelectObject(hdcMask, hbmT);
  594.    DeleteObject(hbmMask);
  595.  
  596.    //
  597.    // Restore the DC colors
  598.    //
  599.    SetBkColor(hdcS, rgbBkS);
  600.    SetBkColor(hdcD, rgbBk);
  601.    SetTextColor(hdcD, rgbFg);
  602.    errorDC:
  603.    DeleteDC(hdcMask);
  604.    return f;
  605. }
  606.