diff options
author | David Robillard <d@drobilla.net> | 2006-06-10 02:43:54 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2006-06-10 02:43:54 +0000 |
commit | 47246db7e9d71ba694b719001033fba1766a58c4 (patch) | |
tree | 25614ea4f2c92033a3cd37f6413df742f09a5369 /src/progs/gtk | |
parent | 98fe0e7056e6697396249531785d3899f94d79be (diff) | |
download | ingen-47246db7e9d71ba694b719001033fba1766a58c4.tar.gz ingen-47246db7e9d71ba694b719001033fba1766a58c4.tar.bz2 ingen-47246db7e9d71ba694b719001033fba1766a58c4.zip |
More juggling
git-svn-id: http://svn.drobilla.net/lad/grauph@16 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/progs/gtk')
82 files changed, 17500 insertions, 0 deletions
diff --git a/src/progs/gtk/App.cpp b/src/progs/gtk/App.cpp new file mode 100644 index 00000000..6b71b4ec --- /dev/null +++ b/src/progs/gtk/App.cpp @@ -0,0 +1,230 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "App.h" +#include <cassert> +#include <string> +#include <fstream> +#include <libgnomecanvasmm.h> +#include <time.h> +#include <sys/time.h> +#include "ControlInterface.h" +#include "PatchView.h" +#include "OmModule.h" +#include "ControlPanel.h" +#include "SubpatchModule.h" +#include "OmFlowCanvas.h" +#include "GtkObjectController.h" +#include "PatchController.h" +#include "NodeController.h" +#include "PortController.h" +#include "LoadPluginWindow.h" +#include "PatchWindow.h" +#include "MessagesWindow.h" +#include "ConfigWindow.h" +#include "Controller.h" +#include "GladeFactory.h" +#include "util/Path.h" +#include "ObjectModel.h" +#include "PatchModel.h" +#include "PatchTreeWindow.h" +#include "Configuration.h" +#include "ConnectWindow.h" +#ifdef HAVE_LASH +#include "LashController.h" +#endif +using std::cerr; using std::cout; using std::endl; +using std::string; +namespace LibOmClient { class PluginModel; } +using namespace LibOmClient; + +namespace OmGtk { + +class OmPort; + +App::App() +: m_control_interface(new ControlInterface(this)), + m_configuration(new Configuration()), + m_about_dialog(NULL), + m_enable_signal(true) +{ + Glib::RefPtr<Gnome::Glade::Xml> glade_xml = GladeFactory::new_glade_reference(); + + glade_xml->get_widget_derived("connect_win", m_connect_window); + //glade_xml->get_widget_derived("new_patch_win", m_new_patch_window); + //glade_xml->get_widget_derived("load_patch_win", m_load_patch_window); + glade_xml->get_widget_derived("config_win", m_config_window); + glade_xml->get_widget_derived("patch_tree_win", m_patch_tree_window); +// glade_xml->get_widget_derived("main_patches_treeview", m_objects_treeview); + glade_xml->get_widget("about_win", m_about_dialog); + + m_config_window->configuration(m_configuration); + + glade_xml->get_widget_derived("messages_win", m_messages_window); +} + + +App::~App() +{ + delete m_control_interface; +} + + +void +App::error_message(const string& str) +{ + m_messages_window->post(str); + m_messages_window->show(); + m_messages_window->raise(); +} + + +/* +bool +App::idle_callback() +{ + m_client_hooks->process_events(); + +#ifdef HAVE_LASH + //if (lash_controller->enabled()) + // lash_controller->process_events(); +#endif + + return true; +} +*/ + + +/******** Event Handlers ************/ + + +#if 0 +App::event_load_session() +{ + Gtk::FileChooserDialog* dialog + = new Gtk::FileChooserDialog(*m_main_window, "Load Session", Gtk::FILE_CHOOSER_ACTION_OPEN); + + dialog->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog->add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); + int result = dialog->run(); + string filename = dialog->get_filename(); + delete dialog; + + cout << result << endl; + + assert(result == Gtk::RESPONSE_OK || result == Gtk::RESPONSE_CANCEL || result == Gtk::RESPONSE_NONE); + + if (result == Gtk::RESPONSE_OK) + //configuration->load_session(filename); + _controller->load_session(filename); +} + + +void +App::event_save_session_as() +{ + Gtk::FileChooserDialog dialog(*m_main_window, "Save Session", Gtk::FILE_CHOOSER_ACTION_SAVE); + + /* + Gtk::VBox* box = dialog.get_vbox(); + Gtk::Label warning("Warning: Recursively saving will overwrite any subpatch files \ + without confirmation."); + box->pack_start(warning, false, false, 2); + Gtk::CheckButton recursive_checkbutton("Recursively save all subpatches"); + box->pack_start(recursive_checkbutton, false, false, 0); + recursive_checkbutton.show(); + */ + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + + int result = dialog.run(); + //bool recursive = recursive_checkbutton.get_active(); + + assert(result == Gtk::RESPONSE_OK || result == Gtk::RESPONSE_CANCEL || result == Gtk::RESPONSE_NONE); + + if (result == Gtk::RESPONSE_OK) { + string filename = dialog.get_filename(); + if (filename.length() < 11 || filename.substr(filename.length()-10) != ".omsession") + filename += ".omsession"; + + bool confirm = false; + std::fstream fin; + fin.open(filename.c_str(), std::ios::in); + if (fin.is_open()) { // File exists + string msg = "File already exists! Are you sure you want to overwrite "; + msg += filename + "?"; + Gtk::MessageDialog confirm_dialog(*m_main_window, + msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); + if (confirm_dialog.run() == Gtk::RESPONSE_YES) + confirm = true; + else + confirm = false; + } else { // File doesn't exist + confirm = true; + } + fin.close(); + + if (confirm) { + _controller->save_session(filename); + } + } +} +#endif + +void +App::add_patch_window(PatchWindow* pw) +{ + m_windows.push_back(pw); +} + + +void +App::remove_patch_window(PatchWindow* pw) +{ + m_windows.erase(find(m_windows.begin(), m_windows.end(), pw)); +} + + +/** Returns the number of Patch windows currently visible. + */ +int +App::num_open_patch_windows() +{ + int ret = 0; + for (list<PatchWindow*>::iterator i = m_windows.begin(); i != m_windows.end(); ++i) + if ((*i)->is_visible()) + ++ret; + + return ret; +} + +void +App::quit() +{ + Gtk::Main::quit(); +} + +void +App::quit_and_kill() +{ + Controller::instance().quit(); + Gtk::Main::quit(); +} + + +} // namespace OmGtk + diff --git a/src/progs/gtk/App.h b/src/progs/gtk/App.h new file mode 100644 index 00000000..1ba18962 --- /dev/null +++ b/src/progs/gtk/App.h @@ -0,0 +1,123 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OMGTKAPP_H +#define OMGTKAPP_H + +#include <cassert> +#include <string> +#include <map> +#include <list> +#include <iostream> +#include <libgnomecanvasmm.h> +#include <gtkmm.h> +#include <libglademm.h> +using std::string; using std::map; using std::list; +using std::cerr; using std::endl; + +namespace LibOmClient { class PatchModel; class PluginModel; } +using namespace LibOmClient; + +/** \defgroup OmGtk GTK Client + */ + +namespace OmGtk { + +class PatchWindow; +class GtkObjectController; +class PatchController; +class NodeController; +class PortController; +class LoadPatchWindow; +class MessagesWindow; +class ConfigWindow; +class OmGtkObject; +class OmModule; +class OmPort; +class OmFlowCanvas; +class PatchTreeView; +class PatchTreeWindow; +class ControlInterface; +class ConnectWindow; +class Configuration; + + +/** Singleton master class most everything is contained within. + * + * This is a horrible god-object, but it's shrinking in size as things are + * moved out. Hopefully it will go away entirely some day.. + * + * \ingroup OmGtk + */ +class App +{ +public: + ~App(); + + void error_message(const string& msg); + + void quit(); + void quit_and_kill(); + + void add_patch_window(PatchWindow* pw); + void remove_patch_window(PatchWindow* pw); + + int num_open_patch_windows(); + + ConnectWindow* connect_window() const { return m_connect_window; } + Gtk::Dialog* about_dialog() const { return m_about_dialog; } + ConfigWindow* configuration_dialog() const { return m_config_window; } + MessagesWindow* messages_dialog() const { return m_messages_window; } + PatchTreeWindow* patch_tree() const { return m_patch_tree_window; } + Configuration* configuration() const { return m_configuration; } + + ControlInterface* control_interface() { return m_control_interface; } + + static void instantiate() { if (!_instance) _instance = new App(); } + static inline App& instance() { assert(_instance); return *_instance; } + +protected: + App(); + static App* _instance; + + //bool connect_callback(); + //bool idle_callback(); + + ControlInterface* m_control_interface; + Configuration* m_configuration; + + list<PatchWindow*> m_windows; + + ConnectWindow* m_connect_window; + MessagesWindow* m_messages_window; + PatchTreeWindow* m_patch_tree_window; + ConfigWindow* m_config_window; + Gtk::Dialog* m_about_dialog; + Gtk::Button* m_engine_error_close_button; + + /** Used to avoid feedback loops with (eg) process checkbutton + * FIXME: Maybe this should be globally implemented at the Controller level, + * disable all command sending while handling events to avoid feedback + * issues with widget event callbacks? This same pattern is duplicated + * too much... */ + bool m_enable_signal; +}; + + +} // namespace OmGtk + +#endif // OMGTKAPP_H + diff --git a/src/progs/gtk/BreadCrumb.h b/src/progs/gtk/BreadCrumb.h new file mode 100644 index 00000000..f79ad363 --- /dev/null +++ b/src/progs/gtk/BreadCrumb.h @@ -0,0 +1,66 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef BREADCRUMB_H +#define BREADCRUMB_H + +#include <gtkmm.h> +#include "PatchWindow.h" +#include "PatchController.h" +#include "PatchModel.h" + +namespace OmGtk { + + +/** Breadcrumb button in a PatchWindow. + * + * \ingroup OmGtk + */ +class BreadCrumb : public Gtk::ToggleButton +{ +public: + BreadCrumb(PatchWindow* window, PatchController* patch) + : m_window(window), + m_patch(patch) + { + assert(patch != NULL); + set_border_width(0); + path(m_patch->path()); + signal_clicked().connect(sigc::bind(sigc::mem_fun( + m_window, &PatchWindow::breadcrumb_clicked), this)); + show_all(); + } + + PatchController* patch() { return m_patch; } + + void path(const Path& path) + { + remove(); + const string text = (path == "/") ? "/" : path.name(); + Gtk::Label* lab = manage(new Gtk::Label(text)); + lab->set_padding(0, 0); + lab->show(); + add(*lab); + } + +private: + PatchWindow* m_window; + PatchController* m_patch; +}; + +} // namespace OmGtk + +#endif // BREADCRUMB_H diff --git a/src/progs/gtk/ConfigWindow.cpp b/src/progs/gtk/ConfigWindow.cpp new file mode 100644 index 00000000..db3bce18 --- /dev/null +++ b/src/progs/gtk/ConfigWindow.cpp @@ -0,0 +1,86 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ConfigWindow.h" +#include <iostream> +#include <cassert> +#include <algorithm> +#include <cctype> +#include "PatchController.h" +#include "NodeModel.h" +#include "OmFlowCanvas.h" +using std::cout; using std::cerr; using std::endl; + + +namespace OmGtk { + +ConfigWindow::ConfigWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml) +: Gtk::Window(cobject), + m_configuration(NULL) +{ + xml->get_widget("config_path_entry", m_path_entry); + xml->get_widget("config_save_button", m_save_button); + xml->get_widget("config_cancel_button", m_cancel_button); + xml->get_widget("config_ok_button", m_ok_button); + + m_save_button->signal_clicked().connect( sigc::mem_fun(this, &ConfigWindow::save_clicked)); + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &ConfigWindow::cancel_clicked)); + m_ok_button->signal_clicked().connect( sigc::mem_fun(this, &ConfigWindow::ok_clicked)); +} + + +/** Sets the state manager for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +ConfigWindow::configuration(Configuration* sm) +{ + m_configuration = sm; + m_path_entry->set_text(sm->patch_path()); +} + + + +///// Event Handlers ////// + + +void +ConfigWindow::save_clicked() +{ + m_configuration->patch_path(m_path_entry->get_text()); + m_configuration->apply_settings(); + m_configuration->save_settings(); +} + + +void +ConfigWindow::cancel_clicked() +{ + hide(); +} + + +void +ConfigWindow::ok_clicked() +{ + m_configuration->patch_path(m_path_entry->get_text()); + m_configuration->apply_settings(); + hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/ConfigWindow.h b/src/progs/gtk/ConfigWindow.h new file mode 100644 index 00000000..caf1531f --- /dev/null +++ b/src/progs/gtk/ConfigWindow.h @@ -0,0 +1,63 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef CONFIGWINDOW_H +#define CONFIGWINDOW_H + +#include "PluginModel.h" +#include "Configuration.h" +#include <list> +#include <libglademm/xml.h> +#include <libglademm.h> +#include <gtkmm.h> + +using std::list; +using LibOmClient::PluginModel; + +namespace OmGtk { + + +/** 'Configuration' window. + * + * Loaded by glade as a derived object. + * + * \ingroup OmGtk + */ +class ConfigWindow : public Gtk::Window +{ +public: + ConfigWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml); + + void configuration(Configuration* sm); + +private: + void save_clicked(); + void cancel_clicked(); + void ok_clicked(); + + Configuration* m_configuration; + + Gtk::Entry* m_path_entry; + Gtk::Button* m_save_button; + Gtk::Button* m_cancel_button; + Gtk::Button* m_ok_button; +}; + + +} // namespace OmGtk + +#endif // CONFIGWINDOW_H diff --git a/src/progs/gtk/Configuration.cpp b/src/progs/gtk/Configuration.cpp new file mode 100644 index 00000000..e4882cc3 --- /dev/null +++ b/src/progs/gtk/Configuration.cpp @@ -0,0 +1,184 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Configuration.h" +#include <cstdlib> +#include <cassert> +#include <iostream> +#include <fstream> +#include <map> +#include "PortModel.h" +#include "PluginModel.h" +#include "PatchController.h" +#include "PatchModel.h" +#include "OmFlowCanvas.h" +#include "Controller.h" + +using std::cerr; using std::cout; using std::endl; +using std::map; using std::string; +using LibOmClient::PatchModel; + +namespace OmGtk { + +using namespace LibOmClient; + + +Configuration::Configuration() +: m_patch_path("/usr/share/om/patches:/usr/local/share/om/patches"), + m_audio_port_color( 0x394f66FF), + m_control_port_color(0x396639FF), + m_midi_port_color( 0x663939FF) +{ +} + + +Configuration::~Configuration() +{ +} + + +/** Loads settings from the rc file. Passing no parameter will load from + * the default location. + */ +void +Configuration::load_settings(string filename) +{ + if (filename == "") + filename = string(getenv("HOME")).append("/.omgtkrc"); + + std::ifstream is; + is.open(filename.c_str(), std::ios::in); + + if ( ! is.good()) { + cout << "[Configuration] Unable to open settings file " << filename << endl; + return; + } else { + cout << "[Configuration] Loading settings from " << filename << endl; + } + + string s; + + is >> s; + if (s != "file_version") { + cerr << "[Configuration] Corrupt settings file, load aborted." << endl; + is.close(); + return; + } + + is >> s; + if (s != "1") { + cerr << "[Configuration] Unknown settings file version number, load aborted." << endl; + is.close(); + return; + } + + is >> s; + if (s != "patch_path") { + cerr << "[Configuration] Corrupt settings file, load aborted." << endl; + is.close(); + return; + } + + is >> s; + m_patch_path = s; + + is.close(); +} + + +/** Saves settings to rc file. Passing no parameter will save to the + * default location. + */ +void +Configuration::save_settings(string filename) +{ + if (filename == "") + filename = string(getenv("HOME")).append("/.omgtkrc"); + + std::ofstream os; + os.open(filename.c_str(), std::ios::out); + + if ( ! os.good()) { + cout << "[Configuration] Unable to write to setting file " << filename << endl; + return; + } else { + cout << "[Configuration] Saving settings to " << filename << endl; + } + + os << "file_version 1" << endl; + os << "patch_path " << m_patch_path << endl; + + os.close(); +} + + +/** Applies the current loaded settings to whichever parts of the app + * need updating. + */ +void +Configuration::apply_settings() +{ + Controller::instance().set_patch_path(m_patch_path); +} + + +int +Configuration::get_port_color(const PortModel* pi) +{ + assert(pi != NULL); + + if (pi->is_control()) { + return m_control_port_color; + } else if (pi->is_audio()) { + return m_audio_port_color; + } else if (pi->is_midi()) { + return m_midi_port_color; + } + + cerr << "[Configuration] Unknown port type! Port will be bright red, this is an error." << endl; + return 0xFF0000FF; +} + +/* +Coord +Configuration::get_window_location(const string& id) +{ + return m_window_locations[id]; +} + + +void +Configuration::set_window_location(const string& id, Coord loc) +{ + m_window_locations[id] = loc; +} + + +Coord +Configuration::get_window_size(const string& id) +{ + return m_window_sizes[id]; +} + + +void +Configuration::set_window_size(const string& id, Coord size) +{ + m_window_sizes[id] = size; +}*/ + + +} // namespace OmGtk diff --git a/src/progs/gtk/Configuration.h b/src/progs/gtk/Configuration.h new file mode 100644 index 00000000..f0f9bef9 --- /dev/null +++ b/src/progs/gtk/Configuration.h @@ -0,0 +1,76 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#include <string> + +namespace LibOmClient { class PortModel; } +using LibOmClient::PortModel; +using std::string; + +struct Coord { double x; double y; }; + +namespace OmGtk { + +class Controller; + + +/** Singleton state manager for the entire app. + * + * Stores settings like color preferences, search paths, etc. + * (ie any user-defined preferences to be stoed in the rc file). + * + * \ingroup OmGtk + */ +class Configuration +{ +public: + Configuration(); + ~Configuration(); + + void load_settings(string filename = ""); + void save_settings(string filename = ""); + + void apply_settings(); + + string patch_path() { return m_patch_path; } + void patch_path(const string& path) { m_patch_path = path; } + + const string& patch_folder() { return m_patch_folder; } + void set_patch_folder(const string& f) { m_patch_folder = f; } + + int get_port_color(const PortModel* pi); + +private: + /** Search path for patch files. Colon delimited, as usual. */ + string m_patch_path; + + /** Most recent patch folder shown in open dialog */ + string m_patch_folder; + + int m_audio_port_color; + int m_control_port_color; + int m_midi_port_color; +}; + + +} // namespace OmGtk + +#endif // CONFIG_H + + diff --git a/src/progs/gtk/ConnectWindow.cpp b/src/progs/gtk/ConnectWindow.cpp new file mode 100644 index 00000000..15bab62c --- /dev/null +++ b/src/progs/gtk/ConnectWindow.cpp @@ -0,0 +1,170 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ConnectWindow.h" +#include <string> +#include <time.h> +#include <sys/time.h> +#include "interface/ClientKey.h" +#include "interface/ClientInterface.h" +#include "ThreadedSigClientInterface.h" +#include "Controller.h" +#include "OSCListener.h" +#include "Store.h" + +namespace OmGtk { + + +ConnectWindow::ConnectWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml) +: Gtk::Dialog(cobject) +, _client(NULL) +{ + xml->get_widget("connect_progress_bar", _progress_bar); + xml->get_widget("connect_label", _label); + xml->get_widget("connect_launch_button", _launch_button); + xml->get_widget("connect_cancel_button", _cancel_button); + + assert(_progress_bar); + assert(_label); + assert(_launch_button); + assert(_cancel_button); + + _launch_button->signal_clicked().connect(sigc::mem_fun(this, &ConnectWindow::launch_engine)); + _cancel_button->signal_clicked().connect(sigc::ptr_fun(&Gtk::Main::quit)); +} + + +void +ConnectWindow::start(CountedPtr<Om::Shared::ClientInterface> client) +{ + _client = client; + + Glib::signal_timeout().connect( + sigc::mem_fun(this, &ConnectWindow::gtk_callback), 100); + + resize(100, 100); +} + + +void +ConnectWindow::launch_engine() +{ + if (fork() == 0) { + //cerr << "Launching engine.."; + execlp("om", NULL); + } +} + + +bool +ConnectWindow::gtk_callback() +{ + /* This isn't very nice (isn't threaded), but better than no dialog at + * all like before :) + */ + + // Timing stuff for repeated attach attempts + timeval now; + gettimeofday(&now, NULL); + static timeval last = now; + + static int stage = 0; + + /* Connecting to engine */ + if (stage == 0) { + // FIXME + //assert(!Controller::instance().is_attached()); + _label->set_text(string("Connecting to engine at ").append( + Controller::instance().engine_url()).append("...")); + present(); + Controller::instance().attach(); + ++stage; + } else if (stage == 1) { + if (Controller::instance().is_attached()) { + Controller::instance().activate(); + ++stage; + } else { + const float ms_since_last = (now.tv_sec - last.tv_sec) * 1000.0f + + (now.tv_usec - last.tv_usec) * 0.001f; + if (ms_since_last > 1000) { + Controller::instance().attach(); + last = now; + } + } + } else if (stage == 2) { + _label->set_text(string("Registering as client...")); + //Controller::instance().register_client(Controller::instance().client_hooks()); + // FIXME + //auto_ptr<ClientInterface> client(new ThreadedSigClientInterface(); + Controller::instance().register_client(ClientKey(), _client); + Controller::instance().load_plugins(); + ++stage; + } else if (stage == 3) { + // Register idle callback to process events and whatnot + // (Gtk refreshes at priority G_PRIORITY_HIGH_IDLE+20) + /*Glib::signal_timeout().connect( + sigc::mem_fun(this, &App::idle_callback), 100, G_PRIORITY_HIGH_IDLE);*/ + //Glib::signal_idle().connect(sigc::mem_fun(this, &App::idle_callback)); + /* Glib::signal_timeout().connect( + sigc::mem_fun((ThreadedSigClientInterface*)_client, &ThreadedSigClientInterface::emit_signals), + 5, G_PRIORITY_DEFAULT_IDLE);*/ + + _label->set_text(string("Requesting plugins...")); + Controller::instance().request_plugins(); + ++stage; + } else if (stage == 4) { + // Wait for first plugins message + if (Store::instance().plugins().size() > 0) { + _label->set_text(string("Receiving plugins...")); + ++stage; + } + } else if (stage == 5) { + // FIXME + /*if (Store::instance().plugins().size() < _client->num_plugins()) { + static char buf[32]; + snprintf(buf, 32, "%zu/%zu", Store::instance().plugins().size(), + ThreadedSigClientInterface::instance()->num_plugins()); + _progress_bar->set_text(Glib::ustring(buf)); + _progress_bar->set_fraction( + Store::instance().plugins().size() / (double)_client->num_plugins()); + } else {*/ + _progress_bar->set_text(""); + ++stage; + //} + } else if (stage == 6) { + _label->set_text(string("Waiting for root patch...")); + Controller::instance().request_all_objects(); + ++stage; + } else if (stage == 7) { + if (Store::instance().num_objects() > 0) + ++stage; + } else if (stage == 8) { + stage = -1; + hide(); // FIXME: actually destroy window to save mem? + } + + if (stage != 5) // yeah, ew + _progress_bar->pulse(); + + if (stage == -1) { // finished connecting + return false; // deregister this callback + } else { + return true; + } +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/ConnectWindow.h b/src/progs/gtk/ConnectWindow.h new file mode 100644 index 00000000..8c0c7390 --- /dev/null +++ b/src/progs/gtk/ConnectWindow.h @@ -0,0 +1,61 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONNECT_WINDOW_H +#define CONNECT_WINDOW_H + +#include <gtkmm.h> +#include <libglademm/xml.h> +#include <libglademm.h> +#include "util/CountedPtr.h" +#include "interface/ClientInterface.h" + +namespace OmGtk { + +class App; +class Controller; + + +/** The initially visible "Connect to engine" window. + * + * This handles actually connecting to the engine and making sure everything + * is ready before really launching the app (eg wait for the root patch). + * + * \ingroup OmGtk + */ +class ConnectWindow : public Gtk::Dialog +{ +public: + ConnectWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml); + + void start(CountedPtr<Om::Shared::ClientInterface> client); + +private: + void launch_engine(); + + bool gtk_callback(); + + CountedPtr<Om::Shared::ClientInterface> _client; + Gtk::ProgressBar* _progress_bar; + Gtk::Label* _label; + Gtk::Button* _launch_button; + Gtk::Button* _cancel_button; +}; + + +} // namespace OmGtk + +#endif // CONNECT_WINDOW_H diff --git a/src/progs/gtk/ControlGroups.cpp b/src/progs/gtk/ControlGroups.cpp new file mode 100644 index 00000000..de87be05 --- /dev/null +++ b/src/progs/gtk/ControlGroups.cpp @@ -0,0 +1,419 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ControlGroups.h" +#include "ControlPanel.h" +#include "PortModel.h" +#include "Controller.h" +//#include "GtkClientInterface.h" +#include <cmath> +#include <iostream> +using std::cerr; using std::cout; using std::endl; + +using namespace LibOmClient; + +namespace OmGtk { + +//////////////////// SliderControlGroup //////////////////////// + + +SliderControlGroup::SliderControlGroup(ControlPanel* panel, PortModel* pm, bool separator) +: ControlGroup(panel, pm, separator), + m_enabled(true), + m_enable_signal(false), + m_name_label(pm->name(), 0.0, 0.0), + m_range_box(false, 0), + m_range_label("<small>Range: </small>"), + m_min_spinner(1.0, (pm->is_integer() ? 0 : 4)), // climb rate, digits + m_hyphen_label(" - "), + m_max_spinner(1.0, (pm->is_integer() ? 0 : 4)), + m_slider_box(false, 0), + m_value_spinner(1.0, (pm->is_integer() ? 0 : 4)), + m_slider(pm->user_min(), pm->user_max(), (pm->is_integer() ? 1.0 : 0.0001)) +{ + m_slider.set_increments(1.0, 10.0); + + // Compensate for crazy plugins + if (m_port_model->user_max() <= m_port_model->user_min()) { + m_port_model->user_max(m_port_model->user_min() + 1.0); + m_slider.set_range(m_port_model->user_min(), m_port_model->user_max()); + } + m_slider.property_draw_value() = false; + + set_name(pm->name()); + + m_name_label.property_use_markup() = true; + m_range_label.property_use_markup() = true; + + m_value_spinner.set_range(-99999, 99999); + m_value_spinner.set_update_policy(Gtk::UPDATE_ALWAYS); // allow entered values outside range + m_value_spinner.set_value(m_port_model->value()); + m_value_spinner.set_increments(1.0, 10.0); + m_value_spinner.set_digits(5); + m_value_spinner.signal_value_changed().connect( + sigc::mem_fun(*this, &SliderControlGroup::update_value_from_spinner)); + m_min_spinner.set_range(-99999, 99999); + m_min_spinner.set_value(m_port_model->user_min()); + m_min_spinner.set_increments(1.0, 10.0); + m_min_spinner.set_digits(5); + m_min_spinner.signal_value_changed().connect(sigc::mem_fun(*this, &SliderControlGroup::min_changed)); + m_max_spinner.set_range(-99999, 99999); + m_max_spinner.set_value(m_port_model->user_max()); + m_max_spinner.set_increments(1.0, 10.0); + m_max_spinner.set_digits(5); + m_max_spinner.signal_value_changed().connect(sigc::mem_fun(*this, &SliderControlGroup::max_changed)); + + m_slider.set_value(m_port_model->value()); + + m_slider.signal_event().connect( + sigc::mem_fun(*this, &SliderControlGroup::slider_pressed)); + + m_slider.signal_value_changed().connect( + sigc::mem_fun(*this, &SliderControlGroup::update_value_from_slider)); + + m_range_box.pack_start(m_range_label, false, false, 2); + m_range_box.pack_start(m_min_spinner, false, false, 1); + m_range_box.pack_start(m_hyphen_label, false, false, 1); + m_range_box.pack_start(m_max_spinner, false, false, 1); + + m_header_box.pack_start(m_name_label, true, true, 0); + m_header_box.pack_start(m_range_box, true, true, 2); + + m_slider_box.pack_start(m_value_spinner, false, false, 1); + m_slider_box.pack_start(m_slider, true, true, 5); + + pack_start(m_header_box, false, false, 0); + pack_start(m_slider_box, false, false, 0); + + update_range(); + + m_enable_signal = true; + + show_all(); +} + + +void +SliderControlGroup::set_name(const string& name) +{ + string name_label = "<small><span weight=\"bold\">"; + name_label += name + "</span></small>"; + m_name_label.set_markup(name_label); +} + + +void +SliderControlGroup::set_min(float val) +{ + m_enable_signal = false; + m_min_spinner.set_value(val); + m_enable_signal = true; +} + + +void +SliderControlGroup::set_max(float val) +{ + m_enable_signal = false; + m_max_spinner.set_value(val); + m_enable_signal = true; +} + + +void +SliderControlGroup::enable() +{ + m_slider.property_sensitive() = true; + m_min_spinner.property_sensitive() = true; + m_max_spinner.property_sensitive() = true; + m_value_spinner.property_sensitive() = true; + m_name_label.property_sensitive() = true; + m_range_label.property_sensitive() = true; +} + + +void +SliderControlGroup::disable() +{ + m_slider.property_sensitive() = false; + m_min_spinner.property_sensitive() = false; + m_max_spinner.property_sensitive() = false; + m_value_spinner.property_sensitive() = false; + m_name_label.property_sensitive() = false; + m_range_label.property_sensitive() = false; +} + + +void +SliderControlGroup::min_changed() +{ + double min = m_min_spinner.get_value(); + const double max = m_max_spinner.get_value(); + + if (min >= max) { + min = max - 1.0; + m_min_spinner.set_value(min); + } + + update_range(); +} + + +void +SliderControlGroup::max_changed() +{ + const double min = m_min_spinner.get_value(); + double max = m_max_spinner.get_value(); + + if (max <= min) { + max = min + 1.0; + m_max_spinner.set_value(max); + } + + update_range(); +} + + +void +SliderControlGroup::update_range() +{ + const double min = m_min_spinner.get_value(); + const double max = m_max_spinner.get_value(); + + assert(min < max); + m_slider.set_range(min, max); + + m_port_model->user_min(min); + m_port_model->user_max(max); + + if (m_enable_signal) { + char temp_buf[16]; + snprintf(temp_buf, 16, "%f", m_port_model->user_min()); + Controller::instance().set_metadata(m_port_model->path(), "user-min", temp_buf); + snprintf(temp_buf, 16, "%f", m_port_model->user_max()); + Controller::instance().set_metadata(m_port_model->path(), "user-max", temp_buf); + } +} + + +void +SliderControlGroup::update_value_from_slider() +{ + if (m_enable_signal) { + const float value = m_slider.get_value(); + // Prevent spinner signal from doing all this over again (slow) + m_enable_signal = false; + m_value_spinner.set_value(value); + m_control_panel->value_changed(m_port_model->path(), value); + m_port_model->value(value); + m_enable_signal = true; + } +} + + +void +SliderControlGroup::update_value_from_spinner() +{ + if (m_enable_signal) { + m_enable_signal = false; + const float value = m_value_spinner.get_value(); + if (value < m_min_spinner.get_value()) + m_min_spinner.set_value(value); + if (value > m_max_spinner.get_value()) + m_max_spinner.set_value(value); + + m_enable_signal = false; + update_range(); + m_slider.set_value(m_value_spinner.get_value()); + m_enable_signal = true; + + m_control_panel->value_changed(m_port_model->path(), value); + + m_port_model->value(value); + m_enable_signal = true; + } +} + + +/** Callback for when slider is grabbed so we can ignore set_control + * events for this port (and avoid nasty feedback issues). + */ +bool +SliderControlGroup::slider_pressed(GdkEvent* ev) +{ + //cerr << "Pressed: " << ev->type << endl; + if (ev->type == GDK_BUTTON_PRESS) { + m_enabled = false; + cerr << "SLIDER FIXME\n"; + //GtkClientInterface::instance()->set_ignore_port(m_port_model->path()); + } else if (ev->type == GDK_BUTTON_RELEASE) { + m_enabled = true; + cerr << "SLIDER FIXME\n"; + //GtkClientInterface::instance()->clear_ignore_port(); + } + + return false; +} + + +/////////////// IntegerControlGroup //////////////// + + +IntegerControlGroup::IntegerControlGroup(ControlPanel* panel, PortModel* pm, bool separator) +: ControlGroup(panel, pm, separator), + m_enable_signal(false), + m_alignment(0.5, 0.5, 0.0, 0.0), + m_name_label(pm->name()), + m_spinner(1.0, 0) +{ + set_name(pm->name()); + + m_spinner.set_range(-99999, 99999); + m_spinner.set_value(m_port_model->value()); + m_spinner.signal_value_changed().connect( + sigc::mem_fun(*this, &IntegerControlGroup::update_value)); + m_spinner.set_increments(1, 10); + + m_alignment.add(m_spinner); + pack_start(m_name_label); + pack_start(m_alignment); + + m_enable_signal = true; + + show_all(); +} + + +void +IntegerControlGroup::set_name(const string& name) +{ + string name_label = "<span weight=\"bold\">"; + name_label += name + "</span>"; + m_name_label.set_markup(name_label); +} + + +void +IntegerControlGroup::set_value(float val) +{ + //cerr << "[IntegerControlGroup] Setting value to " << val << endl; + m_enable_signal = false; + m_spinner.set_value(val); + m_port_model->value(val); + m_enable_signal = true; +} + + +void +IntegerControlGroup::enable() +{ + m_spinner.property_sensitive() = true; + m_name_label.property_sensitive() = true; +} + + +void +IntegerControlGroup::disable() +{ + m_spinner.property_sensitive() = false; + m_name_label.property_sensitive() = false; +} + + +void +IntegerControlGroup::update_value() +{ + if (m_enable_signal) { + float value = m_spinner.get_value(); + m_control_panel->value_changed(m_port_model->path(), value); + m_port_model->value(value); + } +} + + +/////////////// ToggleControlGroup //////////////// + + +ToggleControlGroup::ToggleControlGroup(ControlPanel* panel, PortModel* pm, bool separator) +: ControlGroup(panel, pm, separator), + m_enable_signal(false), + m_alignment(0.5, 0.5, 0.0, 0.0), + m_name_label(pm->name()) +{ + set_name(pm->name()); + + set_value(m_port_model->value()); + m_checkbutton.signal_toggled().connect( + sigc::mem_fun(*this, &ToggleControlGroup::update_value)); + + m_alignment.add(m_checkbutton); + pack_start(m_name_label); + pack_start(m_alignment); + + m_enable_signal = true; + + show_all(); +} + + +void +ToggleControlGroup::set_name(const string& name) +{ + string name_label = "<span weight=\"bold\">"; + name_label += name + "</span>"; + m_name_label.set_markup(name_label); +} + + +void +ToggleControlGroup::set_value(float val) +{ + //cerr << "[ToggleControlGroup] Setting value to " << val << endl; + m_enable_signal = false; + m_checkbutton.set_active( (val > 0.0f) ); + m_port_model->value(val); + m_enable_signal = true; +} + + +void +ToggleControlGroup::enable() +{ + m_checkbutton.property_sensitive() = true; + m_name_label.property_sensitive() = true; +} + + +void +ToggleControlGroup::disable() +{ + m_checkbutton.property_sensitive() = false; + m_name_label.property_sensitive() = false; +} + + +void +ToggleControlGroup::update_value() +{ + if (m_enable_signal) { + float value = m_checkbutton.get_active() ? 1.0f : 0.0f; + m_control_panel->value_changed(m_port_model->path(), value); + m_port_model->value(value); + } +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/ControlGroups.h b/src/progs/gtk/ControlGroups.h new file mode 100644 index 00000000..ab1e3413 --- /dev/null +++ b/src/progs/gtk/ControlGroups.h @@ -0,0 +1,196 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONTROLGROUPS_H +#define CONTROLGROUPS_H + +#include <cassert> +#include <gtkmm.h> +#include <libglademm/xml.h> +#include <libglademm.h> +#include "PortModel.h" + + +namespace LibOmClient { class PortModel; } +using namespace LibOmClient; + +namespace OmGtk { + +class ControlPanel; + + +/** A group of controls in a NodeControlWindow. + * + * \ingroup OmGtk + */ +class ControlGroup : public Gtk::VBox +{ +public: + ControlGroup(ControlPanel* panel, PortModel* pm, bool separator) + : Gtk::VBox(false, 0), + m_control_panel(panel), + m_port_model(pm), + m_has_separator(separator) + { + assert(m_port_model != NULL); + assert(panel != NULL); + + if (separator) { + m_separator = new Gtk::HSeparator(); + pack_start(*m_separator, false, false, 4); + } else { + m_separator = NULL; + } + } + + ~ControlGroup() { delete m_separator; } + + virtual void set_name(const string& name) {} + + virtual void set_value(float val) = 0; + + inline const PortModel* const port_model() { return m_port_model; } + + virtual void set_min(float val) {} + virtual void set_max(float val) {} + + void remove_separator() { assert(m_has_separator); + remove(*m_separator); delete m_separator; } + + virtual void enable() {} + virtual void disable() {} + +protected: + ControlPanel* m_control_panel; + PortModel* m_port_model; + bool m_has_separator; + Gtk::HSeparator* m_separator; +}; + + +/** A slider for a continuous control. + * + * \ingroup OmGtk + */ +class SliderControlGroup : public ControlGroup +{ +public: + SliderControlGroup(ControlPanel* panel, PortModel* pm, bool separator); + + void set_name(const string& name); + + inline void set_value(const float val); + void set_min(float val); + void set_max(float val); + + void enable(); + void disable(); + +private: + void min_changed(); + void max_changed(); + void update_range(); + void update_value_from_slider(); + void update_value_from_spinner(); + + //void slider_grabbed(bool b); + + bool slider_pressed(GdkEvent* ev); + + bool m_enabled; + bool m_enable_signal; + + Gtk::HBox m_header_box; + Gtk::Label m_name_label; + Gtk::HBox m_range_box; + Gtk::Label m_range_label; + Gtk::SpinButton m_min_spinner; + Gtk::Label m_hyphen_label; + Gtk::SpinButton m_max_spinner; + Gtk::HBox m_slider_box; + Gtk::SpinButton m_value_spinner; + Gtk::HScale m_slider; +}; + + +inline void +SliderControlGroup::set_value(const float val) +{ + m_enable_signal = false; + if (m_enabled) { + m_slider.set_value(val); + m_value_spinner.set_value(val); + } + m_port_model->value(val); + m_enable_signal = true; +} + + + + +/** A spinbutton for integer controls. + * + * \ingroup OmGtk + */ +class IntegerControlGroup : public ControlGroup +{ +public: + IntegerControlGroup(ControlPanel* panel, PortModel* pm, bool separator); + + void set_name(const string& name); + void set_value(float val); + + void enable(); + void disable(); + +private: + void update_value(); + + bool m_enable_signal; + Gtk::Alignment m_alignment; + Gtk::Label m_name_label; + Gtk::SpinButton m_spinner; +}; + + +/** A radio button for toggle controls. + * + * \ingroup OmGtk + */ +class ToggleControlGroup : public ControlGroup +{ +public: + ToggleControlGroup(ControlPanel* panel, PortModel* pm, bool separator); + + void set_name(const string& name); + void set_value(float val); + + void enable(); + void disable(); + +private: + void update_value(); + + bool m_enable_signal; + Gtk::Alignment m_alignment; + Gtk::Label m_name_label; + Gtk::CheckButton m_checkbutton; +}; + + +} // namespace OmGtk + +#endif // CONTROLGROUPS_H diff --git a/src/progs/gtk/ControlInterface.cpp b/src/progs/gtk/ControlInterface.cpp new file mode 100644 index 00000000..9ac6e07e --- /dev/null +++ b/src/progs/gtk/ControlInterface.cpp @@ -0,0 +1,302 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <cassert> + +#include "ControlInterface.h" +#include "App.h" + +#include "PluginModel.h" +#include "PatchModel.h" +#include "NodeModel.h" +#include "PortModel.h" +#include "ConnectionModel.h" + +#include "PatchController.h" +#include "PortController.h" +#include "PatchTreeWindow.h" +#include "Store.h" + +namespace OmGtk +{ + + +void +ControlInterface::error(const string& msg) +{ + _app->error_message(msg); +} + + +void +ControlInterface::new_plugin_model(PluginModel* pm) +{ + cerr << "NEW PLUGIN\n"; + Store::instance().add_plugin(pm); +} + + +void +ControlInterface::new_patch_model(PatchModel* const pm) +{ + assert(pm); + + //cout << "[ControlInterface] New patch." << endl; + + if (Store::instance().patch(pm->path()) != NULL) { + delete pm; + } else { + + // See if we cached this patch model to store its location (to avoid the + // module "jumping") and filename (which isn't sent to engine) + /*PatchModel* pm = _controller->yank_added_patch(pm->path()); + if (pm != NULL) { + assert(pm->path() == pm->path()); + // FIXME: ew + if (pm->parent() != NULL) + pm->set_parent(NULL); + const PluginModel* plugin = pm->plugin(); + *pm = *pm; + pm->plugin(plugin); + }*/ + + assert(pm->parent() == NULL); + PatchController* patch = new PatchController(pm); + Store::instance().add_object(patch); + _app->patch_tree()->add_patch(patch); + + if (pm->path() == "/") + patch->show_patch_window(); + + //_app->add_patch(pm, show); + } +} + + +void +ControlInterface::new_node_model(NodeModel* const nm) +{ + assert(nm); + + //cerr << "[ControlInterface] New node: " << nm->name() << endl; + + PatchController* const pc = Store::instance().patch(nm->path().parent()); + + if (pc != NULL) { + /* FIXME: this is crazy slow, and slows down patch loading too much. Define some + * kind of unified string to describe all plugins (ie ladspa:amp.so:amp_gaia) and + * just store that in node models, and look it up when needed */ + + /* Bit of a hack, throw away the placeholder PluginModel in the NodeModel + * and set it to the nice complete one we have stored */ + + for (map<string, const PluginModel*>::const_iterator i = Store::instance().plugins().begin(); + i != Store::instance().plugins().end(); ++i) { + if ((*i).second->uri() == nm->plugin()->uri()) { + // FIXME: EVIL + delete (PluginModel*)(nm->plugin()); + nm->plugin((*i).second); + break; + } + } + + pc->add_node(nm); + + } else { + cerr << "[NewNode] Can not find parent of " << nm->path() + << ". Module will not appear." << endl; + } +} + + +void +ControlInterface::new_port_model(PortModel* const pm) +{ + assert(pm); + + //cout << "[ControlInterface] New port." << endl; + + NodeController* node = Store::instance().node(pm->path().parent()); + if (node != NULL) + node->add_port(pm); + else + cerr << "[NewPort] Could not find parent for " + << pm->path() << endl; +} + + +void +ControlInterface::patch_enabled(const string& path) +{ + //cout << "[ControlInterface] Patch enabled." << endl; + + PatchController* patch = Store::instance().patch(path); + if (patch != NULL) + patch->enable(); + else + cerr << "[PatchEnabled] Cannot find patch " << path << endl; +} + + +void +ControlInterface::patch_disabled(const string& path) +{ + //cout << "[ControlInterface] Patch disabled." << endl; + + PatchController* patch = Store::instance().patch(path); + if (patch != NULL) + patch->disable(); + else + cerr << "[PatchDisabled] Cannot find patch " << path << endl; +} + + +void +ControlInterface::patch_cleared(const string& path) +{ + //cout << "[ControlInterface] Patch cleared." << endl; + + PatchController* patch = Store::instance().patch(path); + if (patch != NULL) + patch->clear(); + else + cerr << "[PatchCleared] Cannot find patch " << path << endl; +} + + +void +ControlInterface::object_destroyed(const string& path) +{ + //cout << "[ControlInterface] Destroying." << endl; + + GtkObjectController* object = Store::instance().object(path); + if (object != NULL) { + object->destroy(); + delete object; + } else { + cerr << "[Destroy] Cannot find object " << path << endl; + } +} + + +void +ControlInterface::object_renamed(const string& old_path, const string& new_path) +{ + //cout << "[ControlInterface] Renaming." << endl; + + GtkObjectController* object = Store::instance().object(old_path); + if (object != NULL) + object->set_path(new_path); + else + cerr << "[ObjectRenamed] Can not find object " << old_path + << " to rename." << endl; +} + + +void +ControlInterface::connection_model(ConnectionModel* connection) +{ + assert(connection); + + //cout << "[ControlInterface] Connection" << endl; + + assert(connection->src_port_path().parent().parent() + == connection->dst_port_path().parent().parent()); + + PatchController* pc = Store::instance().patch(connection->patch_path()); + + if (pc != NULL) + pc->connection(connection); + else + cerr << "[Connection] Can not find patch " << connection->patch_path() + << ". Connection will not be made." << endl; +} + + +void +ControlInterface::disconnection(const string& src_port_path, const string& dst_port_path) +{ + //cerr << "[ControlInterface] Disconnection." << endl; + string patch_path = src_port_path; + patch_path = patch_path.substr(0, patch_path.find_last_of("/")); + patch_path = patch_path.substr(0, patch_path.find_last_of("/")); + + if (patch_path == "") + patch_path = "/"; + + PatchController* pc = Store::instance().patch(patch_path); + + if (pc != NULL) + pc->disconnection(src_port_path, dst_port_path); + else + cerr << "[Disconnection] Can not find window for patch " << patch_path + << ". Connection will not be removed." << endl; +} + + +void +ControlInterface::metadata_update(const string& path, const string& key, const string& value) +{ + //cerr << "[ControlInterface] Metadata." << endl; + + GtkObjectController* object = Store::instance().object(path); + if (object != NULL) + object->metadata_update(key, value); + else + cerr << "[MetadataUpdate] Could not find object " << path << endl; +} + + +void +ControlInterface::control_change(const string& port_path, float value) +{ + //cerr << "[ControlInterface] Control change." << endl; + + PortController* port = Store::instance().port(port_path); + if (port != NULL) + port->control_change(value); + else + cerr << "[ControlChange] Can not find port " << port_path << endl; +} + + +void +ControlInterface::program_add(const string& path, uint32_t bank, uint32_t program, const string& name) +{ + NodeController* node = Store::instance().node(path); + if (node != NULL) { + node->program_add(bank, program, name); + return; + } else { + cerr << "[ProgramAdd] Can not find node " << path << endl; + } +} + + +void +ControlInterface::program_remove(const string& path, uint32_t bank, uint32_t program) +{ + NodeController* node = Store::instance().node(path); + if (node != NULL) { + node->program_remove(bank, program); + return; + } else { + cerr << "[ProgramRemove] Can not find node " << path << endl; + } +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/ControlInterface.h b/src/progs/gtk/ControlInterface.h new file mode 100644 index 00000000..8cba6a79 --- /dev/null +++ b/src/progs/gtk/ControlInterface.h @@ -0,0 +1,129 @@ +/* This file is part of Om. Copyright(C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONTROLINTERFACE_H +#define CONTROLINTERFACE_H + +#include <cassert> +#include "ModelClientInterface.h" +#include <sigc++/sigc++.h> +#include <string> +using std::string; + +namespace LibOmClient +{ +class PluginModel; +class PatchModel; +class NodeModel; +class PortModel; +class ConnectionModel; +} +using namespace LibOmClient; + +namespace OmGtk +{ + +class App; + + +/** Provides the public interface for controlling OmGtk(via engine events). + * + * All control of OmGtk from the engine happens through this interface. + * + * All of these functions must be called in the GTK thread. This is a unified + * interface for controlling OmGtk(eg from the engine) but it doesn't take + * care of any threading issues. + * + * \ingroup OmGtk + */ +class ControlInterface : public sigc::trackable//, public ModelClientInterface +{ +public: + + ControlInterface(App* app) + : error_slot(sigc::mem_fun(this, &ControlInterface::error)) + , new_plugin_slot(sigc::mem_fun(this, &ControlInterface::new_plugin_model)) + , new_patch_slot(sigc::mem_fun(this, &ControlInterface::new_patch_model)) + , new_node_slot(sigc::mem_fun(this, &ControlInterface::new_node_model)) + , new_port_slot(sigc::mem_fun(this, &ControlInterface::new_port_model)) + , patch_enabled_slot(sigc::mem_fun(this, &ControlInterface::patch_enabled)) + , patch_disabled_slot(sigc::mem_fun(this, &ControlInterface::patch_disabled)) + , patch_cleared_slot(sigc::mem_fun(this, &ControlInterface::patch_cleared)) + , object_destroyed_slot(sigc::mem_fun(this, &ControlInterface::object_destroyed)) + , object_renamed_slot(sigc::mem_fun(this, &ControlInterface::object_renamed)) + , connection_slot(sigc::mem_fun(this, &ControlInterface::connection_model)) + , disconnection_slot(sigc::mem_fun(this, &ControlInterface::disconnection)) + , metadata_update_slot(sigc::mem_fun(this, &ControlInterface::metadata_update)) + , control_change_slot(sigc::mem_fun(this, &ControlInterface::control_change)) + , program_add_slot(sigc::mem_fun(this, &ControlInterface::program_add)) + , program_remove_slot(sigc::mem_fun(this, &ControlInterface::program_remove)) + , _app(app) + { + assert(_app); + } + + virtual ~ControlInterface() {} + + sigc::slot<void> bundle_begin_slot; + sigc::slot<void> bundle_end_slot; + sigc::slot<void, uint32_t> num_plugins_slot; + sigc::slot<void, string> error_slot; + sigc::slot<void, PluginModel*> new_plugin_slot; + sigc::slot<void, PatchModel*> new_patch_slot; + sigc::slot<void, NodeModel*> new_node_slot; + sigc::slot<void, PortModel*> new_port_slot; + sigc::slot<void, string> patch_enabled_slot; + sigc::slot<void, string> patch_disabled_slot; + sigc::slot<void, string> patch_cleared_slot; + sigc::slot<void, string> object_destroyed_slot; + sigc::slot<void, string, string> object_renamed_slot; + sigc::slot<void, ConnectionModel*> connection_slot; + sigc::slot<void, string, string> disconnection_slot; + sigc::slot<void, string, string, string> metadata_update_slot; + sigc::slot<void, string, float> control_change_slot; + sigc::slot<void, string, uint32_t, uint32_t, const string&> program_add_slot; + sigc::slot<void, string, uint32_t, uint32_t> program_remove_slot; + +private: + + void bundle_begin(); + void bundle_end(); + void num_plugins(uint32_t); + void error(const string&); + void new_plugin_model(PluginModel*); + void new_patch_model(PatchModel*); + void new_node_model(NodeModel*); + void new_port_model(PortModel*); + void patch_enabled(const string&); + void patch_disabled(const string&); + void patch_cleared(const string&); + void object_destroyed(const string&); + void object_renamed(const string&, const string&); + void connection_model(ConnectionModel*); + void disconnection(const string&, const string&); + void metadata_update(const string&, const string&, const string&); + void control_change(const string&, float); + void program_add(const string&, uint32_t, uint32_t, const string&); + void program_remove(const string&, uint32_t, uint32_t); + + App* _app; +}; + + +} // namespace OmGtk + +#endif // CONTROLINTERFACE_H + diff --git a/src/progs/gtk/ControlPanel.cpp b/src/progs/gtk/ControlPanel.cpp new file mode 100644 index 00000000..f344e2c3 --- /dev/null +++ b/src/progs/gtk/ControlPanel.cpp @@ -0,0 +1,279 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 alongCont + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ControlPanel.h" +#include "PatchModel.h" +#include "NodeModel.h" +#include "PortModel.h" +#include "ControlGroups.h" +#include "PatchController.h" +#include "Controller.h" + +namespace OmGtk { + + +ControlPanel::ControlPanel(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml) +: Gtk::VBox(cobject), + m_callback_enabled(true) +{ + xml->get_widget("control_panel_controls_box", m_control_box); + xml->get_widget("control_panel_voice_controls_box", m_voice_control_box); + xml->get_widget("control_panel_all_voices_radio", m_all_voices_radio); + xml->get_widget("control_panel_specific_voice_radio", m_specific_voice_radio); + xml->get_widget("control_panel_voice_spinbutton", m_voice_spinbutton); + + m_all_voices_radio->signal_toggled().connect(sigc::mem_fun(this, &ControlPanel::all_voices_selected)); + m_specific_voice_radio->signal_toggled().connect(sigc::mem_fun(this, &ControlPanel::specific_voice_selected)); + m_voice_spinbutton->signal_value_changed().connect(sigc::mem_fun(this, &ControlPanel::voice_selected)); + + show_all(); +} + + +ControlPanel::~ControlPanel() +{ + for (vector<ControlGroup*>::iterator i = m_controls.begin(); i != m_controls.end(); ++i) + delete (*i); +} + + +void +ControlPanel::init(NodeController* node, size_t poly) +{ + assert(node != NULL); + assert(poly > 0); + + NodeModel* const node_model = node->node_model(); + + if (poly > 1) { + m_voice_spinbutton->set_range(0, poly - 1); + } else { + remove(*m_voice_control_box); + } + + for (PortModelList::const_iterator i = node_model->ports().begin(); + i != node_model->ports().end(); ++i) { + PortController* pc = (PortController*)(*i)->controller(); + assert(pc != NULL); + add_port(pc); + } + + m_callback_enabled = true; +} + + +ControlGroup* +ControlPanel::find_port(const Path& path) const +{ + for (vector<ControlGroup*>::const_iterator cg = m_controls.begin(); cg != m_controls.end(); ++cg) + if ((*cg)->port_model()->path() == path) + return (*cg); + + return NULL; +} + + +/** Add a control to the panel for the given port. + */ +void +ControlPanel::add_port(PortController* port) +{ + assert(port != NULL); + assert(port->model() != NULL); + assert(port->control_panel() == NULL); + + PortModel* const pm = port->port_model(); + + // Already have port, don't add another + if (find_port(pm->path()) != NULL) + return; + + // Add port + if (pm->is_control() && pm->is_input()) { + bool separator = (m_controls.size() > 0); + ControlGroup* cg = NULL; + if (pm->is_integer()) + cg = new IntegerControlGroup(this, pm, separator); + else if (pm->is_toggle()) + cg = new ToggleControlGroup(this, pm, separator); + else + cg = new SliderControlGroup(this, pm, separator); + + m_controls.push_back(cg); + m_control_box->pack_start(*cg, false, false, 0); + + if (pm->connected()) + cg->disable(); + else + cg->enable(); + } + + port->set_control_panel(this); + + Gtk::Requisition controls_size; + m_control_box->size_request(controls_size); + m_ideal_size.first = controls_size.width; + m_ideal_size.second = controls_size.height; + + Gtk::Requisition voice_size; + m_voice_control_box->size_request(voice_size); + m_ideal_size.first += voice_size.width; + m_ideal_size.second += voice_size.height; + + //cerr << "Setting ideal size to " << m_ideal_size.first + // << " x " << m_ideal_size.second << endl; +} + + +/** Remove the control for the given port. + */ +void +ControlPanel::remove_port(const Path& path) +{ + bool was_first = false; + for (vector<ControlGroup*>::iterator cg = m_controls.begin(); cg != m_controls.end(); ++cg) { + if ((*cg)->port_model()->path() == path) { + m_control_box->remove(**cg); + if (cg == m_controls.begin()) + was_first = true; + m_controls.erase(cg); + break; + } + } + + if (was_first && m_controls.size() > 0) + (*m_controls.begin())->remove_separator(); +} + + +/** Rename the control for the given port. + */ +void +ControlPanel::rename_port(const Path& old_path, const Path& new_path) +{ + for (vector<ControlGroup*>::iterator cg = m_controls.begin(); cg != m_controls.end(); ++cg) { + if ((*cg)->port_model()->path() == old_path) { + (*cg)->set_name(new_path.name()); + return; + } + } +} + + +/** Enable the control for the given port. + * + * Used when all connections to port are un-made. + */ +void +ControlPanel::enable_port(const Path& path) +{ + for (vector<ControlGroup*>::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { + if ((*i)->port_model()->path() == path) { + (*i)->enable(); + return; + } + } +} + + +/** Disable the control for the given port. + * + * Used when port is connected. + */ +void +ControlPanel::disable_port(const Path& path) +{ + for (vector<ControlGroup*>::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { + if ((*i)->port_model()->path() == path) { + (*i)->disable(); + return; + } + } +} + + +/** Callback for ControlGroups to notify this of a change. + */ +void +ControlPanel::value_changed(const Path& port_path, float val) +{ + if (m_callback_enabled) { + // Update patch control slider, if this is a control panel for a patch + // (or vice versa) + //if (m_mirror != NULL) + // m_mirror->set_port_value(port_path, val); + + if (m_all_voices_radio->get_active()) { + Controller::instance().set_port_value(port_path, val); + } else { + int voice = m_voice_spinbutton->get_value_as_int(); + Controller::instance().set_port_value(port_path, voice, val); + } + } +} + + +void +ControlPanel::set_range_min(const Path& port_path, float val) +{ + bool found = false; + for (vector<ControlGroup*>::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { + if ((*i)->port_model()->path() == port_path) { + found = true; + (*i)->set_min(val); + } + } + if (found == false) + cerr << "[ControlPanel::set_range_min] Unable to find control " << port_path << endl; +} + + +void +ControlPanel::set_range_max(const Path& port_path, float val) +{ + bool found = false; + for (vector<ControlGroup*>::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { + if ((*i)->port_model()->path() == port_path) { + found = true; + (*i)->set_max(val); + } + } + if (found == false) + cerr << "[ControlPanel::set_range_max] Unable to find control " << port_path << endl; +} + + +void +ControlPanel::all_voices_selected() +{ + m_voice_spinbutton->property_sensitive() = false; +} + + +void +ControlPanel::specific_voice_selected() +{ + m_voice_spinbutton->property_sensitive() = true; +} + + +void +ControlPanel::voice_selected() +{ +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/ControlPanel.h b/src/progs/gtk/ControlPanel.h new file mode 100644 index 00000000..1f24344f --- /dev/null +++ b/src/progs/gtk/ControlPanel.h @@ -0,0 +1,129 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONTROLPANEL_H +#define CONTROLPANEL_H + +#include <gtkmm.h> +#include <sigc++/sigc++.h> +#include <libglademm/xml.h> +#include <libglademm.h> +#include <vector> +#include <string> +#include <iostream> +#include <utility> // for pair<> +#include "ControlGroups.h" +#include "util/Path.h" +#include "PortController.h" + +using std::vector; using std::string; using std::pair; +using std::cerr; using std::cout; using std::endl; + +namespace LibOmClient { +class PortModel; +class NodeModel; +} +using namespace LibOmClient; +using Om::Path; + +namespace OmGtk { + +class NodeController; +class PortController; + + +/** A group of controls for a node (or patch). + * + * Used by both NodeControlWindow and the main window (for patch controls). + * + * \ingroup OmGtk + */ +class ControlPanel : public Gtk::VBox { +public: + ControlPanel(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& glade_xml); + virtual ~ControlPanel(); + + void init(NodeController* node, size_t poly); + + ControlGroup* find_port(const Path& path) const; + + void add_port(PortController* port); + void remove_port(const Path& path); + + void rename_port(const Path& old_path, const Path& new_path); + + void enable_port(const Path& path); + void disable_port(const Path& path); + + size_t num_controls() const { return m_controls.size(); } + pair<int,int> ideal_size() const { return m_ideal_size; } + + // Callback for ControlGroup + void value_changed(const Path& port_path, float val); + + inline void set_control(const Path& port_path, float value); + void set_range_min(const Path& port_path, float value); + void set_range_max(const Path& port_path, float value); + +private: + void all_voices_selected(); + void specific_voice_selected(); + void voice_selected(); + + bool m_callback_enabled; + + pair<int,int> m_ideal_size; + + vector<ControlGroup*> m_controls; + Gtk::VBox* m_control_box; + Gtk::Box* m_voice_control_box; + Gtk::RadioButton* m_all_voices_radio; + Gtk::RadioButton* m_specific_voice_radio; + Gtk::SpinButton* m_voice_spinbutton; +}; + + +/** Set a port on this panel to a certain value. + * + * Profiling has shown this is performance critical. Needs to be made + * faster. + */ +inline void +ControlPanel::set_control(const Path& port_path, const float val) +{ + // FIXME: double lookup, ports should just have a pointer directly to + // their control group + + m_callback_enabled = false; + ControlGroup* cg = NULL; + + for (vector<ControlGroup*>::iterator i = m_controls.begin(); i != m_controls.end(); ++i) { + cg = (*i); + if (cg->port_model()->path() == port_path) { + cg->set_value(val); + m_callback_enabled = true; + return; + } + } + + cerr << "[ControlPanel::set_control] Unable to find control " << port_path << endl; + m_callback_enabled = true; +} + + +} // namespace OmGtk + +#endif // CONTROLPANEL_H diff --git a/src/progs/gtk/Controller.cpp b/src/progs/gtk/Controller.cpp new file mode 100644 index 00000000..05ebe84a --- /dev/null +++ b/src/progs/gtk/Controller.cpp @@ -0,0 +1,173 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PatchModel.h" +#include "PatchController.h" +#include "ControlInterface.h" +#include "OSCModelEngineInterface.h" +#include "OSCListener.h" +//#include "GtkClientInterface.h" +#include "PatchLibrarian.h" +#include "Controller.h" +#include "Loader.h" +#include "interface/ClientKey.h" + +namespace OmGtk { + + +Controller::Controller(const string& engine_url) +: OSCModelEngineInterface(engine_url), + m_patch_librarian(new PatchLibrarian(this)), + m_loader(new Loader(m_patch_librarian)) +{ + m_loader->launch(); +} + + +Controller::~Controller() +{ + if (is_attached()) { + unregister_client(ClientKey()); // FIXME + detach(); + } + + delete m_loader; + delete m_patch_librarian; +} + + +/** "Attach" to the Om engine. + * See documentation OSCModelEngineInterface::attach. + */ +void +Controller::attach() +{ + OSCModelEngineInterface::attach(false); +} + +/* +void +Controller::register_client_and_wait() +{ +// int id = get_next_request_id(); +// set_wait_response_id(id); + OSCModelEngineInterface::register_client(); +// wait_for_response(); + cout << "[Controller] Registered with engine. maybe. fixme." << endl; +} +*/ +void Controller::set_engine_url(const string& url) { _engine_url = url; } + +void +Controller::create_node_from_model(const NodeModel* nm) +{ + //push_added_node(nm); + OSCModelEngineInterface::create_node_from_model(nm); + char temp_buf[16]; + snprintf(temp_buf, 16, "%f", nm->x()); + set_metadata(nm->path(), "module-x", temp_buf); + snprintf(temp_buf, 16, "%f", nm->y()); + set_metadata(nm->path(), "module-y", temp_buf); +} + +void +Controller::create_patch_from_model(const PatchModel* pm) +{ + //push_added_patch(pm); + + //int id = get_next_request_id(); + //set_wait_response_id(id); + create_patch_from_model(pm); + if (pm->parent() != NULL) { + // wait_for_response(); + char temp_buf[16]; + snprintf(temp_buf, 16, "%f", pm->x()); + set_metadata(pm->path(), "module-x", temp_buf); + snprintf(temp_buf, 16, "%f", pm->y()); + set_metadata(pm->path(), "module-y", temp_buf); + } + enable_patch(pm->path()); +} + + +void +Controller::set_patch_path(const string& path) +{ + m_patch_librarian->path(path); +} + + +/** Load patch in a seperate thread. + * This will return immediately and the patch will be loaded in the background. + * FIXME: merge parameter makes no sense, always true */ +void +Controller::load_patch(PatchModel* model, bool wait, bool merge) +{ + //push_added_patch(model); + m_loader->load_patch(model, wait, merge); +} + + +/** Load patch in a seperate thread. + * This will return immediately and the patch will be saved in the background. */ +void +Controller::save_patch(PatchModel* model, const string& filename, bool recursive) +{ + m_loader->save_patch(model, filename, recursive); +} + + +#if 0 +/** Returns the added node with the given path and removes it from the cache. + */ +NodeModel* +Controller::yank_added_node(const string& path) +{ + NodeModel* nm = NULL; + + for (list<NodeModel*>::iterator i = m_added_nodes.begin(); i != m_added_nodes.end(); ++i) { + if ((*i)->path() == path) { + nm = *i; + m_added_nodes.erase(i); + break; + } + } + + return nm; +} + + +/** Returns the added patch with the given path and removes it from the cache. + */ +PatchModel* +Controller::yank_added_patch(const string& path) +{ + PatchModel* pm = NULL; + + for (list<PatchModel*>::iterator i = m_added_patches.begin(); i != m_added_patches.end(); ++i) { + if ((*i)->path() == path) { + pm = *i; + m_added_patches.erase(i); + break; + } + } + + return pm; +} +#endif + +} // namespace OmGtk + diff --git a/src/progs/gtk/Controller.h b/src/progs/gtk/Controller.h new file mode 100644 index 00000000..fd516992 --- /dev/null +++ b/src/progs/gtk/Controller.h @@ -0,0 +1,112 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONTROLLER_H +#define CONTROLLER_H + +#include <cassert> +#include <string> +#include <list> +#include <glibmm.h> +#include "PluginModel.h" +#include "OSCModelEngineInterface.h" + +namespace LibOmClient { +class PatchModel; +class NodeModel; +class PatchLibrarian; +} + +using std::string; using std::list; +using namespace LibOmClient; + +namespace OmGtk { + +class PatchController; +//class GtkClientInterface; +class Loader; + + +/** Singleton engine controller for the entire app. + * + * This is hardly more than a trivial wrapper for OSCModelEngineInterface, suggesting something + * needs a rethink around here.. + * + * This needs to be either eliminated or the name changed to OmController. Probably + * best to keep around in case multiple engine control support comes around? + * + * \ingroup OmGtk + */ +class Controller : public OSCModelEngineInterface +{ +public: + ~Controller(); + + void attach(); + + //void register_client_and_wait(); + + void set_engine_url(const string& url); + + void create_node_from_model(const NodeModel* nm); + + void load_patch(PatchModel* model, bool wait = true, bool merge = false); + void save_patch(PatchModel* model, const string& filename, bool recursive); + + void create_patch_from_model(const PatchModel* pm); + + //void lash_restore_finished(); + + void set_patch_path(const string& path); + + /* + void push_added_node(NodeModel* nm) { m_added_nodes.push_back(nm); } + NodeModel* yank_added_node(const string& path); + + void push_added_patch(PatchModel* pm) { m_added_patches.push_back(pm); } + PatchModel* yank_added_patch(const string& path); + */ + //GtkClientInterface* client_hooks() { return (GtkClientInterface*)m_client_hooks; } + + static void instantiate(const string& engine_url) + { if (!_instance) _instance = new Controller(engine_url); } + + inline static Controller& instance() { assert(_instance); return *_instance; } + +private: + Controller(const string& engine_url); + static Controller* _instance; + + PatchLibrarian* m_patch_librarian; + Loader* m_loader; + + /** Used to cache added nodes so client can remember some values when the + * new node notification comes (location, etc). Used to prevent the node + * jumping locations during the delay between new node and the module-x/y + * metadata notifications */ + //list<NodeModel*> m_added_nodes; + + /** Used to cache added patches in the same was as m_added_nodes. Used to + * rember filename so File->Save can work without prompting (filename can't + * be sent to the server as metadata, because a client on another machine + * doesn't want that information) */ + //list<PatchModel*> m_added_patches; +}; + + +} // namespace OmGtk + +#endif // CONTROLLER_H diff --git a/src/progs/gtk/DSSIController.cpp b/src/progs/gtk/DSSIController.cpp new file mode 100644 index 00000000..570211c7 --- /dev/null +++ b/src/progs/gtk/DSSIController.cpp @@ -0,0 +1,280 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DSSIController.h" +#include <iomanip> +#include <sstream> +#include <dirent.h> +#include <unistd.h> +#include <sys/stat.h> +#include "NodeModel.h" +#include "DSSIModule.h" +#include "Controller.h" + +namespace OmGtk { + + +DSSIController::DSSIController(NodeModel* model) +: NodeController(model), + m_banks_dirty(true) +{ + assert(model->plugin()->type() == PluginModel::DSSI); + Gtk::Menu::MenuList& items = m_menu.items(); + items[0].property_sensitive() = true; // "Show Control Window" item + + Gtk::Menu_Helpers::MenuElem program_elem("Select Program", m_program_menu); + items.push_front(program_elem); + m_program_menu_item = program_elem.get_child(); + m_program_menu_item->set_sensitive(false); + + items.push_front(Gtk::Menu_Helpers::MenuElem("Show Plugin GUI", + sigc::mem_fun(this, &DSSIController::show_gui))); +} + +void +DSSIController::program_add(int bank, int program, const string& name) +{ + node_model()->add_program(bank, program, name); + m_banks_dirty = true; +} + + +void +DSSIController::program_remove(int bank, int program) +{ + node_model()->remove_program(bank, program); + m_banks_dirty = true; +} + +/** Trivial wrapper of attempt_to_show_gui for libsigc + */ +void +DSSIController::show_gui() +{ + attempt_to_show_gui(); +} + + +void +DSSIController::update_program_menu() +{ + m_program_menu.items().clear(); + + const map<int, map<int, string> >& banks = node_model()->get_programs(); + std::ostringstream oss; + + map<int, map<int, string> >::const_iterator i; + for (i = banks.begin(); i != banks.end(); ++i) { + Gtk::Menu* bank_menu; + if (banks.size() > 1) + bank_menu = manage(new Gtk::Menu()); + else + bank_menu = &m_program_menu; + map<int, string>::const_iterator j; + for (j = i->second.begin(); j != i->second.end(); ++j) { + oss.str(""); + oss << std::setw(3) << std::setfill('0') + << j->first << ' ' << j->second; + sigc::slot<void> slt = bind( + bind(sigc::mem_fun(*this, &DSSIController::send_program_change), + j->first), i->first); + bank_menu->items().push_back( + Gtk::Menu_Helpers::MenuElem(oss.str(), slt)); + } + if (banks.size() > 1) { + oss.str(""); + oss << "Bank " << i->first; + m_program_menu.items().push_back( + Gtk::Menu_Helpers::MenuElem(oss.str(), *bank_menu)); + } + } + + // Disable the program menu if there are no programs + if (banks.size() == 0) + m_program_menu_item->set_sensitive(false); + else + m_program_menu_item->set_sensitive(true); + + m_banks_dirty = false; +} + + +void +DSSIController::send_program_change(int bank, int program) +{ + Controller::instance().set_program(node_model()->path(), bank, program); +} + + +void +DSSIController::create_module(OmFlowCanvas* canvas) +{ + //cerr << "Creating DSSI module " << m_model->path() << endl; + + assert(canvas != NULL); + assert(m_module == NULL); + + m_module = new DSSIModule(canvas, this); + create_all_ports(); + + m_module->move_to(node_model()->x(), node_model()->y()); +} + + + +/** Attempt to show the DSSI GUI for this plugin. + * + * Returns whether or not GUI was successfully loaded/shown. + */ +bool +DSSIController::attempt_to_show_gui() +{ + // Shamelessley "inspired by" jack-dssi-host + // Copyright 2004 Chris Cannam, Steve Harris and Sean Bolton. + + const bool verbose = false; + + string engine_url = Controller::instance().engine_url(); + // Hack off last character if it's a / + if (engine_url[engine_url.length()-1] == '/') + engine_url = engine_url.substr(0, engine_url.length()-1); + + const char* dllName = node_model()->plugin()->lib_name().c_str(); + const char* label = node_model()->plugin()->plug_label().c_str(); + const char* myName = "om_gtk"; + const string& oscUrl = engine_url + "/dssi" + node_model()->path(); + + struct dirent* entry = NULL; + char* dllBase = strdup(dllName); + char* subpath = NULL; + DIR* subdir = NULL; + char* filename = NULL; + struct stat buf; + int fuzzy = 0; + + char* env_dssi_path = getenv("DSSI_PATH"); + string dssi_path; + if (!env_dssi_path) { + cerr << "DSSI_PATH is empty. Assuming /usr/lib/dssi:/usr/local/lib/dssi." << endl; + dssi_path = "/usr/lib/dssi:/usr/local/lib/dssi"; + } else { + dssi_path = env_dssi_path; + } + + if (strlen(dllBase) > 3 && !strcasecmp(dllBase + strlen(dllBase) - 3, ".so")) { + dllBase[strlen(dllBase) - 3] = '\0'; + } + + + // This is pretty nasty, it loops through the path, even if the dllBase is absolute + while (dssi_path != "") { + string directory = dssi_path.substr(0, dssi_path.find(':')); + if (dssi_path.find(':') != string::npos) + dssi_path = dssi_path.substr(dssi_path.find(':')+1); + else + dssi_path = ""; + + if (*dllBase == '/') { + subpath = strdup(dllBase); + } else { + subpath = (char*)malloc(strlen(directory.c_str()) + strlen(dllBase) + 2); + sprintf(subpath, "%s/%s", directory.c_str(), dllBase); + } + + for (fuzzy = 0; fuzzy <= 1; ++fuzzy) { + + if (!(subdir = opendir(subpath))) { + if (verbose) { + fprintf(stderr, "%s: can't open plugin GUI directory \"%s\"\n", myName, subpath); + } + break; + } + + while ((entry = readdir(subdir))) { + + if (entry->d_name[0] == '.') + continue; + if (!strchr(entry->d_name, '_')) + continue; + + if (fuzzy) { + if (verbose) { + fprintf(stderr, "checking %s against %s\n", entry->d_name, dllBase); + } + if (strncmp(entry->d_name, dllBase, strlen(dllBase))) + continue; + } else { + if (verbose) { + fprintf(stderr, "checking %s against %s\n", entry->d_name, label); + } + if (strncmp(entry->d_name, label, strlen(label))) + continue; + } + + filename = (char*)malloc(strlen(subpath) + strlen(entry->d_name) + 2); + sprintf(filename, "%s/%s", subpath, entry->d_name); + + if (stat(filename, &buf)) { + perror("stat failed"); + free(filename); + continue; + } + + if ((S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode)) && + (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { + + if (verbose) { + fprintf(stderr, "%s: trying to execute GUI at \"%s\"\n", + myName, filename); + } + + if (fork() == 0) { + execlp(filename, filename, oscUrl.c_str(), dllName, label, + node_model()->name().c_str(), 0); + perror("exec failed"); + exit(1); + } + + free(filename); + free(subpath); + free(dllBase); + return true; + } + + free(filename); + } + } + } + + cerr << "Unable to launch DSSI GUI for " << node_model()->path() << endl; + + free(subpath); + free(dllBase); + return false; +} + + +void +DSSIController::show_menu(GdkEventButton* event) +{ + if (m_banks_dirty) + update_program_menu(); + NodeController::show_menu(event); +} + + +} // namespace OmGtk + diff --git a/src/progs/gtk/DSSIController.h b/src/progs/gtk/DSSIController.h new file mode 100644 index 00000000..53f6fc8b --- /dev/null +++ b/src/progs/gtk/DSSIController.h @@ -0,0 +1,79 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DSSICONTROLLER_H +#define DSSICONTROLLER_H + +#include <string> +#include <gtkmm.h> +#include "util/Path.h" +#include "NodeController.h" + +using std::string; +using Om::Path; +using namespace LibOmClient; + +namespace LibOmClient { + class MetadataModel; + class NodeModel; + class PortModel; +} + +namespace OmGtk { + +class Controller; +class OmModule; +class NodeControlWindow; +class NodePropertiesWindow; +class PortController; +class OmFlowCanvas; +class DSSIModule; + +/* Controller for a DSSI node. + * + * \ingroup OmGtk + */ +class DSSIController : public NodeController +{ +public: + DSSIController(NodeModel* model); + + virtual ~DSSIController() {} + + void show_gui(); + bool attempt_to_show_gui(); + void program_add(int bank, int program, const string& name); + void program_remove(int bank, int program); + + void send_program_change(int bank, int program); + + void create_module(OmFlowCanvas* canvas); + + void show_menu(GdkEventButton* event); + +private: + void update_program_menu(); + + Gtk::Menu m_program_menu; + Glib::RefPtr<Gtk::MenuItem> m_program_menu_item; + + bool m_banks_dirty; +}; + + +} // namespace OmGtk + +#endif // DSSICONTROLLER_H diff --git a/src/progs/gtk/DSSIModule.cpp b/src/progs/gtk/DSSIModule.cpp new file mode 100644 index 00000000..7dae48ac --- /dev/null +++ b/src/progs/gtk/DSSIModule.cpp @@ -0,0 +1,38 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "DSSIModule.h" +#include "DSSIController.h" + +namespace OmGtk { + + +DSSIModule::DSSIModule(OmFlowCanvas* canvas, DSSIController* node) +: OmModule(canvas, static_cast<NodeController*>(node)) +{ +} + + +void +DSSIModule::on_double_click(GdkEventButton* ev) +{ + DSSIController* const dc = static_cast<DSSIController*>(m_node); + if (!dc->attempt_to_show_gui()) + show_control_window(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/DSSIModule.h b/src/progs/gtk/DSSIModule.h new file mode 100644 index 00000000..2ad10c04 --- /dev/null +++ b/src/progs/gtk/DSSIModule.h @@ -0,0 +1,43 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DSSIMODULE_H +#define DSSIMODULE_H + +#include "OmModule.h" + +namespace OmGtk { + +class DSSIController; + +/* Module for a DSSI node. + * + * \ingroup OmGtk + */ +class DSSIModule : public OmModule +{ +public: + DSSIModule(OmFlowCanvas* canvas, DSSIController* node); + virtual ~DSSIModule() {} + + void on_double_click(GdkEventButton* ev); +}; + + +} // namespace OmGtk + +#endif // DSSIMODULE_H + diff --git a/src/progs/gtk/GladeFactory.cpp b/src/progs/gtk/GladeFactory.cpp new file mode 100644 index 00000000..e930c4c4 --- /dev/null +++ b/src/progs/gtk/GladeFactory.cpp @@ -0,0 +1,69 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "GladeFactory.h" +#include <iostream> +#include <fstream> +using std::cout; using std::cerr; using std::endl; +using std::ifstream; + +namespace OmGtk { + + +Glib::ustring GladeFactory::glade_filename = ""; + + +void +GladeFactory::find_glade_file() +{ + // Check for the .glade file in current directory + glade_filename = "./om_gtk.glade"; + ifstream fs(glade_filename.c_str()); + if (fs.fail()) { // didn't find it, check PKGDATADIR + fs.clear(); + glade_filename = PKGDATADIR; + glade_filename += "/om_gtk.glade"; + + fs.open(glade_filename.c_str()); + if (fs.fail()) { + cerr << "[GladeFactory] Unable to find om_gtk.glade in current directory or " << PKGDATADIR << "." << endl; + throw; + } + fs.close(); + } + cerr << "[GladeFactory] Loading widgets from " << glade_filename.c_str() << endl; +} + + +Glib::RefPtr<Gnome::Glade::Xml> +GladeFactory::new_glade_reference(const string& toplevel_widget) +{ + if (glade_filename == "") + find_glade_file(); + + try { + if (toplevel_widget == "") + return Gnome::Glade::Xml::create(glade_filename); + else + return Gnome::Glade::Xml::create(glade_filename, toplevel_widget.c_str()); + } catch (const Gnome::Glade::XmlError& ex) { + cerr << ex.what() << endl; + throw ex; + } +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/GladeFactory.h b/src/progs/gtk/GladeFactory.h new file mode 100644 index 00000000..a3ee1022 --- /dev/null +++ b/src/progs/gtk/GladeFactory.h @@ -0,0 +1,48 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GLADEFACTORY_H +#define GLADEFACTORY_H + +#include <string> +#include <libglademm/xml.h> + +using std::string; + +namespace OmGtk { + + +/** Creates glade references, so various objects can create widgets. + * Purely static. + * + * \ingroup OmGtk + */ +class GladeFactory { +public: + static Glib::RefPtr<Gnome::Glade::Xml> + new_glade_reference(const string& toplevel_widget = ""); + +private: + GladeFactory() {} + + static void find_glade_file(); + static Glib::ustring glade_filename; +}; + + +} // namespace OmGtk + +#endif // GLADEFACTORY_H diff --git a/src/progs/gtk/GtkClientInterface.cpp b/src/progs/gtk/GtkClientInterface.cpp new file mode 100644 index 00000000..7bda1e9e --- /dev/null +++ b/src/progs/gtk/GtkClientInterface.cpp @@ -0,0 +1,81 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "GtkClientInterface.h" +#include <cstdio> +#include <string> +#include <sys/time.h> +#include <time.h> +#include <gtkmm.h> +#include "ControlInterface.h" + +namespace OmGtk { + + +GtkClientInterface::GtkClientInterface(ControlInterface* interface, int client_port) +: OSCListener(client_port) +, ModelClientInterface() +, _interface(interface) +, _num_plugins(0) +, _events(4096) +{ +} + + +/** Push an event (from the engine, ie 'new patch') on to the queue. + */ +void +GtkClientInterface::push_event(Closure ev) +{ + bool success = false; + bool first = true; + + // (Very) slow busy-wait if the queue is full + // FIXME: Make this wait on a signal from process_events iff this happens + while (!success) { + success = _events.push(ev); + if (!success) { + if (first) { + cerr << "[GtkClientInterface] WARNING: (Client) event queue full. Waiting to try again..." << endl; + first = false; + } + usleep(200000); // 100 milliseconds (2* rate process_events is called) + } + } +} + + +/** Process all queued events that came from the OSC thread. + * + * This function is to be called from the Gtk thread only. + */ +bool +GtkClientInterface::process_events() +{ + // Process a maximum of queue-size events, to prevent locking the GTK + // thread indefinitely while processing continually arriving events + size_t num_processed = 0; + while (!_events.is_empty() && num_processed++ < _events.capacity()/2) { + Closure& ev = _events.pop(); + ev(); + ev.disconnect(); + } + + return true; +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/GtkClientInterface.h b/src/progs/gtk/GtkClientInterface.h new file mode 100644 index 00000000..7214ef19 --- /dev/null +++ b/src/progs/gtk/GtkClientInterface.h @@ -0,0 +1,156 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GTKCLIENTHOOKS_H +#define GTKCLIENTHOOKS_H + +#include <cassert> +#include <string> +#include <queue> +#include <iostream> +#include <sigc++/sigc++.h> +#include "ControlInterface.h" +#include "OSCListener.h" +#include "util/Queue.h" +#include "util/CountedPtr.h" +#include "ModelClientInterface.h" +#include "SigClientInterface.h" +using std::string; +using std::cerr; using std::endl; + +namespace LibOmClient { class PluginModel; } +using namespace LibOmClient; + +namespace OmGtk { + +/** Returns nothing and takes no parameters (because they have been bound) */ +typedef sigc::slot<void> Closure; + +#if 0 +/** ModelClientInterface implementation for the Gtk client. + * + * This is a threadsafe interface to OmGtk. It provides the same interface as + * @ref ControlInterface, except all public functions may be called in a thread + * other than the GTK thread (a closure will be created and pushed through a + * queue for the GTK thread to execute). + * + * It is also a ModelClientInterface, which is how it is driven by the engine. + * This is redundant, "ControlInterface" needs to go away. A model database + * that wraps a ClientInterface and emits sigc signals when things change would + * be a much better way of doing this. + * + * \ingroup OmGtk + */ +class GtkClientInterface : public OSCListener, public ModelClientInterface +{ +public: + GtkClientInterface(ControlInterface* interface, int client_port); + + void set_ignore_port(const string& path) { _ignore_port_path = path; } + void clear_ignore_port() { _ignore_port_path = ""; } + + // FIXME: ugly accessor + size_t num_plugins() const { return _num_plugins; } + + // OSC thread functions (deferred calls) + + void bundle_begin() {} + void bundle_end() {} + + void num_plugins(size_t num) { _num_plugins = num; } + + void error(const string& msg) + { push_event(sigc::bind(_interface->error_slot, msg)); } + + void new_plugin_model(PluginModel* const pm) + { push_event(sigc::bind(_interface->new_plugin_slot, pm)); } + + void new_patch_model(PatchModel* const pm) + { push_event(sigc::bind(_interface->new_patch_slot, pm)); } + + void new_node_model(NodeModel* const nm) + { assert(nm); push_event(sigc::bind(_interface->new_node_slot, nm)); } + + void new_port_model(PortModel* const pm) + { push_event(sigc::bind(_interface->new_port_slot, pm)); } + + void connection_model(ConnectionModel* const cm) + { push_event(sigc::bind(_interface->connection_slot, cm)); } + + void object_destroyed(const string& path) + { push_event(sigc::bind(_interface->object_destroyed_slot, path)); } + + void patch_enabled(const string& path) + { push_event(sigc::bind(_interface->patch_enabled_slot, path)); } + + void patch_disabled(const string& path) + { push_event(sigc::bind(_interface->patch_disabled_slot, path)); } + + void patch_cleared(const string& path) + { push_event(sigc::bind(_interface->patch_cleared_slot, path)); } + + void object_renamed(const string& old_path, const string& new_path) + { push_event(sigc::bind(_interface->object_renamed_slot, old_path, new_path)); } + + void disconnection(const string& src_port_path, const string& dst_port_path) + { push_event(sigc::bind(_interface->disconnection_slot, src_port_path, dst_port_path)); } + + void metadata_update(const string& path, const string& key, const string& value) + { push_event(sigc::bind(_interface->metadata_update_slot, path, key, value)); } + + void control_change(const string& port_path, float value) + { push_event(sigc::bind(_interface->control_change_slot, port_path, value)); } + + void program_add(const string& path, uint32_t bank, uint32_t program, const string& name) + { push_event(sigc::bind(_interface->program_add_slot, path, bank, program, name)); } + + void program_remove(const string& path, uint32_t bank, uint32_t program) + { push_event(sigc::bind(_interface->program_remove_slot, path, bank, program)); } + + /** Process all queued events - MUST be called from Gtk thread. + * Registered as a GTK idle handler by App. */ + bool process_events(); + + static void instantiate(ControlInterface* interface, int client_port) + { if (!_instance) _instance = new GtkClientInterface(interface, client_port); } + + inline static CountedPtr<GtkClientInterface> instance() + { assert(_instance); return _instance; } + +private: + + static CountedPtr<GtkClientInterface> _instance; + + /** Provides the functions/slots the closures will actually call in the GTK thread */ + ControlInterface* _interface; + + size_t _num_plugins; + + void push_event(Closure ev); + + /** Set if a port slider is grabbed and is being dragged. + * If a control event comes in for a port with this path, we'll just + * ignore it outright. (Just an optimization over doing all the searching + * for the port slider just to ignore the event) */ + string _ignore_port_path; + + Queue<Closure> _events; +}; +#endif + +} // namespace OmGtk + +#endif // GTKCLIENTHOOKS_H diff --git a/src/progs/gtk/GtkObjectController.cpp b/src/progs/gtk/GtkObjectController.cpp new file mode 100644 index 00000000..7277d346 --- /dev/null +++ b/src/progs/gtk/GtkObjectController.cpp @@ -0,0 +1,40 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "GtkObjectController.h" + +namespace OmGtk { + + +GtkObjectController::GtkObjectController(ObjectModel* model) +: m_model(model) +{ + assert(m_model != NULL); +} + + +/** Derived classes should override this to handle special metadata + * keys, then call this to set the model's metadata key. + */ +void +GtkObjectController::metadata_update(const string& key, const string& value) +{ + m_model->set_metadata(key, value); +} + + +} // namespace OmGtk + diff --git a/src/progs/gtk/GtkObjectController.h b/src/progs/gtk/GtkObjectController.h new file mode 100644 index 00000000..4a09b9c7 --- /dev/null +++ b/src/progs/gtk/GtkObjectController.h @@ -0,0 +1,77 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef GTKOBJECTCONTROLLER_H +#define GTKOBJECTCONTROLLER_H + +#include <string> +#include <gtkmm.h> + +#include "ObjectModel.h" +#include "ObjectController.h" + + +using std::string; + +using namespace LibOmClient; + +namespace OmGtk { + +class Controller; + + +/** Controller for an Om object. + * + * Management of the model and view are this object's responsibility. + * The view may not be created (ie in the case of patches which have never + * been shown and all their children). + * + * \ingroup OmGtk + */ +class GtkObjectController : public LibOmClient::ObjectController +{ +public: + GtkObjectController(ObjectModel* model); + virtual ~GtkObjectController() {} + + /** Destroy object. + * + * Object must be safe to delete immediately following the return of + * this call. + */ + virtual void destroy() = 0; + + virtual void add_to_store() = 0; + virtual void remove_from_store() = 0; + + virtual void metadata_update(const string& key, const string& value); + + /** Rename object */ + virtual void set_path(const Path& new_path) + { m_model->set_path(new_path); } + + const Path& path() const { return m_model->path(); } + + ObjectModel* model() const { return m_model; } + +protected: + ObjectModel* m_model; ///< Model for this object +}; + + +} // namespace OmGtk + +#endif // GTKOBJECTCONTROLLER_H diff --git a/src/progs/gtk/LashController.cpp b/src/progs/gtk/LashController.cpp new file mode 100644 index 00000000..d95d8515 --- /dev/null +++ b/src/progs/gtk/LashController.cpp @@ -0,0 +1,168 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "LashController.h" +#include "config.h" +#include <iostream> +#include <string> +#include <cassert> +#include <sys/stat.h> +#include <sys/types.h> +#include "App.h" +#include "PatchController.h" +#include "PatchModel.h" + +using std::cerr; using std::cout; using std::endl; +using std::string; + +namespace OmGtk { + + +LashController::LashController(lash_args_t* args) +: m_client(NULL) +{ + m_client = lash_init(args, PACKAGE_NAME, + /*LASH_Config_Data_Set|*/LASH_Config_File, LASH_PROTOCOL(2, 0)); + if (m_client == NULL) { + cerr << "[LashController] Failed to connect to LASH. Session management will not function." << endl; + } else { + cout << "[LashController] Lash initialised" << endl; + } + + lash_event_t* event = lash_event_new_with_type(LASH_Client_Name); + lash_event_set_string(event, "OmGtk"); + lash_send_event(m_client, event); +} + + +LashController::~LashController() +{ + if (m_client != NULL) { + lash_event_t* quit_event = lash_event_new_with_type(LASH_Quit); + lash_send_event(m_client, quit_event); + } +} + + +void +LashController::process_events() +{ + assert(m_client != NULL); + + lash_event_t* ev = NULL; + lash_config_t* conf = NULL; + + // Process events + while ((ev = lash_get_event(m_client)) != NULL) { + handle_event(ev); + lash_event_destroy(ev); + } + + // Process configs + while ((conf = lash_get_config(m_client)) != NULL) { + handle_config(conf); + lash_config_destroy(conf); + } +} + + +void +LashController::handle_event(lash_event_t* ev) +{ + assert(ev != NULL); + + LASH_Event_Type type = lash_event_get_type(ev); + const char* c_str = lash_event_get_string(ev); + string str = (c_str == NULL) ? "" : c_str; + + if (type == LASH_Save_File) { + cout << "[LashController] LASH Save File - " << str << endl; + save(str); + lash_send_event(m_client, lash_event_new_with_type(LASH_Save_File)); + } else if (type == LASH_Restore_File) { + cout << "[LashController] LASH Restore File - " << str << endl; + cerr << "LASH RESTORE NOT YET (RE)IMPLEMENTED." << endl; + /*_controller->load_session_blocking(str + "/session"); + _controller->lash_restore_finished(); + lash_send_event(m_client, lash_event_new_with_type(LASH_Restore_File)); + */ + /*} else if (type == LASH_Save_Data_Set) { + //cout << "[LashController] LASH Save Data Set - " << endl; + + // Tell LASH we're done + lash_send_event(m_client, lash_event_new_with_type(LASH_Save_Data_Set)); + */ + } else if (type == LASH_Quit) { + cout << "[LashController] LASH Quit" << endl; + m_client = NULL; + App::instance().quit(); + } else { + cerr << "[LashController] Unhandled LASH event, type: " << static_cast<int>(type) << endl; + } +} + + +void +LashController::handle_config(lash_config_t* conf) +{ + assert(conf != NULL); + + const char* key = NULL; + const void* val = NULL; + size_t val_size = 0; + + cout << "[LashController] LASH Config. Key = " << key << endl; + + key = lash_config_get_key(conf); + val = lash_config_get_value(conf); + val_size = lash_config_get_value_size(conf); +} + +void +LashController::save(const string& dir) +{ + cerr << "LASH SAVING NOT YET (RE)IMPLEMENTED\n"; + /* + PatchController* pc = NULL; + + // Save every patch under dir with it's path as a filename + // (so the dir structure will resemble the patch heirarchy) + for (map<string,PatchController*>::iterator i = m_app->patches().begin(); + i != m_app->patches().end(); ++i) { + pc = (*i).second; + pc->model()->filename(dir + pc->model()->path() + ".om"); + } + + // Create directories + for (map<string,PatchController*>::iterator i = m_app->patches().begin(); + i != m_app->patches().end(); ++i) { + pc = (*i).second; + if (pc->model()->parent() != NULL) { + string path = OmPath::parent(pc->model()->path()).substr(1) + "/"; + while (path.find("/") != string::npos) { + mkdir(string(dir +"/"+ path.substr(0, path.find("/"))).c_str(), 0744); + path = path.substr(path.find("/")+1); + } + } + _controller->save_patch_blocking(pc->model(), pc->model()->filename(), false); + } + + //m_app->state_manager()->save(str + "/omgtkrc"); + _controller->save_session_blocking(dir + "/session"); + */ +} + +} // namespace OmGtk diff --git a/src/progs/gtk/LashController.h b/src/progs/gtk/LashController.h new file mode 100644 index 00000000..f61c9f7f --- /dev/null +++ b/src/progs/gtk/LashController.h @@ -0,0 +1,53 @@ +/* This file is part of OmGtk. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LASHCONTROLLER_H +#define LASHCONTROLLER_H + +#include <string> +#include <lash/lash.h> +using std::string; + +namespace OmGtk { + +class App; + +/* Old and unused LASH controller. + * + * \ingroup OmGtk + */ +class LashController +{ +public: + LashController(lash_args_t* args); + ~LashController(); + + bool enabled() { return lash_enabled(m_client); } + void process_events(); + +private: + void save(const string& dir); + + lash_client_t* m_client; + + void handle_event(lash_event_t* conf); + void handle_config(lash_config_t* conf); +}; + + +} // namespace OmGtk + +#endif // LASHCONTROLLER_H diff --git a/src/progs/gtk/LoadPatchWindow.cpp b/src/progs/gtk/LoadPatchWindow.cpp new file mode 100644 index 00000000..60f6e15f --- /dev/null +++ b/src/progs/gtk/LoadPatchWindow.cpp @@ -0,0 +1,131 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "LoadPatchWindow.h" +#include <sys/types.h> +#include <dirent.h> +#include "App.h" +#include "Configuration.h" +#include "PatchController.h" +#include "PatchModel.h" +#include "Controller.h" + +namespace OmGtk { + + +LoadPatchWindow::LoadPatchWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml) +: Gtk::FileChooserDialog(cobject), + m_patch_controller(NULL), + m_replace(true) +{ + xml->get_widget("load_patch_poly_from_current_radio", m_poly_from_current_radio); + xml->get_widget("load_patch_poly_from_file_radio", m_poly_from_file_radio); + xml->get_widget("load_patch_poly_from_user_radio", m_poly_from_user_radio); + xml->get_widget("load_patch_poly_spinbutton", m_poly_spinbutton); + xml->get_widget("load_patch_ok_button", m_ok_button); + xml->get_widget("load_patch_cancel_button", m_cancel_button); + + m_poly_from_current_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadPatchWindow::poly_from_file_selected)); + m_poly_from_file_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadPatchWindow::poly_from_file_selected)); + m_poly_from_user_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadPatchWindow::poly_from_user_selected)); + m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &LoadPatchWindow::ok_clicked)); + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &LoadPatchWindow::cancel_clicked)); + + m_poly_from_current_radio->set_active(true); + + Gtk::FileFilter filt; + filt.add_pattern("*.om"); + filt.set_name("Om patch files (*.om)"); + set_filter(filt); + + // Add global examples directory to "shortcut folders" (bookmarks) + string examples_dir = PKGDATADIR; + examples_dir.append("/patches"); + DIR* d = opendir(examples_dir.c_str()); + if (d != NULL) + add_shortcut_folder(examples_dir); +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +LoadPatchWindow::patch_controller(PatchController* pc) +{ + m_patch_controller = pc; +} + + +void +LoadPatchWindow::on_show() +{ + if (App::instance().configuration()->patch_folder().length() > 0) + set_current_folder(App::instance().configuration()->patch_folder()); + Gtk::FileChooserDialog::on_show(); +} + + +///// Event Handlers ////// + + +void +LoadPatchWindow::poly_from_file_selected() +{ + m_poly_spinbutton->property_sensitive() = false; +} + + +void +LoadPatchWindow::poly_from_user_selected() +{ + m_poly_spinbutton->property_sensitive() = true; +} + + +void +LoadPatchWindow::ok_clicked() +{ + // These values are interpreted by load_patch() as "not defined", ie load from file + string name = ""; + int poly = 0; + + if (m_poly_from_user_radio->get_active()) + poly = m_poly_spinbutton->get_value_as_int(); + + if (m_replace) + Controller::instance().clear_patch(m_patch_controller->model()->path()); + + PatchModel* pm = new PatchModel(m_patch_controller->model()->path(), poly); + pm->filename(get_filename()); + pm->set_metadata("filename", get_filename()); + pm->set_parent(m_patch_controller->patch_model()->parent()); + //Controller::instance().push_added_patch(pm); + Controller::instance().load_patch(pm, true, true); + + hide(); +} + + +void +LoadPatchWindow::cancel_clicked() +{ + hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/LoadPatchWindow.h b/src/progs/gtk/LoadPatchWindow.h new file mode 100644 index 00000000..7d7093bd --- /dev/null +++ b/src/progs/gtk/LoadPatchWindow.h @@ -0,0 +1,73 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LOADPATCHWINDOW_H +#define LOADPATCHWINDOW_H + +#include "PluginModel.h" + +#include <libglademm/xml.h> +#include <gtkmm.h> + +namespace OmGtk { + +class PatchController; + + +/** 'Load Patch' window. + * + * Loaded by glade as a derived object. Used for both "Load" and "Load Into" + * operations (the radio button state should be changed with the provided + * methods prior to presenting this window). + * + * This is not for loading subpatches. See @a LoadSubpatchWindow for that. + * + * \ingroup OmGtk + */ +class LoadPatchWindow : public Gtk::FileChooserDialog +{ +public: + LoadPatchWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml); + + void patch_controller(PatchController* pc); + + void set_replace() { m_replace = true; } + void set_merge() { m_replace = false; } + +protected: + void on_show(); + +private: + void poly_from_file_selected(); + void poly_from_user_selected(); + void ok_clicked(); + void cancel_clicked(); + + PatchController* m_patch_controller; + bool m_replace; + + Gtk::RadioButton* m_poly_from_current_radio; + Gtk::RadioButton* m_poly_from_file_radio; + Gtk::RadioButton* m_poly_from_user_radio; + Gtk::SpinButton* m_poly_spinbutton; + Gtk::Button* m_ok_button; + Gtk::Button* m_cancel_button; +}; + + +} // namespace OmGtk + +#endif // LOADPATCHWINDOW_H diff --git a/src/progs/gtk/LoadPluginWindow.cpp b/src/progs/gtk/LoadPluginWindow.cpp new file mode 100644 index 00000000..b84ae39e --- /dev/null +++ b/src/progs/gtk/LoadPluginWindow.cpp @@ -0,0 +1,407 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "LoadPluginWindow.h" +#include <iostream> +#include <cassert> +#include <algorithm> +#include <cctype> +#include "PatchController.h" +#include "NodeModel.h" +#include "Controller.h" +#include "App.h" +#include "PatchWindow.h" +#include "OmFlowCanvas.h" +#include "PatchModel.h" +#include "Store.h" +using std::cout; using std::cerr; using std::endl; + + +namespace OmGtk { + +LoadPluginWindow::LoadPluginWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml) +: Gtk::Window(cobject), + m_patch_controller(NULL), + m_has_shown(false), + m_plugin_name_offset(0), + m_new_module_x(0), + m_new_module_y(0) +{ + xml->get_widget("load_plugin_plugins_treeview", m_plugins_treeview); + xml->get_widget("load_plugin_polyphonic_checkbutton", m_polyphonic_checkbutton); + xml->get_widget("load_plugin_name_entry", m_node_name_entry); + xml->get_widget("load_plugin_clear_button", m_clear_button); + xml->get_widget("load_plugin_add_button", m_add_button); + xml->get_widget("load_plugin_close_button", m_close_button); + //xml->get_widget("load_plugin_ok_button", m_ok_button); + + xml->get_widget("load_plugin_filter_combo", m_filter_combo); + xml->get_widget("load_plugin_search_entry", m_search_entry); + + // Set up the plugins list + m_plugins_liststore = Gtk::ListStore::create(m_plugins_columns); + m_plugins_treeview->set_model(m_plugins_liststore); + m_plugins_treeview->append_column("Name", m_plugins_columns.m_col_name); + m_plugins_treeview->append_column("Type", m_plugins_columns.m_col_type); + m_plugins_treeview->append_column("URI", m_plugins_columns.m_col_uri); + //m_plugins_treeview->append_column("Library", m_plugins_columns.m_col_library); + //m_plugins_treeview->append_column("Label", m_plugins_columns.m_col_label); + + // This could be nicer.. store the TreeViewColumns locally maybe? + m_plugins_treeview->get_column(0)->set_sort_column(m_plugins_columns.m_col_name); + m_plugins_treeview->get_column(1)->set_sort_column(m_plugins_columns.m_col_type); + m_plugins_treeview->get_column(2)->set_sort_column(m_plugins_columns.m_col_uri); + //m_plugins_treeview->get_column(3)->set_sort_column(m_plugins_columns.m_col_library); + //m_plugins_treeview->get_column(4)->set_sort_column(m_plugins_columns.m_col_label); + for (int i=0; i < 3; ++i) + m_plugins_treeview->get_column(i)->set_resizable(true); + + // Set up the search criteria combobox + m_criteria_liststore = Gtk::ListStore::create(m_criteria_columns); + m_filter_combo->set_model(m_criteria_liststore); + Gtk::TreeModel::iterator iter = m_criteria_liststore->append(); + Gtk::TreeModel::Row row = *iter; + row[m_criteria_columns.m_col_label] = "Name contains: "; + row[m_criteria_columns.m_col_criteria] = CriteriaColumns::NAME; + m_filter_combo->set_active(iter); + iter = m_criteria_liststore->append(); row = *iter; + row[m_criteria_columns.m_col_label] = "Type contains: "; + row[m_criteria_columns.m_col_criteria] = CriteriaColumns::TYPE; + iter = m_criteria_liststore->append(); row = *iter; + row[m_criteria_columns.m_col_label] = "URI contains: "; + row[m_criteria_columns.m_col_criteria] = CriteriaColumns::URI; + /*iter = m_criteria_liststore->append(); row = *iter; + row[m_criteria_columns.m_col_label] = "Library contains: "; + row[m_criteria_columns.m_col_criteria] = CriteriaColumns::LIBRARY; + iter = m_criteria_liststore->append(); row = *iter; + row[m_criteria_columns.m_col_label] = "Label contains: "; + row[m_criteria_columns.m_col_criteria] = CriteriaColumns::LABEL;*/ + + m_clear_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::clear_clicked)); + m_add_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::add_clicked)); + m_close_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::close_clicked)); + //m_ok_button->signal_clicked().connect( sigc::mem_fun(this, &LoadPluginWindow::ok_clicked)); + m_plugins_treeview->signal_row_activated().connect(sigc::mem_fun(this, &LoadPluginWindow::plugin_activated)); + m_search_entry->signal_activate().connect( sigc::mem_fun(this, &LoadPluginWindow::add_clicked)); + m_search_entry->signal_changed().connect( sigc::mem_fun(this, &LoadPluginWindow::filter_changed)); + + m_selection = m_plugins_treeview->get_selection(); + m_selection->signal_changed().connect(sigc::mem_fun(this, &LoadPluginWindow::plugin_selection_changed)); + + //m_add_button->grab_default(); +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +LoadPluginWindow::patch_controller(PatchController* pc) +{ + m_patch_controller = pc; + + if (pc->patch_model()->poly() <= 1) + m_polyphonic_checkbutton->property_sensitive() = false; + else + m_polyphonic_checkbutton->property_sensitive() = true; + +} + + +/** Populates the plugin list on the first show. + * + * This is done here instead of construction time as the list population is + * really expensive and bogs down creation of a patch. This is especially + * important when many patch notifications are sent at one time from the + * engine. + */ +void +LoadPluginWindow::on_show() +{ + if (!m_has_shown) { + set_plugin_model(Store::instance().plugins()); + + // Center on patch window + int m_w, m_h; + get_size(m_w, m_h); + + int parent_x, parent_y, parent_w, parent_h; + m_patch_controller->window()->get_position(parent_x, parent_y); + m_patch_controller->window()->get_size(parent_w, parent_h); + + move(parent_x + parent_w/2 - m_w/2, parent_y + parent_h/2 - m_h/2); + + m_has_shown = true; + } + Gtk::Window::on_show(); +} + + +void +LoadPluginWindow::on_hide() +{ + m_new_module_x = 0; + m_new_module_y = 0; + Gtk::Window::on_hide(); +} + + +void +LoadPluginWindow::set_plugin_model(const std::map<string, const PluginModel*>& m) +{ + m_plugins_liststore->clear(); + + const PluginModel* plugin = NULL; + for (std::map<string, const PluginModel*>::const_iterator i = m.begin(); i != m.end(); ++i) { + plugin = (*i).second; + + Gtk::TreeModel::iterator iter = m_plugins_liststore->append(); + Gtk::TreeModel::Row row = *iter; + + row[m_plugins_columns.m_col_name] = plugin->name(); + //row[m_plugins_columns.m_col_label] = plugin->plug_label(); + row[m_plugins_columns.m_col_type] = plugin->type_string(); + row[m_plugins_columns.m_col_uri] = plugin->uri(); + row[m_plugins_columns.m_col_label] = plugin->name(); + //row[m_plugins_columns.m_col_library] = plugin->lib_name(); + row[m_plugins_columns.m_col_plugin_model] = plugin; + } + + m_plugins_treeview->columns_autosize(); +} + + +void +LoadPluginWindow::add_plugin(const PluginModel* const plugin) +{ + Gtk::TreeModel::iterator iter = m_plugins_liststore->append(); + Gtk::TreeModel::Row row = *iter; + + row[m_plugins_columns.m_col_name] = plugin->name(); + //row[m_plugins_columns.m_col_label] = plugin->plug_label(); + row[m_plugins_columns.m_col_type] = plugin->type_string(); + row[m_plugins_columns.m_col_uri] = plugin->uri(); + row[m_plugins_columns.m_col_label] = plugin->name(); + //row[m_plugins_columns.m_col_library] = plugin->lib_name(); + row[m_plugins_columns.m_col_plugin_model] = plugin; +} + + + +///// Event Handlers ////// + + +void +LoadPluginWindow::plugin_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* col) +{ + add_clicked(); +} + + +void +LoadPluginWindow::plugin_selection_changed() +{ + m_plugin_name_offset = 0; + + m_node_name_entry->set_text(generate_module_name()); + + //Gtk::TreeModel::iterator iter = m_selection->get_selected(); + //Gtk::TreeModel::Row row = *iter; + //const PluginModel* plugin = row.get_value(m_plugins_columns.m_col_plugin_model); +} + + +/** Generate an automatic name for this Node. + * + * Offset is an offset of the number that will be appended to the plugin's + * label, needed if the user adds multiple plugins faster than the engine + * sends the notification back. + */ +string +LoadPluginWindow::generate_module_name(int offset) +{ + string name = ""; + + Gtk::TreeModel::iterator iter = m_selection->get_selected(); + + if (iter) { + Gtk::TreeModel::Row row = *iter; + const PluginModel* const plugin = row.get_value(m_plugins_columns.m_col_plugin_model); + char num_buf[3]; + for (uint i=0; i < 99; ++i) { + name = plugin->plug_label(); + if (name == "") + name = plugin->name().substr(0, plugin->name().find(' ')); + if (i+offset != 0) { + snprintf(num_buf, 3, "%d", i+offset+1); + name += "_"; + name += num_buf; + } + if (m_patch_controller->patch_model()->get_node(name) == NULL) + break; + else + name = ""; + } + } + + return name; +} + + +void +LoadPluginWindow::add_clicked() +{ + Gtk::TreeModel::iterator iter = m_selection->get_selected(); + bool polyphonic = m_polyphonic_checkbutton->get_active(); + + if (iter) { // If anything is selected + Gtk::TreeModel::Row row = *iter; + const PluginModel* const plugin = row.get_value(m_plugins_columns.m_col_plugin_model); + string name = m_node_name_entry->get_text(); + if (name == "") { + name = generate_module_name(); + } + if (name == "") { + Gtk::MessageDialog dialog(*this, + "Unable to chose a default name for this node. Please enter a name.", + false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + + dialog.run(); + } else { + const string path = m_patch_controller->model()->base_path() + name; + NodeModel* nm = new NodeModel(path); + nm->plugin(plugin); + nm->polyphonic(polyphonic); + + if (m_new_module_x == 0 && m_new_module_y == 0) { + m_patch_controller->get_new_module_location( + m_new_module_x, m_new_module_y); + } + nm->x(m_new_module_x); + nm->y(m_new_module_y); + + Controller::instance().create_node_from_model(nm); + ++m_plugin_name_offset; + m_node_name_entry->set_text(generate_module_name(m_plugin_name_offset)); + + // Set the next module location 20 over, for a cascade effect + m_new_module_x += 20; + m_new_module_y += 20; + } + } +} + + +void +LoadPluginWindow::close_clicked() +{ + hide(); +} + + +/* +void +LoadPluginWindow::ok_clicked() +{ + add_clicked(); + close_clicked(); +} +*/ + +void +LoadPluginWindow::filter_changed() +{ + m_plugins_liststore->clear(); + + string search = m_search_entry->get_text(); + transform(search.begin(), search.end(), search.begin(), toupper); + + // Get selected criteria + const Gtk::TreeModel::Row row = *(m_filter_combo->get_active()); + CriteriaColumns::Criteria criteria = row[m_criteria_columns.m_col_criteria]; + + string field; + + Gtk::TreeModel::Row model_row; + Gtk::TreeModel::iterator model_iter; + size_t num_visible = 0; + + const PluginModel* plugin = NULL; + for (std::map<string, const PluginModel*>::const_iterator i = Store::instance().plugins().begin(); + i != Store::instance().plugins().end(); ++i) { + plugin = (*i).second; + + switch (criteria) { + case CriteriaColumns::NAME: + field = plugin->name(); break; + case CriteriaColumns::TYPE: + field = plugin->type_string(); break; + case CriteriaColumns::URI: + field = plugin->uri(); break; + /*case CriteriaColumns::LIBRARY: + field = plugin->lib_name(); break; + case CriteriaColumns::LABEL: + field = plugin->plug_label(); break;*/ + default: + throw; + } + + transform(field.begin(), field.end(), field.begin(), toupper); + + if (field.find(search) != string::npos) { + model_iter = m_plugins_liststore->append(); + model_row = *model_iter; + + model_row[m_plugins_columns.m_col_name] = plugin->name(); + //model_row[m_plugins_columns.m_col_label] = plugin->plug_label(); + model_row[m_plugins_columns.m_col_type] = plugin->type_string(); + model_row[m_plugins_columns.m_col_uri] = plugin->uri(); + model_row[m_plugins_columns.m_col_label] = plugin->plug_label(); + //model_row[m_plugins_columns.m_col_library] = plugin->lib_name(); + model_row[m_plugins_columns.m_col_plugin_model] = plugin; + + ++num_visible; + } + } + + if (num_visible == 1) { + m_selection->unselect_all(); + m_selection->select(model_iter); + } +} + + +void +LoadPluginWindow::clear_clicked() +{ + m_search_entry->set_text(""); + set_plugin_model(Store::instance().plugins()); +} + +bool +LoadPluginWindow::on_key_press_event(GdkEventKey* event) +{ + if (event->keyval == GDK_w && event->state & GDK_CONTROL_MASK) { + hide(); + return true; + } else { + return Gtk::Window::on_key_press_event(event); + } +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/LoadPluginWindow.h b/src/progs/gtk/LoadPluginWindow.h new file mode 100644 index 00000000..adf11ab4 --- /dev/null +++ b/src/progs/gtk/LoadPluginWindow.h @@ -0,0 +1,145 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef LOADPLUGINWINDOW_H +#define LOADPLUGINWINDOW_H + +#include "PluginModel.h" +#include <map> +#include <libglademm/xml.h> +#include <libglademm.h> +#include <gtkmm.h> + + +using LibOmClient::PluginModel; + +namespace OmGtk { + +class PatchController; + +// Gtkmm _really_ needs to add some helper to abstract away this stupid nonsense + +/** Columns for the plugin list in the load plugin window. + * + * \ingroup OmGtk + */ +class ModelColumns : public Gtk::TreeModel::ColumnRecord +{ +public: + ModelColumns() { + add(m_col_name); + add(m_col_type); + add(m_col_uri); + add(m_col_label); + //add(m_col_library); + //add(m_col_label); + add(m_col_plugin_model); + } + + Gtk::TreeModelColumn<Glib::ustring> m_col_name; + Gtk::TreeModelColumn<Glib::ustring> m_col_type; + Gtk::TreeModelColumn<Glib::ustring> m_col_uri; + + // Not displayed: + Gtk::TreeModelColumn<Glib::ustring> m_col_label; + Gtk::TreeModelColumn<const PluginModel*> m_col_plugin_model; +}; + + +/** Column for the criteria combo box in the load plugin window. + * + * \ingroup OmGtk + */ +class CriteriaColumns : public Gtk::TreeModel::ColumnRecord +{ +public: + enum Criteria { NAME, TYPE, URI, }; + + CriteriaColumns() { add(m_col_label); add(m_col_criteria); } + + Gtk::TreeModelColumn<Glib::ustring> m_col_label; + Gtk::TreeModelColumn<Criteria> m_col_criteria; +}; + + +/** 'Load Plugin' window. + * + * Loaded by glade as a derived object. + * + * \ingroup OmGtk + */ +class LoadPluginWindow : public Gtk::Window +{ +public: + LoadPluginWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml); + + void patch_controller(PatchController* pc); + void set_plugin_model(const std::map<string, const PluginModel*>& m); + + void set_next_module_location(int x, int y) + { m_new_module_x = x; m_new_module_y = y; } + + void add_plugin(const PluginModel* info); + bool has_shown() const { return m_has_shown; } + +protected: + void on_show(); + void on_hide(); + bool on_key_press_event(GdkEventKey* event); + +private: + void add_clicked(); + void close_clicked(); + //void ok_clicked(); + void filter_changed(); + void clear_clicked(); + + void plugin_activated(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* col); + void plugin_selection_changed(); + string generate_module_name(int offset = 0); + + PatchController* m_patch_controller; + bool m_has_shown; // plugin list only populated on show to speed patch window creation + + Glib::RefPtr<Gtk::ListStore> m_plugins_liststore; + ModelColumns m_plugins_columns; + + Glib::RefPtr<Gtk::ListStore> m_criteria_liststore; + CriteriaColumns m_criteria_columns; + + Glib::RefPtr<Gtk::TreeSelection> m_selection; + + int m_plugin_name_offset; // see comments for generate_plugin_name + + int m_new_module_x; + int m_new_module_y; + + Gtk::TreeView* m_plugins_treeview; + Gtk::CheckButton* m_polyphonic_checkbutton; + Gtk::Entry* m_node_name_entry; + Gtk::Button* m_clear_button; + Gtk::Button* m_add_button; + Gtk::Button* m_close_button; + //Gtk::Button* m_ok_button; + Gtk::ComboBox* m_filter_combo; + Gtk::Entry* m_search_entry; +}; + + +} // namespace OmGtk + +#endif // LOADPLUGINWINDOW_H diff --git a/src/progs/gtk/LoadSubpatchWindow.cpp b/src/progs/gtk/LoadSubpatchWindow.cpp new file mode 100644 index 00000000..fe02d772 --- /dev/null +++ b/src/progs/gtk/LoadSubpatchWindow.cpp @@ -0,0 +1,177 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "LoadSubpatchWindow.h" +#include <sys/types.h> +#include <dirent.h> +#include <cassert> +#include "App.h" +#include "PatchController.h" +#include "NodeModel.h" +#include "Controller.h" +#include "PatchModel.h" +#include "Configuration.h" + +namespace OmGtk { + + +LoadSubpatchWindow::LoadSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml) +: Gtk::FileChooserDialog(cobject), + m_patch_controller(NULL), + m_new_module_x(0), + m_new_module_y(0) +{ + xml->get_widget("load_subpatch_name_from_file_radio", m_name_from_file_radio); + xml->get_widget("load_subpatch_name_from_user_radio", m_name_from_user_radio); + xml->get_widget("load_subpatch_name_entry", m_name_entry); + xml->get_widget("load_subpatch_poly_from_file_radio", m_poly_from_file_radio); + xml->get_widget("load_subpatch_poly_from_parent_radio", m_poly_from_parent_radio); + xml->get_widget("load_subpatch_poly_from_user_radio", m_poly_from_user_radio); + xml->get_widget("load_subpatch_poly_spinbutton", m_poly_spinbutton); + xml->get_widget("load_subpatch_ok_button", m_ok_button); + xml->get_widget("load_subpatch_cancel_button", m_cancel_button); + + m_name_from_file_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::disable_name_entry)); + m_name_from_user_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::enable_name_entry)); + m_poly_from_file_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::disable_poly_spinner)); + m_poly_from_parent_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::disable_poly_spinner)); + m_poly_from_user_radio->signal_toggled().connect(sigc::mem_fun(this, &LoadSubpatchWindow::enable_poly_spinner)); + m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &LoadSubpatchWindow::ok_clicked)); + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &LoadSubpatchWindow::cancel_clicked)); + + Gtk::FileFilter filt; + filt.add_pattern("*.om"); + filt.set_name("Om patch files (*.om)"); + set_filter(filt); + + // Add global examples directory to "shortcut folders" (bookmarks) + string examples_dir = PKGDATADIR; + examples_dir.append("/patches"); + DIR* d = opendir(examples_dir.c_str()); + if (d != NULL) + add_shortcut_folder(examples_dir); +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +LoadSubpatchWindow::patch_controller(PatchController* pc) +{ + m_patch_controller = pc; + + char temp_buf[4]; + snprintf(temp_buf, 4, "%zd", pc->patch_model()->poly()); + Glib::ustring txt = "Same as parent ("; + txt.append(temp_buf).append(")"); + m_poly_from_parent_radio->set_label(txt); +} + + +void +LoadSubpatchWindow::on_show() +{ + if (App::instance().configuration()->patch_folder().length() > 0) + set_current_folder(App::instance().configuration()->patch_folder()); + Gtk::FileChooserDialog::on_show(); +} + + +///// Event Handlers ////// + + + +void +LoadSubpatchWindow::disable_name_entry() +{ + m_name_entry->property_sensitive() = false; +} + + +void +LoadSubpatchWindow::enable_name_entry() +{ + m_name_entry->property_sensitive() = true; +} + + +void +LoadSubpatchWindow::disable_poly_spinner() +{ + m_poly_spinbutton->property_sensitive() = false; +} + + +void +LoadSubpatchWindow::enable_poly_spinner() +{ + m_poly_spinbutton->property_sensitive() = true; +} + + +void +LoadSubpatchWindow::ok_clicked() +{ + assert(m_patch_controller != NULL); + assert(m_patch_controller->model() != NULL); + + // These values are interpreted by load_patch() as "not defined", ie load from file + string name = ""; + int poly = 0; + + if (m_name_from_user_radio->get_active()) + name = m_name_entry->get_text(); + + if (m_poly_from_user_radio->get_active()) + poly = m_poly_spinbutton->get_value_as_int(); + else if (m_poly_from_parent_radio->get_active()) + poly = m_patch_controller->patch_model()->poly(); + + if (m_new_module_x == 0 && m_new_module_y == 0) { + m_patch_controller->get_new_module_location( + m_new_module_x, m_new_module_y); + } + + PatchModel* pm = new PatchModel(m_patch_controller->model()->base_path() + name, poly); + pm->filename(get_filename()); + pm->set_parent(m_patch_controller->model()); + pm->x(m_new_module_x); + pm->y(m_new_module_y); + if (name == "") + pm->set_path(""); + char temp_buf[16]; + snprintf(temp_buf, 16, "%d", m_new_module_x); + pm->set_metadata("module-x", temp_buf); + snprintf(temp_buf, 16, "%d", m_new_module_y); + pm->set_metadata("module-y", temp_buf); + Controller::instance().load_patch(pm); + + App::instance().configuration()->set_patch_folder(pm->filename().substr(0, pm->filename().find_last_of("/"))); + + hide(); +} + + +void +LoadSubpatchWindow::cancel_clicked() +{ + hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/LoadSubpatchWindow.h b/src/progs/gtk/LoadSubpatchWindow.h new file mode 100644 index 00000000..45efdd15 --- /dev/null +++ b/src/progs/gtk/LoadSubpatchWindow.h @@ -0,0 +1,78 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef LOADSUBPATCHWINDOW_H +#define LOADSUBPATCHWINDOW_H + +#include "PluginModel.h" +#include <libglademm/xml.h> +#include <gtkmm.h> + + +namespace OmGtk { + +class PatchController; + + +/** 'Add Subpatch' window. + * + * Loaded by glade as a derived object. + * + * \ingroup OmGtk + */ +class LoadSubpatchWindow : public Gtk::FileChooserDialog +{ +public: + LoadSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml); + + void patch_controller(PatchController* pc); + + void set_next_module_location(int x, int y) + { m_new_module_x = x; m_new_module_y = y; } + +protected: + void on_show(); + +private: + void disable_name_entry(); + void enable_name_entry(); + void disable_poly_spinner(); + void enable_poly_spinner(); + + void ok_clicked(); + void cancel_clicked(); + + PatchController* m_patch_controller; + + int m_new_module_x; + int m_new_module_y; + + Gtk::RadioButton* m_name_from_file_radio; + Gtk::RadioButton* m_name_from_user_radio; + Gtk::Entry* m_name_entry; + Gtk::RadioButton* m_poly_from_file_radio; + Gtk::RadioButton* m_poly_from_parent_radio; + Gtk::RadioButton* m_poly_from_user_radio; + Gtk::SpinButton* m_poly_spinbutton; + Gtk::Button* m_ok_button; + Gtk::Button* m_cancel_button; +}; + + +} // namespace OmGtk + +#endif // LOADSUBPATCHWINDOW_H diff --git a/src/progs/gtk/Loader.cpp b/src/progs/gtk/Loader.cpp new file mode 100644 index 00000000..643dc3c9 --- /dev/null +++ b/src/progs/gtk/Loader.cpp @@ -0,0 +1,233 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Loader.h" +#include <fstream> +#include <cassert> +#include <string> +#include "PatchLibrarian.h" +#include "PatchModel.h" +#include "PatchController.h" +using std::cout; using std::endl; + +namespace OmGtk { + + +// LoadPatchEvent // + +void +LoadPatchEvent::execute() +{ + assert(m_patch_librarian != NULL); + m_patch_librarian->load_patch(m_patch_model, m_wait, m_merge); +} + + + +// SavePatchEvent // + +void +SavePatchEvent::execute() +{ + assert(m_patch_librarian != NULL); + m_patch_librarian->save_patch(m_patch_model, m_filename, m_recursive); +} + +/* +void +LoadSessionEvent::execute() +{ + std::ifstream is; + is.open(m_filename.c_str(), std::ios::in); + + if ( ! is.good()) { + cout << "[Loader] Unable to open session file " << m_filename << endl; + return; + } else { + cout << "[Loader] Loading session from " << m_filename << endl; + } + string s; + + is >> s; + if (s != "version") { + cout << "[Loader] Corrupt session file." << endl; + is.close(); + return; + } + + is >> s; + if (s != "1") { + cout << "[Loader] Unrecognised session file version." << endl; + is.close(); + return; + } + + while (!is.eof()) { + is >> s; + if (s == "") continue; + + if (s != "patch") { + //cerr << "[Loader] Corrupt session file, aborting session load." << endl; + break; + } else { + is >> s; + PatchModel* pm = new PatchModel("", 0); + if (s.substr(0, 1) != "/") + s = m_filename.substr(0, m_filename.find_last_of("/")+1) + s; + pm->filename(s); + pm->parent(NULL); + m_patch_librarian->load_patch(pm); + } + } + + is.close(); +} + + +void +SaveSessionEvent::execute() +{ + assert(m_filename != ""); + string dir = m_filename.substr(0, m_filename.find_last_of("/")); + + string patch_filename; + + std::ofstream os; + os.open(m_filename.c_str(), std::ios::out); + + if ( ! os.good()) { + cout << "[Loader] Unable to write to session file " << m_filename << endl; + return; + } else { + cout << "[Loader] Saving session to " << m_filename << endl; + } + + os << "version 1" << endl; + + for (map<string,PatchController*>::iterator i = app->patches().begin(); + i != app->patches().end(); ++i) + { + if ((*i).second->model()->parent() == NULL) { + patch_filename = (*i).second->model()->filename(); + + // Make path relative if possible + if (patch_filename.length() > dir.length() && + patch_filename.substr(0, dir.length()) == dir) + patch_filename = patch_filename.substr(dir.length()+1); + + os << "patch " << patch_filename << endl; + } + } + + os.close(); +} +*/ + + +//////// Loader ////////// + + +Loader::Loader(PatchLibrarian* const patch_librarian) +: m_patch_librarian(patch_librarian), + m_event(NULL), + m_thread_exit_flag(false) +{ + assert(m_patch_librarian != NULL); + pthread_mutex_init(&m_mutex, NULL); + pthread_cond_init(&m_cond, NULL); +} + + +void +Loader::set_event(LoaderEvent* ev) +{ + assert(ev != NULL); + + pthread_mutex_lock(&m_mutex); + assert(m_event == NULL); + m_event = ev; + pthread_cond_signal(&m_cond); + pthread_mutex_unlock(&m_mutex); +} + + +void +Loader::launch() +{ + pthread_create(&m_thread, NULL, Loader::thread_function, this); +} + + +void* +Loader::thread_function(void* me) +{ + Loader* ct = static_cast<Loader*>(me); + return ct->m_thread_function(NULL); +} + + +void* +Loader::m_thread_function(void *) +{ + while ( ! m_thread_exit_flag) { + pthread_mutex_lock(&m_mutex); + pthread_cond_wait(&m_cond, &m_mutex); + + LoaderEvent* ev = m_event; + ev->execute(); + delete ev; + m_event = NULL; + + pthread_mutex_unlock(&m_mutex); + } + + pthread_exit(NULL); + return NULL; +} + + +void +Loader::load_patch(PatchModel* model, bool wait, bool merge) +{ + set_event(new LoadPatchEvent(m_patch_librarian, model, wait, merge)); +} + + +void +Loader::save_patch(PatchModel* model, const string& filename, bool recursive) +{ + cout << "[Loader] Saving patch " << filename << endl; + set_event(new SavePatchEvent(m_patch_librarian, model, filename, recursive)); +} + + +/* +void +Loader::load_session(const string& filename) +{ + set_event(new LoadSessionEvent(m_patch_librarian, filename)); +} + + +void +Loader::save_session(const string& filename) +{ + cout << "Saving session..." << endl; + set_event(new SaveSessionEvent(m_patch_librarian, filename)); +} +*/ + +} // namespace OmGtk diff --git a/src/progs/gtk/Loader.h b/src/progs/gtk/Loader.h new file mode 100644 index 00000000..46b5f3a8 --- /dev/null +++ b/src/progs/gtk/Loader.h @@ -0,0 +1,154 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LOADERTHREAD_H +#define LOADERTHREAD_H + +#include <string> +#include <cassert> +using std::string; + +namespace LibOmClient { + class PatchLibrarian; + class PatchModel; +} +using LibOmClient::PatchLibrarian; +using LibOmClient::PatchModel; + + +namespace OmGtk { + +/** Event to run in the Loader thread. + * + * \ingroup OmGtk + */ +class LoaderEvent +{ +public: + virtual void execute() = 0; + virtual ~LoaderEvent() {} +protected: + LoaderEvent() {} +}; + + +/** Loader thread patch loading event. + * + * \ingroup OmGtk + */ +class LoadPatchEvent : public LoaderEvent +{ +public: + LoadPatchEvent(PatchLibrarian* pl, PatchModel* model, bool wait, bool merge) + : m_patch_librarian(pl), m_patch_model(model), m_wait(wait), m_merge(merge) {} + virtual ~LoadPatchEvent() {} + void execute(); +private: + PatchLibrarian* m_patch_librarian; + PatchModel* m_patch_model; + bool m_wait; + bool m_merge; +}; + + +/** Loader thread patch loading event. + * + * \ingroup OmGtk + */ +class SavePatchEvent : public LoaderEvent +{ +public: + SavePatchEvent(PatchLibrarian* pl, PatchModel* pm, const string& filename, bool recursive) + : m_patch_librarian(pl), m_patch_model(pm), m_filename(filename), m_recursive(recursive) {} + virtual ~SavePatchEvent() {} + void execute(); +private: + PatchLibrarian* m_patch_librarian; + PatchModel* m_patch_model; + string m_filename; + bool m_recursive; +}; + +/* +class LoadSessionEvent : public LoaderEvent +{ +public: + LoadSessionEvent(PatchLibrarian* pl, const string& filename) + : m_patch_librarian(pl), m_filename(filename) {} + virtual ~LoadSessionEvent() {} + void execute(); +private: + PatchLibrarian* m_patch_librarian; + string m_filename; +}; + + +class SaveSessionEvent : public LoaderEvent +{ +public: + SaveSessionEvent(PatchLibrarian* pl, const string& filename) + : m_patch_librarian(pl), m_filename(filename) {} + virtual ~SaveSessionEvent() {} + void execute(); +private: + PatchLibrarian* m_patch_librarian; + string m_filename; +}; +*/ + +/** Thread for loading patch files. + * + * This is a seperate thread so it can send all the loading message without + * blocking everything else, so the app can respond to the incoming events + * caused as a result of the patch loading. + * + * \ingroup OmGtk + */ +class Loader +{ +public: + Loader(PatchLibrarian* const patch_librarian); + ~Loader() { m_thread_exit_flag = true; } + + void launch(); + void exit() { m_thread_exit_flag = true; } + + void load_patch(PatchModel* model, bool wait, bool merge); + void save_patch(PatchModel* model, const string& filename, bool recursive); + + //void load_session(const string& filename); + //void save_session(const string& filename); + + static void* thread_function(void* me); + +private: + void* m_thread_function(void*); + + void set_event(LoaderEvent* ev); + + PatchLibrarian* const m_patch_librarian; + LoaderEvent* m_event; + bool m_thread_exit_flag; + pthread_t m_thread; + pthread_mutex_t m_mutex; + pthread_cond_t m_cond; + +}; + + +} // namespace OmGtk + +#endif // LOADERRTHREAD_H diff --git a/src/progs/gtk/Makefile.am b/src/progs/gtk/Makefile.am new file mode 100644 index 00000000..c92ae2b2 --- /dev/null +++ b/src/progs/gtk/Makefile.am @@ -0,0 +1,98 @@ +if BUILD_GTK_CLIENT + +EXTRA_DIST = om_gtk.gladep + +sharefilesdir = $(pkgdatadir) +dist_sharefiles_DATA = om_gtk.glade om-icon.png + +AM_CXXFLAGS = -DGTK_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -I$(top_srcdir)/src/common -I$(top_srcdir)/src/clients -DPKGDATADIR=\"$(pkgdatadir)\" @GTKMM_CFLAGS@ @LIBGLADEMM_CFLAGS@ @GNOMECANVASMM_CFLAGS@ @LOSC_CFLAGS@ @LASH_CFLAGS@ @FLOWCANVAS_CFLAGS@ +om_gtk_LDADD = @GTKMM_LIBS@ @LIBGLADEMM_LIBS@ @GNOMECANVASMM_LIBS@ @LOSC_LIBS@ @LASH_LIBS@ @FLOWCANVAS_LIBS@ ../libomclient.a +om_gtk_DEPENDENCIES = ../libomclient.a + + +bin_PROGRAMS = om_gtk +om_gtk_SOURCES = \ + cmdline.h \ + cmdline.c \ + main.cpp \ + singletons.cpp \ + ConnectWindow.h \ + ConnectWindow.cpp \ + App.h \ + App.cpp \ + Store.h \ + Store.cpp \ + Configuration.h \ + Configuration.cpp \ + GladeFactory.h \ + GladeFactory.cpp \ + Controller.h \ + Controller.cpp \ + GtkObjectController.h \ + GtkObjectController.cpp \ + PatchController.h \ + PatchController.cpp \ + NodeController.h \ + NodeController.cpp \ + PortController.h \ + PortController.cpp \ + DSSIController.h \ + DSSIController.cpp \ + LoadPluginWindow.h \ + LoadPluginWindow.cpp \ + LoadPatchWindow.h \ + LoadPatchWindow.cpp \ + MessagesWindow.h \ + MessagesWindow.cpp \ + LoadSubpatchWindow.h \ + LoadSubpatchWindow.cpp \ + ControlInterface.h \ + ControlInterface.cpp \ + NodeControlWindow.h \ + NodeControlWindow.cpp \ + ControlPanel.h \ + ControlPanel.cpp \ + ControlGroups.h \ + ControlGroups.cpp \ + PatchView.h \ + PatchView.cpp \ + PatchWindow.h \ + PatchWindow.cpp \ + BreadCrumb.h \ + OmFlowCanvas.h \ + OmFlowCanvas.cpp \ + ../../common/types.h \ + ../../common/Path.h \ + OmModule.h \ + OmModule.cpp \ + DSSIModule.h \ + DSSIModule.cpp \ + SubpatchModule.h \ + SubpatchModule.cpp \ + OmPort.h \ + OmPort.cpp \ + NewSubpatchWindow.h \ + NewSubpatchWindow.cpp \ + ConfigWindow.h \ + ConfigWindow.cpp \ + PatchDescriptionWindow.h \ + PatchDescriptionWindow.cpp \ + Loader.h \ + Loader.cpp \ + RenameWindow.h \ + RenameWindow.cpp \ + NodePropertiesWindow.h \ + NodePropertiesWindow.cpp \ + PatchTreeWindow.h \ + PatchTreeWindow.cpp + +#GtkClientInterface.h +#GtkClientInterface.cpp + + +if WITH_LASH +om_gtk_SOURCES += LashController.h LashController.cpp +endif + + +endif # WITH_GTK_CLIENT diff --git a/src/progs/gtk/MessagesWindow.cpp b/src/progs/gtk/MessagesWindow.cpp new file mode 100644 index 00000000..dfdc3750 --- /dev/null +++ b/src/progs/gtk/MessagesWindow.cpp @@ -0,0 +1,64 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "MessagesWindow.h" +#include <string> + +namespace OmGtk { +using std::string; + + +MessagesWindow::MessagesWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& glade_xml) +: Gtk::Window(cobject) +{ + glade_xml->get_widget("messages_textview", m_textview); + glade_xml->get_widget("messages_clear_button", m_clear_button); + glade_xml->get_widget("messages_close_button", m_close_button); + + m_clear_button->signal_clicked().connect(sigc::mem_fun(this, &MessagesWindow::clear_clicked)); + m_close_button->signal_clicked().connect(sigc::mem_fun(this, &MessagesWindow::close_clicked)); +} + + +void +MessagesWindow::post(const string& msg) +{ + Glib::RefPtr<Gtk::TextBuffer> text_buf = m_textview->get_buffer(); + text_buf->insert(text_buf->end(), msg); + text_buf->insert(text_buf->end(), "\n"); + + if (!m_clear_button->is_sensitive()) + m_clear_button->set_sensitive(true); +} + + +void +MessagesWindow::close_clicked() +{ + hide(); +} + + +void +MessagesWindow::clear_clicked() +{ + Glib::RefPtr<Gtk::TextBuffer> text_buf = m_textview->get_buffer(); + text_buf->erase(text_buf->begin(), text_buf->end()); + m_clear_button->set_sensitive(false); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/MessagesWindow.h b/src/progs/gtk/MessagesWindow.h new file mode 100644 index 00000000..5f5b86e6 --- /dev/null +++ b/src/progs/gtk/MessagesWindow.h @@ -0,0 +1,55 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MESSAGESWINDOW_H +#define MESSAGESWINDOW_H + +#include <string> +#include <gtkmm.h> +#include <libglademm/xml.h> +using std::string; + + +namespace OmGtk { + + +/** Messages Window. + * + * Loaded by libglade as a derived object. + * This is shown when errors occur (ie during patch loading). + * + * \ingroup OmGtk + */ +class MessagesWindow : public Gtk::Window +{ +public: + MessagesWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade); + + void post(const string& str); + +private: + void clear_clicked(); + void close_clicked(); + + Gtk::TextView* m_textview; + Gtk::Button* m_clear_button; + Gtk::Button* m_close_button; +}; + + +} // namespace OmGtk + +#endif // MESSAGESWINDOW_H diff --git a/src/progs/gtk/NewSubpatchWindow.cpp b/src/progs/gtk/NewSubpatchWindow.cpp new file mode 100644 index 00000000..dcc2cd2d --- /dev/null +++ b/src/progs/gtk/NewSubpatchWindow.cpp @@ -0,0 +1,110 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "NewSubpatchWindow.h" +#include "PatchController.h" +#include "NodeModel.h" +#include "Controller.h" +#include "PatchModel.h" + +namespace OmGtk { + + +NewSubpatchWindow::NewSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml) +: Gtk::Window(cobject), + m_new_module_x(0), + m_new_module_y(0) +{ + xml->get_widget("new_subpatch_name_entry", m_name_entry); + xml->get_widget("new_subpatch_message_label", m_message_label); + xml->get_widget("new_subpatch_polyphony_spinbutton", m_poly_spinbutton); + xml->get_widget("new_subpatch_ok_button", m_ok_button); + xml->get_widget("new_subpatch_cancel_button", m_cancel_button); + + m_name_entry->signal_changed().connect(sigc::mem_fun(this, &NewSubpatchWindow::name_changed)); + m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubpatchWindow::ok_clicked)); + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &NewSubpatchWindow::cancel_clicked)); + + m_ok_button->property_sensitive() = false; +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +NewSubpatchWindow::patch_controller(PatchController* pc) +{ + m_patch_controller = pc; +} + + +/** Called every time the user types into the name input box. + * Used to display warning messages, and enable/disable the OK button. + */ +void +NewSubpatchWindow::name_changed() +{ + string name = m_name_entry->get_text(); + if (name.find("/") != string::npos) { + m_message_label->set_text("Name may not contain '/'"); + m_ok_button->property_sensitive() = false; + } else if (m_patch_controller->patch_model()->get_node(name) != NULL) { + m_message_label->set_text("An object already exists with that name."); + m_ok_button->property_sensitive() = false; + } else if (name.length() == 0) { + m_message_label->set_text(""); + m_ok_button->property_sensitive() = false; + } else { + m_message_label->set_text(""); + m_ok_button->property_sensitive() = true; + } +} + + +void +NewSubpatchWindow::ok_clicked() +{ + PatchModel* pm = new PatchModel( + m_patch_controller->model()->base_path() + m_name_entry->get_text(), + m_poly_spinbutton->get_value_as_int()); + + if (m_new_module_x == 0 && m_new_module_y == 0) { + m_patch_controller->get_new_module_location( + m_new_module_x, m_new_module_y); + } + pm->set_parent(m_patch_controller->patch_model()); + pm->x(m_new_module_x); + pm->y(m_new_module_y); + char temp_buf[16]; + snprintf(temp_buf, 16, "%d", m_new_module_x); + pm->set_metadata("module-x", temp_buf); + snprintf(temp_buf, 16, "%d", m_new_module_y); + pm->set_metadata("module-y", temp_buf); + Controller::instance().create_patch_from_model(pm); + hide(); +} + + +void +NewSubpatchWindow::cancel_clicked() +{ + hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/NewSubpatchWindow.h b/src/progs/gtk/NewSubpatchWindow.h new file mode 100644 index 00000000..8421ea08 --- /dev/null +++ b/src/progs/gtk/NewSubpatchWindow.h @@ -0,0 +1,67 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef NEWSUBPATCHWINDOW_H +#define NEWSUBPATCHWINDOW_H + +#include "PluginModel.h" +#include <libglademm/xml.h> +#include <gtkmm.h> + + +namespace OmGtk { + +class PatchController; + + +/** 'New Subpatch' window. + * + * Loaded by glade as a derived object. + * + * \ingroup OmGtk + */ +class NewSubpatchWindow : public Gtk::Window +{ +public: + NewSubpatchWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml); + + void patch_controller(PatchController* pc); + + void set_next_module_location(int x, int y) + { m_new_module_x = x; m_new_module_y = y; } + +private: + void name_changed(); + void ok_clicked(); + void cancel_clicked(); + + PatchController* m_patch_controller; + + int m_new_module_x; + int m_new_module_y; + + Gtk::Entry* m_name_entry; + Gtk::Label* m_message_label; + Gtk::SpinButton* m_poly_spinbutton; + Gtk::Button* m_ok_button; + Gtk::Button* m_cancel_button; +}; + + +} // namespace OmGtk + +#endif // NEWSUBPATCHWINDOW_H diff --git a/src/progs/gtk/NodeControlWindow.cpp b/src/progs/gtk/NodeControlWindow.cpp new file mode 100644 index 00000000..e40af67f --- /dev/null +++ b/src/progs/gtk/NodeControlWindow.cpp @@ -0,0 +1,127 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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 alongCont + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "NodeControlWindow.h" +#include "GladeFactory.h" +#include "NodeController.h" +#include "ControlGroups.h" +#include "PatchWindow.h" +#include <iostream> +#include <cmath> +using std::cerr; using std::cout; using std::endl; + +namespace OmGtk { + + +/** Create a node control window and load a new ControlPanel for it. + */ +NodeControlWindow::NodeControlWindow(NodeController* node, size_t poly) +: m_node(node), + m_position_stored(false), + m_x(0), m_y(0) +{ + assert(m_node != NULL); + + property_resizable() = true; + set_border_width(5); + + set_title(m_node->path() + " Controls"); + + Glib::RefPtr<Gnome::Glade::Xml> xml = GladeFactory::new_glade_reference("warehouse_win"); + xml->get_widget_derived("control_panel_vbox", m_control_panel); + m_control_panel->reparent(*this); + + m_control_panel->init(m_node, poly); + + show_all_children(); + resize(); + + // FIXME: not working + set_icon_from_file(string(PKGDATADIR) + "/om-icon.png"); + + m_callback_enabled = true; +} + + +/** Create a node control window and with an existing ControlPanel. + */ +NodeControlWindow::NodeControlWindow(NodeController* node, ControlPanel* panel) +: m_node(node), + m_control_panel(panel) +{ + assert(m_node != NULL); + + property_resizable() = true; + set_border_width(5); + + set_title(m_node->path() + " Controls"); + + m_control_panel->reparent(*this); + + show_all_children(); + resize(); + + m_callback_enabled = true; +} + + +NodeControlWindow::~NodeControlWindow() +{ + delete m_control_panel; +} + + +void +NodeControlWindow::resize() +{ + pair<int,int> controls_size = m_control_panel->ideal_size(); + /*int width = 400; + int height = controls_size.second + + ((m_node->polyphonic()) ? 4 : 40);*/ + int width = controls_size.first; + int height = controls_size.second; + + if (height > property_screen().get_value()->get_height() - 64) + height = property_screen().get_value()->get_height() - 64; + if (width > property_screen().get_value()->get_width() - 64) + width = property_screen().get_value()->get_width() - 64; + + //cerr << "Resizing to: " << width << " x " << height << endl; + + Gtk::Window::resize(width, height); +} + + +void +NodeControlWindow::on_show() +{ + if (m_position_stored) + move(m_x, m_y); + + Gtk::Window::on_show(); +} + + +void +NodeControlWindow::on_hide() +{ + m_position_stored = true; + get_position(m_x, m_y); + Gtk::Window::on_hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/NodeControlWindow.h b/src/progs/gtk/NodeControlWindow.h new file mode 100644 index 00000000..a9224de9 --- /dev/null +++ b/src/progs/gtk/NodeControlWindow.h @@ -0,0 +1,69 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef NODECONTROLWINDOW_H +#define NODECONTROLWINDOW_H + +#include <vector> +#include <string> +#include <gtkmm.h> +#include <libglademm.h> +#include <sigc++/sigc++.h> +#include "ControlPanel.h" +using std::string; using std::vector; + +using namespace LibOmClient; + +namespace OmGtk { + +class ControlGroup; +class NodeController; + + +/** Window with controls (sliders) for all control-rate ports on a Node. + * + * \ingroup OmGtk + */ +class NodeControlWindow : public Gtk::Window +{ +public: + NodeControlWindow(NodeController* node, size_t poly); + NodeControlWindow(NodeController* node, ControlPanel* panel); + virtual ~NodeControlWindow(); + + ControlPanel* control_panel() const { return m_control_panel; } + + void resize(); + +protected: + void on_show(); + void on_hide(); + +private: + NodeController* m_node; + ControlPanel* m_control_panel; + bool m_callback_enabled; + + bool m_position_stored; + int m_x; + int m_y; +}; + + +} // namespace OmGtk + +#endif // NODECONTROLWINDOW_H diff --git a/src/progs/gtk/NodeController.cpp b/src/progs/gtk/NodeController.cpp new file mode 100644 index 00000000..57756877 --- /dev/null +++ b/src/progs/gtk/NodeController.cpp @@ -0,0 +1,408 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "NodeController.h" +#include <iostream> +#include <gtkmm.h> +#include "OmModule.h" +#include "NodeModel.h" +#include "PortModel.h" +#include "PortController.h" +#include "GtkObjectController.h" +#include "NodeControlWindow.h" +#include "OmModule.h" +#include "PatchController.h" +#include "OmFlowCanvas.h" +#include "RenameWindow.h" +#include "GladeFactory.h" +#include "Controller.h" +#include "PatchWindow.h" +#include "PatchModel.h" +#include "NodePropertiesWindow.h" +#include "Store.h" +using std::cerr; using std::endl; + +namespace OmGtk { + + +NodeController::NodeController(NodeModel* model) +: GtkObjectController(model), + m_controls_menuitem(NULL), + m_module(NULL), + m_control_window(NULL), + m_properties_window(NULL), + m_bridge_port(NULL) +{ + assert(model->controller() == NULL); + model->set_controller(this); + + // Create port controllers + for (list<PortModel*>::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + assert((*i)->controller() == NULL); + assert((*i)->parent() == model); + PortController* const pc = new PortController(*i); + assert((*i)->controller() == pc); // PortController() does this + } + + // Build menu + + Gtk::Menu::MenuList& items = m_menu.items(); + + Gtk::Menu_Helpers::MenuElem controls_elem + = Gtk::Menu_Helpers::MenuElem("Controls", + sigc::mem_fun(this, &NodeController::show_control_window)); + m_controls_menuitem = controls_elem.get_child(); + items.push_back(controls_elem); + items.push_back(Gtk::Menu_Helpers::MenuElem("Properties", + sigc::mem_fun(this, &NodeController::show_properties_window))); + items.push_back(Gtk::Menu_Helpers::SeparatorElem()); + items.push_back(Gtk::Menu_Helpers::MenuElem("Rename...", + sigc::mem_fun(this, &NodeController::show_rename_window))); + items.push_back(Gtk::Menu_Helpers::MenuElem("Clone", + sigc::mem_fun(this, &NodeController::on_menu_clone))); + items.push_back(Gtk::Menu_Helpers::MenuElem("Disconnect All", + sigc::mem_fun(this, &NodeController::on_menu_disconnect_all))); + items.push_back(Gtk::Menu_Helpers::MenuElem("Destroy", + sigc::mem_fun(this, &NodeController::on_menu_destroy))); + + m_controls_menuitem->property_sensitive() = false; + + if (node_model()->plugin()->type() == PluginModel::Internal + && node_model()->plugin()->plug_label() == "midi_control_in") { + Gtk::Menu::MenuList& items = m_menu.items(); + items.push_back(Gtk::Menu_Helpers::MenuElem("Learn", + sigc::mem_fun(this, &NodeController::on_menu_learn))); + } +} + + +NodeController::~NodeController() +{ +} + + +void +NodeController::create_module(OmFlowCanvas* canvas) +{ + //cerr << "Creating node module " << m_model->path() << endl; + + // If this is a DSSI plugin, DSSIController should be doing this + assert(node_model()->plugin()->type() != PluginModel::DSSI); + assert(canvas != NULL); + assert(m_module == NULL); + + m_module = new OmModule(canvas, this); + + create_all_ports(); + + m_module->move_to(node_model()->x(), node_model()->y()); +} + + +void +NodeController::add_to_store() +{ + // Add self + Store::instance().add_object(this); + + // Add ports + for (list<PortModel*>::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + //GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); + assert((*i)->controller() != NULL); + ((GtkObjectController*)((*i)->controller()))->add_to_store(); + } +} + + +void +NodeController::remove_from_store() +{ + // Remove ports + for (list<PortModel*>::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); + assert(pc != NULL); + pc->remove_from_store(); + } + + // Remove self + Store::instance().remove_object(this); +} + + +void +NodeController::set_path(const Path& new_path) +{ + remove_from_store(); + + // Rename ports + for (list<PortModel*>::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); + assert(pc != NULL); + pc->set_path(m_model->path().base_path() + pc->model()->name()); + } + + // Handle bridge port, if this node represents one + if (m_bridge_port != NULL) + m_bridge_port->set_path(new_path); + + if (m_module != NULL) + m_module->canvas()->rename_module(node_model()->path().name(), new_path.name()); + + GtkObjectController::set_path(new_path); + + add_to_store(); +} + + +void +NodeController::destroy() +{ + PatchController* pc = ((PatchController*)m_model->parent()->controller()); + assert(pc != NULL); + + remove_from_store(); + pc->remove_node(m_model->path().name()); + + if (m_bridge_port != NULL) + m_bridge_port->destroy(); + m_bridge_port = NULL; + + //if (m_module != NULL) + // delete m_module; +} + + +void +NodeController::metadata_update(const string& key, const string& value) +{ + //cout << "[NodeController] Metadata update: " << m_model->path() << endl; + + if (m_module != NULL) { + if (key == "module-x") { + float x = atof(value.c_str()); + //if (x > 0 && x < m_canvas->width()) + m_module->move_to(x, m_module->property_y().get_value()); + } else if (key == "module-y") { + float y = atof(value.c_str()); + //if (y > 0 && y < m_canvas->height()) + m_module->move_to(m_module->property_x().get_value(), y); + } + } + + if (m_bridge_port != NULL) + m_bridge_port->metadata_update(key, value); + GtkObjectController::metadata_update(key, value); +} + + +void +NodeController::add_port(PortModel* pm) +{ + assert(pm->parent() == NULL); + + cout << "[NodeController] Adding port " << pm->path() << endl; + + node_model()->add_port(pm); + PortController* pc = new PortController(pm); + assert(pm->controller() == pc); + pc->add_to_store(); + + if (m_module != NULL) { + pc->create_port(m_module); + m_module->resize(); + + // Enable "Controls" menu item on module + if (has_control_inputs()) + enable_controls_menuitem(); + } + + if (m_control_window != NULL) { + assert(m_control_window->control_panel() != NULL); + m_control_window->control_panel()->add_port(pc); + m_control_window->resize(); + } +} + + +void +NodeController::show_control_window() +{ + size_t poly = 1; + if (node_model()->polyphonic()) + poly = node_model()->parent_patch()->poly(); + + if (m_control_window == NULL) + m_control_window = new NodeControlWindow(this, poly); + + if (m_control_window->control_panel()->num_controls() > 0) + m_control_window->present(); +} + + +void +NodeController::on_menu_destroy() +{ + Controller::instance().destroy(node_model()->path()); +} + + +void +NodeController::show_rename_window() +{ + assert(node_model()->parent() != NULL); + + // FIXME: will this be magically cleaned up? + RenameWindow* win = NULL; + Glib::RefPtr<Gnome::Glade::Xml> xml = GladeFactory::new_glade_reference("rename_win"); + xml->get_widget_derived("rename_win", win); + + PatchController* parent = ((PatchController*)node_model()->parent()->controller()); + assert(parent != NULL); + + if (parent->window() != NULL) + win->set_transient_for(*parent->window()); + + win->set_object(this); + win->show(); +} + +void +NodeController::on_menu_clone() +{ + assert(node_model() != NULL); + //assert(m_parent != NULL); + //assert(m_parent->model() != NULL); + + string clone_name = node_model()->name(); + int i = 2; // postfix number (ie oldname_2) + + // Check if name already has a number postfix + if (clone_name.find_last_of("_") != string::npos) { + string name_postfix = clone_name.substr(clone_name.find_last_of("_")+1); + clone_name = clone_name.substr(0, clone_name.find_last_of("_")); + if (sscanf(name_postfix.c_str(), "%d", &i)) + ++i; + } + + char clone_postfix[4]; + for ( ; i < 100; ++i) { + snprintf(clone_postfix, 4, "_%d", i); + if (node_model()->parent_patch()->get_node(clone_name + clone_postfix) == NULL) + break; + } + + clone_name = clone_name + clone_postfix; + + const string path = node_model()->parent_patch()->base_path() + clone_name; + NodeModel* nm = new NodeModel(path); + nm->plugin(node_model()->plugin()); + nm->polyphonic(node_model()->polyphonic()); + nm->x(node_model()->x() + 20); + nm->y(node_model()->y() + 20); + Controller::instance().create_node_from_model(nm); +} + + +void +NodeController::on_menu_learn() +{ + Controller::instance().midi_learn(node_model()->path()); +} + +void +NodeController::on_menu_disconnect_all() +{ + Controller::instance().disconnect_all(node_model()->path()); +} + + +void +NodeController::show_properties_window() +{ + PatchController* parent = ((PatchController*)node_model()->parent()->controller()); + assert(parent != NULL); + + if (m_properties_window == NULL) { + Glib::RefPtr<Gnome::Glade::Xml> xml = GladeFactory::new_glade_reference("node_properties_win"); + xml->get_widget_derived("node_properties_win", m_properties_window); + } + assert(m_properties_window != NULL); + assert(parent != NULL); + m_properties_window->set_node(node_model()); + if (parent->window() != NULL) + m_properties_window->set_transient_for(*parent->window()); + m_properties_window->show(); +} + + +/** Create all (visual) ports and add them to module (and resize it). + */ +void +NodeController::create_all_ports() +{ + assert(m_module != NULL); + + PortController* pc = NULL; + for (PortModelList::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + pc = dynamic_cast<PortController*>((*i)->controller()); + assert(pc != NULL); + pc->create_port(m_module); + } + + m_module->resize(); + + if (has_control_inputs()) + enable_controls_menuitem(); +} + + +bool +NodeController::has_control_inputs() +{ + for (PortModelList::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) + if ((*i)->is_input() && (*i)->is_control()) + return true; + + return false; +} + + +void +NodeController::enable_controls_menuitem() +{ + m_controls_menuitem->property_sensitive() = true; +} + + +void +NodeController::disable_controls_menuitem() +{ + m_controls_menuitem->property_sensitive() = false; + + if (m_control_window != NULL) + m_control_window->hide(); +} + + + +} // namespace OmGtk + diff --git a/src/progs/gtk/NodeController.h b/src/progs/gtk/NodeController.h new file mode 100644 index 00000000..ed2a6d59 --- /dev/null +++ b/src/progs/gtk/NodeController.h @@ -0,0 +1,114 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NODECONTROLLER_H +#define NODECONTROLLER_H + +#include <string> +#include <gtkmm.h> +#include "util/Path.h" +#include "GtkObjectController.h" + +using std::string; +using Om::Path; +using namespace LibOmClient; + +namespace LibOmClient { + class MetadataModel; + class NodeModel; + class PortModel; +} + +namespace OmGtk { + +class Controller; +class OmModule; +class NodeControlWindow; +class NodePropertiesWindow; +class PortController; +class OmFlowCanvas; + +/** Controller for a Node. + * + * \ingroup OmGtk + */ +class NodeController : public GtkObjectController +{ +public: + NodeController(NodeModel* model); + virtual ~NodeController(); + + virtual void destroy(); + + virtual void add_to_store(); + virtual void remove_from_store(); + + virtual void metadata_update(const string& key, const string& value); + + virtual void create_module(OmFlowCanvas* canvas); + + void set_path(const Path& new_path); + + virtual void add_port(PortModel* pm); + virtual void remove_port(const Path& path, bool resize_module) {} + + virtual void program_add(int bank, int program, const string& name) {} + virtual void program_remove(int bank, int program) {} + + OmModule* module() { return m_module; } + + void bridge_port(PortController* port) { m_bridge_port = port; } + PortController* as_port() { return m_bridge_port; } + + NodeModel* node_model() { return (NodeModel*)m_model; } + + NodeControlWindow* control_window() { return m_control_window; } + void control_window(NodeControlWindow* cw) { m_control_window = cw; } + + virtual void show_control_window(); + void show_rename_window(); + void show_properties_window(); + + bool has_control_inputs(); + + virtual void show_menu(GdkEventButton* event) + { m_menu.popup(event->button, event->time); } + + virtual void enable_controls_menuitem(); + virtual void disable_controls_menuitem(); + +protected: + void create_all_ports(); + + void on_menu_destroy(); + void on_menu_clone(); + void on_menu_learn(); + void on_menu_disconnect_all(); + + Gtk::Menu m_menu; + Glib::RefPtr<Gtk::MenuItem> m_controls_menuitem; + + OmModule* m_module; ///< View (module on a patch canvas) + + NodeControlWindow* m_control_window; + NodePropertiesWindow* m_properties_window; + PortController* m_bridge_port; +}; + + +} // namespace OmGtk + +#endif // NODECONTROLLER_H diff --git a/src/progs/gtk/NodePropertiesWindow.cpp b/src/progs/gtk/NodePropertiesWindow.cpp new file mode 100644 index 00000000..048f2513 --- /dev/null +++ b/src/progs/gtk/NodePropertiesWindow.cpp @@ -0,0 +1,62 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "NodePropertiesWindow.h" +#include <cassert> +#include <string> +#include "NodeModel.h" +#include "PluginModel.h" + +namespace OmGtk { +using std::string; + + +NodePropertiesWindow::NodePropertiesWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& glade_xml) +: Gtk::Window(cobject) +{ + glade_xml->get_widget("node_properties_path_label", m_node_path_label); + glade_xml->get_widget("node_properties_polyphonic_checkbutton", m_node_polyphonic_toggle); + glade_xml->get_widget("node_properties_plugin_type_label", m_plugin_type_label); + glade_xml->get_widget("node_properties_plugin_uri_label", m_plugin_uri_label); + glade_xml->get_widget("node_properties_plugin_name_label", m_plugin_name_label); +} + + +/** Set the node this window is associated with. + * This function MUST be called before using this object in any way. + */ +void +NodePropertiesWindow::set_node(NodeModel* node_model) +{ + assert(node_model != NULL); + + m_node_model = node_model; + + set_title(node_model->path() + " Properties"); + + m_node_path_label->set_text(node_model->path()); + m_node_polyphonic_toggle->set_active(node_model->polyphonic()); + + const PluginModel* const pm = node_model->plugin(); + + m_plugin_type_label->set_text(pm->type_string()); + m_plugin_uri_label->set_text(pm->uri()); + m_plugin_name_label->set_text(pm->name()); +} + + +} // namespace OmGtk + diff --git a/src/progs/gtk/NodePropertiesWindow.h b/src/progs/gtk/NodePropertiesWindow.h new file mode 100644 index 00000000..efff01bb --- /dev/null +++ b/src/progs/gtk/NodePropertiesWindow.h @@ -0,0 +1,55 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef NODEPROPERTIESWINDOW_H +#define NODEPROPERTIESWINDOW_H + +#include <gtkmm.h> +#include <libglademm.h> + +namespace LibOmClient { class NodeModel; } +using namespace LibOmClient; + +namespace OmGtk { + + +/** 'New Patch' Window. + * + * Loaded by libglade as a derived object. + * + * \ingroup OmGtk + */ +class NodePropertiesWindow : public Gtk::Window +{ +public: + NodePropertiesWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade); + + void set_node(NodeModel* node_model); + +private: + + NodeModel* m_node_model; + + Gtk::Label* m_node_path_label; + Gtk::CheckButton* m_node_polyphonic_toggle; + Gtk::Label* m_plugin_type_label; + Gtk::Label* m_plugin_uri_label; + Gtk::Label* m_plugin_name_label; +}; + +} // namespace OmGtk + +#endif // NODEPROPERTIESWINDOW_H diff --git a/src/progs/gtk/OmFlowCanvas.cpp b/src/progs/gtk/OmFlowCanvas.cpp new file mode 100644 index 00000000..a7e41ea2 --- /dev/null +++ b/src/progs/gtk/OmFlowCanvas.cpp @@ -0,0 +1,166 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OmFlowCanvas.h" +#include <cassert> +#include <flowcanvas/FlowCanvas.h> +#include "Controller.h" +#include "PatchController.h" +#include "PatchModel.h" +#include "PatchWindow.h" +#include "LoadPluginWindow.h" +#include "LoadSubpatchWindow.h" +#include "NewSubpatchWindow.h" +#include "OmPort.h" +#include "NodeModel.h" +#include "OmModule.h" + + +namespace OmGtk { + + +OmFlowCanvas::OmFlowCanvas(PatchController* controller, int width, int height) +: FlowCanvas(width, height), + m_patch_controller(controller), + m_last_click_x(0), + m_last_click_y(0) +{ + assert(controller != NULL); + + Gtk::Menu::MenuList& items = m_menu.items(); + items.push_back(Gtk::Menu_Helpers::MenuElem("Load Plugin...", + sigc::mem_fun(this, &OmFlowCanvas::menu_load_plugin))); + items.push_back(Gtk::Menu_Helpers::MenuElem("Load Subpatch...", + sigc::mem_fun(this, &OmFlowCanvas::menu_load_subpatch))); + items.push_back(Gtk::Menu_Helpers::MenuElem("New Subpatch...", + sigc::mem_fun(this, &OmFlowCanvas::menu_create_subpatch))); +} + + +void +OmFlowCanvas::connect(const Port* src_port, const Port* dst_port) +{ + assert(src_port != NULL); + assert(dst_port != NULL); + + const OmPort* const src = static_cast<const OmPort* const>(src_port); + const OmPort* const dst = static_cast<const OmPort* const>(dst_port); + + // Midi binding/learn shortcut + if (src->model()->type() == PortModel::MIDI && + dst->model()->type() == PortModel::CONTROL) + { + // FIXME: leaks? + NodeModel* nm = new NodeModel(m_patch_controller->model()->base_path() + + src->name() + "-" + dst->name()); + PluginModel* pm = new PluginModel(PluginModel::Internal, "", "midi_control_in", ""); + nm->plugin(pm); + nm->x(dst->module()->property_x() - dst->module()->width() - 20); + nm->y(dst->module()->property_y()); + Controller::instance().create_node_from_model(nm); + Controller::instance().connect(src->model()->path(), nm->path() + "/MIDI In"); + Controller::instance().connect(nm->path() + "/Out (CR)", dst->model()->path()); + Controller::instance().midi_learn(nm->path()); + + // Set control node range to port's user range + + Controller::instance().set_port_value_queued(nm->path().base_path() + "Min", + atof(dst->model()->get_metadata("user-min").c_str())); + Controller::instance().set_port_value_queued(nm->path().base_path() + "Max", + atof(dst->model()->get_metadata("user-max").c_str())); + } else { + Controller::instance().connect(src->model()->path(), + dst->model()->path()); + } +} + + +void +OmFlowCanvas::disconnect(const Port* src_port, const Port* dst_port) +{ + assert(src_port != NULL); + assert(dst_port != NULL); + + Controller::instance().disconnect(((OmPort*)src_port)->model()->path(), + ((OmPort*)dst_port)->model()->path()); +} + + +bool +OmFlowCanvas::canvas_event(GdkEvent* event) +{ + assert(event != NULL); + + switch (event->type) { + + case GDK_BUTTON_PRESS: + if (event->button.button == 3) { + m_last_click_x = (int)event->button.x; + m_last_click_y = (int)event->button.y; + show_menu(event); + } + break; + + /*case GDK_KEY_PRESS: + if (event->key.keyval == GDK_Delete) + destroy_selected(); + break; + */ + + default: + break; + } + + return FlowCanvas::canvas_event(event); +} + + +void +OmFlowCanvas::destroy_selected() +{ + for (list<Module*>::iterator m = m_selected_modules.begin(); m != m_selected_modules.end(); ++m) + Controller::instance().destroy(((OmModule*)(*m))->node()->path()); +} + + +void +OmFlowCanvas::menu_load_plugin() +{ + m_patch_controller->window()->load_plugin_window()->set_next_module_location( + m_last_click_x, m_last_click_y); + m_patch_controller->window()->load_plugin_window()->show(); +} + + +void +OmFlowCanvas::menu_load_subpatch() +{ + m_patch_controller->window()->load_subpatch_window()->set_next_module_location( + m_last_click_x, m_last_click_y); + m_patch_controller->window()->load_subpatch_window()->show(); +} + + +void +OmFlowCanvas::menu_create_subpatch() +{ + m_patch_controller->window()->new_subpatch_window()->set_next_module_location( + m_last_click_x, m_last_click_y); + m_patch_controller->window()->new_subpatch_window()->show(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/OmFlowCanvas.h b/src/progs/gtk/OmFlowCanvas.h new file mode 100644 index 00000000..2a553f5b --- /dev/null +++ b/src/progs/gtk/OmFlowCanvas.h @@ -0,0 +1,70 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OMPATCHBAYAREA_H +#define OMPATCHBAYAREA_H + +#include <string> +#include <flowcanvas/FlowCanvas.h> + + +using std::string; +using namespace LibFlowCanvas; + +using LibFlowCanvas::Port; + +namespace OmGtk { + +class OmModule; +class PatchController; + +/** Patch canvas widget. + * + * \ingroup OmGtk + */ +class OmFlowCanvas : public LibFlowCanvas::FlowCanvas +{ +public: + OmFlowCanvas(PatchController* controller, int width, int height); + + OmModule* find_module(const string& name) + { return (OmModule*)FlowCanvas::find_module(name); } + + void connect(const Port* src_port, const Port* dst_port); + void disconnect(const Port* src_port, const Port* dst_port); + + bool canvas_event(GdkEvent* event); + void destroy_selected(); + + void show_menu(GdkEvent* event) + { m_menu.popup(event->button.button, event->button.time); } + + void menu_load_plugin(); + void menu_load_subpatch(); + void menu_create_subpatch(); + +private: + PatchController* m_patch_controller; + int m_last_click_x; + int m_last_click_y; + + Gtk::Menu m_menu; +}; + + +} // namespace OmGtk + +#endif // OMPATCHBAYAREA_H diff --git a/src/progs/gtk/OmModule.cpp b/src/progs/gtk/OmModule.cpp new file mode 100644 index 00000000..3a31b7f3 --- /dev/null +++ b/src/progs/gtk/OmModule.cpp @@ -0,0 +1,85 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OmModule.h" +#include <cassert> +#include "Controller.h" +#include "OmFlowCanvas.h" +#include "PatchModel.h" +#include "NodeModel.h" +#include "OmPort.h" +#include "GladeFactory.h" +#include "RenameWindow.h" +#include "PatchController.h" +#include "PatchWindow.h" + +namespace OmGtk { + + +OmModule::OmModule(OmFlowCanvas* canvas, NodeController* node) +: LibFlowCanvas::Module(canvas, node->node_model()->name(), + node->node_model()->x(), node->node_model()->y()), + m_node(node) +{ + assert(m_node != NULL); + + /*if (node_model()->polyphonic() && node_model()->parent() != NULL + && node_model()->parent_patch()->poly() > 1) { + border_width(2.0); + }*/ + if (node->node_model()->polyphonic()) { + border_width(2.0); + } +} + + +void +OmModule::show_control_window() +{ + node()->show_control_window(); +} + + +void +OmModule::store_location() +{ + if (m_node->node_model()->x() == 0 || m_node->node_model()->y() == 0) + return; + + char temp_buf[16]; + + m_node->node_model()->x(property_x()); + snprintf(temp_buf, 16, "%f", m_node->node_model()->x()); + m_node->node_model()->set_metadata("module-x", temp_buf); // just in case? + Controller::instance().set_metadata(m_node->node_model()->path(), "module-x", temp_buf); + + m_node->node_model()->y(property_y()); + snprintf(temp_buf, 16, "%f", m_node->node_model()->y()); + m_node->node_model()->set_metadata("module-y", temp_buf); // just in case? + Controller::instance().set_metadata(m_node->node_model()->path(), "module-y", temp_buf); +} + + +void +OmModule::move_to(double x, double y) +{ + Module::move_to(x, y); + m_node->node_model()->x(x); + m_node->node_model()->y(y); + //store_location(); +} + +} // namespace OmGtk diff --git a/src/progs/gtk/OmModule.h b/src/progs/gtk/OmModule.h new file mode 100644 index 00000000..ebb36fe6 --- /dev/null +++ b/src/progs/gtk/OmModule.h @@ -0,0 +1,77 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef OMMODULE_H +#define OMMODULE_H + +#include <string> +#include <libgnomecanvasmm.h> +#include <flowcanvas/Module.h> +#include "NodeController.h" +using std::string; + +namespace LibOmClient { +class PortModel; +class NodeModel; +class ControlModel; +} +using namespace LibOmClient; + +namespace OmGtk { + +class PatchController; +class OmFlowCanvas; +class OmPort; + + +/** A module in a patch. + * + * This base class is extended for various types of modules - SubpatchModule, + * DSSIModule, etc. + * + * \ingroup OmGtk + */ +class OmModule : public LibFlowCanvas::Module +{ +public: + OmModule(OmFlowCanvas* canvas, NodeController* node); + virtual ~OmModule() {} + + virtual OmPort* port(const string& port_name) { + return (OmPort*)Module::port(port_name); + } + + virtual void store_location(); + void move_to(double x, double y); + + void on_right_click(GdkEventButton* event) { m_node->show_menu(event); } + + void show_control_window(); + + NodeController* node() const { return m_node; } + +protected: + virtual void on_double_click(GdkEventButton* ev) { show_control_window(); } + virtual void on_middle_click(GdkEventButton* ev) { show_control_window(); } + + NodeController* m_node; +}; + + +} // namespace OmGtk + +#endif // OMMODULE_H diff --git a/src/progs/gtk/OmPort.cpp b/src/progs/gtk/OmPort.cpp new file mode 100644 index 00000000..b43b8294 --- /dev/null +++ b/src/progs/gtk/OmPort.cpp @@ -0,0 +1,57 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OmPort.h" +#include <cassert> +#include <iostream> +#include "PortModel.h" +#include "OmModule.h" +#include "ControlModel.h" +#include "Configuration.h" +#include "App.h" +using std::cerr; using std::endl; + +using namespace LibOmClient; + +namespace OmGtk { + +OmPort::OmPort(OmModule* module, PortModel* pm) +: Port(module, pm->name(), pm->is_input(), App::instance().configuration()->get_port_color(pm)), + m_port_model(pm) +{ + assert(module != NULL); + assert(m_port_model != NULL); +} + +#if 0 +void +OmPort::set_name(const string& n) +{ + cerr << "********** OmPort::set_name broken **********************" << endl; + + /* FIXME: move to PortController + string new_path = OmPath::parent(m_port_model->path()) +"/"+ n; + + for (list<ControlPanel*>::iterator i = m_control_panels.begin(); i != m_control_panels.end(); ++i) + (*i)->rename_port(m_port_model->path(), new_path); + + Port::set_name(n); + m_port_model->path(new_path); + */ +} +#endif + +} // namespace OmGtk diff --git a/src/progs/gtk/OmPort.h b/src/progs/gtk/OmPort.h new file mode 100644 index 00000000..69a867d5 --- /dev/null +++ b/src/progs/gtk/OmPort.h @@ -0,0 +1,59 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef OMPORT_H +#define OMPORT_H + +#include <cassert> +#include <string> +#include <flowcanvas/Port.h> + +namespace LibOmClient { class PortModel; } +using namespace LibOmClient; +using namespace LibFlowCanvas; +using std::string; using std::list; + +namespace OmGtk { + +class FlowCanvas; +class PatchController; +class PatchWindow; +class OmModule; + + +/** A Port on an OmModule. + * + * \ingroup OmGtk + */ +class OmPort : public LibFlowCanvas::Port +{ +public: + OmPort(OmModule* module, PortModel* pm); + + virtual ~OmPort() {} + + //void set_name(const string& n); + + PortModel* model() const { return m_port_model; } + +private: + PortModel* m_port_model; +}; + + +} // namespace OmGtk + +#endif // OMPORT_H diff --git a/src/progs/gtk/PatchController.cpp b/src/progs/gtk/PatchController.cpp new file mode 100644 index 00000000..83ba62d9 --- /dev/null +++ b/src/progs/gtk/PatchController.cpp @@ -0,0 +1,685 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "PatchController.h" +#include <cassert> +#include <cstdlib> +#include "GladeFactory.h" +#include "Configuration.h" +#include "util/Path.h" +#include "ControlPanel.h" +#include "ConnectionModel.h" +#include "OmFlowCanvas.h" +#include "PatchView.h" +#include "flowcanvas/Module.h" +#include "PluginModel.h" +#include "Controller.h" +#include "SubpatchModule.h" +#include "DSSIModule.h" +#include "PatchWindow.h" +#include "NodeModel.h" +#include "OmModule.h" +#include "OmPort.h" +#include "ControlModel.h" +#include "NodeControlWindow.h" +#include "NodeController.h" +#include "PortController.h" +#include "App.h" +#include "PatchTreeWindow.h" +#include "DSSIController.h" +#include "PatchModel.h" +#include "Store.h" + +using std::cerr; using std::cout; using std::endl; +using Om::Path; +using namespace LibOmClient; + +namespace OmGtk { + + +PatchController::PatchController(PatchModel* model) +: NodeController(model), + m_window(NULL), + m_patch_view(NULL), + m_module_x(0), + m_module_y(0) +{ + assert(model->path().length() > 0); + assert(model->parent() == NULL); + assert(model->controller() == this); // NodeController() does this + + if (model->path() != "/") { + PatchController* parent = Store::instance().patch(model->path().parent()); + if (parent != NULL) + parent->add_subpatch(this); + else + cerr << "[PatchController] " << path() << " ERROR: Parent not found." << endl; + } +} + + +PatchController::~PatchController() +{ + if (m_patch_view != NULL) { + claim_patch_view(); + m_patch_view->hide(); + delete m_patch_view; + m_patch_view = NULL; + } + + if (m_control_window != NULL) { + m_control_window->hide(); + delete m_control_window; + m_control_window = NULL; + } + + if (m_window != NULL) { + m_window->hide(); + delete m_window; + m_window = NULL; + } +} + + +void +PatchController::add_to_store() +{ + Store::instance().add_object(this); +} + + +void +PatchController::remove_from_store() +{ + Store::instance().remove_object(this); +} + + +void +PatchController::clear() +{ + // Destroy model + // Destroying nodes removes models from patch model, which invalidates any + // iterator to nodes, so avoid the iterator problem by doing it this way: + const NodeModelMap& nodes = patch_model()->nodes(); + size_t remaining = nodes.size(); + + while (remaining > 0) { + NodeController* const nc = (NodeController*)(*nodes.begin()).second->controller(); + assert(nc != NULL); + nc->destroy(); + assert(nodes.size() == remaining - 1); + --remaining; + } + assert(nodes.empty()); + + patch_model()->clear(); + + if (m_patch_view != NULL) { + assert(m_patch_view->canvas() != NULL); + m_patch_view->canvas()->destroy(); + } +} + + +void +PatchController::destroy() +{ + // Destroying nodes removes models from patch model, which invalidates any + // iterator to nodes, so avoid the iterator problem by doing it this way: + const NodeModelMap& nodes = patch_model()->nodes(); + size_t remaining = nodes.size(); + + while (remaining > 0) { + NodeController* const nc = (NodeController*) + (*nodes.begin()).second->controller(); + assert(nc != NULL); + nc->destroy(); + assert(nodes.size() == remaining - 1); + --remaining; + } + assert(nodes.empty()); + + //App::instance().remove_patch(this); + App::instance().patch_tree()->remove_patch(path()); + + // Delete all children models + //patch_model()->clear(); + + // Remove self from object store + Store::instance().remove_object(this); + + // Delete self from parent (this will delete model) + if (patch_model()->parent() != NULL) { + PatchController* const parent = (PatchController*)patch_model()->parent()->controller(); + assert(parent != NULL); + parent->remove_node(name()); + } else { + delete m_model; + } +} + + +void +PatchController::metadata_update(const string& key, const string& value) +{ + NodeController::metadata_update(key, value); + + if (key == "filename") + patch_model()->filename(value); +} + + +void +PatchController::set_path(const Path& new_path) +{ + assert(m_model != NULL); + Path old_path = path(); + + // Rename nodes + for (NodeModelMap::const_iterator i = patch_model()->nodes().begin(); + i != patch_model()->nodes().end(); ++i) { + const NodeModel* const nm = (*i).second; + assert(nm != NULL); + NodeController* const nc = ((NodeController*)nm->controller()); + assert(nc != NULL); + nc->set_path(new_path.base_path() + nc->node_model()->name()); + } + +#ifdef DEBUG + // Be sure ports were renamed by their bridge nodes + for (list<PortModel*>::const_iterator i = node_model()->ports().begin(); + i != node_model()->ports().end(); ++i) { + GtkObjectController* const pc = (GtkObjectController*)((*i)->controller()); + assert(pc != NULL); + assert(pc->path().parent()== new_path); + } +#endif + + App::instance().patch_tree()->patch_renamed(old_path, new_path); + + if (m_window != NULL) + m_window->patch_renamed(new_path); + + if (m_control_window != NULL) + m_control_window->set_title(new_path + " Controls"); + + if (m_module != NULL) { + assert(m_module->canvas() != NULL); + m_module->canvas()->rename_module(old_path.name(), new_path.name()); + assert(m_module->name() == new_path.name()); + } + + PatchController* parent = dynamic_cast<PatchController*>( + patch_model()->parent()->controller()); + + if (parent != NULL && parent->window() != NULL) + parent->window()->node_renamed(old_path, new_path); + + remove_from_store(); + GtkObjectController::set_path(new_path); + add_to_store(); + + if (old_path.name() != new_path.name()) + parent->patch_model()->rename_node(old_path, new_path); +} + + +void +PatchController::enable() +{ + if (m_patch_view != NULL) + m_patch_view->enabled(true); + + patch_model()->enabled(true); + + App::instance().patch_tree()->patch_enabled(m_model->path()); +} + + +void +PatchController::disable() +{ + if (m_patch_view != NULL) + m_patch_view->enabled(false); + + patch_model()->enabled(false); + + App::instance().patch_tree()->patch_disabled(m_model->path()); +} + + +void +PatchController::create_module(OmFlowCanvas* canvas) +{ + //cerr << "Creating patch module " << m_model->path() << endl; + + assert(canvas != NULL); + assert(m_module == NULL); + + m_module = new SubpatchModule(canvas, this); + + + m_menu.remove(m_menu.items()[4]); + + // Add navigation menu items + Gtk::Menu::MenuList& items = m_menu.items(); + items.push_front(Gtk::Menu_Helpers::SeparatorElem()); + items.push_front(Gtk::Menu_Helpers::MenuElem("Browse to Patch", + sigc::mem_fun((SubpatchModule*)m_module, &SubpatchModule::browse_to_patch))); + items.push_front(Gtk::Menu_Helpers::MenuElem("Open Patch in New Window", + sigc::mem_fun(this, &PatchController::show_patch_window))); + + create_all_ports(); + + m_module->move_to(node_model()->x(), node_model()->y()); + m_module->store_location(); +} + + +void +PatchController::create_view() +{ + assert(m_patch_view == NULL); + + Glib::RefPtr<Gnome::Glade::Xml> xml = GladeFactory::new_glade_reference(); + + xml->get_widget_derived("patch_view_vbox", m_patch_view); + assert(m_patch_view != NULL); + m_patch_view->patch_controller(this); + assert(m_patch_view->canvas() != NULL); + + // Create modules for nodes + for (NodeModelMap::const_iterator i = patch_model()->nodes().begin(); + i != patch_model()->nodes().end(); ++i) { + + NodeModel* const nm = (*i).second; + + string val = nm->get_metadata("module-x"); + if (val != "") + nm->x(atof(val.c_str())); + val = nm->get_metadata("module-y"); + if (val != "") + nm->y(atof(val.c_str())); + + /* Set sane default coordinates if not set already yet */ + if (nm->x() == 0.0f && nm->y() == 0.0f) { + int x, y; + get_new_module_location(x, y); + nm->x(x); + nm->y(y); + } + + NodeController* nc = ((NodeController*)nm->controller()); + assert(nc != NULL); + if (nc->module() == NULL); + nc->create_module(m_patch_view->canvas()); + assert(nc->module() != NULL); + m_patch_view->canvas()->add_module(nc->module()); + } + + // Create connections + for (list<ConnectionModel*>::const_iterator i = patch_model()->connections().begin(); + i != patch_model()->connections().end(); ++i) { + create_connection(*i); + } + + // Set run checkbox + m_patch_view->enabled(patch_model()->enabled()); +} + + +/** Create a connection in the view (canvas). + */ +void +PatchController::create_connection(const ConnectionModel* cm) +{ + m_patch_view->canvas()->add_connection( + cm->src_port_path().parent().name(), + cm->src_port_path().name(), + cm->dst_port_path().parent().name(), + cm->dst_port_path().name()); + + // Disable control slider from destination node control window + + PortController* p = Store::instance().port(cm->dst_port_path()); + assert(p != NULL); + + if (p->control_panel() != NULL) + p->control_panel()->disable_port(p->path()); + // FIXME: don't use canvas as a model (search object store) + /*OmModule* m = (OmModule*)m_patch_view->canvas()->find_module( + cm->dst_port_path().parent().name()); + + if (m != NULL) { + OmPort* p = m->port(cm->dst_port_path().name()); + if (p != NULL && p->connections().size() == 1) { + p->model()->connected(true); + assert(m->node_model()->controller() != NULL); + NodeControlWindow* cw = (((NodeController*) + m->node_model()->controller())->control_window()); + if (cw != NULL) + cw->control_panel()->disable_port(cm->dst_port_path()); + } + }*/ +} + + +/** Add a subpatch to this patch. + */ +void +PatchController::add_subpatch(PatchController* patch) +{ + assert(patch != NULL); + assert(patch->patch_model() != NULL); + assert(patch->patch_model()->parent() == NULL); + + /*if (pm->x() == 0 && pm->y() == 0) { + int x, y; + parent_pc->get_new_module_location(x, y); + pm->x(x); + pm->y(y); + }*/ + + patch_model()->add_node(patch->patch_model()); + + if (m_patch_view != NULL) { + patch->create_module(m_patch_view->canvas()); + m_patch_view->canvas()->add_module(patch->module()); + patch->module()->resize(); + } +} + + +void +PatchController::add_node(NodeModel* nm) +{ + assert(nm != NULL); + assert(nm->parent() == NULL); + assert(nm->path().parent() == m_model->path()); + + if (patch_model()->get_node(nm->name()) != NULL) { + // Node already exists, ignore + delete nm; + } else { + // FIXME: Should PatchController really be responsible for creating these? + NodeController* nc = NULL; + + if (nm->plugin()->type() == PluginModel::DSSI) + nc = new DSSIController(nm); + else + nc = new NodeController(nm); + + assert(nc != NULL); + assert(nm->controller() == nc); + + // Check if this is a bridge node + PortModel* const pm = patch_model()->get_port(nm->path().name()); + if (pm != NULL) { + cerr << "Bridge node." << endl; + PortController* pc = ((PortController*)pm->controller()); + assert(pc != NULL); + nc->bridge_port(pc); + } + + nc->add_to_store(); + patch_model()->add_node(nm); + + if (m_patch_view != NULL) { + + int x, y; + get_new_module_location(x, y); + nm->x(x); + nm->y(y); + + // Set zoom to 1.0 so module isn't messed up (Death to GnomeCanvas) + float old_zoom = m_patch_view->canvas()->zoom(); + if (old_zoom != 1.0) + m_patch_view->canvas()->zoom(1.0); + + if (nc->module() == NULL) + nc->create_module(m_patch_view->canvas()); + assert(nc->module() != NULL); + m_patch_view->canvas()->add_module(nc->module()); + nc->module()->resize(); + + // Reset zoom + if (old_zoom != 1.0) { + m_patch_view->canvas()->zoom(old_zoom); + nc->module()->zoom(old_zoom); + } + } + } +} + + +/** Removes a node from this patch. + */ +void +PatchController::remove_node(const string& name) +{ + assert(name.find("/") == string::npos); + + // Update breadcrumbs if necessary + if (m_window != NULL) + m_window->node_removed(name); + + if (m_patch_view != NULL) { + assert(m_patch_view->canvas() != NULL); + m_patch_view->canvas()->remove_module(name); + } + + patch_model()->remove_node(name); +} + + +/** Add a port to this patch. + * + * Will add a port to the subpatch module and the control window, if they + * exist. + */ +void +PatchController::add_port(PortModel* pm) +{ + assert(pm != NULL); + assert(pm->parent() == NULL); + + //cerr << "[PatchController] Adding port " << pm->path() << endl; + + if (patch_model()->get_port(pm->name()) != NULL) { + cerr << "[PatchController] Ignoring duplicate port " + << pm->path() << endl; + delete pm; + return; + } + + node_model()->add_port(pm); + PortController* pc = new PortController(pm); + + // Handle bridge ports/nodes (this is uglier than it should be) + NodeController* nc = Store::instance().node(pm->path()); + if (nc != NULL) + nc->bridge_port(pc); + + if (m_module != NULL) { + pc->create_port(m_module); + m_module->resize(); + } + + if (m_control_window != NULL) { + assert(m_control_window->control_panel() != NULL); + m_control_window->control_panel()->add_port(pc); + m_control_window->resize(); + } + + // Enable "Controls" menuitem on module and patch window, if necessary + if (has_control_inputs()) + enable_controls_menuitem(); +} + + +/** Removes a port from this patch + */ +void +PatchController::remove_port(const Path& path, bool resize_module) +{ + assert(path.parent() == m_model->path()); + + //cerr << "[PatchController] Removing port " << path << endl; + + /* FIXME + if (m_control_panel != NULL) { + m_control_panel->remove_port(path); + if (m_control_window != NULL) { + assert(m_control_window->control_panel() == m_control_panel); + m_control_window->resize(); + } + }*/ + + // Remove port on module + if (m_module != NULL) { + assert(m_module->port(path.name()) != NULL); + m_module->remove_port(path.name(), resize_module); + assert(m_module->port(path.name()) == NULL); + } + + patch_model()->remove_port(path); + assert(patch_model()->get_port(path.name()) == NULL); + + // Disable "Controls" menuitem on module and patch window, if necessary + if (!has_control_inputs()) + disable_controls_menuitem(); +} + + +void +PatchController::connection(ConnectionModel* const cm) +{ + assert(cm != NULL); + + patch_model()->add_connection(cm); + + if (m_patch_view != NULL) + create_connection(cm); +} + + + +void +PatchController::disconnection(const Path& src_port_path, const Path& dst_port_path) +{ + const string& src_node_name = src_port_path.parent().name(); + const string& src_port_name = src_port_path.name(); + const string& dst_node_name = dst_port_path.parent().name(); + const string& dst_port_name = dst_port_path.name(); + + if (m_patch_view != NULL) + m_patch_view->canvas()->remove_connection( + src_node_name, src_port_name, dst_node_name, dst_port_name); + + patch_model()->remove_connection(src_port_path, dst_port_path); + + // Enable control slider in destination node control window + PortController* p = Store::instance().port(dst_port_path); + assert(p != NULL); + + if (p->control_panel() != NULL) + p->control_panel()->enable_port(p->path()); +} + + +/** Try to guess a suitable location for a new module. + */ +void +PatchController::get_new_module_location(int& x, int& y) +{ + assert(m_patch_view != NULL); + assert(m_patch_view->canvas() != NULL); + m_patch_view->canvas()->get_scroll_offsets(x, y); + x += 20; + y += 20; +} + + +void +PatchController::show_patch_window() +{ + if (m_window == NULL) { + Glib::RefPtr<Gnome::Glade::Xml> xml = GladeFactory::new_glade_reference(); + + xml->get_widget_derived("patch_win", m_window); + assert(m_window != NULL); + + if (m_patch_view == NULL) + create_view(); + + m_window->patch_controller(this); + } + + assert(m_window != NULL); + m_window->present(); +} + + +/** Become the parent of the patch view. + * + * Steals the view away from whatever window is currently showing it. + */ +void +PatchController::claim_patch_view() +{ + assert(m_patch_view != NULL); + + m_patch_view->hide(); + m_patch_view->reparent(m_patch_view_bin); +} + + +void +PatchController::show_control_window() +{ + assert(patch_model() != NULL); + + if (m_control_window == NULL) + m_control_window = new NodeControlWindow(this, patch_model()->poly()); + + if (m_control_window->control_panel()->num_controls() > 0) + m_control_window->present(); +} + + +void +PatchController::enable_controls_menuitem() +{ + if (m_window != NULL) + m_window->menu_view_control_window()->property_sensitive() = true; + + NodeController::enable_controls_menuitem(); +} + + +void +PatchController::disable_controls_menuitem() +{ + if (m_window != NULL) + m_window->menu_view_control_window()->property_sensitive() = false; + + NodeController::disable_controls_menuitem(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/PatchController.h b/src/progs/gtk/PatchController.h new file mode 100644 index 00000000..de4af5e4 --- /dev/null +++ b/src/progs/gtk/PatchController.h @@ -0,0 +1,127 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PATCHCONTROLLER_H +#define PATCHCONTROLLER_H + +#include <string> +#include <gtkmm.h> +#include "NodeController.h" + +namespace LibOmClient { +class PatchModel; +class NodeModel; +class PortModel; +class ControlModel; +class ConnectionModel; +} + +using std::string; +using namespace LibOmClient; + +namespace OmGtk { + +class PatchWindow; +class SubpatchModule; +class Controller; +class OmFlowCanvas; +class NodeControlWindow; +class ControlPanel; +class PatchView; +class NodeController; + + +/** Controller for a patch. + * + * A patch is different from a port or node because there are two + * representations in the Gtk client - the window and the module in the parent + * patch (if applicable). So, this is a master class that contains both of + * those representations, and acts as the recipient of all patch related + * events (being the controller). + * + * \ingroup OmGtk + */ +class PatchController : public NodeController +{ +public: + PatchController(PatchModel* model); + virtual ~PatchController(); + + virtual void add_to_store(); + virtual void remove_from_store(); + + virtual void destroy(); + + virtual void metadata_update(const string& key, const string& value); + + void add_node(NodeModel* nm); + void remove_node(const string& name); + + virtual void add_port(PortModel* pm); + virtual void remove_port(const Path& path, bool resize_module); + + void connection(ConnectionModel* const cm); + void disconnection(const Path& src_port_path, const Path& dst_port_path); + void clear(); + + void add_subpatch(PatchController* patch); + + void get_new_module_location(int& x, int& y); + + void show_control_window(); + void show_patch_window(); + + void claim_patch_view(); + + void create_module(OmFlowCanvas* canvas); + void create_view(); + + PatchView* view() const { return m_patch_view; } + PatchWindow* window() const { return m_window; } + void window(PatchWindow* pw) { m_window = pw; } + + inline string name() const { return m_model->name(); } + inline const string& path() const { return m_model->path(); } + + void set_path(const Path& new_path); + + void enable(); + void disable(); + + PatchModel* patch_model() const { return (PatchModel*)m_model; } + + void enable_controls_menuitem(); + void disable_controls_menuitem(); + +private: + void create_connection(const ConnectionModel* cm); + + PatchWindow* m_window; ///< Window currently showing this patch + PatchView* m_patch_view; ///< View (canvas) of this patch + + /** Invisible bin used to store patch view when not shown by a patch window */ + Gtk::Alignment m_patch_view_bin; + + // Coordinates for next added plugin (used by canvas menu) + // 0 means "not set", ie guess at the best location + int m_module_x; + int m_module_y; +}; + + +} // namespace OmGtk + +#endif // PATCHCONTROLLER_H diff --git a/src/progs/gtk/PatchDescriptionWindow.cpp b/src/progs/gtk/PatchDescriptionWindow.cpp new file mode 100644 index 00000000..d10a9c0e --- /dev/null +++ b/src/progs/gtk/PatchDescriptionWindow.cpp @@ -0,0 +1,72 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PatchDescriptionWindow.h" +#include <string> +#include "PatchModel.h" + +namespace OmGtk { +using std::string; + + +PatchDescriptionWindow::PatchDescriptionWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& glade_xml) +: Gtk::Window(cobject) +{ + glade_xml->get_widget("description_author_entry", m_author_entry); + glade_xml->get_widget("description_description_textview", m_textview); + glade_xml->get_widget("description_cancel_button", m_cancel_button); + glade_xml->get_widget("description_ok_button", m_ok_button); + + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &PatchDescriptionWindow::cancel_clicked)); + m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &PatchDescriptionWindow::ok_clicked)); +} + + +/** Set the patch model this description is for. + * + * This function is a "post-constructor" - it MUST be called before using + * the window in any way. + */ +void +PatchDescriptionWindow::patch_model(PatchModel* patch_model) +{ + property_title() = patch_model->path() + " Properties"; + m_patch_model = patch_model; + m_author_entry->set_text(m_patch_model->get_metadata("author")); + m_textview->get_buffer()->set_text(m_patch_model->get_metadata("description")); +} + + +void +PatchDescriptionWindow::cancel_clicked() +{ + m_author_entry->set_text(m_patch_model->get_metadata("author")); + m_textview->get_buffer()->set_text(m_patch_model->get_metadata("description")); + hide(); +} + + +void +PatchDescriptionWindow::ok_clicked() +{ + m_patch_model->set_metadata("author", m_author_entry->get_text()); + m_patch_model->set_metadata("description", m_textview->get_buffer()->get_text()); + hide(); +} + + + +} // namespace OmGtk diff --git a/src/progs/gtk/PatchDescriptionWindow.h b/src/progs/gtk/PatchDescriptionWindow.h new file mode 100644 index 00000000..7c00faab --- /dev/null +++ b/src/progs/gtk/PatchDescriptionWindow.h @@ -0,0 +1,59 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PATCHDESCRIPTIONWINDOW_H +#define PATCHDESCRIPTIONWINDOW_H + +#include <string> +#include <gtkmm.h> +#include <libglademm/xml.h> +using std::string; + +namespace LibOmClient { class PatchModel; } +using LibOmClient::PatchModel; + +namespace OmGtk { + + +/** Patch Description Window. + * + * Loaded by libglade as a derived object. + * + * \ingroup OmGtk + */ +class PatchDescriptionWindow : public Gtk::Window +{ +public: + PatchDescriptionWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade); + + void patch_model(PatchModel* patch_model); + + void cancel_clicked(); + void ok_clicked(); + +private: + PatchModel* m_patch_model; + + Gtk::Entry* m_author_entry; + Gtk::TextView* m_textview; + Gtk::Button* m_cancel_button; + Gtk::Button* m_ok_button; +}; + + +} // namespace OmGtk + +#endif // PATCHDESCRIPTIONWINDOW_H diff --git a/src/progs/gtk/PatchTreeWindow.cpp b/src/progs/gtk/PatchTreeWindow.cpp new file mode 100644 index 00000000..065f4d6a --- /dev/null +++ b/src/progs/gtk/PatchTreeWindow.cpp @@ -0,0 +1,252 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PatchTreeWindow.h" +#include "Controller.h" +#include "PatchController.h" +#include "PatchWindow.h" +#include "SubpatchModule.h" +#include "PatchModel.h" +#include "util/Path.h" + +using Om::Path; + +namespace OmGtk { + + +PatchTreeWindow::PatchTreeWindow(BaseObjectType* cobject, + const Glib::RefPtr<Gnome::Glade::Xml>& xml) +: Gtk::Window(cobject), + m_enable_signal(true) +{ + xml->get_widget_derived("patches_treeview", m_patches_treeview); + + m_patch_treestore = Gtk::TreeStore::create(m_patch_tree_columns); + m_patches_treeview->set_window(this); + m_patches_treeview->set_model(m_patch_treestore); + Gtk::TreeViewColumn* name_col = Gtk::manage(new Gtk::TreeViewColumn( + "Patch", m_patch_tree_columns.name_col)); + Gtk::TreeViewColumn* enabled_col = Gtk::manage(new Gtk::TreeViewColumn( + "Run", m_patch_tree_columns.enabled_col)); + name_col->set_resizable(true); + name_col->set_expand(true); + + m_patches_treeview->append_column(*name_col); + m_patches_treeview->append_column(*enabled_col); + Gtk::CellRendererToggle* enabled_renderer = dynamic_cast<Gtk::CellRendererToggle*>( + m_patches_treeview->get_column_cell_renderer(1)); + enabled_renderer->property_activatable() = true; + + m_patch_tree_selection = m_patches_treeview->get_selection(); + + //m_patch_tree_selection->signal_changed().connect( + // sigc::mem_fun(this, &PatchTreeWindow::event_patch_selected)); + m_patches_treeview->signal_row_activated().connect( + sigc::mem_fun(this, &PatchTreeWindow::event_patch_activated)); + enabled_renderer->signal_toggled().connect( + sigc::mem_fun(this, &PatchTreeWindow::event_patch_enabled_toggled)); + + m_patches_treeview->columns_autosize(); +} + + +void +PatchTreeWindow::add_patch(PatchController* pc) +{ + PatchModel* const pm = pc->patch_model(); + + if (pm->parent() == NULL) { + Gtk::TreeModel::iterator iter = m_patch_treestore->append(); + Gtk::TreeModel::Row row = *iter; + if (pm->path() == "/") { + string root_name = Controller::instance().engine_url(); + // Hack off trailing '/' if it's there (ugly) + //if (root_name.substr(root_name.length()-1,1) == "/") + // root_name = root_name.substr(0, root_name.length()-1); + //root_name.append(":/"); + row[m_patch_tree_columns.name_col] = root_name; + } else { + row[m_patch_tree_columns.name_col] = pm->path().name(); + } + row[m_patch_tree_columns.enabled_col] = false; + row[m_patch_tree_columns.patch_controller_col] = pc; + m_patches_treeview->expand_row(m_patch_treestore->get_path(iter), true); + } else { + Gtk::TreeModel::Children children = m_patch_treestore->children(); + Gtk::TreeModel::iterator c = find_patch(children, pm->parent()->path()); + + if (c != children.end()) { + Gtk::TreeModel::iterator iter = m_patch_treestore->append(c->children()); + Gtk::TreeModel::Row row = *iter; + row[m_patch_tree_columns.name_col] = pm->path().name(); + row[m_patch_tree_columns.enabled_col] = false; + row[m_patch_tree_columns.patch_controller_col] = pc; + m_patches_treeview->expand_row(m_patch_treestore->get_path(iter), true); + } + } +} + + +void +PatchTreeWindow::remove_patch(const Path& path) +{ + Gtk::TreeModel::iterator i = find_patch(m_patch_treestore->children(), path); + if (i != m_patch_treestore->children().end()) + m_patch_treestore->erase(i); +} + + +Gtk::TreeModel::iterator +PatchTreeWindow::find_patch(Gtk::TreeModel::Children root, const Path& path) +{ + PatchController* pc = NULL; + + for (Gtk::TreeModel::iterator c = root.begin(); c != root.end(); ++c) { + pc = (*c)[m_patch_tree_columns.patch_controller_col]; + if (pc->model()->path() == path) { + return c; + } else if ((*c)->children().size() > 0) { + Gtk::TreeModel::iterator ret = find_patch(c->children(), path); + if (ret != c->children().end()) + return ret; + } + } + return root.end(); +} + +/* +void +PatchTreeWindow::event_patch_selected() +{ + Gtk::TreeModel::iterator active = m_patch_tree_selection->get_selected(); + if (active) { + Gtk::TreeModel::Row row = *active; + PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; + } +} +*/ + + +/** Show the context menu for the selected patch in the patches treeview. + */ +void +PatchTreeWindow::show_patch_menu(GdkEventButton* ev) +{ + Gtk::TreeModel::iterator active = m_patch_tree_selection->get_selected(); + if (active) { + Gtk::TreeModel::Row row = *active; + PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; + if (pc != NULL) + pc->show_menu(ev); + } +} + + +void +PatchTreeWindow::event_patch_activated(const Gtk::TreeModel::Path& path, Gtk::TreeView::Column* col) +{ + Gtk::TreeModel::iterator active = m_patch_treestore->get_iter(path); + Gtk::TreeModel::Row row = *active; + PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; + + pc->show_patch_window(); +} + + +void +PatchTreeWindow::event_patch_enabled_toggled(const Glib::ustring& path_str) +{ + Gtk::TreeModel::Path path(path_str); + Gtk::TreeModel::iterator active = m_patch_treestore->get_iter(path); + Gtk::TreeModel::Row row = *active; + + PatchController* pc = row[m_patch_tree_columns.patch_controller_col]; + Glib::ustring patch_path = pc->model()->path(); + + assert(pc != NULL); + + if ( ! pc->patch_model()->enabled()) { + if (m_enable_signal) + Controller::instance().enable_patch(patch_path); + pc->enable(); + row[m_patch_tree_columns.enabled_col] = true; + } else { + if (m_enable_signal) + Controller::instance().disable_patch(patch_path); + pc->disable(); + row[m_patch_tree_columns.enabled_col] = false; + } +} + + +void +PatchTreeWindow::patch_enabled(const Path& path) +{ + m_enable_signal = false; + + Gtk::TreeModel::iterator i + = find_patch(m_patch_treestore->children(), path); + + if (i != m_patch_treestore->children().end()) { + Gtk::TreeModel::Row row = *i; + row[m_patch_tree_columns.enabled_col] = true; + } else { + cerr << "[PatchTreeWindow] Unable to find patch " << path << endl; + } + + m_enable_signal = true; +} + + +void +PatchTreeWindow::patch_disabled(const Path& path) +{ + m_enable_signal = false; + + Gtk::TreeModel::iterator i + = find_patch(m_patch_treestore->children(), path); + + if (i != m_patch_treestore->children().end()) { + Gtk::TreeModel::Row row = *i; + row[m_patch_tree_columns.enabled_col] = false; + } else { + cerr << "[PatchTreeWindow] Unable to find patch " << path << endl; + } + + m_enable_signal = true; +} + + +void +PatchTreeWindow::patch_renamed(const Path& old_path, const Path& new_path) +{ + m_enable_signal = false; + + Gtk::TreeModel::iterator i + = find_patch(m_patch_treestore->children(), old_path); + + if (i != m_patch_treestore->children().end()) { + Gtk::TreeModel::Row row = *i; + row[m_patch_tree_columns.name_col] = new_path.name(); + } else { + cerr << "[PatchTreeWindow] Unable to find patch " << old_path << endl; + } + + m_enable_signal = true; +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/PatchTreeWindow.h b/src/progs/gtk/PatchTreeWindow.h new file mode 100644 index 00000000..3177e5e2 --- /dev/null +++ b/src/progs/gtk/PatchTreeWindow.h @@ -0,0 +1,105 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PATCHTREEWINDOW_H +#define PATCHTREEWINDOW_H + +#include <gtkmm.h> +#include <libglademm.h> +#include "util/Path.h" + + +using namespace Om; +using Om::Path; + +namespace OmGtk { + +class PatchWindow; +class PatchController; +class PatchTreeView; + + +/** Window with a TreeView of all loaded patches. + * + * \ingroup OmGtk + */ +class PatchTreeWindow : public Gtk::Window +{ +public: + PatchTreeWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade); + + void patch_enabled(const Path& path); + void patch_disabled(const Path& path); + void patch_renamed(const Path& old_path, const Path& new_path); + + void add_patch(PatchController* pc); + void remove_patch(const Path& path); + void show_patch_menu(GdkEventButton* ev); + +protected: + //void event_patch_selected(); + void event_patch_activated(const Gtk::TreeModel::Path& path, Gtk::TreeView::Column* col); + void event_patch_enabled_toggled(const Glib::ustring& path_str); + + Gtk::TreeModel::iterator find_patch(Gtk::TreeModel::Children root, const Path& path); + + PatchTreeView* m_patches_treeview; + + struct PatchTreeModelColumns : public Gtk::TreeModel::ColumnRecord + { + PatchTreeModelColumns() + { add(name_col); add(enabled_col); add(patch_controller_col); } + + Gtk::TreeModelColumn<Glib::ustring> name_col; + Gtk::TreeModelColumn<bool> enabled_col; + Gtk::TreeModelColumn<PatchController*> patch_controller_col; + }; + + bool m_enable_signal; + PatchTreeModelColumns m_patch_tree_columns; + Glib::RefPtr<Gtk::TreeStore> m_patch_treestore; + Glib::RefPtr<Gtk::TreeSelection> m_patch_tree_selection; +}; + + +/** Derived TreeView class to support context menus for patches */ +class PatchTreeView : public Gtk::TreeView +{ +public: + PatchTreeView(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml) + : Gtk::TreeView(cobject) + {} + + void set_window(PatchTreeWindow* win) { m_window = win; } + + bool on_button_press_event(GdkEventButton* ev) { + bool ret = Gtk::TreeView::on_button_press_event(ev); + + if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3)) + m_window->show_patch_menu(ev); + + return ret; + } + +private: + PatchTreeWindow* m_window; + +}; // struct PatchTreeView + + +} // namespace OmGtk + +#endif // PATCHTREEWINDOW_H diff --git a/src/progs/gtk/PatchView.cpp b/src/progs/gtk/PatchView.cpp new file mode 100644 index 00000000..e89428e9 --- /dev/null +++ b/src/progs/gtk/PatchView.cpp @@ -0,0 +1,119 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PatchView.h" +#include <iostream> +#include <cassert> +#include <fstream> +#include "App.h" +#include "OmFlowCanvas.h" +#include "PatchController.h" +#include "LoadPluginWindow.h" +#include "PatchModel.h" +#include "NewSubpatchWindow.h" +#include "LoadSubpatchWindow.h" +#include "NodeControlWindow.h" +#include "PatchDescriptionWindow.h" +#include "PatchTreeWindow.h" +#include "Controller.h" + +namespace OmGtk { + + +PatchView::PatchView(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml) +: Gtk::Box(cobject), + m_patch(NULL), + m_canvas(NULL), + m_enable_signal(true) +{ + property_visible() = false; + + xml->get_widget("patch_canvas_scrolledwindow", m_canvas_scrolledwindow); + xml->get_widget("patch_zoom_scale", m_zoom_slider); + xml->get_widget("patch_polyphony_label", m_polyphony_label); + xml->get_widget("patch_process_checkbutton", m_process_checkbutton); + + m_zoom_slider->signal_value_changed().connect( sigc::mem_fun(this, &PatchView::zoom_changed)); + m_process_checkbutton->signal_toggled().connect(sigc::mem_fun(this, &PatchView::process_toggled)); +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +PatchView::patch_controller(PatchController* pc) +{ + //m_patch = new PatchController(pm, controller); + m_patch = pc; + + m_canvas = new OmFlowCanvas(pc, 1600*2, 1200*2); + + m_canvas_scrolledwindow->add(*m_canvas); + //m_canvas->show(); + //m_canvas_scrolledwindow->show(); + + char txt[4]; + snprintf(txt, 8, "%zd", pc->patch_model()->poly()); + m_polyphony_label->set_text(txt); + + //m_description_window->patch_model(pc->model()); +} + + +void +PatchView::show_control_window() +{ + if (m_patch != NULL) + m_patch->show_control_window(); +} + + +void +PatchView::zoom_changed() +{ + float z = m_zoom_slider->get_value(); + m_canvas->zoom(z); +} + + +void +PatchView::process_toggled() +{ + if (!m_enable_signal) + return; + + if (m_process_checkbutton->get_active()) { + Controller::instance().enable_patch(m_patch->model()->path()); + App::instance().patch_tree()->patch_enabled(m_patch->model()->path()); + } else { + Controller::instance().disable_patch(m_patch->model()->path()); + App::instance().patch_tree()->patch_disabled(m_patch->model()->path()); + } +} + + +void +PatchView::enabled(bool e) +{ + m_enable_signal = false; + m_process_checkbutton->set_active(e); + m_enable_signal = true; +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/PatchView.h b/src/progs/gtk/PatchView.h new file mode 100644 index 00000000..ff6aebf9 --- /dev/null +++ b/src/progs/gtk/PatchView.h @@ -0,0 +1,86 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PATCHVIEW_H +#define PATCHVIEW_H + +#include <string> +#include <gtkmm.h> +#include <libglademm/xml.h> +#include <libglademm.h> + +using std::string; + +namespace LibOmClient { +class PatchModel; +class NodeModel; +class PortModel; +class ControlModel; +class MetadataModel; +} +using namespace LibOmClient; + + +namespace OmGtk { + +class PatchController; +class OmFlowCanvas; +class LoadPluginWindow; +class NewSubpatchWindow; +class LoadSubpatchWindow; +class NewSubpatchWindow; +class NodeControlWindow; +class PatchDescriptionWindow; +class SubpatchModule; +class OmPort; + + +/** The patch specific contents of a PatchWindow (ie the canvas and whatever else). + * + * \ingroup OmGtk + */ +class PatchView : public Gtk::Box +{ +public: + PatchView(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& glade_xml); + + void patch_controller(PatchController* pc); + + OmFlowCanvas* canvas() const { return m_canvas; } + PatchController* patch_controller() const { return m_patch; } + + void show_control_window(); + void zoom_changed(); + void process_toggled(); + + void enabled(bool e); + +private: + PatchController* m_patch; + OmFlowCanvas* m_canvas; + + Gtk::ScrolledWindow* m_canvas_scrolledwindow; + Gtk::HScale* m_zoom_slider; + Gtk::Label* m_polyphony_label; + Gtk::CheckButton* m_process_checkbutton; + + bool m_enable_signal; +}; + + +} // namespace OmGtk + +#endif // PATCHVIEW_H diff --git a/src/progs/gtk/PatchWindow.cpp b/src/progs/gtk/PatchWindow.cpp new file mode 100644 index 00000000..1513d473 --- /dev/null +++ b/src/progs/gtk/PatchWindow.cpp @@ -0,0 +1,532 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PatchWindow.h" +#include <iostream> +#include <cassert> +#include <fstream> +#include "App.h" +#include "PatchView.h" +#include "OmFlowCanvas.h" +#include "PatchController.h" +#include "LoadPluginWindow.h" +#include "PatchModel.h" +#include "NewSubpatchWindow.h" +#include "LoadPatchWindow.h" +#include "LoadSubpatchWindow.h" +#include "NodeControlWindow.h" +#include "PatchDescriptionWindow.h" +#include "ConfigWindow.h" +#include "MessagesWindow.h" +#include "PatchTreeWindow.h" +#include "Controller.h" +#include "BreadCrumb.h" +#include "Store.h" + +namespace OmGtk { + + +PatchWindow::PatchWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& xml) +: Gtk::Window(cobject), + m_patch(NULL), + m_load_plugin_window(NULL), + m_new_subpatch_window(NULL), + m_enable_signal(true), + m_position_stored(false), + m_x(0), + m_y(0) +{ + property_visible() = false; + + xml->get_widget("patch_win_vbox", m_vbox); + xml->get_widget("patch_win_viewport", m_viewport); + xml->get_widget("patch_win_breadcrumb_box", m_breadcrumb_box); + //xml->get_widget("patch_win_status_bar", m_status_bar); + xml->get_widget("patch_open_menuitem", m_menu_open); + xml->get_widget("patch_open_into_menuitem", m_menu_open_into); + xml->get_widget("patch_save_menuitem", m_menu_save); + xml->get_widget("patch_save_as_menuitem", m_menu_save_as); + xml->get_widget("patch_close_menuitem", m_menu_close); + xml->get_widget("patch_configuration_menuitem", m_menu_configuration); + xml->get_widget("patch_quit_menuitem", m_menu_quit); + xml->get_widget("patch_quit_and_kill_menuitem", m_menu_quit_and_kill); + xml->get_widget("patch_view_control_window_menuitem", m_menu_view_control_window); + xml->get_widget("patch_description_menuitem", m_menu_view_patch_description); + xml->get_widget("patch_fullscreen_menuitem", m_menu_fullscreen); + xml->get_widget("patch_clear_menuitem", m_menu_clear); + xml->get_widget("patch_destroy_menuitem", m_menu_destroy_patch); + xml->get_widget("patch_add_plugin_menuitem", m_menu_add_plugin); + xml->get_widget("patch_add_new_subpatch_menuitem", m_menu_new_subpatch); + xml->get_widget("patch_add_subpatch_from_file_menuitem", m_menu_load_subpatch); + xml->get_widget("patch_view_messages_window_menuitem", m_menu_view_messages_window); + xml->get_widget("patch_view_patch_tree_window_menuitem", m_menu_view_patch_tree_window); + xml->get_widget("patch_help_about_menuitem", m_menu_help_about); + + xml->get_widget_derived("load_plugin_win", m_load_plugin_window); + xml->get_widget_derived("new_subpatch_win", m_new_subpatch_window); + xml->get_widget_derived("load_patch_win", m_load_patch_window); + xml->get_widget_derived("load_subpatch_win", m_load_subpatch_window); + xml->get_widget_derived("patch_description_win", m_description_window); + + //m_load_plugin_window->set_transient_for(*this); + m_new_subpatch_window->set_transient_for(*this); + m_load_patch_window->set_transient_for(*this); + m_load_subpatch_window->set_transient_for(*this); + m_description_window->set_transient_for(*this); + + m_menu_view_control_window->property_sensitive() = false; + //m_status_bar->push(Controller::instance().engine_url()); + //m_status_bar->pack_start(*Gtk::manage(new Gtk::Image(Gtk::Stock::CONNECT, Gtk::ICON_SIZE_MENU)), false, false); + + m_menu_open->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_open)); + m_menu_open_into->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_open_into)); + m_menu_save->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_save)); + m_menu_save_as->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_save_as)); + m_menu_close->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_close)); + m_menu_quit->signal_activate().connect( + sigc::mem_fun(App::instance(), &App::quit)); + m_menu_quit_and_kill->signal_activate().connect( + sigc::mem_fun(App::instance(), &App::quit_and_kill)); + m_menu_configuration->signal_activate().connect( + sigc::mem_fun(App::instance().configuration_dialog(), &ConfigWindow::show)); + m_menu_fullscreen->signal_toggled().connect( + sigc::mem_fun(this, &PatchWindow::event_fullscreen_toggled)); + m_menu_view_control_window->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::show_control_window)); + m_menu_view_patch_description->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::show_description_window)); + m_menu_destroy_patch->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_destroy)); + m_menu_clear->signal_activate().connect( + sigc::mem_fun(this, &PatchWindow::event_clear)); + m_menu_add_plugin->signal_activate().connect( + sigc::mem_fun<void>(m_load_plugin_window, &LoadPluginWindow::present)); + m_menu_new_subpatch->signal_activate().connect( + sigc::mem_fun<void>(m_new_subpatch_window, &NewSubpatchWindow::present)); + m_menu_load_subpatch->signal_activate().connect( + sigc::mem_fun<void>(m_load_subpatch_window, &LoadSubpatchWindow::present)); + m_menu_view_messages_window->signal_activate().connect( + sigc::mem_fun<void>(App::instance().messages_dialog(), &MessagesWindow::present)); + m_menu_view_patch_tree_window->signal_activate().connect( + sigc::mem_fun<void>(App::instance().patch_tree(), &PatchTreeWindow::present)); + + // Temporary workaround for Gtkmm 2.4 (no AboutDialog) + if (App::instance().about_dialog() != NULL) + m_menu_help_about->signal_activate().connect( + sigc::mem_fun<void>(App::instance().about_dialog(), &Gtk::Dialog::present)); + + App::instance().add_patch_window(this); +} + + +PatchWindow::~PatchWindow() +{ + App::instance().remove_patch_window(this); + + hide(); + + delete m_new_subpatch_window; + delete m_load_subpatch_window; +} + + +/** Sets the patch controller for this window and initializes everything. + * + * This function MUST be called before using the window in any way! + */ +void +PatchWindow::patch_controller(PatchController* pc) +{ + m_enable_signal = false; + + assert(pc != NULL); + assert(m_patch != pc); + assert(m_patch == NULL || + pc->model()->path() != m_patch->model()->path()); + + PatchController* old_pc = m_patch; + if (old_pc != NULL) { + assert(old_pc->window() == NULL || old_pc->window() == this); + old_pc->claim_patch_view(); + old_pc->window(NULL); + } + + m_patch = pc; + + if (pc->view() == NULL) + pc->create_view(); + assert(pc->view() != NULL); + + PatchView* const patch_view = pc->view(); + assert(patch_view != NULL); + patch_view->reparent(*m_viewport); + pc->window(this); + show_all(); + + assert(m_load_plugin_window != NULL); + assert(m_new_subpatch_window != NULL); + assert(m_load_patch_window != NULL); + assert(m_load_subpatch_window != NULL); + + m_load_patch_window->patch_controller(m_patch); + m_load_plugin_window->patch_controller(m_patch); + m_new_subpatch_window->patch_controller(m_patch); + m_load_subpatch_window->patch_controller(m_patch); + + m_menu_view_control_window->property_sensitive() = pc->has_control_inputs(); + + int width, height; + get_size(width, height); + patch_view->canvas()->scroll_to( + ((int)patch_view->canvas()->width() - width)/2, + ((int)patch_view->canvas()->height() - height)/2); + + set_title(m_patch->model()->path()); + + m_description_window->patch_model(pc->patch_model()); + + + // Setup breadcrumbs box + // FIXME: this is filthy + + // Moving to a parent patch, depress correct button + if (old_pc != NULL && + old_pc->model()->path().substr(0, pc->model()->path().length()) + == pc->model()->path()) { + for (list<BreadCrumb*>::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { + if ((*i)->patch() == pc) + (*i)->set_active(true); + else if ((*i)->patch() == old_pc) + (*i)->set_active(false); + } + + // Rebuild breadcrumbs from scratch (yeah, laziness..) + } else { + rebuild_breadcrumbs(); + } + + if (pc->model()->path() == "/") + m_menu_destroy_patch->set_sensitive(false); + else + m_menu_destroy_patch->set_sensitive(true); + + assert(old_pc == NULL || old_pc->window() != this); + assert(m_patch == pc); + assert(m_patch->window() == this); + + m_enable_signal = true; +} + + +/** Destroys current breadcrumbs and rebuilds from scratch. + * + * (Needs to be called when a patch is cleared to eliminate children crumbs) + */ +void +PatchWindow::rebuild_breadcrumbs() +{ + // Empty existing breadcrumbs + for (list<BreadCrumb*>::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) + m_breadcrumb_box->remove(**i); + m_breadcrumbs.clear(); + + // Add new ones + string path = m_patch->path(); // To be chopped up, starting at the left + string but_name; // Name on breadcrumb button + string but_path; // Full path breadcrumb represents + + // Add root + assert(path[0] == '/'); + BreadCrumb* but = manage(new BreadCrumb(this, Store::instance().patch("/"))); + m_breadcrumb_box->pack_start(*but, false, false, 1); + m_breadcrumbs.push_back(but); + path = path.substr(1); // hack off leading slash + + // Add the rest + while (path.length() > 0) { + if (path.find("/") != string::npos) { + but_name = path.substr(0, path.find("/")); + but_path += string("/") + path.substr(0, path.find("/")); + path = path.substr(path.find("/")+1); + } else { + but_name = path; + but_path += string("/") + path; + path = ""; + } + BreadCrumb* but = manage(new BreadCrumb(this, Store::instance().patch(but_path))); + m_breadcrumb_box->pack_start(*but, false, false, 1); + m_breadcrumbs.push_back(but); + } + (*m_breadcrumbs.back()).set_active(true); + +} + + +void +PatchWindow::breadcrumb_clicked(BreadCrumb* crumb) +{ + if (m_enable_signal) { + PatchController* const pc = crumb->patch(); + assert(pc != NULL); + + if (pc == m_patch) { + crumb->set_active(true); + } else if (pc->window() != NULL && pc->window()->is_visible()) { + pc->show_patch_window(); + crumb->set_active(false); + } else { + patch_controller(pc); + } + } +} + + +void +PatchWindow::show_control_window() +{ + if (m_patch != NULL) + m_patch->show_control_window(); +} + + +void +PatchWindow::show_description_window() +{ + m_description_window->show(); +} + + +/** Notification a node has been removed from the PatchView this window + * currently contains. + * + * This is used to update the breadcrumbs in case the Node is a patch which has + * a button present in the breadcrumbs that needs to be removed. + */ +void +PatchWindow::node_removed(const string& name) +{ + for (list<BreadCrumb*>::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { + if ((*i)->patch()->path() == m_patch->model()->base_path() + name) { + for (list<BreadCrumb*>::iterator j = i; j != m_breadcrumbs.end(); ) { + BreadCrumb* bc = *j; + j = m_breadcrumbs.erase(j); + m_breadcrumb_box->remove(*bc); + } + break; + } + } +} + + +/** Same as @a node_removed, but for renaming. + */ +void +PatchWindow::node_renamed(const string& old_path, const string& new_path) +{ + for (list<BreadCrumb*>::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { + if ((*i)->patch()->model()->path() == old_path) + (*i)->path(new_path); + } +} + + +/** Notification the patch this window is currently showing was renamed. + */ +void +PatchWindow::patch_renamed(const string& new_path) +{ + set_title(new_path); + for (list<BreadCrumb*>::iterator i = m_breadcrumbs.begin(); i != m_breadcrumbs.end(); ++i) { + if ((*i)->patch() == m_patch) + (*i)->path(new_path); + } +} + + +void +PatchWindow::event_open() +{ + m_load_patch_window->set_replace(); + m_load_patch_window->present(); +} + +void +PatchWindow::event_open_into() +{ + m_load_patch_window->set_merge(); + m_load_patch_window->present(); +} + + +void +PatchWindow::event_save() +{ + PatchModel* const model = m_patch->patch_model(); + + if (model->filename() == "") + event_save_as(); + else + Controller::instance().save_patch(model, model->filename(), false); +} + + +void +PatchWindow::event_save_as() +{ + Gtk::FileChooserDialog dialog(*this, "Save Patch", Gtk::FILE_CHOOSER_ACTION_SAVE); + + Gtk::VBox* box = dialog.get_vbox(); + Gtk::Label warning("Warning: Recursively saving will overwrite any subpatch files \ + without confirmation."); + box->pack_start(warning, false, false, 2); + Gtk::CheckButton recursive_checkbutton("Recursively save all subpatches"); + box->pack_start(recursive_checkbutton, false, false, 0); + recursive_checkbutton.show(); + + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + + // Set current folder to most sensible default + const string& current_filename = m_patch->patch_model()->filename(); + if (current_filename.length() > 0) + dialog.set_filename(current_filename); + else if (App::instance().configuration()->patch_folder().length() > 0) + dialog.set_current_folder(App::instance().configuration()->patch_folder()); + + int result = dialog.run(); + bool recursive = recursive_checkbutton.get_active(); + + assert(result == Gtk::RESPONSE_OK || result == Gtk::RESPONSE_CANCEL || result == Gtk::RESPONSE_NONE); + + if (result == Gtk::RESPONSE_OK) { + string filename = dialog.get_filename(); + if (filename.length() < 4 || filename.substr(filename.length()-3) != ".om") + filename += ".om"; + + bool confirm = false; + std::fstream fin; + fin.open(filename.c_str(), std::ios::in); + if (fin.is_open()) { // File exists + string msg = "File already exists! Are you sure you want to overwrite "; + msg += filename + "?"; + Gtk::MessageDialog confirm_dialog(*this, + msg, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); + if (confirm_dialog.run() == Gtk::RESPONSE_YES) + confirm = true; + else + confirm = false; + } else { // File doesn't exist + confirm = true; + } + fin.close(); + + if (confirm) { + Controller::instance().save_patch(m_patch->patch_model(), filename, recursive); + m_patch->patch_model()->filename(filename); + } + } + App::instance().configuration()->set_patch_folder(dialog.get_current_folder()); +} + + +void +PatchWindow::on_show() +{ + if (m_position_stored) + move(m_x, m_y); + + Gtk::Window::on_show(); +} + + +void +PatchWindow::on_hide() +{ + m_position_stored = true; + get_position(m_x, m_y); + Gtk::Window::on_hide(); +} + + +bool +PatchWindow::on_delete_event(GdkEventAny* ev) +{ + event_close(); + return true; // destroy window +} + + +bool +PatchWindow::on_key_press_event(GdkEventKey* event) +{ + if (event->keyval == GDK_Delete) { + if (m_patch != NULL && m_patch->view() != NULL) { + assert(m_patch->view()->canvas() != NULL); + m_patch->view()->canvas()->destroy_selected(); + } + return true; + } else { + return Gtk::Window::on_key_press_event(event); + } +} + + +void +PatchWindow::event_close() +{ + if (App::instance().num_open_patch_windows() > 1) { + hide(); + } else { + Gtk::MessageDialog d(*this, "This is the last remaining open Om patch\ +window. Closing this window will exit OmGtk (the engine will remain running).\n\n\ +Are you sure you want to quit?", + true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK_CANCEL, true); + int ret = d.run(); + if (ret == Gtk::RESPONSE_OK) + App::instance().quit(); + } +} + + +void +PatchWindow::event_destroy() +{ + Controller::instance().destroy(m_patch->model()->path()); +} + + +void +PatchWindow::event_clear() +{ + Controller::instance().clear_patch(m_patch->model()->path()); +} + +void +PatchWindow::event_fullscreen_toggled() +{ + if (m_menu_fullscreen->get_active()) + fullscreen(); + else + unfullscreen(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/PatchWindow.h b/src/progs/gtk/PatchWindow.h new file mode 100644 index 00000000..54ea11ef --- /dev/null +++ b/src/progs/gtk/PatchWindow.h @@ -0,0 +1,142 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PATCHWINDOW_H +#define PATCHWINDOW_H + +#include <string> +#include <list> +#include <gtkmm.h> +#include <libglademm/xml.h> +#include <libglademm.h> + +using std::string; using std::list; + +namespace LibOmClient { +class PatchModel; +class NodeModel; +class PortModel; +class ControlModel; +class MetadataModel; +} +using namespace LibOmClient; + + +namespace OmGtk { + +class PatchController; +class OmFlowCanvas; +class PatchView; +class LoadPluginWindow; +class LoadPatchWindow; +class NewSubpatchWindow; +class LoadSubpatchWindow; +class NewSubpatchWindow; +class NodeControlWindow; +class PatchDescriptionWindow; +class SubpatchModule; +class OmPort; +class BreadCrumb; + + +/** A window for a patch. + * + * \ingroup OmGtk + */ +class PatchWindow : public Gtk::Window +{ +public: + PatchWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& glade_xml); + ~PatchWindow(); + + void patch_controller(PatchController* pc); + + PatchController* patch_controller() const { return m_patch; } + LoadPluginWindow* load_plugin_window() const { return m_load_plugin_window; } + LoadSubpatchWindow* load_subpatch_window() const { return m_load_subpatch_window; } + NewSubpatchWindow* new_subpatch_window() const { return m_new_subpatch_window; } + + void show_control_window(); + void show_description_window(); + + // Breadcrumb management + void node_removed(const string& name); + void node_renamed(const string& old_path, const string& new_path); + void patch_renamed(const string& new_path); + void rebuild_breadcrumbs(); + void breadcrumb_clicked(BreadCrumb* crumb); + + Gtk::MenuItem* menu_view_control_window() { return m_menu_view_control_window; } + +protected: + void on_show(); + void on_hide(); + bool on_delete_event(GdkEventAny* ev); + bool on_key_press_event(GdkEventKey* event); + +private: + void event_open(); + void event_open_into(); + void event_save(); + void event_save_as(); + void event_close(); + void event_destroy(); + void event_clear(); + void event_fullscreen_toggled(); + + PatchController* m_patch; + LoadPluginWindow* m_load_plugin_window; + LoadPatchWindow* m_load_patch_window; + NewSubpatchWindow* m_new_subpatch_window; + LoadSubpatchWindow* m_load_subpatch_window; + PatchDescriptionWindow* m_description_window; + + bool m_enable_signal; + bool m_position_stored; + int m_x; + int m_y; + + Gtk::MenuItem* m_menu_open; + Gtk::MenuItem* m_menu_open_into; + Gtk::MenuItem* m_menu_save; + Gtk::MenuItem* m_menu_save_as; + Gtk::MenuItem* m_menu_configuration; + Gtk::MenuItem* m_menu_close; + Gtk::MenuItem* m_menu_quit; + Gtk::MenuItem* m_menu_quit_and_kill; + Gtk::CheckMenuItem* m_menu_fullscreen; + Gtk::MenuItem* m_menu_clear; + Gtk::MenuItem* m_menu_destroy_patch; + Gtk::MenuItem* m_menu_view_control_window; + Gtk::MenuItem* m_menu_view_patch_description; + Gtk::MenuItem* m_menu_add_plugin; + Gtk::MenuItem* m_menu_new_subpatch; + Gtk::MenuItem* m_menu_load_subpatch; + Gtk::MenuItem* m_menu_view_messages_window; + Gtk::MenuItem* m_menu_view_patch_tree_window; + Gtk::MenuItem* m_menu_help_about; + + Gtk::VBox* m_vbox; + Gtk::Viewport* m_viewport; + Gtk::HBox* m_breadcrumb_box; + list<BreadCrumb*> m_breadcrumbs; + //Gtk::Statusbar* m_status_bar; +}; + + +} // namespace OmGtk + +#endif // PATCHWINDOW_H diff --git a/src/progs/gtk/PortController.cpp b/src/progs/gtk/PortController.cpp new file mode 100644 index 00000000..ec05541b --- /dev/null +++ b/src/progs/gtk/PortController.cpp @@ -0,0 +1,143 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PortController.h" +#include "OmModule.h" +#include "PortModel.h" +#include "ControlPanel.h" +#include "OmPort.h" +#include "Store.h" + +namespace OmGtk { + + +PortController::PortController(PortModel* model) +: GtkObjectController(model), + m_port(NULL), + m_control_panel(NULL) +{ + assert(model != NULL); + assert(model->parent() != NULL); + assert(model->controller() == NULL); + + model->set_controller(this); +} + + +void +PortController::add_to_store() +{ + Store::instance().add_object(this); +} + + +void +PortController::remove_from_store() +{ + Store::instance().remove_object(this); +} + + +void +PortController::destroy() +{ + assert(m_model->parent() != NULL); + NodeController* parent = (NodeController*)m_model->parent()->controller(); + assert(parent != NULL); + + if (m_control_panel != NULL) + m_control_panel->remove_port(path()); + + parent->remove_port(path(), false); +} + + +void +PortController::metadata_update(const string& key, const string& value) +{ + // FIXME: double lookups + + //cerr << path() << ": " << key << " = " << value << endl; + + if (key == "user-min") { + port_model()->user_min(atof(value.c_str())); + if (m_control_panel != NULL) + m_control_panel->set_range_min(m_model->path(), atof(value.c_str())); + } else if (key == "user-max") { + port_model()->user_max(atof(value.c_str())); + if (m_control_panel != NULL) + m_control_panel->set_range_max(m_model->path(), atof(value.c_str())); + } + + GtkObjectController::metadata_update(key, value); +} + + +void +PortController::control_change(float value) +{ + // FIXME: double lookups + + port_model()->value(value); + + if (m_control_panel != NULL) + m_control_panel->set_control(port_model()->path(), value); +} + + +/** "Register" a control panel that is monitoring this port. + * + * The OmPort will handle notifying the ControlPanel when state + * changes occur, etc. + */ +void +PortController::set_control_panel(ControlPanel* cp) +{ + assert(m_control_panel == NULL); + m_control_panel = cp; +} + + +void +PortController::set_path(const Path& new_path) +{ + // Change port name on module, if view exists + if (m_port != NULL) + m_port->set_name(new_path.name()); + + if (m_control_panel != NULL) + m_control_panel->rename_port(m_model->path(), new_path); + + m_model->set_path(new_path); +} + + +/** Create the visible port on a canvas module. + * + * Does not resize the module, caller's responsibility to do so if necessary. + */ +void +PortController::create_port(OmModule* module) +{ + assert(module != NULL); + + m_port = new OmPort(module, port_model()); + module->add_port(m_port, false); +} + + +} // namespace OmGtk + diff --git a/src/progs/gtk/PortController.h b/src/progs/gtk/PortController.h new file mode 100644 index 00000000..cc2f9dc3 --- /dev/null +++ b/src/progs/gtk/PortController.h @@ -0,0 +1,75 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PORTCONTROLLER_H +#define PORTCONTROLLER_H + +#include <string> +#include <gtkmm.h> +#include "GtkObjectController.h" + +using std::string; +using namespace LibOmClient; + +namespace LibOmClient { + class MetadataModel; + class PortModel; +} + +namespace OmGtk { + +class Controller; +class OmPort; +class ControlPanel; +class OmModule; + + +/** Controller for a port on a (non-patch) node. + * + * \ingroup OmGtk + */ +class PortController : public GtkObjectController +{ +public: + PortController(PortModel* model); + virtual ~PortController() {} + + virtual void destroy(); + + virtual void add_to_store(); + virtual void remove_from_store(); + + virtual void metadata_update(const string& key, const string& value); + + void create_port(OmModule* module); + void set_path(const Path& new_path); + + void control_change(float value); + + ControlPanel* control_panel() const { return m_control_panel; } + void set_control_panel(ControlPanel* cp); + + PortModel* port_model() const { return (PortModel*)m_model; } + +private: + OmPort* m_port; ///< Canvas module port + ControlPanel* m_control_panel; ///< Control panel that contains this port +}; + + +} // namespace OmGtk + +#endif // PORTCONTROLLER_H diff --git a/src/progs/gtk/RenameWindow.cpp b/src/progs/gtk/RenameWindow.cpp new file mode 100644 index 00000000..bde9a2c1 --- /dev/null +++ b/src/progs/gtk/RenameWindow.cpp @@ -0,0 +1,113 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "RenameWindow.h" +#include <cassert> +#include <string> +#include "Controller.h" +#include "ObjectModel.h" +#include "GtkObjectController.h" +#include "Store.h" +using std::string; + +namespace OmGtk { + + +RenameWindow::RenameWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& glade_xml) +: Gtk::Window(cobject) +{ + glade_xml->get_widget("rename_name_entry", m_name_entry); + glade_xml->get_widget("rename_message_label", m_message_label); + glade_xml->get_widget("rename_cancel_button", m_cancel_button); + glade_xml->get_widget("rename_ok_button", m_ok_button); + + m_name_entry->signal_changed().connect(sigc::mem_fun(this, &RenameWindow::name_changed)); + m_cancel_button->signal_clicked().connect(sigc::mem_fun(this, &RenameWindow::cancel_clicked)); + m_ok_button->signal_clicked().connect(sigc::mem_fun(this, &RenameWindow::ok_clicked)); + + m_ok_button->property_sensitive() = false; +} + + +/** Set the object this window is renaming. + * This function MUST be called before using this object in any way. + */ +void +RenameWindow::set_object(GtkObjectController* object) +{ + m_object = object; + m_name_entry->set_text(object->path().name()); +} + + +/** Called every time the user types into the name input box. + * Used to display warning messages, and enable/disable the rename button. + */ +void +RenameWindow::name_changed() +{ + assert(m_name_entry != NULL); + assert(m_message_label != NULL); + assert(m_object->model() != NULL); + assert(m_object->model()->parent() != NULL); + + string name = m_name_entry->get_text(); + if (name.find("/") != string::npos) { + m_message_label->set_text("Name may not contain '/'"); + m_ok_button->property_sensitive() = false; + //} else if (m_object->parent()->patch_model()->get_node(name) != NULL) { + } else if (Store::instance().object(m_object->model()->parent()->base_path() + name) != NULL) { + m_message_label->set_text("An object already exists with that name."); + m_ok_button->property_sensitive() = false; + } else if (name.length() == 0) { + m_message_label->set_text(""); + m_ok_button->property_sensitive() = false; + } else { + m_message_label->set_text(""); + m_ok_button->property_sensitive() = true; + } +} + + +void +RenameWindow::cancel_clicked() +{ + cout << "cancel\n"; + m_name_entry->set_text(""); + hide(); +} + + +/** Rename the object. + * + * It shouldn't be possible for this to be called with an invalid name set + * (since the Rename button should be deactivated). This is just shinification + * though - the engine will handle invalid names gracefully. + */ +void +RenameWindow::ok_clicked() +{ + string name = m_name_entry->get_text(); + assert(name.length() > 0); + assert(name.find("/") == string::npos); + + Controller::instance().rename(m_object->model()->path(), name); + + hide(); +} + + +} // namespace OmGtk diff --git a/src/progs/gtk/RenameWindow.h b/src/progs/gtk/RenameWindow.h new file mode 100644 index 00000000..81dc96e3 --- /dev/null +++ b/src/progs/gtk/RenameWindow.h @@ -0,0 +1,57 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef RENAMEWINDOW_H +#define RENAMEWINDOW_H + +#include <gtkmm.h> +#include <libglademm.h> + + +namespace OmGtk { + +class GtkObjectController; + + +/** 'New Patch' Window. + * + * Loaded by libglade as a derived object. + * + * \ingroup OmGtk + */ +class RenameWindow : public Gtk::Window +{ +public: + RenameWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade); + + void set_object(GtkObjectController* object); + +private: + void name_changed(); + void cancel_clicked(); + void ok_clicked(); + + GtkObjectController* m_object; + + Gtk::Entry* m_name_entry; + Gtk::Label* m_message_label; + Gtk::Button* m_cancel_button; + Gtk::Button* m_ok_button; +}; + +} // namespace OmGtk + +#endif // RENAMEWINDOW_H diff --git a/src/progs/gtk/Store.cpp b/src/progs/gtk/Store.cpp new file mode 100644 index 00000000..97e556c9 --- /dev/null +++ b/src/progs/gtk/Store.cpp @@ -0,0 +1,155 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Store.h" +#include "GtkObjectController.h" +#include "PatchController.h" +#include "NodeController.h" +#include "PortController.h" +#include "PluginModel.h" +#include "SigClientInterface.h" + +namespace OmGtk { + +Store::Store(SigClientInterface& emitter) +{ + //emitter.new_plugin_sig.connect(sigc::mem_fun(this, &Store::add_plugin)); + emitter.object_destroyed_sig.connect(sigc::mem_fun(this, &Store::destruction_event)); + emitter.new_plugin_sig.connect(sigc::mem_fun(this, &Store::new_plugin_event)); +} + +void +Store::add_object(GtkObjectController* object) +{ + assert(object->path() != ""); + assert(m_objects.find(object->path()) == m_objects.end()); + + m_objects[object->path()] = object; + + cout << "[Store] Added " << object->path() << endl; +} + + +void +Store::remove_object(GtkObjectController* object) +{ + if (!object) + return; + + map<string, GtkObjectController*>::iterator i + = m_objects.find(object->model()->path()); + + if (i != m_objects.end()) { + assert((*i).second == object); + m_objects.erase(i); + } else { + cerr << "[App] Unable to find object " << object->model()->path() + << " to remove." << endl; + } + + cout << "[Store] Removed " << object->path() << endl; +} + + +GtkObjectController* +Store::object(const string& path) const +{ + assert(path.length() > 0); + map<string, GtkObjectController*>::const_iterator i = m_objects.find(path); + if (i == m_objects.end()) + return NULL; + else + return (*i).second; +} + + +PatchController* +Store::patch(const string& path) const +{ + assert(path.length() > 0); + map<string, GtkObjectController*>::const_iterator i = m_objects.find(path); + if (i == m_objects.end()) + return NULL; + else + return dynamic_cast<PatchController*>((*i).second); +} + + +NodeController* +Store::node(const string& path) const +{ + assert(path.length() > 0); + map<string, GtkObjectController*>::const_iterator i = m_objects.find(path); + if (i == m_objects.end()) + return NULL; + else + return dynamic_cast<NodeController*>((*i).second); +} + + +PortController* +Store::port(const string& path) const +{ + assert(path.length() > 0); + map<string, GtkObjectController*>::const_iterator i = m_objects.find(path); + if (i == m_objects.end()) { + return NULL; + } else { + // Normal port + PortController* const pc = dynamic_cast<PortController*>((*i).second); + if (pc != NULL) + return pc; + + // Patch port (corresponding Node is in store) + NodeController* const nc = dynamic_cast<NodeController*>((*i).second); + if (nc != NULL) + return nc->as_port(); // Patch port (maybe) + } + + return NULL; +} + + +void +Store::add_plugin(const PluginModel* pm) +{ + if (m_plugins.find(pm->uri()) != m_plugins.end()) { + cerr << "DUPE! " << pm->uri() << endl; + delete m_plugins[pm->uri()]; + } + + m_plugins[pm->uri()] = pm; +} + + +/* ****** Slots ******** */ + +void +Store::destruction_event(const string& path) +{ + remove_object(object(path)); +} + +void +Store::new_plugin_event(const string& type, const string& uri, const string& name) +{ + PluginModel* const p = new PluginModel(type, uri); + p->name(name); + add_plugin(p); +} + +} // namespace OmGtk + diff --git a/src/progs/gtk/Store.h b/src/progs/gtk/Store.h new file mode 100644 index 00000000..9fb4b270 --- /dev/null +++ b/src/progs/gtk/Store.h @@ -0,0 +1,75 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef STORE_H +#define STORE_H + +#include <cassert> +#include <string> +#include <map> +using std::string; using std::map; + +namespace LibOmClient { class PatchModel; class PluginModel; class SigClientInterface; } +using namespace LibOmClient; + +namespace OmGtk { + +class GtkObjectController; +class PatchController; +class NodeController; +class PortController; + +/** Singeton which holds all "Om Objects" for easy/fast lookup + * + * \ingroup OmGtk + */ +class Store { +public: + GtkObjectController* object(const string& path) const; + PatchController* patch(const string& path) const; + NodeController* node(const string& path) const; + PortController* port(const string& path) const; + + void add_object(GtkObjectController* object); + void remove_object(GtkObjectController* object); + + size_t num_objects() { return m_objects.size(); } + + void add_plugin(const PluginModel* pm); + const map<string, const PluginModel*>& plugins() const { return m_plugins; } + + static void instantiate(SigClientInterface& emitter) + { if (!_instance) _instance = new Store(emitter); } + + inline static Store& instance() { assert(_instance); return *_instance; } + +private: + Store(SigClientInterface& emitter); + + static Store* _instance; + + // Slots for SigClientInterface signals + void destruction_event(const string& path); + void new_plugin_event(const string& type, const string& uri, const string& name); + + map<string, GtkObjectController*> m_objects; ///< Keyed by Om path + map<string, const PluginModel*> m_plugins; ///< Keyed by URI +}; + + +} // namespace OmGtk + +#endif // STORE_H diff --git a/src/progs/gtk/SubpatchModule.cpp b/src/progs/gtk/SubpatchModule.cpp new file mode 100644 index 00000000..9c0e78e4 --- /dev/null +++ b/src/progs/gtk/SubpatchModule.cpp @@ -0,0 +1,102 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "SubpatchModule.h" +#include <cassert> +#include <iostream> +#include "OmModule.h" +#include "NodeControlWindow.h" +#include "PatchModel.h" +#include "PatchWindow.h" +#include "OmFlowCanvas.h" +#include "PatchController.h" +#include "OmPort.h" +#include "Controller.h" +using std::cerr; using std::cout; using std::endl; + +namespace OmGtk { + + +SubpatchModule::SubpatchModule(OmFlowCanvas* canvas, PatchController* patch) +: OmModule(canvas, patch), + m_patch(patch) +{ + assert(canvas != NULL); + assert(patch != NULL); +} + + +void +SubpatchModule::add_om_port(PortModel* pm, bool resize_to_fit) +{ + OmPort* port = new OmPort(this, pm); + + port->signal_event().connect( + sigc::bind<Port*>(sigc::mem_fun(m_canvas, &OmFlowCanvas::port_event), port)); + + Module::add_port(port, resize_to_fit); +} + + +void +SubpatchModule::on_double_click(GdkEventButton* event) +{ + assert(m_patch != NULL); + + // If window is visible + if (m_patch->window() != NULL + && m_patch->window()->is_visible()) { + m_patch->show_patch_window(); // just raise it + // No window visible + } else { + if (event->state & GDK_SHIFT_MASK) + m_patch->show_patch_window(); // open a new window + else + browse_to_patch(); + } +} + + + +/** Browse to this patch in current (parent's) window. */ +void +SubpatchModule::browse_to_patch() +{ + assert(m_patch->model()->parent() != NULL); + PatchController* pc = (PatchController*)m_patch->model()->parent()->controller(); + assert(pc != NULL); + assert(pc->window() != NULL); + + assert(pc->window() != NULL); + pc->window()->patch_controller(m_patch); +} + + + +void +SubpatchModule::show_dialog() +{ + m_patch->show_control_window(); +} + + +void +SubpatchModule::menu_remove() +{ + Controller::instance().destroy(m_patch->model()->path()); +} + +} // namespace OmGtk diff --git a/src/progs/gtk/SubpatchModule.h b/src/progs/gtk/SubpatchModule.h new file mode 100644 index 00000000..162779d7 --- /dev/null +++ b/src/progs/gtk/SubpatchModule.h @@ -0,0 +1,69 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef SUBPATCHMODULE_H +#define SUBPATCHMODULE_H + +#include <string> +#include <libgnomecanvasmm.h> +#include "OmModule.h" +#include "PatchController.h" +using std::string; using std::list; + +namespace LibOmClient { +class PatchModel; +class NodeModel; +class PortModel; +class PatchWindow; +} +using namespace LibOmClient; + +namespace OmGtk { + +class OmFlowCanvas; +class NodeControlWindow; +class PatchController; + + +/** A module to represent a subpatch + * + * \ingroup OmGtk + */ +class SubpatchModule : public OmModule +{ +public: + SubpatchModule(OmFlowCanvas* canvas, PatchController* controller); + virtual ~SubpatchModule() {} + + void add_om_port(PortModel* pm, bool resize=true); + + void on_double_click(GdkEventButton* ev); + + void show_dialog(); + void browse_to_patch(); + void menu_remove(); + + PatchController* patch() { return m_patch; } + +protected: + PatchController* m_patch; +}; + + +} // namespace OmGtk + +#endif // SUBPATCHMODULE_H diff --git a/src/progs/gtk/cmdline.c b/src/progs/gtk/cmdline.c new file mode 100644 index 00000000..11fcd108 --- /dev/null +++ b/src/progs/gtk/cmdline.c @@ -0,0 +1,149 @@ +/* + File autogenerated by gengetopt version 2.10 + generated with the following command: + gengetopt + + The developers of gengetopt consider the fixed text that goes in all + gengetopt output files to be in the public domain: + we make no copyright claims on it. +*/ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "getopt.h" + +#include "cmdline.h" + +void +cmdline_parser_print_version (void) +{ + printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); +} + +void +cmdline_parser_print_help (void) +{ + cmdline_parser_print_version (); + printf("\n" + "Usage: %s [OPTIONS]...\n", CMDLINE_PARSER_PACKAGE); + printf(" -h --help Print help and exit\n"); + printf(" -V --version Print version and exit\n"); + printf(" -uSTRING --engine-url=STRING Om engine URL to connect to\n"); + printf(" -pINT --client-port=INT Client port to listen on\n"); +} + + +static char *gengetopt_strdup (const char *s); + +/* gengetopt_strdup() */ +/* strdup.c replacement of strdup, which is not standard */ +char * +gengetopt_strdup (const char *s) +{ + char *result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} + +int +cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) +{ + int c; /* Character of the parsed option. */ + int missing_required_options = 0; + + args_info->help_given = 0 ; + args_info->version_given = 0 ; + args_info->engine_url_given = 0 ; + args_info->client_port_given = 0 ; +#define clear_args() { \ + args_info->engine_url_arg = NULL; \ +} + + clear_args(); + + optarg = 0; + optind = 1; + opterr = 1; + optopt = '?'; + + while (1) + { + int option_index = 0; + char *stop_char; + + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "engine-url", 1, NULL, 'u' }, + { "client-port", 1, NULL, 'p' }, + { NULL, 0, NULL, 0 } + }; + + stop_char = 0; + c = getopt_long (argc, argv, "hVu:p:", long_options, &option_index); + + if (c == -1) break; /* Exit from `while (1)' loop. */ + + switch (c) + { + case 'h': /* Print help and exit. */ + clear_args (); + cmdline_parser_print_help (); + exit (EXIT_SUCCESS); + + case 'V': /* Print version and exit. */ + clear_args (); + cmdline_parser_print_version (); + exit (EXIT_SUCCESS); + + case 'u': /* Om engine URL to connect to. */ + if (args_info->engine_url_given) + { + fprintf (stderr, "%s: `--engine-url' (`-u') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->engine_url_given = 1; + args_info->engine_url_arg = gengetopt_strdup (optarg); + break; + + case 'p': /* Client port to listen on. */ + if (args_info->client_port_given) + { + fprintf (stderr, "%s: `--client-port' (`-p') option given more than once\n", CMDLINE_PARSER_PACKAGE); + clear_args (); + exit (EXIT_FAILURE); + } + args_info->client_port_given = 1; + args_info->client_port_arg = strtol (optarg,&stop_char,0); + break; + + + case 0: /* Long option with no short option */ + + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + exit (EXIT_FAILURE); + + default: /* bug: option not considered. */ + fprintf (stderr, "%s: option unknown: %c\n", CMDLINE_PARSER_PACKAGE, c); + abort (); + } /* switch */ + } /* while */ + + + if ( missing_required_options ) + exit (EXIT_FAILURE); + + return 0; +} diff --git a/src/progs/gtk/cmdline.ggo b/src/progs/gtk/cmdline.ggo new file mode 100644 index 00000000..d62cf521 --- /dev/null +++ b/src/progs/gtk/cmdline.ggo @@ -0,0 +1,7 @@ +# Process this file with gengetopt -u to generate the necessary code (in cmdline.h, cmdline.c) + +package "om_gtk - A GUI client for the Om realtime modular synthesizer" + +option "engine-url" u "Om engine URL to connect to" string no +option "client-port" p "Client port to listen on" int no + diff --git a/src/progs/gtk/cmdline.h b/src/progs/gtk/cmdline.h new file mode 100644 index 00000000..e404ac2e --- /dev/null +++ b/src/progs/gtk/cmdline.h @@ -0,0 +1,45 @@ +/* cmdline.h */ + +/* File autogenerated by gengetopt version 2.10 */ + +#ifndef CMDLINE_H +#define CMDLINE_H + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef CMDLINE_PARSER_PACKAGE +#define CMDLINE_PARSER_PACKAGE "om_gtk - A GUI client for the Om realtime modular synthesizer" +#endif + +#ifndef CMDLINE_PARSER_VERSION +#define CMDLINE_PARSER_VERSION VERSION +#endif + +struct gengetopt_args_info +{ + char * engine_url_arg; /* Om engine URL to connect to. */ + int client_port_arg; /* Client port to listen on. */ + + int help_given ; /* Whether help was given. */ + int version_given ; /* Whether version was given. */ + int engine_url_given ; /* Whether engine-url was given. */ + int client_port_given ; /* Whether client-port was given. */ + +} ; + +int cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info); + +void cmdline_parser_print_help(void); +void cmdline_parser_print_version(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CMDLINE_H */ diff --git a/src/progs/gtk/main.cpp b/src/progs/gtk/main.cpp new file mode 100644 index 00000000..702d52f9 --- /dev/null +++ b/src/progs/gtk/main.cpp @@ -0,0 +1,103 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "cmdline.h" +#include "ConnectWindow.h" +#include "App.h" +#include "Store.h" +#include "Controller.h" +#include "Configuration.h" +#include "GtkClientInterface.h" +#ifdef HAVE_LASH + #include "LashController.h" +#endif +#include "ThreadedSigClientInterface.h" +using Om::Shared::ClientInterface; + +using namespace OmGtk; + + +class OSCSigEmitter : public OSCListener, public ThreadedSigClientInterface { +public: + OSCSigEmitter(size_t queue_size, int listen_port) + : Om::Shared::ClientInterface() + , OSCListener(listen_port) + , ThreadedSigClientInterface(queue_size) + { + Glib::signal_timeout().connect( + sigc::mem_fun((ThreadedSigClientInterface*)this, + &ThreadedSigClientInterface::emit_signals), + 5, G_PRIORITY_DEFAULT_IDLE); + } +}; + + +int +main(int argc, char** argv) +{ + string engine_url = "osc.udp://localhost:16180"; + int client_port = 0; + + /* **** Parse command line options **** */ + gengetopt_args_info args_info; + if (cmdline_parser (argc, argv, &args_info) != 0) + return 1; + + if (args_info.engine_url_given) + engine_url = args_info.engine_url_arg; + if (args_info.client_port_given) + client_port = args_info.client_port_arg; + + // FIXME: + client_port = 16181; + + Gnome::Canvas::init(); + Gtk::Main gtk_main(argc, argv); + + OSCSigEmitter* emitter = new OSCSigEmitter(1024, 16181); + + //CountedPtr<Om::Shared::ClientInterface> emitter(new OSCSigEmitter(1024, 16181)); + + /* Instantiate all singletons */ + App::instantiate(); + Store::instantiate(*(SigClientInterface*)emitter); + ControlInterface* gtk_interface = App::instance().control_interface(); + assert(gtk_interface); + + //GtkClientInterface::instantiate(App::instance().control_interface(), client_port); + Controller::instantiate(engine_url); + + /* Load settings */ + App::instance().configuration()->load_settings(); + App::instance().configuration()->apply_settings(); + + #ifdef HAVE_LASH + lash_args_t* lash_args = lash_extract_args(&argc, &argv); + #endif + + //gtk_main.signal_quit().connect(sigc::ptr_fun(cleanup)); + + #ifdef HAVE_LASH + LashController* lash_controller = new LashController(lash_args); + #endif + + App::instance().connect_window()->start(CountedPtr<ClientInterface>(emitter)); + gtk_main.run(); + + return 0; +} + diff --git a/src/progs/gtk/om-icon.png b/src/progs/gtk/om-icon.png Binary files differnew file mode 100644 index 00000000..b26dd942 --- /dev/null +++ b/src/progs/gtk/om-icon.png diff --git a/src/progs/gtk/om_gtk.glade b/src/progs/gtk/om_gtk.glade new file mode 100644 index 00000000..abe5f254 --- /dev/null +++ b/src/progs/gtk/om_gtk.glade @@ -0,0 +1,3555 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> + +<widget class="GtkWindow" id="patch_win"> + <property name="border_width">1</property> + <property name="title" translatable="yes">Om</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="default_width">640</property> + <property name="default_height">480</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="patch_win_vbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkMenuBar" id="menubar"> + <property name="visible">True</property> + <property name="pack_direction">GTK_PACK_DIRECTION_LTR</property> + <property name="child_pack_direction">GTK_PACK_DIRECTION_LTR</property> + + <child> + <widget class="GtkMenuItem" id="patch_file_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_File</property> + <property name="use_underline">True</property> + + <child> + <widget class="GtkMenu" id="patch_file_menu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="patch_open_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Open (Replace)...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_open_(replace)1_activate" last_modification_time="Mon, 06 Feb 2006 06:20:27 GMT"/> + <accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1609"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_open_into_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">Open _Into (Import)...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_open_into_(merge)1_activate" last_modification_time="Mon, 06 Feb 2006 06:20:27 GMT"/> + <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1610"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator9"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_save_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Save this patch</property> + <property name="label" translatable="yes">_Save</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_file_save_patch_menuitem_activate" last_modification_time="Thu, 20 Jan 2005 08:35:00 GMT"/> + <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1611"> + <property name="visible">True</property> + <property name="stock">gtk-save</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_save_as_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Save this patch to a specific filename</property> + <property name="label" translatable="yes">Save _As...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_file_save_patch_menuitem_activate" last_modification_time="Sat, 23 Oct 2004 02:16:12 GMT"/> + <accelerator key="S" modifiers="GDK_CONTROL_MASK | GDK_SHIFT_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1612"> + <property name="visible">True</property> + <property name="stock">gtk-save-as</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator10"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_configuration_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Configure OmGtk</property> + <property name="label" translatable="yes">Confi_guration</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_configuration_menuitem_activate" last_modification_time="Sun, 29 Jan 2006 21:17:26 GMT"/> + <accelerator key="G" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1613"> + <property name="visible">True</property> + <property name="stock">gtk-preferences</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator11"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_close_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Close this window (patch will not be destroyed)</property> + <property name="label" translatable="yes">Close _Window</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_file_close_menuitem_activate" last_modification_time="Sat, 11 Sep 2004 20:05:11 GMT"/> + <accelerator key="W" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1614"> + <property name="visible">True</property> + <property name="stock">gtk-close</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator6"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_quit_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Quit OmGtk (Om engine will continue running)</property> + <property name="label" translatable="yes">_Quit</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_file_quit_nokill_menuitem_activate" last_modification_time="Sun, 29 Jan 2006 21:18:07 GMT"/> + <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1615"> + <property name="visible">True</property> + <property name="stock">gtk-quit</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_quit_and_kill_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Quit OmGtk and kill the Om engine</property> + <property name="label" translatable="yes">Quit and _Kill Engine</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_file_quit_and_kill_menuitem_activate" last_modification_time="Sun, 29 Jan 2006 21:18:19 GMT"/> + <accelerator key="Q" modifiers="GDK_CONTROL_MASK | GDK_SHIFT_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1616"> + <property name="visible">True</property> + <property name="stock">gtk-stop</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="patch_patch_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Patch</property> + <property name="use_underline">True</property> + + <child> + <widget class="GtkMenu" id="patch_patch_menu_menu"> + + <child> + <widget class="GtkCheckMenuItem" id="patch_fullscreen_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">Fullscreen</property> + <property name="use_underline">True</property> + <property name="active">False</property> + <signal name="activate" handler="patch_fullscreen_menuitem" last_modification_time="Sat, 11 Mar 2006 05:24:13 GMT"/> + <accelerator key="F11" modifiers="0" signal="activate"/> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator12"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_view_control_window_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">View/Edit controls for this patch</property> + <property name="label" translatable="yes">_Controls</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_view_control_window_menuitem_activate" last_modification_time="Wed, 20 Apr 2005 16:05:32 GMT"/> + <accelerator key="C" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1617"> + <property name="visible">True</property> + <property name="stock">gtk-preferences</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_description_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">View/Edit description for this patch</property> + <property name="label" translatable="yes">Descr_iption</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_description_menuitem_activate" last_modification_time="Mon, 08 Aug 2005 07:18:52 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1618"> + <property name="visible">True</property> + <property name="stock">gtk-edit</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_clear_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Remove all objects from patch</property> + <property name="label" translatable="yes">Clear</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_clear_menuitem_activate" last_modification_time="Wed, 22 Feb 2006 21:29:43 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1619"> + <property name="visible">True</property> + <property name="stock">gtk-clear</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_destroy_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Destoy this patch (remove it from the engine)</property> + <property name="label" translatable="yes">_Destroy</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_destroy_menuitem_activate" last_modification_time="Wed, 25 May 2005 00:22:00 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1620"> + <property name="visible">True</property> + <property name="stock">gtk-delete</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="add_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Insert</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_add_menu_activate" last_modification_time="Sun, 26 Dec 2004 04:33:10 GMT"/> + + <child> + <widget class="GtkMenu" id="add_menu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="patch_add_plugin_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Insert a plugin into this patch</property> + <property name="label" translatable="yes">_Plugin...</property> + <property name="use_underline">True</property> + <accelerator key="P" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1621"> + <property name="visible">True</property> + <property name="stock">gtk-execute</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_add_new_subpatch_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Insert a new, empty subpatch into this patchch</property> + <property name="label" translatable="yes">_New Patch...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_add_new_subpatch_menuitem_activate" last_modification_time="Sun, 26 Dec 2004 04:33:10 GMT"/> + <accelerator key="N" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1622"> + <property name="visible">True</property> + <property name="stock">gtk-new</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_add_subpatch_from_file_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Load a subpatch from a file and insert it into this patch</property> + <property name="label" translatable="yes">_Load Patch...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_subpatch_from_file1_activate" last_modification_time="Sun, 27 Feb 2005 00:37:03 GMT"/> + <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1623"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator7"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="right_click_on_canvas_to_place_a_new_object1"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Using this menu will place items randomly - right click!</property> + <property name="label" translatable="yes">Right click on canvas to manually place an object</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_right_click_on_canvas_to_place_a_new_object1_activate" last_modification_time="Sun, 29 Jan 2006 21:22:13 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1624"> + <property name="visible">True</property> + <property name="stock">gtk-info</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="view1"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Windows</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_view1_activate" last_modification_time="Sun, 29 Jan 2006 21:29:58 GMT"/> + + <child> + <widget class="GtkMenu" id="view1_menu"> + + <child> + <widget class="GtkImageMenuItem" id="patch_view_patch_tree_window_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">View all patches in the engine as a heirarchial list</property> + <property name="label" translatable="yes">_Patch Tree</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_view_tree_window_menuitem_activate" last_modification_time="Sun, 29 Jan 2006 21:29:58 GMT"/> + <accelerator key="T" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1625"> + <property name="visible">True</property> + <property name="stock">gtk-index</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_view_messages_window_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">View error messages from the engine</property> + <property name="label" translatable="yes">_Messages</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_view_messages_window_menuitem_activate" last_modification_time="Sun, 29 Jan 2006 21:29:58 GMT"/> + <accelerator key="M" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1626"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-error</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="help_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Help</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_help_menu_activate" last_modification_time="Sun, 29 Jan 2006 02:34:41 GMT"/> + + <child> + <widget class="GtkMenu" id="help_menu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="patch_help_about_menuitem"> + <property name="visible">True</property> + <property name="label">gtk-about</property> + <property name="use_stock">True</property> + <signal name="activate" handler="on_about1_activate" last_modification_time="Sun, 29 Jan 2006 02:35:55 GMT"/> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="patch_win_breadcrumb_box"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="patch_win_scrolledwin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkViewport" id="patch_win_viewport"> + <property name="visible">True</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + + <child> + <placeholder/> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="load_plugin_win"> + <property name="border_width">8</property> + <property name="title" translatable="yes">Load Plugin</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="default_width">640</property> + <property name="default_height">480</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox5"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">10</property> + + <child> + <widget class="GtkHBox" id="hbox7"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">10</property> + + <child> + <widget class="GtkVBox" id="vbox7"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkVBox" id="vbox9"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">1</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow3"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="load_plugin_plugins_treeview"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">All plugins available for loading</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">True</property> + <property name="reorderable">True</property> + <property name="enable_search">True</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table16"> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">12</property> + <property name="column_spacing">0</property> + + <child> + <widget class="GtkButton" id="load_plugin_clear_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Clear filter text (show all plugins)</property> + <property name="can_focus">True</property> + <property name="label">gtk-clear</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label66"> + <property name="visible">True</property> + <property name="label" translatable="yes">Module Name:</property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">1</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="load_plugin_close_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Close dialog</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkHSeparator" id="hseparator1"> + <property name="visible">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkHSeparator" id="hseparator2"> + <property name="visible">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkHSeparator" id="hseparator3"> + <property name="visible">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox63"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkEntry" id="load_plugin_name_entry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Name of new Module</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="load_plugin_polyphonic_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Polyphonic</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">8</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="load_plugin_add_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Add selected plugin to patch</property> + <property name="can_focus">True</property> + <property name="label">gtk-add</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_padding">6</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="load_plugin_search_entry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Search string to filter plugin list</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_padding">6</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="load_plugin_filter_combo"> + <property name="visible">True</property> + <property name="items" translatable="yes">Name contains: </property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="new_subpatch_win"> + <property name="border_width">8</property> + <property name="width_request">320</property> + <property name="title" translatable="yes">Create Subpatch</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">0</property> + <property name="column_spacing">0</property> + + <child> + <widget class="GtkLabel" id="label8"> + <property name="visible">True</property> + <property name="label" translatable="yes">Name: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_padding">5</property> + <property name="x_options">fill</property> + <property name="y_options">expand</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label9"> + <property name="visible">True</property> + <property name="label" translatable="yes">Polyphony: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_padding">5</property> + <property name="x_options">fill</property> + <property name="y_options">expand</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="new_subpatch_polyphony_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 100 1 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_padding">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="new_subpatch_name_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="has_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_padding">4</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="new_subpatch_message_label"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox5"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkButton" id="new_subpatch_cancel_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="new_subpatch_ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment2"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox54"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image259"> + <property name="visible">True</property> + <property name="stock">gtk-ok</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label96"> + <property name="visible">True</property> + <property name="label">Create</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkFileChooserDialog" id="load_subpatch_win"> + <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property> + <property name="local_only">True</property> + <property name="select_multiple">False</property> + <property name="show_hidden">False</property> + <property name="do_overwrite_confirmation">False</property> + <property name="title" translatable="yes">Load Subpatch</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">10</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="load_subpatch_cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="load_subpatch_ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-open</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table6"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">4</property> + <property name="homogeneous">False</property> + <property name="row_spacing">4</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkLabel" id="label79"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Name: </b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label80"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Polyphony: </b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="load_subpatch_name_from_file_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Use the name stored in the patch file</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Load from file</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="load_subpatch_poly_from_file_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Use the polyphony value stored in the patch file</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Load from file</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox46"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="load_subpatch_poly_from_user_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Specify a custom polyphony value for new patch</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Specify: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">load_subpatch_poly_from_file_radio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="load_subpatch_poly_spinbutton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Specify a custom polyphony value for new patch</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 1000 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="load_subpatch_poly_from_parent_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Set polyphony to the same value as the parent (containing) patch</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Same as parent (?)</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">load_subpatch_poly_from_file_radio</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label104"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox45"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="load_subpatch_name_from_user_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Specify the name for the new patch</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Specify: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">load_subpatch_name_from_file_radio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="load_subpatch_name_entry"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Specify the name for the new patch</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkFileChooserDialog" id="load_patch_win"> + <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property> + <property name="local_only">True</property> + <property name="select_multiple">False</property> + <property name="show_hidden">False</property> + <property name="do_overwrite_confirmation">False</property> + <property name="title" translatable="yes">Load Patch</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="vbox11"> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="load_patch_cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="load_patch_ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-open</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table14"> + <property name="visible">True</property> + <property name="n_rows">1</property> + <property name="n_columns">4</property> + <property name="homogeneous">False</property> + <property name="row_spacing">4</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkLabel" id="label123"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Polyphony: </b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="load_patch_poly_from_current_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Use the same polyphony as the current patch</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Keep current</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="load_patch_poly_from_file_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Use the polyphony value stored in the patch file</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Load from file</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">load_patch_poly_from_current_radio</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox58"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="load_patch_poly_from_user_radio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Specify:</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">load_patch_poly_from_current_radio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="load_patch_poly_spinbutton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Specify a custom polyphony value for new patch</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 100 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="warehouse_win"> + <property name="title" translatable="yes">window1</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkTable" id="table8"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">0</property> + <property name="column_spacing">0</property> + + <child> + <widget class="GtkVBox" id="control_panel_vbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwin1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkViewport" id="viewport1"> + <property name="visible">True</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + + <child> + <widget class="GtkVBox" id="control_panel_controls_box"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <placeholder/> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="control_panel_voice_controls_box"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="control_panel_all_voices_radio"> + <property name="tooltip" translatable="yes">Apply changed controls to all voices</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">All Voices</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox32"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkRadioButton" id="control_panel_specific_voice_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Apply changed controls to one voice only</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Specific Voice:</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">control_panel_all_voices_radio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="control_panel_voice_spinbutton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Voice control changes are applied to</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 1 100 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="patch_view_vbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkScrolledWindow" id="patch_canvas_scrolledwindow"> + <property name="border_width">1</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkCheckButton" id="patch_process_checkbutton"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Enable audio processing for this patch</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Run</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkSeparatorToolItem" id="separatortoolitem2"> + <property name="visible">True</property> + <property name="draw">True</property> + <property name="visible_horizontal">False</property> + <property name="visible_vertical">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox26"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label33"> + <property name="visible">True</property> + <property name="label" translatable="yes">Polyphony: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="patch_polyphony_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">?</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">10</property> + <property name="expand">True</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSeparatorToolItem" id="separatortoolitem3"> + <property name="visible">True</property> + <property name="draw">True</property> + <property name="visible_horizontal">False</property> + <property name="visible_vertical">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label77"> + <property name="visible">True</property> + <property name="label" translatable="yes">Zoom: </property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.469999998808</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">2</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHScale" id="patch_zoom_scale"> + <property name="width_request">90</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="draw_value">False</property> + <property name="value_pos">GTK_POS_RIGHT</property> + <property name="digits">1</property> + <property name="update_policy">GTK_UPDATE_CONTINUOUS</property> + <property name="inverted">False</property> + <property name="adjustment">1.10638296604 0.25 2 0.25 0 0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="messages_win"> + <property name="border_width">8</property> + <property name="width_request">400</property> + <property name="height_request">180</property> + <property name="title" translatable="yes">Error Messages</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox12"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="messages_textview"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Error messages from the engine since the last time "Clear" was pressed</property> + <property name="can_focus">True</property> + <property name="editable">False</property> + <property name="overwrite">False</property> + <property name="accepts_tab">False</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_WORD</property> + <property name="cursor_visible">False</property> + <property name="pixels_above_lines">5</property> + <property name="pixels_below_lines">5</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">5</property> + <property name="right_margin">5</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox8"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkButton" id="messages_clear_button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-clear</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="messages_close_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="config_win"> + <property name="border_width">8</property> + <property name="title" translatable="yes">Configuration</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox13"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkTable" id="table9"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">0</property> + <property name="column_spacing">0</property> + + <child> + <widget class="GtkLabel" id="label90"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Patch Search Path: </b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="config_path_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label91"> + <property name="visible">True</property> + <property name="label" translatable="yes"><i>Example: /foo/bar:/home/john/patches:/usr/share/om/patches</i></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label103"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox2"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkButton" id="config_save_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Save these settings for future sessions</property> + <property name="can_focus">True</property> + <property name="label">gtk-save</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="config_cancel_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="config_ok_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Apply these settings to this session only</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="patch_description_win"> + <property name="border_width">8</property> + <property name="width_request">400</property> + <property name="height_request">200</property> + <property name="title" translatable="yes">Patch Description</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox14"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkHBox" id="hbox51"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkLabel" id="label93"> + <property name="visible">True</property> + <property name="label" translatable="yes">Author:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="description_author_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow9"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="description_description_textview"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">A short description of the patch to be included in the patch file</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="overwrite">False</property> + <property name="accepts_tab">True</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_WORD</property> + <property name="cursor_visible">True</property> + <property name="pixels_above_lines">0</property> + <property name="pixels_below_lines">0</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">0</property> + <property name="right_margin">0</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox3"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkButton" id="description_cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="description_ok_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Apply these changes to be saved the next time the patch is saved</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="rename_win"> + <property name="width_request">250</property> + <property name="title" translatable="yes">Rename</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox15"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="hbox53"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label95"> + <property name="visible">True</property> + <property name="label" translatable="yes">New name: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="rename_name_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="rename_message_label"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">6</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox4"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkButton" id="rename_cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="rename_ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox52"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image258"> + <property name="visible">True</property> + <property name="stock">gtk-ok</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label94"> + <property name="visible">True</property> + <property name="label" translatable="yes">Rename</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="node_properties_win"> + <property name="border_width">6</property> + <property name="title" translatable="yes">window1</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox17"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label105"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Node</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox18"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkHBox" id="hbox56"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkLabel" id="label121"> + <property name="visible">True</property> + <property name="label" translatable="yes">Path: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="node_properties_path_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">-</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="node_properties_polyphonic_checkbutton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Polyphonic</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">6</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label106"> + <property name="width_request">240</property> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Plugin</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table13"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">10</property> + + <child> + <widget class="GtkLabel" id="node_properties_plugin_type_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">-</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label114"> + <property name="visible">True</property> + <property name="label" translatable="yes">Type: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label120"> + <property name="visible">True</property> + <property name="label" translatable="yes">URI: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="node_properties_plugin_uri_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">-</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label116"> + <property name="visible">True</property> + <property name="label" translatable="yes">Name: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="node_properties_plugin_name_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">-</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkAboutDialog" id="about_win"> + <property name="destroy_with_parent">True</property> + <property name="name" translatable="yes">OmGtk</property> + <property name="copyright" translatable="yes">Copyright (C) 2005-2006 Dave Robillard</property> + <property name="comments" translatable="yes">A client for the Om modular synthesizer</property> + <property name="license" translatable="yes">Licensed under the GNU GPL, Version 2. + +See COPYING file included with Om, or http://www.gnu.org/licenses/gpl.txt for more information</property> + <property name="wrap_license">False</property> + <property name="website">http://om-synth.nongnu.org</property> + <property name="website_label" translatable="yes"></property> + <property name="authors">Author: + Dave Robillard <drobilla@connect.carelton.ca> + +Contributors: + Lars Luthman - DSSI enhancements, bugfixes + Mario Lang - SuperCollider bindings, bugfixes + Leonard Ritter - Python bindings +</property> + <property name="artists">Usability / UI Design: + Thorsten Wilms</property> + <property name="translator_credits" translatable="yes" comments="TRANSLATORS: Replace this string with your names, one name per line.">translator-credits</property> + <property name="logo">om-icon.png</property> +</widget> + +<widget class="GtkWindow" id="patch_tree_win"> + <property name="border_width">8</property> + <property name="width_request">320</property> + <property name="height_request">340</property> + <property name="title" translatable="yes">Patches</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow8"> + <property name="border_width">3</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="patches_treeview"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">All patches loaded in the engine</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">True</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="connect_win"> + <property name="border_width">6</property> + <property name="title" translatable="yes">Connecting to Engine</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <property name="has_separator">True</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox3"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area3"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property> + + <child> + <widget class="GtkButton" id="connect_launch_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">0</property> + + <child> + <widget class="GtkAlignment" id="alignment4"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox62"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image946"> + <property name="visible">True</property> + <property name="stock">gtk-execute</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label126"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Launch Engine</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkButton" id="connect_cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-6</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox19"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="hbox61"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkImage" id="image846"> + <property name="visible">True</property> + <property name="pixbuf">om-icon.png</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">6</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox20"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label125"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkProgressBar" id="connect_progress_bar"> + <property name="visible">True</property> + <property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property> + <property name="fraction">0</property> + <property name="pulse_step">0.10000000149</property> + <property name="text" translatable="yes"></property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label124"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="connect_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Connecting to engine</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">4</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/src/progs/gtk/om_gtk.glade.bak b/src/progs/gtk/om_gtk.glade.bak new file mode 100644 index 00000000..7714d1f3 --- /dev/null +++ b/src/progs/gtk/om_gtk.glade.bak @@ -0,0 +1,3555 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> + +<widget class="GtkWindow" id="patch_win"> + <property name="border_width">1</property> + <property name="title" translatable="yes">Om</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="default_width">640</property> + <property name="default_height">480</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="patch_win_vbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkMenuBar" id="menubar"> + <property name="visible">True</property> + <property name="pack_direction">GTK_PACK_DIRECTION_LTR</property> + <property name="child_pack_direction">GTK_PACK_DIRECTION_LTR</property> + + <child> + <widget class="GtkMenuItem" id="patch_file_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_File</property> + <property name="use_underline">True</property> + + <child> + <widget class="GtkMenu" id="patch_file_menu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="patch_open_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Open (Replace)...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_open_(replace)1_activate" last_modification_time="Mon, 06 Feb 2006 06:20:27 GMT"/> + <accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1609"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_open_into_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">Open _Into (Import)...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_open_into_(merge)1_activate" last_modification_time="Mon, 06 Feb 2006 06:20:27 GMT"/> + <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1610"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator9"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_save_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Save this patch</property> + <property name="label" translatable="yes">_Save</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_file_save_patch_menuitem_activate" last_modification_time="Thu, 20 Jan 2005 08:35:00 GMT"/> + <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1611"> + <property name="visible">True</property> + <property name="stock">gtk-save</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_save_as_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Save this patch to a specific filename</property> + <property name="label" translatable="yes">Save _As...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_file_save_patch_menuitem_activate" last_modification_time="Sat, 23 Oct 2004 02:16:12 GMT"/> + <accelerator key="S" modifiers="GDK_CONTROL_MASK | GDK_SHIFT_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1612"> + <property name="visible">True</property> + <property name="stock">gtk-save-as</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator10"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_configuration_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Configure OmGtk</property> + <property name="label" translatable="yes">Confi_guration</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_configuration_menuitem_activate" last_modification_time="Sun, 29 Jan 2006 21:17:26 GMT"/> + <accelerator key="G" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1613"> + <property name="visible">True</property> + <property name="stock">gtk-preferences</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator11"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_close_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Close this window (patch will not be destroyed)</property> + <property name="label" translatable="yes">Close _Window</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_file_close_menuitem_activate" last_modification_time="Sat, 11 Sep 2004 20:05:11 GMT"/> + <accelerator key="W" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1614"> + <property name="visible">True</property> + <property name="stock">gtk-close</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator6"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_quit_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Quit OmGtk (Om engine will continue running)</property> + <property name="label" translatable="yes">_Quit</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_file_quit_nokill_menuitem_activate" last_modification_time="Sun, 29 Jan 2006 21:18:07 GMT"/> + <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1615"> + <property name="visible">True</property> + <property name="stock">gtk-quit</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_quit_and_kill_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Quit OmGtk and kill the Om engine</property> + <property name="label" translatable="yes">Quit and _Kill Engine</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_file_quit_and_kill_menuitem_activate" last_modification_time="Sun, 29 Jan 2006 21:18:19 GMT"/> + <accelerator key="Q" modifiers="GDK_CONTROL_MASK | GDK_SHIFT_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1616"> + <property name="visible">True</property> + <property name="stock">gtk-stop</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="patch_patch_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Patch</property> + <property name="use_underline">True</property> + + <child> + <widget class="GtkMenu" id="patch_patch_menu_menu"> + + <child> + <widget class="GtkCheckMenuItem" id="patch_fullscreen_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">Fullscreen</property> + <property name="use_underline">True</property> + <property name="active">False</property> + <signal name="activate" handler="patch_fullscreen_menuitem" last_modification_time="Sat, 11 Mar 2006 05:24:13 GMT"/> + <accelerator key="F11" modifiers="0" signal="activate"/> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator12"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_view_control_window_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">View/Edit controls for this patch</property> + <property name="label" translatable="yes">_Controls</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_view_control_window_menuitem_activate" last_modification_time="Wed, 20 Apr 2005 16:05:32 GMT"/> + <accelerator key="C" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1617"> + <property name="visible">True</property> + <property name="stock">gtk-preferences</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_description_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">View/Edit description for this patch</property> + <property name="label" translatable="yes">Descr_iption</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_description_menuitem_activate" last_modification_time="Mon, 08 Aug 2005 07:18:52 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1618"> + <property name="visible">True</property> + <property name="stock">gtk-edit</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_clear_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Remove all objects from patch</property> + <property name="label" translatable="yes">Clear</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_clear_menuitem_activate" last_modification_time="Wed, 22 Feb 2006 21:29:43 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1619"> + <property name="visible">True</property> + <property name="stock">gtk-clear</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_destroy_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Destoy this patch (remove it from the engine)</property> + <property name="label" translatable="yes">_Destroy</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_destroy_menuitem_activate" last_modification_time="Wed, 25 May 2005 00:22:00 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1620"> + <property name="visible">True</property> + <property name="stock">gtk-delete</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="add_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Insert</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_add_menu_activate" last_modification_time="Sun, 26 Dec 2004 04:33:10 GMT"/> + + <child> + <widget class="GtkMenu" id="add_menu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="patch_add_plugin_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Insert a plugin into this patch</property> + <property name="label" translatable="yes">_Plugin...</property> + <property name="use_underline">True</property> + <accelerator key="P" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1621"> + <property name="visible">True</property> + <property name="stock">gtk-execute</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_add_new_subpatch_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Insert a new, empty subpatch into this patchch</property> + <property name="label" translatable="yes">_New Patch...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_add_new_subpatch_menuitem_activate" last_modification_time="Sun, 26 Dec 2004 04:33:10 GMT"/> + <accelerator key="N" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1622"> + <property name="visible">True</property> + <property name="stock">gtk-new</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_add_subpatch_from_file_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Load a subpatch from a file and insert it into this patch</property> + <property name="label" translatable="yes">_Load Patch...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_subpatch_from_file1_activate" last_modification_time="Sun, 27 Feb 2005 00:37:03 GMT"/> + <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1623"> + <property name="visible">True</property> + <property name="stock">gtk-open</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator7"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="right_click_on_canvas_to_place_a_new_object1"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Using this menu will place items randomly - right click!</property> + <property name="label" translatable="yes">Right click on canvas to manually place an object</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_right_click_on_canvas_to_place_a_new_object1_activate" last_modification_time="Sun, 29 Jan 2006 21:22:13 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1624"> + <property name="visible">True</property> + <property name="stock">gtk-info</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="view1"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Windows</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_view1_activate" last_modification_time="Sun, 29 Jan 2006 21:29:58 GMT"/> + + <child> + <widget class="GtkMenu" id="view1_menu"> + + <child> + <widget class="GtkImageMenuItem" id="patch_view_patch_tree_window_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">View all patches in the engine as a heirarchial list</property> + <property name="label" translatable="yes">_Patch Tree</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_view_tree_window_menuitem_activate" last_modification_time="Sun, 29 Jan 2006 21:29:58 GMT"/> + <accelerator key="T" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1625"> + <property name="visible">True</property> + <property name="stock">gtk-index</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="patch_view_messages_window_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">View error messages from the engine</property> + <property name="label" translatable="yes">_Messages</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_patch_view_messages_window_menuitem_activate" last_modification_time="Sun, 29 Jan 2006 21:29:58 GMT"/> + <accelerator key="M" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1626"> + <property name="visible">True</property> + <property name="stock">gtk-dialog-error</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="help_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Help</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_help_menu_activate" last_modification_time="Sun, 29 Jan 2006 02:34:41 GMT"/> + + <child> + <widget class="GtkMenu" id="help_menu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="patch_help_about_menuitem"> + <property name="visible">True</property> + <property name="label">gtk-about</property> + <property name="use_stock">True</property> + <signal name="activate" handler="on_about1_activate" last_modification_time="Sun, 29 Jan 2006 02:35:55 GMT"/> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="patch_win_breadcrumb_box"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="patch_win_scrolledwin"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkViewport" id="patch_win_viewport"> + <property name="visible">True</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + + <child> + <placeholder/> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="load_plugin_win"> + <property name="border_width">8</property> + <property name="title" translatable="yes">Load Plugin</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="default_width">640</property> + <property name="default_height">480</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox5"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">10</property> + + <child> + <widget class="GtkHBox" id="hbox7"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">10</property> + + <child> + <widget class="GtkVBox" id="vbox7"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkVBox" id="vbox9"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">1</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow3"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="load_plugin_plugins_treeview"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">All plugins available for loading</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">True</property> + <property name="reorderable">True</property> + <property name="enable_search">True</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table16"> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">3</property> + <property name="homogeneous">False</property> + <property name="row_spacing">12</property> + <property name="column_spacing">0</property> + + <child> + <widget class="GtkButton" id="load_plugin_clear_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Clear filter text (show all plugins)</property> + <property name="can_focus">True</property> + <property name="label">gtk-clear</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label66"> + <property name="visible">True</property> + <property name="label" translatable="yes">Module Name:</property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">1</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="load_plugin_close_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Close dialog</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkHSeparator" id="hseparator1"> + <property name="visible">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkHSeparator" id="hseparator2"> + <property name="visible">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkHSeparator" id="hseparator3"> + <property name="visible">True</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox63"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkEntry" id="load_plugin_name_entry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Name of new Module</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="load_plugin_polyphonic_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Polyphonic</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">8</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="load_plugin_add_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Add selected plugin to patch</property> + <property name="can_focus">True</property> + <property name="label">gtk-add</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_padding">6</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="load_plugin_search_entry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Search string to filter plugin list</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_padding">6</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="load_plugin_filter_combo"> + <property name="visible">True</property> + <property name="items" translatable="yes">Name contains: </property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="new_subpatch_win"> + <property name="border_width">8</property> + <property name="width_request">320</property> + <property name="title" translatable="yes">Create Subpatch</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">0</property> + <property name="column_spacing">0</property> + + <child> + <widget class="GtkLabel" id="label8"> + <property name="visible">True</property> + <property name="label" translatable="yes">Name: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_padding">5</property> + <property name="x_options">fill</property> + <property name="y_options">expand</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label9"> + <property name="visible">True</property> + <property name="label" translatable="yes">Polyphony: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_padding">5</property> + <property name="x_options">fill</property> + <property name="y_options">expand</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="new_subpatch_polyphony_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 100 1 10 10</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_padding">4</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="new_subpatch_name_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="has_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_padding">4</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="new_subpatch_message_label"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox5"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkButton" id="new_subpatch_cancel_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="new_subpatch_ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment2"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox54"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image259"> + <property name="visible">True</property> + <property name="stock">gtk-ok</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label96"> + <property name="visible">True</property> + <property name="label">Create</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkFileChooserDialog" id="load_subpatch_win"> + <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property> + <property name="local_only">True</property> + <property name="select_multiple">False</property> + <property name="show_hidden">False</property> + <property name="do_overwrite_confirmation">False</property> + <property name="title" translatable="yes">Load Subpatch</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">24</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="load_subpatch_cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="load_subpatch_ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-open</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table6"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">4</property> + <property name="homogeneous">False</property> + <property name="row_spacing">4</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkLabel" id="label79"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Name: </b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label80"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Polyphony: </b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="load_subpatch_name_from_file_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Use the name stored in the patch file</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Load from file</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="load_subpatch_poly_from_file_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Use the polyphony value stored in the patch file</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Load from file</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox46"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="load_subpatch_poly_from_user_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Specify a custom polyphony value for new patch</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Specify: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">load_subpatch_poly_from_file_radio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="load_subpatch_poly_spinbutton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Specify a custom polyphony value for new patch</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 1000 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="load_subpatch_poly_from_parent_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Set polyphony to the same value as the parent (containing) patch</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Same as parent (?)</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">load_subpatch_poly_from_file_radio</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label104"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox45"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="load_subpatch_name_from_user_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Specify the name for the new patch</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Specify: </property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">load_subpatch_name_from_file_radio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="load_subpatch_name_entry"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Specify the name for the new patch</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkFileChooserDialog" id="load_patch_win"> + <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property> + <property name="local_only">True</property> + <property name="select_multiple">False</property> + <property name="show_hidden">False</property> + <property name="do_overwrite_confirmation">False</property> + <property name="title" translatable="yes">Load Patch</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="vbox11"> + <property name="homogeneous">False</property> + <property name="spacing">24</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="load_patch_cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-6</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="load_patch_ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-open</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-5</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table14"> + <property name="visible">True</property> + <property name="n_rows">1</property> + <property name="n_columns">4</property> + <property name="homogeneous">False</property> + <property name="row_spacing">4</property> + <property name="column_spacing">12</property> + + <child> + <widget class="GtkLabel" id="label123"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Polyphony: </b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="load_patch_poly_from_current_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Use the same polyphony as the current patch</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Keep current</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">True</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="load_patch_poly_from_file_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Use the polyphony value stored in the patch file</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Load from file</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">load_patch_poly_from_current_radio</property> + </widget> + <packing> + <property name="left_attach">2</property> + <property name="right_attach">3</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox58"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="load_patch_poly_from_user_radio"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Specify:</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">load_patch_poly_from_current_radio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="load_patch_poly_spinbutton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Specify a custom polyphony value for new patch</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 100 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="warehouse_win"> + <property name="title" translatable="yes">window1</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkTable" id="table8"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">0</property> + <property name="column_spacing">0</property> + + <child> + <widget class="GtkVBox" id="control_panel_vbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwin1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkViewport" id="viewport1"> + <property name="visible">True</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + + <child> + <widget class="GtkVBox" id="control_panel_controls_box"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <placeholder/> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="control_panel_voice_controls_box"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="control_panel_all_voices_radio"> + <property name="tooltip" translatable="yes">Apply changed controls to all voices</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">All Voices</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox32"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkRadioButton" id="control_panel_specific_voice_radio"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Apply changed controls to one voice only</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Specific Voice:</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">control_panel_all_voices_radio</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="control_panel_voice_spinbutton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="tooltip" translatable="yes">Voice control changes are applied to</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">True</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 1 100 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="patch_view_vbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkScrolledWindow" id="patch_canvas_scrolledwindow"> + <property name="border_width">1</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkCheckButton" id="patch_process_checkbutton"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Enable audio processing for this patch</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Run</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkSeparatorToolItem" id="separatortoolitem2"> + <property name="visible">True</property> + <property name="draw">True</property> + <property name="visible_horizontal">False</property> + <property name="visible_vertical">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox26"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label33"> + <property name="visible">True</property> + <property name="label" translatable="yes">Polyphony: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="patch_polyphony_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">?</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">10</property> + <property name="expand">True</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSeparatorToolItem" id="separatortoolitem3"> + <property name="visible">True</property> + <property name="draw">True</property> + <property name="visible_horizontal">False</property> + <property name="visible_vertical">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label77"> + <property name="visible">True</property> + <property name="label" translatable="yes">Zoom: </property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.469999998808</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">2</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHScale" id="patch_zoom_scale"> + <property name="width_request">90</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="draw_value">False</property> + <property name="value_pos">GTK_POS_RIGHT</property> + <property name="digits">1</property> + <property name="update_policy">GTK_UPDATE_CONTINUOUS</property> + <property name="inverted">False</property> + <property name="adjustment">1.10638296604 0.25 2 0.25 0 0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="messages_win"> + <property name="border_width">8</property> + <property name="width_request">400</property> + <property name="height_request">180</property> + <property name="title" translatable="yes">Error Messages</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox12"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="messages_textview"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Error messages from the engine since the last time "Clear" was pressed</property> + <property name="can_focus">True</property> + <property name="editable">False</property> + <property name="overwrite">False</property> + <property name="accepts_tab">False</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_WORD</property> + <property name="cursor_visible">False</property> + <property name="pixels_above_lines">5</property> + <property name="pixels_below_lines">5</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">5</property> + <property name="right_margin">5</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox8"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkButton" id="messages_clear_button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-clear</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="messages_close_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-close</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="config_win"> + <property name="border_width">8</property> + <property name="title" translatable="yes">Configuration</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox13"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkTable" id="table9"> + <property name="visible">True</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">0</property> + <property name="column_spacing">0</property> + + <child> + <widget class="GtkLabel" id="label90"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Patch Search Path: </b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="config_path_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label91"> + <property name="visible">True</property> + <property name="label" translatable="yes"><i>Example: /foo/bar:/home/john/patches:/usr/share/om/patches</i></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label103"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox2"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkButton" id="config_save_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Save these settings for future sessions</property> + <property name="can_focus">True</property> + <property name="label">gtk-save</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="config_cancel_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="config_ok_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Apply these settings to this session only</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="patch_description_win"> + <property name="border_width">8</property> + <property name="width_request">400</property> + <property name="height_request">200</property> + <property name="title" translatable="yes">Patch Description</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox14"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkHBox" id="hbox51"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkLabel" id="label93"> + <property name="visible">True</property> + <property name="label" translatable="yes">Author:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="description_author_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow9"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="description_description_textview"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">A short description of the patch to be included in the patch file</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="overwrite">False</property> + <property name="accepts_tab">True</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_WORD</property> + <property name="cursor_visible">True</property> + <property name="pixels_above_lines">0</property> + <property name="pixels_below_lines">0</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">0</property> + <property name="right_margin">0</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox3"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkButton" id="description_cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="description_ok_button"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Apply these changes to be saved the next time the patch is saved</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="rename_win"> + <property name="width_request">250</property> + <property name="title" translatable="yes">Rename</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox15"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="hbox53"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label95"> + <property name="visible">True</property> + <property name="label" translatable="yes">New name: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="rename_name_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">*</property> + <property name="activates_default">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="rename_message_label"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">6</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHButtonBox" id="hbuttonbox4"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">5</property> + + <child> + <widget class="GtkButton" id="rename_cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + </widget> + </child> + + <child> + <widget class="GtkButton" id="rename_ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox52"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image258"> + <property name="visible">True</property> + <property name="stock">gtk-ok</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label94"> + <property name="visible">True</property> + <property name="label" translatable="yes">Rename</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkWindow" id="node_properties_win"> + <property name="border_width">6</property> + <property name="title" translatable="yes">window1</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkVBox" id="vbox17"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label105"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Node</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox18"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child> + <widget class="GtkHBox" id="hbox56"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">4</property> + + <child> + <widget class="GtkLabel" id="label121"> + <property name="visible">True</property> + <property name="label" translatable="yes">Path: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="node_properties_path_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">-</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="node_properties_polyphonic_checkbutton"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Polyphonic</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">6</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label106"> + <property name="width_request">240</property> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Plugin</b></property> + <property name="use_underline">False</property> + <property name="use_markup">True</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table13"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">6</property> + <property name="column_spacing">10</property> + + <child> + <widget class="GtkLabel" id="node_properties_plugin_type_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">-</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label114"> + <property name="visible">True</property> + <property name="label" translatable="yes">Type: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label120"> + <property name="visible">True</property> + <property name="label" translatable="yes">URI: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="node_properties_plugin_uri_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">-</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label116"> + <property name="visible">True</property> + <property name="label" translatable="yes">Name: </property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="node_properties_plugin_name_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">-</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkAboutDialog" id="about_win"> + <property name="destroy_with_parent">True</property> + <property name="name" translatable="yes">OmGtk</property> + <property name="copyright" translatable="yes">Copyright (C) 2005-2006 Dave Robillard</property> + <property name="comments" translatable="yes">A client for the Om modular synthesizer</property> + <property name="license" translatable="yes">Licensed under the GNU GPL, Version 2. + +See COPYING file included with Om, or http://www.gnu.org/licenses/gpl.txt for more information</property> + <property name="wrap_license">False</property> + <property name="website">http://om-synth.nongnu.org</property> + <property name="website_label" translatable="yes"></property> + <property name="authors">Author: + Dave Robillard <drobilla@connect.carelton.ca> + +Contributors: + Lars Luthman - DSSI enhancements, bugfixes + Mario Lang - SuperCollider bindings, bugfixes + Leonard Ritter - Python bindings +</property> + <property name="artists">Usability / UI Design: + Thorsten Wilms</property> + <property name="translator_credits" translatable="yes" comments="TRANSLATORS: Replace this string with your names, one name per line.">translator-credits</property> + <property name="logo">om-icon.png</property> +</widget> + +<widget class="GtkWindow" id="patch_tree_win"> + <property name="border_width">8</property> + <property name="width_request">320</property> + <property name="height_request">340</property> + <property name="title" translatable="yes">Patches</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow8"> + <property name="border_width">3</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="patches_treeview"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">All patches loaded in the engine</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">True</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="connect_win"> + <property name="border_width">6</property> + <property name="title" translatable="yes">Connecting to Engine</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_CENTER</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="icon">om-icon.png</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <property name="has_separator">True</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox3"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">6</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area3"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property> + + <child> + <widget class="GtkButton" id="connect_launch_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">0</property> + + <child> + <widget class="GtkAlignment" id="alignment4"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox62"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image946"> + <property name="visible">True</property> + <property name="stock">gtk-execute</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label126"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Launch Engine</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkButton" id="connect_cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-6</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox19"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="hbox61"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkImage" id="image846"> + <property name="visible">True</property> + <property name="pixbuf">om-icon.png</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">6</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox20"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="label125"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkProgressBar" id="connect_progress_bar"> + <property name="visible">True</property> + <property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property> + <property name="fraction">0</property> + <property name="pulse_step">0.10000000149</property> + <property name="text" translatable="yes"></property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label124"> + <property name="visible">True</property> + <property name="label" translatable="yes"></property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="connect_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Connecting to engine</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">4</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/src/progs/gtk/om_gtk.gladep b/src/progs/gtk/om_gtk.gladep new file mode 100644 index 00000000..a8bd18bd --- /dev/null +++ b/src/progs/gtk/om_gtk.gladep @@ -0,0 +1,9 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd"> + +<glade-project> + <name>OmGtk</name> + <program_name>om_gtk</program_name> + <language>C++</language> + <gnome_support>FALSE</gnome_support> +</glade-project> diff --git a/src/progs/gtk/om_gtk.gladep.bak b/src/progs/gtk/om_gtk.gladep.bak new file mode 100644 index 00000000..a8bd18bd --- /dev/null +++ b/src/progs/gtk/om_gtk.gladep.bak @@ -0,0 +1,9 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd"> + +<glade-project> + <name>OmGtk</name> + <program_name>om_gtk</program_name> + <language>C++</language> + <gnome_support>FALSE</gnome_support> +</glade-project> diff --git a/src/progs/gtk/singletons.cpp b/src/progs/gtk/singletons.cpp new file mode 100644 index 00000000..75b441e9 --- /dev/null +++ b/src/progs/gtk/singletons.cpp @@ -0,0 +1,29 @@ +/* This file is part of Om. Copyright (C) 2006 Dave Robillard. + * + * Om 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. + * + * Om 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., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "App.h" +#include "Store.h" +#include "Controller.h" +//#include "GtkClientInterface.h" + +namespace OmGtk +{ + App* App::_instance = 0; + Store* Store::_instance = 0; + Controller* Controller::_instance = 0; + //CountedPtr<GtkClientInterface> GtkClientInterface::_instance = 0; +} + |