home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / widgetry.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  18.2 KB  |  805 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "stdafx.h"
  20. #include "widgetry.h"
  21.  
  22. class CProgressMeterClass
  23. {
  24. protected:
  25.      HWND    m_hWnd;
  26.     int        cubeHeight;
  27.     int        cubeWidth;
  28.     int        cubeCount;
  29.     int     percent;     
  30.     int        lastUpdate;
  31.  
  32.     HBRUSH    m_hbrushBlue;
  33.  
  34.     void PaintCube(HDC hdc, int position);
  35.  
  36. public:
  37.     static void RegisterClass();
  38.  
  39.     CProgressMeterClass(HWND hwnd);
  40.     ~CProgressMeterClass();
  41.  
  42.     void OnPaint();
  43.     void OnStep();
  44.     void OnStepTo(int newPercent);
  45. };
  46.  
  47. //////////////////////////////////////////////////////////////////////////////
  48. // CProgressMeter
  49. // The progress meter draws a 3D progress status inside the static 
  50. // control
  51.  
  52. #define EDGE_WIDTH  2       // default bevel edge width
  53.  
  54. CProgressMeterClass::CProgressMeterClass(HWND hwnd)
  55. {
  56.     m_hWnd = hwnd;
  57.     lastUpdate = percent = cubeWidth = cubeHeight = 0;        
  58.     cubeCount = 1;
  59.     m_hbrushBlue = ::CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
  60. }
  61.  
  62. CProgressMeterClass::~CProgressMeterClass()
  63. {
  64.     VERIFY(::DeleteObject(m_hbrushBlue));
  65. }
  66.  
  67.  
  68. void CProgressMeterClass::OnPaint()
  69. {
  70.     PAINTSTRUCT             paint;
  71.     BeginPaint(m_hWnd, &paint);
  72.     HDC hdc = paint.hdc;
  73.     RECT rect;                      // get the entire area of the static region
  74.     ::GetClientRect(m_hWnd, &rect);           
  75.  
  76.     int nCubes, oldmod = 21;
  77.  
  78.     // try 20 to 30 cubes and select the best fit (least modulo)
  79.     for ( nCubes = 30; nCubes <= 50; nCubes++ )
  80.     {
  81.         int extra = ( rect.right - 4 ) / nCubes;
  82.         int val = ( ( rect.right - 4 ) + ( extra / 2 ) ) % nCubes;
  83.  
  84.         // is this a better fit than the last try?
  85.         if ( val < oldmod )
  86.         {
  87.             oldmod = val;           // yes, save count
  88.             cubeCount = nCubes;
  89.  
  90.             // compute the cube width and height for the control
  91.             cubeWidth = ( ( ( rect.right - 4 ) + ( extra / 2 ) ) ) / nCubes;
  92.             cubeHeight = rect.bottom - 4;
  93.  
  94.             // if this is a perfect fit, look no further
  95.             if ( !val )
  96.                 break;
  97.         }
  98.     }        
  99.  
  100.     WFE_DrawLoweredRect(hdc, &rect);
  101.         
  102.     // draw the center of the control in the button face color
  103.     ::InflateRect(&rect, -EDGE_WIDTH, -EDGE_WIDTH);
  104.     ::FillRect( hdc, &rect, sysInfo.m_hbrBtnFace );
  105.  
  106.     // paint all the cubes that have been painted already (this is for refresh)
  107.     long i;
  108.     long interval = 1000 / cubeCount;
  109.     if ( !interval )
  110.         interval = 1;
  111.  
  112.     if (percent > 100)
  113.         percent = 100;
  114.     if (percent < 0)
  115.         percent = 0;
  116.  
  117.     for ( i = 0; i < long(percent) * 1000L / interval / 100; i++ )
  118.         PaintCube( hdc, CASTINT(i) );
  119.  
  120.     EndPaint(m_hWnd, &paint);
  121. }
  122.  
  123. // Paint a single cube in the progress control
  124.  
  125. void CProgressMeterClass::PaintCube ( HDC hdc, int position )
  126. {
  127.     if ( position <= cubeCount )
  128.     {
  129.         RECT MeterRect;
  130.         ::GetClientRect(m_hWnd, &MeterRect);
  131.         RECT rect;
  132.  
  133.         // cubes get painted 1 pixel less than the inside area with
  134.         // 2 pixel spaces between cubes
  135.         rect.left = EDGE_WIDTH + 2 + ( position * cubeWidth );
  136.         rect.top = EDGE_WIDTH + 3;
  137.         rect.bottom = cubeHeight;
  138.         rect.right = ( rect.left + cubeWidth ) - 2;
  139.  
  140.         if (rect.right < MeterRect.right)
  141.             ::FillRect(hdc, &rect, m_hbrushBlue);
  142.     }
  143. }
  144.  
  145. void CProgressMeterClass::OnStepTo(int newPercent)
  146. {
  147.     if (newPercent < percent) {
  148.         lastUpdate = percent = 0;
  149.         RedrawWindow(m_hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
  150.     }
  151.     while (percent<newPercent) 
  152.         OnStep();
  153. }
  154.  
  155. // increase the gauge by 1% and update the cubes if required
  156.  
  157. void CProgressMeterClass::OnStep()
  158. {
  159.     HDC hdc = GetDC(m_hWnd);
  160.  
  161.     // did we overstep?
  162.     if ( percent < 100 )
  163.     {
  164.         // get the spacing
  165.         long interval = 1000 / cubeCount;
  166.         if ( !interval )
  167.             interval = 1;
  168.         percent++;
  169.  
  170.         // time to draw another cube?
  171.         if (long(percent) * 1000L / interval / 100 > lastUpdate)
  172.         {   
  173.             PaintCube ( hdc, lastUpdate );
  174.             lastUpdate = CASTINT(long(percent) * 1000L / interval  / 100);
  175.         }
  176.     }
  177.     ReleaseDC(m_hWnd, hdc);
  178. }
  179.  
  180. LRESULT CALLBACK EXPORT
  181. ProgressMeterWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  182. {
  183.     CProgressMeterClass *pObject;
  184.  
  185.     // If we've been created then create our C++ object
  186.     if (iMsg == WM_CREATE) {
  187.         pObject = new CProgressMeterClass(hwnd);
  188.         if (!pObject)
  189.             return -1;
  190.  
  191.         SetWindowLong(hwnd, 0, (LONG) pObject);
  192.         return 0;
  193.     }
  194.  
  195.     // Get the pointer to our C++ object
  196.     pObject = (CProgressMeterClass *)GetWindowLong(hwnd, 0);
  197.     if (!pObject)
  198.         return DefWindowProc(hwnd, iMsg, wParam, lParam);
  199.  
  200.     switch (iMsg) {
  201.         case WM_DESTROY:
  202.             delete pObject;
  203.             SetWindowLong(hwnd, 0, 0L);
  204.             break;
  205.  
  206.         case WM_PAINT:
  207.             pObject->OnPaint();
  208.             break;
  209.  
  210.         case NSPM_STEP:
  211.             pObject->OnStep();
  212.             break;
  213.  
  214.         case NSPM_STEPTO:
  215.             pObject->OnStepTo((int) wParam);
  216.             break;
  217.  
  218.         default:
  219.             return DefWindowProc(hwnd, iMsg, wParam, lParam);
  220.     }
  221.  
  222.     return 0;
  223. }
  224.  
  225. // Initialization routine
  226.  
  227. void CProgressMeterClass::RegisterClass()
  228. {
  229.     WNDCLASS    wndclass;
  230.  
  231.     wndclass.style         = 0;
  232.     wndclass.lpfnWndProc   = ProgressMeterWndProc;
  233.     wndclass.cbClsExtra    = 0;
  234.     wndclass.cbWndExtra    = sizeof(CProgressMeterClass *);
  235.     wndclass.hInstance     = AfxGetInstanceHandle();
  236.     wndclass.hIcon         = NULL;
  237.     wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  238.     wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  239.     wndclass.lpszMenuName  = NULL;
  240.     wndclass.lpszClassName = WC_NSPROGRESS;
  241.  
  242.     ::RegisterClass(&wndclass);
  243. }
  244.  
  245. CProgressMeter::CProgressMeter()
  246. {
  247.     m_hWnd = NULL;
  248. }
  249.  
  250. BOOL CProgressMeter::SubclassDlgItem(UINT nID, CWnd *pParent)
  251. {
  252.     HWND hwnd = pParent->GetDlgItem(nID)->GetSafeHwnd();
  253.     RECT rcWindow;
  254.     GetWindowRect(hwnd, &rcWindow);
  255.     MapWindowPoints(NULL, pParent->GetSafeHwnd(), (LPPOINT) &rcWindow, 2);
  256.  
  257.     m_hWnd = ::CreateWindow(WC_NSPROGRESS, NULL, WS_CHILD|WS_VISIBLE,
  258.                             rcWindow.left, rcWindow.top,
  259.                             rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top,
  260.                             pParent->GetSafeHwnd(),
  261.                             (HMENU) ::GetDlgCtrlID(hwnd),
  262.                             AfxGetInstanceHandle(),
  263.                             NULL);
  264.  
  265.     ::DestroyWindow(hwnd);
  266.     return m_hWnd != NULL;
  267. }
  268.  
  269. void CProgressMeter::StepIt()
  270. {
  271.     if (m_hWnd)
  272.         ::SendMessage(m_hWnd, NSPM_STEP, (WPARAM) 0, (LPARAM) 0);
  273. }
  274.  
  275. void CProgressMeter::StepItTo(int newPercent)
  276. {
  277.     if (m_hWnd)
  278.         ::SendMessage(m_hWnd, NSPM_STEPTO, (WPARAM) newPercent, (LPARAM) 0);
  279. }
  280.  
  281. #ifndef _WIN32X
  282.  
  283. /////////////////////////////////////////////////////////////////////
  284. // CUpDownClass
  285.  
  286. #define UDT_PAUSE    1
  287. #define UDT_REFRESH    2
  288.  
  289. static const char szProp[] = "NSUpDown";
  290.  
  291. class CUpDownClass {
  292. private:
  293.     HWND m_hWnd, m_hwndBuddy;
  294.     UINT m_nBase;
  295.     int m_nPos, m_nLower, m_nUpper;
  296.     DWORD m_dwStyle;
  297.     UINT m_idTimer;
  298.     int m_iHit, m_iState;
  299.     HBITMAP m_hbmArrows;
  300.  
  301.     enum { udsNone, udsUp, udsDown };
  302.  
  303.     void _UpdateValue(int nPos);
  304.     int _GetValue();
  305.  
  306.     void _Up();
  307.     void _Down();
  308.  
  309.     void _SetState(int iState);
  310.  
  311. public:
  312.     WNDPROC m_pfSuperProc;
  313.  
  314.     CUpDownClass(HWND hwnd);
  315.     ~CUpDownClass();
  316.  
  317.     BOOL HandleEvent(UINT iMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult);
  318.  
  319.     void OnEnable(BOOL bEnable);
  320.     void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
  321.     void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
  322.     void OnLButtonDown(UINT nFlags, POINT point);
  323.     void OnLButtonUp(UINT nFlags, POINT point);
  324.     void OnPaint();
  325.     void OnTimer(UINT nID);
  326.  
  327.     BOOL SetAccel(int nAccel, UDACCEL* pAccel);
  328.     UINT GetAccel(int nAccel, UDACCEL* pAccel) const;
  329.     UINT SetBase(UINT nBase);
  330.     UINT GetBase() const;
  331.     HWND SetBuddy(HWND hwndBuddy);
  332.     HWND GetBuddy() const;
  333.     int SetPos(int nPos);
  334.     int GetPos() const;
  335.     void SetRange(int nLower, int nUpper);
  336.     DWORD GetRange() const;
  337.  
  338.     static void RegisterClass();
  339. };
  340.  
  341. // WNDPROCs
  342.  
  343. LRESULT CALLBACK
  344. UpDownWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  345. {
  346.     CUpDownClass *pObject;
  347.     POINT pt;
  348.  
  349.     // If we've been created then create our C++ object
  350.     if (iMsg == WM_CREATE) {
  351.         pObject = new CUpDownClass(hwnd);
  352.         if (!pObject)
  353.             return -1;
  354.  
  355.         SetWindowLong(hwnd, 0, (LONG) pObject);
  356.         return 0;
  357.     }
  358.  
  359.     // Get the pointer to our C++ object
  360.     pObject = (CUpDownClass *)GetWindowLong(hwnd, 0);
  361.     if (!pObject)
  362.         return DefWindowProc(hwnd, iMsg, wParam, lParam);
  363.  
  364.     switch (iMsg) {
  365.         case WM_DESTROY:
  366.             delete pObject;
  367.             SetWindowLong(hwnd, 0, 0L);
  368.             break;
  369.  
  370.         case WM_ENABLE:
  371.             pObject->OnEnable((BOOL) wParam);
  372.             break;
  373.  
  374.         case WM_KEYDOWN:
  375.             pObject->OnKeyDown((UINT) wParam, (UINT) LOWORD(lParam), (UINT) HIWORD(lParam));
  376.             break;
  377.  
  378.         case WM_KEYUP:
  379.             pObject->OnKeyUp((UINT) wParam, (UINT) LOWORD(lParam), (UINT) HIWORD(lParam));
  380.             break;
  381.  
  382.         case WM_LBUTTONDOWN:
  383.             pt.x = LOWORD(lParam);
  384.             pt.y = HIWORD(lParam);
  385.             pObject->OnLButtonDown((UINT) wParam, pt);
  386.             break;
  387.  
  388.         case WM_LBUTTONUP:
  389.             pt.x = LOWORD(lParam);
  390.             pt.y = HIWORD(lParam);
  391.             pObject->OnLButtonUp((UINT) wParam, pt);
  392.  
  393.         case WM_PAINT:
  394.             pObject->OnPaint();
  395.             break;
  396.  
  397.         case WM_TIMER:
  398.             pObject->OnTimer((UINT) wParam);
  399.             break;
  400.  
  401.         case UDM_SETRANGE:
  402.             pObject->SetRange((int) HIWORD(lParam), (int) LOWORD(lParam));
  403.             break;
  404.  
  405.         case UDM_GETRANGE:
  406.             return (LRESULT) pObject->GetRange();
  407.  
  408.         case UDM_SETPOS:
  409.             pObject->SetPos((int) wParam);
  410.  
  411.         case UDM_GETPOS:
  412.             return (LRESULT) pObject->GetPos();
  413.  
  414.         case UDM_SETBUDDY:
  415.             pObject->SetBuddy((HWND) wParam);
  416.             break;
  417.  
  418.         case UDM_GETBUDDY:
  419.             return (LRESULT) pObject->GetBuddy();
  420.  
  421.         case UDM_SETACCEL:
  422.             return (LPARAM) pObject->SetAccel((int) wParam, (LPUDACCEL) lParam);
  423.  
  424.         case UDM_GETACCEL:
  425.             return (LPARAM) pObject->GetAccel((int) wParam, (LPUDACCEL) lParam);
  426.             break;
  427.  
  428.         case UDM_SETBASE:
  429.             pObject->SetBase((UINT) wParam);
  430.             break;
  431.  
  432.         case UDM_GETBASE:
  433.             return (LRESULT) pObject->GetBase();
  434.  
  435.         default:
  436.             return DefWindowProc(hwnd, iMsg, wParam, lParam);
  437.     }
  438.  
  439.     return 0;
  440. }
  441.  
  442. LRESULT CALLBACK UpDownSubWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
  443. {
  444.     HWND hwndUpDown = (HWND) ::GetProp(hwnd, szProp);
  445.     if (hwndUpDown) {
  446.         CUpDownClass *pObject = (CUpDownClass *) GetWindowLong(hwndUpDown, 0);
  447.         if (pObject) {
  448.             LRESULT lResult;
  449.             if (!pObject->HandleEvent(iMsg, wParam, lParam, &lResult))
  450.                 return CallWindowProc(pObject->m_pfSuperProc, hwnd, iMsg, wParam, lParam );
  451.             else
  452.                 return lResult;
  453.         }
  454.     }
  455.     // Tragedy, punt
  456.     return DefWindowProc(hwnd, iMsg, wParam, lParam);
  457. }
  458.  
  459. // Constructor/Destructor
  460.  
  461. static WORD awArrows[] = { 0xef, 0xc7, 0x83, 0x01, 0x83, 0xc7, 0xef, 0x00 };
  462.  
  463. CUpDownClass::CUpDownClass(HWND hwnd)
  464. {
  465.     m_hWnd = hwnd;
  466.     m_dwStyle = ::GetWindowLong(m_hWnd, GWL_STYLE);
  467.     m_iState = m_iHit = udsNone;
  468.  
  469.     m_hbmArrows = ::CreateBitmap(8, 8, 1, 1, awArrows);
  470.  
  471.     m_nPos = 1;
  472.     m_nLower = 1;
  473.     m_nUpper = 100;
  474.  
  475.     m_pfSuperProc = NULL;
  476. }
  477.  
  478. CUpDownClass::~CUpDownClass()
  479. {
  480.     if (m_idTimer)
  481.         KillTimer(m_hWnd, m_idTimer);
  482.  
  483.     SetBuddy(NULL);
  484.  
  485.     VERIFY(::DeleteObject(m_hbmArrows));
  486. }
  487.  
  488. // Private methods
  489.  
  490. void CUpDownClass::_UpdateValue(int nPos)
  491. {
  492.     m_nPos = nPos;
  493.     if (m_hwndBuddy && (m_dwStyle & UDS_SETBUDDYINT)) {
  494.         char szText[17];
  495.         _itoa(m_nPos, szText, 10);
  496.         ::SendMessage(m_hwndBuddy, WM_SETTEXT, (WPARAM) 0, (LPARAM) szText);
  497.     }
  498. }
  499.  
  500. int CUpDownClass::_GetValue()
  501. {
  502.     int nPos = m_nPos;
  503.     if (m_hwndBuddy && (m_dwStyle & UDS_SETBUDDYINT)) {
  504.         char szText[17];
  505.         ::SendMessage(m_hwndBuddy, WM_GETTEXT, (WPARAM) 17, (LPARAM) szText);
  506.         int nVal = atoi(szText);
  507.         if (nVal >= m_nLower && nVal <= m_nUpper)
  508.             nPos = nVal;
  509.     }
  510.  
  511.     return nPos;
  512. }
  513.  
  514. void CUpDownClass::_Up()
  515. {
  516.     int nPos = _GetValue();
  517.     if (nPos < m_nUpper) {
  518.         nPos++;
  519.     } else if (m_dwStyle & UDS_WRAP) {
  520.         nPos = m_nLower;
  521.     }
  522.     _UpdateValue(nPos);
  523. }
  524.  
  525. void CUpDownClass::_Down()
  526. {
  527.     int nPos = _GetValue();
  528.     if (nPos > m_nLower) {
  529.         nPos--;
  530.     } else if (m_dwStyle & UDS_WRAP) {
  531.         nPos = m_nUpper;
  532.     }
  533.     _UpdateValue(nPos);
  534. }
  535.  
  536. void CUpDownClass::_SetState(int iState)
  537. {
  538.     if (m_iState != iState) {
  539.         m_iState = iState;
  540.         ::InvalidateRect(m_hWnd, NULL, TRUE);
  541.         ::UpdateWindow(m_hWnd);
  542.     }
  543. }
  544.  
  545. BOOL CUpDownClass::HandleEvent(UINT iMsg, WPARAM wParam, LPARAM lParam, LRESULT *lResult)
  546. {
  547.     *lResult = 0;
  548.  
  549.     if ((iMsg == WM_KEYDOWN || iMsg == WM_KEYUP) && m_dwStyle & UDS_ARROWKEYS) {
  550.         if (((UINT) wParam) == VK_UP || ((UINT) wParam) == VK_DOWN) {
  551.             if (iMsg == WM_KEYDOWN) {
  552.                 OnKeyDown((UINT) wParam, LOWORD(lParam), HIWORD(lParam));
  553.             } else {
  554.                 OnKeyUp((UINT) wParam, LOWORD(lParam), HIWORD(lParam));
  555.             }
  556.             return TRUE;
  557.         }
  558.     }
  559.  
  560.     return FALSE;
  561. }
  562.  
  563. // WM_ methods
  564.  
  565. void CUpDownClass::OnEnable(BOOL bEnable)
  566. {
  567.     ::InvalidateRect(m_hWnd, NULL, TRUE);
  568.     ::UpdateWindow(m_hWnd);
  569. }
  570.  
  571. void CUpDownClass::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  572. {
  573.     if (m_dwStyle & UDS_ARROWKEYS) {
  574.         if (nChar == VK_UP) {
  575.             _Up();
  576.             _SetState(udsUp);
  577.         } else if (nChar = VK_DOWN) {
  578.             _Down();
  579.             _SetState(udsDown);
  580.         }
  581.     }
  582. }
  583.  
  584. void CUpDownClass::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  585. {
  586.     _SetState(udsNone);
  587. }
  588.  
  589. void CUpDownClass::OnLButtonDown(UINT nFlags, POINT point)
  590. {
  591.     ::SetCapture(m_hWnd);
  592.     RECT rcClient;
  593.     ::GetClientRect(m_hWnd, &rcClient);
  594.     if (point.y < (rcClient.bottom / 2)) {
  595.         m_iHit = udsUp;
  596.         _Up();
  597.     } else {
  598.         m_iHit = udsDown;
  599.         _Down();
  600.     }
  601.     m_idTimer = ::SetTimer(m_hWnd, UDT_PAUSE, 500, NULL);
  602.  
  603.     _SetState(m_iHit);
  604. }
  605.  
  606. void CUpDownClass::OnLButtonUp(UINT nFlags, POINT point)
  607. {
  608.     if (::GetCapture() == m_hWnd)
  609.         ::ReleaseCapture();
  610.  
  611.     if (m_idTimer) {
  612.         ::KillTimer(m_hWnd, m_idTimer);
  613.         m_idTimer = 0;
  614.     }
  615.     m_iHit = udsNone;
  616.     _SetState(udsNone);
  617. }
  618.  
  619. void CUpDownClass::OnPaint()
  620. {
  621.     PAINTSTRUCT             paint;
  622.     BeginPaint(m_hWnd, &paint);
  623.     HDC hdc = paint.hdc;
  624.  
  625.     HDC hdcArrows = ::CreateCompatibleDC(hdc);
  626.     HBITMAP hbmOld = (HBITMAP) ::SelectObject(hdcArrows, m_hbmArrows);
  627.     COLORREF oldBk = ::SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
  628.     COLORREF oldText = ::SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
  629.  
  630.     RECT rcTop, rcBottom;
  631.     ::GetClientRect(m_hWnd, &rcTop);
  632.     rcBottom = rcTop;
  633.     rcTop.bottom = rcTop.bottom / 2;
  634.     rcBottom.top = rcTop.bottom + 1;
  635.  
  636.     int ux, uy, dx, dy;
  637.     ux = (rcTop.right + 1) / 2 - 4;
  638.     uy = (rcTop.bottom + 1) / 2 - 2;
  639.     dx = ux;
  640.     dy = rcBottom.bottom - uy - 3;
  641.  
  642.     if (m_iState == udsUp) {
  643.         ux++;
  644.         uy++;
  645.     } else if (m_iState == udsDown) {
  646.         dx++;
  647.         dy++;
  648.     }
  649.     ::BitBlt(hdc, ux, uy, 8, 3, hdcArrows, 0, 0, SRCCOPY);
  650.     ::BitBlt(hdc, dx, dy, 8, 3, hdcArrows, 0, 4, SRCCOPY);
  651.  
  652.     WFE_Draw3DButtonRect(hdc, &rcTop, m_iState == udsUp);
  653.     WFE_Draw3DButtonRect(hdc, &rcBottom, m_iState == udsDown);
  654.  
  655.     ::SelectObject(hdcArrows, hbmOld);
  656.     VERIFY(::DeleteDC(hdcArrows));
  657.     ::SetBkColor(hdc, oldBk);
  658.     ::SetTextColor(hdc, oldText);
  659.  
  660.     EndPaint(m_hWnd, &paint);
  661. }
  662.  
  663. void CUpDownClass::OnTimer(UINT nID)
  664. {
  665.     int iState = udsNone;
  666.  
  667.     if (::GetCapture() == m_hWnd) {
  668.         if (nID == UDT_PAUSE) {
  669.             ::KillTimer(m_hWnd, m_idTimer);
  670.             m_idTimer = ::SetTimer(m_hWnd, UDT_REFRESH, 100, NULL);
  671.         }
  672.         
  673.         RECT rcClient;
  674.         ::GetClientRect(m_hWnd, &rcClient);
  675.         POINT pt;
  676.         ::GetCursorPos(&pt);
  677.         ::ScreenToClient(m_hWnd, &pt);
  678.  
  679.         if (::PtInRect(&rcClient, pt)) {
  680.             iState = (pt.y < rcClient.bottom / 2) ? udsUp : udsDown;
  681.             if (iState == m_iHit) {
  682.                 if (iState == udsUp) {
  683.                     _Up();
  684.                 } else {
  685.                     _Down();
  686.                 }
  687.             }
  688.         }
  689.     } else {
  690.         ::KillTimer(m_hWnd, m_idTimer);
  691.         m_idTimer = 0;
  692.     }
  693.     _SetState(iState);
  694. }
  695.  
  696. // UDM_ methods
  697.  
  698. BOOL CUpDownClass::SetAccel(int nAccel, UDACCEL* pAccel)
  699. {
  700.     ASSERT(0);
  701.     return FALSE;
  702. }
  703.  
  704. UINT CUpDownClass::GetAccel(int nAccel, UDACCEL* pAccel) const
  705. {
  706.     ASSERT(0);
  707.     return 0;
  708. }
  709.  
  710. UINT CUpDownClass::SetBase(UINT nBase)
  711. {
  712.     int res = m_nBase;
  713.     m_nBase = nBase;
  714.     return res;
  715. }
  716.  
  717. UINT CUpDownClass::GetBase() const
  718. {
  719.     return m_nBase;
  720. }
  721.  
  722. HWND CUpDownClass::SetBuddy(HWND hwndBuddy)
  723. {
  724.     HWND res = m_hwndBuddy;
  725.  
  726.     if (::IsWindow(m_hwndBuddy)) {
  727.         // Unsubclass the parent window        
  728.         if (GetWindowLong(m_hwndBuddy, GWL_WNDPROC) == (LONG) UpDownSubWndProc) {       
  729.             ::SetWindowLong(m_hwndBuddy, GWL_WNDPROC, (LONG) m_pfSuperProc);
  730.         }
  731.         VERIFY(RemoveProp(m_hwndBuddy, szProp));
  732.         m_hwndBuddy = NULL;
  733.     }
  734.     if (::IsWindow(hwndBuddy)) {
  735.         m_hwndBuddy = hwndBuddy;
  736.         VERIFY(SetProp(m_hwndBuddy, szProp, (HANDLE) m_hWnd));
  737.         m_pfSuperProc = (WNDPROC) ::SetWindowLong(m_hwndBuddy, GWL_WNDPROC, (LONG) UpDownSubWndProc);
  738.     }
  739.     return res;
  740. }
  741.  
  742. HWND CUpDownClass::GetBuddy() const
  743. {
  744.     return m_hwndBuddy;
  745. }
  746.  
  747. int CUpDownClass::SetPos(int nPos)
  748. {
  749.     int res = m_nPos;
  750.     m_nPos = nPos;
  751.     return res;
  752. }
  753.  
  754. int CUpDownClass::GetPos() const
  755. {
  756.     return m_nPos;
  757. }
  758.  
  759. void CUpDownClass::SetRange(int nLower, int nUpper)
  760. {
  761.     m_nLower = nLower;
  762.     m_nUpper = nUpper;
  763. }
  764.  
  765.  
  766. DWORD CUpDownClass::GetRange() const
  767. {
  768.     return MAKELONG(m_nLower, m_nUpper);
  769. }
  770.  
  771. void CUpDownClass::RegisterClass()
  772. {
  773.     WNDCLASS    wndclass;
  774.  
  775.     wndclass.style         = CS_PARENTDC|CS_HREDRAW|CS_VREDRAW;
  776.     wndclass.lpfnWndProc   = UpDownWndProc;
  777.     wndclass.cbClsExtra    = 0;
  778.     wndclass.cbWndExtra    = sizeof(CUpDownClass *);
  779.     wndclass.hInstance     = AfxGetInstanceHandle();
  780.     wndclass.hIcon         = NULL;
  781.     wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  782.     wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  783.     wndclass.lpszMenuName  = NULL;
  784.     wndclass.lpszClassName = NSUPDOWN_CLASS;
  785.  
  786.     ::RegisterClass(&wndclass);
  787. }
  788.  
  789. #endif
  790.  
  791. #ifdef FEATURE_SPIN_BUTTON
  792. #include "widgetry.i01"
  793. #endif
  794.  
  795. /////////////////////////////////////////////////////////////////////
  796. // AssortedWidgetInit
  797.  
  798. void AssortedWidgetInit()
  799. {
  800.     CProgressMeterClass::RegisterClass();
  801. #ifndef _WIN32X
  802.     CUpDownClass::RegisterClass();
  803. #endif
  804. }
  805.