/* * File: tipwin.cc * * Copyright 2012 Jorge Arellano Cid * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * The tipwin idea was derived from the Fl_Slider example [1] * by Greg Ercolano, which is in public domain. * * [1] http://seriss.com/people/erco/fltk/#SliderTooltip */ #include #include #include #include #include #include #include #include #include #include "tipwin.hh" /* * Forward declarations */ static void show_timeout(void*); static void recent_timeout(void*); /* * Custom tooltip window */ TipWin::TipWin() : Fl_Menu_Window(1, 1) // will autosize { bgcolor = fl_color_cube(FL_NUM_RED - 1, FL_NUM_GREEN - 1, FL_NUM_BLUE - 2); recent = 0; strcpy(tip, ""); cur_widget = NULL; set_override(); // no border end(); } void TipWin::draw() { draw_box(FL_BORDER_BOX, 0, 0, w(), h(), bgcolor); fl_color(FL_BLACK); fl_font(labelfont(), labelsize()); fl_draw(tip, 3, 3, w() - 6, h() - 6, //Fl_Align(FL_ALIGN_LEFT | FL_ALIGN_WRAP)); Fl_Align(FL_ALIGN_LEFT)); } void TipWin::value(const char *s) { // Recalc size of window snprintf(tip, sizeof(tip) - 1, "%s", s); fl_font(labelfont(), labelsize()); int W = w(), H = h(); W = 0; fl_measure(tip, W, H, 0); W += 8; H += 8; size(W, H); redraw(); } void TipWin::do_show(void *wid) { cur_widget = wid; // Keep track of requesting widget Fl::add_timeout(recent ? 0.2f : 0.8f, show_timeout); } void TipWin::do_hide() { Fl::remove_timeout(show_timeout); if (shown()) { hide(); recent = 1; Fl::add_timeout(0.8f, recent_timeout); } } void TipWin::recent_tooltip(int val) { recent = val; } //-------------------------------------------------------------------------- TipWin *my_tipwin(void) { static TipWin *tw = NULL; if (!tw) { Fl_Group *save = Fl_Group::current(); // save current widget.. tw = new TipWin(); // ..because this trashes it tw->hide(); // start hidden Fl_Group::current(save); // ..then back to previous. } return tw; } static void show_timeout(void*) { // if offscreen, move tip ABOVE mouse instead int scr_x, scr_y, scr_w, scr_h; Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h); int ty = Fl::event_y_root() + 20; if (ty + my_tipwin()->h() > scr_h) ty = Fl::event_y_root() - 20 - my_tipwin()->h(); if (ty < 0) ty = 0; my_tipwin()->position(Fl::event_x_root(), ty); my_tipwin()->show(); my_tipwin()->recent_tooltip(0); } static void recent_timeout(void*) { my_tipwin()->recent_tooltip(0); } //--------------------------------------------------------------------------- /* * A Button sharing a custom tooltip window */ TipWinButton::TipWinButton(int x, int y, int w, int h, const char *l) : Fl_Button(x, y, w, h, l) { tipwin = my_tipwin(); mytooltip = strdup("empty"); } TipWinButton::~TipWinButton(void) { tipwin->cancel(this); // cancel tooltip if shown free(mytooltip); } int TipWinButton::handle(int e) { switch (e) { case FL_ENTER: tipwin->value(mytooltip); tipwin->do_show(this); break; case FL_PUSH: // push mouse case FL_RELEASE: // release mouse case FL_HIDE: // widget goes away case FL_LEAVE: // leave focus tipwin->do_hide(); break; } return (Fl_Button::handle(e)); } void TipWinButton::set_tooltip(const char *s) { free(mytooltip); mytooltip = strdup(s); } //--------------------------------------------------------------------------- /* * A Light Button sharing a custom tooltip window */ CustButton::CustButton(int x, int y, int w, int h, const char *l) : TipWinButton(x,y,w,h,l) { norm_color = color(); light_color = 17; // {17,26,51} } int CustButton::handle(int e) { if (active()) { if (e == FL_ENTER) { color(light_color); redraw(); } else if (e == FL_LEAVE || e == FL_RELEASE || e == FL_HIDE) { color(norm_color); redraw(); } } else if (e == FL_DEACTIVATE && color() != norm_color) { color(norm_color); redraw(); } return TipWinButton::handle(e); } void CustButton::hl_color(Fl_Color col) { light_color = col; } //--------------------------------------------------------------------------- /* * An Input with custom tooltip window */ TipWinInput::TipWinInput (int x, int y, int w, int h, const char *l) : Fl_Input(x,y,w,h,l) { tipwin = my_tipwin(); mytooltip = strdup("empty"); } TipWinInput::~TipWinInput(void) { tipwin->cancel(this); // cancel tooltip if shown free(mytooltip); } int TipWinInput::handle(int e) { switch (e) { case FL_ENTER: tipwin->value(mytooltip); tipwin->do_show(this); break; case FL_PUSH: // push mouse case FL_RELEASE: // release mouse case FL_HIDE: // widget goes away case FL_LEAVE: // leave focus case FL_KEYBOARD: // key press tipwin->do_hide(); break; } return (Fl_Input::handle(e)); } void TipWinInput::set_tooltip(const char *s) { free(mytooltip); mytooltip = strdup(s); }