From 1f22a1e6dce27a9ce1b4ccd434be371994ae14e6 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 31 Mar 2014 02:28:26 +0000 Subject: Make port colours configurable. git-svn-id: http://svn.drobilla.net/lad/trunk/patchage@5350 a436a847-0d15-0410-975c-d299462d15a1 --- src/AlsaDriver.cpp | 10 ++--- src/Configuration.cpp | 75 +++++++++++++++++-------------- src/Configuration.hpp | 16 +++++-- src/JackDriver.cpp | 8 ++-- src/Legend.hpp | 68 ++++++++++++++++++++++++++++ src/Patchage.cpp | 120 ++++++++++++++++++++++++++++++++++++++++--------- src/Patchage.hpp | 14 ++++-- src/PatchageEvent.cpp | 2 +- src/PatchageModule.cpp | 8 ++-- src/patchage.ui | 16 +++++-- 10 files changed, 259 insertions(+), 78 deletions(-) create mode 100644 src/Legend.hpp (limited to 'src') diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp index b4b43d7..78a0a16 100644 --- a/src/AlsaDriver.cpp +++ b/src/AlsaDriver.cpp @@ -163,7 +163,7 @@ AlsaDriver::refresh() PatchagePort* port2 = _app->canvas()->find_port(id2); if (port2 && !_app->canvas()->get_edge(port, port2)) { _app->canvas()->make_connection( - port, port2, port->get_fill_color() + 0x22222200); + port, port2, port->get_fill_color()); } } @@ -268,11 +268,11 @@ AlsaDriver::create_port_view_internal( bool split = false; if (is_duplex) { split = true; - if (!_app->configuration()->get_module_split(client_name, !is_application)) { - _app->configuration()->set_module_split(client_name, true); + if (!_app->conf()->get_module_split(client_name, !is_application)) { + _app->conf()->set_module_split(client_name, true); } } else { - split = _app->configuration()->get_module_split(client_name, !is_application); + split = _app->conf()->get_module_split(client_name, !is_application); } /*cout << "ALSA PORT: " << client_name << " : " << port_name @@ -312,7 +312,7 @@ AlsaDriver::create_port(PatchageModule& parent, { PatchagePort* ret = new PatchagePort( parent, ALSA_MIDI, name, is_input, - _app->configuration()->get_port_color(ALSA_MIDI)); + _app->conf()->get_port_color(ALSA_MIDI)); dynamic_cast(parent.canvas())->index_port( PortID(addr, is_input), ret); diff --git a/src/Configuration.cpp b/src/Configuration.cpp index ae621cb..78a66d8 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -26,11 +27,20 @@ #include "Configuration.hpp" #include "Patchage.hpp" +static const char* port_type_names[N_PORT_TYPES] = { + "JACK_AUDIO", + "JACK_MIDI", + "ALSA_MIDI" +}; + Configuration::Configuration() : _window_location(0, 0) , _window_size(640, 480) , _zoom(1.0) { + _port_colors[JACK_AUDIO] = _default_port_colors[JACK_AUDIO] = 0x244678FF; + _port_colors[JACK_MIDI] = _default_port_colors[JACK_MIDI] = 0x960909FF; + _port_colors[ALSA_MIDI] = _default_port_colors[ALSA_MIDI] = 0x4A8A0EFF; } bool @@ -166,6 +176,27 @@ Configuration::load() file >> _window_size.x >> _window_size.y; } else if (key == "zoom_level") { file >> _zoom; + } else if (key == "port_color") { + std::string type_name; + uint32_t rgba; + file >> type_name; + file.ignore(1, '#'); + file >> std::hex >> std::uppercase; + file >> rgba; + file >> std::dec >> std::nouppercase; + + bool found = false; + for (int i = 0; i < N_PORT_TYPES; ++i) { + if (type_name == port_type_names[i]) { + _port_colors[i] = rgba; + found = true; + break; + } + } + if (!found) { + std::cerr << "error: color for unknown port type `" + << type_name << "'" << std::endl; + } } else if (key == "module_position" || key[0] == '\"') { Coord loc; @@ -241,50 +272,28 @@ Configuration::save() file << "window_size " << _window_size.x << " " << _window_size.y << std::endl; file << "zoom_level " << _zoom << std::endl; + file << std::hex << std::uppercase; + for (int i = 0; i < N_PORT_TYPES; ++i) { + if (_port_colors[i] != _default_port_colors[i]) { + file << "port_color " << port_type_names[i] << " " << _port_colors[i] << std::endl; + } + } + file << std::dec << std::nouppercase; + for (std::map::iterator i = _module_settings.begin(); i != _module_settings.end(); ++i) { const ModuleSettings& settings = (*i).second; - const std::string& name = (*i).first; + const std::string& name = (*i).first; if (settings.split) { if (settings.input_location && settings.output_location) { write_module_position(file, name, "input", *settings.input_location); write_module_position(file, name, "output", *settings.output_location); } - } else { - if (settings.input_location && settings.inout_location) { - write_module_position(file, name, "inputoutput", *settings.inout_location); - } + } else if (settings.inout_location) { + write_module_position(file, name, "inputoutput", *settings.inout_location); } } file.close(); } - -float -Configuration::get_zoom() -{ - return _zoom; -} - -void -Configuration::set_zoom(float zoom) -{ - _zoom = zoom; -} - -int -Configuration::get_port_color(PortType type) -{ - // Darkest tango palette colour, with S -= 6, V -= 6, w/ transparency - - if (type == JACK_AUDIO) - return 0x244678FF; - else if (type == JACK_MIDI) - return 0x960909FF; - else if (type == ALSA_MIDI) - return 0x4A8A0EFF; - else - return 0xFF0000FF; -} - diff --git a/src/Configuration.hpp b/src/Configuration.hpp index b169c34..34b1595 100644 --- a/src/Configuration.hpp +++ b/src/Configuration.hpp @@ -17,6 +17,8 @@ #ifndef PATCHAGE_CONFIGURATION_HPP #define PATCHAGE_CONFIGURATION_HPP +#include + #include #include #include @@ -27,6 +29,8 @@ enum ModuleType { Input, Output, InputOutput }; enum PortType { JACK_AUDIO, JACK_MIDI, ALSA_MIDI }; +#define N_PORT_TYPES 3 + struct Coord { Coord(double x_=0, double y_=0) : x(x_), y(y_) {} double x; @@ -47,10 +51,13 @@ public: void set_module_split(const std::string& name, bool split); bool get_module_split(const std::string& name, bool default_val) const; - float get_zoom(); - void set_zoom(float zoom); + float get_zoom() { return _zoom; } + void set_zoom(float zoom) { _zoom = zoom; } - int get_port_color(PortType type); + uint32_t get_port_color(PortType type) const { return _port_colors[type]; } + void set_port_color(PortType type, uint32_t rgba) { + _port_colors[type] = rgba; + } Coord get_window_location() { return _window_location; } void set_window_location(Coord loc) { _window_location = loc; } @@ -68,6 +75,9 @@ private: std::map _module_settings; + uint32_t _default_port_colors[N_PORT_TYPES]; + uint32_t _port_colors[N_PORT_TYPES]; + Coord _window_location; Coord _window_size; float _zoom; diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp index 9638ace..8f80a56 100644 --- a/src/JackDriver.cpp +++ b/src/JackDriver.cpp @@ -147,7 +147,7 @@ JackDriver::create_port_view(Patchage* patchage, port_names(id, module_name, port_name); ModuleType type = InputOutput; - if (_app->configuration()->get_module_split( + if (_app->conf()->get_module_split( module_name, (jack_flags & JackPortIsTerminal))) { if (jack_flags & JackPortIsInput) { type = Input; @@ -194,7 +194,7 @@ JackDriver::create_port(PatchageModule& parent, jack_port_t* port, PortID id) PatchagePort* ret( new PatchagePort(parent, port_type, jack_port_short_name(port), (jack_port_flags(port) & JackPortIsInput), - _app->configuration()->get_port_color(port_type))); + _app->conf()->get_port_color(port_type))); if (id.type != PortID::NULL_PORT_ID) { dynamic_cast(parent.canvas())->index_port(id, ret); @@ -248,7 +248,7 @@ JackDriver::refresh() client1_name = client1_name.substr(0, client1_name.find(":")); ModuleType type = InputOutput; - if (_app->configuration()->get_module_split( + if (_app->conf()->get_module_split( client1_name, (jack_port_flags(port) & JackPortIsTerminal))) { if (jack_port_flags(port) & JackPortIsInput) { @@ -318,7 +318,7 @@ JackDriver::refresh() if (src && dst && !_app->canvas()->get_edge(src, dst)) _app->canvas()->make_connection( - src, dst, port1->get_fill_color() + 0x22222200); + src, dst, port1->get_fill_color()); } jack_free(connected_ports); diff --git a/src/Legend.hpp b/src/Legend.hpp new file mode 100644 index 0000000..4c8f57f --- /dev/null +++ b/src/Legend.hpp @@ -0,0 +1,68 @@ +/* This file is part of Patchage. + * Copyright 2014 David Robillard + * + * Patchage 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 3 of the License, or (at your option) + * any later version. + * + * Patchage 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 Patchage. If not, see . + */ + +#ifndef PATCHAGE_LEGEND_HPP +#define PATCHAGE_LEGEND_HPP + +#include +#include + +#include "Configuration.hpp" + +class Legend : public Gtk::HBox { +public: + Legend(const Configuration& configuration) { + add_button(JACK_AUDIO, "Audio", configuration.get_port_color(JACK_AUDIO)); + add_button(JACK_MIDI, "JACK MIDI", configuration.get_port_color(JACK_MIDI)); + add_button(ALSA_MIDI, "ALSA MIDI", configuration.get_port_color(ALSA_MIDI)); + show_all_children(); + } + + void add_button(int id, const std::string& label, uint32_t rgba) { + Gdk::Color col; + col.set_rgb(((rgba >> 24) & 0xFF) * 0x100, + ((rgba>> 16) & 0xFF) * 0x100, + ((rgba >> 8) & 0xFF) * 0x100); + Gtk::HBox* box = new Gtk::HBox(); + Gtk::ColorButton* but = new Gtk::ColorButton(col); + but->set_use_alpha(false); + but->signal_color_set().connect( + sigc::bind(sigc::mem_fun(this, &Legend::on_color_set), + id, label, but)); + + box->pack_end(*Gtk::manage(but)); + box->pack_end(*Gtk::manage(new Gtk::Label(label)), false, false, 2); + + this->pack_start(*Gtk::manage(box), false, false, 6); + } + + void on_color_set(const int id, + const std::string& label, + const Gtk::ColorButton* but) { + const Gdk::Color col = but->get_color(); + const uint32_t rgba = (((col.get_red() / 0x100) << 24) | + ((col.get_green() / 0x100) << 16) | + ((col.get_blue() / 0x100) << 8) | + 0xFF); + + signal_color_changed.emit(id, label, rgba); + } + + sigc::signal signal_color_changed; +}; + +#endif // PATCHAGE_LEGEND_HPP + diff --git a/src/Patchage.cpp b/src/Patchage.cpp index cb2bbda..10acaed 100644 --- a/src/Patchage.cpp +++ b/src/Patchage.cpp @@ -34,12 +34,13 @@ #include "ganv/Module.hpp" #include "ganv/Edge.hpp" -#include "patchage_config.h" -#include "UIFile.hpp" +#include "Configuration.hpp" +#include "Legend.hpp" #include "Patchage.hpp" #include "PatchageCanvas.hpp" #include "PatchageEvent.hpp" -#include "Configuration.hpp" +#include "UIFile.hpp" +#include "patchage_config.h" #if defined(HAVE_JACK_DBUS) #include "JackDbusDriver.hpp" @@ -82,10 +83,11 @@ Patchage::Patchage(int argc, char** argv) , _alsa_driver(NULL) #endif , _jack_driver(NULL) - , _configuration(NULL) + , _conf(NULL) , INIT_WIDGET(_about_win) , INIT_WIDGET(_main_scrolledwin) , INIT_WIDGET(_main_win) + , INIT_WIDGET(_main_vbox) , INIT_WIDGET(_menubar) , INIT_WIDGET(_menu_alsa_connect) , INIT_WIDGET(_menu_alsa_disconnect) @@ -99,6 +101,7 @@ Patchage::Patchage(int argc, char** argv) , INIT_WIDGET(_menu_save_close_session) , INIT_WIDGET(_menu_view_arrange) , INIT_WIDGET(_menu_view_messages) + , INIT_WIDGET(_menu_view_legend) , INIT_WIDGET(_menu_view_refresh) , INIT_WIDGET(_menu_zoom_in) , INIT_WIDGET(_menu_zoom_out) @@ -110,6 +113,7 @@ Patchage::Patchage(int argc, char** argv) , INIT_WIDGET(_messages_close_but) , INIT_WIDGET(_messages_win) , INIT_WIDGET(_status_text) + , _legend(NULL) , _attach(true) , _driver_detached(false) , _refresh(false) @@ -119,7 +123,7 @@ Patchage::Patchage(int argc, char** argv) , _alsa_driver_autoattach(true) #endif { - _configuration = new Configuration(); + _conf = new Configuration(); _canvas = boost::shared_ptr(new PatchageCanvas(this, 1600*2, 1200*2)); while (argc > 0) { @@ -189,6 +193,8 @@ Patchage::Patchage(int argc, char** argv) sigc::mem_fun(this, &Patchage::on_arrange)); _menu_view_messages->signal_activate().connect( sigc::mem_fun(this, &Patchage::on_show_messages)); + _menu_view_legend->signal_activate().connect( + sigc::mem_fun(this, &Patchage::on_view_legend)); _menu_help_about->signal_activate().connect( sigc::mem_fun(this, &Patchage::on_help_about)); _menu_zoom_in->signal_activate().connect( @@ -220,16 +226,21 @@ Patchage::Patchage(int argc, char** argv) _canvas->widget().show(); _main_win->present(); - _configuration->load(); + _conf->load(); _main_win->resize( - static_cast(_configuration->get_window_size().x), - static_cast(_configuration->get_window_size().y)); + static_cast(_conf->get_window_size().x), + static_cast(_conf->get_window_size().y)); _main_win->move( - static_cast(_configuration->get_window_location().x), - static_cast(_configuration->get_window_location().y)); - + static_cast(_conf->get_window_location().x), + static_cast(_conf->get_window_location().y)); + + _legend = new Legend(*_conf); + _legend->signal_color_changed.connect( + sigc::mem_fun(this, &Patchage::on_legend_color_change)); + _main_vbox->pack_end(*Gtk::manage(_legend), false, false); + _about_win->set_transient_for(*_main_win); #if defined(PATCHAGE_LIBJACK) || defined(HAVE_JACK_DBUS) @@ -272,7 +283,7 @@ Patchage::Patchage(int argc, char** argv) Patchage::~Patchage() { store_window_location(); - _configuration->save(); + _conf->save(); #if defined(PATCHAGE_LIBJACK) || defined(HAVE_JACK_DBUS) delete _jack_driver; @@ -281,7 +292,7 @@ Patchage::~Patchage() delete _alsa_driver; #endif - delete _configuration; + delete _conf; _about_win.destroy(); _messages_win.destroy(); @@ -355,7 +366,7 @@ Patchage::idle_callback() void Patchage::zoom(double z) { - _configuration->set_zoom(z); + _conf->set_zoom(z); _canvas->set_zoom(z); } @@ -389,8 +400,8 @@ Patchage::store_window_location() Coord window_size; window_size.x = size_x; window_size.y = size_y; - _configuration->set_window_location(window_location); - _configuration->set_window_size(window_size); + _conf->set_window_location(window_location); + _conf->set_window_size(window_size); } void @@ -422,10 +433,10 @@ static void load_module_location(GanvNode* node, void* data) { if (GANV_IS_MODULE(node)) { - Ganv::Module* cmodule = Glib::wrap(GANV_MODULE(node)); - PatchageModule* pmodule = dynamic_cast(cmodule); - if (pmodule) { - pmodule->load_location(); + Ganv::Module* gmod = Glib::wrap(GANV_MODULE(node)); + PatchageModule* pmod = dynamic_cast(gmod); + if (pmod) { + pmod->load_location(); } } } @@ -648,6 +659,65 @@ Patchage::on_normal_font_size() _canvas->set_font_size(_canvas->get_default_font_size()); } +static inline guint +highlight_color(guint c, guint delta) +{ + const guint max_char = 255; + const guint r = MIN((c >> 24) + delta, max_char); + const guint g = MIN(((c >> 16) & 0xFF) + delta, max_char); + const guint b = MIN(((c >> 8) & 0xFF) + delta, max_char); + const guint a = c & 0xFF; + + return ((((guint)(r)) << 24) | + (((guint)(g)) << 16) | + (((guint)(b)) << 8) | + (((guint)(a)))); +} + +static void +update_port_colors(GanvNode* node, void* data) +{ + Patchage* patchage = (Patchage*)data; + if (!GANV_IS_MODULE(node)) { + return; + } + + Ganv::Module* gmod = Glib::wrap(GANV_MODULE(node)); + PatchageModule* pmod = dynamic_cast(gmod); + if (!pmod) { + return; + } + + for (PatchageModule::iterator i = pmod->begin(); i != pmod->end(); ++i) { + PatchagePort* port = dynamic_cast(*i); + if (port) { + const uint32_t rgba = patchage->conf()->get_port_color(port->type()); + port->set_fill_color(rgba); + port->set_border_color(highlight_color(rgba, 0x20)); + } + } +} + +static void +update_edge_color(GanvEdge* edge, void* data) +{ + Patchage* patchage = (Patchage*)data; + Ganv::Edge* edgemm = Glib::wrap(edge); + + PatchagePort* tail = dynamic_cast((edgemm)->get_tail()); + if (tail) { + edgemm->set_color(patchage->conf()->get_port_color(tail->type())); + } +} + +void +Patchage::on_legend_color_change(int id, const std::string& label, uint32_t rgba) +{ + _conf->set_port_color((PortType)id, rgba); + _canvas->for_each_node(update_port_colors, this); + _canvas->for_each_edge(update_edge_color, this); +} + void Patchage::on_messages_clear() { @@ -710,6 +780,16 @@ Patchage::on_show_messages() _messages_win->present(); } +void +Patchage::on_view_legend() +{ + if (_menu_view_legend->get_active()) { + _legend->show(); + } else { + _legend->hide(); + } +} + bool Patchage::on_scroll(GdkEventScroll* ev) { diff --git a/src/Patchage.hpp b/src/Patchage.hpp index e78c511..c0b01f1 100644 --- a/src/Patchage.hpp +++ b/src/Patchage.hpp @@ -40,6 +40,7 @@ #include "patchage_config.h" #include "Widget.hpp" +#include "Legend.hpp" class AlsaDriver; class JackDriver; @@ -57,10 +58,10 @@ public: Gtk::Window* window() { return _main_win.get(); } - Configuration* configuration() const { return _configuration; } - JackDriver* jack_driver() const { return _jack_driver; } + Configuration* conf() const { return _conf; } + JackDriver* jack_driver() const { return _jack_driver; } #ifdef HAVE_ALSA - AlsaDriver* alsa_driver() const { return _alsa_driver; } + AlsaDriver* alsa_driver() const { return _alsa_driver; } #endif #ifdef PATCHAGE_JACK_SESSION void show_open_session_dialog(); @@ -94,6 +95,7 @@ protected: void on_quit(); void on_draw(); void on_show_messages(); + void on_view_legend(); void on_store_positions(); void on_zoom_in(); void on_zoom_out(); @@ -101,6 +103,7 @@ protected: void on_increase_font_size(); void on_decrease_font_size(); void on_normal_font_size(); + void on_legend_color_change(int id, const std::string& label, uint32_t rgba); bool on_scroll(GdkEventScroll* ev); @@ -125,13 +128,14 @@ protected: boost::shared_ptr _canvas; JackDriver* _jack_driver; - Configuration* _configuration; + Configuration* _conf; Gtk::Main* _gtk_main; Widget _about_win; Widget _main_scrolledwin; Widget _main_win; + Widget _main_vbox; Widget _menubar; Widget _menu_alsa_connect; Widget _menu_alsa_disconnect; @@ -145,6 +149,7 @@ protected: Widget _menu_save_close_session; Widget _menu_view_arrange; Widget _menu_view_messages; + Widget _menu_view_legend; Widget _menu_view_refresh; Widget _menu_zoom_in; Widget _menu_zoom_out; @@ -156,6 +161,7 @@ protected: Widget _messages_close_but; Widget _messages_win; Widget _status_text; + Legend* _legend; Glib::RefPtr _error_tag; Glib::RefPtr _warning_tag; diff --git a/src/PatchageEvent.cpp b/src/PatchageEvent.cpp index 895c071..a30ea57 100644 --- a/src/PatchageEvent.cpp +++ b/src/PatchageEvent.cpp @@ -92,7 +92,7 @@ PatchageEvent::execute(Patchage* patchage) % _port_2).str()); else patchage->canvas()->make_connection( - port_1, port_2, port_1->get_fill_color() + 0x22222200); + port_1, port_2, port_1->get_fill_color()); } else if (_type == DISCONNECTION) { diff --git a/src/PatchageModule.cpp b/src/PatchageModule.cpp index 0d2d77b..2cdc977 100644 --- a/src/PatchageModule.cpp +++ b/src/PatchageModule.cpp @@ -106,7 +106,7 @@ PatchageModule::load_location() { Coord loc; - if (_app->configuration()->get_module_location(_name, _type, loc)) + if (_app->conf()->get_module_location(_name, _type, loc)) move_to(loc.x, loc.y); else move_to(20 + rand() % 640, @@ -117,14 +117,14 @@ void PatchageModule::store_location(double x, double y) { Coord loc(get_x(), get_y()); - _app->configuration()->set_module_location(_name, _type, loc); + _app->conf()->set_module_location(_name, _type, loc); } void PatchageModule::split() { assert(_type == InputOutput); - _app->configuration()->set_module_split(_name, true); + _app->conf()->set_module_split(_name, true); _app->refresh(); } @@ -132,7 +132,7 @@ void PatchageModule::join() { assert(_type != InputOutput); - _app->configuration()->set_module_split(_name, false); + _app->conf()->set_module_split(_name, false); _app->refresh(); } diff --git a/src/patchage.ui b/src/patchage.ui index 2836109..347df40 100644 --- a/src/patchage.ui +++ b/src/patchage.ui @@ -8,7 +8,7 @@ main_win Patchage @PATCHAGE_VERSION@ - © 2005-2013 David Robillard + © 2005-2014 David Robillard © 2008 Nedko Arnaudov A JACK and ALSA front-end. http://drobilla.net/software/patchage @@ -888,6 +888,17 @@ Nedko Arnaudov <nedko@arnaudov.name> + + + False + True + False + _Legend... + True + False + + + True @@ -941,7 +952,6 @@ Nedko Arnaudov <nedko@arnaudov.name> True False True - True @@ -952,7 +962,6 @@ Nedko Arnaudov <nedko@arnaudov.name> True False True - True @@ -963,7 +972,6 @@ Nedko Arnaudov <nedko@arnaudov.name> True False True - True -- cgit v1.2.1