From dbe6899651ac929f59af160dd07aaf6bda079b23 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 27 Nov 2020 18:54:27 +0100 Subject: Factor out log from Patchage class Towards saner dependencies. --- src/AlsaDriver.cpp | 47 ++++++++++++++-------------- src/AlsaDriver.hpp | 4 ++- src/ILog.hpp | 41 +++++++++++++++++++++++++ src/JackDbusDriver.cpp | 7 +++-- src/JackDbusDriver.hpp | 6 ++-- src/JackDriver.cpp | 48 +++++++++++++++-------------- src/JackDriver.hpp | 8 +++-- src/Patchage.cpp | 67 ++++++---------------------------------- src/Patchage.hpp | 8 ++--- src/PatchageCanvas.cpp | 9 ++++-- src/PatchageEvent.cpp | 12 ++++---- src/TextViewLog.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/TextViewLog.hpp | 56 ++++++++++++++++++++++++++++++++++ 13 files changed, 270 insertions(+), 126 deletions(-) create mode 100644 src/ILog.hpp create mode 100644 src/TextViewLog.cpp create mode 100644 src/TextViewLog.hpp (limited to 'src') diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp index fc8fd34..a78c6ee 100644 --- a/src/AlsaDriver.cpp +++ b/src/AlsaDriver.cpp @@ -30,8 +30,9 @@ PATCHAGE_RESTORE_WARNINGS #include #include -AlsaDriver::AlsaDriver(Patchage* app) +AlsaDriver::AlsaDriver(Patchage* app, ILog& log) : _app(app) + , _log(log) , _seq(nullptr) , _refresh_thread{} {} @@ -47,10 +48,10 @@ AlsaDriver::attach(bool /*launch_daemon*/) { int ret = snd_seq_open(&_seq, "default", SND_SEQ_OPEN_DUPLEX, 0); if (ret) { - _app->error_msg("Alsa: Unable to attach."); + _log.error_msg("Alsa: Unable to attach."); _seq = nullptr; } else { - _app->info_msg("Alsa: Attached."); + _log.info_msg("Alsa: Attached."); snd_seq_set_client_name(_seq, "Patchage"); @@ -61,7 +62,7 @@ AlsaDriver::attach(bool /*launch_daemon*/) ret = pthread_create( &_refresh_thread, &attr, &AlsaDriver::refresh_main, this); if (ret) { - _app->error_msg("Alsa: Failed to start refresh thread."); + _log.error_msg("Alsa: Failed to start refresh thread."); } signal_attached.emit(); @@ -77,7 +78,7 @@ AlsaDriver::detach() snd_seq_close(_seq); _seq = nullptr; signal_detached.emit(); - _app->info_msg("Alsa: Detached."); + _log.info_msg("Alsa: Detached."); } } @@ -395,7 +396,7 @@ AlsaDriver::connect(PatchagePort* src_port, PatchagePort* dst_port) PortAddrs::const_iterator d = _port_addrs.find(dst_port); if (s == _port_addrs.end() || d == _port_addrs.end()) { - _app->error_msg("Alsa: Attempt to connect port with no address."); + _log.error_msg("Alsa: Attempt to connect port with no address."); return false; } @@ -404,7 +405,7 @@ AlsaDriver::connect(PatchagePort* src_port, PatchagePort* dst_port) if (src.id.alsa_addr.client == dst.id.alsa_addr.client && src.id.alsa_addr.port == dst.id.alsa_addr.port) { - _app->warning_msg("Alsa: Refusing to connect port to itself."); + _log.warning_msg("Alsa: Refusing to connect port to itself."); return false; } @@ -420,23 +421,23 @@ AlsaDriver::connect(PatchagePort* src_port, PatchagePort* dst_port) // Already connected (shouldn't happen) if (!snd_seq_get_port_subscription(_seq, subs)) { - _app->error_msg("Alsa: Attempt to double subscribe ports."); + _log.error_msg("Alsa: Attempt to double subscribe ports."); result = false; } int ret = snd_seq_subscribe_port(_seq, subs); if (ret < 0) { - _app->error_msg( + _log.error_msg( fmt::format("Alsa: Subscription failed ({}).", snd_strerror(ret))); result = false; } if (result) { - _app->info_msg(std::string("Alsa: Connected ") + src_port->full_name() + - " => " + dst_port->full_name()); + _log.info_msg(std::string("Alsa: Connected ") + src_port->full_name() + + " => " + dst_port->full_name()); } else { - _app->error_msg(std::string("Alsa: Unable to connect ") + - src_port->full_name() + " => " + dst_port->full_name()); + _log.error_msg(std::string("Alsa: Unable to connect ") + + src_port->full_name() + " => " + dst_port->full_name()); } return (!result); @@ -453,7 +454,7 @@ AlsaDriver::disconnect(PatchagePort* src_port, PatchagePort* dst_port) PortAddrs::const_iterator d = _port_addrs.find(dst_port); if (s == _port_addrs.end() || d == _port_addrs.end()) { - _app->error_msg("Alsa: Attempt to connect port with no address"); + _log.error_msg("Alsa: Attempt to connect port with no address"); return false; } @@ -470,21 +471,21 @@ AlsaDriver::disconnect(PatchagePort* src_port, PatchagePort* dst_port) // Not connected (shouldn't happen) if (snd_seq_get_port_subscription(_seq, subs) != 0) { - _app->error_msg( + _log.error_msg( "Alsa: Attempt to unsubscribe ports that are not subscribed."); return false; } int ret = snd_seq_unsubscribe_port(_seq, subs); if (ret < 0) { - _app->error_msg(std::string("Alsa: Unable to disconnect ") + - src_port->full_name() + " => " + dst_port->full_name() + - "(" + snd_strerror(ret) + ")"); + _log.error_msg(std::string("Alsa: Unable to disconnect ") + + src_port->full_name() + " => " + dst_port->full_name() + + "(" + snd_strerror(ret) + ")"); return false; } - _app->info_msg(std::string("Alsa: Disconnected ") + src_port->full_name() + - " => " + dst_port->full_name()); + _log.info_msg(std::string("Alsa: Disconnected ") + src_port->full_name() + + " => " + dst_port->full_name()); return true; } @@ -503,7 +504,7 @@ AlsaDriver::create_refresh_port() int ret = snd_seq_create_port(_seq, port_info); if (ret) { - _app->error_msg( + _log.error_msg( fmt::format("Alsa: Error creating port ({})", snd_strerror(ret))); return false; } @@ -514,7 +515,7 @@ AlsaDriver::create_refresh_port() SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE); if (ret) { - _app->error_msg( + _log.error_msg( fmt::format("Alsa: Failed to connect to system announce port ({})", snd_strerror(ret))); return false; @@ -535,7 +536,7 @@ void AlsaDriver::_refresh_main() { if (!create_refresh_port()) { - _app->error_msg( + _log.error_msg( "Alsa: Could not create listen port, auto-refresh disabled."); return; } diff --git a/src/AlsaDriver.hpp b/src/AlsaDriver.hpp index 2af3553..a953b7b 100644 --- a/src/AlsaDriver.hpp +++ b/src/AlsaDriver.hpp @@ -29,6 +29,7 @@ #include #include +class ILog; class Patchage; class PatchagePort; @@ -37,7 +38,7 @@ class PatchagePort; class AlsaDriver : public Driver { public: - explicit AlsaDriver(Patchage* app); + explicit AlsaDriver(Patchage* app, ILog& log); AlsaDriver(const AlsaDriver&) = delete; AlsaDriver& operator=(const AlsaDriver&) = delete; @@ -88,6 +89,7 @@ private: snd_seq_addr_t addr); Patchage* _app; + ILog& _log; snd_seq_t* _seq; pthread_t _refresh_thread; diff --git a/src/ILog.hpp b/src/ILog.hpp new file mode 100644 index 0000000..a71fda2 --- /dev/null +++ b/src/ILog.hpp @@ -0,0 +1,41 @@ +/* This file is part of Patchage. + * Copyright 2007-2020 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_ILOG_HPP +#define PATCHAGE_ILOG_HPP + +#include + +/// Interface for writing log messages +class ILog +{ +public: + ILog() = default; + + ILog(const ILog&) = default; + ILog& operator=(const ILog&) = default; + + ILog(ILog&&) = default; + ILog& operator=(ILog&&) = default; + + virtual ~ILog() = default; + + virtual void info_msg(const std::string& msg) = 0; + virtual void warning_msg(const std::string& msg) = 0; + virtual void error_msg(const std::string& msg) = 0; +}; + +#endif // PATCHAGE_ILOG_HPP diff --git a/src/JackDbusDriver.cpp b/src/JackDbusDriver.cpp index 7f9221b..8098410 100644 --- a/src/JackDbusDriver.cpp +++ b/src/JackDbusDriver.cpp @@ -54,8 +54,9 @@ PATCHAGE_RESTORE_WARNINGS //#define USE_FULL_REFRESH -JackDriver::JackDriver(Patchage* app) +JackDriver::JackDriver(Patchage* app, ILog& log) : _app(app) + , _log(log) , _dbus_error() , _dbus_connection(nullptr) , _max_dsp_load(0.0f) @@ -1190,11 +1191,11 @@ JackDriver::create_port_view(Patchage*, const PortID&) void JackDriver::error_msg(const std::string& msg) const { - _app->error_msg(std::string{"Jack: "} + msg); + _log.error_msg(std::string{"Jack: "} + msg); } void JackDriver::info_msg(const std::string& msg) const { - _app->info_msg(std::string{"Jack: "} + msg); + _log.info_msg(std::string{"Jack: "} + msg); } diff --git a/src/JackDbusDriver.hpp b/src/JackDbusDriver.hpp index aac7cd7..00c2a83 100644 --- a/src/JackDbusDriver.hpp +++ b/src/JackDbusDriver.hpp @@ -29,14 +29,15 @@ #include -class PatchageEvent; +class ILog; class PatchageCanvas; +class PatchageEvent; class PatchagePort; class JackDriver : public Driver { public: - explicit JackDriver(Patchage* app); + explicit JackDriver(Patchage* app, ILog& log); JackDriver(const JackDriver&) = delete; JackDriver& operator=(const JackDriver&) = delete; @@ -143,6 +144,7 @@ private: void on_jack_disappeared(); Patchage* _app; + ILog& _log; DBusError _dbus_error; DBusConnection* _dbus_connection; float _max_dsp_load; diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp index 29fedd8..8a44d93 100644 --- a/src/JackDriver.cpp +++ b/src/JackDriver.cpp @@ -16,6 +16,7 @@ #include "JackDriver.hpp" +#include "ILog.hpp" #include "Patchage.hpp" #include "PatchageCanvas.hpp" #include "PatchageEvent.hpp" @@ -40,8 +41,9 @@ PATCHAGE_RESTORE_WARNINGS #include #include -JackDriver::JackDriver(Patchage* app) +JackDriver::JackDriver(Patchage* app, ILog& log) : _app(app) + , _log(log) , _client(nullptr) , _events(128) , _last_pos{} @@ -73,7 +75,7 @@ JackDriver::attach(bool launch_daemon) (!launch_daemon) ? JackNoStartServer : JackNullOption; _client = jack_client_open("Patchage", options, nullptr); if (_client == nullptr) { - _app->error_msg("Jack: Unable to create client."); + _log.error_msg("Jack: Unable to create client."); _is_activated = false; } else { jack_client_t* const client = _client; @@ -92,9 +94,9 @@ JackDriver::attach(bool launch_daemon) _is_activated = true; signal_attached.emit(); std::stringstream ss; - _app->info_msg("Jack: Attached."); + _log.info_msg("Jack: Attached."); } else { - _app->error_msg("Jack: Client activation failed."); + _log.error_msg("Jack: Client activation failed."); _is_activated = false; } } @@ -112,7 +114,7 @@ JackDriver::detach() } _is_activated = false; signal_detached.emit(); - _app->info_msg("Jack: Detached."); + _log.info_msg("Jack: Detached."); } static bool @@ -141,8 +143,8 @@ JackDriver::create_port_view(Patchage* patchage, const PortID& id) jack_port_t* jack_port = jack_port_by_id(_client, id.id.jack_id); if (!jack_port) { - _app->error_msg(fmt::format("Jack: Failed to find port with ID `{}'.", - id.id.jack_id)); + _log.error_msg(fmt::format("Jack: Failed to find port with ID `{}'.", + id.id.jack_id)); return nullptr; } @@ -170,9 +172,9 @@ JackDriver::create_port_view(Patchage* patchage, const PortID& id) } if (parent->get_port(port_name)) { - _app->error_msg(fmt::format("Jack: Module `{}' already has port `{}'.", - module_name, - port_name)); + _log.error_msg(fmt::format("Jack: Module `{}' already has port `{}'.", + module_name, + port_name)); return nullptr; } @@ -243,9 +245,9 @@ JackDriver::create_port(PatchageModule& parent, } #endif } else { - _app->warning_msg(fmt::format("Jack: Port `{}' has unknown type `{}'.", - jack_port_name(port), - type_str)); + _log.warning_msg(fmt::format("Jack: Port `{}' has unknown type `{}'.", + jack_port_name(port), + type_str)); return nullptr; } @@ -436,11 +438,11 @@ JackDriver::connect(PatchagePort* src_port, PatchagePort* dst_port) _client, src_port->full_name().c_str(), dst_port->full_name().c_str()); if (result == 0) { - _app->info_msg(std::string("Jack: Connected ") + src_port->full_name() + - " => " + dst_port->full_name()); + _log.info_msg(std::string("Jack: Connected ") + src_port->full_name() + + " => " + dst_port->full_name()); } else { - _app->error_msg(std::string("Jack: Unable to connect ") + - src_port->full_name() + " => " + dst_port->full_name()); + _log.error_msg(std::string("Jack: Unable to connect ") + + src_port->full_name() + " => " + dst_port->full_name()); } return (!result); @@ -462,11 +464,11 @@ JackDriver::disconnect(PatchagePort* const src_port, _client, src_port->full_name().c_str(), dst_port->full_name().c_str()); if (result == 0) { - _app->info_msg(std::string("Jack: Disconnected ") + - src_port->full_name() + " => " + dst_port->full_name()); + _log.info_msg(std::string("Jack: Disconnected ") + + src_port->full_name() + " => " + dst_port->full_name()); } else { - _app->error_msg(std::string("Jack: Unable to disconnect ") + - src_port->full_name() + " => " + dst_port->full_name()); + _log.error_msg(std::string("Jack: Unable to disconnect ") + + src_port->full_name() + " => " + dst_port->full_name()); } return (!result); @@ -543,7 +545,7 @@ JackDriver::jack_shutdown_cb(void* jack_driver) { assert(jack_driver); auto* me = static_cast(jack_driver); - me->_app->info_msg("Jack: Shutdown."); + me->_log.info_msg("Jack: Shutdown."); std::lock_guard lock{me->_shutdown_mutex}; @@ -610,7 +612,7 @@ JackDriver::set_buffer_size(jack_nframes_t size) } if (jack_set_buffer_size(_client, size)) { - _app->error_msg("[JACK] Unable to set buffer size"); + _log.error_msg("[JACK] Unable to set buffer size"); return false; } diff --git a/src/JackDriver.hpp b/src/JackDriver.hpp index 442ce74..0875703 100644 --- a/src/JackDriver.hpp +++ b/src/JackDriver.hpp @@ -26,11 +26,12 @@ #include #include +class ILog; class Patchage; -class PatchageEvent; class PatchageCanvas; -class PatchagePort; +class PatchageEvent; class PatchageModule; +class PatchagePort; /** Handles all externally driven functionality, registering ports etc. * @@ -40,7 +41,7 @@ class PatchageModule; class JackDriver : public Driver { public: - explicit JackDriver(Patchage* app); + explicit JackDriver(Patchage* app, ILog& log); JackDriver(const JackDriver&) = delete; JackDriver& operator=(const JackDriver&) = delete; @@ -108,6 +109,7 @@ private: static void jack_shutdown_cb(void* jack_driver); Patchage* _app; + ILog& _log; jack_client_t* _client; Queue _events; diff --git a/src/Patchage.cpp b/src/Patchage.cpp index 6a40c20..7fbc434 100644 --- a/src/Patchage.cpp +++ b/src/Patchage.cpp @@ -167,6 +167,7 @@ Patchage::Patchage(int argc, char** argv) , INIT_WIDGET(_log_scrolledwindow) , INIT_WIDGET(_status_text) , _legend(nullptr) + , _log(_status_text) , _pane_initialized(false) , _attach(true) , _driver_detached(false) @@ -302,21 +303,6 @@ Patchage::Patchage(int argc, char** argv) _menu_view_sprung_layout->set_sensitive(false); } - for (int s = Gtk::STATE_NORMAL; s <= Gtk::STATE_INSENSITIVE; ++s) { - _status_text->modify_base(static_cast(s), - Gdk::Color("#000000")); - _status_text->modify_text(static_cast(s), - Gdk::Color("#FFFFFF")); - } - - _error_tag = Gtk::TextTag::create(); - _error_tag->property_foreground() = "#CC0000"; - _status_text->get_buffer()->get_tag_table()->add(_error_tag); - - _warning_tag = Gtk::TextTag::create(); - _warning_tag->property_foreground() = "#C4A000"; - _status_text->get_buffer()->get_tag_table()->add(_warning_tag); - _canvas->widget().show(); _main_win->present(); @@ -346,12 +332,12 @@ Patchage::Patchage(int argc, char** argv) _about_win->set_logo(Gdk::Pixbuf::create_from_file( bundle_location() + "/Resources/Patchage.icns")); } catch (const Glib::Exception& e) { - error_msg(fmt::format("failed to set logo ({})", e.what())); + _log.error_msg(fmt::format("failed to set logo ({})", e.what())); } #endif #if defined(PATCHAGE_LIBJACK) || defined(HAVE_JACK_DBUS) - _jack_driver = new JackDriver(this); + _jack_driver = new JackDriver(this, _log); _jack_driver->signal_detached.connect( sigc::mem_fun(this, &Patchage::driver_detached)); @@ -362,7 +348,7 @@ Patchage::Patchage(int argc, char** argv) #endif #ifdef HAVE_ALSA - _alsa_driver = new AlsaDriver(this); + _alsa_driver = new AlsaDriver(this, _log); #endif connect_widgets(); @@ -370,10 +356,6 @@ Patchage::Patchage(int argc, char** argv) _menu_view_toolbar->set_active(_conf->get_show_toolbar()); _menu_view_sprung_layout->set_active(_conf->get_sprung_layout()); _menu_view_sort_ports->set_active(_conf->get_sort_ports()); - _status_text->set_pixels_inside_wrap(2); - _status_text->set_left_margin(4); - _status_text->set_right_margin(4); - _status_text->set_pixels_below_lines(2); g_signal_connect( _main_win->gobj(), "configure-event", G_CALLBACK(configure_cb), this); @@ -594,32 +576,6 @@ Patchage::clear_load() #endif } -void -Patchage::error_msg(const std::string& msg) -{ - Glib::RefPtr buffer = _status_text->get_buffer(); - buffer->insert_with_tag(buffer->end(), std::string("\n") + msg, _error_tag); - _status_text->scroll_to_mark(buffer->get_insert(), 0); - _menu_view_messages->set_active(true); -} - -void -Patchage::info_msg(const std::string& msg) -{ - Glib::RefPtr buffer = _status_text->get_buffer(); - buffer->insert(buffer->end(), std::string("\n") + msg); - _status_text->scroll_to_mark(buffer->get_insert(), 0); -} - -void -Patchage::warning_msg(const std::string& msg) -{ - Glib::RefPtr buffer = _status_text->get_buffer(); - buffer->insert_with_tag( - buffer->end(), std::string("\n") + msg, _warning_tag); - _status_text->scroll_to_mark(buffer->get_insert(), 0); -} - static void load_module_location(GanvNode* node, void*) { @@ -698,14 +654,14 @@ Patchage::show_open_session_dialog() const std::string dir = dialog.get_filename(); if (g_chdir(dir.c_str())) { - error_msg("Failed to switch to session directory " + dir); + _log.error_msg("Failed to switch to session directory " + dir); return; } if (system("./jack-session") < 0) { - error_msg("Error executing `./jack-session' in " + dir); + _log.error_msg("Error executing `./jack-session' in " + dir); } else { - info_msg("Loaded session " + dir); + _log.info_msg("Loaded session " + dir); } } @@ -743,7 +699,7 @@ Patchage::save_session(bool close) std::string path = dialog.get_filename(); if (g_mkdir_with_parents(path.c_str(), 0740)) { - error_msg("Failed to create session directory " + path); + _log.error_msg("Failed to create session directory " + path); return; } @@ -1056,13 +1012,8 @@ Patchage::on_view_messages() if (_menu_view_messages->get_active()) { Glib::RefPtr buffer = _status_text->get_buffer(); if (!_pane_initialized) { - int y = 0; - int line_height = 0; - _status_text->get_line_yrange(buffer->begin(), y, line_height); - - const int pad = _status_text->get_pixels_inside_wrap(); + const int min_height = _log.min_height(); const int max_pos = _main_paned->get_allocation().get_height(); - const int min_height = (line_height + 2 * pad); const int conf_height = _conf->get_messages_height(); _main_paned->set_position(max_pos - std::max(conf_height, min_height)); diff --git a/src/Patchage.hpp b/src/Patchage.hpp index 98537a1..e453b68 100644 --- a/src/Patchage.hpp +++ b/src/Patchage.hpp @@ -38,7 +38,9 @@ #include #include +#include "ILog.hpp" #include "Legend.hpp" +#include "TextViewLog.hpp" #include "Widget.hpp" #include "patchage_config.h" @@ -70,6 +72,7 @@ public: const std::shared_ptr& canvas() const { return _canvas; } Gtk::Window* window() { return _main_win.get(); } + ILog& log() { return _log; } Configuration* conf() const { return _conf; } JackDriver* jack_driver() const { return _jack_driver; } @@ -92,10 +95,6 @@ public: inline void queue_refresh() { _refresh = true; } inline void driver_detached() { _driver_detached = true; } - void info_msg(const std::string& msg); - void error_msg(const std::string& msg); - void warning_msg(const std::string& msg); - void update_state(); void store_window_location(); @@ -210,6 +209,7 @@ protected: Widget _log_scrolledwindow; Widget _status_text; Legend* _legend; + TextViewLog _log; Glib::RefPtr _error_tag; Glib::RefPtr _warning_tag; diff --git a/src/PatchageCanvas.cpp b/src/PatchageCanvas.cpp index b6a592f..13eb0f4 100644 --- a/src/PatchageCanvas.cpp +++ b/src/PatchageCanvas.cpp @@ -246,7 +246,8 @@ PatchageCanvas::connect(Ganv::Node* port1, Ganv::Node* port2) _app->alsa_driver()->connect(p1, p2); #endif } else { - _app->warning_msg("Cannot make connection, incompatible port types."); + _app->log().warning_msg( + "Cannot make connection, incompatible port types."); } } @@ -267,7 +268,8 @@ PatchageCanvas::disconnect(Ganv::Node* port1, Ganv::Node* port2) } if (!input || !output || input->is_output() || output->is_input()) { - _app->error_msg("Attempt to disconnect mismatched/unknown ports."); + _app->log().error_msg( + "Attempt to disconnect mismatched/unknown ports."); return; } @@ -283,7 +285,8 @@ PatchageCanvas::disconnect(Ganv::Node* port1, Ganv::Node* port2) _app->alsa_driver()->disconnect(output, input); #endif } else { - _app->error_msg("Attempt to disconnect ports with strange types."); + _app->log().error_msg( + "Attempt to disconnect ports with strange types."); } } diff --git a/src/PatchageEvent.cpp b/src/PatchageEvent.cpp index 4df2924..0f5645a 100644 --- a/src/PatchageEvent.cpp +++ b/src/PatchageEvent.cpp @@ -69,11 +69,11 @@ PatchageEvent::execute(Patchage* patchage) if (driver) { PatchagePort* port = driver->create_port_view(patchage, _port_1); if (!port) { - patchage->error_msg(fmt::format( + patchage->log().error_msg(fmt::format( "Unable to create view for port `{}'", _port_1)); } } else { - patchage->error_msg( + patchage->log().error_msg( fmt::format("Unknown type for port `{}'", _port_1)); } @@ -87,10 +87,10 @@ PatchageEvent::execute(Patchage* patchage) PatchagePort* port_2 = patchage->canvas()->find_port(_port_2); if (!port_1) { - patchage->error_msg( + patchage->log().error_msg( fmt::format("Unable to find port `{}' to connect", _port_1)); } else if (!port_2) { - patchage->error_msg( + patchage->log().error_msg( fmt::format("Unable to find port `{}' to connect", _port_2)); } else { patchage->canvas()->make_connection(port_1, port_2); @@ -102,10 +102,10 @@ PatchageEvent::execute(Patchage* patchage) PatchagePort* port_2 = patchage->canvas()->find_port(_port_2); if (!port_1) { - patchage->error_msg( + patchage->log().error_msg( fmt::format("Unable to find port `{}' to disconnect", _port_1)); } else if (!port_2) { - patchage->error_msg( + patchage->log().error_msg( fmt::format("Unable to find port `{}' to disconnect", _port_2)); } else { patchage->canvas()->remove_edge_between(port_1, port_2); diff --git a/src/TextViewLog.cpp b/src/TextViewLog.cpp new file mode 100644 index 0000000..b5e7a59 --- /dev/null +++ b/src/TextViewLog.cpp @@ -0,0 +1,83 @@ +/* This file is part of Patchage. + * Copyright 2007-2020 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 . + */ + +#include "TextViewLog.hpp" + +#include +#include + +#include + +TextViewLog::TextViewLog(Widget& text_view) + : _error_tag{Gtk::TextTag::create()} + , _warning_tag{Gtk::TextTag::create()} + , _text_view{text_view} +{ + for (int s = Gtk::STATE_NORMAL; s <= Gtk::STATE_INSENSITIVE; ++s) { + _text_view->modify_base(static_cast(s), + Gdk::Color("#000000")); + _text_view->modify_text(static_cast(s), + Gdk::Color("#FFFFFF")); + } + + _error_tag->property_foreground() = "#CC0000"; + _text_view->get_buffer()->get_tag_table()->add(_error_tag); + + _warning_tag->property_foreground() = "#C4A000"; + _text_view->get_buffer()->get_tag_table()->add(_warning_tag); + + _text_view->set_pixels_inside_wrap(2); + _text_view->set_left_margin(4); + _text_view->set_right_margin(4); + _text_view->set_pixels_below_lines(2); +} + +void +TextViewLog::info_msg(const std::string& msg) +{ + Glib::RefPtr buffer = _text_view->get_buffer(); + buffer->insert(buffer->end(), std::string("\n") + msg); + _text_view->scroll_to_mark(buffer->get_insert(), 0); +} + +void +TextViewLog::warning_msg(const std::string& msg) +{ + Glib::RefPtr buffer = _text_view->get_buffer(); + buffer->insert_with_tag( + buffer->end(), std::string("\n") + msg, _warning_tag); + _text_view->scroll_to_mark(buffer->get_insert(), 0); +} + +void +TextViewLog::error_msg(const std::string& msg) +{ + Glib::RefPtr buffer = _text_view->get_buffer(); + buffer->insert_with_tag(buffer->end(), std::string("\n") + msg, _error_tag); + _text_view->scroll_to_mark(buffer->get_insert(), 0); +} + +int +TextViewLog::min_height() const +{ + Glib::RefPtr buffer = _text_view->get_buffer(); + + int y = 0; + int line_height = 0; + _text_view->get_line_yrange(buffer->begin(), y, line_height); + + return line_height + 2 * _text_view->get_pixels_inside_wrap(); +} diff --git a/src/TextViewLog.hpp b/src/TextViewLog.hpp new file mode 100644 index 0000000..eb44407 --- /dev/null +++ b/src/TextViewLog.hpp @@ -0,0 +1,56 @@ +/* This file is part of Patchage. + * Copyright 2007-2020 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_TEXTVIEWLOG_HPP +#define PATCHAGE_TEXTVIEWLOG_HPP + +#include "ILog.hpp" +#include "Widget.hpp" + +#include +#include +#include + +/// Log that writes colored messages to a Gtk TextView +class TextViewLog : public ILog +{ +public: + explicit TextViewLog(Widget& text_view); + + TextViewLog(const TextViewLog&) = delete; + TextViewLog& operator=(const TextViewLog&) = delete; + + TextViewLog(TextViewLog&&) = delete; + TextViewLog& operator=(TextViewLog&&) = delete; + + ~TextViewLog() override = default; + + void info_msg(const std::string& msg) override; + void error_msg(const std::string& msg) override; + void warning_msg(const std::string& msg) override; + + int min_height() const; + + const Widget& text_view() const { return _text_view; } + Widget& text_view() { return _text_view; } + +private: + Glib::RefPtr _error_tag; + Glib::RefPtr _warning_tag; + Widget& _text_view; +}; + +#endif // PATCHAGE_TEXTVIEWLOG_HPP -- cgit v1.2.1