home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / owlsrc.pak / TINYCAPT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-24  |  21.3 KB  |  819 lines

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