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