tooltip.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:14k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: tooltip.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 21:09:23  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.10
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: tooltip.cpp,v 1000.1 2004/06/01 21:09:23 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Authors:  Andrey Yazhuk
  35.  *
  36.  * File Description:
  37.  */
  38. #include <ncbi_pch.hpp>
  39. #include <gui/widgets/fl/tooltip.hpp>
  40. #include <FL/fl_draw.H>
  41. #include <FL/forms.H>
  42. BEGIN_NCBI_SCOPE
  43. ////////////////////////////////////////////////////////////////////////////////
  44. /// CTooltip
  45. CTooltip::CTooltip()
  46. :   m_bActiveMode(false),
  47.     m_Mode(eHideOnMove),
  48.     m_Delay(0.8f),
  49.     m_bEnabled(true),
  50.     m_Widget(NULL), 
  51.     m_TooltipWidget(NULL),
  52.     m_bRecentTooltip(0),    
  53.     m_bRecursion(0)
  54. {
  55.     m_Color = fl_color_cube(FL_NUM_RED - 1, FL_NUM_GREEN - 1, FL_NUM_BLUE - 2);
  56.     m_TextColor = FL_BLACK;
  57.     m_Font = FL_HELVETICA;
  58.     m_FontSize = FL_SMALL_SIZE;
  59. }
  60. CTooltip::~CTooltip()
  61. {
  62.     Deactivate(true);
  63.     delete m_TooltipWidget;
  64. }
  65. void    CTooltip::SetMode(EMode mode)
  66. {
  67.     m_Mode = mode;
  68. }
  69. CTooltip::EMode   CTooltip::GetMode() const
  70. {
  71.     return m_Mode;
  72. }
  73. float CTooltip::GetDelay()  const   
  74.     return m_Delay; 
  75. }
  76. void  CTooltip::SetDelay(float delay) 
  77.     m_Delay = delay; 
  78. }
  79. int   CTooltip::IsEnabled()   const   
  80.     return m_bEnabled; 
  81. }
  82. void  CTooltip::Enable(bool b_en) 
  83.     m_bEnabled = b_en;
  84. }
  85. void  CTooltip::Disable() 
  86.     m_bEnabled = false; 
  87. }
  88. Fl_Widget* CTooltip::current() 
  89.     return m_Widget;    
  90. }
  91. int   CTooltip::GetFont()   const   
  92.     return m_Font; 
  93. }
  94. void  CTooltip::SetFont(int font) 
  95.     m_Font = font;     
  96. int   CTooltip::GetFontSize()   const   
  97.     return m_FontSize; 
  98. }  
  99. void  CTooltip::SetFontSize(int size) 
  100.     m_FontSize = size; 
  101. }
  102. void  CTooltip::SetColor(Fl_Color color)    
  103.     m_Color = color; 
  104. }
  105. Fl_Color CTooltip::GetColor()  const    
  106.     return m_Color; 
  107. }
  108. void CTooltip::SetTextColor(Fl_Color color) 
  109.     m_TextColor = color; 
  110. }
  111. Fl_Color  CTooltip::GetTextColor()  const 
  112.     return m_TextColor; 
  113. }
  114. const string&   CTooltip::GetText()   const
  115. {
  116.     return m_Text;
  117. }
  118. void    CTooltip::Activate(Fl_Widget* client, const string& text, int x, int y, int w, int h)
  119. {
  120.     _ASSERT(client);
  121.     _ASSERT(! m_bActiveMode);
  122.     
  123.     Fl::belowmouse(client);
  124.     x_Activate(client, x, y, w, h, text.c_str());
  125. }
  126. // hides tooltip
  127. void    CTooltip::Deactivate(bool b_reset)
  128. {
  129.     Fl::remove_timeout(ShowTooltipTimeout);
  130.     if(m_Widget  ||  x_IsTooltipVisible()) {
  131.         /// hide tooltip and remove timer callbacks
  132.         if(x_IsTooltipVisible())     {
  133.             m_TooltipWidget->hide();
  134.         }
  135.     
  136.         if(m_bRecentTooltip) { //needs to be reset
  137.             if(b_reset) {
  138.                 m_bRecentTooltip = 0;  // clear immediately
  139.             } else {
  140.                 Fl::add_timeout(.2f, ClearRecentTimeout, this); // clear after 0.2 sec
  141.             }
  142.         }
  143.         m_Widget = NULL;
  144.     }
  145. }
  146. bool    CTooltip::x_IsTooltipVisible()
  147. {
  148.     return m_TooltipWidget  &&  m_TooltipWidget->visible();
  149. }
  150. void  CTooltip::x_Activate(Fl_Widget* client, int x, int y, int w,int h, const string& text)
  151. {
  152.     _ASSERT(! m_bActiveMode);
  153.     if(IsEnabled()  &&  ! m_bRecursion) {
  154.         bool b_changed = client != m_Widget  ||  text != m_Text 
  155.                         ||  x != m_X  ||  y != m_Y 
  156.                         ||  w != m_W  ||  h != m_H;
  157.         bool b_pos_changed = (m_MouseX != Fl::event_x()  || m_MouseY != Fl::event_y());
  158.         bool b_active = m_TooltipWidget  && m_TooltipWidget->visible();
  159.         ETooltipCmd cmd = eDoNothing;
  160.         if(m_Mode == eHideOnMove)  {
  161.             if(!b_active  || b_changed  ||  b_pos_changed)  {
  162.                 cmd = eShowDelayed;
  163.             }
  164.         } else {
  165.             if(b_active)    {
  166.                 if(b_changed  ||  (m_Mode == eTrackOnMove  &&  b_pos_changed))   {
  167.                     cmd = eUpdateAndMove;
  168.                 }
  169.             } else {
  170.                 cmd = m_bRecentTooltip ? eUpdateAndMove : eShowDelayed;
  171.             }
  172.         }
  173.             
  174.         if(cmd != eDoNothing)   {
  175.             Fl::remove_timeout(ShowTooltipTimeout);
  176.             Fl::remove_timeout(ClearRecentTimeout);
  177.         
  178.             m_Widget = client; 
  179.                     
  180.             m_X = x; 
  181.             m_Y = y; 
  182.             m_W = w; 
  183.             m_H = h; 
  184.             m_MouseX = Fl::event_x();
  185.             m_MouseY = Fl::event_y();
  186.             m_Text = text;
  187.         }
  188.         switch(cmd)  {
  189.         case eUpdateAndMove: {
  190.             x_UpdateTooltipWidget(cmd); // show immediately
  191.         };  break;
  192.         case eShowDelayed: {
  193.             if(m_TooltipWidget  &&  m_TooltipWidget->visible())     {
  194.                 m_TooltipWidget->hide();            
  195.             }
  196.             Fl::add_timeout(m_Delay, ShowTooltipTimeout, this); // show after delay
  197.         }; break;
  198.         default: break;
  199.         }
  200.     }
  201. }
  202. // callback for "recent" timer - after specified delay cleans m_bRecentTooltip 
  203. void CTooltip::ClearRecentTimeout(void* ptr) 
  204. {
  205.     CTooltip* pTooltip = reinterpret_cast<CTooltip*>(ptr);
  206.     _ASSERT(pTooltip);
  207.     pTooltip->m_bRecentTooltip = 0;
  208. }
  209. // callback for "delay" timer
  210. void CTooltip::ShowTooltipTimeout(void* ptr) 
  211. {
  212.     CTooltip* pTooltip = reinterpret_cast<CTooltip*>(ptr);
  213.     _ASSERT(pTooltip);
  214.     if(pTooltip->m_bActiveMode)   { // ask the client and may be show tooltip
  215.         pTooltip->x_AskClientAndUpdate();
  216.     } else { // we know that tootlip must be shown
  217.         pTooltip->x_UpdateTooltipWidget(eShowDelayed);
  218.     }
  219. }
  220. bool    CTooltip::EnableActiveMode(ITooltipClient* client)
  221. {
  222.     if(client)  {
  223.         Deactivate(true);
  224.         m_IClient = client;
  225.         m_bActiveMode = true;
  226.         return true;
  227.     } else return false;
  228. }
  229. void    CTooltip::DisableActiveMode()
  230. {
  231.     if(m_bActiveMode)   {
  232.         Deactivate(true);
  233.         
  234.         m_bActiveMode  = false;
  235.     }
  236. }
  237. const static int    kMouseJump = 4; // max mouse travel between two events
  238. int     CTooltip::Handle(int event)
  239. {
  240.     switch(event)   {
  241.     case FL_MOVE:   {
  242.         if(m_bActiveMode)   {            
  243.             Fl_Widget* wid = dynamic_cast<Fl_Widget*>(m_IClient);
  244.             bool b_client_active = (Fl::belowmouse() == wid);
  245.             
  246.             int d_x = m_MouseX - Fl::event_x();
  247.             int d_y = m_MouseY - Fl::event_y();
  248.             bool jump = (d_x * d_x + d_y * d_y) > (kMouseJump * kMouseJump);
  249.             
  250.             m_MouseX = Fl::event_x();
  251.             m_MouseY = Fl::event_y();
  252.             
  253.             if(m_Mode == eHideOnMove  ||  jump)  { // hide and question client after delay
  254.                 Deactivate(true);
  255.                 if(b_client_active) {
  256.                     Fl::remove_timeout(ShowTooltipTimeout);        
  257.                     Fl::add_timeout(m_Delay, ShowTooltipTimeout, this);
  258.                 }
  259.             } else if(b_client_active)  {
  260.                 if(x_IsTooltipVisible()  ||  m_bRecentTooltip)    {
  261.                     x_AskClientAndUpdate();  // update immediately
  262.                 } else { // question client after delay
  263.                     Fl::add_timeout(m_Delay, ShowTooltipTimeout, this);
  264.                 }
  265.             }
  266.         }
  267.     }; break;
  268.     case FL_PUSH:   case FL_DRAG:   case FL_RELEASE:
  269.     case FL_UNFOCUS:
  270.     case FL_LEAVE:  {
  271.         Deactivate(true); 
  272.     }; break;
  273.     
  274.     }
  275.     return 0;
  276. }
  277. // shows tooltip 
  278. void CTooltip::x_UpdateTooltipWidget(ETooltipCmd cmd)
  279. {
  280.     if(! m_bRecursion)  {
  281.         m_bRecursion = 1;
  282.         if (! m_TooltipWidget) {
  283.             m_TooltipWidget = new CTooltipWidget(this);
  284.         }            
  285.         if(cmd == eShowDelayed  ||  cmd == eUpdateAndMove)  { 
  286.             // this cast bypasses the normal Fl_Window label() code:
  287.             ((Fl_Widget*)m_TooltipWidget)->label(m_Text.c_str());         
  288.             m_TooltipWidget->SetOrigin(Fl::event_x_root(), Fl::event_y_root());            
  289.         }
  290.         if(cmd != eDoNothing)   {
  291.             m_TooltipWidget->layout();
  292.         }
  293.         switch(cmd) {
  294.         case eUpdateAndMove:    {
  295.             if(m_TooltipWidget->visible())  {
  296.                 m_TooltipWidget->damage(1); 
  297.             } else {
  298.                 m_TooltipWidget->show();
  299.             };
  300.         }; break;         
  301.         case eShowDelayed:  {
  302.             m_TooltipWidget->show();
  303.         }; break;
  304.         default: break;
  305.         }
  306.         
  307.         Fl::remove_timeout(ClearRecentTimeout); // remove "recent" timer
  308.         m_bRecentTooltip = 1;
  309.         m_bRecursion = 0;
  310.     }
  311. }
  312. /// This functions queries the Client and shows tooltip if necessary. Funtion never
  313. /// delays showing (if function is called - delay have already elapsed)
  314. void    CTooltip::x_AskClientAndUpdate()
  315. {
  316.     if(m_IClient)   {
  317.         bool b_ok = m_IClient->TC_NeedTooltip(m_MouseX, m_MouseY);
  318.         if(b_ok)   { // show/update tooltip
  319.             int x = m_MouseX, y = m_MouseY, w = 1, h = 1;
  320.             string text = m_IClient->TC_GetTooltip(x, y, w, h);
  321.             bool b_changed = text != m_Text 
  322.                         ||  x != m_X  ||  y != m_Y ||  w != m_W  ||  h != m_H;
  323.                       
  324.             ETooltipCmd cmd = eDoNothing;
  325.             if(! x_IsTooltipVisible())  {
  326.                 cmd = eShowDelayed;
  327.             } else if(b_changed  ||  m_Mode == eTrackOnMove)    {
  328.                 cmd = eUpdateAndMove;
  329.             }
  330.             if(cmd != eDoNothing)   {
  331.                 m_Text = text;
  332.                 m_X = x; 
  333.                 m_Y = y; 
  334.                 m_W = w; 
  335.                 m_H = h;
  336.                 x_UpdateTooltipWidget(cmd);
  337.             }
  338.         } else Deactivate(false); // client doesn't want any tootlips
  339.     }
  340. }
  341. ////////////////////////////////////////////////////////////////////////////////
  342. /// CTooltipWidget
  343. const static int kSpaceX = 4;
  344. const static int kSpaceY = 2;
  345. const static int kOffsetY  = 24;
  346. CTooltipWidget::CTooltipWidget(CTooltip* tooltip)
  347. :   Fl_Menu_Window(0, 0),
  348.     m_Tooltip(tooltip)
  349. {
  350.     set_override();
  351.     end();
  352.     clear_flag(VISIBLE_FOCUS);
  353. }
  354. void    CTooltipWidget::SetOrigin(int x, int y)
  355. {
  356.     m_OrigX = x;
  357.     m_OrigY = y;
  358. }
  359. #define MAX_WIDTH 400
  360.     
  361. void    CTooltipWidget::layout() 
  362. {
  363.     fl_font(m_Tooltip->GetFont(), m_Tooltip->GetFontSize());
  364.     int width = MAX_WIDTH;
  365.     int height = 0;
  366.     fl_measure(m_Tooltip->GetText().c_str(), width, height, 
  367.                 FL_ALIGN_LEFT | FL_ALIGN_WRAP | FL_ALIGN_INSIDE);
  368.     width += 2 * kSpaceX; 
  369.     height += 2 * kSpaceY;
  370.     // horizontal positioning
  371.     int ox = m_OrigX;
  372.     
  373.     if(ox + width > Fl::w()) {
  374.         ox = Fl::w() - width;
  375.     }
  376.     if(ox < 0) 
  377.         ox = 0;
  378.     // vertical positioning
  379.     int oy = m_OrigY + kOffsetY;
  380.     if(oy + height > Fl::h())   {
  381.         oy = Fl::h() - height;
  382.     }
  383.     if(oy < 0 )     {
  384.         oy = 0;
  385.     }
  386.     if (oy < 0) {
  387.         oy = 0;
  388.     }
  389.     resize(ox, oy, width, height);
  390. }
  391. void CTooltipWidget::draw() 
  392. {
  393.   draw_box(FL_BORDER_BOX, 0, 0, w(), h(), m_Tooltip->GetColor());
  394.   fl_color(m_Tooltip->GetTextColor());
  395.   fl_font(m_Tooltip->GetFont(), m_Tooltip->GetFontSize());
  396.   fl_draw(m_Tooltip->GetText().c_str(), kSpaceX, kSpaceY, 
  397.           w() - 2* kSpaceX, h() - 2 * kSpaceY, 
  398.           Fl_Align(FL_ALIGN_LEFT | FL_ALIGN_WRAP | FL_ALIGN_INSIDE));
  399. }
  400. void    CTooltipWidget::show() 
  401. {
  402.     Fl_Menu_Window::show();
  403. }
  404. int     CTooltipWidget::handle(int event)
  405. {
  406.     switch(event)   {
  407.     case FL_FOCUS: return 0;
  408.     default: return Fl_Menu_Window::handle(event);
  409.     }
  410. }
  411. END_NCBI_SCOPE
  412. /*
  413.  * ===========================================================================
  414.  * $Log: tooltip.cpp,v $
  415.  * Revision 1000.1  2004/06/01 21:09:23  gouriano
  416.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.10
  417.  *
  418.  * Revision 1.10  2004/05/21 22:27:53  gorelenk
  419.  * Added PCH ncbi_pch.hpp
  420.  *
  421.  * Revision 1.9  2004/05/13 17:20:48  yazhuk
  422.  * clean-up
  423.  *
  424.  * Revision 1.8  2004/05/03 19:49:28  yazhuk
  425.  * Hide tooltip if mouse moves too fast
  426.  *
  427.  * Revision 1.7  2004/04/22 16:59:10  yazhuk
  428.  * Clean-up
  429.  *
  430.  * Revision 1.6  2004/02/11 15:26:24  yazhuk
  431.  * Event handling fix
  432.  *
  433.  * Revision 1.5  2004/02/04 22:26:31  yazhuk
  434.  * Fixed event handling in active mode
  435.  *
  436.  * Revision 1.4  2004/01/27 18:48:23  dicuccio
  437.  * Added call to DisableActiveMode() in destructor.  Make Deactivate() always
  438.  * remove timeouts
  439.  *
  440.  * Revision 1.3  2004/01/21 14:23:20  rsmith
  441.  * Remove debug output statement.
  442.  *
  443.  * Revision 1.2  2004/01/08 19:45:16  yazhuk
  444.  * Implemented "active" tooltips, refactored code, added comments
  445.  *
  446.  * Revision 1.1  2003/12/29 21:12:22  yazhuk
  447.  * Initial revision
  448.  *
  449.  * ===========================================================================
  450.  */