summaryrefslogtreecommitdiffstats
path: root/src/gui/PropertiesWindow.cpp
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2018-11-24 13:44:03 +0100
committerDavid Robillard <d@drobilla.net>2018-11-24 13:44:03 +0100
commita7d83f19b08eb4c6f79a82fe60c2b86db13f4420 (patch)
treed9b620bfba1e7462df4ddb3f6225cc5216c0ca81 /src/gui/PropertiesWindow.cpp
parentd63edc742cebd685f8a05936682210aa5c1e69a9 (diff)
downloadingen-a7d83f19b08eb4c6f79a82fe60c2b86db13f4420.tar.gz
ingen-a7d83f19b08eb4c6f79a82fe60c2b86db13f4420.tar.bz2
ingen-a7d83f19b08eb4c6f79a82fe60c2b86db13f4420.zip
Squashed 'waflib/' changes from 6e726eb1..5ea8f99f
5ea8f99f Improve test output spacing 0e23b29f Raise exception when test suite fails to ensure non-zero exit status d6de073b Show run time of unit tests 5b655541 Add short configure option for ultra-strict flags 4687ba6d Use gtest-like test output 258903d9 Fix failure count in test group summaries da07e738 Fix verbose tests with Python 3 git-subtree-dir: waflib git-subtree-split: 5ea8f99f6e1246079c1fe6bb590c38a53aadd40d
Diffstat (limited to 'src/gui/PropertiesWindow.cpp')
-rw-r--r--src/gui/PropertiesWindow.cpp591
1 files changed, 0 insertions, 591 deletions
diff --git a/src/gui/PropertiesWindow.cpp b/src/gui/PropertiesWindow.cpp
deleted file mode 100644
index 4d47b3ae..00000000
--- a/src/gui/PropertiesWindow.cpp
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- This file is part of Ingen.
- Copyright 2007-2015 David Robillard <http://drobilla.net/>
-
- Ingen is free software: you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free
- Software Foundation, either version 3 of the License, or 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 Affero General Public License for details.
-
- You should have received a copy of the GNU Affero General Public License
- along with Ingen. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <algorithm>
-#include <cassert>
-#include <set>
-
-#include <gtkmm/label.h>
-#include <gtkmm/spinbutton.h>
-
-#include "ingen/Interface.hpp"
-#include "ingen/Log.hpp"
-#include "ingen/URIMap.hpp"
-#include "ingen/World.hpp"
-#include "ingen/client/BlockModel.hpp"
-#include "ingen/client/PluginModel.hpp"
-
-#include "App.hpp"
-#include "PropertiesWindow.hpp"
-#include "RDFS.hpp"
-#include "URIEntry.hpp"
-
-namespace Ingen {
-
-using namespace Client;
-
-namespace GUI {
-
-typedef std::set<URI> URISet;
-
-PropertiesWindow::PropertiesWindow(BaseObjectType* cobject,
- const Glib::RefPtr<Gtk::Builder>& xml)
- : Window(cobject)
- , _value_type(0)
-{
- xml->get_widget("properties_vbox", _vbox);
- xml->get_widget("properties_scrolledwindow", _scrolledwindow);
- xml->get_widget("properties_table", _table);
- xml->get_widget("properties_key_combo", _key_combo);
- xml->get_widget("properties_value_bin", _value_bin);
- xml->get_widget("properties_add_button", _add_button);
- xml->get_widget("properties_cancel_button", _cancel_button);
- xml->get_widget("properties_apply_button", _apply_button);
- xml->get_widget("properties_ok_button", _ok_button);
-
- _key_store = Gtk::ListStore::create(_combo_columns);
- _key_combo->set_model(_key_store);
- _key_combo->pack_start(_combo_columns.label_col);
-
- _key_combo->signal_changed().connect(
- sigc::mem_fun(this, &PropertiesWindow::key_changed));
-
- _add_button->signal_clicked().connect(
- sigc::mem_fun(this, &PropertiesWindow::add_clicked));
-
- _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));
-}
-
-void
-PropertiesWindow::reset()
-{
- _property_connection.disconnect();
- _property_removed_connection.disconnect();
-
- _key_store->clear();
- _records.clear();
-
- _model.reset();
-
- _table->children().clear();
- _table->resize(1, 3);
- _table->property_n_rows() = 1;
-}
-
-void
-PropertiesWindow::present(SPtr<const ObjectModel> model)
-{
- set_object(model);
- Gtk::Window::present();
-}
-
-void
-PropertiesWindow::add_property(const URI& key, const Atom& value)
-{
- World* world = _app->world();
-
- const unsigned n_rows = _table->property_n_rows() + 1;
- _table->property_n_rows() = n_rows;
-
- // Column 0: Property
- LilvNode* prop = lilv_new_uri(world->lilv_world(), key.c_str());
- std::string name = RDFS::label(world, prop);
- if (name.empty()) {
- name = world->rdf_world()->prefixes().qualify(key);
- }
- Gtk::Label* label = new Gtk::Label(
- std::string("<a href=\"") + key.string() + "\">" + name + "</a>",
- 1.0,
- 0.5);
- label->set_use_markup(true);
- _app->set_tooltip(label, prop);
- _table->attach(*Gtk::manage(label), 0, 1, n_rows, n_rows + 1,
- Gtk::FILL|Gtk::SHRINK, Gtk::SHRINK);
-
- // Column 1: Value
- Gtk::Alignment* align = manage(new Gtk::Alignment(0.0, 0.5, 1.0, 1.0));
- Gtk::CheckButton* present = manage(new Gtk::CheckButton());
- const char* type = _app->world()->uri_map().unmap_uri(value.type());
- Gtk::Widget* val_widget = create_value_widget(key, type, value);
-
- present->set_active();
- if (val_widget) {
- align->add(*Gtk::manage(val_widget));
- _app->set_tooltip(val_widget, prop);
- }
-
- _table->attach(*align, 1, 2, n_rows, n_rows + 1,
- Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK);
- _table->attach(*present, 2, 3, n_rows, n_rows + 1,
- Gtk::FILL, Gtk::SHRINK);
- _records.emplace(key, Record(value, align, n_rows, present));
- _table->show_all();
-
- lilv_node_free(prop);
-}
-
-bool
-PropertiesWindow::datatype_supported(const RDFS::URISet& types,
- URI* widget_type)
-{
- if (types.find(_app->uris().atom_Int) != types.end()) {
- *widget_type = _app->uris().atom_Int;
- return true;
- } else if (types.find(_app->uris().atom_Float) != types.end()) {
- *widget_type = _app->uris().atom_Float;
- return true;
- } else if (types.find(_app->uris().atom_Bool) != types.end()) {
- *widget_type = _app->uris().atom_Bool;
- return true;
- } else if (types.find(_app->uris().atom_String) != types.end()) {
- *widget_type = _app->uris().atom_String;
- return true;
- } else if (types.find(_app->uris().atom_URID) != types.end()) {
- *widget_type = _app->uris().atom_URID;
- return true;
- }
-
- return false;
-}
-
-bool
-PropertiesWindow::class_supported(const RDFS::URISet& types)
-{
- World* world = _app->world();
- LilvNode* rdf_type = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDF "type");
-
- for (const auto& t : types) {
- LilvNode* range = lilv_new_uri(world->lilv_world(), t.c_str());
- LilvNodes* instances = lilv_world_find_nodes(
- world->lilv_world(), nullptr, rdf_type, range);
-
- const bool has_instance = (lilv_nodes_size(instances) > 0);
-
- lilv_nodes_free(instances);
- lilv_node_free(range);
- if (has_instance) {
- lilv_node_free(rdf_type);
- return true;
- }
- }
-
- lilv_node_free(rdf_type);
- return false;
-}
-
-/** Set the node this window is associated with.
- * This function MUST be called before using this object in any way.
- */
-void
-PropertiesWindow::set_object(SPtr<const ObjectModel> model)
-{
- reset();
- _model = model;
-
- set_title(model->path() + " Properties - Ingen");
-
- World* world = _app->world();
-
- LilvNode* rdf_type = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDF "type");
- LilvNode* rdfs_DataType = lilv_new_uri(
- world->lilv_world(), LILV_NS_RDFS "Datatype");
-
- // Populate key combo
- const URISet props = RDFS::properties(world, model);
- std::map<std::string, URI> entries;
- for (const auto& p : props) {
- LilvNode* prop = lilv_new_uri(world->lilv_world(), p.c_str());
- const std::string label = RDFS::label(world, prop);
- URISet ranges = RDFS::range(world, prop, true);
-
- lilv_node_free(prop);
- if (label.empty() || ranges.empty()) {
- // Property has no label or range, can't show a widget for it
- continue;
- }
-
- LilvNode* range = lilv_new_uri(world->lilv_world(), (*ranges.begin()).c_str());
- if (RDFS::is_a(world, range, rdfs_DataType)) {
- // Range is a datatype, show if type or any subtype is supported
- RDFS::datatypes(_app->world(), ranges, false);
- URI widget_type("urn:nothing");
- if (datatype_supported(ranges, &widget_type)) {
- entries.emplace(label, p);
- }
- } else {
- // Range is presumably a class, show if any instances are known
- if (class_supported(ranges)) {
- entries.emplace(label, p);
- }
- }
- }
-
- for (const auto& e : entries) {
- Gtk::ListStore::iterator ki = _key_store->append();
- Gtk::ListStore::Row row = *ki;
- row[_combo_columns.uri_col] = e.second.string();
- row[_combo_columns.label_col] = e.first;
- }
-
- lilv_node_free(rdfs_DataType);
- lilv_node_free(rdf_type);
-
- for (const auto& p : model->properties()) {
- add_property(p.first, p.second);
- }
-
- _table->show_all();
-
- _property_connection = model->signal_property().connect(
- sigc::mem_fun(this, &PropertiesWindow::add_property));
- _property_removed_connection = model->signal_property_removed().connect(
- sigc::mem_fun(this, &PropertiesWindow::remove_property));
-}
-
-Gtk::Widget*
-PropertiesWindow::create_value_widget(const URI& key,
- const char* type_uri,
- const Atom& value)
-{
- if (!type_uri || !URI::is_valid(type_uri)) {
- return nullptr;
- }
-
- URI type(type_uri);
- Ingen::World* world = _app->world();
- LilvWorld* lworld = world->lilv_world();
-
- // See if type is a datatype we support
- std::set<URI> types{type};
- RDFS::datatypes(_app->world(), types, false);
-
- URI widget_type("urn:nothing");
- const bool supported = datatype_supported(types, &widget_type);
- if (supported) {
- type = widget_type;
- _value_type = _app->world()->uri_map().map_uri(type);
- }
-
- if (type == _app->uris().atom_Int) {
- Gtk::SpinButton* widget = manage(new Gtk::SpinButton(0.0, 0));
- widget->property_numeric() = true;
- widget->set_range(INT_MIN, INT_MAX);
- widget->set_increments(1, 10);
- if (value.is_valid()) {
- widget->set_value(value.get<int32_t>());
- }
- widget->signal_value_changed().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- return widget;
- } else if (type == _app->uris().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(-FLT_MAX, FLT_MAX);
- widget->set_increments(0.1, 1.0);
- if (value.is_valid()) {
- widget->set_value(value.get<float>());
- }
- widget->signal_value_changed().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- return widget;
- } else if (type == _app->uris().atom_Bool) {
- Gtk::CheckButton* widget = manage(new Gtk::CheckButton());
- if (value.is_valid()) {
- widget->set_active(value.get<int32_t>());
- }
- widget->signal_toggled().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- return widget;
- } else if (type == _app->uris().atom_String) {
- Gtk::Entry* widget = manage(new Gtk::Entry());
- if (value.is_valid()) {
- widget->set_text(value.ptr<char>());
- }
- widget->signal_changed().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- return widget;
- } else if (type == _app->uris().atom_URID) {
- const char* str = (value.is_valid()
- ? world->uri_map().unmap_uri(value.get<int32_t>())
- : "");
-
- LilvNode* pred = lilv_new_uri(lworld, key.c_str());
- URISet ranges = RDFS::range(world, pred, true);
- URIEntry* widget = manage(new URIEntry(_app, ranges, str ? str : ""));
- widget->signal_changed().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- lilv_node_free(pred);
- return widget;
- }
-
- LilvNode* type_node = lilv_new_uri(lworld, type.c_str());
- LilvNode* rdfs_Class = lilv_new_uri(lworld, LILV_NS_RDFS "Class");
- const bool is_class = RDFS::is_a(world, type_node, rdfs_Class);
- lilv_node_free(rdfs_Class);
- lilv_node_free(type_node);
-
- if (type == _app->uris().atom_URI ||
- type == _app->uris().rdfs_Class ||
- is_class) {
- LilvNode* pred = lilv_new_uri(lworld, key.c_str());
- URISet ranges = RDFS::range(world, pred, true);
- const char* str = value.is_valid() ? value.ptr<const char>() : "";
- URIEntry* widget = manage(new URIEntry(_app, ranges, str));
- widget->signal_changed().connect(
- sigc::bind(sigc::mem_fun(this, &PropertiesWindow::on_change), key));
- lilv_node_free(pred);
- return widget;
- }
-
- _app->log().error(fmt("No widget for value type %1%\n") % type);
-
- return nullptr;
-}
-
-void
-PropertiesWindow::on_show()
-{
- static const int WIN_PAD = 64;
- static const int VBOX_PAD = 16;
-
- int width = 0;
- int height = 0;
-
- for (const auto& c : _vbox->children()) {
- const Gtk::Requisition& req = c.get_widget()->size_request();
-
- width = std::max(width, req.width);
- height += req.height + VBOX_PAD;
- }
-
- const Gtk::Requisition& req = _table->size_request();
-
- width = 1.2 * std::max(width, req.width + 128);
- 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::change_property(const URI& key, const Atom& value)
-{
- auto r = _records.find(key);
- if (r == _records.end()) {
- add_property(key, value);
- _table->show_all();
- return;
- }
-
- Record& record = r->second;
- const char* type = _app->world()->uri_map().unmap_uri(value.type());
- Gtk::Widget* val_widget = create_value_widget(key, type, value);
-
- if (val_widget) {
- record.value_widget->remove();
- record.value_widget->add(*Gtk::manage(val_widget));
- val_widget->show_all();
- }
-
- record.value = value;
-}
-
-void
-PropertiesWindow::remove_property(const URI& key, const Atom& value)
-{
- // Bleh, there doesn't seem to be an easy way to remove a Gtk::Table row...
- _records.clear();
- _table->children().clear();
- _table->resize(1, 3);
- _table->property_n_rows() = 1;
-
- for (const auto& p : _model->properties()) {
- add_property(p.first, p.second);
- }
- _table->show_all();
-}
-
-Atom
-PropertiesWindow::get_value(LV2_URID type, Gtk::Widget* value_widget)
-{
- Forge& forge = _app->forge();
-
- if (type == forge.Int) {
- Gtk::SpinButton* spin = dynamic_cast<Gtk::SpinButton*>(value_widget);
- if (spin) {
- return _app->forge().make(spin->get_value_as_int());
- }
- } else if (type == forge.Float) {
- Gtk::SpinButton* spin = dynamic_cast<Gtk::SpinButton*>(value_widget);
- if (spin) {
- return _app->forge().make(static_cast<float>(spin->get_value()));
- }
- } else if (type == forge.Bool) {
- Gtk::CheckButton* check = dynamic_cast<Gtk::CheckButton*>(value_widget);
- if (check) {
- return _app->forge().make(check->get_active());
- }
- } else if (type == forge.URI || type == forge.URID) {
- URIEntry* uri_entry = dynamic_cast<URIEntry*>(value_widget);
- if (uri_entry && URI::is_valid(uri_entry->get_text())) {
- return _app->forge().make_urid(URI(uri_entry->get_text()));
- } else {
- _app->log().error(fmt("Invalid URI <%1%>\n") % uri_entry->get_text());
- }
- } else if (type == forge.String) {
- Gtk::Entry* entry = dynamic_cast<Gtk::Entry*>(value_widget);
- if (entry) {
- return _app->forge().alloc(entry->get_text());
- }
- }
-
- return Atom();
-}
-
-void
-PropertiesWindow::on_change(const URI& key)
-{
- auto r = _records.find(key);
- if (r == _records.end()) {
- return;
- }
-
- Record& record = r->second;
- const Atom value = get_value(record.value.type(),
- record.value_widget->get_child());
-
- if (value.is_valid()) {
- record.value = value;
- } else {
- _app->log().error(fmt("Failed to get `%1%' value from widget\n") % key);
- }
-}
-
-std::string
-PropertiesWindow::active_key() const
-{
- const Gtk::ListStore::iterator iter = _key_combo->get_active();
- if (!iter) {
- return "";
- }
-
- Glib::ustring prop_uri = (*iter)[_combo_columns.uri_col];
- return prop_uri;
-}
-
-void
-PropertiesWindow::key_changed()
-{
- _value_bin->remove();
- if (!_key_combo->get_active()) {
- return;
- }
-
- LilvWorld* lworld = _app->world()->lilv_world();
- const Gtk::ListStore::Row key_row = *(_key_combo->get_active());
- const Glib::ustring key_uri = key_row[_combo_columns.uri_col];
- LilvNode* prop = lilv_new_uri(lworld, key_uri.c_str());
-
- // Try to create a value widget in the range of this property
- const URISet ranges = RDFS::range(_app->world(), prop, true);
- for (const auto& r : ranges) {
- Gtk::Widget* value_widget = create_value_widget(
- URI(key_uri), r.c_str(), Atom());
-
- if (value_widget) {
- _add_button->set_sensitive(true);
- _value_bin->remove();
- _value_bin->add(*Gtk::manage(value_widget));
- _value_bin->show_all();
- break;
- }
- }
-
- lilv_node_free(prop);
-}
-
-void
-PropertiesWindow::add_clicked()
-{
- if (!_key_combo->get_active() || !_value_type || !_value_bin->get_child()) {
- return;
- }
-
- // Get selected key URI
- const Gtk::ListStore::Row key_row = *(_key_combo->get_active());
- const Glib::ustring key_uri = key_row[_combo_columns.uri_col];
-
- // Try to get value from value widget
- const Atom& value = get_value(_value_type, _value_bin->get_child());
- if (value.is_valid()) {
- // Send property to engine
- Properties properties;
- properties.emplace(URI(key_uri.c_str()), Property(value));
- _app->interface()->put(_model->uri(), properties);
- }
-}
-
-void
-PropertiesWindow::cancel_clicked()
-{
- reset();
- Gtk::Window::hide();
-}
-
-void
-PropertiesWindow::apply_clicked()
-{
- Properties remove;
- Properties add;
- for (const auto& r : _records) {
- const URI& uri = r.first;
- const Record& record = r.second;
- if (record.present_button->get_active()) {
- if (!_model->has_property(uri, record.value)) {
- add.emplace(uri, record.value);
- }
- } else {
- remove.emplace(uri, record.value);
- }
- }
-
- if (remove.empty()) {
- _app->interface()->put(_model->uri(), add);
- } else {
- _app->interface()->delta(_model->uri(), remove, add);
- }
-}
-
-void
-PropertiesWindow::ok_clicked()
-{
- apply_clicked();
- Gtk::Window::hide();
-}
-
-} // namespace GUI
-} // namespace Ingen