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