]> git.lyx.org Git - lyx.git/blob - src/frontends/gtk/GMenubar.C
some tabular fixes for the problems reported by Helge
[lyx.git] / src / frontends / gtk / GMenubar.C
1 /**
2  * \file GMenubar.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Huang Ying
7  * \author John Spray
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 // Too hard to make concept checks work with this file
15 #ifdef _GLIBCXX_CONCEPT_CHECKS
16 #undef _GLIBCXX_CONCEPT_CHECKS
17 #endif
18 #ifdef _GLIBCPP_CONCEPT_CHECKS
19 #undef _GLIBCPP_CONCEPT_CHECKS
20 #endif
21
22 #include "GMenubar.h"
23 #include "GView.h"
24 #include "ghelpers.h"
25
26 #include "ToolbarBackend.h" // for getIcon
27
28 #include "debug.h"
29 #include "lyxfunc.h"
30
31 using std::string;
32
33 namespace lyx {
34 namespace frontend {
35
36 namespace
37 {
38
39 class LyxMenu : public Gtk::Menu {
40 public:
41         LyxMenu() { menu_.reset(new ::Menu); }
42
43         ::Menu& getBackMenu() { return *menu_.get(); }
44
45         void clearBackMenu() { menu_.reset(new ::Menu); }
46 private:
47         std::auto_ptr< ::Menu > menu_;
48 };
49
50
51 Glib::ustring labelTrans(string const & label, string const & shortcut)
52 {
53         string labelN = label;
54         string::size_type i = label.find(shortcut);
55         if (i == string::npos)
56                 return Glib::locale_to_utf8(label);
57         labelN.insert(i, "_");
58         return Glib::locale_to_utf8(labelN);
59 }
60
61
62 void ClearMenu(Gtk::MenuShell * menu)
63 {
64         Gtk::Menu_Helpers::MenuList::iterator m = menu->items().begin();
65         Gtk::Menu_Helpers::MenuList::iterator end = menu->items().end();
66         Gtk::Menu * subMenu;
67         for (; m != end; ++m) {
68                 if ((subMenu = m->get_submenu()) != 0) {
69                         ClearMenu(subMenu);
70                         delete subMenu;
71                 }
72         }
73         menu->items().clear();
74 }
75
76
77 }
78
79
80 GMenubar::GMenubar(LyXView * lyxView, MenuBackend const & /*menuBackend*/) :
81         view_(lyxView)
82 {
83         GView * gview = static_cast<GView*>(lyxView);
84         Menu const & menu = menubackend.getMenubar();
85         Menu::const_iterator i = menu.begin();
86         Menu::const_iterator end = menu.end();
87         for (; i != end; ++i) {
88                 if (i->kind() != MenuItem::Submenu) {
89                         lyxerr << "ERROR: GMenubar::createMenubar:"
90                                 " only submenus can appear in a menubar"
91                                << std::endl;
92                         continue;
93                 }
94                 Gtk::Menu * gmenu = new LyxMenu;
95                 menubar_.items().push_back(
96                         Gtk::Menu_Helpers::MenuElem(
97                                 labelTrans(i->label(), i->shortcut()),
98                                 *gmenu));
99                 menubar_.items().back().signal_activate().connect(
100                         sigc::bind(sigc::mem_fun(*this, &GMenubar::onSubMenuActivate), &(*i),
101                                    &menubar_.items().back()));
102                 mainMenuNames_.push_back(i->submenuname());
103         }
104         menubar_.show();
105         gview->getBox(GView::Top).children().push_back(
106                 Gtk::Box_Helpers::Element(menubar_, Gtk::PACK_SHRINK));
107 }
108
109
110 GMenubar::~GMenubar()
111 {
112         ClearMenu(&menubar_);
113 }
114
115
116 void GMenubar::update()
117 {
118 }
119
120
121 void GMenubar::openByName(string const & name)
122 {
123         Glib::ustring uname = Glib::locale_to_utf8(name);
124         std::vector<Glib::ustring>::iterator it =
125                 std::find(mainMenuNames_.begin(), mainMenuNames_.end(),
126                           uname);
127         if (it != mainMenuNames_.end()) {
128                 Gtk::MenuItem& mitem = menubar_.items()[it - mainMenuNames_.begin()];
129                 mitem.select();
130                 mitem.activate();
131                 return;
132         }
133         lyxerr << "GMenubar::openByName: menu "
134                << name << " not found" << std::endl;
135 }
136
137
138 void GMenubar::onSubMenuActivate(MenuItem const * item,
139                                  Gtk::MenuItem * gitem)
140 {
141         Gtk::Menu * gmenu = gitem->get_submenu();
142         ClearMenu(gmenu);
143         LyxMenu * lyxmenu = static_cast<LyxMenu*>(gmenu);
144         lyxmenu->clearBackMenu();
145         Menu * fmenu = item->submenuname().empty() ?
146                 item->submenu() :
147                 &menubackend.getMenu(item->submenuname());
148
149         // Choose size for icons on command items
150         int iconwidth = 16;
151         int iconheight = 16;
152         Gtk::IconSize::lookup(Gtk::ICON_SIZE_MENU, iconwidth, iconheight);
153
154         menubackend.expand(*fmenu, lyxmenu->getBackMenu(), view_);
155         Menu::const_iterator i = lyxmenu->getBackMenu().begin();
156         Menu::const_iterator end = lyxmenu->getBackMenu().end();
157         Gtk::Menu * gmenu_new;
158         for (; i != end; ++i) {
159                 switch (i->kind()) {
160                 case MenuItem::Submenu:
161                         gmenu_new = new LyxMenu;
162                         gmenu->items().push_back(
163                                 Gtk::Menu_Helpers::MenuElem(
164                                         labelTrans(i->label(), i->shortcut()),
165                                         *gmenu_new));
166                         gmenu->items().back().signal_activate().connect(
167                                 sigc::bind(sigc::mem_fun(*this, &GMenubar::onSubMenuActivate),
168                                            &(*i),
169                                            &gmenu->items().back()));
170                         if (!i->status().enabled())
171                                 gmenu->items().back().set_sensitive(false);
172                         break;
173                 case MenuItem::Command:
174                 {
175                         FuncStatus const flag = i->status();
176                         bool on = flag.onoff(true);
177                         bool off = flag.onoff(false);
178
179                         if (on || off) {
180                                 gmenu->items().push_back(
181                                         Gtk::Menu_Helpers::CheckMenuElem(
182                                                 labelTrans(i->label(),
183                                                            i->shortcut())));
184                                 Gtk::CheckMenuItem& citem =
185                                         static_cast<Gtk::CheckMenuItem&>(
186                                                 gmenu->items().back());
187                                 citem.set_active(on);
188                         } else {
189                                 // Choose an icon from the funcrequest
190                                 Gtk::BuiltinStockID stockID = getGTKStockIcon(i->func());
191                                 Gtk::Image * image = NULL;
192                                 // Prefer stock graphics
193                                 if (stockID != Gtk::Stock::MISSING_IMAGE) {
194                                         image = Gtk::manage(new Gtk::Image(stockID, Gtk::ICON_SIZE_MENU));
195                                 } else {
196                                         Glib::ustring xpmName =
197                                                 Glib::locale_to_utf8(toolbarbackend.getIcon(i->func()));
198                                         if (xpmName.find("unknown.xpm") == Glib::ustring::npos) {
199                                                 // Load icon and shrink it for menu size
200                                                 Glib::RefPtr<Gdk::Pixbuf> bigicon =
201                                                         Gdk::Pixbuf::create_from_file(xpmName);
202                                                 Glib::RefPtr<Gdk::Pixbuf> smallicon =
203                                                         bigicon->scale_simple(iconwidth,iconheight,Gdk::INTERP_TILES);
204                                                 image = Gtk::manage(new Gtk::Image(smallicon));
205                                         }
206                                 }
207
208                                 Gtk::ImageMenuItem * item = Gtk::manage(new Gtk::ImageMenuItem);
209                                 if (image)
210                                         item->set_image(*image);
211
212                                 // This hbox is necessary because add_accel_label is protected,
213                                 // and even if you subclass Gtk::MenuItem then add_accel_label
214                                 // doesn't do what you'd expect.
215                                 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox);
216                                 Gtk::Label * label1 = Gtk::manage(new Gtk::Label(
217                                         labelTrans(i->label(), i->shortcut()), true));
218                                 Gtk::Label * label2 = Gtk::manage(new Gtk::Label(
219                                         "   " + i->binding(), false));
220                                 hbox->pack_start(*label1, false, false, 0);
221                                 hbox->pack_end(*label2, false, false, 0);
222                                 item->add(*hbox);
223
224                                 gmenu->append(*item);
225                                 item->show_all();
226                         }
227                         Gtk::MenuItem & item = gmenu->items().back();
228                         item.signal_activate().connect(
229                                 sigc::bind(sigc::mem_fun(*this, &GMenubar::onCommandActivate),
230                                            &(*i), &item));
231                         if (!flag.enabled())
232                                 item.set_sensitive(false);
233                         break;
234                 }
235                 case MenuItem::Separator:
236                         gmenu->items().push_back(
237                                 Gtk::Menu_Helpers::SeparatorElem());
238                         break;
239                 default:
240                         lyxerr << "GMenubar::create_submenu: "
241                                 "this should not happen" << std::endl;
242                         break;
243                 }
244         }
245 }
246
247
248 void GMenubar::onCommandActivate(MenuItem const * item,
249                                        Gtk::MenuItem * /*gitem*/)
250 {
251         view_->getLyXFunc().dispatch(item->func());
252 }
253
254 } // namespace frontend
255 } // namespace lyx