]> git.lyx.org Git - lyx.git/blob - src/toolbar.C
28ff89134d30e26ab174e1b5f5d119769d4f8344
[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 {
141         FL_OBJECT* ob = (FL_OBJECT*) data;
142         char* help = (char*) ob->u_vdata;
143         fl_show_oneliner(help, ob->form->x + ob->x,
144                          ob->form->y + ob->y + ob->h);
145 }
146
147 extern "C" void C_Toolbar_BubbleTimerCB(FL_OBJECT *ob, long data)
148 {
149         Toolbar::BubbleTimerCB(ob, data);
150 }
151
152 // post_handler for bubble-help (Matthias)
153 int Toolbar::BubblePost(FL_OBJECT *ob, int event,
154              FL_Coord /*mx*/, FL_Coord /*my*/, int /*key*/, void */*xev*/)
155 {
156         string help = (char *)ob->u_vdata;
157         Toolbar *t = (Toolbar*)ob->u_ldata;
158         
159         if(event == FL_ENTER && !help.empty()){
160                 fl_set_object_callback(t->bubble_timer,
161                                        C_Toolbar_BubbleTimerCB, (long) ob);
162                 fl_set_timer(t->bubble_timer, 1);
163         }
164         else if(event != FL_MOTION){
165                 fl_set_timer(t->bubble_timer, 0);
166                 fl_hide_oneliner();
167         }
168         return 0;
169 }
170
171 extern "C" int C_Toolbar_BubblePost(FL_OBJECT *ob, int event,
172                                    FL_Coord /*mx*/, FL_Coord /*my*/, 
173                                    int key, void *xev)
174 {
175         return Toolbar::BubblePost(ob,event,0,0,key,xev);
176 }
177
178 void Toolbar::activate()
179 {
180         toolbarItem *item, *tmp=0;
181         item = toollist;
182         while(item){
183                 tmp = item->next;
184                 if (item->icon) {
185                         fl_activate_object(item->icon);
186                 }
187                 item = tmp;
188         }
189 }
190
191
192 void Toolbar::deactivate()
193 {
194         toolbarItem *item, *tmp=0;
195         item = toollist;
196         while(item){
197                 tmp = item->next;
198                 if (item->icon) {
199                         fl_deactivate_object(item->icon);
200                 }
201                 item = tmp;
202         }
203 }
204
205
206 void Toolbar::ToolbarCB(FL_OBJECT *ob, long ac)
207 {
208         Toolbar *t = (Toolbar*)ob->u_ldata;
209         
210         string res = t->owner->getLyXFunc()->Dispatch(int(ac));
211         if(!res.empty())
212                 lyxerr[Debug::TOOLBAR] << res << endl;
213 }
214
215 extern "C" void C_Toolbar_ToolbarCB(FL_OBJECT *ob, long data)
216 {
217         Toolbar::ToolbarCB(ob, data);
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::init()
235 {
236         add(TOOL_LAYOUTS);
237         add(LFUN_MENUOPEN);
238         //add(LFUN_CLOSEBUFFER);
239         add(LFUN_MENUWRITE);
240         add(LFUN_MENUPRINT);
241         add(TOOL_SEPARATOR);
242
243         add(LFUN_CUT);
244         add(LFUN_COPY);
245         add(LFUN_PASTE);
246         add(TOOL_SEPARATOR);
247         
248         add(LFUN_EMPH);
249         add(LFUN_NOUN);
250         add(LFUN_FREE);
251         add(TOOL_SEPARATOR);
252         
253         add(LFUN_FOOTMELT);
254         add(LFUN_MARGINMELT);
255         add(LFUN_DEPTH);
256         add(TOOL_SEPARATOR);
257
258         add(LFUN_TEX);
259         add(LFUN_MATH_MODE);
260         add(TOOL_SEPARATOR);
261
262         add(LFUN_FIGURE);
263         add(LFUN_TABLE);
264         //add(LFUN_MELT);
265 }
266
267
268 void Toolbar::set(bool doingmain)
269 {
270         // we shouldn't set if we have not cleaned
271         if (!cleaned) return;
272         
273         toolbarItem *item;
274         FL_OBJECT *obj;
275         item = toollist;
276         
277         if (!doingmain) {
278                 fl_freeze_form(owner->getForm());
279                 fl_addto_form(owner->getForm());
280         }
281
282 #if FL_REVISION <86
283         // Ensure borderwidth is 2 to get visual feedback
284         int bw = fl_get_border_width();
285         fl_set_border_width(-2);
286 #endif
287
288         // add the time if it don't exist
289         if (bubble_timer == 0)
290                 bubble_timer = fl_add_timer(FL_HIDDEN_TIMER,
291                                             xpos,ypos,0,0,"Timer");
292         
293         while(item != 0) {
294                 switch(item->action){
295                   case TOOL_SEPARATOR:
296                           xpos += sepspace;
297                           item = item->next;
298                           break;
299                   case TOOL_LAYOUTS:
300                           xpos += standardspacing;
301                           if (!combox)
302                                   combox = new Combox(FL_COMBOX_DROPLIST);
303                           combox->add(xpos, ypos, 135, height, 300);
304                           combox->setcallback(LayoutsCB);
305                           combox->resize(FL_RESIZE_ALL);
306                           combox->gravity(NorthWestGravity, NorthWestGravity);
307                           item = item->next;
308                           xpos += 135;
309                           break;
310                   default:
311                           xpos += standardspacing;
312                           item->icon = obj =
313                                   fl_add_pixmapbutton(FL_NORMAL_BUTTON,
314                                                       xpos,ypos,
315                                                       buttonwidth,
316                                                       height,"");
317                           fl_set_object_boxtype(obj,FL_UP_BOX);
318                           fl_set_object_color(obj,FL_MCOL,FL_BLUE);
319                           fl_set_object_resize(obj, FL_RESIZE_ALL);
320                           fl_set_object_gravity(obj,
321                                                 NorthWestGravity,
322                                                 NorthWestGravity);
323                           fl_set_object_callback(obj,C_Toolbar_ToolbarCB,
324                                                  (long)item->action);
325 #if FL_REVISION >85
326                           // Remove the blue feedback rectangle
327                           fl_set_pixmapbutton_focus_outline(obj,0);
328 #endif
329
330                           // set the bubble-help (Matthias)
331                           obj->u_vdata = (void *) item->help.c_str();
332                           // we need to know what toolbar this item
333                           // belongs too. (Lgb)
334                           obj->u_ldata = (long) this;
335                           
336                           fl_set_object_posthandler(obj, C_Toolbar_BubblePost);
337
338                           fl_set_pixmapbutton_data(obj,item->pixmap);
339                           item = item->next;
340                           // we must remember to update the positions
341                           xpos += buttonwidth;
342                           // ypos is constant
343                           /* Here will come a check to see if the new
344                            * pos is within the bounds of the main frame,
345                            * and perhaps wrap the toolbar if not.
346                            */
347                           break;
348                 }
349         }
350 #if FL_REVISION <86
351         // Reset borderwidth to its default value.
352         fl_set_border_width(bw);
353 #endif
354         if (!doingmain) {
355                 fl_end_form();
356                 fl_unfreeze_form(owner->getForm());
357                 // Should be safe to do this here.
358                 owner->updateLayoutChoice();
359         }
360         
361         cleaned = false;
362 }
363
364
365 char **Toolbar::getPixmap(kb_action action, string const & arg)
366 {
367         char **pixmap = unknown_xpm; //0
368         switch(action){
369         case LFUN_MENUOPEN:    pixmap = open_xpm; break;
370         case LFUN_CLOSEBUFFER: pixmap = close_xpm; break;
371         case LFUN_MENUPRINT:   pixmap = print1_xpm; break;
372         case LFUN_MENUWRITE:   pixmap = save_xpm; break;
373         case LFUN_EMPH:  pixmap = emph_xpm; break;
374         case LFUN_NOUN:        pixmap = noun_xpm; break;
375         case LFUN_FREE:        pixmap = free_xpm; break;
376         case LFUN_FOOTMELT:    pixmap = foot_xpm; break;
377         case LFUN_DEPTH:       pixmap = depth_xpm; break;
378         case LFUN_COPY:        pixmap = copy_xpm; break;
379         case LFUN_CUT:         pixmap = cut_xpm; break;
380         case LFUN_PASTE:       pixmap = paste_xpm; break;
381         case LFUN_TEX:         pixmap = tex_xpm; break;
382         case LFUN_MATH_MODE:   pixmap = math_xpm; break;
383         case LFUN_MARGINMELT:  pixmap = margin_xpm; break;
384         case LFUN_FIGURE:      pixmap = fig_xpm; break;
385         case LFUN_TABLE:       pixmap = tab_xpm; break;
386         case LFUN_MELT:        pixmap = melt_xpm; break;
387         case LFUN_QUIT:        pixmap = quit_xpm; break;
388         case LFUN_RUNDVIPS:    pixmap = update_ps_xpm; break;
389         case LFUN_EXPORT:
390         {
391                 if (arg == "ascii")
392                         pixmap = make_ascii_xpm;
393                 else if (arg == "latex")
394                         pixmap = make_latex_xpm;
395         }
396         break; 
397         case LFUN_LAYOUT:
398         {
399                 if (arg == "Section")
400                         pixmap = layout_sec_xpm;
401                 else if (arg == "LaTeX")
402                         pixmap = layout_latex_xpm;
403                 else if (arg == "LyX-Code")
404                         pixmap = layout_code_xpm;
405                 else if (arg == "Scrap")
406                         pixmap = layout_scrap_xpm;
407                 else
408                         pixmap = layout_std_xpm;
409         }
410         break;
411
412         case LFUN_BOLD : pixmap = bold_xpm; break; 
413         case LFUN_SANS: pixmap = sans_xpm; break; 
414         case LFUN_RUNLATEX: pixmap = run_latex_xpm; break; 
415         case LFUN_BUILDPROG: pixmap = build_xpm; break; 
416         case LFUN_PREVIEWPS: pixmap = view_ps_xpm; break; 
417         case LFUN_PREVIEW: pixmap = view_dvi_xpm; break; 
418         case LFUN_INSERT_MATH:
419         {
420                 if (!arg.empty())
421                         pixmap = get_pixmap_from_symbol(arg.c_str(),
422                                                         buttonwidth,
423                                                         height);
424         }
425         break;
426         default:
427                 //pixmap = unknown_xpm;
428                 break;
429         }
430         return pixmap;
431 }
432
433
434 void Toolbar::add(int action, bool doclean)
435 {
436         if (doclean && !cleaned) clean();
437
438         // this is what we do if we want to add to an existing
439         // toolbar.
440         if (!doclean && owner) {
441                 // first «hide» the toolbar buttons. This is not a real hide
442                 // actually it deletes and frees the button altogether.
443                 lyxerr << "Toolbar::add: «hide» the toolbar buttons." << endl;
444                 toolbarItem *item, *tmp=0;
445                 item = toollist;
446
447                 lightReset();
448                 
449                 fl_freeze_form(owner->getForm());
450                 while(item){
451                         tmp = item->next;
452                         if (item->icon) {
453                                 fl_delete_object(item->icon);
454                                 fl_free_object(item->icon);
455                         }
456                         item = tmp;
457                 }
458                 if (combox) {
459                         delete combox;
460                         combox = 0;
461                 }
462                 fl_unfreeze_form(owner->getForm());
463                 cleaned = true; // this is not completely true, but OK anyway
464         }
465         
466         // there exist some special actions not part of
467         // kb_action: SEPARATOR, LAYOUTS
468         char **pixmap = 0;
469         string help;
470
471         toolbarItem *newItem,*tmp;
472
473         if (lyxaction.isPseudoAction(action)) {
474                 char const *arg;
475                 kb_action act = (kb_action)lyxaction.retrieveActionArg(action, &arg);
476                 pixmap = getPixmap(act, arg);
477                 help = lyxaction.helpText(act);
478                 help += " ";
479                 help += arg;
480                 lyxerr.debug() << "Pseudo action " << action << endl;
481         } else {
482                 pixmap = getPixmap((kb_action)action);
483                 help = lyxaction.helpText((kb_action)action);
484         }
485         
486         // adds an item to the list
487         if (pixmap != 0
488             || action == TOOL_SEPARATOR
489             || action == TOOL_LAYOUTS)
490         {
491                 newItem = new toolbarItem;
492                 newItem->action = action;
493                 newItem->pixmap = pixmap;
494                 newItem->help = help;
495                 // the new item is placed at the end of the list
496                 tmp = toollist;
497                 if (tmp != 0){
498                         while(tmp->next != 0)
499                                 tmp = tmp->next;
500                         // here is tmp->next == 0
501                         tmp->next = newItem;
502                 } else
503                         toollist = newItem;
504         }
505         //if (action == TOOL_LAYOUTS) {
506         //      combox = new Combox(FL_COMBOX_DROPLIST);
507         //}
508 }
509
510
511 void Toolbar::add(string const & func, bool doclean)
512 {
513         int tf = lyxaction.LookupFunc(func.c_str());
514
515         if (tf == -1){
516                 lyxerr << "Toolbar::add: no LyX command called`"
517                        << func << "'exists!" << endl; 
518         } else {
519                 add(tf, doclean);
520         }
521 }
522
523
524 void Toolbar::clean()
525 {
526         toolbarItem *item, *tmp= 0;
527         item = toollist;
528
529         reset();
530
531         //now delete all the objects..
532         if (owner)
533                 fl_freeze_form(owner->getForm());
534         while (item) {
535                 tmp = item->next;
536                 delete item;
537                 item = tmp;
538         }
539         lyxerr[Debug::TOOLBAR] << "Combox: " << combox << endl;
540         if (combox) {
541                 delete combox;
542                 combox = 0;
543         }
544         if (owner)
545                 fl_unfreeze_form(owner->getForm());
546         lyxerr[Debug::TOOLBAR] << "toolbar cleaned" << endl;
547         cleaned = true;
548 }
549
550
551 void Toolbar::push(int nth)
552 {
553         lyxerr[Debug::TOOLBAR] << "Toolbar::push: trying to trigger no `"
554                                << nth << '\'' << endl;
555         
556         if (nth == 0) return;
557
558         int count=0;
559         toolbarItem *tmp = toollist;
560         while (tmp) {
561                 count++;
562                 if (count == nth) {
563                         fl_trigger_object(tmp->icon);
564                         return;
565                 }
566                 tmp = tmp->next;
567         }
568         // item nth not found...
569         LyXBell();
570 }
571
572
573 void Toolbar::read(LyXLex &lex)
574 {
575         //consistency check
576         if (lex.GetString() != "\\begin_toolbar")
577                 lyxerr << "Toolbar::read: ERROR wrong token:`"
578                        << lex.GetString() << '\'' << endl;
579
580         clean();
581         string func;
582         bool quit = false;
583         
584         lex.pushTable(toolTags, TO_LAST - 1);
585
586         if (lyxerr.debugging(Debug::PARSER))
587                 lex.printTable();
588         
589         while (lex.IsOK() && !quit) {
590                 
591                 lyxerr[Debug::TOOLBAR] << "Toolbar::read: current lex text: `"
592                                        << lex.GetString() << '\'' << endl;
593
594                 switch(lex.lex()) {
595                   case TO_ADD:
596                           if (lex.EatLine()) {
597                                   func = lex.GetString();
598                                   lyxerr[Debug::TOOLBAR]
599                                           << "Toolbar::read TO_ADD func: `"
600                                           << func << "'" << endl;
601                                   add(func);
602                           }
603                           break;
604                    
605                   case TO_SEPARATOR:
606                           add(TOOL_SEPARATOR);
607                           break;
608                    
609                   case TO_LAYOUTS:
610                           add(TOOL_LAYOUTS);
611                           break;
612                    
613                   case TO_NEWLINE:
614                           add(TOOL_NEWLINE);
615                           break;
616                         
617                   case TO_ENDTOOLBAR:
618                           // should not set automatically
619                           //set();
620                           quit = true;
621                           break;
622                   default:
623                           lex.printError("Toolbar::read: "
624                                           "Unknown toolbar tag: `$$Token'");
625                           break;
626                 }
627         }
628         lex.popTable();
629 }