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