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