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