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