]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/Menubar_pimpl.C
9f01bd3348d24d9b7f6a6f4fd850579ff0c01f45
[lyx.git] / src / frontends / xforms / Menubar_pimpl.C
1 /* This file is part of
2 * ======================================================
3
4 *           LyX, The Document Processor
5 *        
6 *           Copyright (C) 1999 The LyX Team.
7 *
8 *======================================================*/
9
10 #ifdef __GNUG__
11 #pragma implementation
12 #endif
13
14 #include <config.h>
15
16 #include <algorithm>
17 #include <cctype>
18 #include "support/lstrings.h"
19 #include "support/filetools.h"
20 #include "support/LAssert.h"
21 #include "debug.h"
22 #include "LyXAction.h"
23 #include "lyxfunc.h"
24 #include "kbmap.h"
25 #include "bufferlist.h"
26 #include "lastfiles.h"
27 #include "LyXView.h"
28 #include "MenuBackend.h"
29 #include "Menubar_pimpl.h"
30 #include "exporter.h"
31
32 using std::pair;
33 using std::endl;
34 using std::vector;
35
36 typedef vector<int>::size_type size_type;
37
38 extern kb_keymap * toplevel_keymap;
39 extern LyXAction lyxaction;
40 extern BufferList bufferlist;
41 extern LastFiles * lastfiles; 
42
43 // Some constants
44 const int MENU_LABEL_SIZE = FL_NORMAL_SIZE;
45 const int mheight = 30;
46 const int mbheight= 22;
47 // where to place the menubar?
48 const int yloc = (mheight - mbheight)/2; //air + bw;
49 const int mbadd = 20; // menu button add (to width)
50 // Some space between buttons on the menubar 
51 const int air = 2;
52 char const * menu_tabstop = "aa";
53 char const * default_tabstop = "aaaaaaaa";
54
55
56 Menubar::Pimpl::Pimpl(LyXView * view, MenuBackend const & mb) 
57         : frame_(0), owner_(view), menubackend_(&mb)
58 {
59         // Should we do something here?
60 }
61
62 Menubar::Pimpl::~Pimpl() 
63 {
64         // Should we do something here?
65 }
66
67 // This is used a few times below.
68 inline
69 int string_width(string const & str) 
70 {
71         return fl_get_string_widthTAB(FL_NORMAL_STYLE, MENU_LABEL_SIZE,
72                                       str.c_str(),      str.length());
73 }
74
75 //Defined later, used in set().
76 extern "C"
77 void C_Menubar_Pimpl_MenuCallback(FL_OBJECT * ob, long button);
78
79 void Menubar::Pimpl::set(string const & menu_name) 
80 {
81         lyxerr[Debug::GUI] << "Entering Menubar::Pimpl::set " 
82                            << "for menu `" << menu_name << "'" << endl;
83
84         if (menu_name == current_menu) {
85                 lyxerr[Debug::GUI] << "Nothing to do." << endl;
86                 return;
87         }
88
89         // If the backend has not been initialized yet, we use a
90         // default instead.  
91         if (menubackend_->empty()) {
92                 lyxerr << "Menubar::Pimpl::set: menubackend is empty! "
93                         "using default values." << endl;
94                 MenuBackend * mb = new MenuBackend();
95                 mb->defaults();
96                 menubackend_ = mb;
97         }
98
99         if (!menubackend_->hasMenu(menu_name)){ 
100                 lyxerr << "ERROR:set: Unknown menu `" << menu_name
101                        << "'" << endl;
102                 return;
103         }
104
105         Menu menu = menubackend_->getMenu(menu_name);
106
107         if (!menu.menubar()) {
108                 lyxerr << "Only a menubar-type object can go in a "
109                         "toplevel menu" << endl;
110                 return;
111         }
112
113         current_menu = menu_name;
114         FL_FORM * form = owner_->getForm(); 
115         int moffset = 0;
116         bool form_was_open, form_was_frozen;
117
118         if (fl_current_form == form)
119                 form_was_open = true;
120         else if (fl_current_form == 0) {
121                 form_was_open = false;
122                 fl_addto_form(form);
123         } 
124         else {
125                 lyxerr << "Something is wrong: unknown form " 
126                        << fl_current_form << " is already open" 
127                        << "(main form is " << form << ")" << endl;
128                 return;
129         }
130         if (form->frozen)
131                 form_was_frozen = true;
132         else {
133                 form_was_frozen = false;
134                 fl_freeze_form(form);
135         }
136
137         // Delete old buttons if there are some.
138         for(ButtonList::const_iterator cit = buttonlist_.begin();
139             cit != buttonlist_.end(); ++cit) {
140                 if ((*cit)->obj_) {
141                         fl_delete_object((*cit)->obj_);
142                         fl_free_object((*cit)->obj_);
143                 }
144                 delete (*cit);
145         }
146         buttonlist_.clear();
147
148         // Create menu frame if there is non yet.
149         if (!frame_) {
150                 frame_ = fl_add_frame(FL_UP_FRAME, 0, 0, form->w, mheight, "");
151                 fl_set_object_resize(frame_, FL_RESIZE_ALL);
152                 fl_set_object_gravity(frame_, NorthWestGravity, 
153                                       NorthEastGravity);
154         } 
155
156         for (Menu::const_iterator i = menu.begin(); 
157              i != menu.end(); ++i) {
158                 FL_OBJECT * obj;
159                 if (i->kind() != MenuItem::Submenu) {
160                         lyxerr << "ERROR: Menubar::Pimpl::Pimpl:"
161                                 " only submenus can appear in a menubar";
162                         break;
163                 }
164                 string label = i->label();
165                 string shortcut = '#' + i->shortcut();
166                 int width = string_width(label);
167                 obj = fl_add_button(FL_TOUCH_BUTTON,
168                                     air + moffset, yloc,
169                                     width + mbadd,
170                                     mbheight, 
171                                     label.c_str());
172                 fl_set_object_boxtype(obj, FL_FLAT_BOX);
173                 fl_set_object_color(obj, FL_MCOL, FL_MCOL);
174                 fl_set_object_lsize(obj, MENU_LABEL_SIZE);
175                 fl_set_object_lstyle(obj, FL_NORMAL_STYLE);
176                 fl_set_object_resize(obj, FL_RESIZE_ALL);
177                 fl_set_object_gravity(obj, NorthWestGravity, 
178                                       NorthWestGravity);
179                 moffset += obj->w + air;
180                 fl_set_object_shortcut(obj, shortcut.c_str(), 1);
181                 fl_set_object_callback(obj, C_Menubar_Pimpl_MenuCallback, 1);
182
183                 ItemInfo * iteminfo = new ItemInfo(this, 
184                                                    new MenuItem(*i), obj);
185                 buttonlist_.push_back(iteminfo);
186                 obj->u_vdata = iteminfo;
187 //              lyxerr << "MenuCallback: ItemInfo address=" << iteminfo
188 //                     << " Val=(pimpl_=" << iteminfo->pimpl_
189 //                     << ", item_=" << iteminfo->item_
190 //                     << ", obj_=" << iteminfo->obj_ << ")" <<endl;
191         }
192
193         if (!form_was_frozen) {
194                 fl_unfreeze_form(form);
195         }
196         if (!form_was_open) 
197                 fl_end_form();
198
199         // Force the redraw of the buttons (probably not the best
200         // method, but...) 
201         for(ButtonList::const_iterator cit = buttonlist_.begin();
202             cit != buttonlist_.end(); ++cit) {
203                 if ((*cit)->obj_) {
204                         fl_redraw_object((*cit)->obj_);
205                 }
206         }
207
208         lyxerr[Debug::GUI] << "Menubar set." << endl;
209
210
211 void Menubar::Pimpl::openByName(string const & name)
212 {
213         for(ButtonList::const_iterator cit = buttonlist_.begin();
214             cit != buttonlist_.end(); ++cit) {
215                 if ((*cit)->item_->submenu() == name) {
216                         MenuCallback((*cit)->obj_, 1);
217                         return;
218                 }
219         }
220         lyxerr << "Menubar::Pimpl::openByName: menu "
221                << name << " not found" << endl;
222 }
223
224
225 void Menubar::Pimpl::add_lastfiles(int menu, string const & extra_label) 
226 {
227         int ii = 1;
228         for (LastFiles::const_iterator cit = lastfiles->begin();
229              cit != lastfiles->end() && ii < 10; ++cit, ++ii) {
230
231                 int action =
232                         lyxaction.getPseudoAction(LFUN_FILE_OPEN, (*cit));
233                 string label = tostr(ii) + ". "
234                         + MakeDisplayPath((*cit),30)
235                         + "%x" + tostr(action) + "%h";
236                 if ((cit + 1) == lastfiles->end())
237                         label += extra_label;
238                 string shortcut = tostr(ii) + "#" + tostr(ii); 
239                 lyxerr[Debug::GUI] << "shortcut is " << shortcut <<
240                         endl;
241
242                 fl_addtopup(menu, label.c_str(), shortcut.c_str());
243         }
244
245 }
246
247 void Menubar::Pimpl::add_documents(int menu, string const & extra_label)
248 {
249         vector<string> names = bufferlist.getFileNames();
250
251         if (names.empty()) {
252                 fl_addtopup(menu,_("No Documents Open!%i"));
253                 return;
254         }
255
256         for (vector<string>::const_iterator cit = names.begin();
257              cit != names.end() ; ++cit) {
258                 int action =
259                         lyxaction.getPseudoAction(LFUN_SWITCHBUFFER, *cit);
260                 string label = MakeDisplayPath(*cit, 30)
261                         + "%x" + tostr(action);
262                 if ((cit + 1) == names.end())
263                         label += extra_label;
264                                 
265                 fl_addtopup(menu, label.c_str());
266         }
267
268 }
269
270
271 string limit_string_length(string const & str)
272 {
273         string::size_type const max_item_length = 45;
274
275         if (str.size() > max_item_length)
276                 return str.substr(0, max_item_length-3) + "...";
277         else
278                 return str;
279 }
280
281 size_type const max_number_of_menus = 32;
282 size_type const max_number_of_items = 25;
283
284 void add_toc2(int menu, string const & extra_label,
285               vector<int> & smn, Window win,
286               vector<Buffer::TocItem> const & toc_list,
287               size_type from, size_type to, int depth)
288 {
289         if (to - from <= max_number_of_items) {
290                 for (size_type i = from; i < to; ++i) {
291                         int action = lyxaction.
292                                 getPseudoAction(LFUN_GOTO_PARAGRAPH,
293                                                 tostr(toc_list[i].par->id()));
294                         string label(4 * max(0, toc_list[i].depth - depth),' ');
295                         label += toc_list[i].str;
296                         label = limit_string_length(label);
297                         label += "%x" + tostr(action);
298                         if (i == to - 1 && depth == 0)
299                                 label += extra_label;
300                         fl_addtopup(menu, label.c_str());
301                 }
302         } else {
303                 size_type pos = from;
304                 size_type count = 0;
305                 while (pos < to) {
306                         ++count;
307                         if (count > max_number_of_items) {
308                                 fl_addtopup(menu, ". . .%d");
309                                 break;
310                         }
311                         size_type new_pos = pos+1;
312                         while (new_pos < to &&
313                                toc_list[new_pos].depth > depth)
314                                 ++new_pos;
315
316                         int action = lyxaction.
317                                 getPseudoAction(LFUN_GOTO_PARAGRAPH,
318                                                 tostr(toc_list[pos].par->id()));
319                         string label(4 * max(0, toc_list[pos].depth - depth), ' ');
320                         label += toc_list[pos].str;
321                         label = limit_string_length(label);
322                         if (new_pos == to && depth == 0)
323                                 label += extra_label;
324
325                         if (new_pos == pos + 1) {
326                                 label += "%x" + tostr(action);
327                                 fl_addtopup(menu, label.c_str());
328                         } else if (smn.size() < max_number_of_menus) {
329                                 int menu2 = fl_newpup(win);
330                                 smn.push_back(menu2);
331                                 add_toc2(menu2, extra_label, smn, win,
332                                          toc_list, pos, new_pos, depth+1);
333                                 label += "%m";
334                                 fl_addtopup(menu, label.c_str(), menu2);
335                         } else {
336                                 label += "%d";
337                                 fl_addtopup(menu, label.c_str());
338                         }
339                         pos = new_pos;
340                 }
341         }
342 }
343
344 void Menubar::Pimpl::add_toc(int menu, string const & extra_label,
345                              vector<int> & smn, Window win)
346 {
347         //xgettext:no-c-format
348         static char const * MenuNames[3] = { N_("List of Figures%m"),
349         //xgettext:no-c-format
350                                              N_("List of Tables%m"),
351         //xgettext:no-c-format
352                                              N_("List of Algorithms%m") };
353
354         vector<vector<Buffer::TocItem> > toc_list =
355                 owner_->buffer()->getTocList();
356
357         // Handle LOF/LOT/LOA
358         int max_nonempty = 0;
359         for (int i = 1; i <= 3; ++i)
360                 if (!toc_list[i].empty())
361                         max_nonempty = i;
362
363         for (int j = 1; j <= 3; ++j)
364                 if (!toc_list[j].empty()) {
365                         int menu2 = fl_newpup(win);
366                         smn.push_back(menu2);
367                         for (size_type i = 0; i < toc_list[j].size(); ++i) {
368                                 if (i > max_number_of_items) {
369                                         fl_addtopup(menu2, ". . .%d");
370                                         break;
371                                 }
372                                 int action = lyxaction.
373                                         getPseudoAction(LFUN_GOTO_PARAGRAPH,
374                                                         tostr(toc_list[j][i].par->id()));
375                                 string label =
376                                         limit_string_length(toc_list[j][i].str);
377                                 label += "%x" + tostr(action);
378                                 fl_addtopup(menu2, label.c_str());
379                         }
380                         if (j == max_nonempty) {
381                                 string label = _(MenuNames[j-1]);
382                                 label += "%l";
383                                 fl_addtopup(menu, label.c_str(), menu2);
384                         } else
385                                 fl_addtopup(menu, _(MenuNames[j-1]), menu2);
386                 }
387
388         // Handle normal TOC
389         if (max_nonempty == 0 && toc_list[0].empty()) {
390                 fl_addtopup(menu,_("No Table of Contents%i"));
391                 return;
392         }
393
394         add_toc2(menu, extra_label, smn, win,
395                  toc_list[0], 0, toc_list[0].size(), 0);
396
397 }
398
399 void add_references2(int menu, vector<int> & smn, Window win,
400                      vector<string> const & label_list, string const & type)
401 {
402         size_type const max_number_of_items = 25;
403         size_type const max_number_of_items2 = 20;
404         string::size_type const max_item_length = 40;
405         string::size_type const max_item_length2 = 20;
406
407         if (label_list.size() <= max_number_of_items)
408                 for (size_type i = 0; i < label_list.size(); ++i) {
409                         int action = (type == "goto")
410                                 ? lyxaction.getPseudoAction(LFUN_REF_GOTO, 
411                                                             label_list[i])
412                                 : lyxaction.getPseudoAction(LFUN_REF_INSERT,
413                                                             type + "|++||++|"
414                                                             + label_list[i]);
415                         string label = label_list[i];
416                         if (label.size() > max_item_length)
417                                 label = label.substr(0, max_item_length-1) + "$";
418                         label += "%x" + tostr(action);
419                         fl_addtopup(menu, label.c_str());
420                 }
421         else {
422                 size_type count = 0;
423                 for (size_type i = 0; i < label_list.size();
424                      i += max_number_of_items2) {
425                         ++count;
426                         if (count > max_number_of_items) {
427                                 fl_addtopup(menu, ". . .%d");
428                                 break;
429                         }
430                         size_type j = min(label_list.size(),
431                                           i+max_number_of_items2);
432
433                         string label;
434                         label += (label_list[i].size() > max_item_length2)
435                                 ? label_list[i].substr(0, max_item_length2-1) + "$"
436                                 : label_list[i];
437                         label += "..";
438                         label += (label_list[j-1].size() > max_item_length2)
439                                 ? label_list[j-1].substr(0, max_item_length2-1) + "$"
440                                 : label += label_list[j-1];
441
442                         if (smn.size() < max_number_of_menus) {
443                                 int menu2 = fl_newpup(win);
444                                 smn.push_back(menu2);
445                                 for (size_type k = i;  k < j; ++k) {
446                                         int action = (type == "goto")
447                                                 ? lyxaction.getPseudoAction(LFUN_REF_GOTO, 
448                                                                             label_list[k])
449                                                 : lyxaction.getPseudoAction(LFUN_REF_INSERT,
450                                                                             type + "|++||++|"
451                                                                             + label_list[k]);
452                                         string label2 = label_list[k];
453                                         if (label2.size() > max_item_length)
454                                                 label2 = label2.substr(0, max_item_length-1) + "$";
455                                         label2 += "%x" + tostr(action);
456                                         fl_addtopup(menu2, label2.c_str());
457                                 }
458                                 label += "%m";
459                                 fl_addtopup(menu, label.c_str(), menu2);
460                         } else {
461                                 label += "%d";
462                                 fl_addtopup(menu, label.c_str());
463                         }
464                 }
465         }
466 }
467
468
469 void Menubar::Pimpl::add_references(int menu, string const & extra_label,
470                                     vector<int> & smn, Window win)
471 {
472         //xgettext:no-c-format
473         static char const * MenuNames[6] = { N_("Insert Reference%m"),
474         //xgettext:no-c-format
475                                              N_("Insert Page Number%m"),
476         //xgettext:no-c-format
477                                              N_("Insert vref%m"),
478         //xgettext:no-c-format
479                                              N_("Insert vpageref%m"),
480         //xgettext:no-c-format
481                                              N_("Insert Pretty Ref%m"),
482         //xgettext:no-c-format
483                                              N_("Goto Reference%m") };
484
485         int const EMPTY = 1;
486         int const SGML = 2;
487         int const READONLY = 4;
488
489         static int MenuFlags[6] = {
490                 EMPTY | READONLY,
491                 EMPTY | READONLY,
492                 EMPTY | READONLY | SGML,
493                 EMPTY | READONLY | SGML,
494                 EMPTY | READONLY | SGML,
495                 EMPTY };
496
497         static string const MenuTypes[6] = {
498                 "ref", "pageref", "vref", "vpageref", "prettyref", "goto" };
499
500         vector<string> label_list = owner_->buffer()->getLabelList();
501
502         int flag = 0;
503         if (label_list.empty())
504                 flag += EMPTY;
505         if (owner_->buffer()->isSGML())
506                 flag += SGML;
507         if (owner_->buffer()->isReadonly())
508                 flag += READONLY;
509
510         int max_nonempty = -1;
511         for (int i = 0; i < 6; ++i)
512                 if ((MenuFlags[i] & flag) == 0)
513                         max_nonempty = i;
514
515         for (int i = 0; i < 6; ++i) {
516                 if ((MenuFlags[i] & flag) == 0) {
517                         string label = _(MenuNames[i]);
518                         if (i == max_nonempty)
519                                 label += extra_label;
520                         if (smn.size() < max_number_of_menus) {
521                                 int menu2 = fl_newpup(win);
522                                 smn.push_back(menu2);
523                                 add_references2(menu2, smn, win, label_list,
524                                                 MenuTypes[i]);
525                                 fl_addtopup(menu, label.c_str(), menu2);
526                         } else {
527                                 label += "%d";
528                                 fl_addtopup(menu, label.c_str());       
529                         }
530                 }
531         }
532 }
533
534
535 void Menubar::Pimpl::add_formats(int menu, string const & extra_label,
536                                  kb_action action, bool viewable)
537 {
538         vector<pair<string,string> > names = 
539                 viewable
540                 ? Exporter::GetViewableFormats(owner_->buffer())
541                 : Exporter::GetExportableFormats(owner_->buffer());
542
543         for (vector<pair<string,string> >::const_iterator cit = names.begin();
544              cit != names.end() ; ++cit) {
545                 int action2 =
546                         lyxaction.getPseudoAction(action, (*cit).first);
547                 string label = (*cit).second
548                         + "%x" + tostr(action2);
549                 if ((cit + 1) == names.end())
550                         label += extra_label;
551                                 
552                 fl_addtopup(menu, label.c_str());
553         }
554 }
555
556
557 int Menubar::Pimpl::create_submenu(Window win, LyXView * view, 
558                                    string const & menu_name, 
559                                    vector<int> & smn) 
560 {
561         if (!menubackend_->hasMenu(menu_name)){ 
562                 lyxerr << "ERROR:create_submenu: Unknown menu `" 
563                        << menu_name << "'" << endl;
564                 return -1;
565         }
566         Menu md = menubackend_->getMenu(menu_name);
567
568         int menu = fl_newpup(win);
569         fl_setpup_softedge(menu, true);
570         fl_setpup_bw(menu, -1);
571         lyxerr[Debug::GUI] << "Adding menu " << menu 
572                            << " in deletion list" << endl;
573         smn.push_back(menu);
574
575         // Compute the size of the largest label (because xforms is
576         // not able to support shortcuts correctly...)
577         int max_width = 0;
578         string widest_label;
579         Menu::const_iterator end = md.end();
580         for (Menu::const_iterator i = md.begin(); i != end; ++i) {
581                 MenuItem const & item = (*i);
582                 if (item.kind() == MenuItem::Command) {
583                         string label = item.label() + '\t';
584                         int width = string_width(label);
585                         if (width > max_width) {
586                                 max_width = width;
587                                 widest_label = label;
588                         }
589                 }
590         }
591         lyxerr[Debug::GUI] << "max_width=" << max_width 
592                            << ", widest_label=`" << widest_label 
593                            << "'" << endl;
594
595         // Compute where to put separators
596         vector<string> extra_labels(md.size());
597         vector<string>::iterator it = extra_labels.begin();
598         vector<string>::iterator last = it;
599         for (Menu::const_iterator i = md.begin(); i != end; ++i, ++it)
600                 if (i->kind() == MenuItem::Separator)
601                         *last = "%l";
602                 else if (!i->optional() ||
603                          !(view->getLyXFunc()->getStatus(i->action()) & LyXFunc::Disabled))
604                         last = it;
605
606         it = extra_labels.begin();
607         for (Menu::const_iterator i = md.begin(); i != end; ++i, ++it) {
608                 MenuItem const & item = (*i);
609                 string & extra_label = *it;
610
611                 switch(item.kind()) {
612                 case MenuItem::Command: {
613                         LyXFunc::func_status flag = 
614                                 view->getLyXFunc()->getStatus(item.action()); 
615
616                         // handle optional entries.
617                         if (item.optional() && (flag & LyXFunc::Disabled)) {
618                                 lyxerr[Debug::GUI] 
619                                         << "Skipping optional item " 
620                                         << item.label() << endl; 
621                                 break;
622                         }
623
624                         // Get the keys bound to this action, but keep only the
625                         // first one later
626                         string accel = toplevel_keymap->findbinding(item.action());
627                         // Build the menu label from all the info
628                         string label = item.label();
629
630                         if (!accel.empty()) {
631                                 // Try to be clever and add  just enough
632                                 // tabs to align shortcuts.
633                                 do 
634                                         label += '\t';
635                                 while (string_width(label) < max_width);
636                                 label += accel.substr(1,accel.find(']') - 1);
637                         }
638                         label += "%x" + tostr(item.action()) + extra_label;
639                         
640                         // Modify the entry using the function status
641                         string pupmode;
642                         if (flag & (LyXFunc::Disabled | LyXFunc::Unknown))
643                                 pupmode += "%i";
644                         if (flag & LyXFunc::ToggleOn)
645                                 pupmode += "%B";
646                         if (flag & LyXFunc::ToggleOff)
647                                 pupmode += "%b";
648                         label += pupmode;
649
650                         // Finally the menu shortcut
651                         string shortcut = item.shortcut();
652
653                         if (!shortcut.empty()) {
654                                 shortcut += lowercase(shortcut[0]);
655                                 label += "%h";
656                                 fl_addtopup(menu, label.c_str(), 
657                                             shortcut.c_str());
658                         } else
659                                 fl_addtopup(menu, label.c_str());
660                         
661                         lyxerr[Debug::GUI] << "Command: \""  
662                                            << lyxaction.getActionName(item.action())
663                                            << "\", Binding " << accel 
664                                            << ", shortcut " << shortcut 
665                                            << endl;
666
667
668                         break;
669                 }
670
671                 case MenuItem::Submenu: {
672                         int submenu = create_submenu(win, view, 
673                                                      item.submenu(), smn);
674                         if (submenu == -1)
675                                 return -1;
676                         string label = item.label();
677                         label += extra_label + "%m";
678                         string shortcut = item.shortcut();
679                         if (!shortcut.empty()) {
680                                 shortcut += lowercase(shortcut[0]);
681                                 fl_addtopup(menu, (label + "%h").c_str(),
682                                             submenu, shortcut.c_str());
683                         }
684                         else {
685                                 fl_addtopup(menu, label.c_str(), submenu);
686                         }
687                         break;
688                 }
689
690                 case MenuItem::Separator:
691                         // already done, and if it was the first one,
692                         // we just ignore it.
693                         break;
694
695                 case MenuItem::Documents: 
696                         add_documents(menu, extra_label);
697                         break;
698
699                 case MenuItem::Lastfiles: 
700                         add_lastfiles(menu, extra_label);
701                         break;
702
703                 case MenuItem::Toc:
704                         add_toc(menu, extra_label, smn, win);
705                         break;
706
707                 case MenuItem::References:
708                         add_references(menu, extra_label, smn, win);
709                         break;
710
711                 case MenuItem::ViewFormats:
712                         add_formats(menu, extra_label, LFUN_PREVIEW, true);
713                         break;
714
715                 case MenuItem::UpdateFormats:
716                         add_formats(menu, extra_label, LFUN_UPDATE, true);
717                         break;  
718
719                 case MenuItem::ExportFormats:
720                         add_formats(menu, extra_label, LFUN_EXPORT, false);
721                         break;
722
723                 }
724         }
725         return menu;
726 }
727
728 extern "C"
729 void C_Menubar_Pimpl_MenuCallback(FL_OBJECT * ob, long button)
730 {
731         Menubar::Pimpl::MenuCallback(ob, button);
732 }
733
734
735 void Menubar::Pimpl::MenuCallback(FL_OBJECT * ob, long button)
736 {
737         ItemInfo * iteminfo = static_cast<ItemInfo *>(ob->u_vdata);
738 //      lyxerr << "MenuCallback: ItemInfo address=" << iteminfo
739 //             << "Val=(pimpl_=" << iteminfo->pimpl_
740 //             << ", item_=" << iteminfo->item_
741 //             << ", obj_=" << iteminfo->obj_ << ")" <<endl;
742
743         LyXView * view = iteminfo->pimpl_->owner_;
744         MenuItem const * item = iteminfo->item_;
745
746         if (button == 1) {
747                 // set the pseudo menu-button
748                 fl_set_object_boxtype(ob, FL_DOWN_BOX);
749                 fl_set_button(ob, 0);
750                 fl_redraw_object(ob);
751         }
752
753         // Paranoia check
754         Assert(item->kind() == MenuItem::Submenu);
755         
756         // set tabstop length
757         fl_set_tabstop(menu_tabstop);
758         vector<int> submenus;
759         int menu = iteminfo->pimpl_->
760                 create_submenu(FL_ObjWin(ob), view, 
761                                item->submenu(), submenus);
762         if (menu != -1) {
763                 // place popup
764                 fl_setpup_position(view->getForm()->x + ob->x,
765                                    view->getForm()->y + ob->y + ob->h + 10);   
766                 int choice = fl_dopup(menu);
767                 
768                 if (button == 1) {
769                                 // set the pseudo menu-button back
770                         fl_set_object_boxtype(ob, FL_FLAT_BOX);
771                         fl_redraw_object(ob);
772                 }
773                 
774                 if (choice >= 1) {
775                         view->getLyXFunc()->Dispatch(choice);
776                 }
777         }
778         else 
779                 lyxerr << "Error in MenuCallback" << endl;
780         
781         std::for_each(submenus.begin(), submenus.end(), fl_freepup);
782         // restore tabstop length
783         fl_set_tabstop(default_tabstop);
784
785 }