]> git.lyx.org Git - lyx.git/blob - src/frontends/gtk/GMenubar.C
enable Font cache only for MacOSX and inline width() for other platform.
[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 "support/lstrings.h"
30 #include "support/docstring.h"
31 #include "lyxfunc.h"
32
33 using lyx::char_type;
34 using lyx::docstring;
35
36 using std::string;
37
38 namespace lyx {
39
40 using support::subst;
41
42 namespace frontend {
43
44 namespace
45 {
46
47 class LyxMenu : public Gtk::Menu {
48 public:
49         LyxMenu() { menu_.reset(new ::Menu); }
50
51         ::Menu& getBackMenu() { return *menu_.get(); }
52
53         void clearBackMenu() { menu_.reset(new ::Menu); }
54 private:
55         std::auto_ptr< ::Menu > menu_;
56 };
57
58
59 Glib::ustring labelTrans(docstring const & label_src,
60                          docstring const & shortcut)
61 {
62         docstring label = subst(label_src,
63                                 lyx::from_ascii("_"),
64                                 lyx::from_ascii("__"));
65         docstring::size_type i = label.find(shortcut);
66         if (i == docstring::npos)
67                 return lyx::to_utf8(label);
68         label.insert(i, lyx::from_ascii("_"));
69         return lyx::to_utf8(label);
70 }
71
72
73 void ClearMenu(Gtk::MenuShell * menu)
74 {
75         Gtk::Menu_Helpers::MenuList::iterator m = menu->items().begin();
76         Gtk::Menu_Helpers::MenuList::iterator end = menu->items().end();
77         Gtk::Menu * subMenu;
78         for (; m != end; ++m) {
79                 if ((subMenu = m->get_submenu()) != 0) {
80                         ClearMenu(subMenu);
81                         delete subMenu;
82                 }
83         }
84         menu->items().clear();
85 }
86
87
88 }
89
90
91 GMenubar::GMenubar(LyXView * lyxView, MenuBackend const & /*menuBackend*/) :
92         view_(lyxView)
93 {
94         GView * gview = static_cast<GView*>(lyxView);
95         Menu const & menu = menubackend.getMenubar();
96         Menu::const_iterator i = menu.begin();
97         Menu::const_iterator end = menu.end();
98         for (; i != end; ++i) {
99                 if (i->kind() != MenuItem::Submenu) {
100                         lyxerr << "ERROR: GMenubar::createMenubar:"
101                                 " only submenus can appear in a menubar"
102                                << std::endl;
103                         continue;
104                 }
105                 Gtk::Menu * gmenu = new LyxMenu;
106                 menubar_.items().push_back(
107                         Gtk::Menu_Helpers::MenuElem(
108                                 labelTrans(i->label(), i->shortcut()),
109                                 *gmenu));
110                 menubar_.items().back().signal_activate().connect(
111                         sigc::bind(sigc::mem_fun(*this, &GMenubar::onSubMenuActivate), &(*i),
112                                    &menubar_.items().back()));
113                 mainMenuNames_.push_back(lyx::to_utf8(i->submenuname()));
114         }
115         menubar_.show();
116         gview->getBox(GView::Top).children().push_back(
117                 Gtk::Box_Helpers::Element(menubar_, Gtk::PACK_SHRINK));
118 }
119
120
121 GMenubar::~GMenubar()
122 {
123         ClearMenu(&menubar_);
124 }
125
126
127 void GMenubar::update()
128 {
129 }
130
131
132 void GMenubar::openByName(docstring const & name)
133 {
134         Glib::ustring uname = lyx::to_utf8(name);
135         std::vector<Glib::ustring>::iterator it =
136                 std::find(mainMenuNames_.begin(), mainMenuNames_.end(),
137                           uname);
138         if (it != mainMenuNames_.end()) {
139                 Gtk::MenuItem& mitem = menubar_.items()[it - mainMenuNames_.begin()];
140                 mitem.select();
141                 mitem.activate();
142                 return;
143         }
144         lyxerr << "GMenubar::openByName: menu "
145                << lyx::to_utf8(name) << " not found" << std::endl;
146 }
147
148
149 void GMenubar::onSubMenuActivate(MenuItem const * item,
150                                  Gtk::MenuItem * gitem)
151 {
152         Gtk::Menu * gmenu = gitem->get_submenu();
153         ClearMenu(gmenu);
154         LyxMenu * lyxmenu = static_cast<LyxMenu*>(gmenu);
155         lyxmenu->clearBackMenu();
156
157         Menu * fmenu;
158         Menu::const_iterator i;
159         Menu::const_iterator end;
160         if(!item->submenuname().empty()) {
161                 fmenu = &menubackend.getMenu(item->submenuname());
162                 menubackend.expand(*fmenu, lyxmenu->getBackMenu(), view_->buffer());
163                 i = lyxmenu->getBackMenu().begin();
164                 end = lyxmenu->getBackMenu().end();
165         } else {
166                 fmenu = item->submenu();
167                 i = fmenu->begin();
168                 end = fmenu->end();
169         }
170
171         // Choose size for icons on command items
172         int iconwidth = 16;
173         int iconheight = 16;
174         Gtk::IconSize::lookup(Gtk::ICON_SIZE_MENU, iconwidth, iconheight);
175
176         Gtk::Menu * gmenu_new;
177         for (; i != end; ++i) {
178                 switch (i->kind()) {
179                 case MenuItem::Submenu:
180                         gmenu_new = new LyxMenu;
181                         gmenu->items().push_back(
182                                 Gtk::Menu_Helpers::MenuElem(
183                                         labelTrans(i->label(), i->shortcut()),
184                                         *gmenu_new));
185                         gmenu->items().back().signal_activate().connect(
186                                 sigc::bind(sigc::mem_fun(*this, &GMenubar::onSubMenuActivate),
187                                            &(*i),
188                                            &gmenu->items().back()));
189                         if (!i->status().enabled())
190                                 gmenu->items().back().set_sensitive(false);
191                         break;
192                 case MenuItem::Command:
193                 {
194                         FuncStatus const flag = i->status();
195                         bool on = flag.onoff(true);
196                         bool off = flag.onoff(false);
197
198                         if (on || off) {
199                                 gmenu->items().push_back(
200                                         Gtk::Menu_Helpers::CheckMenuElem(
201                                                 labelTrans(i->label(),
202                                                            i->shortcut())));
203                                 Gtk::CheckMenuItem& checkitem =
204                                         static_cast<Gtk::CheckMenuItem&>(
205                                                 gmenu->items().back());
206                                 checkitem.set_active(on);
207                         } else {
208                                 // Choose an icon from the funcrequest
209                                 Gtk::Image * image = getGTKIcon(i->func(), Gtk::ICON_SIZE_MENU);
210                                 if (!image) {
211                                         // ENCODING, FIXME: does Pixbuf::create_from_file really
212                                         // want UTF-8, or does it want filename encoding?  Is
213                                         // the backend string really in locale encoding?
214                                         // This shouldn't break as long as filenames are ASCII
215                                         Glib::ustring xpmName =
216                                                 Glib::locale_to_utf8(toolbarbackend.getIcon(i->func()));
217                                         if (xpmName.find("unknown.xpm") == Glib::ustring::npos) {
218                                                 // Load icon and shrink it for menu size
219                                                 Glib::RefPtr<Gdk::Pixbuf> bigicon =
220                                                         Gdk::Pixbuf::create_from_file(xpmName);
221                                                 Glib::RefPtr<Gdk::Pixbuf> smallicon =
222                                                         bigicon->scale_simple(iconwidth,iconheight,Gdk::INTERP_TILES);
223                                                 image = Gtk::manage(new Gtk::Image(smallicon));
224                                         }
225                                 }
226
227                                 Gtk::ImageMenuItem * imgitem = Gtk::manage(new Gtk::ImageMenuItem);
228                                 if (image)
229                                         imgitem->set_image(*image);
230
231                                 // This hbox is necessary because add_accel_label is protected,
232                                 // and even if you subclass Gtk::MenuItem then add_accel_label
233                                 // doesn't do what you'd expect.
234                                 Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox);
235                                 Gtk::Label * label1 = Gtk::manage(new Gtk::Label(
236                                         labelTrans(i->label(), i->shortcut()), true));
237                                 Gtk::Label * label2 =
238                                         Gtk::manage(new Gtk::Label(
239                                                                    "   " + lyx::to_utf8(i->binding()), false));
240                                 hbox->pack_start(*label1, false, false, 0);
241                                 hbox->pack_end(*label2, false, false, 0);
242                                 imgitem->add(*hbox);
243
244                                 gmenu->append(*imgitem);
245                                 imgitem->show_all();
246                         }
247                         Gtk::MenuItem & newitem = gmenu->items().back();
248                         newitem.signal_activate().connect(
249                                 sigc::bind(sigc::mem_fun(*this, &GMenubar::onCommandActivate),
250                                            &(*i), &newitem));
251                         if (!flag.enabled())
252                                 newitem.set_sensitive(false);
253                         break;
254                 }
255                 case MenuItem::Separator:
256                         gmenu->items().push_back(
257                                 Gtk::Menu_Helpers::SeparatorElem());
258                         break;
259                 default:
260                         lyxerr << "GMenubar::create_submenu: "
261                                 "this should not happen" << std::endl;
262                         break;
263                 }
264         }
265 }
266
267
268 void GMenubar::onCommandActivate(MenuItem const * item,
269                                        Gtk::MenuItem * /*gitem*/)
270 {
271         view_->getLyXFunc().dispatch(item->func());
272 }
273
274 } // namespace frontend
275 } // namespace lyx