summaryrefslogtreecommitdiffstats
path: root/src/gui/PropertiesWindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/PropertiesWindow.cpp')
-rw-r--r--src/gui/PropertiesWindow.cpp302
1 files changed, 302 insertions, 0 deletions
diff --git a/src/gui/PropertiesWindow.cpp b/src/gui/PropertiesWindow.cpp
new file mode 100644
index 00000000..48440817
--- /dev/null
+++ b/src/gui/PropertiesWindow.cpp
@@ -0,0 +1,302 @@
+/* This file is part of Ingen.
+ * Copyright (C) 2007-2009 Dave Robillard <http://drobilla.net>
+ *
+ * Ingen is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <cassert>
+#include <string>
+#include "raul/log.hpp"
+#include "client/NodeModel.hpp"
+#include "client/PluginModel.hpp"
+#include "App.hpp"
+#include "PropertiesWindow.hpp"
+
+#define LOG(s) s << "[PropertiesWindow] "
+
+using namespace std;
+using namespace Raul;
+
+namespace Ingen {
+namespace GUI {
+
+
+PropertiesWindow::PropertiesWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& glade_xml)
+ : Window(cobject)
+{
+ glade_xml->get_widget("properties_vbox", _vbox);
+ glade_xml->get_widget("properties_scrolledwindow", _scrolledwindow);
+ glade_xml->get_widget("properties_table", _table);
+ glade_xml->get_widget("properties_cancel_button", _cancel_button);
+ glade_xml->get_widget("properties_apply_button", _apply_button);
+ glade_xml->get_widget("properties_ok_button", _ok_button);
+
+ _type_choices = Gtk::ListStore::create(_type_cols);
+ for (int i = Raul::Atom::INT; i <= Raul::Atom::BLOB; ++i) {
+ Gtk::TreeModel::Row row = *_type_choices->append();
+ row[_type_cols.type] = static_cast<Raul::Atom::Type>(i);
+ ostringstream ss;
+ ss << static_cast<Raul::Atom::Type>(i);
+ row[_type_cols.choice] = ss.str();
+ }
+
+ _cancel_button->signal_clicked().connect(
+ sigc::mem_fun(this, &PropertiesWindow::cancel_clicked));
+
+ _apply_button->signal_clicked().connect(
+ sigc::mem_fun(this, &PropertiesWindow::apply_clicked));
+
+ _ok_button->signal_clicked().connect(
+ sigc::mem_fun(this, &PropertiesWindow::ok_clicked));
+}
+
+
+/** Set the node this window is associated with.
+ * This function MUST be called before using this object in any way.
+ */
+void
+PropertiesWindow::set_object(SharedPtr<ObjectModel> model)
+{
+ _table->children().clear();
+ _table->resize(1, 3);
+ _table->property_n_rows() = 1;
+
+ _property_connection.disconnect();
+ _model = model;
+
+ set_title(model->path().chop_scheme() + " Properties - Ingen");
+
+ ostringstream ss;
+ unsigned n_rows = 0;
+ for (ObjectModel::Properties::const_iterator i = model->properties().begin();
+ i != model->properties().end(); ++i) {
+ _table->property_n_rows() = ++n_rows;
+
+ const Raul::Atom& value = i->second;
+
+ // Column 0: Property
+ Gtk::Label* lab = manage(new Gtk::Label(i->first.str(), 0.0, 0.5));
+ _table->attach(*lab, 0, 1, n_rows, n_rows + 1, Gtk::FILL|Gtk::SHRINK, Gtk::SHRINK);
+
+ // Column 1: Type
+ Gtk::ComboBox* combo = manage(new Gtk::ComboBox());
+ combo->set_model(_type_choices);
+ combo->pack_start(_type_cols.choice);
+ const char path[] = { static_cast<int>(value.type()) - 1 + '0', '\0' };
+ combo->set_active(_type_choices->get_iter(path));
+ Gtk::Alignment* align = manage(new Gtk::Alignment(0.0, 0.5, 0.0, 1.0));
+ align->add(*combo);
+ _table->attach(*align, 1, 2, n_rows, n_rows + 1, Gtk::FILL|Gtk::SHRINK, Gtk::SHRINK);
+
+ Record record;
+ record.value = value;
+ record.type_widget = combo;
+
+ // Column 2: Value
+ align = manage(new Gtk::Alignment(0.0, 0.5, 1.0, 0.0));
+ Gtk::Widget* value_widget = create_value_widget(i->first, value);
+ align->add(*value_widget);
+ _table->attach(*align, 2, 3, n_rows, n_rows + 1, Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
+ record.value_widget = align;
+ record.row = n_rows;
+ _records.insert(make_pair(i->first, record));
+ }
+
+ _table->show_all();
+
+ _property_connection = model->signal_property.connect(
+ sigc::mem_fun(this, &PropertiesWindow::property_changed));
+}
+
+Gtk::Widget*
+PropertiesWindow::create_value_widget(const Raul::URI& uri, const Raul::Atom& value)
+{
+ if (value.type() == Atom::INT) {
+ Gtk::SpinButton* widget = manage(new Gtk::SpinButton(0.0, 0));
+ widget->property_numeric() = true;
+ widget->set_value(value.get_int32());
+ widget->set_snap_to_ticks(true);
+ widget->set_range(INT_MIN, INT_MAX);
+ widget->set_increments(1, 10);
+ widget->signal_value_changed().connect(sigc::bind(
+ sigc::mem_fun(this, &PropertiesWindow::value_edited),
+ uri));
+ return widget;
+ } else if (value.type() == Atom::FLOAT) {
+ Gtk::SpinButton* widget = manage(new Gtk::SpinButton(0.0, 4));
+ widget->property_numeric() = true;
+ widget->set_snap_to_ticks(false);
+ widget->set_range(DBL_MIN, DBL_MAX);
+ widget->set_value(value.get_float());
+ widget->set_increments(0.1, 1.0);
+ widget->signal_value_changed().connect(sigc::bind(
+ sigc::mem_fun(this, &PropertiesWindow::value_edited),
+ uri));
+ return widget;
+ } else if (value.type() == Atom::BOOL) {
+ Gtk::CheckButton* widget = manage(new Gtk::CheckButton());
+ widget->set_active(value.get_bool());
+ widget->signal_toggled().connect(sigc::bind(
+ sigc::mem_fun(this, &PropertiesWindow::value_edited),
+ uri));
+ return widget;
+ } else if (value.type() == Atom::URI) {
+ Gtk::Entry* widget = manage(new Gtk::Entry());
+ widget->set_text(value.get_uri());
+ widget->signal_changed().connect(sigc::bind(
+ sigc::mem_fun(this, &PropertiesWindow::value_edited),
+ uri));
+ return widget;
+ } else if (value.type() == Atom::STRING) {
+ Gtk::Entry* widget = manage(new Gtk::Entry());
+ widget->set_text(value.get_string());
+ widget->signal_changed().connect(sigc::bind(
+ sigc::mem_fun(this, &PropertiesWindow::value_edited),
+ uri));
+ return widget;
+ }
+
+ return NULL;
+}
+
+
+void
+PropertiesWindow::on_show()
+{
+ static const int WIN_PAD = 32;
+ static const int VBOX_PAD = 12;
+ int width = 0;
+ int height = 0;
+ Gtk::Requisition req;
+
+ typedef Gtk::Box_Helpers::BoxList Children;
+ for (Children::const_iterator i = _vbox->children().begin(); i != _vbox->children().end(); ++i) {
+ req = (*i).get_widget()->size_request();
+ if ((*i).get_widget() != _scrolledwindow) {
+ width = std::max(width, req.width);
+ height += req.height + VBOX_PAD;
+ }
+ }
+
+ req = _table->size_request();
+ width = std::max(width, req.width);
+ height += req.height;
+
+ set_default_size(width + WIN_PAD, height + WIN_PAD);
+ resize(width + WIN_PAD, height + WIN_PAD);
+ Gtk::Window::on_show();
+}
+
+
+void
+PropertiesWindow::property_changed(const Raul::URI& predicate, const Raul::Atom& value)
+{
+ Records::iterator r = _records.find(predicate);
+ if (r == _records.end()) {
+ LOG(error) << "Unknown property `" << predicate << "' changed" << endl;
+ return;
+ }
+
+ Record& record = r->second;
+ Gtk::Widget* value_widget = create_value_widget(predicate, value);
+
+ record.value_widget->remove();
+ record.value_widget->add(*value_widget);
+ record.value = value;
+ value_widget->show();
+}
+
+
+void
+PropertiesWindow::value_edited(const Raul::URI& predicate)
+{
+ Records::iterator r = _records.find(predicate);
+ if (r == _records.end()) {
+ LOG(error) << "Unknown property `" << predicate << "' edited" << endl;
+ return;
+ }
+
+ Record& record = r->second;
+ Raul::Atom::Type type = (*record.type_widget->get_active())[_type_cols.type];
+ if (type == Atom::INT) {
+ Gtk::SpinButton* widget = dynamic_cast<Gtk::SpinButton*>(record.value_widget->get_child());
+ if (!widget) goto bad_type;
+ record.value = Atom(widget->get_value_as_int());
+ } else if (type == Atom::FLOAT) {
+ Gtk::SpinButton* widget = dynamic_cast<Gtk::SpinButton*>(record.value_widget->get_child());
+ if (!widget) goto bad_type;
+ record.value = Atom(static_cast<float>(widget->get_value()));
+ } else if (type == Atom::BOOL) {
+ Gtk::CheckButton* widget = dynamic_cast<Gtk::CheckButton*>(record.value_widget->get_child());
+ if (!widget) goto bad_type;
+ record.value = Atom(widget->get_active());
+ } else if (type == Atom::URI) {
+ Gtk::Entry* widget = dynamic_cast<Gtk::Entry*>(record.value_widget->get_child());
+ if (!widget) goto bad_type;
+ record.value = Atom(Atom::URI, widget->get_text());
+ } else if (type == Atom::STRING) {
+ Gtk::Entry* widget = dynamic_cast<Gtk::Entry*>(record.value_widget->get_child());
+ if (!widget) goto bad_type;
+ record.value = Atom(Atom::URI, widget->get_text());
+ }
+
+ cout << "VALUE EDITED " << predicate << " = " << record.value << endl;
+ return;
+
+bad_type:
+ LOG(error) << "Property `" << predicate << "' value widget has wrong type" << endl;
+ return;
+}
+
+
+void
+PropertiesWindow::cancel_clicked()
+{
+ set_object(_model); // reset
+ Gtk::Window::hide();
+}
+
+
+void
+PropertiesWindow::apply_clicked()
+{
+ LOG(debug) << "apply {" << endl;
+ Shared::Resource::Properties properties;
+ for (Records::const_iterator r = _records.begin(); r != _records.end(); ++r) {
+ const Raul::URI& uri = r->first;
+ const Record& record = r->second;
+ if (!_model->has_property(uri, record.value)) {
+ LOG(debug) << "\t" << uri
+ << " = " << record.value
+ << " :: " << record.value.type() << endl;
+ properties.insert(make_pair(uri, record.value));
+ }
+ }
+
+ App::instance().engine()->put(_model->path(), properties);
+
+ LOG(debug) << "}" << endl;
+}
+
+
+void
+PropertiesWindow::ok_clicked()
+{
+ apply_clicked();
+ Gtk::Window::hide();
+}
+
+
+} // namespace GUI
+} // namespace Ingen