]> git.lyx.org Git - features.git/blob - src/frontends/gtk/GToolbar.C
* Positionable and dynamically visible toolbars for the XForms frontend.
[features.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  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12 #include <gtkmm.h>
13
14 #include "GToolbar.h"
15 #include "GView.h"
16
17 #include "buffer.h"
18 #include "bufferparams.h"
19 #include "debug.h"
20 #include "funcrequest.h"
21 #include "FuncStatus.h"
22 #include "lyxfunc.h"
23
24 using std::string;
25
26
27 namespace {
28
29 GView::Position getPosition(ToolbarBackend::Flags const & flags)
30 {
31         if (flags & ToolbarBackend::TOP)
32                 return GView::Top;
33         if (flags & ToolbarBackend::BOTTOM)
34                 return GView::Bottom;
35         if (flags & ToolbarBackend::LEFT)
36                 return GView::Left;
37         if (flags & ToolbarBackend::RIGHT)
38                 return GView::Right;
39         return GView::Top;
40 }
41
42
43 LyXTextClass const & getTextClass(LyXView const & lv)
44 {
45         return lv.buffer()->params().getLyXTextClass();
46 }
47
48
49 void comboClear(Gtk::Combo & combo)
50 {
51         std::vector<Glib::ustring> strings;
52         strings.push_back("");
53         combo.set_popdown_strings(strings);
54 }
55
56
57 bool comboIsEmpty(Gtk::Combo & combo)
58 {
59         std::vector<Glib::ustring> strings = combo.get_popdown_strings();
60         return (strings.empty() || (strings.size() == 1 && strings[0] == ""));
61 }
62
63 char const * gToolData = "tool_data";
64
65 } // namespace anon
66
67
68 GLayoutBox::GLayoutBox(LyXView & owner,
69                        Gtk::Toolbar & toolbar,
70                        FuncRequest const & func)
71         : owner_(owner),
72           internal_(false)
73 {
74         combo_.set_value_in_list();
75         combo_.get_entry()->set_editable(false);
76         combo_.unset_flags(Gtk::CAN_FOCUS | Gtk::CAN_DEFAULT);
77         combo_.get_entry()->unset_flags(Gtk::CAN_FOCUS | Gtk::CAN_DEFAULT);
78         comboClear(combo_);
79
80         combo_.get_entry()->signal_changed().connect(
81                 SigC::slot(*this,
82                            &GLayoutBox::selected));
83
84         combo_.show();
85         toolbar.tools().push_back(Gtk::Toolbar_Helpers::Element(combo_));
86         toolbar.tools().back().get_widget()->set_data(
87                 gToolData,
88                 reinterpret_cast<void*>(&const_cast<FuncRequest &>(func)));
89 }
90
91
92 void GLayoutBox::set(string const & layout)
93 {
94         LyXTextClass const & tc = getTextClass(owner_);
95
96         internal_ = true;
97         combo_.get_entry()->set_text(tc[layout]->name());
98         internal_ = false;
99 }
100
101
102 void GLayoutBox::update()
103 {
104         LyXTextClass const & tc = getTextClass(owner_);
105
106         std::vector<Glib::ustring> strings;
107
108         LyXTextClass::const_iterator it = tc.begin();
109         LyXTextClass::const_iterator const end = tc.end();
110         for (; it != end; ++it)
111                 if ((*it)->obsoleted_by().empty())
112                         strings.push_back(
113                                 Glib::locale_to_utf8((*it)->name()));
114         internal_ = true;
115         combo_.set_popdown_strings(strings);
116         internal_ = false;
117 }
118
119
120 void GLayoutBox::clear()
121 {
122         internal_ = true;
123         comboClear(combo_);
124         internal_ = false;
125 }
126
127
128 void GLayoutBox::open()
129 {
130         combo_.get_list()->activate();
131 }
132
133
134 void GLayoutBox::setEnabled(bool sensitive)
135 {
136         combo_.set_sensitive(sensitive);
137 }
138
139
140 void GLayoutBox::selected()
141 {
142         if (internal_)
143                 return;
144
145         string layoutGuiName = combo_.get_entry()->get_text();
146         // we get two signal, one of it is empty and useless
147         if (layoutGuiName.empty())
148                 return;
149         LyXTextClass const & tc = getTextClass(owner_);
150
151         LyXTextClass::const_iterator it = tc.begin();
152         LyXTextClass::const_iterator const end = tc.end();
153         for (; it != end; ++it) {
154                 string const & name = (*it)->name();
155                 if (name == layoutGuiName) {
156                         owner_.getLyXFunc().dispatch(
157                                 FuncRequest(LFUN_LAYOUT, name),
158                                 true);
159                         return;
160                 }
161         }
162         lyxerr << "ERROR (GLayoutBox::selected): layout not found! name: "
163                << layoutGuiName << std::endl;
164 }
165
166
167 Toolbars::ToolbarPtr make_toolbar(ToolbarBackend::Toolbar const & tbb,
168                                   LyXView & owner)
169 {
170         return Toolbars::ToolbarPtr(new GToolbar(tbb, owner));
171 }
172
173
174 GToolbar::GToolbar(ToolbarBackend::Toolbar const & tbb, LyXView & owner)
175         : owner_(dynamic_cast<GView &>(owner))
176 {
177         ToolbarBackend::item_iterator it = tbb.items.begin();
178         ToolbarBackend::item_iterator end = tbb.items.end();
179         for (; it != end; ++it)
180                 add(it->first, it->second);
181
182         toolbar_.set_toolbar_style(Gtk::TOOLBAR_ICONS);
183
184         GView::Position const position = getPosition(tbb.flags);
185
186         if (position == GView::Left || position == GView::Right)
187                 toolbar_.set_orientation(Gtk::ORIENTATION_VERTICAL);
188
189         owner_.getBox(position).children().push_back(
190                 Gtk::Box_Helpers::Element(toolbar_, Gtk::PACK_SHRINK));
191 }
192
193
194 void GToolbar::add(FuncRequest const & func, string const & tooltip)
195 {
196         switch (func.action) {
197         case ToolbarBackend::SEPARATOR:
198                 toolbar_.tools().push_back(Gtk::Toolbar_Helpers::Space());
199                 break;
200         case ToolbarBackend::MINIBUFFER:
201                 // Not supported yet.
202                 break;
203         case ToolbarBackend::LAYOUTS:
204         {
205                 layout_.reset(new GLayoutBox(owner_, toolbar_, func));
206                 break;
207         }
208         default:
209                 Glib::ustring xpmName =
210                         Glib::locale_to_utf8(toolbarbackend.getIcon(func));
211                 Glib::ustring tip = Glib::locale_to_utf8(tooltip);
212                 if (xpmName.size() == 0) {
213                         toolbar_.tools().push_back(
214                                 Gtk::Toolbar_Helpers::ButtonElem(
215                                         "",
216                                         SigC::bind(SigC::slot(*this, &GToolbar::clicked),
217                                                    FuncRequest(func)),
218                                         tip));
219                 } else {
220                         Gtk::Image * image =
221                                 Gtk::manage(new Gtk::Image(xpmName));
222                         image->show();
223                         toolbar_.tools().push_back(
224                                 Gtk::Toolbar_Helpers::ButtonElem(
225                                         "",
226                                         *image,
227                                         SigC::bind(SigC::slot(*this, &GToolbar::clicked),
228                                                    FuncRequest(func)),
229                                         tip));
230                 }
231                 toolbar_.tools().back().get_content()->set_data(
232                         gToolData,
233                         reinterpret_cast<void*>(&const_cast<FuncRequest &>(func)));
234                 break;
235         }
236 }
237
238
239 void GToolbar::clicked(FuncRequest func)
240 {
241         owner_.getLyXFunc().dispatch(func, true);
242 }
243
244
245 void GToolbar::hide(bool)
246 {
247         toolbar_.hide();
248 }
249
250
251 void GToolbar::show(bool)
252 {
253         toolbar_.show();
254 }
255
256
257 void GToolbar::update()
258 {
259         Gtk::Toolbar_Helpers::ToolList::iterator it =
260                 toolbar_.tools().begin();
261         Gtk::Toolbar_Helpers::ToolList::iterator const end =
262                 toolbar_.tools().end();
263
264         for (; it != end; ++it) {
265                 Gtk::Widget * widget;
266                 switch (it->get_type()) {
267                 case Gtk::TOOLBAR_CHILD_WIDGET:
268                         widget = it->get_widget();
269                         break;
270                 case Gtk::TOOLBAR_CHILD_SPACE:
271                         continue;
272                 default:
273                         widget = it->get_content();
274                 }
275
276                 FuncRequest const & func = *reinterpret_cast<FuncRequest *>(
277                         widget->get_data(gToolData));
278
279                 if (func.action == int(ToolbarBackend::LAYOUTS))
280                         continue;
281
282                 FuncStatus const status = owner_.getLyXFunc().getStatus(func);
283                 bool sensitive = status.enabled();
284                 widget->set_sensitive(sensitive);
285                 if (it->get_type() != Gtk::TOOLBAR_CHILD_BUTTON)
286                         return;
287                 if (status.onoff(true))
288                         static_cast<Gtk::Button*>(widget)->
289                                 set_relief(Gtk::RELIEF_NORMAL);
290                 if (status.onoff(false))
291                         static_cast<Gtk::Button*>(widget)->
292                                 set_relief(Gtk::RELIEF_NONE);
293         }
294 }