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