home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / OWLSRC.PAK / TOOLTIP.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  26.4 KB  |  1,093 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1995, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.31  $
  6. //
  7. // Implements the TTooltip class
  8. //----------------------------------------------------------------------------
  9. #include <owl/pch.h>
  10. #if !defined(OWL_WINDOW_H)
  11. # include <owl/window.h>
  12. #endif
  13. #if !defined(OWL_GDIOBJEC_H)
  14. # include <owl/gdiobjec.h>
  15. #endif
  16. #if !defined(OWL_TOOLTIP_H)
  17. # include <owl/tooltip.h>
  18. #endif
  19. #if !defined(OWL_COMMCTRL_H)
  20. # include <owl/commctrl.h>
  21. #endif
  22. #if !defined(WINSYS_UIMETRIC_H)
  23. # include <winsys/uimetric.h>
  24. #endif
  25.  
  26.  
  27. OWL_DIAGINFO;
  28. DIAG_DECLARE_GROUP(OwlControl);        // General Controls diagnostic group
  29.  
  30. //
  31. // Size of container of tools
  32. //
  33. const int InitSize = 5;               // Initial size of tool container
  34. const int InitDelta= 5;               // Inc/Dec of tools container
  35. const int DefDelay = 500;             // Default delay is 1/2 second
  36. const int HorzPad  = 4;               // Side pads around text of tooltip
  37. const int VertPad  = 2;               // Top/Down pads around text of tooltip
  38. const int DefTipTextCacheSize = 128;  // Default cache size of tip text
  39.  
  40. //
  41. // Timer id used by Tooltip window
  42. //
  43. const unsigned TOOLTIP_TIMERID = 0xABBA;
  44.  
  45. //
  46. // Default constructor of TToolInfo - used mainly when retrieving
  47. // information about the current tool of the tooltip control or
  48. // for initializing a brand new tool to be registered with the
  49. // control. For example,
  50. //
  51. //              TToolInfo ti(true);
  52. //              tooltip.GetCurrentTool(ti);
  53. //
  54. TToolInfo::TToolInfo(bool allocCache)
  55. {
  56.   memset(this, 0, sizeof(TOOLINFO));
  57.   cbSize = sizeof(TOOLINFO);
  58.   if (allocCache) {
  59.     CacheText = new char[DefTipTextCacheSize];
  60.     lpszText = (char*)CacheText;
  61.   }
  62. }
  63.  
  64. //
  65. // Constructor for tool implemented as rectangular area within
  66. // a window's client area. 'window' receives the 'TTN_NEEDTEXT'
  67. // notification in case of txt default to LPSTR_TEXTCALLBACK.
  68. //
  69. TToolInfo::TToolInfo(HWND window, const TRect& rc, uint toolId,
  70.                      const char* txt /*=LPSTR_TEXTCALLBACK*/)
  71. {
  72.   memset(this, 0, sizeof(TOOLINFO));
  73.   cbSize = sizeof(TOOLINFO);
  74.   SetToolInfo(window, toolId);
  75.   SetRect(rc);
  76. #if defined(BI_PLAT_WIN32)
  77.  
  78.   // NOTE: When we're using the Common Control implementation we don't want
  79.   //       to cache the text since we won't keep a copy of the TToolInfo
  80.   //       structure around.
  81.   //
  82.   SetText(txt, false);
  83. #elif defined(BI_PLAT_WIN16)
  84.   SetText(txt, true);
  85. #endif
  86. }
  87.  
  88. //
  89. // Constructor for tool implemented as rectangular area within
  90. // a window's client area. 'strRes' and 'hInst' specify a string
  91. // resource of the message to be used by the tooltip window.
  92. //
  93. TToolInfo::TToolInfo(HWND window, const TRect& rc, uint toolId,
  94.                      int strRes, HINSTANCE hInst)
  95. {
  96.   memset(this, 0, sizeof(TOOLINFO));
  97.   cbSize = sizeof(TOOLINFO);
  98.   SetToolInfo(window, toolId, rc);
  99.   SetText(strRes, hInst);
  100. }
  101.  
  102. //
  103. // Constructor for tool implemented as windows (eg. child/controls).
  104. // 'parent' receives the 'TTN_NEEDTEXT' notification in case of
  105. // 'txt' defaults to the LPSTR_TEXTCALLBACK.
  106. //
  107. TToolInfo::TToolInfo(HWND parent, HWND toolWnd,
  108.                      const char* txt /*=LPSTR_TEXTCALLBACK*/)
  109. {
  110.   memset(this, 0, sizeof(TOOLINFO));
  111.   cbSize = sizeof(TOOLINFO);
  112.   SetToolInfo(toolWnd, parent);
  113. #if defined(BI_PLAT_WIN32)
  114.   SetText(txt, false);
  115. #elif defined(BI_PLAT_WIN16)
  116.   SetText(txt, true);
  117. #endif
  118. }
  119.  
  120. //
  121. // Constructor for tool implemented as a window (child/control).
  122. // 'strRes' and 'hInst' specify a string resource to be used by
  123. // the tooltip window.
  124. //
  125. TToolInfo::TToolInfo(HWND parent, HWND toolWnd,
  126.                      int strRes, HINSTANCE hInst)
  127. {
  128.   memset(this, 0, sizeof(TOOLINFO));
  129.   cbSize = sizeof(TOOLINFO);
  130.   SetToolInfo(toolWnd, parent);
  131.   SetText(strRes, hInst);
  132. }
  133.  
  134. //
  135. //
  136. //
  137. TToolInfo::TToolInfo(const TToolInfo& other)
  138. {
  139.   // Use assignment operator
  140.   //
  141.   *this = other;
  142. }
  143.  
  144. //
  145. //
  146. //
  147. TToolInfo&
  148. TToolInfo::operator =(const TToolInfo& other)
  149. {
  150.   if (&other != this) {
  151.     *((TOOLINFO*)this) = *((TOOLINFO*)&other);
  152.     if (other.lpszText == other.GetCacheText())
  153.       SetText(other.GetCacheText());
  154.     /***
  155.     else
  156.      'other.lpszText' is assumed to be NULL, LPSTR_CALLBACK or pointing
  157.       to a buffer with a long lifetime. In all three cases a shallow copy of
  158.       the pointer is safe.
  159.     ***/
  160.   }
  161.   return *this;
  162. }
  163.  
  164. //
  165. //
  166. //
  167. void
  168. TToolInfo::SetToolInfo(HWND toolWin, uint id)
  169. {
  170.   PRECONDITION(::IsWindow(toolWin));
  171.   hwnd = toolWin;
  172.   uFlags &= ~TTF_IDISHWND;
  173.   uId = id;
  174. }
  175.  
  176. //
  177. //
  178. //
  179. void
  180. TToolInfo::SetToolInfo(HWND toolWin, uint id, const TRect& rc)
  181. {
  182.   SetToolInfo(toolWin, id);
  183.   SetRect(rc);
  184. }
  185.  
  186. //
  187. //
  188. //
  189. void
  190. TToolInfo::SetToolInfo(HWND toolWin, HWND parent)
  191. {
  192.   PRECONDITION(::IsWindow(toolWin));
  193.   PRECONDITION(::IsWindow(parent));
  194.   hwnd = parent;
  195.   uFlags |= TTF_IDISHWND;
  196.   uId = uint(toolWin);
  197. }
  198.  
  199. //
  200. // Sets the text of this tool by providing a buffer that contains
  201. // the string. The boolean 'copy' flag specifies whether the method
  202. // should make a local copy of the string.
  203. //
  204. void
  205. TToolInfo::SetText(const char* text, bool copy)
  206. {
  207.   if (text == LPSTR_TEXTCALLBACK || !text || !copy) {
  208.     lpszText = (char*)text;
  209.     CacheText= 0;
  210.   }
  211.   else {
  212.     CacheText = strnewdup(text);
  213.     lpszText = (char*)CacheText;
  214.   }
  215. }
  216.  
  217. //
  218. // This method returns the actual HWND linked to a tool. For tools
  219. // implemented as a rectangle within a client area, the window's
  220. // handle is returned. For tools associated with a control, the handle
  221. // of the control is returned.
  222. //
  223. HWND
  224. TToolInfo::GetToolWindow() const
  225. {
  226.   return (uFlags & TTF_IDISHWND) ? HWND(uId) : hwnd;
  227. }
  228.  
  229. //
  230. // This method retrieves the actual RECT  linked to a tool. For tools
  231. // implemented as a rectangle within a client area, that rectangle
  232. // is retrieved. For tools associated with a control, the latter's client
  233. // area is retrieved.
  234. //
  235. void
  236. TToolInfo::GetToolRect(TRect& rc) const
  237. {
  238.   if (uFlags & TTF_IDISHWND) {
  239.     CHECK(::IsWindow(HWND(uId)));
  240.     ::GetClientRect(HWND(uId), &rc);
  241.   }
  242.   else {
  243.     rc = rect;
  244.   }
  245. }
  246.  
  247. //
  248. // This method determines whether a particular location of a window is
  249. // relevant to this tool. For tools implemented as a rectangle within
  250. // a window's client area, we simply check that 'pt' is within that
  251. // rectangle. For tools representing a child window, we check that
  252. // 'pt' is within the client area of the child window.
  253. // NOTE: 'pt' must be relative to the window's client area...
  254. // Returns true if succesful or false otherwise.
  255. //
  256. bool
  257. TToolInfo::IsPointInTool(HWND win, const TPoint& pt) const
  258. {
  259.   HWND window = GetToolWindow();
  260.   if (window == win) {
  261.     TRect rc;
  262.     GetToolRect(rc);
  263.     if (rc.Contains(pt))
  264.       return true;
  265.   }
  266.   return false;
  267. }
  268.  
  269. //----------------------------------------------------------------------------
  270. // TTooltipText
  271. //
  272.  
  273. //
  274. // Sets text of tooltip to specified buffer.
  275. // NOTE: The buffer pointed to by the specified parameter must be
  276. //       valid for as long as the TTooltipText points to it.
  277. //       For temporary buffers, use the 'CopyText' method instead.
  278. //
  279. void
  280. TTooltipText::SetText(char* buff)
  281. {
  282.   lpszText = buff;
  283. }
  284.  
  285. //
  286. // Sets the text of the tooltip. The text is copied into the
  287. // buffer owned by the 'TTooltipText'.
  288. //
  289. void
  290. TTooltipText::CopyText(const char* text)
  291. {
  292.   strncpy(szText, text, sizeof(szText));
  293. }
  294.  
  295. //
  296. // Sets the text of the tooltip. The 'resId' identifies a string resource
  297. // found in the module pointed to by the 'hInstance' parameter.
  298. //
  299. void
  300. TTooltipText::SetText(int resId, HINSTANCE hInstance)
  301. {
  302.   lpszText = CONST_CAST(char far*, MAKEINTRESOURCE(resId));
  303.   hinst = hInstance;
  304. }
  305.  
  306. //----------------------------------------------------------------------------
  307. // TTooltipEnabler
  308. //
  309.  
  310. //
  311. // Construct enabler object to be sent to a window so that the latter
  312. // can provide the text of the specified tool.
  313. //
  314. TTooltipEnabler::TTooltipEnabler(TTooltipText& tt, HWND hReceiver)
  315. :
  316.   TCommandEnabler(tt.hdr.idFrom, hReceiver),
  317.   TipText(tt)
  318. {
  319. }
  320.  
  321. //
  322. // Sets the text of the tool specified by the TTooltipEnabler object.
  323. // NOTE: The text is copied to the TTooltopText structure.
  324. //
  325. void
  326. TTooltipEnabler::SetText(const char far* text)
  327. {
  328.   TipText.CopyText(text);
  329. }
  330.  
  331. //
  332. // Place-holder function - Does nothing...
  333. //
  334. void
  335. TTooltipEnabler::SetCheck(int /*check*/)
  336. {
  337. }
  338.  
  339. //----------------------------------------------------------------------------
  340. // TTooltip
  341. //
  342.  
  343. //
  344. // Constructor for TTooltip
  345. //
  346. // Initializes its data fields using parameters passed and default values
  347. //
  348. // By default, a Tooltip associated with the TTooltip will:
  349. //   - be active regardless of whether its owner is active or inactive
  350. //
  351. TTooltip::TTooltip(TWindow* parent, bool alwaysTip, TModule* module)
  352.          :TControl(parent, 0, "", 0, 0, 0, 0, module)
  353. {
  354.   Attr.Style = (WS_POPUP | WS_DISABLED);
  355.  
  356.  
  357.   if (alwaysTip)
  358.     Attr.Style |= TTS_ALWAYSTIP;
  359.  
  360. #if defined(BI_PLAT_WIN16)
  361.  
  362.   Attr.Style |= WS_BORDER;
  363.  
  364. #elif defined(BI_PLAT_WIN32)
  365.  
  366.   if (TSystem::Has3dUI())
  367.     Attr.ExStyle |= WS_EX_WINDOWEDGE;
  368.   else
  369.     Attr.Style |= WS_BORDER;
  370.  
  371. #endif
  372.  
  373.   Attr.ExStyle |= WS_EX_TOPMOST;
  374.  
  375.   // Use Native implementation if available
  376.   //
  377.   NativeUse = TCommCtrl::IsAvailable() ? nuAlways : nuNever;
  378.  
  379. #if defined(BI_PLAT_WIN16)
  380.  
  381.   // When running in an environment where the system does not provide
  382.   // Common Controls we need to initialize the variables used for
  383.   // emulating a tabcontrol...
  384.   //
  385.   Init();
  386.  
  387. #elif defined(BI_PLAT_WIN32)
  388.  
  389.   // For 32-bit platforms we rely on the Common Control Library
  390.   //
  391.   CHECK(TCommCtrl::IsAvailable());
  392. #endif
  393. }
  394.  
  395. #if defined(BI_PLAT_WIN32)
  396. //
  397. // Constructor to alias a non-OWL TOOLTIP control. Specially useful when
  398. // used with controls that automatically create a tooltip (eg TabControls
  399. // with TCS_TOOLTIPS style).
  400. //
  401. TTooltip::TTooltip(THandle handle, TModule* module)
  402. :
  403.   TControl(handle, module)
  404. {
  405.   PRECONDITION(handle);
  406.   CHECK(TCommCtrl::IsAvailable());
  407. }
  408. #endif
  409.  
  410. //
  411. // Destructor of TTooltip class.
  412. //
  413. TTooltip::~TTooltip()
  414. {
  415. #if defined(BI_PLAT_WIN16)
  416.   Cleanup();
  417. #endif
  418. }
  419.  
  420. //
  421. // Returns the native class of the tooltip control or the class
  422. // implementing OWL's version of tooltips.
  423. //
  424. char far*
  425. TTooltip::GetClassName()
  426. {
  427. #if defined(BI_PLAT_WIN32)
  428.  
  429.   PRECONDITION(TCommCtrl::IsAvailable());
  430.   return TOOLTIPS_CLASS;
  431.  
  432. #elif defined(BI_PLAT_WIN16)
  433.  
  434.   // OWL implements tooltips in 16-bit
  435.   //
  436.   return "OWL_Tooltip";
  437. #endif
  438. }
  439.  
  440. //----------------------------------------------------------------------------
  441. // The following is only relevant if the 'TTooltip' object needs to be
  442. // flexible and support cases where the OS does not provide the underlying
  443. // implementation of TOOLTIPS.
  444. //
  445. #if defined(BI_PLAT_WIN16)
  446.  
  447. //
  448. // Message Response Table of TTooltip...
  449. //
  450. DEFINE_RESPONSE_TABLE1(TTooltip, TControl)
  451.   EV_WM_TIMER,
  452.   EV_WM_SETTEXT,
  453.   EV_WM_SETFONT,
  454.   EV_WM_GETFONT,
  455.   EV_WM_LBUTTONDOWN,
  456.   EV_WM_RBUTTONDOWN,
  457. END_RESPONSE_TABLE;
  458.  
  459. //
  460. // Activates or deactivates the tooltip control. If 'activate' is true,
  461. // the tooltip control is activated, If it is false the tooltip control
  462. // is deactivated.
  463. //
  464. void
  465. TTooltip::Activate(bool activate)
  466. {
  467.   Active = activate;
  468. }
  469.  
  470. //
  471. // Registers a tool with the tooltip control. The 'TToolInfo' parameter
  472. // contains information that the tooltip control needs to display text
  473. // for the tool.
  474. // NOTE: This method does not check for duplicate tool ids!
  475. //
  476. bool
  477. TTooltip::AddTool(const TToolInfo& ti)
  478. {
  479.   ToolList->Append(new TToolInfo(ti));
  480.   return true;
  481. }
  482.  
  483. //
  484. // Removes a tool from the tooltip control. You must invoke the
  485. // 'SetToolInfo' method of TToolInfo to identify the tool to remove.
  486. // [i.e. the 'hwnd' or 'uId' members of the TToolInfo must identify the tool].
  487. //
  488. void
  489. TTooltip::DeleteTool(const TToolInfo& ti)
  490. {
  491.   // Make sure we don't hang on to a dangling pointer
  492.   //
  493.   if (&ti == ActiveTool)
  494.     ActiveTool = 0;
  495.   if (&ti == PotentialTool)
  496.     PotentialTool = 0;
  497.  
  498.   int i;
  499.   for (i=0; i<ToolList->GetCount(); i++) {
  500.     if ((*ToolList)[i] == ti) {
  501.       ToolList->FreeAt(i);
  502.       break;
  503.     }
  504.   }
  505.   WARNX(OwlControl, i==ToolList->GetCount(), 0, "Unable to delete tool");
  506. }
  507.  
  508. //
  509. // Retrieves the information that the tooltip control maintains
  510. // about the specified tool. Returns true if successul or false otherwise.
  511. // NOTE: The index is zero-based and the TToolInfo structure receives
  512. //       the information about the tool.
  513. //
  514. bool
  515. TTooltip::EnumTools(uint index, TToolInfo& ti) const
  516. {
  517.   if (index < ToolList->GetCount()) {
  518.     ti = (TToolInfo&)((*ToolList)[index]);
  519.     return true;
  520.   }
  521.   TRACEX(OwlControl, 0, "EnumTools: Invalid index specified");
  522.   return false;
  523. }
  524.  
  525. //
  526. // Retrieves information about the current tool. The 'TToolInfo'
  527. // parameter receives the information. Returns true if successful or
  528. // false otherwise.
  529. //
  530. bool
  531. TTooltip::GetCurrentTool(TToolInfo& /*ti*/) const
  532. {
  533.   TRACEX(OwlControl, 0, "TTooltip::GetCurrentTool requires system "\
  534.                         "implementation of tooltips");
  535.   return false;
  536. }
  537.  
  538. //
  539. // Retrieves the text associated with the specified tool. You must
  540. // invoke the 'SetToolInfo' of the TToolInfo object to identify the tool.
  541. // [i.e. the 'hwnd' or 'uId' members of the TToolInfo must identify the tool].
  542. //
  543. void
  544. TTooltip::GetToolText(TToolInfo& ti) const
  545. {
  546.   int i;
  547.   for (i=0; i<ToolList->GetCount(); i++) {
  548.     if ((*ToolList)[i] == ti) {
  549.       ti.lpszText = ((*ToolList)[i]).lpszText;
  550.       break;
  551.     }
  552.   }
  553.   WARNX(OwlControl, i==ToolList->GetCount(), 0, "Tool text not found");
  554. }
  555.  
  556. //
  557. // Returns the number of tools currently registered with the
  558. // tooltip control.
  559. //
  560. uint
  561. TTooltip::GetToolCount() const
  562. {
  563.   return ToolList->GetCount();
  564. }
  565.  
  566. //
  567. // Retrieves the information that the tooltip control maintains about
  568. // a tool. You must invoke the 'SetToolInfo' of TToolInfo object to identify
  569. // the tool. [i.e. the 'hwnd' or 'uId' members of the TToolInfo must
  570. // identify the tool].
  571. //
  572. bool
  573. TTooltip::GetToolInfo(TToolInfo& ti) const
  574. {
  575.   for (int i=0; i<ToolList->GetCount(); i++) {
  576.     if ((*ToolList)[i] == ti) {
  577.       ti = (TToolInfo&)((*ToolList)[i]);
  578.       return true;
  579.     }
  580.   }
  581.   TRACEX(OwlControl, 0, "GetToolInfo: tool not found");
  582.   return false;
  583. }
  584.  
  585. //
  586. // Sets the information that the tooltip control maintains for a
  587. // particular tool. You must invoke the 'SetToolInfo' of the ToolInfo object
  588. // to identify the tool.
  589. //
  590. void
  591. TTooltip::SetToolInfo(const TToolInfo& ti)
  592. {
  593.   for (int i=0; i<ToolList->GetCount(); i++) {
  594.     if ((*ToolList)[i] == ti) {
  595.       (*ToolList)[i] = ti;
  596.       return;
  597.     }
  598.   }
  599.   TRACEX(OwlControl, 0, "SetToolInfo: tool not found");
  600. }
  601.  
  602. //
  603. // Sets the text of a tool. You must invoke the 'SetToolInfo' method of
  604. // TToolInfo to identify the tool being referred to.
  605. //
  606. void
  607. TTooltip::UpdateTipText(const TToolInfo& ti)
  608. {
  609.   for (int i=0; i<ToolList->GetCount(); i++) {
  610.     if ((*ToolList)[i] == ti) {
  611.       (*ToolList)[i] = ti;
  612.       return;
  613.     }
  614.   }
  615.   TRACEX(OwlControl, 0, "UpdateTipText: tool not found");
  616. }
  617.  
  618. //
  619. // Determines whether a tool is within a specified point. The method
  620. // also retrieves information about the tool if one is identified at
  621. // that location. Returns true if a tool if found at the location or
  622. // false otherwise.
  623. //
  624. bool
  625. TTooltip::HitTest(TTooltipHitTestInfo& /*ttHTInfo*/) const
  626. {
  627.   TRACEX(OwlControl, 0, "TTooltip::HitTest requires native "\
  628.                         "implementation of tooltips");
  629.   return false;
  630. }
  631.  
  632. //
  633. // Updates the bounding rectangle of a tool. You must invoke the 'SetToolId'
  634. // method of TToolInfo to identify the tool. [i.e. the 'uId' member
  635. // of the TToolInfo must identify the tool].
  636. //
  637. void
  638. TTooltip::NewToolRect(const TToolInfo& ti)
  639. {
  640.   for (int i=0; i<ToolList->GetCount(); i++) {
  641.     if ((*ToolList)[i] == ti) {
  642.       (*ToolList)[i].rect = ti.rect;
  643.       return;
  644.     }
  645.   }
  646.   TRACEX(OwlControl, 0, "NewToolRect: tool not found");
  647. }
  648.  
  649. //
  650. // Passes a mouse message to the tooltip control for processing.
  651. //
  652. void
  653. TTooltip::RelayEvent(MSG& msg)
  654. {
  655.   if (Active) {
  656.  
  657.     // Filter messages and pass on interesting ones...
  658.     //
  659.     switch(msg.message) {
  660.  
  661.       case WM_MOUSEMOVE:
  662.       case WM_LBUTTONDOWN:
  663.       case WM_LBUTTONUP:
  664.       case WM_MBUTTONDOWN:
  665.       case WM_MBUTTONUP:
  666.       case WM_RBUTTONDOWN:
  667.       case WM_RBUTTONUP: {
  668.           // Compute mouse location
  669.           //
  670.           TPoint pt(LOWORD(msg.lParam), HIWORD(msg.lParam));
  671.  
  672.           // Relay the event
  673.           //
  674.           RelayEvent(msg.hwnd, msg.message, pt);
  675.         }
  676.         break;
  677.  
  678.       default:
  679.         break;
  680.     }
  681.   }
  682. }
  683.  
  684. //
  685. // Sets the initial, reshow and autopopup durations for a tooltip
  686. // control. The 'flag' parameter can be one of the following:
  687. //      TTDT_AUTOMATIC: Automatically calculates the initial. reshow
  688. //                      and autopopup duration based on 'delay'.
  689. //      TTDT_AUTOPOP:   Sets the length of time before the tooltip
  690. //                      window is hidden if the cursor remains
  691. //                      stationary in the tool's bounding rectangle
  692. //                      after the tooltip window has disappeared.
  693. //      TTDT_INITIAL:   Set the length of time that the cursor must
  694. //                      remain stationary within the bounding rectangle
  695. //                      before the tooltip window is displayed.
  696. //      TTDT_RESHOW:    Set the length of time before subsequent tooltip
  697. //                      windows are displayed when the cursor is moved
  698. //                      from one tool to another.
  699. //
  700. // NOTE: The 'delay' duration is in milliseconds.
  701. //
  702. void
  703. TTooltip::SetDelayTime(WPARAM /*flag*/, int delay)
  704. {
  705.   Delay = delay;
  706.  
  707.   // Restart timer if one's enabled
  708.   //
  709.   if (TimerEnabled) {
  710.     DisableTimer();
  711.     EnableTimer();
  712.   }
  713.  
  714.   // 'flag' is ignored when ObjectWindows provides underlying
  715.   // implementation of tooltips..
  716.   //
  717.   TRACEX(OwlControl, 0, "TTooltip::SetDelayTime: flag is ignored");
  718.  
  719. }
  720.  
  721. //----------------------------------------------------------------------------
  722. // Helper routines used by ObjectWindows' implementation of Tooltips
  723. //
  724.  
  725. //
  726. // Initialize internal variables
  727. //
  728. void
  729. TTooltip::Init()
  730. {
  731.   Active = true;
  732.   TimerEnabled = false;
  733.   Delay = DefDelay;
  734.   ToolFont = 0;
  735.   ToolList = 0;
  736.   ActiveTool = 0;
  737.   PotentialTool = 0;
  738. }
  739.  
  740. //
  741. // Cleanup internal variables
  742. //
  743. void
  744. TTooltip::Cleanup()
  745. {
  746.   delete ToolList;
  747.   delete ToolFont;
  748. }
  749.  
  750. //
  751. // Update the CLASSINFO to be registered to include SAVEBITS and
  752. // a NUL brush.
  753. //
  754. void
  755. TTooltip::GetWindowClass(WNDCLASS& wndClass)
  756. {
  757.   TControl::GetWindowClass(wndClass);
  758.   wndClass.style = CS_HREDRAW|CS_VREDRAW|CS_SAVEBITS;
  759.   wndClass.hbrBackground = 0;
  760. }
  761.  
  762. //
  763. // Overriden to initialize internal variables when providing
  764. // underlying implementation of tooltips.
  765. //
  766. void
  767. TTooltip::SetupWindow()
  768. {
  769.   TControl::SetupWindow();
  770.  
  771.   // Initialize helper objects used by OWL's implementation
  772.   //
  773.   SetBkgndColor(TColor::Transparent);
  774.   ToolFont = new TFont("MS Sans Serif", -9);
  775.   ToolList = new TCollection<TToolInfo>(InitSize, InitDelta);
  776. }
  777.  
  778. //
  779. // Overriden to cleanup internal variables when providing
  780. // underlying implementation of tooltips.
  781. //
  782. void
  783. TTooltip::CleanupWindow()
  784. {
  785.   TControl::CleanupWindow();
  786.  
  787.   // Cleanup any pending timers
  788.   //
  789.   DisableTimer();
  790. }
  791.  
  792. //
  793. // WM_PAINT Handler: displays tip if we have an active tool
  794. //
  795. void
  796. TTooltip::Paint(TDC& dc, bool /*erase*/, TRect& /*rect*/)
  797. {
  798.   if (ActiveTool) {
  799.     TRect rcClient;
  800.     GetClientRect(rcClient);
  801.  
  802.     TColor bkgColor = TColor::SysInfoBk;
  803.     TColor txtColor = TColor::SysInfoText;
  804.  
  805.     // Set up background/colours etc..
  806.     //
  807.     TBrush bkBrush(bkgColor);
  808.     dc.FillRect(rcClient, bkBrush);
  809.     dc.SetTextColor(txtColor);
  810.     dc.SetBkMode(TRANSPARENT);
  811.  
  812.     // Draw text
  813.     //
  814.     dc.SelectObject(*ToolFont);
  815.     dc.DrawText(ActiveTool->GetCacheText(), -1, rcClient,
  816.                 DT_CENTER|DT_SINGLELINE|DT_VCENTER);
  817.     dc.RestoreFont();
  818.   }
  819. }
  820.  
  821. //
  822. // Sets on a timer and updates the state variable
  823. //
  824. void
  825. TTooltip::EnableTimer()
  826. {
  827.   // Set on the timer if not already set
  828.   //
  829.   if (!TimerEnabled) {
  830.     SetTimer(TOOLTIP_TIMERID, Delay);
  831.     TimerEnabled = true;
  832.   }
  833. }
  834.  
  835. //
  836. // Kills the timer if it was enabled
  837. //
  838. void
  839. TTooltip::DisableTimer()
  840. {
  841.   if (TimerEnabled) {
  842.     KillTimer(TOOLTIP_TIMERID);
  843.     TimerEnabled = false;
  844.   }
  845. }
  846.  
  847. //
  848. // WM_TIMER Handler: Display a tip if the appropriate timeout has
  849. //                   occur for a tool.
  850. //
  851. void
  852. TTooltip::EvTimer(uint timerId)
  853. {
  854.   // Check for out timerID - just in case
  855.   //
  856.   if (timerId == TOOLTIP_TIMERID) {
  857.  
  858.     // Retrieve current location of cursor
  859.     //
  860.     TPoint curLoc;
  861.     GetCursorPos(curLoc);
  862.  
  863.     // If we've been waiting on a tool, check & tip it
  864.     //
  865.     if (!ActiveTool) {
  866.       if (PotentialTool) {
  867.         if (curLoc == MouseLoc) {
  868.           // Update tool pointers
  869.           //
  870.           ActiveTool = PotentialTool;
  871.           PotentialTool = 0;
  872.           ShowActiveTip(curLoc);
  873.         }
  874.       }
  875.     }
  876.     else {
  877.       // Check if mouse is still within the ActiveTool and hide tip if not
  878.       //
  879.       HWND hwnd = WindowFromPoint(curLoc);
  880.       if (hwnd)
  881.         ::MapWindowPoints(HWND_DESKTOP, hwnd, LPPOINT(&curLoc), 1);
  882.       if (!ActiveTool->IsPointInTool(hwnd, curLoc)) {
  883.         ActiveTool = 0;
  884.         HideActiveTip();
  885.       }
  886.     }
  887.   }
  888. }
  889.  
  890. //
  891. // WM_GETFONT Handler: Return font used by tooltip
  892. //
  893. HFONT
  894. TTooltip::EvGetFont()
  895. {
  896.   HFONT hFont = (ToolFont && HFONT(*ToolFont)) ? HFONT(*ToolFont) :
  897.                 HFONT(GetStockObject(ANSI_VAR_FONT));
  898.   return hFont;
  899. }
  900.  
  901. //
  902. // WM_SETFONT Handler: Sets a new font to be used by handler
  903. //
  904. void
  905. TTooltip::EvSetFont(HFONT hFont, bool /*redraw*/)
  906. {
  907.   delete ToolFont;
  908.   ToolFont = hFont ? new TFont(hFont) : (TFont*)0;
  909.  
  910.   //
  911.   //
  912.   // if (redraw)
  913.   //   Invalidate();
  914. }
  915.  
  916. //
  917. // WM_LBUTTONDOWN handler
  918. //
  919. void
  920. TTooltip::EvLButtonDown(uint /*modKeys*/, TPoint& /*point*/)
  921. {
  922.   // NOP
  923. }
  924.  
  925. //
  926. // WM_RBUTTONDOWN handler
  927. //
  928. void
  929. TTooltip::EvRButtonDown(uint /*modKeys*/, TPoint& /*point*/)
  930. {
  931.   // NOP
  932. }
  933.  
  934.  
  935. //
  936. // Checked relayed event and filter the ones that matter to the
  937. // tooltip.
  938. //
  939. void
  940. TTooltip::RelayEvent(HWND receiver, uint msg, const TPoint& pt)
  941. {
  942.   // If there's a current active tool, validate it based on the current event.
  943.   // Hide and reset the current active tool if necessary.
  944.   //
  945.   if (ActiveTool) {
  946.     if (!ActiveTool->IsPointInTool(receiver, pt)) {
  947.       ActiveTool = 0;
  948.       HideActiveTip();
  949.     }
  950.   }
  951.  
  952.   // If there are no current active tools, validate any 'pending' tool or look
  953.   // for a new 'pending' tool.
  954.   //
  955.   if (!ActiveTool && msg == WM_MOUSEMOVE) {
  956.     if (!PotentialTool || !PotentialTool->IsPointInTool(receiver, pt)) {
  957.  
  958.       // Reset the 'pending' tool pointer and stop the timer
  959.       //
  960.       PotentialTool = 0;
  961.       DisableTimer();
  962.  
  963.       // Scan for a new tool, if found, save the current mouse location and
  964.       // restart the timer.
  965.       //
  966.       for (int i=0; i<ToolList->GetCount(); i++) {
  967.         TToolInfo& tool = (*ToolList)[i];
  968.         if (tool.IsPointInTool(receiver, pt)) {
  969.           PotentialTool = &tool;
  970.           EnableTimer();
  971.           break;
  972.         }
  973.       }
  974.     }
  975.   }
  976.  
  977.   // If we have a potential tool but no active tool, update the mouse location
  978.   //
  979.   if (!ActiveTool && PotentialTool)
  980.     GetCursorPos(MouseLoc);
  981.  
  982.   // Kill the timer if we have neither a potential nor active tool
  983.   //
  984.   if (!PotentialTool && !ActiveTool)
  985.     DisableTimer();
  986. }
  987.  
  988. //
  989. // Displays the tip of the current tool at the specified location, if we
  990. // have the hint text.
  991. //
  992. void
  993. TTooltip::ShowActiveTip(TPoint& pt)
  994. {
  995.   PRECONDITION(ActiveTool);
  996.  
  997.   char* tipText   = 0;
  998.   HINSTANCE hInst = 0;
  999.   uint strResId   = 0;
  1000.   TTooltipText ttText;
  1001.  
  1002.   // Retrieve text if necessary
  1003.   //
  1004.   if (ActiveTool->lpszText == LPSTR_TEXTCALLBACK) {
  1005.     CHECK(::IsWindow(ActiveTool->hwnd));
  1006.  
  1007.     memset(&ttText, 0, sizeof(ttText));
  1008.     ttText.hdr.hwndFrom = GetHandle();
  1009.     ttText.hdr.idFrom = ActiveTool->uId;
  1010.     ttText.hdr.code = TTN_NEEDTEXT;
  1011.     ttText.uFlags = ActiveTool->uFlags;
  1012.     ::SendMessage(ActiveTool->hwnd, WM_NOTIFY, WPARAM(ActiveTool->uId),
  1013.                   LPARAM(&ttText));
  1014.  
  1015.     // Check if text is being provided via a resource
  1016.     // NOTE: Non null 'hinst' implies 'lpszText' is a string resource
  1017.     //       identifier.
  1018.     //
  1019.     if (ttText.hinst && ttText.lpszText) {
  1020.       hInst = ttText.hinst;
  1021.       strResId = LOWORD(ttText.lpszText);
  1022.     }
  1023.     else if (ttText.szText[0]) {
  1024.       tipText = ttText.szText;
  1025.     }
  1026.     else if (ttText.lpszText) {
  1027.       tipText = ttText.lpszText;
  1028.     }
  1029.   }
  1030.   else if (ActiveTool->hinst && ActiveTool->lpszText) {
  1031.     hInst = ActiveTool->hinst;
  1032.     strResId = LOWORD(ActiveTool->lpszText);
  1033.   }
  1034.  
  1035.   // Load string from resource, if necessary
  1036.   //
  1037.   if (hInst && strResId) {
  1038.     if (LoadString(hInst, strResId, ttText.szText, sizeof(ttText.szText)))
  1039.       tipText = ttText.szText;
  1040.   }
  1041.  
  1042.   // If we don't have any text, abort operation
  1043.   //
  1044.   if (!tipText && !ActiveTool->GetCacheText())
  1045.     return;
  1046.  
  1047.   // Cache newly retrieve tip text
  1048.   //
  1049.   if (tipText)
  1050.     ActiveTool->SetText(tipText);
  1051.  
  1052.   // Now that we've cached the text, compute the size of the display
  1053.   //
  1054.   TSize size; {
  1055.     TClientDC dc(*this);
  1056.     dc.SelectObject(*ToolFont);
  1057.     dc.GetTextExtent(ActiveTool->GetCacheText(),
  1058.                      strlen(ActiveTool->GetCacheText()),
  1059.                      size);
  1060.     dc.RestoreFont();
  1061.   }
  1062.  
  1063.   // Add some padding - position tip...
  1064.   //
  1065.   size.cx += HorzPad*2;
  1066.   size.cy += VertPad*2;
  1067.   if (pt.y + size.cy + TUIMetric::CyMenu < TUIMetric::CyScreen)
  1068.     pt.y += TUIMetric::CyMenu;
  1069.   else
  1070.     pt.y -= TUIMetric::CyMenu;
  1071.   if (pt.x + size.cx > TUIMetric::CxScreen)
  1072.     pt.x = TUIMetric::CxScreen - size.cx;
  1073.  
  1074.   // Move & Display tip...
  1075.   //
  1076.   TRect rcLoc(pt, size);
  1077.   SetWindowPos(HWND_TOPMOST, rcLoc, SWP_NOACTIVATE|SWP_SHOWWINDOW);
  1078.   UpdateWindow();
  1079. }
  1080.  
  1081. //
  1082. // Hides the tooltip window
  1083. //
  1084. void
  1085. TTooltip::HideActiveTip()
  1086. {
  1087.   // Hide tooltip window
  1088.   //
  1089.   ShowWindow(SW_HIDE);
  1090. }
  1091.  
  1092. #endif  //  BI_PLAT_WIN16
  1093.