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