home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / mac / UserInterface / CToolTipAttachment.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  15.3 KB  |  461 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #ifdef PowerPlant_PCH
  20. #include PowerPlant_PCH
  21. #endif
  22.  
  23. #include "CToolTipAttachment.h"
  24. #include "UGraphicGizmos.h"
  25.  
  26. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  27. //    Ñ    
  28. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  29.  
  30. Boolean CToolTipAttachment::sTipsEnabled = true;
  31. CToolTipPane* CToolTipAttachment::sActiveTip = NULL;
  32.  
  33. // This is a special value that we use to indicate that the mouse has
  34. // gone down inside a pane with a CToolTipAttachment.  The reason we need
  35. // this is because we need to reset the trigger interval when the mouse
  36. // goes up.  Since mouse up events don't trigger an attachment execution,
  37. // we look for this value during the next pass through the mouse track
  38. // dispatch and reset the interval there if necessary.
  39.  
  40. const UInt32 ToolTipsTicks_Indefinite = 0xFFFFFFFF;
  41.  
  42. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  43. //    Ñ    CToolTipAttachment
  44. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  45.  
  46. CToolTipAttachment::CToolTipAttachment(LStream* inStream)
  47.     :    CMouseTrackAttachment(inStream)
  48. {
  49.     *inStream >> mDelayTicks;
  50.     *inStream >> mTipPaneResID;
  51. }
  52.  
  53. CToolTipAttachment::CToolTipAttachment(UInt32 inDelayTicks, ResIDT inPaneResID)
  54. :    mDelayTicks(inDelayTicks)
  55. ,    mTipPaneResID(inPaneResID)
  56. {
  57. }
  58.  
  59. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  60. //    Ñ    ~CToolTipAttachment
  61. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  62.  
  63. CToolTipAttachment::~CToolTipAttachment()
  64. {
  65.     HideToolTip();
  66. }
  67.  
  68. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  69. //    Ñ    NoteTipDied
  70. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  71.  
  72. void CToolTipAttachment::NoteTipDied(CToolTipPane* inTip)
  73. {
  74.     Assert_(sActiveTip != NULL);
  75.     Assert_(sActiveTip == inTip);
  76.     
  77.     sActiveTip = NULL;
  78. }
  79.  
  80. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  81. //    Ñ    ExecuteSelf
  82. //
  83. //    We add the tracking of events that should hide the current tool tip (if
  84. //    any) to the base CMouseTrackerAttachment execution.
  85. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  86.  
  87. void CToolTipAttachment::ExecuteSelf(
  88.     MessageT            inMessage,
  89.     void*                ioParam)
  90. {
  91.     if ((inMessage == msg_KeyPress) && IsToolTipActive())
  92.         {
  93.         // We hide the tip, but updating is deferred in an update
  94.         // event.
  95.         HideToolTip();
  96.         }
  97.     else if (inMessage == msg_Click)
  98.         {
  99.         // Hide the tip, and in this case we want to immediately update
  100.         // the space occupied by the removed tip.  We do this because we
  101.         // know that the tip is essentially guaranteed to be in close
  102.         // proximity to the cursor.
  103.         
  104.         if (IsToolTipActive())
  105.             {
  106.             HideToolTip();
  107.             mOwningPane->UpdatePort();
  108.             }
  109.         
  110.         // Here we note that the mouse has gone down.  We reset the interval
  111.         // on the next pass through MouseWithin().
  112.         ResetTriggerInterval(ToolTipsTicks_Indefinite);
  113.         }
  114.     else if ( inMessage == msg_HideTooltip )
  115.         HideToolTip();
  116.     else
  117.         CMouseTrackAttachment::ExecuteSelf(inMessage, ioParam);
  118. }
  119.  
  120. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  121. //    Ñ    MouseEnter
  122. //
  123. //    All we need to do here is note the time that the mouse entered the pane.
  124. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  125.  
  126. void CToolTipAttachment::MouseEnter(
  127.     Point                /* inPortPt */,
  128.     const EventRecord&    /* inMacEvent */)
  129. {
  130.     if (!mOwningPane || !mOwningPane->IsActive() || !mOwningPane->IsEnabled())
  131.         return;
  132.  
  133.     ResetTriggerInterval(::LMGetTicks());
  134. }
  135.  
  136. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  137. //    Ñ    MouseWithin
  138. //    
  139. //    The mouse is still in the currently tracked pane.  Here we determine
  140. //    whether a tip needs to be hidden or shown.
  141. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  142.  
  143. void CToolTipAttachment::MouseWithin(
  144.     Point                /* inPortPt */,
  145.     const EventRecord&    inMacEvent)
  146. {
  147.     if (!mOwningPane || !mOwningPane->IsActive() || !mOwningPane->IsEnabled())
  148.         return;
  149.  
  150.     if (!sTipsEnabled)
  151.         return;
  152.  
  153.     // First we check the case where we just got time after a mouse track
  154.     // in the attached pane.  If so, simply reset the interval.  Otherwise
  155.     // if the user tracks for longer than the trigger interval the tip will
  156.     // display immediately after the mouse is released, which is not
  157.     // correct behaviour.
  158.     if (mEnterTicks == ToolTipsTicks_Indefinite)
  159.         ResetTriggerInterval(::LMGetTicks());
  160.         
  161.     // If the tip is active and the corresponding event is one that should
  162.     // cancel the tip, kill it.
  163.     else if (IsToolTipActive() && IsTipCancellingEvent(inMacEvent))
  164.         HideToolTip();
  165.         
  166.     // If the tip is not active and the trigger interval has elapsed
  167.     // then we need to show the new tip.
  168.     else if (!IsToolTipActive() && IsDelayElapsed(::LMGetTicks()))
  169.         ShowToolTip(inMacEvent); // pass the event, some panes need the point!
  170. }                            
  171.  
  172. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  173. //    Ñ    MouseLeave
  174. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  175.  
  176. void CToolTipAttachment::MouseLeave(void)
  177. {
  178.     if (!mOwningPane || !mOwningPane->IsActive() || !mOwningPane->IsEnabled())
  179.         return;
  180.  
  181.     HideToolTip();
  182. }
  183.  
  184. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  185. //    Ñ    IsTipCancellingEvent
  186. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  187.  
  188. Boolean CToolTipAttachment::IsTipCancellingEvent(const EventRecord& inMacEvent) const
  189. {
  190.     Boolean bShouldCancel = ((inMacEvent.what != nullEvent) &&
  191.                              (inMacEvent.what != updateEvt) &&
  192.                             ((inMacEvent.what != osEvt) || ((inMacEvent.message & osEvtMessageMask) != (mouseMovedMessage << 24))));
  193.     return bShouldCancel;
  194. }
  195.  
  196. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  197. //    Ñ    CalcTipText
  198. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  199.  
  200. void CToolTipAttachment::CalcTipText(
  201.     LWindow*                inOwningWindow,
  202.     LPane*                    inOwningPane,
  203.     const EventRecord&        inMacEvent,
  204.     StringPtr                outTipText)
  205. {
  206.     sActiveTip->CalcTipText(inOwningWindow, inOwningPane, inMacEvent, outTipText);
  207. }
  208.  
  209. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  210. //    Ñ    ShowToolTip
  211. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  212.  
  213. void CToolTipAttachment::ShowToolTip(const EventRecord&    inMacEvent)
  214. {
  215.     try
  216.         {
  217.         GrafPtr theMacPort = mOwningPane->GetMacPort();
  218.         ThrowIfNULL_(theMacPort);
  219.         
  220.         LWindow* theWindow = LWindow::FetchWindowObject(theMacPort);
  221.         ThrowIfNULL_(theWindow);
  222.  
  223.         Assert_(sActiveTip == NULL);
  224.         // This is a bit of a skanky cast.  The alternative was to call ReadObjects() and
  225.         // explicitly cast the void* (on which RTTI will not help you. This seemed to be
  226.         // the lesser of the two evils.                
  227.         sActiveTip = dynamic_cast<CToolTipPane*>(UReanimator::CreateView(mTipPaneResID, theWindow, theWindow));
  228.         ThrowIfNULL_(sActiveTip);
  229.         sActiveTip->SetParent(this);
  230.         
  231.         // Calculate the tip text first because the size and positioning rely on it.
  232.         // The practice of having the tip pane calculate the text and then have that
  233.         // same text set as its descriptor may seem weird.  It's purpose is to
  234.         // allow CToolTipPane subclasses to override the text calc method without
  235.         // overriding this class in order to alter the way it gets set.
  236.         //
  237.         // If no text is returned, abort instead of showing an empty tooltip
  238.         Str255 theTipText;
  239.         this->CalcTipText(theWindow, mOwningPane, inMacEvent, theTipText);
  240.         if ( !theTipText[0] )
  241.             throw (0);
  242.         sActiveTip->SetDescriptor(theTipText);
  243.  
  244.         Rect theTipPortFrame;
  245.         theWindow->FocusDraw();
  246.         sActiveTip->CalcFrameWithRespectTo(theWindow, mOwningPane, inMacEvent, theTipPortFrame);
  247.         
  248.         sActiveTip->ResizeFrameTo(RectWidth(theTipPortFrame), RectHeight(theTipPortFrame), false);        
  249.         sActiveTip->PlaceInSuperFrameAt(theTipPortFrame.left, theTipPortFrame.top, false);
  250.         sActiveTip->Show();
  251.         }
  252.     catch(...)    
  253.         {
  254.         delete sActiveTip;
  255.         sActiveTip = NULL;
  256.         }
  257. }
  258.  
  259. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  260. //    Ñ    HideToolTip
  261. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  262.  
  263. void CToolTipAttachment::HideToolTip(void)
  264. {
  265.     // calc the tip's port rect 
  266.     if (IsToolTipActive())
  267.         {
  268.         Rect thePortFrame;
  269.         sActiveTip->CalcPortFrameRect(thePortFrame);
  270.         sActiveTip->InvalPortRect(&thePortFrame);
  271.     
  272.         // hide the tip
  273.         delete sActiveTip;
  274.         sActiveTip = NULL;
  275.         }
  276.     
  277.     ResetTriggerInterval(::LMGetTicks());
  278. }
  279.  
  280. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  281. //    Ñ    CToolTipPane
  282. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  283.  
  284. CToolTipPane::CToolTipPane(LStream* inStream)
  285.     :    LPane(inStream)
  286. {
  287.     *inStream >> mTipTraitsID;
  288.     mParent = NULL;
  289. }
  290.  
  291. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  292. //    Ñ    ~CToolTipPane
  293. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  294.  
  295. CToolTipPane::~CToolTipPane()
  296. {
  297.     if (mParent != NULL)
  298.         mParent->NoteTipDied(this);
  299. }
  300.  
  301. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  302. //    Ñ    SetParent
  303. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  304.  
  305. void CToolTipPane::SetParent(CToolTipAttachment* inParent)
  306. {
  307.     mParent = inParent;
  308. }
  309.  
  310. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  311. //    Ñ    CalcFrameWithRespectTo
  312. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  313.  
  314. void CToolTipPane::CalcFrameWithRespectTo(
  315.     LWindow*                inOwningWindow,
  316.     LPane*                    inOwningPane,
  317.     const EventRecord&        /* inMacEvent */,
  318.     Rect&                     outPortFrame)
  319. {
  320.     StTextState theTextSaver;
  321.     UTextTraits::SetPortTextTraits(mTipTraitsID);
  322.     
  323.     FontInfo theFontInfo;
  324.     ::GetFontInfo(&theFontInfo);
  325.     Int16 theTextHeight    = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading + (2 * 2);
  326.     Int16 theTextWidth = ::StringWidth(mTip) + (2 * ::CharWidth(char_Space));
  327.     
  328.     inOwningWindow->FocusDraw();    
  329.  
  330.     Rect theOwningPortFrame;
  331.     inOwningPane->CalcPortFrameRect(theOwningPortFrame);
  332.     
  333.     outPortFrame.left = ((theOwningPortFrame.left + theOwningPortFrame.right) >> 1) - (theTextWidth >> 1);
  334.     outPortFrame.top = theOwningPortFrame.bottom + 3;
  335.     outPortFrame.right = outPortFrame.left + theTextWidth; 
  336.     outPortFrame.bottom = outPortFrame.top + theTextHeight;
  337.  
  338.     ForceInPortFrame(inOwningWindow, outPortFrame);
  339. }
  340.  
  341. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  342. //    Ñ    CalcTipText
  343. //
  344. //    The default implementation of the tool tip is to return the descriptor of
  345. //    the pane that owns it.  If you need a different behaviour, sublclass the
  346. //    CToolTipPane (not the attachment), and override this method.  See notes
  347. //    in the header file.
  348. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  349.  
  350. void CToolTipPane::CalcTipText(
  351.     LWindow*    /* inOwningWindow */,
  352.     LPane*        inOwningPane,
  353.     const EventRecord&    /* inMacEvent */,
  354.     StringPtr    outTipText)
  355. {
  356.     inOwningPane->GetDescriptor(outTipText);
  357. }
  358.  
  359. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  360. //    Ñ    ForceInPortFrame
  361. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  362.  
  363. void CToolTipPane::ForceInPortFrame(
  364.     LWindow*                inOwningWindow,
  365.     Rect&                    ioTipFrame)
  366. {
  367.     // Now make sure the tip is fits inside the owning window    
  368.     Rect theWindowPortFrame;
  369.     inOwningWindow->CalcPortFrameRect(theWindowPortFrame);
  370.     
  371.     Int16 theHOffset = 0, theVOffset = 0;
  372.     
  373.     if (ioTipFrame.right > theWindowPortFrame.right)
  374.         theHOffset = theWindowPortFrame.right - ioTipFrame.right;        // bump it to the left
  375.     else if (ioTipFrame.left < theWindowPortFrame.left)
  376.         theHOffset = theWindowPortFrame.left - ioTipFrame.left;        // bump it to the right
  377.         
  378.     if (ioTipFrame.bottom > theWindowPortFrame.bottom)
  379.         theVOffset = theWindowPortFrame.bottom - ioTipFrame.bottom;    // bump it up
  380.     else if (ioTipFrame.top < theWindowPortFrame.top)
  381.         theVOffset = theWindowPortFrame.top - ioTipFrame.top;            // bump it down
  382.  
  383.     if ((theHOffset != 0) || (theVOffset != 0))
  384.         ::OffsetRect(&ioTipFrame, theHOffset, theVOffset);
  385. }
  386.  
  387. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  388. //    Ñ    SetDescriptor
  389. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  390.  
  391. void CToolTipPane::SetDescriptor(ConstStringPtr inDescriptor)
  392. {
  393.     mTip = inDescriptor;
  394. }
  395.  
  396. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  397. //    Ñ    DrawSelf
  398. //    
  399. //    This is the default drawing of the tip pane.  To change tip appearance
  400. //    override this method.
  401. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  402.  
  403. void CToolTipPane::DrawSelf(void)
  404. {
  405.     StColorPenState thePenSaver;
  406.     thePenSaver.Normalize();
  407.     
  408.     Rect theFrame;
  409.     CalcLocalFrameRect(theFrame);
  410.     
  411.     // Ñ Setup a device loop so that we can handle drawing at the correct bit depth
  412.     StDeviceLoop    theLoop ( theFrame );
  413.     Int16            depth;
  414.     while ( theLoop.NextDepth ( depth )) 
  415.     {
  416.         if ( depth < 4 )        // Ñ BLACK & WHITE
  417.         {
  418.             ::EraseRect(&theFrame);
  419.             ::FrameRect(&theFrame);
  420.         }
  421.         else
  422.         {
  423.             // We want the light tinge of the owning window.  It makes a good fill for
  424.             // the tip and is likely to look really nice as it accents the window's
  425.             // structure appearance.
  426.             RGBColor theLightTinge, theDarkTinge;
  427.             UGraphicGizmos::CalcWindowTingeColors(GetMacPort(), theLightTinge, theDarkTinge);
  428.             ::RGBForeColor(&theLightTinge);
  429.             ::PaintRect(&theFrame);
  430.         }
  431.     }
  432.     thePenSaver.Normalize();
  433.     UTextTraits::SetPortTextTraits(mTipTraitsID);
  434.     UGraphicGizmos::CenterStringInRect(mTip, theFrame);
  435. }
  436.     
  437. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  438. //    Ñ    CSharedToolTipAttachment
  439. //
  440. //    Allows many buttons to share one tooltip pane.  A ToolTipPane resource is 54
  441. //    bytes, and the only part that is unique is usually the string index/id pair.
  442. //    Using this saves making a new pain [sic] for every new button.
  443. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  444.  
  445. CSharedToolTipAttachment::CSharedToolTipAttachment(LStream* inStream)
  446.     :    CToolTipAttachment(inStream)
  447. {
  448.     *inStream >> mStringListID;
  449.     *inStream >> mStringIndex;
  450. }
  451.  
  452. void CSharedToolTipAttachment::CalcTipText(
  453.     LWindow*    /* inOwningWindow */,
  454.     LPane*        /* inOwningPane */,
  455.     const EventRecord&    /* inMacEvent */,
  456.     StringPtr    outTipText)
  457. {
  458.     ::GetIndString(outTipText, mStringListID, mStringIndex);
  459. }
  460.  
  461.