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