]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/Tooltips.C
Give people a rational basis to describe what they dislike about tooltips!!!
[lyx.git] / src / frontends / xforms / Tooltips.C
1 /*
2  * \file Tooltips.C
3  * Copyright 2002 the LyX Team
4  * Read the file COPYING
5  *
6  * \author Angus Leeming, a.leeming@ic.ac.uk
7  *
8  * Tooltips for xforms. xforms 0.89 supports them directly, but 0.88 needs
9  * a bit of jiggery pokery. This class wraps it all up in a neat interface.
10  * Based on code originally in Toolbar_pimpl.C that appears to have been
11  * written by Matthias Ettrich and Jean-Marc Lasgouttes.
12  */
13
14 #include <config.h>
15
16 #ifdef __GNUG__
17 #pragma implementation
18 #endif
19
20 #include "Tooltips.h"
21 #include "Dialogs.h"
22 #include "xforms_helpers.h" // formatted
23 #include "gettext.h"
24 #include "support/lstrings.h"
25 #include "support/LAssert.h"
26
27 using SigC::slot;
28
29
30 bool Tooltips::enabled_ = false;
31
32 SigC::Signal0<void> Tooltips::tooltipsToggled;
33
34
35 #if FL_REVISION >= 89
36
37 Tooltips::Tooltips()
38 {
39         static bool first = true;
40         if (first) {
41                 first = false;
42                 Dialogs::toggleTooltips.connect(slot(&Tooltips::toggleEnabled));
43         }
44         tooltipsToggled.connect(slot(this, &Tooltips::toggleTooltips));
45 }
46
47
48 void Tooltips::toggleEnabled()
49 {
50         enabled_ = !enabled_;
51         tooltipsToggled();
52 }
53
54
55 void Tooltips::toggleTooltips()
56 {
57         if (tooltipsMap.empty())
58                 // There are no objects with tooltips in this dialog, so
59                 // just go away. Don't change the cursor to a question mark.
60                 return;
61
62         TooltipsMap::iterator it  = tooltipsMap.begin();
63         TooltipsMap::iterator end = tooltipsMap.end();
64         for (; it != end; ++it) {
65                 FL_OBJECT * const ob = it->first;
66                 char const * const c_str = enabled_ ? it->second.c_str() : 0;
67                 fl_set_object_helper(ob, c_str);
68         }
69
70         // Set the cursor to a question mark or back to the default.
71         FL_OBJECT * const ob = tooltipsMap.begin()->first;
72         int const cursor = enabled_ ? XC_question_arrow : FL_DEFAULT_CURSOR;
73         fl_set_cursor(FL_ObjWin(ob), cursor);
74 }
75
76
77 void Tooltips::initTooltip(FL_OBJECT * ob, string const & tip)
78 {
79         lyx::Assert(ob);
80
81         // Paranoia check!
82         TooltipsMap::const_iterator it = tooltipsMap.find(ob);
83         if (it != tooltipsMap.end())
84                 return;
85
86         string const str = strip(frontStrip(tip));
87         if (str.empty())
88                 return;
89
90         // Store the tooltip string
91         tooltipsMap[ob] = formatted(_(str), 400);
92
93         // Set the initial state of the tooltips
94         char const * const c_str = enabled_ ? str.c_str() : 0;
95         fl_set_object_helper(ob, c_str);
96 }
97
98
99 #else // if FL_REVISION < 89
100
101 namespace {
102
103 int TooltipHandler(FL_OBJECT *ob, int event);
104
105 void TooltipTimerCB(FL_OBJECT * timer, long data);
106  
107 }
108
109 extern "C" {
110
111 static int C_TooltipHandler(FL_OBJECT * ob, int event,
112                                     FL_Coord, FL_Coord, int, void *)
113 {
114         return TooltipHandler(ob, event);
115 }
116
117
118 static void C_TooltipTimerCB(FL_OBJECT * ob, long data)
119 {
120         TooltipTimerCB(ob, data);
121 }
122
123 }
124  
125
126 Tooltips::Tooltips()
127         : tooltip_timer_(0)
128 {
129         static bool first = true;
130         if (first) {
131                 first = false;
132                 Dialogs::toggleTooltips.connect(slot(&Tooltips::toggleEnabled));
133         }
134         tooltipsToggled.connect(slot(this, &Tooltips::toggleTooltips));
135 }
136
137
138 void Tooltips::toggleEnabled()
139 {
140         enabled_ = !enabled_;
141         tooltipsToggled();
142 }
143
144
145 void Tooltips::toggleTooltips()
146 {
147         if (tooltipsMap.empty())
148                 // There are no objects with tooltips in this dialog, so
149                 // just go away. Don't change the cursor to a question mark.
150                 return;
151
152         // Set the cursor to a question mark or back to the default.
153         FL_OBJECT * const ob = tooltipsMap.begin()->first;
154         int const cursor = enabled_ ? XC_question_arrow : FL_DEFAULT_CURSOR;
155         fl_set_cursor(FL_ObjWin(ob), cursor);
156 }
157
158
159 void Tooltips::initTooltip(FL_OBJECT * ob, string const & tip)
160 {
161         lyx::Assert(ob);
162
163         // Paranoia check!
164         TooltipsMap::const_iterator it = tooltipsMap.find(ob);
165         if (it != tooltipsMap.end())
166                 return;
167
168         string const str = strip(frontStrip(tip));
169         if (str.empty())
170                 return;
171
172         // Store the tooltip string
173         tooltipsMap[ob] = formatted(_(str), 400);
174
175         if (!tooltip_timer_) {
176                 lyx::Assert(ob->form);
177                 if (fl_current_form && ob->form != fl_current_form)
178                         fl_end_form();
179
180                 bool const open_form = !fl_current_form;
181                 if (open_form)
182                         fl_addto_form(ob->form);
183
184                 tooltip_timer_ = fl_add_timer(FL_HIDDEN_TIMER, 0, 0, 0, 0, "");
185
186                 if (open_form)
187                         fl_end_form();
188         }
189
190         fl_set_object_posthandler(ob, C_TooltipHandler);
191         ob->u_cdata = reinterpret_cast<char *>(tooltip_timer_);
192         tooltip_timer_->u_vdata = this;
193 }
194
195
196 string const Tooltips::getTooltip(FL_OBJECT * ob) const 
197 {
198         TooltipsMap::const_iterator it = tooltipsMap.find(ob);
199         if (it == tooltipsMap.end())
200                 return string();
201         return it->second;
202 }
203
204
205 namespace {
206
207 void TooltipTimerCB(FL_OBJECT * timer, long data)
208 {
209         FL_OBJECT * ob = reinterpret_cast<FL_OBJECT*>(data);
210         lyx::Assert(ob && ob->form && timer && timer->u_vdata);
211         FL_FORM * form = ob->form;
212         Tooltips * tooltip = static_cast<Tooltips *>(timer->u_vdata);
213         
214         string const help = tooltip->getTooltip(ob);
215         if (help.empty())
216                 return;
217
218         fl_show_oneliner(help.c_str(),
219                          form->x + ob->x, form->y + ob->y + ob->h);
220 }
221
222
223 // post_handler for tooltip help
224 int TooltipHandler(FL_OBJECT * ob, int event)
225 {
226         if (!Tooltips::enabled())
227                 return 0;
228
229         lyx::Assert(ob);
230         FL_OBJECT * timer = reinterpret_cast<FL_OBJECT *>(ob->u_cdata);
231         lyx::Assert(timer);
232
233         // We do not test for empty help here, since this can never happen
234         if (event == FL_ENTER) {
235                 fl_set_object_callback(timer,
236                                        C_TooltipTimerCB,
237                                        reinterpret_cast<long>(ob));
238                 fl_set_timer(timer, 1);
239         }
240         else if (event != FL_MOTION) {
241                 fl_set_timer(timer, 0);
242                 fl_hide_oneliner();
243         }
244         return 0;
245 }
246
247 } // namespace anon
248
249 #endif // FL_REVISION >= 89