* Licence details can be found in the file COPYING.
*
* \author Huang Ying
+ * \author John Spray
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
-#include <gtkmm.h>
+
+// Too hard to make concept checks work with this file
+#ifdef _GLIBCPP_CONCEPT_CHECKS
+#undef _GLIBCPP_CONCEPT_CHECKS
+#endif
#include "GToolbar.h"
#include "GView.h"
-#include "LyXAction.h"
-#include "lyxfunc.h"
-#include "FuncStatus.h"
+
+#include "ghelpers.h"
+
#include "buffer.h"
#include "bufferparams.h"
-#include "funcrequest.h"
-#include "gettext.h"
-#include "Tooltips.h"
-#include "support/filetools.h"
-#include "support/lstrings.h"
#include "debug.h"
+#include "funcrequest.h"
+#include "FuncStatus.h"
+#include "lyxfunc.h"
using std::string;
+namespace lyx {
+namespace frontend {
+
+namespace {
-namespace
+GView::Position getPosition(ToolbarBackend::Flags const & flags)
{
+ if (flags & ToolbarBackend::TOP)
+ return GView::Top;
+ if (flags & ToolbarBackend::BOTTOM)
+ return GView::Bottom;
+ if (flags & ToolbarBackend::LEFT)
+ return GView::Left;
+ if (flags & ToolbarBackend::RIGHT)
+ return GView::Right;
+ return GView::Top;
+}
+LyXTextClass const & getTextClass(LyXView const & lv)
+{
+ return lv.buffer()->params().getLyXTextClass();
+}
+
char const * gToolData = "tool_data";
+} // namespace anon
+
+
+GLayoutBox::GLayoutBox(LyXView & owner,
+ Gtk::Toolbar & toolbar,
+ FuncRequest const & func)
+ : owner_(owner),
+ internal_(false)
+{
+ combo_.signal_changed().connect(
+ sigc::mem_fun(*this,&GLayoutBox::selected));
+
+ model_ = Gtk::ListStore::create(cols_);
+ combo_.set_model(model_);
+ Gtk::CellRendererText * cell = Gtk::manage(new Gtk::CellRendererText);
+ combo_.pack_start(*cell, true);
+ combo_.add_attribute(*cell,"text",0);
+ combo_.set_wrap_width(2);
+ // Initially there's nothing in the liststore, so set the size
+ // to avoid it jumping too much when the user does something that
+ // causes the first update()
+ combo_.set_size_request(130,-1);
+
+
+ combo_.set_data(
+ gToolData,
+ reinterpret_cast<void*>(&const_cast<FuncRequest &>(func)));
+
+ combo_.show();
+
+ Gtk::ToolItem * toolitem = Gtk::manage(new Gtk::ToolItem);
+ toolitem->add(combo_);
+ toolbar.append(*toolitem);
+}
-inline void comboClear(Gtk::Combo & combo)
+void GLayoutBox::set(string const & layout)
{
- std::vector<Glib::ustring> strings;
- strings.push_back("");
- combo.set_popdown_strings(strings);
+ LyXTextClass const & tc = getTextClass(owner_);
+ string const target = tc[layout]->name();
+
+ internal_ = true;
+ Gtk::TreeModel::iterator it = model_->children().begin();
+ Gtk::TreeModel::iterator end = model_->children().end();
+ for (; it != end; ++it) {
+ if ((*it)[cols_.name] == target){
+ combo_.set_active(it);
+ internal_ = false;
+ return;
+ }
+ }
+ internal_ = false;
+
+ lyxerr << "ERROR (GLayoutBox::set): layout not found! name: "
+ << target << std::endl;
}
-inline bool comboIsEmpty(Gtk::Combo & combo)
+void GLayoutBox::update()
{
- std::vector<Glib::ustring> strings = combo.get_popdown_strings();
- return (strings.empty() || (strings.size() == 1 && strings[0] == ""));
+ clear();
+
+ LyXTextClass const & tc = getTextClass(owner_);
+
+ LyXTextClass::const_iterator it = tc.begin();
+ LyXTextClass::const_iterator const end = tc.end();
+
+ internal_ = true;
+ for (; it != end; ++it)
+ if ((*it)->obsoleted_by().empty()) {
+ Gtk::TreeModel::iterator iter = model_->append();
+ Gtk::TreeModel::Row row = *iter;
+ row[cols_.name] = Glib::locale_to_utf8((*it)->name());
+ }
+ internal_ = false;
+
+ // now that we've loaded something into the combobox, forget
+ // the initial fixed size and let GTK decide.
+ combo_.set_size_request(-1,-1);
}
+void GLayoutBox::clear()
+{
+ internal_ = true;
+ model_->clear();
+ internal_ = false;
}
-GToolbar::GToolbar(LyXView * lyxView, int /*x*/, int /*y*/)
- : view_(lyxView), internal_(false)
+void GLayoutBox::open()
{
- combo_.set_value_in_list();
- combo_.get_entry()->set_editable(false);
- combo_.unset_flags(Gtk::CAN_FOCUS | Gtk::CAN_DEFAULT);
- combo_.get_entry()->unset_flags(Gtk::CAN_FOCUS | Gtk::CAN_DEFAULT);
- comboClear(combo_);
- combo_.get_entry()->signal_changed().connect(
- SigC::slot(*this,
- >oolbar::onLayoutSelected));
- GView * gview = static_cast<GView*>(lyxView);
- vbox_.show();
- Gtk::VBox & vbox = gview->getVBox();
- vbox.children().push_back(Gtk::Box_Helpers::Element(vbox_,
- Gtk::PACK_SHRINK));
+ combo_.popup();
}
-GToolbar::~GToolbar()
+void GLayoutBox::setEnabled(bool sensitive)
{
+ combo_.set_sensitive(sensitive);
}
-void GToolbar::add(ToolbarBackend::Toolbar const & tb)
+void GLayoutBox::selected()
{
- Gtk::Toolbar * toolbar = manage(new Gtk::Toolbar);
- ToolbarBackend::item_iterator it = tb.items.begin();
- ToolbarBackend::item_iterator end = tb.items.end();
- for (; it != end; ++it)
- add(toolbar, *it);
- toolbar->set_toolbar_style(Gtk::TOOLBAR_ICONS);
- toolbar->show();
- vbox_.children().push_back(
- Gtk::Box_Helpers::Element(*toolbar,
- Gtk::PACK_SHRINK));
- toolbars_.push_back(toolbar);
+ if (internal_)
+ return;
+
+ Glib::ustring layoutGuiName = (*(combo_.get_active()))[cols_.name];
+
+ // we get two signal, one of them is empty and useless
+ if (layoutGuiName.empty())
+ return;
+
+ layoutSelected(owner_, layoutGuiName);
+}
+
+} // namespace frontend
+} // namespace lyx
+
+
+Toolbars::ToolbarPtr make_toolbar(ToolbarBackend::Toolbar const & tbb,
+ LyXView & owner)
+{
+ using lyx::frontend::GToolbar;
+ return Toolbars::ToolbarPtr(new GToolbar(tbb, owner));
}
+namespace lyx {
+namespace frontend {
-void GToolbar::add(Gtk::Toolbar * toolbar,
- ToolbarBackend::Item const & item)
+GToolbar::GToolbar(ToolbarBackend::Toolbar const & tbb, LyXView & owner)
+ : owner_(dynamic_cast<GView &>(owner))
+{
+ ToolbarBackend::item_iterator it = tbb.items.begin();
+ ToolbarBackend::item_iterator end = tbb.items.end();
+ for (; it != end; ++it)
+ add(it->first, it->second);
+
+ toolbar_.set_toolbar_style(Gtk::TOOLBAR_ICONS);
+ toolbar_.show_all();
+
+ GView::Position const position = getPosition(tbb.flags);
+
+ if (position == GView::Left || position == GView::Right)
+ toolbar_.set_orientation(Gtk::ORIENTATION_VERTICAL);
+
+ owner_.getBox(position).children().push_back(
+ Gtk::Box_Helpers::Element(toolbar_, Gtk::PACK_SHRINK));
+
+ toolbar_.set_tooltips(true);
+}
+
+void GToolbar::add(FuncRequest const & func, string const & tooltip)
{
- FuncRequest const & func = item.first;
- string const & tooltip = item.second;
switch (func.action) {
- case ToolbarBackend::SEPARATOR:
- toolbar->tools().push_back(Gtk::Toolbar_Helpers::Space());
+ case ToolbarBackend::SEPARATOR: {
+ Gtk::SeparatorToolItem * space =
+ Gtk::manage(new Gtk::SeparatorToolItem);
+ toolbar_.append(*space);
break;
+ }
+
case ToolbarBackend::MINIBUFFER:
// Not supported yet.
break;
- case ToolbarBackend::LAYOUTS:
- {
- combo_.show();
- toolbar->tools().push_back(
- Gtk::Toolbar_Helpers::Element(combo_));
- toolbar->tools().back().get_widget()->set_data(
- gToolData,
- reinterpret_cast<void*>(&const_cast<ToolbarBackend::Item&>(item)));
+
+ case ToolbarBackend::LAYOUTS: {
+ layout_.reset(new GLayoutBox(owner_, toolbar_, func));
break;
}
- default:
- {
- Glib::ustring xpmName =
- Glib::locale_to_utf8(toolbarbackend.getIcon(func));
+
+ default: {
+ // choose an icon from the funcrequest
+ Gtk::BuiltinStockID stockID = getGTKStockIcon(func);
+
Glib::ustring tip = Glib::locale_to_utf8(tooltip);
- if (xpmName.size() == 0) {
- toolbar->tools().push_back(
- Gtk::Toolbar_Helpers::ButtonElem(
- "",
- SigC::bind(SigC::slot(*this, >oolbar::onButtonClicked),
- FuncRequest(func)),
- tip));
+
+ Gtk::ToolButton * toolbutton;
+ if (stockID != Gtk::Stock::MISSING_IMAGE) {
+ // Prefer stock gtk graphics
+ Gtk::IconSize size(Gtk::ICON_SIZE_LARGE_TOOLBAR);
+ Gtk::Image * image = Gtk::manage(new Gtk::Image(stockID, size));
+ image->show();
+ toolbutton = Gtk::manage(new Gtk::ToolButton(*image));
} else {
- Gtk::Image * image =
- Gtk::manage(new Gtk::Image(xpmName));
+ Glib::ustring xpmName =
+ Glib::locale_to_utf8(toolbarbackend.getIcon(func));
+ Gtk::Image * image = Gtk::manage(new Gtk::Image(xpmName));
image->show();
- toolbar->tools().push_back(
- Gtk::Toolbar_Helpers::ButtonElem(
- "",
- *image,
- SigC::bind(SigC::slot(*this, >oolbar::onButtonClicked),
- FuncRequest(func)),
- tip));
+ toolbutton = Gtk::manage(new Gtk::ToolButton(*image));
}
- toolbar->tools().back().get_content()->set_data(
- gToolData,
- reinterpret_cast<void*>(&const_cast<ToolbarBackend::Item&>(item)));
- break;
- }
- }
-}
+ // This code is putting a function reference into the GObject data field
+ // named gToolData. That's how we know how to update the status of the
+ // toolitem later.
+ toolbutton->set_data(gToolData,
+ reinterpret_cast<void*>(&const_cast<FuncRequest &>(func)));
-void GToolbar::onButtonClicked(FuncRequest func)
-{
- view_->getLyXFunc().dispatch(func, true);
-}
+ toolbutton->set_tooltip(*toolbar_.get_tooltips_object(),tip);
+ toolbutton->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this,
+ >oolbar::clicked), FuncRequest(func)));
+ toolbar_.append(*toolbutton);
+ break;
+ }
-void GToolbar::onLayoutSelected()
-{
- if (internal_)
- return;
- string layoutGuiName = combo_.get_entry()->get_text();
- // we get two signal, one of it is empty and useless
- if (layoutGuiName.empty())
- return;
- LyXTextClass const & tc =
- view_->buffer()->params().getLyXTextClass();
-
- LyXTextClass::const_iterator end = tc.end();
- for (LyXTextClass::const_iterator cit = tc.begin();
- cit != end; ++cit) {
- if ((*cit)->name() == layoutGuiName) {
- view_->getLyXFunc().dispatch(
- FuncRequest(LFUN_LAYOUT, (*cit)->name()),
- true);
- return;
- }
}
- lyxerr << "ERROR (GToolbar::layoutSelected): layout not found! name : "
- << layoutGuiName
- << std::endl;
}
-void GToolbar::displayToolbar(ToolbarBackend::Toolbar const & /*tb*/, bool /*show*/)
+void GToolbar::clicked(FuncRequest func)
{
+ owner_.getLyXFunc().dispatch(func);
}
-void GToolbar::update()
+void GToolbar::hide(bool)
{
- std::vector<Gtk::Toolbar*>::iterator itToolbar;
- for (itToolbar = toolbars_.begin();
- itToolbar != toolbars_.end(); ++itToolbar) {
- Gtk::Toolbar * toolbar = *itToolbar;
- Gtk::Toolbar_Helpers::ToolList::iterator it;
- for (it = toolbar->tools().begin();
- it != toolbar->tools().end(); ++it) {
- Gtk::Widget * widget;
- switch (it->get_type()) {
- case Gtk::TOOLBAR_CHILD_WIDGET:
- widget = it->get_widget();
- break;
- case Gtk::TOOLBAR_CHILD_SPACE:
- continue;
- default:
- widget = it->get_content();
- }
- ToolbarBackend::Item * item =
- reinterpret_cast<ToolbarBackend::Item*>(
- widget->get_data(gToolData));
- if (item->first.action == ToolbarBackend::LAYOUTS) {
- LyXFunc const & lf = view_->getLyXFunc();
- bool const sensitive =
- !lf.getStatus(FuncRequest(LFUN_LAYOUT)).disabled();
- widget->set_sensitive(sensitive);
- continue;
- }
- FuncStatus const status = view_->
- getLyXFunc().getStatus(item->first);
- bool sensitive = !status.disabled();
- widget->set_sensitive(sensitive);
- if (it->get_type() != Gtk::TOOLBAR_CHILD_BUTTON)
- return;
- if (status.onoff(true))
- static_cast<Gtk::Button*>(widget)->
- set_relief(Gtk::RELIEF_NORMAL);
- if (status.onoff(false))
- static_cast<Gtk::Button*>(widget)->
- set_relief(Gtk::RELIEF_NONE);
- }
- }
+ toolbar_.hide();
}
-void GToolbar::setLayout(string const & layout)
+void GToolbar::show(bool)
{
- LyXTextClass const & tc =
- view_->buffer()->params().getLyXTextClass();
- internal_ = true;
- combo_.get_entry()->set_text(tc[layout]->name());
- internal_ = false;
+ toolbar_.show();
}
-void GToolbar::updateLayoutList()
+void GToolbar::update()
{
- LyXTextClass const & tc =
- view_->buffer()->params().getLyXTextClass();
- LyXTextClass::const_iterator end = tc.end();
- std::vector<Glib::ustring> strings;
- for (LyXTextClass::const_iterator cit = tc.begin();
- cit != end; ++cit)
- if ((*cit)->obsoleted_by().empty())
- strings.push_back(
- Glib::locale_to_utf8((*cit)->name()));
- internal_ = true;
- combo_.set_popdown_strings(strings);
- internal_ = false;
-}
+ int const items = toolbar_.get_n_items();
+ for (int i = 0; i < items; ++i) {
+ Gtk::ToolItem * item = toolbar_.get_nth_item(i);
-void GToolbar::openLayoutList()
-{
- combo_.get_list()->activate();
+ FuncRequest const * func = reinterpret_cast<FuncRequest *>(
+ item->get_data(gToolData));
+ if (func) {
+ FuncStatus const status = owner_.getLyXFunc().getStatus(*func);
+ item->set_sensitive(status.enabled());
+ }
+ }
}
-
-void GToolbar::clearLayoutList()
-{
- internal_ = true;
- comboClear(combo_);
- internal_ = false;
-}
+} // namespace frontend
+} // namespace lyx