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