home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / msysjour / vol03 / 04 / spectrum / spectrum.c < prev    next >
C/C++ Source or Header  |  1988-04-13  |  17KB  |  608 lines

  1. /*
  2.  * WINDOWS SPECTRUM CONTROL
  3.  *
  4.  * LANGUAGE : Microsoft C 5.0
  5.  * TOOLKIT  : Windows 2.03 SDK
  6.  * MODEL    : Small or Medium
  7.  * STATUS   : Operational
  8.  *
  9.  * 03/20/88 - Kevin P. Welch - initial creation.
  10.  *
  11.  */
  12.  
  13. #include <windows.h>
  14. #include "spectrum.h"
  15.  
  16. /* general spectrum definitions */
  17. #define    ID                            GetWindowWord( hWnd, GWW_ID )
  18. #define    PARENT                    GetWindowWord( hWnd, GWW_HWNDPARENT )
  19. #define    INSTANCE                    GetWindowWord( hWnd, GWW_HINSTANCE )
  20.  
  21. /* spectrum specific definitions */
  22. #define    SPECTRUM_EXTRA            12                
  23.  
  24. #define    RANGE                        GetWindowWord( hWnd, 0 )
  25. #define    TABLE                        GetWindowWord( hWnd, 2 )
  26. #define    WIDTH                        GetWindowWord( hWnd, 4 )
  27. #define    HEIGHT                    GetWindowWord( hWnd, 6 )
  28. #define    CHOICE                    GetWindowWord( hWnd, 8 )
  29. #define    CAPTURE                    GetWindowWord( hWnd, 10 )
  30.  
  31. #define    SET_RANGE(x)            SetWindowWord( hWnd, 0, x )
  32. #define    SET_TABLE(x)            SetWindowWord( hWnd, 2, x )
  33. #define    SET_WIDTH(x)            SetWindowWord( hWnd, 4, x )
  34. #define    SET_HEIGHT(x)            SetWindowWord( hWnd, 6, x )
  35. #define    SET_CHOICE(x)            SetWindowWord( hWnd, 8, x )
  36. #define    SET_CAPTURE(x)            SetWindowWord( hWnd, 10, x )
  37.  
  38. /* caret related definitions */
  39. #define    CARET_XPOS                ((CHOICE*WIDTH)+3)
  40. #define    CARET_YPOS                (3)
  41. #define    CARET_WIDTH                (WIDTH-6)
  42. #define    CARET_HEIGHT            (HEIGHT-6)
  43.  
  44. /* selector related definitions */
  45. #define    SELECTOR_XPOS            ((CHOICE*WIDTH)+1)
  46. #define    SELECTOR_YPOS            (1)
  47. #define    SELECTOR_WIDTH            (WIDTH-1)
  48. #define    SELECTOR_HEIGHT        (HEIGHT-1)
  49.  
  50. /* */
  51.  
  52. /*
  53.  * RegisterSpectrum( hAppInstance ) : BOOL
  54.  *
  55.  *        hAppInstance        application instance handle
  56.  *
  57.  * This function is responsible for the definition and registration
  58.  * of the spectrum window class.  Note that this function should
  59.  * only be called ONCE (typically during the initialization phase
  60.  * of the host application) within a program.
  61.  *
  62.  * A value of TRUE is returned if the registration operation was
  63.  * performed sucessfully.
  64.  *
  65.  */
  66.  
  67. BOOL FAR PASCAL RegisterSpectrum( hAppInstance )
  68.     HANDLE        hAppInstance;
  69. {
  70.     /* local variables */
  71.     WNDCLASS        WndClass;                /* window class data structure */
  72.  
  73.     /* Define spectrum window class.  Note that no check is made to
  74.      * see if it has been previously registed!  It is up to the host
  75.      * application to prevent multiple registrations.
  76.      */
  77.      
  78.     memset( &WndClass, 0, sizeof(WNDCLASS) );
  79.     
  80.     WndClass.lpszClassName =     (LPSTR)"Spectrum";
  81.     WndClass.hCursor =            LoadCursor( NULL, IDC_ARROW );
  82.     WndClass.lpszMenuName =        (LPSTR)NULL;
  83.     WndClass.style =                CS_HREDRAW|CS_VREDRAW;
  84.     WndClass.lpfnWndProc =        SpectrumWndFn;
  85.     WndClass.hInstance =            hAppInstance;
  86.     WndClass.hIcon =                NULL;
  87.     WndClass.cbWndExtra =        SPECTRUM_EXTRA;
  88.     WndClass.hbrBackground =    (HBRUSH)(COLOR_WINDOW + 1 );
  89.     
  90.     /* register spectrum window class & return */
  91.     return( RegisterClass( (LPWNDCLASS)&WndClass ) );
  92.  
  93. }
  94.  
  95. /* */
  96.  
  97. /*
  98.  * SetSpectrum( hWnd, pwEntry ) : BOOL
  99.  *
  100.  *        hWnd                    handle to spectrum control
  101.  *        pwEntry                new selected entry
  102.  *
  103.  * This function enables the caller to define the entry provided
  104.  * as the selected color.  The selected color will default to
  105.  * zero if the entry provided is out of range.
  106.  *
  107.  * A value of TRUE is returned if a selection was sucessfully made.
  108.  *
  109.  */
  110.  
  111. BOOL FAR PASCAL SetSpectrum( hWnd, pwEntry )
  112.     HWND            hWnd;
  113.     WORD *        pwEntry;
  114. {
  115.     /* local variables */
  116.     LONG FAR *        lprgbEntry;                /* rgb color list */
  117.     
  118.     /* update selection & redraw spectrum */
  119.     SET_CHOICE( (*pwEntry >= RANGE) ? 0 : *pwEntry );
  120.     InvalidateRect( hWnd, NULL, TRUE );
  121.  
  122.     /* retrieve new result & notify parent window */
  123.     lprgbEntry = (LONG FAR *)GlobalLock( TABLE );
  124.     SendMessage( PARENT, WM_COMMAND, ID, lprgbEntry[RANGE+CHOICE] );
  125.     GlobalUnlock( TABLE );
  126.  
  127.     /* normal return */
  128.     return( TRUE );
  129.  
  130. }
  131.  
  132. /* */
  133.  
  134. /*
  135.  * GetSpectrum( hWnd, pwEntry ) : BOOL
  136.  *
  137.  *        hWnd                    handle to spectrum control
  138.  *        pwEntry                currently selected entry
  139.  *
  140.  * This function enables the caller to retrieve an index to
  141.  * the currently selected color.  Using this index the caller
  142.  * can then lookup the associated rgb color or table value.
  143.  *
  144.  * A value of TRUE is return if the call was successful.
  145.  *
  146.  */
  147.  
  148. BOOL FAR PASCAL GetSpectrum( hWnd, pwEntry )
  149.     HWND            hWnd;
  150.     WORD *        pwEntry;
  151. {
  152.     *pwEntry = CHOICE;
  153.     return( TRUE );
  154. }
  155.  
  156. /* */
  157.  
  158. /*
  159.  * SetSpectrumColors( hWnd, pwRange, prgbList ) : BOOL
  160.  *
  161.  *        hWnd                    handle to spectrum control in dialog box
  162.  *        pwRange                number of color entries in rgb list
  163.  *        prgbList                list of rgb colors & values for spectrum
  164.  *
  165.  * This function enables the caller to define a new spectrum
  166.  * with associated lookup values for the control.  It is left
  167.  * up to the calling routine to determine the appropriate rgb
  168.  * colors and lookup values.  Note that the selected color is
  169.  * always reset to the first available entry whenever a new
  170.  * range is defined.
  171.  *
  172.  * A value of TRUE is returned if a new rgb color list was
  173.  * sucessfully defined.
  174.  *
  175.  */
  176.  
  177. BOOL FAR PASCAL SetSpectrumColors( hWnd, pwRange, prgbList )
  178.     HWND            hWnd;
  179.     WORD *        pwRange;
  180.     LONG *        prgbList;
  181. {
  182.     /* local variables */
  183.     WORD            wEntry;                    /* temporary color entry */
  184.     HANDLE        hrgbList;                /* handle to rgb list */
  185.     LONG FAR *    lprgbEntry;                /* pointer to rgb list */
  186.     RECT            rectClient;                /* client area rectangle */
  187.     
  188.     /* release previous table from memory */
  189.     GlobalFree( TABLE );
  190.     
  191.     hrgbList = GlobalAlloc(    GMEM_MOVEABLE,    sizeof(LONG)*(*pwRange)*2L);        
  192.     if ( hrgbList ) {
  193.             
  194.         /* define initial rgb colors & values */
  195.         lprgbEntry = (LONG FAR *)GlobalLock( hrgbList );        
  196.         for ( wEntry=0; wEntry < *pwRange; wEntry++ ) {
  197.             lprgbEntry[wEntry] = prgbList[wEntry];        
  198.             lprgbEntry[(*pwRange)+wEntry] = prgbList[(*pwRange)+wEntry];
  199.         }    
  200.         GlobalUnlock( hrgbList );
  201.             
  202.         /* retrieve current window dimensions */
  203.         GetClientRect( hWnd, &rectClient );
  204.  
  205.         /* re-define instance variables */
  206.         SET_RANGE( *pwRange );
  207.         SET_TABLE( hrgbList );
  208.         SET_WIDTH( (rectClient.right-rectClient.left)/(*pwRange) );
  209.         SET_HEIGHT( rectClient.bottom-rectClient.top );
  210.         SET_CHOICE( 0 );
  211.     
  212.         /* update window & notify parent of new selection */
  213.         InvalidateRect( hWnd, NULL, TRUE );
  214.         SendMessage( PARENT, WM_COMMAND, ID, lprgbEntry[RANGE+CHOICE] );
  215.  
  216.         /* normal return */
  217.         return( TRUE );
  218.         
  219.     } else
  220.         return( FALSE );    
  221.         
  222. }
  223.  
  224. /* */
  225.  
  226. /*
  227.  * GetSpectrumColors( hWnd, pwRange, prgbList ) : BOOL
  228.  *
  229.  *        hWnd                    handle to spectrum control in dialog box
  230.  *        pwRange                number of color entries in rgb list
  231.  *        prgbList                list of rgb color values for spectrum
  232.  *
  233.  * This function enables the caller to retrieve the current
  234.  * colors & values maintained by the spectrum control.  If the
  235.  * color range has never been defined the spectrum represents
  236.  * a set of default colors and values.
  237.  *
  238.  * A value of TRUE is returned if this function was successful.
  239.  *
  240.  */
  241.  
  242. BOOL FAR PASCAL GetSpectrumColors( hWnd, pwRange, prgbList )
  243.     HWND            hWnd;
  244.     WORD *        pwRange;
  245.     LONG *        prgbList;
  246. {
  247.     /* local variables */
  248.     WORD            wEntry;                    /* index to color table  */
  249.     LONG FAR *    lprgbEntry;                /* pointer to rgb value */
  250.  
  251.     /* retrieve number of colors */
  252.     *pwRange = RANGE;
  253.     
  254.     /* retrieve rgb color list */
  255.     lprgbEntry = (LONG FAR *)GlobalLock( TABLE );        
  256.     for ( wEntry=0; wEntry < RANGE; wEntry++ ) {
  257.         prgbList[wEntry] = lprgbEntry[wEntry];        
  258.         prgbList[(*pwRange)+wEntry] = lprgbEntry[(*pwRange)+wEntry];
  259.     }
  260.     GlobalUnlock( TABLE );
  261.     
  262.     return( TRUE );
  263.     
  264. }
  265.  
  266. /* */
  267.  
  268. /*
  269.  * SpectrumWndFn( hWnd, wMsg, wParam, lParam ) : LONG
  270.  *
  271.  *        hWnd                    handle to spectrum window
  272.  *        wMsg                    message number
  273.  *        wParam                single word parameter
  274.  *        lParam                double word parameter
  275.  *
  276.  * This function is responsible for processing all the messages
  277.  * which relate to the spectrum control window.  Note how the
  278.  * code is written to avoid potential problems when re-entrancy
  279.  * happens - this involves the use of extra bytes associated
  280.  * with the window data structure.
  281.  *
  282.  * The LONG value returned by this function is the conventional
  283.  * result of the default window procedure or the internal
  284.  * handling of a message.
  285.  *
  286.  */
  287.  
  288. LONG FAR PASCAL SpectrumWndFn( hWnd, wMsg, wParam, lParam )
  289.     HWND            hWnd;
  290.     WORD            wMsg;
  291.     WORD            wParam;
  292.     LONG            lParam;
  293. {
  294.     /* local variables */
  295.     LONG            lResult;                    /* temporary result variable */
  296.     
  297.     /* initialization */
  298.     lResult = TRUE;
  299.     
  300.     /* process message */
  301.     switch( wMsg )
  302.         {
  303.     case WM_GETDLGCODE : /* capture all key strokes */
  304.         lParam = DLGC_WANTARROWS;        
  305.         break;
  306.     case WM_CREATE : /* create pallette window */
  307.         
  308.         {
  309.             /* temporary variables */
  310.             HANDLE        hrgbList;                /* handle to rgb list */
  311.             LONG FAR *    lprgbEntry;                /* pointer to rgb list */
  312.             
  313.             /* allocate space for rgb color list */
  314.             hrgbList = GlobalAlloc( GMEM_MOVEABLE, sizeof(LONG)*16L );
  315.             if ( hrgbList ) {
  316.             
  317.                 /* define initial rgb color & value list - note that
  318.                  * eight default colors are selected with the values
  319.                  * matching each of the colors.
  320.                  */
  321.  
  322.                 lprgbEntry = (LONG FAR *)GlobalLock( hrgbList );
  323.                 lprgbEntry[0] = RGB( 0x00, 0x00, 0x00 );
  324.                 lprgbEntry[1] = RGB( 0x00, 0x00, 0xFF );
  325.                 lprgbEntry[2] = RGB( 0x00, 0xFF, 0x00 );
  326.                 lprgbEntry[3] = RGB( 0xFF, 0x00, 0x00 );
  327.                 lprgbEntry[4] = RGB( 0x00, 0xFF, 0xFF );
  328.                 lprgbEntry[5] = RGB( 0xFF, 0xFF, 0x00 );
  329.                 lprgbEntry[6] = RGB( 0xFF, 0x00, 0xFF );
  330.                 lprgbEntry[7] = RGB( 0xFF, 0xFF, 0xFF );
  331.                 lprgbEntry[8] = RGB( 0x00, 0x00, 0x00 );
  332.                 lprgbEntry[9] = RGB( 0x00, 0x00, 0xFF );
  333.                 lprgbEntry[10] = RGB( 0x00, 0xFF, 0x00 );
  334.                 lprgbEntry[11] = RGB( 0xFF, 0x00, 0x00 );
  335.                 lprgbEntry[12] = RGB( 0x00, 0xFF, 0xFF );
  336.                 lprgbEntry[13] = RGB( 0xFF, 0xFF, 0x00 );
  337.                 lprgbEntry[14] = RGB( 0xFF, 0x00, 0xFF );
  338.                 lprgbEntry[15] = RGB( 0xFF, 0xFF, 0xFF );
  339.                 GlobalUnlock( hrgbList );
  340.             
  341.                 /* define instance variables */
  342.                 SET_RANGE( 8 );
  343.                 SET_TABLE( hrgbList );
  344.                 SET_WIDTH( ((LPCREATESTRUCT)lParam)->cx / 8 );
  345.                 SET_HEIGHT( ((LPCREATESTRUCT)lParam)->cy );
  346.                 SET_CHOICE( 0 );
  347.                 SET_CAPTURE( FALSE );
  348.     
  349.             } else
  350.                 DestroyWindow( hWnd );
  351.                 
  352.         }
  353.         
  354.         break;
  355.     case WM_SIZE : /* window being resized */
  356.     
  357.         /* redefine width & height instance variables */
  358.         SET_WIDTH( LOWORD(lParam) / 8 );
  359.         SET_HEIGHT( HIWORD(lParam) );
  360.  
  361.         break;
  362.     case WM_PAINT : /* paint control window */
  363.         
  364.         {
  365.             PAINTSTRUCT        Ps;                    /* paint structure */
  366.             WORD                wEntry;                /* current color entry */
  367.             HANDLE            hBrush;                /* handle to new brush */
  368.             HANDLE            hOldBrush;            /* handle to old brush */
  369.             LONG FAR *        lprgbEntry;            /* pointer to rgb list */
  370.                     
  371.             /* start paint operation */
  372.             BeginPaint( hWnd, (LPPAINTSTRUCT)&Ps );
  373.             
  374.             /* iteratively paint each color patch */
  375.             lprgbEntry = (LONG FAR *)GlobalLock( TABLE );
  376.             for ( wEntry=0; wEntry<RANGE; wEntry++ ) {
  377.  
  378.                 /* create solid brush for patch & select */
  379.                 hBrush = CreateSolidBrush( lprgbEntry[wEntry] );
  380.                 hOldBrush = SelectObject( Ps.hdc, hBrush );
  381.     
  382.                 /* draw rectangle with brush fill */
  383.                 Rectangle(
  384.                     Ps.hdc,
  385.                     wEntry*WIDTH,
  386.                     0,
  387.                     (wEntry*WIDTH)+WIDTH,
  388.                     HEIGHT
  389.                 );
  390.  
  391.                 /* unselect brush and delete */
  392.                 SelectObject( Ps.hdc, hOldBrush );
  393.                 DeleteObject( hBrush );
  394.     
  395.             }
  396.             GlobalUnlock( TABLE );
  397.                     
  398.             /* define current selection & end paint operation */
  399.             DrawSelector( hWnd, Ps.hdc );
  400.             EndPaint( hWnd, (LPPAINTSTRUCT)&Ps );
  401.  
  402.         }
  403.         
  404.         break;
  405.     case WM_KEYDOWN : /* key being pressed */
  406.         
  407.         {
  408.             /* local variables */
  409.             HDC                hDC;                    /* display context handle */
  410.             LONG FAR *        lprgbEntry;            /* pointer to rgb list */    
  411.         
  412.             /* retrieve display context & unmark current selection */
  413.             hDC = GetDC( hWnd );
  414.             DrawSelector( hWnd, hDC );            
  415.  
  416.             /* process virtual key codes */
  417.             switch( wParam )
  418.                 {
  419.             case VK_HOME : /* home key */
  420.                 SET_CHOICE( 0 );
  421.                 break;
  422.             case VK_LEFT : /* left cursor key */
  423.                 SET_CHOICE( (CHOICE > 0) ? CHOICE-1 : RANGE-1 );
  424.                 break;
  425.             case VK_RIGHT : /* right cursor key */
  426.             case VK_SPACE : /* space bar - move right */
  427.                 SET_CHOICE( (CHOICE < RANGE-1) ? CHOICE+1 : 0 );
  428.                 break;
  429.             case VK_END : /* end key */
  430.                 SET_CHOICE( RANGE-1 );
  431.                 break;
  432.             default : /* some other key */
  433.                 lResult = FALSE;
  434.                 break;
  435.             }
  436.  
  437.             /* mark new selection & release display context */
  438.             DrawSelector( hWnd, hDC );
  439.             ReleaseDC( hWnd, hDC );
  440.  
  441.             /* move caret to new position */
  442.             SetCaretPos( CARET_XPOS, CARET_YPOS );
  443.  
  444.             /* notify parent of new selection */
  445.             lprgbEntry = (LONG FAR *)GlobalLock( TABLE );
  446.             SendMessage(PARENT,WM_COMMAND,ID,lprgbEntry[RANGE+CHOICE]);
  447.             GlobalUnlock( TABLE );
  448.                     
  449.         }
  450.         
  451.         break;
  452.     case WM_SETFOCUS : /* get focus - display caret */
  453.  
  454.         /* create caret & display */
  455.         CreateCaret( hWnd, NULL, CARET_WIDTH, CARET_HEIGHT );
  456.         SetCaretPos( CARET_XPOS, CARET_YPOS );
  457.         ShowCaret( hWnd );
  458.  
  459.         break;
  460.     case WM_LBUTTONDOWN : /* left button depressed - fall through */
  461.  
  462.         {
  463.             /* local variables */
  464.             HDC                hDC;                    /* display context handle */
  465.             LONG FAR *        lprgbEntry;            /* pointer to rgb list */    
  466.  
  467.             /* retrieve display context */
  468.             hDC = GetDC ( hWnd );
  469.  
  470.             /* unmark old selection & mark new one */
  471.             DrawSelector( hWnd, hDC );            
  472.             SET_CHOICE( LOWORD(lParam)/WIDTH );
  473.             DrawSelector( hWnd, hDC );
  474.         
  475.             /* release display context & move caret */
  476.             ReleaseDC( hWnd, hDC );
  477.  
  478.             /* capture focus & move caret */
  479.             if ( hWnd == SetFocus(hWnd) )
  480.                 SetCaretPos( CARET_XPOS, CARET_YPOS );
  481.  
  482.             /* notify parent of new selection */
  483.             lprgbEntry = (LONG FAR *)GlobalLock( TABLE );
  484.             SendMessage(PARENT,WM_COMMAND,ID,lprgbEntry[RANGE+CHOICE]);
  485.             GlobalUnlock( TABLE );
  486.             
  487.             /* activate capture */
  488.             SetCapture( hWnd );
  489.             SET_CAPTURE( TRUE );            
  490.  
  491.         }
  492.         
  493.         break;
  494.     case WM_MOUSEMOVE : /* mouse being moved */
  495.  
  496.         /* track mouse only if capture on */
  497.         if ( CAPTURE ) {
  498.         
  499.             /* local variables */
  500.             HDC                hDC;                    /* display context handle */
  501.             WORD                wNewChoice;            /* new mouse selection */
  502.             LONG FAR *        lprgbEntry;            /* pointer to rgb list */    
  503.         
  504.             /* calculate new selection */
  505.             wNewChoice = ( *((int*)&lParam) <= 0 ) ?
  506.                 0 :
  507.                 ( LOWORD(lParam)/WIDTH >= RANGE ) ?
  508.                     RANGE - 1 :
  509.                     LOWORD(lParam) / WIDTH;
  510.             
  511.             /* update display if different */
  512.             if ( wNewChoice != CHOICE ) {
  513.  
  514.                 /* retrieve display context */
  515.                 hDC = GetDC ( hWnd );
  516.  
  517.                 /* unmark old selection & mark new one */
  518.                 DrawSelector( hWnd, hDC );            
  519.                 SET_CHOICE( wNewChoice );
  520.                 DrawSelector( hWnd, hDC );
  521.         
  522.                 /* release display context & move caret */
  523.                 ReleaseDC( hWnd, hDC );
  524.                 SetCaretPos( CARET_XPOS, CARET_YPOS );
  525.             
  526.                 /* notify parent of new selection */
  527.                 lprgbEntry = (LONG FAR *)GlobalLock( TABLE );
  528.                 SendMessage(PARENT,WM_COMMAND,ID,lprgbEntry[RANGE+CHOICE]);
  529.                 GlobalUnlock( TABLE );
  530.             
  531.             }
  532.             
  533.         }
  534.         
  535.         break;
  536.     case WM_LBUTTONUP : /* left button released */
  537.  
  538.         /* release capture if active */
  539.         if ( CAPTURE ) {
  540.             SET_CAPTURE( FALSE );
  541.             ReleaseCapture();
  542.         }            
  543.  
  544.         break;
  545.     case WM_KILLFOCUS : /* kill focus - hide caret */
  546.         DestroyCaret();
  547.         break;
  548.     case WM_DESTROY : /* window being destroyed */
  549.         GlobalFree( TABLE );        
  550.         break;
  551.     default : /* default window message processing */
  552.         lResult = DefWindowProc( hWnd, wMsg, wParam, lParam );
  553.         break;
  554.     }
  555.     
  556.     /* return final result */
  557.     return( lResult );
  558.  
  559. }
  560.  
  561. /* */
  562.  
  563. /*
  564.  * DrawSelector( hWnd, hDC )
  565.  *
  566.  *        hWnd            window handle
  567.  *        hDC            handle to display context
  568.  *
  569.  *    This function is responsible for drawing the selector
  570.  * which surrounds the active color patch.  This drawing
  571.  * process involves the use of the R2_NOT operator to
  572.  * simplify the drawing & re-drawing process.
  573.  *
  574.  */
  575.  
  576. static DrawSelector( hWnd, hDC )
  577.     HWND            hWnd;
  578.     HDC            hDC;
  579. {
  580.     /* local variables */
  581.     HANDLE        hOldPen;                    /* old pen */
  582.     WORD            wOldROP2;                /* old raster op code */
  583.     WORD            wOldBkMode;                /* old background mode */
  584.     
  585.     /* setup display context */
  586.     wOldROP2 = SetROP2( hDC, R2_NOT );
  587.     wOldBkMode = SetBkMode( hDC, TRANSPARENT );
  588.  
  589.     hOldPen = SelectObject( hDC, CreatePen(0,2,RGB(0,0,0)) );
  590.     
  591.     /* draw selector rectangle */
  592.     Rectangle(
  593.         hDC,
  594.         SELECTOR_XPOS,
  595.         SELECTOR_YPOS,
  596.         SELECTOR_XPOS+SELECTOR_WIDTH,
  597.         SELECTOR_YPOS+SELECTOR_HEIGHT
  598.     );
  599.  
  600.     DeleteObject( SelectObject(hDC,hOldPen) );
  601.  
  602.     /* restore display context */
  603.     SetBkMode( hDC, wOldBkMode );
  604.     SetROP2( hDC, wOldROP2 );
  605.  
  606. }
  607.  
  608.