home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / ITSY.ZIP / ITSYBITS.C < prev    next >
C/C++ Source or Header  |  1993-03-19  |  47KB  |  1,451 lines

  1. /////////////////////////////////////////////////////////////////////////
  2. //
  3. //     Project:  ItsyBitsy window support module
  4. //
  5. //      Module:  itsybits.c
  6. //
  7. //     Remarks:
  8. //
  9. //    ItsyBitsy is a support module that allows you to create windows
  10. //    that look and act very much like a popup window witha system
  11. //    menu and caption bar, except everything is scaled to about 2/3
  12. //    scale.
  13. //
  14. //    For documentation on how to use ItsyBits, read the document
  15. //    ITSYBITS.RTF, which is in rich text format.
  16. //
  17. //   Revisions:
  18. //      9/27/91 Charles E. Kindel, Jr (Charlkin)
  19. //              Wrote and documented it.
  20. //
  21. //      1/14/93 Charles E. Kindel, Jr. (CKindel)
  22. //      2/23/93 Charles E. Kindel, Jr.
  23. //              Added minimize/maximize buttons.
  24. //      3/18/93 Fixed system menu bug where system menu popped back up
  25. //              if you clicked on the icon again while it was up.
  26. //
  27. //////////////////////////////////////////////////////////////////////////
  28.  
  29. #include "precomp.h"
  30.  
  31. #ifdef NOPRECOMP
  32. #include <windows.h>
  33. #include <windowsx.h>
  34. #include <memory.h>
  35. #endif
  36.  
  37. #include "itsybits.h"
  38.  
  39. // Caption XY is the default size of the system menu icon.  This
  40. // determines the height/width of the caption.
  41. //
  42. // The value that results from the following formula works out
  43. // nicely for the veritcal caption on VGA, 8514 (Large Fonts),
  44. // 8514 (Small Fonts), XGA (Small Fonts), XGA (Large Fonts),
  45. // and TIGA (Small Fonts).  It may not be good on other displays.
  46. //
  47. // The problem is that TT fonts turn into bitmap fonts when they
  48. // are sized below a certain threshold.  The idea is to make the
  49. // size of the caption just big enough to get the smallest TT
  50. // (scalable) font to fit.
  51. //
  52. #define CAPTIONXY (GetSystemMetrics( SM_CYCAPTION ) / 2 + 1)
  53.  
  54. #define HASCAPTION( hwnd ) (TestWinStyle( hwnd, IBS_VERTCAPTION ) ||\
  55.                             TestWinStyle( hwnd, IBS_HORZCAPTION ))
  56. #define SETCAPTIONSIZE(h,i)   (UINT)SetProp(h,MAKEINTATOM( 0xFF42 ),(HANDLE)i)
  57. #define GETCAPTIONSIZE(h)     (UINT)GetProp(h,MAKEINTATOM( 0xFF42 ))
  58. #define FREECAPTIONSIZE(h)    RemoveProp(h,MAKEINTATOM( 0xFF42 ))
  59. #define SETMENUWASUPFLAG(h,i)   (UINT)SetProp(h,MAKEINTATOM( 0xFF43 ),(HANDLE)i)
  60. #define GETMENUWASUPFLAG(h)     (UINT)GetProp(h,MAKEINTATOM( 0xFF43 ))
  61. #define FREEMENUWASUPFLAG(h)    RemoveProp(h,MAKEINTATOM( 0xFF43 ))
  62.  
  63. #define TestWinStyle( hWnd, dwStyleBit ) \
  64.         (((DWORD)GetWindowLong( hWnd, GWL_STYLE ) & (DWORD)dwStyleBit) ? TRUE : FALSE )
  65.  
  66. /////////////////////////////////////////////////////////////////////
  67. // Little known fact:
  68. //    ExtTextOut() is the fastest way to draw a filled rectangle
  69. //    in Windows (if you don't want dithered colors or borders).
  70. //
  71. //    Unfortunately there is a bug in the Windows 3.0 8514 driver
  72. //    in using ExtTextOut() to a memory DC.  If you are drawing
  73. //    to an off screen bitmap, then blitting that bitmap to the
  74. //    display, do not #define USE_EXTTEXTOUT below.
  75. //
  76. //    The following macro (DRAWFASTRECT) draws a filled rectangle
  77. //    with no border and a solid color.  It uses the current back-
  78. //    ground color as the fill color.
  79. //////////////////////////////////////////////////////////////////////
  80. #define USE_EXTTEXTOUT
  81. #ifdef USE_EXTTEXTOUT
  82.    #define DRAWFASTRECT(hdc,lprc) ExtTextOut(hdc,0,0,ETO_OPAQUE,lprc,NULL,0,NULL)
  83. #else
  84.    #define DRAWFASTRECT(hdc,lprc) {\
  85.    HBRUSH hbr = CreateSolidBrush( GetBkColor( hdc ) ) ;\
  86.    hbr = SelectObject(hdc, hbr) ;\
  87.    PatBlt(hdc,(lprc)->left,(lprc)->top,(lprc)->right-(lprc)->left,(lprc)->bottom-(lprc)->top,PATCOPY) ;\
  88.    hbr = SelectObject(hdc, hbr) ;\
  89.    DeleteObject( hbr ) ;\
  90.    }
  91. #endif
  92.  
  93. BOOL NEAR PASCAL DepressMinMaxButton( HWND hWnd, UINT uiHT, LPRECT ) ;
  94. BOOL NEAR PASCAL DoMenu( HWND hWnd ) ;
  95. void NEAR PASCAL SetupSystemMenu( HWND hWnd, HMENU hMenu ) ;
  96. BOOL NEAR PASCAL GetCaptionRect( HWND hWnd, LPRECT lprc ) ;
  97. BOOL NEAR PASCAL GetIconRect( HWND hWnd, LPRECT lprc ) ;
  98. BOOL NEAR PASCAL GetButtonRect( HWND hWnd, UINT nPos, LPRECT lprc ) ;
  99. BOOL NEAR PASCAL GetMinButtonRect( HWND hWnd, LPRECT lprc ) ;
  100. BOOL NEAR PASCAL GetMaxButtonRect( HWND hWnd, LPRECT lprc ) ;
  101. BOOL NEAR PASCAL DrawCaption( HDC hDC, HWND hWnd, LPRECT lprc,
  102.                               BOOL fVert, BOOL fSysMenu, 
  103.                               BOOL fMin, BOOL fMax, BOOL fActive ) ;
  104. VOID NEAR PASCAL DrawSysMenu( HDC hDC, HWND hWnd, BOOL fInvert ) ;
  105. VOID NEAR PASCAL DrawButton( HDC hDC, HWND hWnd, BOOL fMin, BOOL fDepressed ) ;
  106. VOID NEAR PASCAL DrawArrow( HDC hdc, LPRECT lprc, UINT uiStyle ) ;
  107.  
  108. #define ARROW_UP        0
  109. #define ARROW_DOWN      1
  110. #define ARROW_RESTORE   2
  111.  
  112. // Global vars
  113. //
  114. static BOOL fWin31 ;
  115.  
  116. /////////////////////////////////////////////////////////////////
  117. //  UINT WINAPI ibGetCaptionSize( HWND hWnd )
  118. //
  119. //  Description: 
  120. //
  121. //    Gets the size of the caption (height if horz, width if
  122. //    vertical).
  123. //
  124. //  Comments:
  125. //
  126. ///////////////////////////////////////////////////////////////
  127. UINT WINAPI ibGetCaptionSize( HWND hWnd  )
  128. {
  129.     return GETCAPTIONSIZE( hWnd ) + 1 ;
  130. } // ibSetCaptionSize()
  131.  
  132. /////////////////////////////////////////////////////////////////
  133. //  UINT WINAPI ibSetCaptionSize( HWND hWnd, UINT nSize )
  134. //
  135. //  Description: 
  136. //
  137. //    Changes the size of the caption (height if horz, width if
  138. //    vertical).
  139. //
  140. //  Comments:
  141. //
  142. //////////////////////////////////////////////////////////////////
  143. UINT WINAPI ibSetCaptionSize( HWND hWnd, UINT nSize )
  144. {
  145.     UINT ui ;
  146.  
  147.     if (nSize <= 0)
  148.         return 0 ;
  149.  
  150.     nSize-- ;
  151.     ui = SETCAPTIONSIZE( hWnd, nSize ) ;
  152.  
  153.     // Once we change the window style, we need a WM_NCCALCRECT
  154.     // to be generated.
  155.     //
  156.     // SWP_FRAMECHANGED is not documented in the 3.1 SDK docs,
  157.     // but *is* in WINDOWS.H.
  158.     //
  159.     SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | 
  160.                         SWP_NOSIZE | SWP_NOMOVE | 
  161.                         SWP_NOACTIVATE | SWP_NOZORDER) ;
  162.  
  163.     return ui ;
  164.  
  165. } // ibSetCaptionSize()
  166.  
  167. /////////////////////////////////////////////////////////////////
  168. //  LRESULT WINAPI ibDefWindowProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam )
  169. //
  170. //  Description: 
  171. //
  172. //    This function should be called instead of DefWindowProc() for
  173. //    windows that want to have itsybitsy captions.
  174. //
  175. //  Comments:
  176. //
  177. //////////////////////////////////////////////////////////////////
  178. LRESULT WINAPI ibDefWindowProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam )
  179. {
  180.     LRESULT lRet ;
  181.     UINT  nCapSize ;
  182.  
  183.     switch( uiMsg )
  184.     {
  185.         case WM_SYSCHAR:
  186.             // If ALT-SPACE 
  187.             // was hit then pop up the menu
  188.             // 
  189.             if (HASCAPTION( hWnd ) && (wParam == VK_SPACE))
  190.             {
  191.                 DoMenu( hWnd ) ;
  192.                 break ;
  193.             }
  194.  
  195.             // FALL THROUGH!!!!
  196.             // 
  197.  
  198.         case WM_SYSKEYDOWN:
  199.         case WM_SYSKEYUP:
  200.         case WM_KEYDOWN:
  201.         case WM_KEYUP:
  202.         {
  203.             DWORD dw = GetWindowLong( hWnd, GWL_STYLE ) ;
  204.  
  205.             // Fool DefWindowProc into thinking we do not have
  206.             // a system menu.  Otherwise it will try to
  207.             // pop up it's own.
  208.             // 
  209.             SetWindowLong( hWnd, GWL_STYLE, dw &~WS_SYSMENU ) ;
  210.             lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  211.             SetWindowLong( hWnd, GWL_STYLE, dw ) ;
  212.             return lRet ;
  213.         }
  214.         break ;
  215.  
  216.         case WM_GETMINMAXINFO:
  217.         {
  218.             nCapSize = GETCAPTIONSIZE( hWnd ) ;
  219.             if (HASCAPTION( hWnd ) && TestWinStyle( hWnd, WS_THICKFRAME ))
  220.             {
  221.                 LPPOINT lppt = (LPPOINT)lParam ;
  222.                 RECT    rcMenu ;
  223.                 RECT    rcMin ;
  224.                 RECT    rcMax ;
  225.                 int     nX ;
  226.                 int     cx, cy ;    // window frame/border width
  227.  
  228.                 if (TestWinStyle( hWnd, WS_THICKFRAME ))
  229.                 {
  230.                     cx = GetSystemMetrics( SM_CXFRAME ) ;
  231.                     cy = GetSystemMetrics( SM_CYFRAME ) ;
  232.                 }
  233.                 else
  234.                     if (TestWinStyle(hWnd, WS_BORDER ))
  235.                     {
  236.                         cx = GetSystemMetrics( SM_CXBORDER ) ;
  237.                         cy = GetSystemMetrics( SM_CYBORDER ) ;
  238.                     }
  239.                                 
  240.                 GetIconRect( hWnd, &rcMenu ) ;
  241.                 GetMinButtonRect( hWnd, &rcMin ) ;
  242.                 GetMaxButtonRect( hWnd, &rcMax ) ;
  243.                 nX = (rcMenu.right-rcMenu.left) + 
  244.                     (rcMin.right-rcMin.left) +
  245.                     (rcMin.right-rcMin.left) ;
  246.  
  247.  
  248.                 if (TestWinStyle( hWnd, IBS_VERTCAPTION ) )
  249.                 {
  250.                     lppt[3].x = nCapSize + cx * 2 - 1 ;
  251.                     lppt[3].y = nX + (2* nCapSize) ;
  252.                 }
  253.                 else
  254.                 {
  255.                     lppt[3].x = nX + (2* nCapSize) ;
  256.                     lppt[3].y = nCapSize + cy * 2 - 1 ;
  257.                 }
  258.             }
  259.             return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  260.         }
  261.         break ;
  262.  
  263.         case WM_COMMAND:
  264.             // The menu that is poped up for the system menu with
  265.             // TrackPopupMenu() sends it's notifications as WM_COMMAND
  266.             // messages.  We need to translate these into
  267.             // WM_SYSCOMMAND messages.  All standard WM_SYSCOMMAND
  268.             // ids are greater than 0xF000.
  269.             //
  270.             // This could be a possible cause of confusion if the
  271.             // itsybitsy window had children that used SC_MOVE or SC_CLOSE
  272.             // as their IDs.  Take note and be careful.
  273.             //
  274.             // Also, because ibDefWindowProc looks at WM_COMMAND messages,
  275.             // you will need to be careful to call ibDefWindowProc() for
  276.             // any wm_command messages that you would normally ignore.
  277.             // Otherwise the system menu won't work.
  278.             //
  279.             if (wParam >= 0xF000)
  280.                 // Call PostMessage() here instead of SendMessage!
  281.                 // Here's why:
  282.                 //      Our menu was created by TrackPopupMenu().  TPM() does
  283.                 //      not return until after the menu has been destroyed 
  284.                 //      (and thus the command associated with the menu selection
  285.                 //      sent).  Therefore when we get here, we are still
  286.                 //      *inside* TPM().  If we Send WM_SYSCOMMAND, SC_CLOSE
  287.                 //      to the window, the window will be destroyed before
  288.                 //      TPM() returns to our code within DoMenu() below.  Wel...
  289.                 //      We do stuff with the window handle after DoMenu()
  290.                 //      returns (namely GetProp()).  Since the window has
  291.                 //      been destroyed,this is bad.  
  292.                 PostMessage( hWnd, WM_SYSCOMMAND, wParam, lParam ) ;
  293.  
  294.         return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  295.  
  296.         /////////////////////////////////////////////////////////////////////
  297.         // Non-client area messages.  These are used to allow the
  298.         // minature caption bar to be handled correctly.
  299.         //
  300.         case WM_NCCREATE:
  301.         {
  302.             DWORD dwStyle ;
  303.  
  304.             // CAPTIONXY is a macro that calls GetSystemMetrics.
  305.             // nCapSize is a global variable.
  306.             //
  307.             SETCAPTIONSIZE( hWnd, CAPTIONXY ) ;
  308.  
  309.             // Set our flag that tells us whether the system menu was
  310.             // 'just up'.
  311.             SETMENUWASUPFLAG( hWnd, FALSE ) ;
  312.  
  313.             // Are we in 3.1?  If so we have some neat features
  314.             // we can use like rotated TrueType fonts.
  315.             //
  316.             fWin31 = (BOOL)(LOWORD( GetVersion() ) >= 0x030A) ;
  317.  
  318.             // If IBS_????CAPTION was specified and the WS_DLGFRAME (or
  319.             // WS_DLGFRAME 'cause it == WS_CAPTION | WS_BORDER)
  320.             // was specified the creator made a mistake.  Things get really
  321.             // ugly if DefWindowProc sees WS_DLGFRAME, so we strip
  322.             // the WS_DLGFRAME part off!
  323.             //
  324.             dwStyle = GetWindowLong( hWnd, GWL_STYLE ) ;
  325.             if ((dwStyle & IBS_VERTCAPTION || dwStyle & IBS_HORZCAPTION) &&
  326.                  dwStyle & WS_DLGFRAME)
  327.             {
  328.                 dwStyle &= (DWORD)~WS_DLGFRAME ;
  329.                 SetWindowLong( hWnd, GWL_STYLE, dwStyle ) ;
  330.             }
  331.         }
  332.         return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  333.  
  334.         case WM_NCDESTROY:
  335.             // We store the caption size in a window prop. so we
  336.             // must remove prop.
  337.             //
  338.             FREECAPTIONSIZE( hWnd ) ;
  339.             FREEMENUWASUPFLAG( hWnd ) ;
  340.         return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  341.  
  342.         case WM_NCCALCSIZE:
  343.             // This is sent when the window manager wants to find out
  344.             // how big our client area is to be.  If we have a mini-caption
  345.             // then we trap this message and calculate the cleint area rect,
  346.             // which is the client area rect calculated by DefWindowProc()
  347.             // minus the width/height of the mini-caption bar
  348.             //
  349.             lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  350.             if (!IsIconic( hWnd ) && HASCAPTION( hWnd ))
  351.             {
  352.                 nCapSize = GETCAPTIONSIZE( hWnd ) ;
  353.  
  354.                 if (TestWinStyle( hWnd, IBS_VERTCAPTION ) )
  355.                     ((LPRECT)lParam)->left += nCapSize ;
  356.                 else
  357.                     ((LPRECT)lParam)->top += nCapSize ;
  358.             }
  359.         return lRet ;
  360.  
  361.         case WM_NCHITTEST:
  362.             // This message is sent whenever the mouse moves over us.
  363.             // We will depend on DefWindowProc for everything unless
  364.             // there is a mini-caption, in which case we will
  365.             // return HTCAPTION or HTSYSMENU.  When the user clicks
  366.             // or double clicks, NC_LBUTTON/ message are sent with
  367.             // wParam equal to what we return here.
  368.             // This means that this is an ideal place to figure out
  369.             // where we are!
  370.             //
  371.             // let defwindowproc handle the standard borders etc...
  372.             //
  373.             lRet = DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  374.             if (!IsIconic( hWnd ) && HASCAPTION( hWnd ) && lRet == HTNOWHERE)
  375.             {
  376.                 RECT  rc ;
  377.                 RECT  rcMenu ;
  378.                 RECT  rcMinButton ;
  379.                 RECT  rcMaxButton ;
  380.                 POINT pt ;
  381.  
  382.                 nCapSize = GETCAPTIONSIZE( hWnd ) ;
  383.  
  384.                 // if DefWindowProc returned HTCAPTION then we have to
  385.                 // refine the area and return HTSYSMENU if appropriate
  386.                 //
  387.                 pt.x = LOWORD( lParam ) ;
  388.                 pt.y = HIWORD( lParam ) ;
  389.  
  390.                 GetCaptionRect( hWnd, &rc ) ;  // window coords
  391.                 if (PtInRect( &rc, pt ))
  392.                 {
  393.                      lRet = HTCAPTION ;
  394.  
  395.                      // rely on the fact that Get???Rect() return an invalid 
  396.                      // (empty) rectangle if the menu/buttons don't exist
  397.                      //
  398.                      GetIconRect( hWnd, &rcMenu ) ;
  399.                      GetMinButtonRect( hWnd, &rcMinButton ) ;
  400.                      GetMaxButtonRect( hWnd, &rcMaxButton ) ;
  401.      
  402.                      if (PtInRect( &rcMenu, pt ))
  403.                           lRet = HTSYSMENU ;
  404.  
  405.                      if (PtInRect( &rcMinButton, pt ))
  406.                           lRet = HTMINBUTTON ;
  407.                      else
  408.                           if (PtInRect( &rcMaxButton, pt ))
  409.                                 lRet = HTMAXBUTTON ;
  410.                 }
  411.             }
  412.             if (lRet != HTSYSMENU)
  413.                 SETMENUWASUPFLAG( hWnd, FALSE ) ;
  414.         return lRet ;
  415.  
  416.         case WM_NCLBUTTONDBLCLK:
  417.             if (!IsIconic( hWnd ) && HASCAPTION( hWnd ) && wParam == HTSYSMENU)
  418.             {
  419.                 SendMessage( hWnd, WM_CLOSE, 0, 0L ) ;
  420.                 break ;
  421.             }
  422.         return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  423.  
  424.         case WM_NCLBUTTONDOWN:
  425.         {
  426.             RECT rc ;
  427.             
  428.             // Here's were we handle the system menu, the min and max buttons.
  429.             // If you wanted to change the behavior of the min/max buttons
  430.             // do something like swap tool palettes or something, you 
  431.             // would change the SendMessage() calls below.
  432.             //
  433.             if (IsIconic( hWnd ) || !HASCAPTION( hWnd ))
  434.                  return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  435.  
  436.             switch (wParam)
  437.             {
  438.                 case HTSYSMENU:
  439.                     if (GETMENUWASUPFLAG( hWnd ) == FALSE && DoMenu( hWnd ))
  440.                         SETMENUWASUPFLAG( hWnd, TRUE ) ;
  441.                     else
  442.                         SETMENUWASUPFLAG( hWnd, FALSE ) ;
  443.                 break ;
  444.                 
  445.                 case HTMINBUTTON:
  446.                     GetMinButtonRect( hWnd, &rc ) ;
  447.                     // Note that DepressMinMaxButton() goes into
  448.                     // a PeekMessage() loop waiting for the mouse
  449.                     // to come back up.
  450.                     //
  451.                     if (DepressMinMaxButton( hWnd, wParam, &rc ))
  452.                         SendMessage( hWnd, WM_SYSCOMMAND, SC_MINIMIZE, lParam ) ;
  453.                 break ;
  454.                 
  455.                 case HTMAXBUTTON:
  456.                     GetMaxButtonRect( hWnd, &rc ) ;
  457.                     // Note that DepressMinMaxButton() goes into
  458.                     // a PeekMessage() loop waiting for the mouse
  459.                     // to come back up.
  460.                     //
  461.                     if (DepressMinMaxButton( hWnd, wParam, &rc ))
  462.                     {
  463.                         if (IsZoomed(hWnd))
  464.                             SendMessage( hWnd, WM_SYSCOMMAND, SC_RESTORE, lParam ) ;
  465.                         else
  466.                             SendMessage( hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, lParam ) ;
  467.                     }
  468.                 break ;
  469.                 
  470.                 default:
  471.                     return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  472.             }
  473.         }
  474.         break ;
  475.  
  476.         case WM_NCPAINT:
  477.         case WM_NCACTIVATE:
  478.             if (IsIconic( hWnd ))
  479.                 return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  480.  
  481.             // Paint the non-client area here.  We will call DefWindowProc
  482.             // after we are done so it can paint the boarders and so
  483.             // forth...
  484.             //
  485.             if (HASCAPTION( hWnd ))
  486.             {
  487.                 RECT  rcCap ;
  488.                 RECT  rc ;
  489.                 HDC    hDC = GetWindowDC( hWnd ) ;
  490.                 BOOL  fActive ;
  491.  
  492.                 GetCaptionRect( hWnd, &rcCap ) ;    // Convert to window coords
  493.                 GetWindowRect( hWnd, &rc ) ;
  494.                 OffsetRect( &rcCap, -rc.left, -rc.top ) ;
  495.  
  496.                 if (uiMsg == WM_NCPAINT)
  497.                     fActive = (hWnd == GetActiveWindow()) ;
  498.                 else
  499.                     fActive = wParam ;
  500.  
  501.                 DrawCaption( hDC, hWnd, &rcCap,
  502.                                         TestWinStyle(hWnd, IBS_VERTCAPTION),
  503.                                         TestWinStyle(hWnd, WS_SYSMENU),
  504.                                         TestWinStyle(hWnd, WS_MINIMIZEBOX),
  505.                                         TestWinStyle(hWnd, WS_MAXIMIZEBOX),
  506.                                         fActive ) ;
  507.  
  508.                 ReleaseDC( hWnd, hDC ) ;
  509.             }
  510.         return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  511.  
  512.         default:
  513.             return DefWindowProc( hWnd, uiMsg, wParam, lParam ) ;
  514.     }
  515.  
  516.     return 0L ;
  517.  
  518. } // ibDefWindowProc()
  519.  
  520. // DepressMinMaxButton()
  521. //
  522. // This function is called when the user has pressed either the min or
  523. // max button (i.e. WM_NCLBUTTONDOWN).  We go into a Peekmessage() loop,
  524. // waiting for the mouse to come back up.  This allows us to make the
  525. // button change up/down state like a real button does.
  526. //
  527. // lprc points to the rectangle that describes the button the
  528. // user has clicked on.
  529. //
  530. BOOL NEAR PASCAL DepressMinMaxButton( HWND hWnd, UINT uiHT, LPRECT lprc )
  531. {             
  532.     BOOL    fDepressed = TRUE ;
  533.     MSG     msg ;
  534.                       
  535.     // Draw button in down state
  536.     DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed ) ;
  537.     SetCapture( hWnd ) ;
  538.     
  539.     while (TRUE)
  540.     {
  541.         if (PeekMessage((LPMSG)&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
  542.         {
  543.             switch (msg.message)
  544.             {
  545.                 case WM_LBUTTONUP:
  546.                     if (fDepressed)
  547.                         DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, !fDepressed ) ;
  548.                     ReleaseCapture();
  549.                 return PtInRect( lprc, msg.pt ) ;
  550.                 
  551.                 case WM_MOUSEMOVE:
  552.                     if (PtInRect( lprc, msg.pt ))
  553.                     {
  554.                         if (!fDepressed)
  555.                             DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed = TRUE ) ;
  556.                     }
  557.                     else
  558.                     {
  559.                         if (fDepressed)
  560.                             DrawButton( NULL, hWnd, uiHT == HTMINBUTTON, fDepressed = FALSE ) ;
  561.                     }
  562.                 break;
  563.             }
  564.         }
  565.     }
  566.     
  567. } // DepressMinMaxButton()  
  568.  
  569. //  ibAdjustWindowRect( HWND hWnd, LPRECT lprc )
  570. //
  571. //    Does the same thing as the USER function AdjustWindowRect(),
  572. //    but knows about itsybitsy windows.  AdjustWindowRect() is
  573. //    bogus for stuff like this.
  574. //
  575. VOID FAR PASCAL ibAdjustWindowRect( HWND hWnd, LPRECT lprc )
  576. {
  577.    short    cx = 0, cy = 0 ;
  578.    UINT     nCapSize ;
  579.  
  580.    nCapSize = GETCAPTIONSIZE( hWnd ) ;
  581.  
  582.    // First check Windows's styles, then our own.
  583.    //
  584.    if (TestWinStyle( hWnd, WS_THICKFRAME ))
  585.    {
  586.       cx = GetSystemMetrics( SM_CXFRAME ) ;
  587.       cy = GetSystemMetrics( SM_CYFRAME ) ;
  588.    }
  589.    else
  590.       if (TestWinStyle(hWnd, WS_BORDER ))
  591.       {
  592.          cx = GetSystemMetrics( SM_CXBORDER ) ;
  593.          cy = GetSystemMetrics( SM_CYBORDER ) ;
  594.       }
  595.  
  596.    InflateRect( lprc, cx, cy ) ;
  597.  
  598.    if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
  599.       lprc->left -= nCapSize ;
  600.    else
  601.       if (TestWinStyle( hWnd, IBS_HORZCAPTION ))
  602.             lprc->top -= nCapSize ;
  603.  
  604. } // ibAdjustWindowRect() 
  605.  
  606. // DrawCaption( HDC hDC, HWND hWnd, LPRECT lprc,
  607. //                   BOOL fVert, BOOL fSysMenu, BOOL fActive )
  608. //
  609. //    This function draws an itsy bitsy caption bar with or
  610. //    without system menu to the dc specified by hDC.  The
  611. //    caption is drawn to fit within the lprc RECT and is
  612. //    drawn//withOut/ borders.
  613. //
  614. BOOL NEAR PASCAL DrawCaption( HDC hDC, HWND hWnd, LPRECT lprc,
  615.                               BOOL fVert, BOOL fSysMenu, BOOL fMin, 
  616.                               BOOL fMax, BOOL fActive )
  617. {
  618.     RECT        rc ;
  619.     RECT        rcCap ;
  620.     COLORREF    rgbCaptionBG ;
  621.     COLORREF    rgbText ;
  622.     COLORREF    rgbWindowFrame ;
  623.     HBRUSH      hbrCaption ;
  624.     UINT        ui ;
  625.     UINT        nCapSize ;
  626.     
  627.     nCapSize = GETCAPTIONSIZE( hWnd ) ;
  628.     
  629.     // Get the colors.
  630.     //
  631.     rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ;
  632.     
  633.     // if we have focus use the active caption color
  634.     // otherwise use the inactive caption color
  635.     //
  636.     if (fActive)
  637.     {
  638.         rgbText = GetSysColor( COLOR_CAPTIONTEXT ) ;
  639.         rgbCaptionBG = GetSysColor( COLOR_ACTIVECAPTION ) ;
  640.     }
  641.     else
  642.     {
  643.         if (fWin31)
  644.             rgbText = GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ;
  645.         else
  646.             rgbText = GetSysColor( COLOR_CAPTIONTEXT ) ;
  647.  
  648.         rgbCaptionBG = GetSysColor( COLOR_INACTIVECAPTION )  ;
  649.     }
  650.  
  651.     SetBkMode( hDC, TRANSPARENT ) ;
  652.     SelectObject( hDC, GetStockObject( NULL_BRUSH ) ) ;
  653.     SelectObject( hDC, GetStockObject( NULL_PEN ) ) ;
  654.     
  655.     rcCap = *lprc ;
  656.     
  657.     if (fSysMenu)
  658.     {
  659.         if (fVert)
  660.             rcCap.top += nCapSize ;
  661.         else
  662.             rcCap.left += nCapSize ;
  663.     }
  664.     
  665.     if (fMax)
  666.     {
  667.         if (fVert)
  668.             rcCap.bottom -= nCapSize ;
  669.         else
  670.             rcCap.right -= nCapSize ;
  671.     }
  672.     
  673.     if (fMin)
  674.     {
  675.         if (fVert)
  676.             rcCap.bottom -= nCapSize ;
  677.         else
  678.             rcCap.right -= nCapSize ;
  679.     }
  680.     
  681.     if (fVert)
  682.     {
  683.         rc.left = lprc->right - 1 ;
  684.         rc.right = lprc->right ;
  685.         rc.top = lprc->top ;
  686.         rc.bottom = lprc->bottom ;
  687.     }
  688.     else
  689.     {
  690.         rc.left = lprc->left ;
  691.         rc.right = lprc->right ;
  692.         rc.bottom = lprc->bottom ;
  693.         rc.top = rc.bottom - 1 ;
  694.     }
  695.     
  696.     SetBkColor( hDC, rgbWindowFrame ) ;
  697.     DRAWFASTRECT( hDC, &rc ) ;
  698.  
  699.     hbrCaption = CreateSolidBrush( rgbCaptionBG ) ;
  700.     hbrCaption = SelectObject( hDC, hbrCaption ) ;
  701.     SelectObject( hDC, GetStockObject( NULL_PEN ) ) ;
  702.     if (fVert)
  703.         Rectangle( hDC, rcCap.left, rcCap.top, rcCap.right, rcCap.bottom + 1 ) ;
  704.     else
  705.         Rectangle( hDC, rcCap.left, rcCap.top, rcCap.right+1, rcCap.bottom ) ;
  706.     hbrCaption = SelectObject( hDC, hbrCaption ) ;
  707.     DeleteObject( hbrCaption ) ;
  708.  
  709.     
  710.     // Draw caption text here.  Only do it in 3.1 'cause 3.1 gives
  711.     // us 'small fonts'.
  712.     //
  713.     ui = GetWindowTextLength( hWnd ) ;
  714.     if (fWin31)
  715.     {
  716.         HFONT          hFont ;
  717.         LPSTR          lpsz ;
  718.         LOGFONT        lf ;
  719.         TEXTMETRIC     tm ;
  720.         int            cx ;
  721.         int            cy ;
  722.         SIZE           Size ;
  723.         
  724.         if (lpsz = GlobalAllocPtr( GHND, ui + 2 ))
  725.         {
  726.             UINT    nBkMode ;
  727.  
  728.             GetWindowText( hWnd, lpsz, ui + 1 ) ;
  729.             nBkMode = SetBkMode( hDC, TRANSPARENT ) ;
  730.             rgbText = SetTextColor( hDC, rgbText ) ;
  731.             
  732.             memset( &lf, '\0', sizeof(LOGFONT) ) ;
  733.  
  734.             lf.lfHeight = -(int)(nCapSize - 3) ;
  735.             lf.lfCharSet = ANSI_CHARSET ;
  736.             lf.lfQuality = DEFAULT_QUALITY ;
  737.             lf.lfClipPrecision = CLIP_LH_ANGLES | CLIP_STROKE_PRECIS ;
  738.             if (nCapSize >= 20)
  739.             {
  740.                 lf.lfWeight = FW_BOLD ;
  741.             }
  742.             
  743.             if (fVert)
  744.             {
  745.                 // Can only rotate true type fonts (well, ok, we could
  746.                 // try and use "modern").
  747.                 lstrcpy( lf.lfFaceName, "Arial" ) ;
  748.                 lf.lfPitchAndFamily = FF_SWISS | 0x04;
  749.                 lf.lfEscapement = 900 ;
  750.  
  751.                 // Note:  The Win 3.1 documentation for CreateFont() say's
  752.                 // that the lfOrientation member is ignored.  It appears,
  753.                 // that on Windows 16 3.1 this is true, but when running
  754.                 // as a 16 bit WinApp on WindowsNT 3.1 the lfOrientation
  755.                 // must be set or the text does not rotate!
  756.                 //
  757.                 lf.lfOrientation = 900 ;
  758.                 
  759.                 hFont = CreateFontIndirect( &lf ) ;
  760.                 hFont = SelectObject( hDC, hFont ) ;
  761.                 
  762.                 GetTextExtentPoint( hDC, lpsz, ui, &Size ) ;
  763.                 cx = rcCap.bottom - ((rcCap.bottom - rcCap.top - Size.cx) / 2) ;
  764.                 cy = rcCap.left - 1 + ((rcCap.right - rcCap.left - Size.cy) / 2) ;
  765.  
  766.                 // Make sure we got a rotatable font back.
  767.                 //
  768.                 GetTextMetrics( hDC, &tm ) ;
  769.                 if (tm.tmPitchAndFamily & TMPF_VECTOR     ||
  770.                     tm.tmPitchAndFamily & TMPF_TRUETYPE)
  771.                 {
  772.                     ExtTextOut( hDC,
  773.                                cy,
  774.                                min( cx, rcCap.bottom),
  775.                                ETO_CLIPPED, &rcCap,
  776.                                lpsz, ui, NULL ) ;
  777.                 }
  778.                 
  779.                 hFont = SelectObject( hDC, hFont ) ;
  780.                 DeleteObject( hFont ) ;
  781.             }
  782.             else
  783.             {
  784.                 // Use small fonts always for the horizontal. Cause it looks
  785.                 // more like "System" than Arial.
  786.                 //
  787.                 lf.lfPitchAndFamily = FF_SWISS ;
  788.                 
  789.                 hFont = CreateFontIndirect( &lf ) ;
  790.                 hFont = SelectObject( hDC, hFont ) ;
  791.                 
  792.                 GetTextExtentPoint( hDC, lpsz, ui, &Size ) ;
  793.                 cx = rcCap.left + ((rcCap.right - rcCap.left - Size.cx) / 2) ;
  794.                 cy = rcCap.top + ((rcCap.bottom - rcCap.top - Size.cy) / 2) ;
  795.                 
  796.                 // Figger out how big the string is
  797.                 //
  798.                 ExtTextOut( hDC,
  799.                             max( cx, rcCap.left ),
  800.                             cy,
  801.                             ETO_CLIPPED, &rcCap,
  802.                             lpsz, ui, NULL ) ;
  803.                 
  804.                 hFont = SelectObject( hDC, hFont ) ;
  805.                 DeleteObject( hFont ) ;
  806.             }
  807.  
  808.             // Unsetup the DC
  809.             //
  810.             rgbText = SetTextColor( hDC, rgbText ) ;
  811.             SetBkMode( hDC, nBkMode ) ;
  812.             
  813.             GlobalFreePtr( lpsz ) ;
  814.         }
  815.     }
  816.     
  817.     if (fSysMenu)
  818.         DrawSysMenu( hDC, hWnd, FALSE ) ;
  819.     
  820.     if (fMin)
  821.         DrawButton( hDC, hWnd, TRUE, FALSE ) ;
  822.  
  823.     if (fMax)
  824.         DrawButton( hDC, hWnd, FALSE, FALSE ) ;
  825.     
  826.     return TRUE ;
  827.     
  828. } // DrawCaption()
  829.  
  830.  
  831. // DrawSysMenu( HDC hDC, hWnd, BOOL fInvert )
  832. //
  833. // Draws the little system menu icon.
  834. //
  835. VOID NEAR PASCAL DrawSysMenu( HDC hDC, HWND hWnd, BOOL fInvert )
  836. {
  837.    RECT         rcIcon ;
  838.    RECT         rcTemp ;
  839.    RECT         rc ;
  840.    COLORREF     rgbIconFace ;
  841.    COLORREF     rgbWindowFrame ;
  842.    BOOL         fDC ;
  843.    UINT         nCapSize ;
  844.  
  845.    nCapSize = GETCAPTIONSIZE( hWnd ) ;
  846.  
  847.    if (!hDC)
  848.    {
  849.       fDC = TRUE ;
  850.       hDC = GetWindowDC( hWnd ) ;
  851.    }
  852.    else
  853.       fDC = FALSE ;
  854.  
  855.    if (hDC)
  856.    {
  857.       rgbIconFace    = GetNearestColor( hDC, RGBLTGRAY ) ;
  858.       rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ;
  859.  
  860.       GetIconRect( hWnd, &rcIcon ) ;
  861.       GetWindowRect( hWnd, &rc ) ;
  862.    
  863.       OffsetRect( &rcIcon, -rc.left, -rc.top ) ;
  864.  
  865.       rcTemp = rcIcon ;
  866.  
  867.       if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
  868.       {
  869.          rc = rcIcon ;      // separator line
  870.          rc.top = ++rc.bottom - 1 ;
  871.       }
  872.       else
  873.       {
  874.          rc = rcIcon ;      // separator line
  875.          rc.left = ++rc.right - 1 ;
  876.       }
  877.  
  878.       // Fill
  879.       SetBkColor( hDC, rgbIconFace ) ;
  880.       DRAWFASTRECT( hDC, &rcTemp ) ;
  881.  
  882.       // Draw separator line
  883.       SetBkColor( hDC, rgbWindowFrame ) ;
  884.       DRAWFASTRECT( hDC, &rc ) ;
  885.  
  886.       if (nCapSize > 4)
  887.       {
  888.           // Draw little doo-hickey
  889.           rcTemp.top = rcIcon.top + ((nCapSize-1) / 2) ;
  890.           rcTemp.bottom = rcTemp.top + 3 ;
  891.           rcTemp.left  = rcTemp.left + 3 ; 
  892.           rcTemp.right = rcTemp.right - 1 ;
  893.     
  894.           SetBkColor( hDC, RGBGRAY ) ;
  895.           DRAWFASTRECT( hDC, &rcTemp ) ;
  896.     
  897.           rc = rcTemp ;
  898.           OffsetRect( &rc, -1, -1 ) ;
  899.           SetBkColor( hDC, RGBBLACK ) ;
  900.           DRAWFASTRECT( hDC, &rc ) ;
  901.     
  902.           InflateRect( &rc, -1, -1 ) ;
  903.           SetBkColor( hDC, RGBWHITE ) ;
  904.           DRAWFASTRECT( hDC, &rc ) ;
  905.       }
  906.  
  907.       if (fInvert)
  908.          InvertRect( hDC, &rcIcon ) ;
  909.  
  910.       if (fDC)
  911.          ReleaseDC( hWnd, hDC ) ;
  912.    }
  913.  
  914. } // DrawSysMenu()
  915.  
  916. // DoMenu( HWND hWnd )
  917. //
  918. //    Pops up the system menu.
  919. //
  920. BOOL NEAR PASCAL DoMenu( HWND hWnd )
  921. {
  922.     HDC    hDC ;
  923.     RECT   rcIcon ;
  924.     RECT   rc ;
  925.     POINT  pt ;
  926.     HMENU  hMenu ;
  927.     DWORD  dw ;
  928.  
  929.     if (!TestWinStyle(hWnd, WS_SYSMENU))
  930.         return FALSE ;
  931.     
  932.     if (hDC = GetWindowDC( hWnd ))
  933.     {
  934.         // Invert the icon
  935.         //
  936.         DrawSysMenu( hDC, hWnd, TRUE ) ;
  937.         
  938.         // Pop up the menu
  939.         //
  940.         if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
  941.         {
  942.             pt.x = -1 ;
  943.             pt.y = 0 ;
  944.         }
  945.         else
  946.         {
  947.             pt.x = 0 ;
  948.             pt.y = -1 ;
  949.         }
  950.         
  951.         GetIconRect( hWnd, &rcIcon ) ;
  952.         GetWindowRect( hWnd, &rc ) ;
  953.         OffsetRect( &rcIcon, -rc.left, -rc.top ) ;
  954.         
  955.         ClientToScreen( hWnd, &pt ) ;
  956.         ClientToScreen( hWnd, (LPPOINT)&rc.right ) ;
  957.         
  958.         dw = GetWindowLong( hWnd, GWL_STYLE ) ;
  959.         SetWindowLong( hWnd, GWL_STYLE, dw | WS_SYSMENU ) ;
  960.         
  961.         hMenu = GetSystemMenu( hWnd, FALSE ) ;
  962.         SetupSystemMenu( hWnd, hMenu ) ;
  963.         
  964.         SetWindowLong( hWnd, GWL_STYLE, dw ) ;
  965.  
  966.         TrackPopupMenu( hMenu, 0, //TPM_LEFTALIGN,
  967.                     pt.x,
  968.                     pt.y,
  969.                     0,
  970.                     hWnd,
  971.                     &rc ) ;
  972.     
  973.         DrawSysMenu( hDC, hWnd, FALSE ) ;
  974.         ReleaseDC( hWnd, hDC ) ;
  975.     }
  976.     return TRUE ;
  977.  
  978. } // DoMenu()
  979.  
  980. // SetupSystemMenu( HWND hWnd, HMENU hMenu )
  981. //
  982. //    Enables/Disables the appropriate menu items on the
  983. //    menu passed for the window passed.
  984. //
  985. void NEAR PASCAL SetupSystemMenu( HWND hWnd, HMENU hMenu )
  986. {
  987.    UINT     wMove ;        
  988.    UINT     wSize ;
  989.    UINT     wMinBox ;
  990.    UINT     wMaxBox ;
  991.    UINT     wRestore ;
  992.  
  993.    // Assume all should be grayed.
  994.    //
  995.    wSize = wMove = wMinBox = wMaxBox = wRestore = MF_GRAYED ;
  996.  
  997.    if (TestWinStyle( hWnd, WS_MAXIMIZEBOX ) || IsIconic( hWnd ))
  998.       wMaxBox = MF_ENABLED ;
  999.  
  1000.    if (TestWinStyle( hWnd, WS_MINIMIZEBOX ))
  1001.       wMinBox = MF_ENABLED ;
  1002.  
  1003.    if (IsZoomed( hWnd ))
  1004.       wRestore = MF_ENABLED ;
  1005.  
  1006.    if (TestWinStyle( hWnd, WS_THICKFRAME ) &&
  1007.        !(IsIconic( hWnd ) || IsZoomed( hWnd )))
  1008.       wSize = MF_ENABLED ;
  1009.  
  1010.    if (!IsZoomed( hWnd ) &&
  1011.        !IsIconic( hWnd ) &&
  1012.        TestWinStyle( hWnd, WS_CAPTION ) )
  1013.       wMove = MF_ENABLED ;
  1014.  
  1015.    EnableMenuItem( hMenu, SC_MOVE,     wMove ) ;
  1016.    EnableMenuItem( hMenu, SC_SIZE,     wSize ) ;
  1017.    EnableMenuItem( hMenu, SC_MINIMIZE, wMinBox ) ;
  1018.    EnableMenuItem( hMenu, SC_MAXIMIZE, wMaxBox ) ;
  1019.    EnableMenuItem( hMenu, SC_RESTORE,  wRestore ) ;
  1020.                         
  1021. } // SetupSystemMenu()
  1022.  
  1023. // GetCaptionRect( HWND hWnd, LPRECT lprc )
  1024. //
  1025. //    calcluales the rectangle of the mini-caption in screen coords.
  1026. //
  1027. BOOL NEAR PASCAL GetCaptionRect( HWND hWnd, LPRECT lprc )
  1028. {
  1029.    UINT     nCapSize ;
  1030.  
  1031.    nCapSize = GETCAPTIONSIZE( hWnd ) ;
  1032.  
  1033.    if (!HASCAPTION( hWnd ))
  1034.    {
  1035.       SetRectEmpty( lprc ) ;
  1036.       return FALSE ;
  1037.    }
  1038.  
  1039.    GetWindowRect( hWnd, lprc ) ;
  1040.  
  1041.    // the window might have other non-client components like
  1042.    // borders 
  1043.    //
  1044.    if (TestWinStyle( hWnd, WS_THICKFRAME ))
  1045.    {
  1046.       lprc->left += GetSystemMetrics( SM_CXFRAME ) ;
  1047.       lprc->top  += GetSystemMetrics( SM_CYFRAME ) ;
  1048.       lprc->right -= GetSystemMetrics( SM_CXFRAME ) ;
  1049.       lprc->bottom -= GetSystemMetrics( SM_CYFRAME ) ;
  1050.    }
  1051.    else
  1052.       if (TestWinStyle( hWnd, WS_BORDER ))
  1053.       {   
  1054.          lprc->left += GetSystemMetrics( SM_CXBORDER ) ;
  1055.          lprc->top  += GetSystemMetrics( SM_CYBORDER ) ;
  1056.          lprc->right -= GetSystemMetrics( SM_CXBORDER ) ;
  1057.          lprc->bottom -= GetSystemMetrics( SM_CYBORDER ) ;
  1058.       }
  1059.  
  1060.    if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
  1061.       lprc->right = lprc->left + nCapSize ;
  1062.    else
  1063.       lprc->bottom = lprc->top + nCapSize ;
  1064.  
  1065.    return TRUE ;
  1066. } // GetCaptionRect()
  1067.  
  1068. // GetIconRect( HWND hWnd, LPRECT lprc )
  1069. //
  1070. //    Calculates the rect of the icon in screen coordinates.
  1071. //
  1072. BOOL NEAR PASCAL GetIconRect( HWND hWnd, LPRECT lprc )
  1073. {
  1074.     UINT    nCapSize ;
  1075.     BOOL    fMenu, fVert ;
  1076.  
  1077.     fMenu= TestWinStyle( hWnd, WS_SYSMENU ) ;
  1078.     fVert = TestWinStyle( hWnd, IBS_VERTCAPTION ) ;
  1079.  
  1080.     if (!GetCaptionRect( hWnd, lprc ))   // window coords
  1081.       return FALSE ;
  1082.  
  1083.     if (!fMenu)
  1084.     {
  1085.         SetRectEmpty( lprc ) ;
  1086.         return FALSE ;
  1087.     }
  1088.  
  1089.     nCapSize = GETCAPTIONSIZE( hWnd ) ;
  1090.  
  1091.     if (fVert)
  1092.         lprc->bottom = lprc->top + nCapSize ;
  1093.     else
  1094.         lprc->right = lprc->left + nCapSize ;
  1095.     
  1096.     lprc->bottom-- ;
  1097.     lprc->right-- ;
  1098.     
  1099.     return TRUE ;
  1100.  
  1101. } // GetIconRect()
  1102.  
  1103. // GetMinButtonRect()
  1104. //
  1105. // Calculates the rect of the minimize button in screen
  1106. // coordinates.
  1107. //
  1108. // For horizontal captions, we have the following situation ('Y' is minimize
  1109. // and '^' is maximize or restore):
  1110. //
  1111. //   +---------------------------------+
  1112. //   | - |                     | Y | ^ |
  1113. //   +---------------------------------+
  1114. //   |                         |.......| <-- This is the width (nSize)
  1115. //
  1116. // For vertical captions, we have the following:
  1117. //
  1118. //   |  |
  1119. //   |  |
  1120. //   |  |
  1121. //   |  |
  1122. //   |  |
  1123. //   |  |
  1124. //   |--|--
  1125. //   | Y| .
  1126. //   |--| . <-- This is the height of the rectangle (nSize)
  1127. //   | ^| .
  1128. //   +--+--
  1129. //
  1130. // In order to figure out where the minimize button goes, we first need
  1131. // to know if there is a maximize button.  If so, use GetMaxButtonRect()
  1132. // to place...
  1133. //
  1134. BOOL NEAR PASCAL GetMinButtonRect( HWND hWnd, LPRECT lprc )
  1135. {
  1136.     if (!TestWinStyle( hWnd, WS_MINIMIZEBOX )) 
  1137.     {
  1138.         SetRectEmpty( lprc ) ;
  1139.         return FALSE ;
  1140.     }
  1141.  
  1142.     // The minimize button can be in either position 1 or 2.  If there
  1143.     // is a maximize button, it's in position 2.
  1144.     //
  1145.     if (TestWinStyle( hWnd, WS_MAXIMIZEBOX ))
  1146.         return GetButtonRect( hWnd, 2, lprc ) ;
  1147.     else
  1148.         return GetButtonRect( hWnd, 1, lprc ) ;
  1149. }
  1150.  
  1151. // GetMaxButtonRect()
  1152. //
  1153. // Calculates the rect of the maximize button in screen
  1154. // coordinates.
  1155. //
  1156. // The maximize button, if present, is always to the far right
  1157. // or bottom.
  1158. //
  1159. BOOL NEAR PASCAL GetMaxButtonRect( HWND hWnd, LPRECT lprc )
  1160. {
  1161.     //The maximize button can only be in position 1.
  1162.     //
  1163.     if (TestWinStyle( hWnd, WS_MAXIMIZEBOX ))
  1164.         return GetButtonRect( hWnd, 1, lprc ) ;
  1165.     else
  1166.     {
  1167.         SetRectEmpty( lprc ) ;
  1168.         return FALSE ;
  1169.     }
  1170. }
  1171.  
  1172. // Get the rect where a button would go. 
  1173. // 
  1174. // This function does not care if it's a min or max, just whether
  1175. // it is the first from the right/bottom or second from the right/bottom
  1176. // and so on..
  1177. //
  1178. BOOL NEAR PASCAL GetButtonRect( HWND hWnd, UINT nPos, LPRECT lprc )
  1179. {
  1180.     UINT    nSize = 0 ;
  1181.  
  1182.     if (!GetCaptionRect( hWnd, lprc ))   //window coords
  1183.       return FALSE ;
  1184.  
  1185.     nSize = GETCAPTIONSIZE( hWnd ) ;
  1186.  
  1187.     if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
  1188.     {
  1189.         lprc->bottom -= nSize * (nPos-1) ;
  1190.         lprc->top = lprc->bottom - nSize + 1 ;
  1191.     }
  1192.     else
  1193.     {
  1194.         lprc->right -= nSize * (nPos-1) ;
  1195.         lprc->left = lprc->right - nSize + 1 ;
  1196.     }
  1197.  
  1198.     return TRUE ;
  1199. } // GetButtonRect()
  1200.  
  1201. // DrawButton( HDC hDC, HWND hWnd, BOOL fMin, BOOL fDepressed )
  1202. // 
  1203. // Draws either the min, max, or restore buttons. If fMin is FALSE then it
  1204. // will draw either the Max or Restore button.  If fDepressed is TRUE it will
  1205. // draw the button in a down state.
  1206. //
  1207. VOID NEAR PASCAL DrawButton( HDC hDC, HWND hWnd, BOOL fMin, BOOL fDepressed)
  1208. {
  1209.     RECT            rcButton ;
  1210.     RECT            rc ;
  1211.     COLORREF        rgbWindowFrame ;
  1212.     BOOL            fDC ;
  1213.     UINT            nCapSize ;
  1214.     UINT            nOffset ;
  1215.     int             n ;
  1216.  
  1217.     nCapSize = GETCAPTIONSIZE( hWnd ) ;
  1218.  
  1219.     // If you look at the standard Windows' min/max buttons, you will notice
  1220.     // that they have two pixels of 'shadow' to the bottom and right.  Since
  1221.     // our buttons can be really, really small, we only want one pixel of 
  1222.     // shadow when they are small.  I arbitrarily decided that if the 
  1223.     // caption size is greater than or equal to 20 we will use two
  1224.     // pixels.  That's what this THREASHOLD stuff does.
  1225.     //
  1226.     #define THRESHOLD   20
  1227.     nOffset = (nCapSize >= THRESHOLD) ? 2 : 1 ;    
  1228.  
  1229.     if (!hDC)
  1230.     {
  1231.         fDC = TRUE ;
  1232.         hDC = GetWindowDC( hWnd ) ;
  1233.     }
  1234.     else
  1235.         fDC = FALSE ;
  1236.     
  1237.     if (hDC)
  1238.     {
  1239.         rgbWindowFrame = GetSysColor( COLOR_WINDOWFRAME ) ;
  1240.         
  1241.         if (fMin)
  1242.             GetMinButtonRect( hWnd, &rcButton ) ;
  1243.         else
  1244.             GetMaxButtonRect( hWnd, &rcButton ) ;
  1245.         
  1246.         GetWindowRect( hWnd, &rc ) ;
  1247.         OffsetRect( &rcButton, -rc.left, -rc.top ) ;
  1248.         
  1249.         rc = rcButton ;
  1250.         if (TestWinStyle( hWnd, IBS_VERTCAPTION ))
  1251.         {
  1252.             rc = rcButton ;     //separator line
  1253.             rc.bottom = --rc.top + 1 ;
  1254.             rcButton.right-- ;
  1255.         }
  1256.         else
  1257.         {
  1258.             rc = rcButton ;     //separator line
  1259.             rc.right = --rc.left + 1 ;
  1260.             rcButton.bottom-- ;
  1261.         }
  1262.         
  1263.         //Draw separator line
  1264.         SetBkColor( hDC, rgbWindowFrame ) ;
  1265.         DRAWFASTRECT( hDC, &rc ) ;
  1266.         
  1267.         //Fill
  1268.         SetBkColor( hDC, RGBLTGRAY ) ;
  1269.         DRAWFASTRECT( hDC, &rcButton ) ;
  1270.         
  1271.         if (!fDepressed)
  1272.         {
  1273.             //The normal min/max buttons have one pixel on the top and left
  1274.             //sides for the highlight, and two pixels on the bottom and
  1275.             //right side for the shadow.
  1276.             //
  1277.             //When our caption is 'small' we only use one pixel on all
  1278.             //sides.
  1279.             //
  1280.             SetBkColor( hDC, RGBWHITE ) ;
  1281.             //Draw left side
  1282.             rc = rcButton ;
  1283.             rc.right = rc.left + 1 ;
  1284.             DRAWFASTRECT( hDC, &rc ) ;
  1285.  
  1286.             //Draw Top
  1287.             rc = rcButton ;
  1288.             rc.bottom = rc.top + 1 ;
  1289.             DRAWFASTRECT( hDC, &rc ) ;
  1290.  
  1291.             SetBkColor( hDC, RGBGRAY ) ;
  1292.             //Draw right side
  1293.             rc = rcButton ;
  1294.             rc.left = rc.right - 1 ;
  1295.             DRAWFASTRECT( hDC, &rc ) ;
  1296.             if (nCapSize > THRESHOLD)
  1297.             {
  1298.                 rc.left-- ;
  1299.                 rc.top++ ;
  1300.                 DRAWFASTRECT( hDC, &rc ) ;
  1301.             }
  1302.  
  1303.             //Draw bottom
  1304.             rc = rcButton ;
  1305.             rc.top = rc.bottom - 1 ;
  1306.             DRAWFASTRECT( hDC, &rc ) ;
  1307.             if (nCapSize > THRESHOLD)
  1308.             {
  1309.                 rc.top-- ;
  1310.                 rc.left++ ;
  1311.                 DRAWFASTRECT( hDC, &rc ) ;
  1312.             }
  1313.  
  1314.             rcButton.left++ ;
  1315.             rcButton.top++ ;
  1316.             rcButton.right -= nOffset ;
  1317.             rcButton.bottom -= nOffset ;
  1318.         }
  1319.         else
  1320.         {
  1321.             //Draw depressed state
  1322.  
  1323.             SetBkColor( hDC, RGBGRAY ) ;
  1324.             //Draw left side
  1325.             rc = rcButton ;
  1326.             rc.right = rc.left + nOffset ;
  1327.             DRAWFASTRECT( hDC, &rc ) ;
  1328.  
  1329.             //Draw Top
  1330.             rc = rcButton ;
  1331.             rc.bottom = rc.top + nOffset ;
  1332.             DRAWFASTRECT( hDC, &rc ) ;
  1333.  
  1334.             rcButton.left += 2 * nOffset ;
  1335.             rcButton.top += 2 * nOffset ;
  1336.         }
  1337.  
  1338.         // Now draw the arrows.  We do not want the
  1339.         // arrows to grow too large when we have a bigger than
  1340.         // normal caption, so we restrict their size.
  1341.         //
  1342.         // rcButton now represents where we can place our
  1343.         // arrows.  
  1344.         //
  1345.         // The maximum size of our arrows (i.e. the width of rcButton)
  1346.         // has been empirically determined to be SM_CYCAPTION / 2
  1347.         //
  1348.         n = ((GetSystemMetrics( SM_CYCAPTION )) / 2) - 
  1349.             (rcButton.right - rcButton.left) ;
  1350.         if (n < 1)
  1351.             InflateRect( &rcButton, n/2-1, n/2-1 ) ;
  1352.  
  1353.         if (fMin)
  1354.             DrawArrow( hDC, &rcButton, ARROW_DOWN ) ;
  1355.         else 
  1356.             if (IsZoomed( hWnd ))
  1357.             {
  1358.                 DrawArrow( hDC, &rcButton, ARROW_RESTORE ) ;
  1359.             }
  1360.             else
  1361.                 DrawArrow( hDC, &rcButton, ARROW_UP ) ;
  1362.         
  1363.         if (fDC)
  1364.             ReleaseDC( hWnd, hDC ) ;
  1365.     }
  1366.  
  1367. } // DrawButton()
  1368.  
  1369.  
  1370. // DrawArrow
  1371. //
  1372. // Draws either a up or down arrow.  The arrow is bound by the rectangle
  1373. //
  1374. VOID NEAR PASCAL DrawArrow( HDC hdc, LPRECT lprc, UINT uiStyle )
  1375. {
  1376.     int     row ;
  1377.     int     xTip ;
  1378.     int     yTip ;
  1379.     RECT    rc ;
  1380.     int     nMax = (lprc->bottom - lprc->top) >> 1 ;
  1381.  
  1382.     SetBkColor( hdc, RGBBLACK ) ;
  1383.  
  1384.     // We draw the arrow by drawing a series of horizontal lines
  1385.     //
  1386.     xTip = lprc->left + ((lprc->right - lprc->left+1) >> 1) ;
  1387.     switch (uiStyle)
  1388.     {
  1389.         case ARROW_UP:
  1390.             yTip = lprc->top + ((lprc->bottom - lprc->top-1) >> 2) ;
  1391.             for (row = 1 ; row <= nMax ; row++ )
  1392.             {
  1393.                 rc.left = xTip - row ;
  1394.                 rc.right = xTip + row - 1 ;
  1395.                 rc.top = yTip + row ;
  1396.                 rc.bottom = rc.top + 1 ;
  1397.                 DRAWFASTRECT( hdc, &rc ) ;
  1398.             }
  1399.         break ;
  1400.  
  1401.         case ARROW_DOWN:
  1402.             yTip = lprc->bottom - ((lprc->bottom - lprc->top-1) >> 2) ;
  1403.             for ( row = nMax ; row > 0 ; row-- )
  1404.             {
  1405.                 rc.left = xTip - row ;
  1406.                 rc.right = xTip + row - 1 ;
  1407.                 rc.top = yTip - row ;
  1408.                 rc.bottom = rc.top + 1 ;
  1409.                 DRAWFASTRECT( hdc, &rc ) ;
  1410.             }
  1411.         break ;
  1412.  
  1413.         case ARROW_RESTORE:
  1414.         default:
  1415.             yTip = lprc->top + ((lprc->bottom - lprc->top-1) >> 3) - 2;
  1416.             for (row = 1 ; row <= nMax ; row++ )
  1417.             {
  1418.                 rc.left = xTip - row ;
  1419.                 rc.right = xTip + row - 1 ;
  1420.                 rc.top = yTip + row ;
  1421.                 rc.bottom = rc.top + 1 ;
  1422.                 DRAWFASTRECT( hdc, &rc ) ;
  1423.             }
  1424.  
  1425.             yTip += (nMax+1) * 2 ;
  1426.             for ( row = nMax ; row > 0 ; row-- )
  1427.             {
  1428.                 rc.left = xTip - row ;
  1429.                 rc.right = xTip + row - 1 ;
  1430.                 rc.top = yTip - row ;
  1431.                 rc.bottom = rc.top + 1 ;
  1432.                 DRAWFASTRECT( hdc, &rc ) ;
  1433.             }
  1434.         break ;
  1435.     }
  1436.  
  1437. }  // DrawArrow()   
  1438.  
  1439. // This function is obsolete.  Some of my apps still call it
  1440. // though so that's why it's still here.
  1441. //
  1442. BOOL FAR PASCAL ibInit( HANDLE hInstance )
  1443. {
  1444.     return TRUE ;
  1445. }
  1446.  
  1447. /////////////////////////////////////////////////////////////////////////
  1448. // End of File: itsybits.c
  1449. /////////////////////////////////////////////////////////////////////////
  1450.  
  1451.