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

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // (C) Copyright 1992, 1994 by Borland International, All Rights Reserved
  4. //
  5. //   Implementation of class TButtonGadget.
  6. //----------------------------------------------------------------------------
  7. #include <owl/owlpch.h>
  8. #include <owl/buttonga.h>
  9. #include <owl/gadgetwi.h>
  10. #include <owl/celarray.h>
  11.  
  12. //
  13. // make the monochrome bitmap large enough to hold any possible bitmap
  14. //
  15. #define GLYPH_MASK_WIDTH   128
  16. #define GLYPH_MASK_HEIGHT  128
  17. const long RopPSDPxax = 0x00B8074AL;  //
  18. const long RopDSPDxax = 0x00E20746L;  // 
  19.  
  20. //
  21. // local 'class' vars
  22. //
  23. static THatch8x8Brush ditherBrush(THatch8x8Brush::Hatch11F1,
  24.                                   ::GetSysColor(COLOR_BTNHIGHLIGHT),
  25.                                   ::GetSysColor(COLOR_BTNHIGHLIGHT));
  26.  
  27. static TBitmap      glyphMask(GLYPH_MASK_WIDTH, GLYPH_MASK_HEIGHT, 1, 1, 0);
  28.  
  29. //
  30. // command enabler for button gadgets
  31. //
  32. class _OWLCLASS TButtonGadgetEnabler : public TCommandEnabler {
  33.   public:
  34.     TButtonGadgetEnabler(HWND hWndReceiver, TButtonGadget* g)
  35.       : TCommandEnabler(g->GetId(), hWndReceiver) {
  36.       Gadget = g;
  37.     }
  38.  
  39.     //
  40.     // override member functions of TCommandEnabler
  41.     //
  42.     void  Enable(bool);
  43.     void  SetText(const char far*);
  44.     void  SetCheck(int);
  45.  
  46.   protected:
  47.     TButtonGadget*  Gadget;
  48. };
  49.  
  50. void
  51. TButtonGadgetEnabler::Enable(bool enable)
  52. {
  53.   TCommandEnabler::Enable(enable);
  54.   Gadget->SetEnabled(enable);
  55. }
  56.  
  57. void
  58. TButtonGadgetEnabler::SetText(const char far*)
  59. {
  60. # pragma warn -ccc
  61.   CHECK(false);
  62. # pragma warn .ccc
  63. }
  64.  
  65. void
  66. TButtonGadgetEnabler::SetCheck(int state)
  67. {
  68.   Gadget->SetButtonState(TButtonGadget::TState(state));
  69. }
  70.  
  71. TButtonGadget::TButtonGadget(TResId bmpResId,
  72.                              int    id,
  73.                              TType  type,
  74.                              bool   enabled,
  75.                              TState state,
  76.                              bool   repeat)
  77. :
  78.   TGadget(id, Plain)
  79. {
  80.   ResId = bmpResId.IsString() ? strnewdup(bmpResId) : (char far*)bmpResId;
  81.   CelArray = 0;
  82.   BitmapOrigin.x = BitmapOrigin.y = 0;
  83.   Type = type;
  84.   Repeat = repeat;
  85.   TrackMouse = true;
  86.   State = state;
  87.   NotchCorners = true;
  88.   Pressed = false;
  89.   SetEnabled(enabled);
  90.   SetShadowStyle(DoubleShadow);
  91.   SetAntialiasEdges(true);
  92. }
  93.  
  94. TButtonGadget::~TButtonGadget()
  95. {
  96.   delete CelArray;
  97.   if (ResId.IsString())
  98.     delete (char far*)ResId;
  99. }
  100.  
  101. void
  102. TButtonGadget::SetShadowStyle(TShadowStyle shadowStyle)
  103. {
  104.   TBorders  borders;
  105.  
  106.   ShadowStyle = shadowStyle;
  107.   borders.Left = borders.Top = 2;
  108.   borders.Right = borders.Bottom = ShadowStyle + 1;
  109.   SetBorders(borders);
  110. }
  111.  
  112. void
  113. TButtonGadget::CommandEnable()
  114. {
  115.   // Must send, not post here, since a ptr to a temp is passed
  116.   //
  117.   Window->Parent->HandleMessage(
  118.     WM_COMMAND_ENABLE,
  119.     0,
  120.     (LPARAM)&TButtonGadgetEnabler(*Window->Parent, this)
  121.   );
  122. }
  123.  
  124. void
  125. TButtonGadget::SysColorChange()
  126. {
  127.   ditherBrush.Reconstruct(THatch8x8Brush::Hatch11F1,
  128.                           ::GetSysColor(COLOR_BTNHIGHLIGHT),
  129.                           ::GetSysColor(COLOR_BTNHIGHLIGHT));
  130.   BuildCelArray();
  131. }
  132.  
  133. void
  134. TButtonGadget::CheckExclusively()
  135. {
  136.   if (State != Down) {
  137.     if (Window) {
  138.       TGadget*        g = Window->FirstGadget();
  139.       TButtonGadget*  first = 0;
  140.       TButtonGadget*  last = this;
  141.  
  142.       //
  143.       // look for the start of the group in which the receiver is located
  144.       //
  145.       while (g != this) {
  146.         TButtonGadget* bg = TYPESAFE_DOWNCAST(g, TButtonGadget);
  147.         if (!bg || bg->Type != Exclusive)
  148.           first = 0;
  149.  
  150.         else if (!first)
  151.           first = bg;
  152.  
  153.         g = g->NextGadget();
  154.       }
  155.       if (!first)
  156.         first = this;
  157.  
  158.       // Look for the end of the group in which the receiver is located
  159.       //
  160.       while (last->NextGadget()) {
  161.         TButtonGadget* bg = TYPESAFE_DOWNCAST(last->NextGadget(), TButtonGadget);
  162.         if (!bg || bg->Type != Exclusive)
  163.           break;
  164.  
  165.         else
  166.           last = bg;
  167.       }
  168.  
  169.       while (true) {
  170.         CHECK(first);     // Already know they are buttons, but just in case...
  171.         if (first->State == Down) {
  172.           first->State = Up;
  173.           first->Invalidate();
  174.           first->Update();
  175.         }
  176.  
  177.         if (first == last)
  178.           break;
  179.  
  180.         first = TYPESAFE_DOWNCAST(first->NextGadget(), TButtonGadget);
  181.       }
  182.     }
  183.  
  184.     State = Down;
  185.   }
  186. }
  187.  
  188. void
  189. TButtonGadget::SetButtonState(TState state)
  190. {
  191.   if (state != State) {
  192.     if (Type == Exclusive && state == Down)
  193.       CheckExclusively();
  194.  
  195.     State = state;
  196.     Invalidate();
  197.     Update();
  198.   }
  199. }
  200.  
  201. void
  202. TButtonGadget::SetBounds(TRect& bounds)
  203. {
  204.   TRect  innerRect;
  205.   TSize  bitmapSize = CelArray->CelSize();
  206.  
  207.   TGadget::SetBounds(bounds);
  208.  
  209.   // Center the glyph within the inner bounds
  210.   //
  211.   GetInnerRect(innerRect);
  212.  
  213.   BitmapOrigin.x = innerRect.left + (innerRect.Width() - bitmapSize.cx) / 2;
  214.   BitmapOrigin.y = innerRect.top + (innerRect.Height() - bitmapSize.cy) / 2;
  215. }
  216.  
  217. void
  218. TButtonGadget::GetDesiredSize(TSize& size)
  219. {
  220.   TGadget::GetDesiredSize(size);
  221.  
  222.   if (!CelArray)
  223.     BuildCelArray();
  224.  
  225.   size += CelArray->CelSize();
  226. }
  227.  
  228. //
  229. // determines the parts of "r1" that do not lie within "r2"
  230. //
  231. // returns the resulting number of rectangles which will be in the
  232. // range "0 .. 4" inclusive
  233. //
  234. uint
  235. Subtract(TRect& r1, TRect& r2, TRect result[4])
  236. {
  237.   if (!r1.Touches(r2)) {
  238.     result[0] = r1;
  239.     return 1;
  240.   }
  241.   else {
  242.     uint  i = 0;
  243.  
  244.     if (r2.top > r1.top) {
  245.       result[i].left = r1.left;
  246.       result[i].top = r1.top;
  247.       result[i].right = r1.right;
  248.       result[i].bottom = r2.top;
  249.       i++;
  250.     }
  251.  
  252.     if (r2.bottom < r1.bottom) {
  253.       result[i].left = r1.left;
  254.       result[i].top = r2.bottom;
  255.       result[i].right = r1.right;
  256.       result[i].bottom = r1.bottom;
  257.       i++;
  258.     }
  259.  
  260.     if (r2.left > r1.left) {
  261.       result[i].left = r1.left;
  262.       result[i].top = max(r1.top, r2.top);
  263.       result[i].right = r2.left;
  264.       result[i].bottom = min(r1.bottom, r2.bottom);
  265.       i++;
  266.     }
  267.  
  268.     if (r2.right < r1.right) {
  269.       result[i].left = r2.right;
  270.       result[i].top = max(r1.top, r2.top);
  271.       result[i].right = r1.right;
  272.       result[i].bottom = min(r1.bottom, r2.bottom);
  273.       i++;
  274.     }
  275.     return i;
  276.   }
  277. }
  278.  
  279. //
  280. // build a monochrome mask bitmap for the glyph that has 1's where
  281. // COLOR_BTNFACE is and 0's everywhere else. assumes glyphDC is already setup
  282. //
  283. static void
  284. BuildMask(TDC& maskDC, TRect& maskRect, TDC& glyphDC, TRect& glyphRect)
  285. {
  286.   maskDC.PatBlt(0, 0, maskRect.Width(), maskRect.Height(), WHITENESS);
  287.   glyphDC.SetBkColor(GetSysColor(COLOR_BTNFACE));  // btnface to white
  288.   maskDC.BitBlt(maskRect.left, maskRect.top, glyphRect.Width(), glyphRect.Height(),
  289.                 glyphDC, glyphRect.left, glyphRect.top, SRCCOPY);
  290. }
  291.  
  292. //
  293. // tiles the rectangle with a even dithered (checkerboard) pattern
  294. //
  295. // maskDC determines the stencil area of dither
  296. //
  297. static void
  298. DitherBackground(TDC& dc, TDC& maskDC, TRect& rect)
  299. {
  300.   dc.SelectObject(HBRUSH(ditherBrush));
  301.  
  302.   dc.SetTextColor(RGB(0, 0, 0));      // 0 to black
  303.   dc.SetBkColor(RGB(255, 255, 255));  // 1 to white
  304.  
  305.   dc.BitBlt(rect, maskDC, TPoint(0, 0), RopDSPDxax);
  306. }
  307.  
  308. //
  309. // virtual function responsible for supplying glyphdib. Can be overriden to
  310. // get dib from elsewhere, cache it, map colors differently, etc.
  311. //
  312. TDib*
  313. TButtonGadget::GetGlyphDib()
  314. {
  315.   TDib* glyph = new TDib(*Window->GetModule(), ResId);
  316.   glyph->MapUIColors(
  317.     TDib::MapFace | TDib::MapText | TDib::MapShadow | TDib::MapHighlight
  318.   );
  319.   return glyph;
  320. }
  321.  
  322. //
  323. // virtual function responsible for releasing glyph dib as needed based on how
  324. // GetGlyphDib() got it (if different from new/delete).
  325. //
  326. void
  327. TButtonGadget::ReleaseGlyphDib(TDib* glyph)
  328. {
  329.   delete glyph;
  330. }
  331.  
  332. //
  333. // Build the CelArray member using the resource bitmap as the base glyph
  334. // CelArray may contain an existing cel array that should be deleted if
  335. // replaced
  336. //
  337. void
  338. TButtonGadget::BuildCelArray()
  339. {
  340.   //
  341.   // Get the base glyph as a dib, & map the colors to current SysColors.
  342.   //
  343.   TDib*  glyph = GetGlyphDib();
  344.   TSize  celSize = glyph->Size();
  345.  
  346.   //
  347.   // Create a TCelArray if we don't already have one, else use existing one.
  348.   //
  349.   if (!CelArray) {
  350.     TBitmap*   bitmap = new TBitmap(TScreenDC(), celSize.cx*CelsTotal,
  351.                                     celSize.cy);
  352.     CelArray = new TCelArray(bitmap, CelsTotal);
  353.   }
  354.   
  355.   TMemoryDC maskDC;
  356.   maskDC.SelectObject(glyphMask);
  357.   TRect maskRect(0,0, celSize.cx, celSize.cy);
  358.  
  359.   TMemoryDC celDC;
  360.   celDC.SelectObject(*CelArray);
  361.   
  362.   //
  363.   // CelArray[CelNormal]: normal appearance, blit directly from the glyph dib
  364.   //
  365.   TRect nrmlCelRect = CelArray->CelRect(CelNormal);
  366.   celDC.StretchDIBits(nrmlCelRect, maskRect, *glyph);
  367.   
  368.   ReleaseGlyphDib(glyph);
  369.  
  370.   //
  371.   // CelArray[CelDisabled]: disabled variant of glyph
  372.   //
  373.   TRect celRect = CelArray->CelRect(CelDisabled);
  374.  
  375.   //
  376.   // make sure area under highlight color ends up face color
  377.   //
  378.   BuildMask(maskDC, maskRect, celDC, nrmlCelRect);
  379.   celDC.TextRect(celRect, GetSysColor(COLOR_BTNFACE));
  380.  
  381.   //
  382.   // inactivate mask--convert the highlight color to 1's on existing mask
  383.   //
  384.   celDC.SetBkColor(GetSysColor(COLOR_BTNHIGHLIGHT));
  385.   maskDC.BitBlt(maskRect, celDC, nrmlCelRect.TopLeft(), SRCPAINT);
  386.  
  387.   //
  388.   // make the image look embossed--highlight color offset down & right
  389.   //
  390.   celDC.SetTextColor(RGB(0, 0, 0));  // 0 to black
  391.   celDC.SetBkColor(RGB(255, 255, 255));  // 1 to white
  392.  
  393.   TBrush  hiliteBrush(GetSysColor(COLOR_BTNHIGHLIGHT));
  394.   celDC.SelectObject(hiliteBrush);  // 0 -> highlight color
  395.   celDC.BitBlt(celRect.left + 1, celRect.top + 1,
  396.                celRect.Width() - 1, celRect.Height() - 1,
  397.                maskDC, 0, 0, RopPSDPxax);
  398.  
  399.   //
  400.   // fade the image by replacing the button text color with the button
  401.   // shadow color
  402.   //
  403.   TBrush  shadowBrush(GetSysColor(COLOR_BTNSHADOW));
  404.   celDC.SelectObject(shadowBrush);  // 0 -> shadow
  405.   celDC.BitBlt(celRect, maskDC, TPoint(0, 0), RopPSDPxax);
  406.  
  407.   //
  408.   // CelArray[CelIndeterm]: Indeterminate variant of glyph
  409.   //
  410.   celRect = CelArray->CelRect(CelIndeterm);
  411.  
  412.   //
  413.   // fade the image by replacing the button text color with the button
  414.   // shadow color
  415.   //
  416.   celDC.SelectObject(shadowBrush);  // 0 -> shadow
  417.   celDC.BitBlt(celRect, maskDC, TPoint(0, 0), RopPSDPxax);
  418.  
  419.   //
  420.   // dither the background everywhere except where the glyph is
  421.   //
  422.   DitherBackground(celDC, maskDC, celRect);
  423.  
  424.   //
  425.   // CelArray[CelDown]: Down (but not Pressed) variant of glyph
  426.   //
  427.   celRect = CelArray->CelRect(CelDown);
  428.   celDC.BitBlt(celRect, celDC, CelArray->CelRect(CelNormal).TopLeft(), SRCCOPY);
  429.  
  430.   //
  431.   // dither the background everywhere except where the glyph is
  432.   //
  433.   BuildMask(maskDC, maskRect, celDC, celRect);
  434.   DitherBackground(celDC, maskDC, celRect);
  435.  
  436.   maskDC.RestoreBitmap();
  437.   celDC.RestoreBitmap();
  438.   celDC.RestoreBitmap();
  439.   celDC.RestoreBrush();
  440. }
  441.  
  442. //
  443. //
  444. //
  445. void
  446. TButtonGadget::Paint(TDC& dc)
  447. {
  448.   int     cxBorder = GetSystemMetrics(SM_CXBORDER);
  449.   int     cyBorder = GetSystemMetrics(SM_CYBORDER);
  450.   TPoint  bitmapOrigin = BitmapOrigin;
  451.   TRect   innerRect(cxBorder, cyBorder,
  452.                     Bounds.Width()-cxBorder, Bounds.Height()-cyBorder);
  453.  
  454.   PaintBorder(dc);  // Assumes Plain border--other styles will be overpainted
  455.  
  456.   TBrush  faceBrush(GetSysColor(COLOR_BTNFACE));
  457.   TBrush  hiliteBrush(GetSysColor(COLOR_BTNHIGHLIGHT));
  458.   TBrush  shadowBrush(GetSysColor(COLOR_BTNSHADOW));
  459.  
  460.   //
  461.   // draw top and left
  462.   //
  463.   int shadow = Pressed && Type != Command ? 2 : 1;
  464.   dc.SelectObject(Pressed || State == Down ? shadowBrush : hiliteBrush);
  465.   dc.PatBlt(innerRect.left, innerRect.top,
  466.             innerRect.Width(), shadow * cyBorder, PATCOPY);
  467.   dc.PatBlt(innerRect.left, innerRect.top,
  468.             shadow * cxBorder, innerRect.Height(), PATCOPY);
  469.  
  470.   if (Pressed || State == Down) {
  471.     innerRect.left += shadow * cxBorder;
  472.     innerRect.top += shadow * cyBorder;
  473.   }
  474.   else {
  475.     int  i = 0;
  476.  
  477.     //
  478.     // draw right and bottom
  479.     //
  480.     dc.SelectObject(shadowBrush);
  481.     innerRect.bottom -= cyBorder;
  482.     innerRect.right -= cxBorder;
  483.  
  484.     while (true) {
  485.       dc.PatBlt(innerRect.left, innerRect.bottom,
  486.                 innerRect.Width() + cxBorder, cyBorder, PATCOPY);
  487.       dc.PatBlt(innerRect.right, innerRect.top,
  488.                 cxBorder, innerRect.Height(), PATCOPY);
  489.  
  490.       if (++i == ShadowStyle)
  491.         break;
  492.  
  493.       innerRect.Inflate(-cxBorder, -cyBorder);
  494.     }
  495.   }
  496.  
  497.   if (NotchCorners || AntialiasEdges && State == Up && !Pressed) {
  498.     dc.SelectObject(faceBrush);
  499.     
  500.     if (NotchCorners) {
  501.       dc.PatBlt(0, 0, cxBorder, cyBorder);
  502.       dc.PatBlt(Bounds.Width() - cxBorder, 0, cxBorder, cyBorder);
  503.       dc.PatBlt(0, Bounds.Height() - cyBorder, cxBorder, cyBorder);
  504.       dc.PatBlt(Bounds.Width() - cxBorder, Bounds.Height() - cyBorder,
  505.                 cxBorder, cyBorder);
  506.     }
  507.     if (AntialiasEdges && State == Up && !Pressed) {
  508.       TRect edge(0, 0, Bounds.Width(), Bounds.Height());
  509.       for (int i = 0; i <= shadow; i++) {
  510.         edge.Inflate(-cxBorder,-cyBorder);
  511.         dc.PatBlt(edge.right-cxBorder, edge.top, cxBorder, cyBorder);
  512.         dc.PatBlt(edge.left, edge.bottom-cyBorder, cxBorder, cyBorder);
  513.       }
  514.     }
  515.     dc.RestoreBrush();
  516.   }
  517.  
  518.   //
  519.   // adjust the bitmap origin based on the state
  520.   //
  521.   if (Pressed || State == Down)
  522.     bitmapOrigin.Offset(shadow * cxBorder, shadow * cyBorder);
  523.   TRect  bitmapRect(bitmapOrigin, CelArray->CelSize());
  524.  
  525.   TMemoryDC celDC;
  526.   celDC.SelectObject(*CelArray);
  527.  
  528.   //
  529.   // blit the appropriate cel at the calculated origin
  530.   //
  531.   if (!GetEnabled() || State == Indeterminate) {
  532.     if (!GetEnabled())
  533.       dc.BitBlt(bitmapRect, celDC, CelArray->CelRect(CelDisabled).TopLeft());
  534.  
  535.     else //(State == Indeterminate)
  536.       dc.BitBlt(bitmapRect, celDC, CelArray->CelRect(CelIndeterm).TopLeft());
  537.   }
  538.   else {
  539.     TRect dirtyRects[4];
  540.     int   numRects = Subtract(innerRect, bitmapRect, dirtyRects);
  541.     if (numRects) {
  542.       dc.SetBkColor(GetSysColor(COLOR_BTNFACE));
  543.       while (numRects--)
  544.         dc.TextRect(dirtyRects[numRects]);
  545.     }
  546.     if (State == Down && !Pressed)
  547.       dc.BitBlt(bitmapRect, celDC, CelArray->CelRect(CelDown).TopLeft());
  548.     else //(State == Up || Pressed)
  549.       dc.BitBlt(bitmapRect, celDC, CelArray->CelRect(CelNormal).TopLeft());
  550.   }
  551.  
  552.   celDC.RestoreBitmap();
  553.   dc.RestoreBrush();
  554. }
  555.  
  556. void
  557. TButtonGadget::Invalidate()
  558. {
  559.   TRect  r(0, 0, Bounds.Width(), Bounds.Height());
  560.  
  561.   r.Inflate(-GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
  562.   InvalidateRect(r, false);
  563. }
  564.  
  565. //
  566. // Begin button pressed state, repaint & enter menuselect state
  567. //
  568. void
  569. TButtonGadget::BeginPressed(TPoint&)
  570. {
  571.   Pressed = true;
  572.   Invalidate();
  573.   Update();
  574.   if (Window->GetHintMode() == TGadgetWindow::PressHints)
  575.     Window->SetHintCommand(GetId());
  576. }
  577.  
  578. //
  579. // Cancel pressed state, repaint & end menuselect state
  580. //
  581. void
  582. TButtonGadget::CancelPressed(TPoint&)
  583. {
  584.   Pressed = false;
  585.   Invalidate();
  586.   Update();
  587.   if (Window->GetHintMode() == TGadgetWindow::PressHints)
  588.     Window->SetHintCommand(-1);
  589. }
  590.  
  591. void
  592. TButtonGadget::Activate(TPoint& pt)
  593. {
  594.   switch (Type) {
  595.     case Exclusive:
  596.       if (State != Down)
  597.         CheckExclusively();
  598.       break;
  599.  
  600.     case NonExclusive:
  601.       State = State == Up ? Down : Up;
  602.       break;
  603.   }
  604.  
  605.   CancelPressed(pt);
  606.  
  607.   if (!(Type == Exclusive && State != Down) && GetEnabled())
  608.     Window->Parent->PostMessage(WM_COMMAND, GetId());
  609. }
  610.  
  611. void
  612. TButtonGadget::LButtonDown(uint modKeys, TPoint& pt)
  613. {
  614.   TGadget::LButtonDown(modKeys, pt);
  615.   BeginPressed(pt);
  616. }
  617.  
  618. void
  619. TButtonGadget::MouseMove(uint modKeys, TPoint& pt)
  620. {
  621.   TGadget::MouseMove(modKeys, pt);
  622.  
  623.   bool  hit = PtIn(pt);
  624.   if (Pressed) {
  625.     if (!hit)
  626.       CancelPressed(pt);
  627.   }
  628.   else if (hit) {
  629.     BeginPressed(pt);
  630.   }
  631. }
  632.  
  633. void
  634. TButtonGadget::MouseEnter(uint modKeys, TPoint& pt)
  635. {
  636.   TGadget::MouseEnter(modKeys, pt);
  637.   if (Window->GetHintMode() == TGadgetWindow::EnterHints)
  638.     Window->SetHintCommand(GetId());
  639. }
  640.  
  641. void
  642. TButtonGadget::MouseLeave(uint modKeys, TPoint& pt)
  643. {
  644.   TGadget::MouseLeave(modKeys, pt);
  645.   if (Window->GetHintMode() == TGadgetWindow::EnterHints)
  646.     Window->SetHintCommand(-1);
  647. }
  648.  
  649. void
  650. TButtonGadget::LButtonUp(uint modKeys, TPoint& pt)
  651. {
  652.   TGadget::LButtonUp(modKeys, pt);
  653.   if (Pressed)
  654.     Activate(pt);
  655. }
  656.