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