fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_Tooltip.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_Tooltip.cxx 8018 2010-12-12 19:52:26Z matt $"
00003 //
00004 // Tooltip source file for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 1998-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 #include <FL/Fl_Tooltip.H>
00029 #include <FL/fl_draw.H>
00030 #include <FL/Fl_Menu_Window.H>
00031 
00032 #include <stdio.h>
00033 #include <string.h>     // strdup()
00034 
00035 float           Fl_Tooltip::delay_ = 1.0f;
00036 float           Fl_Tooltip::hoverdelay_ = 0.2f;
00037 Fl_Color        Fl_Tooltip::color_ = fl_color_cube(FL_NUM_RED - 1,
00038                                                    FL_NUM_GREEN - 1,
00039                                                    FL_NUM_BLUE - 2);
00040 Fl_Color        Fl_Tooltip::textcolor_ = FL_BLACK;
00041 Fl_Font         Fl_Tooltip::font_ = FL_HELVETICA;
00042 Fl_Fontsize     Fl_Tooltip::size_ = FL_NORMAL_SIZE;
00043 
00044 #define MAX_WIDTH 400
00045 
00046 static const char* tip;
00050 class Fl_TooltipBox : public Fl_Menu_Window {
00051 public:
00053   Fl_TooltipBox() : Fl_Menu_Window(0, 0) {
00054     set_override();
00055     set_tooltip_window();
00056     end();
00057   }
00058   void draw();
00059   void layout();
00061   void show() {
00062     if (tip) Fl_Menu_Window::show();
00063   }
00064 };
00065 
00066 Fl_Widget* Fl_Tooltip::widget_ = 0;
00067 static Fl_TooltipBox *window = 0;
00068 static int Y,H;
00069 
00070 #ifdef __APPLE__
00071 // returns the unique tooltip window
00072 Fl_Window *Fl_Tooltip::current_window(void)
00073 {
00074   return (Fl_Window*)window;
00075 }
00076 #endif
00077 
00078 void Fl_TooltipBox::layout() {
00079   fl_font(Fl_Tooltip::font(), Fl_Tooltip::size());
00080   int ww, hh;
00081   ww = MAX_WIDTH;
00082   fl_measure(tip, ww, hh, FL_ALIGN_LEFT|FL_ALIGN_WRAP|FL_ALIGN_INSIDE);
00083   ww += 6; hh += 6;
00084 
00085   // find position on the screen of the widget:
00086   int ox = Fl::event_x_root();
00087   int oy = Y + H+2;
00088   for (Fl_Widget* p = Fl_Tooltip::current(); p; p = p->window()) {
00089     oy += p->y();
00090   }
00091   int scr_x, scr_y, scr_w, scr_h;
00092   Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h);
00093   if (ox+ww > scr_x+scr_w) ox = scr_x+scr_w - ww;
00094   if (ox < scr_x) ox = scr_x;
00095   if (H > 30) {
00096     oy = Fl::event_y_root()+13;
00097     if (oy+hh > scr_y+scr_h) oy -= 23+hh;
00098   } else {
00099     if (oy+hh > scr_y+scr_h) oy -= (4+hh+H);
00100   }
00101   if (oy < scr_y) oy = scr_y;
00102 
00103   resize(ox, oy, ww, hh);
00104 }
00105 
00106 void Fl_TooltipBox::draw() {
00107   draw_box(FL_BORDER_BOX, 0, 0, w(), h(), Fl_Tooltip::color());
00108   fl_color(Fl_Tooltip::textcolor());
00109   fl_font(Fl_Tooltip::font(), Fl_Tooltip::size());
00110   fl_draw(tip, 3, 3, w()-6, h()-6, Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_WRAP));
00111 }
00112 
00113 static char recent_tooltip;
00114 
00115 static void recent_timeout(void*) {
00116 #ifdef DEBUG
00117   puts("recent_timeout();");
00118 #endif // DEBUG
00119 
00120   recent_tooltip = 0;
00121 }
00122 
00123 static char recursion;
00124 
00125 static void tooltip_timeout(void*) {
00126 #ifdef DEBUG
00127   puts("tooltip_timeout();");
00128 #endif // DEBUG
00129 
00130   if (recursion) return;
00131   recursion = 1;
00132   if (!tip || !*tip) {
00133     if (window) window->hide();
00134   } else {
00135     //if (Fl::grab()) return;
00136     if (!window) window = new Fl_TooltipBox;
00137     // this cast bypasses the normal Fl_Window label() code:
00138     ((Fl_Widget*)window)->label(tip);
00139     window->layout();
00140     window->redraw();
00141 //    printf("tooltip_timeout: Showing window %p with tooltip \"%s\"...\n",
00142 //           window, tip ? tip : "(null)");
00143     window->show();
00144   }
00145 
00146   Fl::remove_timeout(recent_timeout);
00147   recent_tooltip = 1;
00148   recursion = 0;
00149 }
00150 
00160 void Fl_Tooltip::enter_(Fl_Widget* w) {
00161 #ifdef DEBUG
00162   printf("Fl_Tooltip::enter_(w=%p)\n", w);
00163   printf("    window=%p\n", window);
00164 #endif // DEBUG
00165 
00166   // find the enclosing group with a tooltip:
00167   Fl_Widget* tw = w;
00168   for (;;) {
00169     if (!tw) {exit_(0); return;}
00170     if (tw == widget_) return;
00171     if (tw->tooltip()) break;
00172     tw = tw->parent();
00173   }
00174   enter_area(w, 0, 0, w->w(), w->h(), tw->tooltip());
00175 }
00183 void Fl_Tooltip::current(Fl_Widget* w) {
00184 #ifdef DEBUG
00185   printf("Fl_Tooltip::current(w=%p)\n", w);
00186 #endif // DEBUG
00187 
00188   exit_(0);
00189   // find the enclosing group with a tooltip:
00190   Fl_Widget* tw = w;
00191   for (;;) {
00192     if (!tw) return;
00193     if (tw->tooltip()) break;
00194     tw = tw->parent();
00195   }
00196   // act just like Fl_Tooltip::enter_() except we can remember a zero:
00197   widget_ = w;
00198 }
00199 
00200 // Hide any visible tooltip.
00202 void Fl_Tooltip::exit_(Fl_Widget *w) {
00203 #ifdef DEBUG
00204   printf("Fl_Tooltip::exit_(w=%p)\n", w);
00205   printf("    widget=%p, window=%p\n", widget_, window);
00206 #endif // DEBUG
00207 
00208   if (!widget_ || (w && w == window)) return;
00209   widget_ = 0;
00210   Fl::remove_timeout(tooltip_timeout);
00211   Fl::remove_timeout(recent_timeout);
00212   if (window && window->visible()) window->hide();
00213   if (recent_tooltip) {
00214     if (Fl::event_state() & FL_BUTTONS) recent_tooltip = 0;
00215     else Fl::add_timeout(Fl_Tooltip::hoverdelay(), recent_timeout);
00216   }
00217 }
00218 
00219 // Get ready to display a tooltip. The widget and the xywh box inside
00220 // it define an area the tooltip is for, this along with the current
00221 // mouse position places the tooltip (the mouse is assumed to point
00222 // inside or near the box).
00234 void Fl_Tooltip::enter_area(Fl_Widget* wid, int x,int y,int w,int h, const char* t)
00235 {
00236   (void)x;
00237   (void)w;
00238 
00239 #ifdef DEBUG
00240   printf("Fl_Tooltip::enter_area(wid=%p, x=%d, y=%d, w=%d, h=%d, t=\"%s\")\n",
00241          wid, x, y, w, h, t ? t : "(null)");
00242   printf("    recursion=%d, window=%p\n", recursion, window);
00243 #endif // DEBUG
00244 
00245   if (recursion) return;
00246   if (!t || !*t || !enabled()) {
00247     exit_(0);
00248     return;
00249   }
00250   // do nothing if it is the same:
00251   if (wid==widget_ /*&& x==X && y==Y && w==W && h==H*/ && t==tip) return;
00252   Fl::remove_timeout(tooltip_timeout);
00253   Fl::remove_timeout(recent_timeout);
00254   // remember it:
00255   widget_ = wid; Y = y; H = h; tip = t;
00256   // popup the tooltip immediately if it was recently up:
00257   if (recent_tooltip) {
00258     if (window) window->hide();
00259     Fl::add_timeout(Fl_Tooltip::hoverdelay(), tooltip_timeout);
00260   } else if (Fl_Tooltip::delay() < .1) {
00261 #ifdef WIN32
00262     // possible fix for the Windows titlebar, it seems to want the
00263     // window to be destroyed, moving it messes up the parenting:
00264     if (window && window->visible()) window->hide();
00265 #endif // WIN32
00266     tooltip_timeout(0);
00267   } else {
00268     if (window && window->visible()) window->hide();
00269     Fl::add_timeout(Fl_Tooltip::delay(), tooltip_timeout);
00270   }
00271 
00272 #ifdef DEBUG
00273   printf("    tip=\"%s\", window->shown()=%d\n", tip ? tip : "(null)",
00274          window ? window->shown() : 0);
00275 #endif // DEBUG
00276 }
00277 
00278 void Fl_Tooltip::set_enter_exit_once_() {
00279   static char beenhere = 0;
00280   if (!beenhere) {
00281     beenhere          = 1;
00282     Fl_Tooltip::enter = Fl_Tooltip::enter_;
00283     Fl_Tooltip::exit  = Fl_Tooltip::exit_;
00284   }
00285 }
00286 
00304 void Fl_Widget::tooltip(const char *text) {
00305   Fl_Tooltip::set_enter_exit_once_();
00306   if (flags() & COPIED_TOOLTIP) {
00307     // reassigning a copied tooltip remains the same copied tooltip
00308     if (tooltip_ == text) return;
00309     free((void*)(tooltip_));            // free maintained copy
00310     clear_flag(COPIED_TOOLTIP);         // disable copy flag (WE don't make copies)
00311   }
00312   tooltip_ = text;
00313 }
00314 
00330 void Fl_Widget::copy_tooltip(const char *text) {
00331   Fl_Tooltip::set_enter_exit_once_();
00332   if (flags() & COPIED_TOOLTIP) free((void *)(tooltip_));
00333   if (text) {
00334     set_flag(COPIED_TOOLTIP);
00335     tooltip_ = strdup(text);
00336   } else {
00337     clear_flag(COPIED_TOOLTIP);
00338     tooltip_ = (char *)0;
00339   }
00340 }
00341 
00342 //
00343 // End of "$Id: Fl_Tooltip.cxx 8018 2010-12-12 19:52:26Z matt $".
00344 //