]> git.lyx.org Git - lyx.git/blob - src/toolbar.C
more changes, read the Changelog
[lyx.git] / src / toolbar.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2000 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 "toolbar.h"
20 #endif
21
22 #include "lyx_main.h"
23 #include "lyx_gui_misc.h"
24 #include "lyx.h"
25 #include "toolbar.h"
26 #include "lyxfunc.h"
27 #include "lyxlex.h"
28 #include "debug.h"
29 #include "combox.h"
30 #include "LyXView.h"
31 #include "LyXAction.h"
32 #include "support/lstrings.h"
33 #include "lyxrc.h"
34
35 #ifdef TWO_COLOR_ICONS
36 #include "cut_bw.xpm"
37 #include "emph_bw.xpm"
38 #include "fig_bw.xpm"
39 #include "foot_bw.xpm"
40 #include "math_bw.xpm"
41 #include "depth_bw.xpm"
42 #include "margin_bw.xpm"
43 #include "melt_bw.xpm"
44 #include "copy_bw.xpm"
45 #include "noun_bw.xpm"
46 #include "paste_bw.xpm"
47 #include "free_bw.xpm"
48 #include "tab_bw.xpm"
49 #include "tex_bw.xpm"
50 #include "open_bw.xpm"
51 #include "close_bw.xpm"
52 #include "save_bw.xpm"
53 #include "print1_bw.xpm"
54 #include "quit_bw.xpm"
55 #include "typeset_ps_bw.xpm"
56 #include "unknown_bw.xpm"
57 #else 
58 #include "cut.xpm"
59 #include "emph.xpm"
60 #include "fig.xpm"
61 #include "foot.xpm"
62 #include "math.xpm"
63 #include "depth.xpm"
64 #include "margin.xpm"
65 #include "melt.xpm"
66 #include "copy.xpm"
67 #include "noun.xpm"
68 #include "paste.xpm"
69 #include "free.xpm"
70 #include "tab.xpm"
71 #include "tex.xpm"
72 #include "open.xpm"
73 #include "close.xpm"
74 #include "save.xpm"
75 #include "print1.xpm"
76 #include "quit.xpm"
77 #include "typeset_ps.xpm"
78 #include "unknown.xpm"
79 #endif
80
81 // These pixmaps are the same regardless of color:
82 #include "bold_bw.xpm"
83 #include "make_ascii_bw.xpm"
84 #include "make_latex_bw.xpm"
85 #include "run_latex_bw.xpm"
86 #include "sans_bw.xpm"
87 #include "view_dvi_bw.xpm"
88 #include "view_ps_bw.xpm"
89 #include "layout_code.xpm"
90 #include "layout_latex.xpm"
91 #include "layout_scrap.xpm"
92 #include "layout_sec.xpm"
93 #include "layout_std.xpm"
94 #include "build.xpm"
95
96 using std::endl;
97
98 // this one is not "C" because combox callbacks are really C++ %-|
99 extern void LayoutsCB(int, void *);
100 extern char const ** get_pixmap_from_symbol(char const * arg, int, int);
101 extern LyXAction lyxaction;
102
103
104 Toolbar::Toolbar(LyXView * o, int x, int y)
105         : owner(o), sxpos(x), sypos(y)
106 {
107         combox = 0;
108 #if FL_REVISION < 89
109         bubble_timer = 0;
110 #endif
111         reset();
112
113         // extracts the default toolbar actions from LyXRC
114         for (ToolbarDefaults::const_iterator cit =
115                      lyxrc.toolbardefaults.begin();
116              cit != lyxrc.toolbardefaults.end(); ++cit) {
117                 add((*cit));
118                 lyxerr[Debug::TOOLBAR] << "tool action: "
119                                        << (*cit) << endl;
120         }
121 }
122
123
124 #if FL_REVISION < 89
125 // timer-cb for bubble-help (Matthias)
126 void Toolbar::BubbleTimerCB(FL_OBJECT *, long data)
127 {
128         FL_OBJECT * ob = reinterpret_cast<FL_OBJECT*>(data);
129         char * help = static_cast<char*>(ob->u_vdata);
130         fl_show_oneliner(help, ob->form->x + ob->x,
131                          ob->form->y + ob->y + ob->h);
132 }
133
134
135 extern "C" void C_Toolbar_BubbleTimerCB(FL_OBJECT * ob, long data)
136 {
137         Toolbar::BubbleTimerCB(ob, data);
138 }
139
140
141 // post_handler for bubble-help (Matthias)
142 int Toolbar::BubblePost(FL_OBJECT *ob, int event,
143                         FL_Coord /*mx*/, FL_Coord /*my*/,
144                         int /*key*/, void */*xev*/)
145 {
146         string help = static_cast<char *>(ob->u_vdata);
147         Toolbar * t = reinterpret_cast<Toolbar*>(ob->u_ldata);
148         
149         if(event == FL_ENTER && !help.empty()){
150                 fl_set_object_callback(t->bubble_timer,
151                                        C_Toolbar_BubbleTimerCB,
152                                        reinterpret_cast<long>(ob));
153                 fl_set_timer(t->bubble_timer, 1);
154         }
155         else if(event != FL_MOTION){
156                 fl_set_timer(t->bubble_timer, 0);
157                 fl_hide_oneliner();
158         }
159         return 0;
160 }
161
162
163 extern "C" int C_Toolbar_BubblePost(FL_OBJECT * ob, int event,
164                                     FL_Coord /*mx*/, FL_Coord /*my*/, 
165                                     int key, void * xev)
166 {
167         return Toolbar::BubblePost(ob, event, 0, 0, key, xev);
168 }
169 #endif
170
171
172 void Toolbar::activate()
173 {
174         toolbarItem * tmp= 0;
175         toolbarItem * item = toollist;
176         while(item){
177                 tmp = item->next;
178                 if (item->icon) {
179                         fl_activate_object(item->icon);
180                 }
181                 item = tmp;
182         }
183 }
184
185
186 void Toolbar::deactivate()
187 {
188         toolbarItem * tmp= 0;
189         toolbarItem * item = toollist;
190         while(item){
191                 tmp = item->next;
192                 if (item->icon) {
193                         fl_deactivate_object(item->icon);
194                 }
195                 item = tmp;
196         }
197 }
198
199
200 void Toolbar::ToolbarCB(FL_OBJECT * ob, long ac)
201 {
202 #if FL_REVISION >= 89
203         Toolbar * t = static_cast<Toolbar*>(ob->u_vdata);
204 #else
205         Toolbar * t = reinterpret_cast<Toolbar*>(ob->u_ldata);
206 #endif
207         
208         string res = t->owner->getLyXFunc()->Dispatch(int(ac));
209         if(!res.empty())
210                 lyxerr[Debug::TOOLBAR] << res << endl;
211 }
212
213
214 extern "C" void C_Toolbar_ToolbarCB(FL_OBJECT * ob, long data)
215 {
216         Toolbar::ToolbarCB(ob, data);
217 }
218
219
220 int Toolbar::get_toolbar_func(string const & func)
221 {
222         int action = lyxaction.LookupFunc(func.c_str());
223         if (action == -1) {
224                 if (func == "separator"){
225                         action = TOOL_SEPARATOR;
226                 } else if (func == "layouts"){
227                         action = TOOL_LAYOUTS;
228                 } else action = 0;
229         }
230         return action;
231 }
232
233
234 void Toolbar::set(bool doingmain)
235 {
236         // we shouldn't set if we have not cleaned
237         if (!cleaned) return;
238         
239         FL_OBJECT * obj;
240         toolbarItem * item = toollist;
241         
242         if (!doingmain) {
243                 fl_freeze_form(owner->getForm());
244                 fl_addto_form(owner->getForm());
245         }
246
247 #if FL_REVISION < 89
248         // add the time if it don't exist
249         if (bubble_timer == 0)
250                 bubble_timer = fl_add_timer(FL_HIDDEN_TIMER,
251                                             xpos, ypos, 0, 0, "Timer");
252 #endif
253         
254         while(item != 0) {
255                 switch(item->action){
256                 case TOOL_SEPARATOR:
257                         xpos += sepspace;
258                         item = item->next;
259                         break;
260                 case TOOL_LAYOUTS:
261                         xpos += standardspacing;
262                         if (!combox)
263                                 combox = new Combox(FL_COMBOX_DROPLIST);
264                         combox->add(xpos, ypos, 135, height, 400);
265                         combox->setcallback(LayoutsCB);
266                         combox->resize(FL_RESIZE_ALL);
267                         combox->gravity(NorthWestGravity, NorthWestGravity);
268                         item = item->next;
269                         xpos += 135;
270                         break;
271                 default:
272                         xpos += standardspacing;
273                         item->icon = obj = 
274                                 fl_add_pixmapbutton(FL_NORMAL_BUTTON,
275                                                     xpos, ypos,
276                                                     buttonwidth,
277                                                     height, "");
278                         fl_set_object_boxtype(obj, FL_UP_BOX);
279                         fl_set_object_color(obj, FL_MCOL, FL_BLUE);
280                         fl_set_object_resize(obj, FL_RESIZE_ALL);
281                         fl_set_object_gravity(obj,
282                                               NorthWestGravity,
283                                               NorthWestGravity);
284                         fl_set_object_callback(obj, C_Toolbar_ToolbarCB,
285                                                static_cast<long>(item->action));
286                         // Remove the blue feedback rectangle
287                         fl_set_pixmapbutton_focus_outline(obj, 0);
288
289                         // set the bubble-help (Matthias)
290 #if FL_REVISION >= 89
291                         // Set the tooltip
292                         fl_set_object_helper(obj, item->help.c_str());
293                         // The toolbar that this object belongs too.
294                         obj->u_vdata = this;
295                         
296                         
297 #else
298 #ifdef WITH_WARNINGS
299 #warning This is dangerous!
300 #endif
301                         obj->u_vdata = const_cast<char*>(item->help.c_str());
302                         // we need to know what toolbar this item
303                         // belongs too. (Lgb)
304                         obj->u_ldata = reinterpret_cast<long>(this);
305                           
306                         fl_set_object_posthandler(obj, C_Toolbar_BubblePost);
307 #endif
308
309                         fl_set_pixmapbutton_data(obj, const_cast<char**>(item->pixmap));
310                         item = item->next;
311                         // we must remember to update the positions
312                         xpos += buttonwidth;
313                         // ypos is constant
314                         /* Here will come a check to see if the new
315                          * pos is within the bounds of the main frame,
316                          * and perhaps wrap the toolbar if not.
317                          */
318                         break;
319                 }
320         }
321
322         if (!doingmain) {
323                 fl_end_form();
324                 fl_unfreeze_form(owner->getForm());
325                 // Should be safe to do this here.
326                 owner->updateLayoutChoice();
327         }
328         
329         cleaned = false;
330 }
331
332
333 char const ** Toolbar::getPixmap(kb_action action, string const & arg)
334 {
335         char const ** pixmap = unknown_xpm; //0
336         switch(action){
337         case LFUN_MENUOPEN:    pixmap = open_xpm; break;
338         case LFUN_CLOSEBUFFER: pixmap = close_xpm; break;
339         case LFUN_MENUPRINT:   pixmap = print1_xpm; break;
340         case LFUN_MENUWRITE:   pixmap = save_xpm; break;
341         case LFUN_EMPH:  pixmap = emph_xpm; break;
342         case LFUN_NOUN:        pixmap = noun_xpm; break;
343         case LFUN_FREE:        pixmap = free_xpm; break;
344         case LFUN_FOOTMELT:    pixmap = foot_xpm; break;
345         case LFUN_DEPTH:       pixmap = depth_xpm; break;
346         case LFUN_COPY:        pixmap = copy_xpm; break;
347         case LFUN_CUT:         pixmap = cut_xpm; break;
348         case LFUN_PASTE:       pixmap = paste_xpm; break;
349         case LFUN_TEX:         pixmap = tex_xpm; break;
350         case LFUN_MATH_MODE:   pixmap = math_xpm; break;
351         case LFUN_MARGINMELT:  pixmap = margin_xpm; break;
352         case LFUN_FIGURE:      pixmap = fig_xpm; break;
353         case LFUN_TABLE:       pixmap = tab_xpm; break;
354         case LFUN_MELT:        pixmap = melt_xpm; break;
355         case LFUN_QUIT:        pixmap = quit_xpm; break;
356         case LFUN_RUNDVIPS:    pixmap = update_ps_xpm; break;
357         case LFUN_EXPORT:
358         {
359                 if (arg == "ascii")
360                         pixmap = make_ascii_xpm;
361                 else if (arg == "latex")
362                         pixmap = make_latex_xpm;
363         }
364         break; 
365         case LFUN_LAYOUT:
366         {
367                 if (arg == "Section")
368                         pixmap = layout_sec_xpm;
369                 else if (arg == "LaTeX")
370                         pixmap = layout_latex_xpm;
371                 else if (arg == "LyX-Code")
372                         pixmap = layout_code_xpm;
373                 else if (arg == "Scrap")
374                         pixmap = layout_scrap_xpm;
375                 else
376                         pixmap = layout_std_xpm;
377         }
378         break;
379
380         case LFUN_BOLD : pixmap = bold_xpm; break; 
381         case LFUN_SANS: pixmap = sans_xpm; break; 
382         case LFUN_RUNLATEX: pixmap = run_latex_xpm; break; 
383         case LFUN_BUILDPROG: pixmap = build_xpm; break; 
384         case LFUN_PREVIEWPS: pixmap = view_ps_xpm; break; 
385         case LFUN_PREVIEW: pixmap = view_dvi_xpm; break; 
386         case LFUN_INSERT_MATH:
387         {
388                 if (!arg.empty())
389                         pixmap = get_pixmap_from_symbol(arg.c_str(),
390                                                         buttonwidth,
391                                                         height);
392         }
393         break;
394         default:
395                 //pixmap = unknown_xpm;
396                 break;
397         }
398         return pixmap;
399 }
400
401
402 void Toolbar::add(int action, bool doclean)
403 {
404         if (doclean && !cleaned) clean();
405
406         // this is what we do if we want to add to an existing
407         // toolbar.
408         if (!doclean && owner) {
409                 // first «hide» the toolbar buttons. This is not a real hide
410                 // actually it deletes and frees the button altogether.
411                 lyxerr << "Toolbar::add: «hide» the toolbar buttons." << endl;
412                 toolbarItem * tmp= 0;
413                 toolbarItem * item = toollist;
414
415                 lightReset();
416                 
417                 fl_freeze_form(owner->getForm());
418                 while(item){
419                         tmp = item->next;
420                         if (item->icon) {
421                                 fl_delete_object(item->icon);
422                                 fl_free_object(item->icon);
423                         }
424                         item = tmp;
425                 }
426                 if (combox) {
427                         delete combox;
428                         combox = 0;
429                 }
430                 fl_unfreeze_form(owner->getForm());
431                 cleaned = true; // this is not completely true, but OK anyway
432         }
433         
434         // there exist some special actions not part of
435         // kb_action: SEPARATOR, LAYOUTS
436         char const ** pixmap = 0;
437         string help;
438
439         toolbarItem * newItem, * tmp;
440
441         if (lyxaction.isPseudoAction(action)) {
442                 string arg;
443                 kb_action act = static_cast<kb_action>
444                         (lyxaction.retrieveActionArg(action, arg));
445                 pixmap = getPixmap(act, arg);
446                 help = lyxaction.helpText(act);
447                 help += " ";
448                 help += arg;
449                 lyxerr.debug() << "Pseudo action " << action << endl;
450         } else {
451                 pixmap = getPixmap(static_cast<kb_action>(action));
452                 help = lyxaction.helpText(static_cast<kb_action>(action));
453         }
454         
455         // adds an item to the list
456         if (pixmap != 0
457             || action == TOOL_SEPARATOR
458             || action == TOOL_LAYOUTS) {
459                 newItem = new toolbarItem;
460                 newItem->action = action;
461                 newItem->pixmap = pixmap;
462                 newItem->help = help;
463                 // the new item is placed at the end of the list
464                 tmp = toollist;
465                 if (tmp != 0){
466                         while(tmp->next != 0)
467                                 tmp = tmp->next;
468                                 // here is tmp->next == 0
469                         tmp->next = newItem;
470                 } else
471                         toollist = newItem;
472         }
473 }
474
475
476 void Toolbar::clean()
477 {
478         toolbarItem * tmp = 0;
479         toolbarItem * item = toollist;
480
481         reset();
482
483         //now delete all the objects..
484         if (owner)
485                 fl_freeze_form(owner->getForm());
486         while (item) {
487                 tmp = item->next;
488                 delete item;
489                 item = tmp;
490         }
491         lyxerr[Debug::TOOLBAR] << "Combox: " << combox << endl;
492         if (combox) {
493                 delete combox;
494                 combox = 0;
495         }
496         if (owner)
497                 fl_unfreeze_form(owner->getForm());
498         lyxerr[Debug::TOOLBAR] << "toolbar cleaned" << endl;
499         cleaned = true;
500 }
501
502
503 void Toolbar::push(int nth)
504 {
505         lyxerr[Debug::TOOLBAR] << "Toolbar::push: trying to trigger no `"
506                                << nth << '\'' << endl;
507         
508         if (nth == 0) return;
509
510         int count = 0;
511         toolbarItem * tmp = toollist;
512         while (tmp) {
513                 ++count;
514                 if (count == nth) {
515                         fl_trigger_object(tmp->icon);
516                         return;
517                 }
518                 tmp = tmp->next;
519         }
520         // item nth not found...
521         LyXBell();
522 }
523
524
525 void Toolbar::add(string const & func, bool doclean)
526 {
527         int tf = lyxaction.LookupFunc(func);
528
529         if (tf == -1) {
530                 lyxerr << "Toolbar::add: no LyX command called`"
531                        << func << "'exists!" << endl; 
532         } else {
533                 add(tf, doclean);
534         }
535 }
536
537
538 void Toolbar::reset() 
539 {
540         toollist = 0;
541         cleaned = false;
542         lightReset();
543 }
544
545 //  void Toolbar::lightReset()
546 //  {
547 //      standardspacing = 2; // the usual space between items
548 //      sepspace = 6; // extra space
549 //      xpos = sxpos - standardspacing;
550 //      ypos = sypos;
551 //      buttonwidth = 30; // the standard button width
552 //      height = 30; // the height of all items in the toolbar
553 //  }