]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/Toolbar_pimpl.C
Give people a rational basis to describe what they dislike about tooltips!!!
[lyx.git] / src / frontends / xforms / Toolbar_pimpl.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2001 The LyX Team.
8  *
9  *           This file is Copyright 1996-1998
10  *           Lars Gullik Bjønnes
11  *
12  * ====================================================== */
13
14 //  Added pseudo-action handling, asierra 180296
15
16 #include <config.h>
17
18 #ifdef __GNUG__
19 #pragma implementation
20 #endif
21
22 #include "Toolbar_pimpl.h"
23 #include "debug.h"
24 #include "XFormsView.h"
25 #include "lyxfunc.h"
26 #include "FuncStatus.h"
27 #include "BufferView.h"
28 #include "buffer.h"
29 #include "lyxtextclasslist.h"
30 #include "LyXAction.h"
31 #include "MathsSymbols.h" 
32 #include "gettext.h"
33 #include "Tooltips.h"
34
35 #include "support/LAssert.h"
36 #include "support/filetools.h"
37 #include "support/lstrings.h" 
38
39 using std::endl;
40
41 extern LyXAction lyxaction;
42
43 // some constants
44 const int standardspacing = 2; // the usual space between items
45 const int sepspace = 6; // extra space
46 const int buttonwidth = 30; // the standard button width
47 const int height = 30; // the height of all items in the toolbar
48
49 Toolbar::Pimpl::toolbarItem::toolbarItem()
50 {
51         action = LFUN_NOACTION;
52         icon = 0;
53 }
54
55
56 Toolbar::Pimpl::toolbarItem::~toolbarItem()
57 {
58         clean();
59 }
60
61
62 void Toolbar::Pimpl::toolbarItem::clean()
63 {
64         if (icon) {
65                 fl_delete_object(icon);
66                 fl_free_object(icon);
67                 icon = 0;
68         }
69 }
70
71
72 Toolbar::Pimpl::toolbarItem & 
73 Toolbar::Pimpl::toolbarItem::operator=(toolbarItem const & ti)
74 {
75         // Are we assigning the object onto itself?
76         if (this == &ti)
77                 return *this;
78
79         // If we already have an icon, release it.
80         clean();
81     
82         // do we have to check icon too?
83         action = ti.action;
84         icon = 0; // locally we need to get the icon anew
85         
86         return *this;
87 }
88
89
90
91 Toolbar::Pimpl::Pimpl(LyXView * o, int x, int y)
92         : owner(static_cast<XFormsView *>(o)), sxpos(x), sypos(y)
93 {
94         combox = 0;
95         tooltip_ = new Tooltips();
96 }
97
98
99 Toolbar::Pimpl::~Pimpl()
100 {
101         clean();
102         delete tooltip_;
103 }
104
105
106 void Toolbar::Pimpl::activate()
107 {
108         ToolbarList::const_iterator p = toollist.begin();
109         ToolbarList::const_iterator end = toollist.end();
110         for (; p != end; ++p) {
111                 if (p->icon) {
112                         fl_activate_object(p->icon);
113                 }
114         }
115 }
116
117
118 void Toolbar::Pimpl::deactivate()
119 {
120         ToolbarList::const_iterator p = toollist.begin();
121         ToolbarList::const_iterator end = toollist.end();
122         for (; p != end; ++p) {
123                 if (p->icon) {
124                         fl_deactivate_object(p->icon);
125                 }
126         }
127 }
128
129
130 void Toolbar::Pimpl::update()
131 {
132         ToolbarList::const_iterator p = toollist.begin();
133         ToolbarList::const_iterator end = toollist.end();
134         for (; p != end; ++p) {
135                 if (p->icon) {
136                         FuncStatus status = owner->getLyXFunc()->getStatus(p->action);
137                         if (status.onoff(true)) {
138                                 // I'd like to use a different color
139                                 // here, but then the problem is to
140                                 // know how to use transparency with
141                                 // Xpm library. It seems pretty
142                                 // complicated to me (JMarc)
143                                 fl_set_object_color(p->icon, FL_LEFT_BCOL, FL_BLUE);
144                                 fl_set_object_boxtype(p->icon, FL_DOWN_BOX);
145                         } else {
146                                 fl_set_object_color(p->icon, FL_MCOL, FL_BLUE);
147                                 fl_set_object_boxtype(p->icon, FL_UP_BOX);
148                         }
149                         if (status.disabled()) {
150                                 // Is there a way here to specify a
151                                 // mask in order to show that the
152                                 // button is disabled? (JMarc)
153                                 fl_deactivate_object(p->icon);
154                         }
155                         else
156                                 fl_activate_object(p->icon);
157                 } else if (p->action == ToolbarDefaults::LAYOUTS && combox) {
158                         if (owner->getLyXFunc()->getStatus(LFUN_LAYOUT).disabled())
159                                 combox->deactivate();
160                         else
161                                 combox->activate();
162                 }
163         }
164 }
165
166
167 // this one is not "C" because combox callbacks are really C++ %-|
168 void Toolbar::Pimpl::layoutSelectedCB(int, void * arg, Combox *)
169 {
170         Toolbar::Pimpl * tb = reinterpret_cast<Toolbar::Pimpl *>(arg);
171
172         tb->layoutSelected();
173 }
174
175
176 void Toolbar::Pimpl::layoutSelected()
177 {
178         string const & layoutguiname = combox->getline();
179         LyXTextClass const & tc =
180                 textclasslist[owner->buffer()->params.textclass];
181         
182         LyXTextClass::const_iterator end = tc.end();
183         for (LyXTextClass::const_iterator cit = tc.begin();
184              cit != end; ++cit) {
185                 if (_(cit->name()) == layoutguiname) {
186                         owner->getLyXFunc()->dispatch(LFUN_LAYOUT, cit->name());
187                         return;
188                 }
189         }
190         lyxerr << "ERROR (Toolbar::Pimpl::layoutSelected): layout not found!"
191                << endl;
192 }
193  
194
195 void Toolbar::Pimpl::setLayout(string const & layout)
196 {
197         if (combox) {
198                 LyXTextClass const & tc =
199                         textclasslist[owner->buffer()->params.textclass];
200                 combox->select(_(tc[layout].name()));
201         }
202 }
203
204
205 void Toolbar::Pimpl::updateLayoutList(bool force)
206 {
207         // Update the layout display
208         if (!combox) return;
209
210         // If textclass is different, we need to update the list
211         if (combox->empty() || force) {
212                 combox->clear();
213                 LyXTextClass const & tc =
214                         textclasslist[owner->buffer()->params.textclass];
215                 LyXTextClass::const_iterator end = tc.end();
216                 for (LyXTextClass::const_iterator cit = tc.begin();
217                      cit != end; ++cit) {
218                         // ignore obsolete entries
219                         if (cit->obsoleted_by().empty())
220                                 combox->addline(_(cit->name()));
221                 }
222         }
223         // we need to do this.
224         combox->redraw();
225 }
226
227
228 void Toolbar::Pimpl::clearLayoutList()
229 {
230         if (combox) {
231                 combox->clear();
232                 combox->redraw();
233         }
234 }
235
236
237 void Toolbar::Pimpl::openLayoutList()
238 {
239         if (combox)
240                 combox->show();
241 }
242
243
244 namespace {
245
246 void ToolbarCB(FL_OBJECT * ob, long ac)
247 {
248         XFormsView * owner = static_cast<XFormsView *>(ob->u_vdata);
249         
250         owner->getLyXFunc()->verboseDispatch(int(ac), true);
251 }
252
253
254 extern "C" {
255         
256         static
257         void C_Toolbar_ToolbarCB(FL_OBJECT * ob, long data)
258         {
259                 ToolbarCB(ob, data);
260         }
261         
262 }
263
264
265 void setPixmap(FL_OBJECT * obj, int action, int buttonwidth, int height)
266 {
267         string arg;
268         string xpm_name;
269
270         const kb_action act = lyxaction.retrieveActionArg(action, arg);
271         string const name = lyxaction.getActionName(act);
272         if (!arg.empty())
273                 xpm_name = subst(name + ' ' + arg, ' ','_');
274         else 
275                 xpm_name = name;
276
277         string fullname = LibFileSearch("images", xpm_name, "xpm");
278
279         if (!fullname.empty()) {
280                 lyxerr[Debug::GUI] << "Full icon name is `" 
281                                        << fullname << "'" << endl;
282                 fl_set_pixmapbutton_file(obj, fullname.c_str());
283                 return;
284         }
285
286         if (act == LFUN_INSERT_MATH && !arg.empty()) {
287                 char const ** pixmap = get_pixmap_from_symbol(arg.c_str(),
288                                                         buttonwidth,
289                                                         height);
290                 if (pixmap) {
291                         lyxerr[Debug::GUI] << "Using mathed-provided icon"
292                                            << endl;
293                         fl_set_pixmapbutton_data(obj,
294                                                  const_cast<char **>(pixmap));
295                         return;
296                 }
297         }
298         
299         lyxerr << "Unable to find icon `" << xpm_name << "'" << endl;
300         fullname = LibFileSearch("images", "unknown", "xpm");
301         if (!fullname.empty()) {
302                 lyxerr[Debug::GUI] << "Using default `unknown' icon" 
303                                        << endl;
304                 fl_set_pixmapbutton_file(obj, fullname.c_str());
305         }
306 }
307
308 } // namespace anon
309
310
311 void Toolbar::Pimpl::set(bool doingmain)
312 {
313         // we shouldn't set if we have not cleaned
314         if (!cleaned) return;
315         
316         FL_OBJECT * obj;
317         
318         if (!doingmain) {
319                 fl_freeze_form(owner->getForm());
320                 fl_addto_form(owner->getForm());
321         }
322
323         ToolbarList::iterator item = toollist.begin();
324         ToolbarList::iterator end = toollist.end();
325         for (; item != end; ++item) {
326                 switch (item->action) {
327                 case ToolbarDefaults::SEPARATOR:
328                         xpos += sepspace;
329                         break;
330                 case ToolbarDefaults::NEWLINE:
331                         // Not supported yet.
332                         break;
333                 case ToolbarDefaults::LAYOUTS:
334                         xpos += standardspacing;
335                         if (!combox)
336                                 combox = new Combox(FL_COMBOX_DROPLIST);
337                         combox->add(xpos, ypos, 135, height, 400);
338                         combox->setcallback(layoutSelectedCB, this);
339                         combox->resize(FL_RESIZE_ALL);
340                         combox->gravity(NorthWestGravity, NorthWestGravity);
341                         xpos += 135;
342                         break;
343                 default:
344                         xpos += standardspacing;
345                         item->icon = obj = 
346                                 fl_add_pixmapbutton(FL_NORMAL_BUTTON,
347                                                     xpos, ypos,
348                                                     buttonwidth,
349                                                     height, "");
350                         fl_set_object_resize(obj, FL_RESIZE_ALL);
351                         fl_set_object_gravity(obj,
352                                               NorthWestGravity,
353                                               NorthWestGravity);
354                         fl_set_object_callback(obj, C_Toolbar_ToolbarCB,
355                                                static_cast<long>(item->action));
356                         // Remove the blue feedback rectangle
357                         fl_set_pixmapbutton_focus_outline(obj, 0);
358
359                         // initialise the tooltip
360                         string const tip = _(lyxaction.helpText(obj->argument));
361                         tooltip_->initTooltip(obj, tip);
362                         
363                         // The view that this object belongs to.
364                         obj->u_vdata = owner;
365
366                         setPixmap(obj, item->action, buttonwidth, height);
367                         // we must remember to update the positions
368                         xpos += buttonwidth;
369                         // ypos is constant
370                         /* Here will come a check to see if the new
371                          * pos is within the bounds of the main frame,
372                          * and perhaps wrap the toolbar if not.
373                          */
374                         break;
375                 }
376         }
377
378         if (!doingmain) {
379                 fl_end_form();
380                 fl_unfreeze_form(owner->getForm());
381                 // Should be safe to do this here.
382                 owner->updateLayoutChoice();
383         }
384
385         // set the state of the icons
386         //update();
387
388         cleaned = false;
389 }
390
391
392 void Toolbar::Pimpl::add(int action, bool doclean)
393 {
394         if (doclean && !cleaned) clean();
395
396         // this is what we do if we want to add to an existing
397         // toolbar.
398         if (!doclean && owner) {
399                 // first "hide" the toolbar buttons. This is not a real hide
400                 // actually it deletes and frees the button altogether.
401                 lyxerr << "Toolbar::add: \"hide\" the toolbar buttons." 
402                        << endl;
403
404                 lightReset();
405                 
406                 fl_freeze_form(owner->getForm());
407
408                 ToolbarList::iterator p = toollist.begin();
409                 ToolbarList::iterator end = toollist.end();
410                 for (; p != end; ++p) {
411                         p->clean();
412                 }
413
414                 if (combox) {
415                         delete combox;
416                         combox = 0;
417                 }
418                 fl_unfreeze_form(owner->getForm());
419                 cleaned = true; // this is not completely true, but OK anyway
420         }
421         
422         // there exist some special actions not part of
423         // kb_action: SEPARATOR, LAYOUTS
424
425         toolbarItem newItem;
426         newItem.action = action;
427         toollist.push_back(newItem);
428 }
429
430
431 void Toolbar::Pimpl::clean()
432 {
433         //reset(); // I do not understand what this reset() is, anyway
434
435         //now delete all the objects..
436         if (owner)
437                 fl_freeze_form(owner->getForm());
438
439         // G++ vector does not have clear defined
440         //toollist.clear();
441         toollist.erase(toollist.begin(), toollist.end());
442
443         lyxerr[Debug::GUI] << "Combox: " << combox << endl;
444         if (combox) {
445                 delete combox;
446                 combox = 0;
447         }
448
449         if (owner)
450                 fl_unfreeze_form(owner->getForm());
451         lyxerr[Debug::GUI] << "toolbar cleaned" << endl;
452         cleaned = true;
453 }
454
455
456 void Toolbar::Pimpl::push(int nth)
457 {
458         lyxerr[Debug::GUI] << "Toolbar::push: trying to trigger no `"
459                                << nth << '\'' << endl;
460         
461         if (nth <= 0 || nth >= int(toollist.size())) {
462                 // item nth not found...
463                 return;
464         }
465
466         fl_trigger_object(toollist[nth - 1].icon);
467 }
468
469
470 void Toolbar::Pimpl::reset() 
471 {
472         //toollist = 0; // what is this supposed to do?
473         cleaned = false;
474         lightReset();
475 }
476
477
478 void Toolbar::Pimpl::lightReset() {
479         xpos = sxpos - standardspacing;
480         ypos = sypos;
481 }