]> git.lyx.org Git - lyx.git/blob - src/frontends/gtk/GToolbar.C
Menu icons, gtk stock icons in toolbar
[lyx.git] / src / frontends / gtk / GToolbar.C
1 /**
2  * \file GToolbar.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 "GToolbar.h"
15 #include "GView.h"
16
17 #include "ghelpers.h"
18
19 #include "buffer.h"
20 #include "bufferparams.h"
21 #include "debug.h"
22 #include "funcrequest.h"
23 #include "FuncStatus.h"
24 #include "lyxfunc.h"
25
26 using std::string;
27
28 namespace lyx {
29 namespace frontend {
30
31 namespace {
32
33 GView::Position getPosition(ToolbarBackend::Flags const & flags)
34 {
35         if (flags & ToolbarBackend::TOP)
36                 return GView::Top;
37         if (flags & ToolbarBackend::BOTTOM)
38                 return GView::Bottom;
39         if (flags & ToolbarBackend::LEFT)
40                 return GView::Left;
41         if (flags & ToolbarBackend::RIGHT)
42                 return GView::Right;
43         return GView::Top;
44 }
45
46
47 LyXTextClass const & getTextClass(LyXView const & lv)
48 {
49         return lv.buffer()->params().getLyXTextClass();
50 }
51
52 char const * gToolData = "tool_data";
53
54 } // namespace anon
55
56
57 GLayoutBox::GLayoutBox(LyXView & owner,
58                        Gtk::Toolbar & toolbar,
59                        FuncRequest const & func)
60         : owner_(owner),
61           internal_(false)
62 {
63         combo_.signal_changed().connect(
64                 sigc::mem_fun(*this,&GLayoutBox::selected));
65
66         model_ = Gtk::ListStore::create(cols_);
67         combo_.set_model(model_);
68         Gtk::CellRendererText * cell = Gtk::manage(new Gtk::CellRendererText);
69         combo_.pack_start(*cell, true);
70         combo_.add_attribute(*cell,"text",0);
71         combo_.set_wrap_width(2);
72         // Initially there's nothing in the liststore, so set the size
73         // to avoid it jumping too much when the user does something that
74         // causes the first update()
75         combo_.set_size_request(130,-1);
76
77
78         combo_.set_data(
79                 gToolData,
80                 reinterpret_cast<void*>(&const_cast<FuncRequest &>(func)));
81
82         combo_.show();
83
84         Gtk::ToolItem * toolitem = Gtk::manage(new Gtk::ToolItem);
85         toolitem->add(combo_);
86         toolbar.append(*toolitem);
87 }
88
89 void GLayoutBox::set(string const & layout)
90 {
91         LyXTextClass const & tc = getTextClass(owner_);
92         string const target = tc[layout]->name();
93
94         internal_ = true;
95         Gtk::TreeModel::iterator it = model_->children().begin();
96         Gtk::TreeModel::iterator end = model_->children().end();
97         for (; it != end; ++it) {
98                 if ((*it)[cols_.name] == target){
99                         combo_.set_active(it);
100                         internal_ = false;
101                         return;
102                 }
103         }
104         internal_ = false;
105
106         lyxerr << "ERROR (GLayoutBox::set): layout not found! name: "
107                << target << std::endl;
108 }
109
110
111 void GLayoutBox::update()
112 {
113         clear();
114
115         LyXTextClass const & tc = getTextClass(owner_);
116
117         LyXTextClass::const_iterator it = tc.begin();
118         LyXTextClass::const_iterator const end = tc.end();
119
120         internal_ = true;
121         for (; it != end; ++it)
122                 if ((*it)->obsoleted_by().empty()) {
123                         Gtk::TreeModel::iterator iter = model_->append();
124                         Gtk::TreeModel::Row row = *iter;
125                         row[cols_.name] = Glib::locale_to_utf8((*it)->name());
126                 }
127         internal_ = false;
128
129         // now that we've loaded something into the combobox, forget
130         // the initial fixed size and let GTK decide.
131         combo_.set_size_request(-1,-1);
132 }
133
134
135 void GLayoutBox::clear()
136 {
137         internal_ = true;
138         model_->clear();
139         internal_ = false;
140 }
141
142
143 void GLayoutBox::open()
144 {
145         combo_.popup();
146 }
147
148
149 void GLayoutBox::setEnabled(bool sensitive)
150 {
151         combo_.set_sensitive(sensitive);
152 }
153
154
155 void GLayoutBox::selected()
156 {
157         if (internal_)
158                 return;
159
160         Glib::ustring layoutGuiName = (*(combo_.get_active()))[cols_.name];
161
162         // we get two signal, one of them is empty and useless
163         if (layoutGuiName.empty())
164                 return;
165
166         layoutSelected(owner_, layoutGuiName);
167 }
168
169 } // namespace frontend
170 } // namespace lyx
171
172
173 Toolbars::ToolbarPtr make_toolbar(ToolbarBackend::Toolbar const & tbb,
174                                   LyXView & owner)
175 {
176         using lyx::frontend::GToolbar;
177         return Toolbars::ToolbarPtr(new GToolbar(tbb, owner));
178 }
179
180 namespace lyx {
181 namespace frontend {
182
183 GToolbar::GToolbar(ToolbarBackend::Toolbar const & tbb, LyXView & owner)
184         : owner_(dynamic_cast<GView &>(owner))
185 {
186         ToolbarBackend::item_iterator it = tbb.items.begin();
187         ToolbarBackend::item_iterator end = tbb.items.end();
188         for (; it != end; ++it)
189                 add(it->first, it->second);
190
191         toolbar_.set_toolbar_style(Gtk::TOOLBAR_ICONS);
192         toolbar_.show_all();
193
194         GView::Position const position = getPosition(tbb.flags);
195
196         if (position == GView::Left || position == GView::Right)
197                 toolbar_.set_orientation(Gtk::ORIENTATION_VERTICAL);
198
199         owner_.getBox(position).children().push_back(
200                 Gtk::Box_Helpers::Element(toolbar_, Gtk::PACK_SHRINK));
201
202         toolbar_.set_tooltips(true);
203 }
204
205 void GToolbar::add(FuncRequest const & func, string const & tooltip)
206 {
207         switch (func.action) {
208         case ToolbarBackend::SEPARATOR: {
209                 Gtk::SeparatorToolItem * space =
210                         Gtk::manage(new Gtk::SeparatorToolItem);
211                 toolbar_.append(*space);
212                 break;
213         }
214
215         case ToolbarBackend::MINIBUFFER:
216                 // Not supported yet.
217                 break;
218
219         case ToolbarBackend::LAYOUTS: {
220                 layout_.reset(new GLayoutBox(owner_, toolbar_, func));
221                 break;
222         }
223
224         default: {
225                 // choose an icon from the funcrequest
226                 Gtk::BuiltinStockID stockID = getGTKStockIcon(func);
227
228                 Glib::ustring tip = Glib::locale_to_utf8(tooltip);
229
230                 Gtk::ToolButton * toolbutton;
231                 if (stockID != Gtk::Stock::MISSING_IMAGE) {
232                         // Prefer stock gtk graphics
233                         Gtk::IconSize size(Gtk::ICON_SIZE_LARGE_TOOLBAR);
234                         Gtk::Image * image = Gtk::manage(new Gtk::Image(stockID, size));
235                         image->show();
236                         toolbutton = Gtk::manage(new Gtk::ToolButton(*image));
237                 } else {
238                         Glib::ustring xpmName =
239                                 Glib::locale_to_utf8(toolbarbackend.getIcon(func));
240                         Gtk::Image * image = Gtk::manage(new Gtk::Image(xpmName));
241                         image->show();
242                         toolbutton = Gtk::manage(new Gtk::ToolButton(*image));
243                 }
244
245                 // This code is putting a function reference into the GObject data field
246                 // named gToolData.  That's how we know how to update the status of the
247                 // toolitem later.
248                 toolbutton->set_data(gToolData,
249                         reinterpret_cast<void*>(&const_cast<FuncRequest &>(func)));
250
251                 toolbutton->set_tooltip(*toolbar_.get_tooltips_object(),tip);
252
253                 toolbutton->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this,
254                         &GToolbar::clicked), FuncRequest(func)));
255                 toolbar_.append(*toolbutton);
256                 break;
257         }
258
259         }
260 }
261
262
263 void GToolbar::clicked(FuncRequest func)
264 {
265         owner_.getLyXFunc().dispatch(func);
266 }
267
268
269 void GToolbar::hide(bool)
270 {
271         toolbar_.hide();
272 }
273
274
275 void GToolbar::show(bool)
276 {
277         toolbar_.show();
278 }
279
280
281 void GToolbar::update()
282 {
283         int const items = toolbar_.get_n_items();
284
285         for (int i = 0; i < items; ++i) {
286                 Gtk::ToolItem * item = toolbar_.get_nth_item(i);
287
288                 FuncRequest const * func = reinterpret_cast<FuncRequest *>(
289                         item->get_data(gToolData));
290                 if (func) {
291                         FuncStatus const status = owner_.getLyXFunc().getStatus(*func);
292                         item->set_sensitive(status.enabled());
293                 }
294         }
295 }
296
297 } // namespace frontend
298 } // namespace lyx