1 /*
2 * File: tipwin.cc
3 *
4 * Copyright 2012 Jorge Arellano Cid <jcid@dillo.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * The tipwin idea was derived from the Fl_Slider example [1]
12 * by Greg Ercolano, which is in public domain.
13 *
14 * [1] http://seriss.com/people/erco/fltk/#SliderTooltip
15 */
16
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <FL/fl_draw.H>
22 #include <FL/Fl.H>
23 #include <FL/Fl_Group.H>
24 #include <FL/Fl_Menu_Window.H>
25 #include <FL/Fl_Tooltip.H>
26 #include <FL/Fl_Button.H>
27
28 #include "prefs.h"
29 #include "tipwin.hh"
30
31 /*
32 * Forward declarations
33 */
34 static void show_timeout(void*);
35 static void recent_timeout(void*);
36
37 /*
38 * Custom tooltip window
39 */
TipWin()40 TipWin::TipWin() : Fl_Menu_Window(1, 1) // will autosize
41 {
42 bgcolor = fl_color_cube(FL_NUM_RED - 1, FL_NUM_GREEN - 1, FL_NUM_BLUE - 2);
43 recent = 0;
44 strcpy(tip, "");
45 cur_widget = NULL;
46 set_override(); // no border
47 end();
48 }
49
draw()50 void TipWin::draw()
51 {
52 draw_box(FL_BORDER_BOX, 0, 0, w(), h(), bgcolor);
53 fl_color(FL_BLACK);
54 fl_font(labelfont(), labelsize());
55 fl_draw(tip, 3, 3, w() - 6, h() - 6,
56 //Fl_Align(FL_ALIGN_LEFT | FL_ALIGN_WRAP));
57 Fl_Align(FL_ALIGN_LEFT));
58 }
59
value(const char * s)60 void TipWin::value(const char *s) {
61 // Recalc size of window
62 snprintf(tip, sizeof(tip) - 1, "%s", s);
63 fl_font(labelfont(), labelsize());
64 int W = w(), H = h();
65 W = 0;
66 fl_measure(tip, W, H, 0);
67 W += 8; H += 8;
68 size(W, H);
69 redraw();
70 }
71
do_show(void * wid)72 void TipWin::do_show(void *wid) {
73 cur_widget = wid; // Keep track of requesting widget
74 if (prefs.show_ui_tooltip) {
75 Fl::add_timeout(recent ? 0.2f : 0.8f, show_timeout);
76 }
77 }
78
do_hide()79 void TipWin::do_hide() {
80 Fl::remove_timeout(show_timeout);
81 if (shown()) {
82 hide();
83 recent = 1;
84 Fl::add_timeout(0.8f, recent_timeout);
85 }
86 }
87
recent_tooltip(int val)88 void TipWin::recent_tooltip(int val) {
89 recent = val;
90 }
91
92 //--------------------------------------------------------------------------
93
my_tipwin(void)94 TipWin *my_tipwin(void)
95 {
96 static TipWin *tw = NULL;
97
98 if (!tw) {
99 Fl_Group *save = Fl_Group::current(); // save current widget..
100 tw = new TipWin(); // ..because this trashes it
101 tw->hide(); // start hidden
102 Fl_Group::current(save); // ..then back to previous.
103 }
104 return tw;
105 }
106
show_timeout(void *)107 static void show_timeout(void*) {
108 // if offscreen, move tip ABOVE mouse instead
109 int scr_x, scr_y, scr_w, scr_h;
110 Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h);
111 int ty = Fl::event_y_root() + 20;
112 if (ty + my_tipwin()->h() > scr_h)
113 ty = Fl::event_y_root() - 20 - my_tipwin()->h();
114 if (ty < 0) ty = 0;
115
116 my_tipwin()->position(Fl::event_x_root(), ty);
117 my_tipwin()->show();
118 my_tipwin()->recent_tooltip(0);
119 }
120
recent_timeout(void *)121 static void recent_timeout(void*) {
122 my_tipwin()->recent_tooltip(0);
123 }
124
125
126 //---------------------------------------------------------------------------
127
128 /*
129 * A Button sharing a custom tooltip window
130 */
TipWinButton(int x,int y,int w,int h,const char * l)131 TipWinButton::TipWinButton(int x, int y, int w, int h, const char *l) :
132 Fl_Button(x, y, w, h, l)
133 {
134 tipwin = my_tipwin();
135 mytooltip = strdup("empty");
136 }
137
~TipWinButton(void)138 TipWinButton::~TipWinButton(void)
139 {
140 tipwin->cancel(this); // cancel tooltip if shown
141 free(mytooltip);
142 }
143
handle(int e)144 int TipWinButton::handle(int e)
145 {
146 switch (e) {
147 case FL_ENTER:
148 tipwin->value(mytooltip);
149 tipwin->do_show(this);
150 break;
151 case FL_PUSH: // push mouse
152 case FL_RELEASE: // release mouse
153 case FL_HIDE: // widget goes away
154 case FL_LEAVE: // leave focus
155 tipwin->do_hide();
156 break;
157 }
158 return (Fl_Button::handle(e));
159 }
160
set_tooltip(const char * s)161 void TipWinButton::set_tooltip(const char *s)
162 {
163 free(mytooltip);
164 mytooltip = strdup(s);
165 }
166
167
168 //---------------------------------------------------------------------------
169
170 /*
171 * A Light Button sharing a custom tooltip window
172 */
CustButton(int x,int y,int w,int h,const char * l)173 CustButton::CustButton(int x, int y, int w, int h, const char *l) :
174 TipWinButton(x,y,w,h,l)
175 {
176 norm_color = color();
177 light_color = PREFS_UI_BUTTON_HIGHLIGHT_COLOR;
178 }
179
handle(int e)180 int CustButton::handle(int e)
181 {
182 if (active()) {
183 if (e == FL_ENTER) {
184 color(light_color);
185 redraw();
186 } else if (e == FL_LEAVE || e == FL_RELEASE || e == FL_HIDE) {
187 color(norm_color);
188 redraw();
189 }
190 } else if (e == FL_DEACTIVATE && color() != norm_color) {
191 color(norm_color);
192 redraw();
193 }
194 return TipWinButton::handle(e);
195 }
196
hl_color(Fl_Color col)197 void CustButton::hl_color(Fl_Color col)
198 {
199 light_color = col;
200 }
201
202
203 //---------------------------------------------------------------------------
204
205 /*
206 * An Input with custom tooltip window
207 */
TipWinInput(int x,int y,int w,int h,const char * l)208 TipWinInput::TipWinInput (int x, int y, int w, int h, const char *l) :
209 Fl_Input(x,y,w,h,l)
210 {
211 tipwin = my_tipwin();
212 mytooltip = strdup("empty");
213 }
214
~TipWinInput(void)215 TipWinInput::~TipWinInput(void)
216 {
217 tipwin->cancel(this); // cancel tooltip if shown
218 free(mytooltip);
219 }
220
handle(int e)221 int TipWinInput::handle(int e)
222 {
223 switch (e) {
224 case FL_ENTER:
225 tipwin->value(mytooltip);
226 tipwin->do_show(this);
227 break;
228 case FL_PUSH: // push mouse
229 case FL_RELEASE: // release mouse
230 case FL_HIDE: // widget goes away
231 case FL_LEAVE: // leave focus
232 case FL_KEYBOARD: // key press
233 tipwin->do_hide();
234 break;
235 }
236 return (Fl_Input::handle(e));
237 }
238
set_tooltip(const char * s)239 void TipWinInput::set_tooltip(const char *s)
240 {
241 free(mytooltip);
242 mytooltip = strdup(s);
243 }
244
245