home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c083 / 11.ddi / OWLSRC.PAK / TINYCAPT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-02  |  20.2 KB  |  804 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1991, 1993 by Borland International
  3. //   source\owl\tinycapt.cpp
  4. //   Defines type TTinyCaption
  5. //----------------------------------------------------------------------------
  6. #pragma hdrignore SECTION
  7. #include <owl\owlpch.h>
  8. #include <owl\tinycapt.h>
  9. #include <owl\gdiobjec.h>
  10.  
  11. #if !defined(SECTION) || SECTION == 1
  12.  
  13. //
  14. // We only want to search this mixin for events, so don't include any base
  15. // classes in Find()
  16. //
  17. DEFINE_RESPONSE_TABLE(TTinyCaption)
  18.   EV_WM_NCHITTEST,
  19.   EV_WM_NCPAINT,
  20.   EV_WM_NCCALCSIZE,
  21.   EV_WM_NCLBUTTONDOWN,
  22.   EV_WM_MOUSEMOVE,
  23.   EV_WM_LBUTTONUP,
  24.   EV_WM_NCACTIVATE,
  25.   EV_WM_SYSCOMMAND,
  26. END_RESPONSE_TABLE;
  27.  
  28. //
  29. // Rely on TWindow's default ctor since we will always be mixed-in and another
  30. // window will perform Init()
  31. //
  32. TTinyCaption::TTinyCaption()
  33. {
  34.   TCEnabled = FALSE;
  35.   CaptionFont = 0;
  36. }
  37.  
  38. TTinyCaption::~TTinyCaption()
  39. {
  40.   delete CaptionFont;
  41. }
  42.  
  43. void
  44. TTinyCaption::EnableTinyCaption(int captionHeight, BOOL closeBox)
  45. {
  46.   Border.cx = GetSystemMetrics(SM_CXBORDER);
  47.   Border.cy = GetSystemMetrics(SM_CYBORDER);
  48.  
  49.   //
  50.   // Get width of window borders, these will vary with type of window
  51.   //
  52.   long style = Attr.Style;
  53.   if (style & WS_THICKFRAME) {
  54.     Frame.cx = GetSystemMetrics(SM_CXFRAME);
  55.     Frame.cy = GetSystemMetrics(SM_CYFRAME);
  56.  
  57.   } else if (style & WS_DLGFRAME) {
  58.     Frame.cx = GetSystemMetrics(SM_CXDLGFRAME);
  59.     Frame.cy = GetSystemMetrics(SM_CYDLGFRAME);
  60.  
  61.   } else if (style & WS_BORDER) {
  62.     Frame = Border;
  63.  
  64.   } else {
  65.     Frame.cx = 0;
  66.     Frame.cy = 0;
  67.   }
  68.  
  69.   CaptionHeight = ((Border.cy+GetSystemMetrics(SM_CYCAPTION)) * captionHeight)
  70.                     / 100;
  71.   CloseBox = closeBox;
  72.  
  73.   delete CaptionFont;
  74.   CaptionFont = new TFont(
  75.     "Small Fonts",              // facename
  76.     -(CaptionHeight-Border.cy), // pixel height,
  77.     0, 0, 0, FW_NORMAL,         // width,esc,orientation,weight
  78.     VARIABLE_PITCH | FF_SWISS,  // Pitch and Family
  79.     FALSE, FALSE, FALSE,        // Italic, Underline, Strikeout
  80.     ANSI_CHARSET,               // Charset
  81.     OUT_CHARACTER_PRECIS,       // Output precision
  82.     CLIP_DEFAULT_PRECIS,        // Clip precision
  83.     PROOF_QUALITY               // Quality
  84.   );
  85.  
  86.   TCEnabled = TRUE;
  87. }
  88.  
  89. //
  90. // Return where in the non client area we are.  We only handle caption
  91. // bar area
  92. //
  93. UINT
  94. TTinyCaption::EvNCHitTest(TPoint& screenPt)
  95. {
  96.   UINT er;
  97.   if (DoNCHitTest(screenPt, er) == esComplete)
  98.     return er;
  99.   return TWindow::EvNCHitTest(screenPt);
  100. }
  101.  
  102. TEventStatus
  103. TTinyCaption::DoNCHitTest(TPoint& screenPt, UINT& evRes)
  104. {
  105.   if (!TCEnabled)
  106.     return esPartial;
  107.  
  108.   //
  109.   // Check style bits to see what to paint
  110.   //
  111.   long style = GetWindowLong(GWL_STYLE);
  112.   BOOL hasCaption, hasSysMenu, hasMaximize, hasMinimize;
  113.   hasCaption = hasSysMenu = hasMaximize = hasMinimize = FALSE;
  114.   if (style & WS_CAPTION) {
  115.     hasCaption = TRUE;
  116.     if (style & WS_SYSMENU)
  117.       hasSysMenu = TRUE;
  118.     if (style & WS_MAXIMIZEBOX)
  119.       hasMaximize = TRUE;
  120.     if (style & WS_MINIMIZEBOX)
  121.       hasMinimize = TRUE;
  122.   }
  123.  
  124.   //
  125.   // Convert to window coordinates
  126.   //
  127.   TPoint winPt = screenPt - GetWindowRect().TopLeft();
  128.  
  129.   if ((hasSysMenu || CloseBox) && GetSysBoxRect().Contains(winPt)) {
  130.     evRes = HTSYSMENU;
  131.     return esComplete;
  132.  
  133.   } else if (hasMinimize && GetMinBoxRect().Contains(winPt)) {
  134.     evRes = HTMINBUTTON;
  135.     return esComplete;
  136.  
  137.   } else if (hasMaximize && GetMaxBoxRect().Contains(winPt)) {
  138.     evRes = HTMAXBUTTON;
  139.     return esComplete;
  140.  
  141.   //
  142.   // CaptionRect includes buttons so make sure it's last checked
  143.   // Should modify this one to allow clicking in left, top, right thin 
  144.   // borders of caption
  145.   //
  146.   } else if (hasCaption && GetCaptionRect().Contains(winPt)) {
  147.     evRes = HTCAPTION;
  148.     return esComplete;
  149.  
  150.   } else {
  151.     evRes = 0;
  152.     return esPartial;
  153.   }
  154. }
  155.  
  156. //
  157. // We only need to paint the caption. Someone else will paint the borders
  158. //
  159. void
  160. TTinyCaption::EvNCPaint()
  161. {
  162.   TWindow::EvNCPaint();  // Default border painting
  163.   DoNCPaint();           // Then our special caption painting
  164. }
  165.  
  166. TEventStatus
  167. TTinyCaption::DoNCPaint()
  168. {
  169.   if (!TCEnabled || IsIconic())
  170.     return esPartial;  // We don't do anything special for an Icon
  171.  
  172.   //
  173.   // If we have focus or our children have focus, then we're active
  174.   // Note: We can't use GetFocus here because when we're being restored
  175.   // from an icon, we're active, but don't yet have focus!
  176.   //
  177.   HWND focus = GetFocus();
  178.   PaintCaption(GetActiveWindow() == HWindow || focus == HWindow || IsChild(focus));
  179.   return esPartial;       // Caller must call function to paint borders
  180. }
  181.  
  182. //
  183. // Returns the size of our client area
  184. //
  185. UINT
  186. TTinyCaption::EvNCCalcSize(BOOL calcValidRects, NCCALCSIZE_PARAMS far& calcSize)
  187. {
  188.   UINT er;
  189.   if (DoNCCalcSize(calcValidRects, calcSize, er) == esComplete)
  190.     return er;
  191.   return TWindow::EvNCCalcSize(calcValidRects, calcSize);
  192. }
  193.  
  194. //
  195. // Return the size of our client area, leaving room for caption bar
  196. //
  197. TEventStatus
  198. TTinyCaption::DoNCCalcSize(BOOL /*calcValidRects*/,
  199.                            NCCALCSIZE_PARAMS far& calcSize, UINT& evRes)
  200. {
  201.   if (!TCEnabled || IsIconic())
  202.     return esPartial;
  203.  
  204.   TRect captRect = GetCaptionRect();
  205.  
  206.   calcSize.rgrc[0].left +=   Frame.cx;
  207.   calcSize.rgrc[0].top +=    Frame.cy + captRect.Height();
  208.   calcSize.rgrc[0].right -=  Frame.cx;
  209.   calcSize.rgrc[0].bottom -= Frame.cy;
  210.  
  211.   evRes = 0;
  212.   return esComplete;
  213. }
  214.  
  215. void
  216. TTinyCaption::EvNCLButtonDown(UINT hitTest, TPoint& screenPt)
  217. {
  218.   //
  219.   // Display system menu, invert min/max icons (not), etc
  220.   //
  221.   if (DoNCLButtonDown(hitTest,screenPt) == esPartial)
  222.     TWindow::EvNCLButtonDown(hitTest, screenPt);
  223. }
  224.  
  225. TEventStatus
  226. TTinyCaption::DoNCLButtonDown(UINT hitTest, TPoint& /*screenPt*/)
  227. {
  228.   if (!TCEnabled)
  229.     return esPartial;
  230.  
  231.   switch (hitTest) {
  232.     case HTSYSMENU:
  233.       DownHit = HTSYSMENU;
  234.       if (CloseBox) {
  235.         IsPressed = TRUE;
  236.         SetCapture();
  237.         PaintCloseBox(TWindowDC(*this), GetSysBoxRect(), IsPressed);
  238.  
  239.       } else {
  240.         TWindowDC(*this).PatBlt(GetSysBoxRect(), PATINVERT);
  241.         //
  242.         // Display sys menu on button down
  243.         // Need to lock sys menu until user clicks outside
  244.         //
  245.  
  246.         //
  247.         // Set flag to indicate we're expecting a sys command
  248.         //
  249.         WaitingForSysCmd = TRUE;
  250.         DoSysMenu();
  251.  
  252.         //
  253.         // If we didn't execute a command, user released btn outside of menu
  254.         // If it was released in sys menu box, then redisplay menu as if it
  255.         // were brought up with a keystroke
  256.         //
  257.         if (WaitingForSysCmd) {
  258.           UINT hitTest;
  259.           TPoint pt;
  260.           GetCursorPos(pt);
  261.           DoNCHitTest(pt, hitTest);
  262.           if (hitTest == HTSYSMENU) {
  263.             //
  264.             // Make this look like menu was brought up with LButton UP or
  265.             // Alt-Space so that it stays on screen after mouse is released
  266.             //
  267.             BYTE rgbKeyState[256];
  268.             GetKeyboardState(rgbKeyState);
  269.             rgbKeyState[VK_LBUTTON] = 0;      // 0==UP, 1==DOWN
  270.             SetKeyboardState(rgbKeyState);
  271.             DoSysMenu();  // TrackPopupMenu will now have alt-space behavior
  272.           }
  273.         }
  274.         if (HWindow)
  275.           TWindowDC(*this).PatBlt(GetSysBoxRect(), PATINVERT);
  276.       }
  277.       return esComplete;
  278.  
  279.     case HTMINBUTTON:
  280.       DownHit = HTMINBUTTON;
  281.       IsPressed = TRUE;
  282.       SetCapture();
  283.       PaintMinBox(TWindowDC(*this), GetMinBoxRect(), IsPressed);
  284.       return esComplete;
  285.  
  286.     case HTMAXBUTTON:
  287.       DownHit = HTMAXBUTTON;
  288.       IsPressed = TRUE;
  289.       SetCapture();
  290.       PaintMaxBox(TWindowDC(*this), GetMaxBoxRect(), IsPressed);
  291.       return esComplete;
  292.   }
  293.   DownHit = HTNOWHERE;
  294.   return esPartial;
  295. }
  296.  
  297. void
  298. TTinyCaption::EvMouseMove(UINT modKeys, TPoint& pt)
  299. {
  300.   if (DoMouseMove(modKeys, pt) == esPartial)
  301.     TWindow::EvMouseMove(modKeys, pt);
  302. }
  303.  
  304. TEventStatus
  305. TTinyCaption::DoMouseMove(UINT /*modKeys*/, TPoint& pt)
  306. {
  307.   if (TCEnabled && DownHit != HTNOWHERE) {
  308.     UINT   hitTest;
  309.     TPoint screenPt = pt;
  310.     ClientToScreen(screenPt);    // Cvt to screen coord
  311.     DoNCHitTest(screenPt, hitTest);
  312.     BOOL isNowPressed = hitTest == DownHit;
  313.  
  314.     if (isNowPressed != IsPressed) {
  315.       IsPressed = isNowPressed;
  316.       switch (DownHit) {
  317.         case HTSYSMENU:
  318.           if (CloseBox)
  319.             PaintCloseBox(TWindowDC(*this), GetSysBoxRect(), IsPressed);
  320.           return esComplete;
  321.         case HTMINBUTTON:
  322.           PaintMinBox(TWindowDC(*this), GetMinBoxRect(), IsPressed);
  323.           return esComplete;
  324.         case HTMAXBUTTON:
  325.           PaintMaxBox(TWindowDC(*this), GetMaxBoxRect(), IsPressed);
  326.           return esComplete;
  327.       }
  328.     }
  329.   }
  330.   return esPartial;
  331. }
  332.  
  333. void
  334. TTinyCaption::EvLButtonUp(UINT modKeys, TPoint& pt)
  335. {
  336.   //
  337.   // If we're still in area where buton went down, then do it
  338.   //
  339.   if (DoLButtonUp(modKeys, pt) == esPartial)
  340.     TWindow::EvLButtonUp(modKeys, pt);
  341. }
  342.  
  343. TEventStatus
  344. TTinyCaption::DoLButtonUp(UINT modKeys, TPoint& pt)
  345. {
  346.   if (TCEnabled && DownHit != HTNOWHERE) {
  347.     ReleaseCapture();
  348.     DoMouseMove(modKeys, pt);
  349.  
  350.     UINT   hitTest;
  351.     TPoint screenPt = pt;
  352.     ClientToScreen(screenPt);    // Cvt to screen coord
  353.     DoNCHitTest(screenPt, hitTest);
  354.  
  355.     if (hitTest == DownHit) {
  356.       DownHit = HTNOWHERE;
  357.       switch (hitTest) {
  358.         case HTSYSMENU:
  359.           if (CloseBox)
  360.             PostMessage(WM_CLOSE);
  361.           return esComplete;
  362.  
  363.         //
  364.         // We have to handle these buttons also to prevent defproc from painting
  365.         // the standard big min/max buttons when left mouse button is pressed
  366.         //
  367.         case HTMINBUTTON:
  368.           HandleMessage(WM_SYSCOMMAND, SC_MINIMIZE);
  369.           return esComplete;
  370.  
  371.         case HTMAXBUTTON:
  372.           HandleMessage(WM_SYSCOMMAND, IsZoomed() ? SC_RESTORE : SC_MAXIMIZE);
  373.           return esComplete;
  374.       }
  375.     }
  376.     DownHit = HTNOWHERE;
  377.   }
  378.   return esPartial;
  379. }
  380.  
  381. BOOL
  382. TTinyCaption::EvNCActivate(BOOL active)
  383. {
  384.   BOOL er;
  385.   if (DoNCActivate(active, er) == esComplete)
  386.     return er;
  387.   return TWindow::EvNCActivate(active);
  388. }
  389.  
  390. TEventStatus
  391. TTinyCaption::DoNCActivate(BOOL active, BOOL& evRes)
  392. {
  393.   if (!TCEnabled || IsIconic())
  394.     return esPartial;  // Let default do it's thing
  395.  
  396.   PaintCaption(active);
  397.   evRes = !active;
  398.   return esComplete;
  399. }
  400.  
  401.  
  402. LRESULT
  403. TTinyCaption::EvCommand(UINT id, HWND hWndCtl, UINT notifyCode)
  404. {
  405.   LRESULT er;
  406.   if (DoCommand(id, hWndCtl, notifyCode, er) == esComplete)
  407.     return er;
  408.   return TWindow::EvCommand(id, hWndCtl, notifyCode);
  409. }
  410.  
  411. TEventStatus
  412. TTinyCaption::DoCommand(UINT id, HWND /*hWndCtl*/, UINT notifyCode, LRESULT& evRes)
  413. {
  414.   //
  415.   // We're displaying system menu using TrackPopup...
  416.   // This will send us WM_COMMAND messages instead of WM_SYSCOMMAND msgs
  417.   // If we get a system menu command then transform it into a WM_SYSCOMMAND
  418.   //
  419.   if (!TCEnabled)
  420.     return esPartial;
  421.  
  422.   if (id >= 0xF000) {
  423.     WaitingForSysCmd = FALSE;  // For LButtonDown use
  424.     evRes = HandleMessage(WM_SYSCOMMAND, id, notifyCode);
  425.     return esComplete;
  426.  
  427.   } else {
  428.     evRes = 0;
  429.     return esPartial;
  430.   }
  431. }
  432.  
  433. void
  434. TTinyCaption::EvSysCommand(UINT cmdType, TPoint& p)
  435. {
  436.   if (DoSysCommand(cmdType,p) == esPartial)
  437.     TWindow::EvSysCommand(cmdType,p);
  438. }
  439.  
  440. TEventStatus
  441. TTinyCaption::DoSysCommand(UINT cmdType, TPoint&)
  442. {
  443.   if (!TCEnabled)
  444.     return esPartial;
  445.  
  446.   //
  447.   // Make sure that ALT-SPACE brings up our sys menu at the right coord
  448.   //
  449.   if (cmdType == SC_KEYMENU) {
  450.     //
  451.     // If we're iconized, windows sends us the SC_KEYMENU message when the
  452.     // user clicks on the icon.  We want the menu to be displayed in the
  453.     // default position
  454.     //
  455.     if (!IsIconic()) {
  456.       DoSysMenu();
  457.       return esComplete;
  458.     }
  459.   }
  460.   return esPartial;
  461. }
  462.  
  463. void
  464. TTinyCaption::PaintButton(TDC& dc, TRect& r, BOOL pressed)
  465. {
  466. //  dc.OWLFastWindowFrame(TBrush(GetSysColor(COLOR_WINDOWFRAME)), r, 1, 1);
  467.   dc.FrameRect(r, TBrush(TColor::Black));
  468.  
  469.   r.Inflate(-1,-1);
  470.   dc.TextRect(r, TColor::LtGray);
  471.   if (r.Width() > 4 && r.Height() > 4) {
  472.     if (pressed) {
  473.       dc.TextRect(r.left, r.top, r.right, r.top+1, TColor::Gray);
  474.       dc.TextRect(r.left, r.top+1, r.left+1, r.bottom, TColor::Gray);
  475.     } else {
  476.       dc.TextRect(r.left, r.top, r.right-1, r.top+1, TColor::White);
  477.       dc.TextRect(r.left, r.top+1, r.left+1, r.bottom-1, TColor::White);
  478.       dc.TextRect(r.right-1, r.top+1, r.right, r.bottom, TColor::Gray);
  479.       dc.TextRect(r.left+1, r.bottom-1, r.right-1, r.bottom, TColor::Gray);
  480.     }
  481.   }
  482. }
  483.  
  484. void
  485. TTinyCaption::PaintCloseBox(TDC& dc, TRect& boxRect, BOOL pressed)
  486. {
  487.   //
  488.   // Fill the box with light gray & draw bevel if possible
  489.   //
  490.   PaintButton(dc, boxRect, pressed);
  491.  
  492.   if (pressed)
  493.     boxRect.Offset(1,1);
  494.  
  495.   //
  496.   // Do something different to differentiate from standard system menu--
  497.   // draw a recessed black box
  498.   //
  499.   TRect glyphRect(0, 0, boxRect.Width()/2+1, boxRect.Height()/2+1);
  500.   glyphRect += TPoint(boxRect.left + glyphRect.right/2,
  501.                       boxRect.top + glyphRect.bottom/2);
  502.  
  503.   dc.TextRect(glyphRect, TColor::Gray);
  504.   glyphRect.Offset(1,1);
  505.   dc.TextRect(glyphRect, TColor::White);
  506.   glyphRect.BottomRight().Offset(-1,-1);
  507.   dc.TextRect(glyphRect, TColor::Black);
  508. }
  509.  
  510. void
  511. TTinyCaption::PaintSysBox(TDC& dc, TRect& boxRect, BOOL /*pressed*/)
  512. {
  513.   //
  514.   // Dont paint over the left & top borders
  515.   //
  516.   boxRect.left++;
  517.   boxRect.top++;
  518.  
  519.   //
  520.   // Fill the box with light gray
  521.   //
  522.   dc.TextRect(boxRect, TColor::LtGray);
  523.  
  524.   //
  525.   // Draw the ventilator (sysmenu) box, with shadow
  526.   // 
  527.   TPoint begPt = boxRect.TopLeft().OffsetBy(2, (boxRect.Height()-3)/2);
  528.   TRect ventRect(begPt, TSize(boxRect.Width()-5, 3));
  529.  
  530.   // Draw shadow down and right 1
  531.   dc.TextRect(ventRect.left+1, ventRect.top+1,
  532.               ventRect.right+1, ventRect.bottom+1, TColor::Gray);
  533.  
  534.   // Draw ventilator rectangle
  535.   dc.FrameRect(ventRect, TBrush(TColor::Black));
  536.  
  537.   // Draw white interior of ventilator
  538.   dc.TextRect(ventRect.left+1, ventRect.top+1,
  539.               ventRect.right-1, ventRect.top+2, TColor::White);
  540.  
  541.   dc.TextRect(boxRect.right, boxRect.top,
  542.               boxRect.right+1, boxRect.bottom, TColor::Black);
  543. }
  544.  
  545. void
  546. TTinyCaption::PaintMinBox(TDC& dc, TRect& boxRect, BOOL pressed)
  547. {
  548.   //
  549.   // Fill the box with light gray & draw bevel if possible
  550.   //
  551.   PaintButton(dc, boxRect, pressed);
  552.  
  553.   if (pressed)
  554.     boxRect.Offset(1,1);
  555.  
  556.   int bh = boxRect.Height();
  557.   int bw = boxRect.Width();
  558.  
  559.   TPoint begPt = boxRect.TopLeft().OffsetBy((bw+1)/4, (bh+2)/3);
  560.   TPoint endPt = begPt.OffsetBy((bw+1)/2,0);
  561.   for (int i = 0; begPt.x < endPt.x; i++) {
  562.     dc.MoveTo(begPt);
  563.     dc.LineTo(endPt);
  564.     begPt.Offset(1,1);
  565.     endPt.Offset(-1,1);
  566.   }
  567. }
  568.  
  569. void
  570. TTinyCaption::PaintMaxBox(TDC& dc, TRect& boxRect, BOOL pressed)
  571. {
  572.   //
  573.   // Fill the box with light gray & draw bevel if possible
  574.   //
  575.   PaintButton(dc, boxRect, pressed);
  576.  
  577.   if (pressed)
  578.     boxRect.Offset(1,1);
  579.  
  580.   //
  581.   // Down triangle
  582.   //
  583.   int bh = boxRect.Height();
  584.   int bw = boxRect.Width();
  585.  
  586.   if (IsZoomed()) {
  587.     TPoint begPt = boxRect.BottomLeft().OffsetBy((bw+1)/4, -bh*3/8);
  588.     TPoint endPt = begPt.OffsetBy((bw+1)/2, 0);
  589.     for (int i = 0; begPt.x < endPt.x; i++) {
  590.       dc.MoveTo(begPt);
  591.       dc.LineTo(endPt);
  592.       begPt.Offset(1,1);
  593.       endPt.Offset(-1,1);
  594.     }
  595.   }
  596.  
  597.   //
  598.   // Up triangle
  599.   //
  600.   {
  601.     TPoint begPt = boxRect.TopLeft().OffsetBy((bw+1)/4, IsZoomed() ? bh*3/8 : bh*2/3);
  602.     TPoint endPt = begPt.OffsetBy((bw+1)/2, 0);
  603.     for (int i = 0; begPt.x < endPt.x; i++) {
  604.       dc.MoveTo(begPt);
  605.       dc.LineTo(endPt);
  606.       begPt.Offset(1, -1);
  607.       endPt.Offset(-1, -1);
  608.     }
  609.   }
  610. }
  611.  
  612. void
  613. TTinyCaption::PaintCaption(BOOL active)
  614. {
  615.   int xOrg;
  616.  
  617.   long style = GetWindowLong(GWL_STYLE);
  618.   if (!(style & WS_CAPTION))
  619.     return;    // Leave now if there is no caption, it's all we care about
  620.  
  621.   //
  622.   // Paint caption background and caption text if any.
  623.   //
  624.   TWindowDC dc(*this);
  625.   TRect captRect = GetCaptionRect();
  626.  
  627.   HBRUSH captionBrush = CreateSolidBrush(GetSysColor(active ?
  628.                                                      COLOR_ACTIVECAPTION :
  629.                                                      COLOR_INACTIVECAPTION));
  630.   dc.SetTextColor(GetSysColor(active ? COLOR_CAPTIONTEXT :
  631.                                        COLOR_INACTIVECAPTIONTEXT));
  632.   dc.FillRect(captRect, captionBrush);
  633.   DeleteObject(captionBrush);
  634.  
  635.   dc.SelectObject(*CaptionFont);
  636.   dc.SetBkMode(TRANSPARENT);
  637.   TSize textSize = dc.GetTextExtent(Title, lstrlen(Title));
  638.  
  639.   //
  640.   // Calc x coord for text, so that text is centered between caption buttons
  641.   //
  642.   xOrg = captRect.right - captRect.left;
  643.   if (style & WS_MINIMIZEBOX)
  644.     xOrg -= GetMinBoxRect().Width();
  645.  
  646.   if (style & WS_MAXIMIZEBOX)
  647.     xOrg -= GetMaxBoxRect().Width();
  648.  
  649.   if ((style & WS_SYSMENU) || CloseBox)
  650.     xOrg -= GetSysBoxRect().Width();
  651.  
  652.   xOrg -= textSize.cx;
  653.   if (xOrg<0)
  654.     xOrg = 0;
  655.   else
  656.     xOrg = xOrg/2;
  657.   
  658.   xOrg += captRect.left;
  659.  
  660.   if ((style & WS_SYSMENU) || CloseBox)
  661.     xOrg += GetSysBoxRect().Width();
  662.  
  663.   dc.ExtTextOut(xOrg, captRect.top,
  664.     ETO_CLIPPED,
  665.     &captRect,
  666.     Title,
  667.     lstrlen(Title)
  668.   );
  669.   dc.RestoreFont();
  670.  
  671.   //
  672.   // Paint widgets: sysmenu or close button, minimize button, maximize button
  673.   //
  674.   dc.SelectStockObject(BLACK_PEN);
  675.  
  676.   //
  677.   // Paint system menu or close button
  678.   //
  679.  
  680.   if (CloseBox)
  681.     PaintCloseBox(dc, GetSysBoxRect(), FALSE);
  682.   else if (style & WS_SYSMENU)
  683.     PaintSysBox(dc, GetSysBoxRect(), FALSE);
  684.  
  685.   //
  686.   // Paint minimize button
  687.   //
  688.   if (style & WS_MINIMIZEBOX)
  689.     PaintMinBox(dc, GetMinBoxRect(), FALSE);
  690.  
  691.   //
  692.   // Paint maximize button
  693.   //
  694.   if (style & WS_MAXIMIZEBOX)
  695.     PaintMaxBox(dc, GetMaxBoxRect(), FALSE);
  696.  
  697.   //
  698.   // Draw black line under caption
  699.   //
  700.   dc.MoveTo(captRect.left, captRect.bottom-1);
  701.   dc.LineTo(captRect.right, captRect.bottom-1);
  702. }
  703.  
  704. //
  705. //  NOTE: GetCaptionRect and GetSysBoxRect must be kept in sync!
  706. //
  707. TRect
  708. TTinyCaption::GetCaptionRect()
  709. {
  710.   //
  711.   // Get caption rect converted to window relative coordinates
  712.   //
  713.   TRect captRect = GetWindowRect();
  714.   captRect -= captRect.TopLeft();
  715.  
  716.   captRect.left +=  Frame.cx;
  717.   captRect.top +=   Frame.cy;
  718.   captRect.right -= Frame.cx;
  719.   captRect.bottom = captRect.top + CaptionHeight;
  720.  
  721.   return captRect;
  722. }
  723.  
  724. //
  725. // Returns a rectangle for sysmenu, minimize, or maximize rectangle
  726. //
  727. TRect
  728. TTinyCaption::GetSysBoxRect()
  729. {
  730.   TRect boxRect = GetCaptionRect();
  731.   boxRect.right = boxRect.left + CaptionHeight;
  732.   boxRect.left -= 1;
  733.   boxRect.top -= 1;
  734.   return boxRect;
  735. }
  736.  
  737. TRect
  738. TTinyCaption::GetMinBoxRect()
  739. {
  740.   //
  741.   // Far right on caption if no max box, else next to max box
  742.   //
  743.   TRect boxRect = GetMaxBoxRect();
  744.   if (GetWindowLong(GWL_STYLE) & WS_MAXIMIZEBOX)
  745.     boxRect.Offset(-CaptionHeight, 0);
  746.   return boxRect;
  747. }
  748.  
  749. TRect
  750. TTinyCaption::GetMaxBoxRect()
  751. {
  752.   TRect boxRect = GetCaptionRect();
  753.   boxRect.left = boxRect.right - CaptionHeight; 
  754.   boxRect.top -= 1;
  755.   boxRect.right += 1;
  756.   return boxRect;
  757. }
  758.  
  759. void
  760. TTinyCaption::DoSysMenu()
  761. {
  762.   HMENU h = GetSystemMenu();
  763.   if (h) {
  764.     TRect r = GetSysBoxRect();
  765.     ClientToScreen(r.TopLeft());  // Cvt pt to screen coord
  766.     TrackPopupMenu(h, TPM_LEFTALIGN | TPM_LEFTBUTTON,
  767.                    r.left-Frame.cx, r.top-Frame.cy-1, 0, HWindow,0);
  768.   }
  769. }
  770.  
  771. #endif
  772. #if !defined(SECTION) || SECTION == 2
  773.  
  774. IMPLEMENT_STREAMABLE(TTinyCaption);
  775.  
  776. void*
  777. TTinyCaption::Streamer::Read(ipstream& is, uint32 /*version*/) const
  778. {
  779.   TTinyCaption* o = GetObject();
  780.  
  781.   o->CaptionFont = 0;
  782.   is >> o->TCEnabled;
  783.   if (o->TCEnabled) {
  784.     int captionHeight;
  785.     is >> captionHeight >> o->CloseBox;;
  786.     o->EnableTinyCaption(captionHeight, o->CloseBox);
  787.   }
  788.   return o;
  789. }
  790.  
  791. void
  792. TTinyCaption::Streamer::Write(opstream& os) const
  793. {
  794.   TTinyCaption* o = GetObject();
  795.  
  796.   os << o->TCEnabled;
  797.   if (o->TCEnabled) {
  798.     int captionHeight = (100*o->CaptionHeight) /
  799.                           (o->Border.cy+GetSystemMetrics(SM_CYCAPTION));
  800.     os << captionHeight << o->CloseBox;
  801.   }
  802. }
  803. #endif
  804.