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