From b233455b3fd00789e4f8a951f9fe205de92f94e2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 3 Jul 2009 18:37:15 +0000 Subject: Split route group list out of Editor. git-svn-id: svn://localhost/ardour2/branches/3.0@5308 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/editor.cc | 157 ++----- gtk2_ardour/editor.h | 75 +--- gtk2_ardour/editor_actions.cc | 6 +- gtk2_ardour/editor_canvas.cc | 2 +- gtk2_ardour/editor_component.cc | 48 +++ gtk2_ardour/editor_component.h | 51 +++ gtk2_ardour/editor_edit_groups.cc | 580 ------------------------- gtk2_ardour/editor_group_tabs.cc | 6 +- gtk2_ardour/editor_group_tabs.h | 2 - gtk2_ardour/editor_mixer.cc | 11 +- gtk2_ardour/editor_ops.cc | 13 +- gtk2_ardour/editor_route_groups.cc | 668 +++++++++++++++++++++++++++++ gtk2_ardour/editor_route_groups.h | 77 ++++ gtk2_ardour/editor_route_list.cc | 842 ------------------------------------- gtk2_ardour/editor_route_list.h | 102 ----- gtk2_ardour/editor_routes.cc | 842 +++++++++++++++++++++++++++++++++++++ gtk2_ardour/editor_routes.h | 101 +++++ gtk2_ardour/editor_summary.cc | 15 +- gtk2_ardour/editor_summary.h | 7 +- gtk2_ardour/group_tabs.cc | 11 +- gtk2_ardour/group_tabs.h | 9 +- gtk2_ardour/mixer_group_tabs.cc | 3 +- gtk2_ardour/mixer_ui.cc | 2 +- gtk2_ardour/wscript | 5 +- 24 files changed, 1865 insertions(+), 1770 deletions(-) create mode 100644 gtk2_ardour/editor_component.cc create mode 100644 gtk2_ardour/editor_component.h delete mode 100644 gtk2_ardour/editor_edit_groups.cc create mode 100644 gtk2_ardour/editor_route_groups.cc create mode 100644 gtk2_ardour/editor_route_groups.h delete mode 100644 gtk2_ardour/editor_route_list.cc delete mode 100644 gtk2_ardour/editor_route_list.h create mode 100644 gtk2_ardour/editor_routes.cc create mode 100644 gtk2_ardour/editor_routes.h (limited to 'gtk2_ardour') diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 0d8a589349..9e04d0c388 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -98,9 +98,10 @@ #include "editor_drag.h" #include "editor_group_tabs.h" #include "automation_time_axis.h" -#include "editor_route_list.h" +#include "editor_routes.h" #include "midi_time_axis.h" #include "mixer_strip.h" +#include "editor_route_groups.h" #include "i18n.h" @@ -314,7 +315,6 @@ Editor::Editor () _xfade_visibility = true; editor_ruler_menu = 0; no_ruler_shown_update = false; - route_group_menu = 0; region_list_menu = 0; marker_menu = 0; start_end_marker_menu = 0; @@ -338,7 +338,6 @@ Editor::Editor () clear_entered_track = false; _new_regionviews_show_envelope = false; current_timefx = 0; - in_route_group_row_change = false; playhead_cursor = 0; button_release_can_deselect = true; _dragging_playhead = false; @@ -531,117 +530,8 @@ Editor::Editor () bottom_hbox.set_border_width (2); bottom_hbox.set_spacing (3); - group_model = ListStore::create(group_columns); - route_group_display.set_model (group_model); - - route_group_display.append_column (_("Name"), group_columns.text); - - route_group_display.append_column (_("G"), group_columns.gain); - route_group_display.append_column (_("R"), group_columns.record); - route_group_display.append_column (_("M"), group_columns.mute); - route_group_display.append_column (_("S"), group_columns.solo); - route_group_display.append_column (_("Sel"), group_columns.select); - route_group_display.append_column (_("E"), group_columns.edits); - - route_group_display.append_column (_("Show"), group_columns.is_visible); - - route_group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0)); - route_group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1)); - route_group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2)); - route_group_display.get_column (3)->set_data (X_("colnum"), GUINT_TO_POINTER(3)); - route_group_display.get_column (4)->set_data (X_("colnum"), GUINT_TO_POINTER(4)); - route_group_display.get_column (5)->set_data (X_("colnum"), GUINT_TO_POINTER(5)); - route_group_display.get_column (6)->set_data (X_("colnum"), GUINT_TO_POINTER(6)); - route_group_display.get_column (7)->set_data (X_("colnum"), GUINT_TO_POINTER(7)); - - route_group_display.get_column (0)->set_expand (true); - route_group_display.get_column (1)->set_expand (false); - route_group_display.get_column (2)->set_expand (false); - route_group_display.get_column (3)->set_expand (false); - route_group_display.get_column (4)->set_expand (false); - route_group_display.get_column (5)->set_expand (false); - route_group_display.get_column (6)->set_expand (false); - route_group_display.get_column (7)->set_expand (false); - - route_group_display.set_headers_visible (true); - - /* name is directly editable */ - - CellRendererText* name_cell = dynamic_cast(route_group_display.get_column_cell_renderer (0)); - name_cell->property_editable() = true; - name_cell->signal_edited().connect (mem_fun (*this, &Editor::route_group_name_edit)); - - /* use checkbox for the active + visible columns */ - - CellRendererToggle* active_cell = dynamic_cast(route_group_display.get_column_cell_renderer (1)); - active_cell->property_activatable() = true; - active_cell->property_radio() = false; - - active_cell = dynamic_cast(route_group_display.get_column_cell_renderer (2)); - active_cell->property_activatable() = true; - active_cell->property_radio() = false; - - active_cell = dynamic_cast(route_group_display.get_column_cell_renderer (3)); - active_cell->property_activatable() = true; - active_cell->property_radio() = false; - - active_cell = dynamic_cast(route_group_display.get_column_cell_renderer (4)); - active_cell->property_activatable() = true; - active_cell->property_radio() = false; - - active_cell = dynamic_cast(route_group_display.get_column_cell_renderer (5)); - active_cell->property_activatable() = true; - active_cell->property_radio() = false; - - active_cell = dynamic_cast(route_group_display.get_column_cell_renderer (6)); - active_cell->property_activatable() = true; - active_cell->property_radio() = false; - - active_cell = dynamic_cast(route_group_display.get_column_cell_renderer (7)); - active_cell->property_activatable() = true; - active_cell->property_radio() = false; - - group_model->signal_row_changed().connect (mem_fun (*this, &Editor::route_group_row_change)); - - _route_list = new EditorRouteList (this); - - route_group_display.set_name ("EditGroupList"); - route_group_display.get_selection()->set_mode (SELECTION_SINGLE); - route_group_display.set_headers_visible (true); - route_group_display.set_reorderable (false); - route_group_display.set_rules_hint (true); - route_group_display.set_size_request (75, -1); - - route_group_display_scroller.add (route_group_display); - route_group_display_scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC); - - route_group_display.signal_button_press_event().connect (mem_fun(*this, &Editor::route_group_list_button_press_event), false); - - VBox* route_group_display_packer = manage (new VBox()); - HBox* route_group_display_button_box = manage (new HBox()); - route_group_display_button_box->set_homogeneous (true); - - Button* route_group_add_button = manage (new Button ()); - Button* route_group_remove_button = manage (new Button ()); - - Widget* w; - - w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON)); - w->show(); - route_group_add_button->add (*w); - - w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON)); - w->show(); - route_group_remove_button->add (*w); - - route_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_route_group)); - route_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_route_group)); - - route_group_display_button_box->pack_start (*route_group_add_button); - route_group_display_button_box->pack_start (*route_group_remove_button); - - route_group_display_packer->pack_start (route_group_display_scroller, true, true); - route_group_display_packer->pack_start (*route_group_display_button_box, false, false); + _route_groups = new EditorRouteGroups (this); + _routes = new EditorRoutes (this); region_list_display.set_size_request (100, -1); region_list_display.set_name ("RegionListDisplay"); @@ -748,13 +638,13 @@ Editor::Editor () the_notebook.append_page (region_list_scroller, *nlabel); nlabel = manage (new Label (_("Tracks/Busses"))); nlabel->set_angle (-90); - the_notebook.append_page (_route_list->widget (), *nlabel); + the_notebook.append_page (_routes->widget (), *nlabel); nlabel = manage (new Label (_("Snapshots"))); nlabel->set_angle (-90); the_notebook.append_page (snapshot_display_scroller, *nlabel); nlabel = manage (new Label (_("Route Groups"))); nlabel->set_angle (-90); - the_notebook.append_page (*route_group_display_packer, *nlabel); + the_notebook.append_page (_route_groups->widget (), *nlabel); if (!Profile->get_sae()) { nlabel = manage (new Label (_("Chunks"))); @@ -893,7 +783,8 @@ Editor::~Editor() } #endif - delete _route_list; + delete _routes; + delete _route_groups; delete track_canvas; delete _drag; } @@ -1278,8 +1169,6 @@ Editor::connect_to_session (Session *t) session_connections.push_back (session->RegionsAdded.connect (mem_fun(*this, &Editor::handle_new_regions))); session_connections.push_back (session->RegionRemoved.connect (mem_fun(*this, &Editor::handle_region_removed))); session_connections.push_back (session->DurationChanged.connect (mem_fun(*this, &Editor::handle_new_duration))); - session_connections.push_back (session->route_group_added.connect (mem_fun(*this, &Editor::add_route_group))); - session_connections.push_back (session->route_group_removed.connect (mem_fun(*this, &Editor::route_groups_changed))); session_connections.push_back (session->NamedSelectionAdded.connect (mem_fun(*this, &Editor::handle_new_named_selection))); session_connections.push_back (session->NamedSelectionRemoved.connect (mem_fun(*this, &Editor::handle_new_named_selection))); session_connections.push_back (session->DirtyChanged.connect (mem_fun(*this, &Editor::update_title))); @@ -1294,7 +1183,7 @@ Editor::connect_to_session (Session *t) session_connections.push_back (session->Located.connect (mem_fun (*this, &Editor::located))); session_connections.push_back (session->config.ParameterChanged.connect (mem_fun (*this, &Editor::parameter_changed))); - route_groups_changed (); + _route_groups->connect_to_session (session); edit_point_clock.set_mode(AudioClock::BBT); edit_point_clock.set_session (session); @@ -1375,7 +1264,7 @@ Editor::connect_to_session (Session *t) //tempo_map_changed (Change (0)); session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); - _route_list->initial_display (); + _routes->initial_display (); for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { (static_cast(*i))->set_samples_per_unit (frames_per_unit); @@ -1398,8 +1287,8 @@ Editor::connect_to_session (Session *t) /* register for undo history */ session->register_with_memento_command_factory(_id, this); - _summary->set_session (session); - _group_tabs->set_session (session); + _summary->connect_to_session (session); + _group_tabs->connect_to_session (session); start_updating (); } @@ -4615,7 +4504,7 @@ Editor::use_visual_state (VisualState& vs) { no_save_visual = true; - _route_list->suspend_redisplay (); + _routes->suspend_redisplay (); vertical_adjustment.set_value (vs.y_position); @@ -4635,10 +4524,10 @@ Editor::use_visual_state (VisualState& vs) if (!vs.track_states.empty()) { - _route_list->update_visibility (); + _routes->update_visibility (); } - _route_list->resume_redisplay (); + _routes->resume_redisplay (); no_save_visual = false; } @@ -5136,7 +5025,7 @@ Editor::first_idle () } // first idle adds route children (automation tracks), so we need to redisplay here - _route_list->redisplay (); + _routes->redisplay (); delete dialog; @@ -5282,7 +5171,7 @@ Editor::handle_new_route (RouteList& routes) rtv->GoingAway.connect (bind (mem_fun(*this, &Editor::remove_route), rtv)); } - _route_list->routes_added (new_views); + _routes->routes_added (new_views); if (show_editor_mixer_when_tracks_arrive) { show_editor_mixer (true); @@ -5343,13 +5232,13 @@ Editor::hide_track_in_display (TimeAxisView& tv, bool temponly) set_selected_mixer_strip (tv); } - _route_list->hide_track_in_display (tv); + _routes->hide_track_in_display (tv); } bool -Editor::sync_track_view_list_and_route_list () +Editor::sync_track_view_list_and_routes () { - track_views = TrackSelection (_route_list->views ()); + track_views = TrackSelection (_routes->views ()); _summary->set_dirty (); _group_tabs->set_dirty (); @@ -5381,3 +5270,9 @@ Editor::get_route_view_by_id (PBD::ID& id) return 0; } +void +Editor::fit_route_group (RouteGroup *g) +{ + TrackSelection ts = axis_views_from_routes (g->route_list ()); + fit_tracks (ts); +} diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 7a62353bca..2748beaf1a 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -116,7 +116,8 @@ class TimeFXDialog; class TimeSelection; class TrackSelection; class EditorGroupTabs; -class EditorRouteList; +class EditorRoutes; +class EditorRouteGroups; /* */ class ImageFrameView; @@ -399,6 +400,10 @@ class Editor : public PublicEditor void goto_visual_state (uint32_t); void save_visual_state (uint32_t); + TrackViewList const & get_track_views () { + return track_views; + } + protected: void map_transport_state (); void map_position_change (nframes64_t); @@ -1761,7 +1766,8 @@ public: ArdourCanvas::SimpleRect *zoom_rect; void reposition_zoom_rect (nframes64_t start, nframes64_t end); - EditorRouteList* _route_list; + EditorRouteGroups* _route_groups; + EditorRoutes* _routes; /* diskstream/route display management */ Glib::RefPtr rec_enabled_icon; @@ -1769,65 +1775,7 @@ public: Glib::RefPtr route_display_selection; - bool sync_track_view_list_and_route_list (); - - /* edit group management */ - - struct GroupListModelColumns : public Gtk::TreeModel::ColumnRecord { - - GroupListModelColumns () { - add (is_visible); - add (gain); - add (record); - add (mute); - add (solo); - add (select); - add (edits); - add (text); - add (routegroup); - } - - Gtk::TreeModelColumn is_visible; - Gtk::TreeModelColumn gain; - Gtk::TreeModelColumn record; - Gtk::TreeModelColumn mute; - Gtk::TreeModelColumn solo; - Gtk::TreeModelColumn select; - Gtk::TreeModelColumn edits; - Gtk::TreeModelColumn text; - Gtk::TreeModelColumn routegroup; - }; - - GroupListModelColumns group_columns; - - Glib::RefPtr group_model; - Glib::RefPtr group_selection; - - Gtk::TreeView route_group_display; - Gtk::ScrolledWindow route_group_display_scroller; - Gtk::Menu* route_group_menu; - - void build_route_group_menu (ARDOUR::RouteGroup *); - void activate_all_route_groups (); - void disable_all_route_groups (); - void subgroup_route_group (ARDOUR::RouteGroup*); - void unsubgroup_route_group (ARDOUR::RouteGroup*); - - bool in_route_group_row_change; - void route_group_row_change (const Gtk::TreeModel::Path&,const Gtk::TreeModel::iterator&); - void route_group_name_edit (const Glib::ustring&, const Glib::ustring&); - void new_route_group (); - void new_route_group_from_selection (); - void new_route_group_from_rec_enabled (); - void new_route_group_from_soloed (); - void edit_route_group (ARDOUR::RouteGroup *); - void fit_route_group (ARDOUR::RouteGroup *); - void route_group_list_button_clicked (); - gint route_group_list_button_press_event (GdkEventButton* ev); - void add_route_group (ARDOUR::RouteGroup* group); - void remove_selected_route_group (); - void route_groups_changed (); - void group_flags_changed (void*, ARDOUR::RouteGroup*); + bool sync_track_view_list_and_routes (); Gtk::VBox list_vpacker; @@ -2197,8 +2145,7 @@ public: void streamview_height_changed (); EditorGroupTabs* _group_tabs; - - void set_route_group_activation (ARDOUR::RouteGroup *, bool); + void fit_route_group (ARDOUR::RouteGroup *); friend class Drag; friend class RegionDrag; @@ -2227,7 +2174,7 @@ public: friend class EditorSummary; friend class EditorGroupTabs; - friend class EditorRouteList; + friend class EditorRoutes; }; #endif /* __ardour_editor_h__ */ diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc index 22db438a62..6b98446fde 100644 --- a/gtk2_ardour/editor_actions.cc +++ b/gtk2_ardour/editor_actions.cc @@ -30,7 +30,7 @@ #include "i18n.h" #include "audio_time_axis.h" #include "editor_group_tabs.h" -#include "editor_route_list.h" +#include "editor_routes.h" using namespace Gtk; using namespace Glib; @@ -313,9 +313,9 @@ Editor::register_actions () act = ActionManager::register_action (editor_actions, "toggle-zoom", _("Toggle Zoom State"), mem_fun(*this, &Editor::swap_visual_state)); ActionManager::session_sensitive_actions.push_back (act); - act = ActionManager::register_action (editor_actions, "move-selected-tracks-up", _("Move Selected Tracks Up"), bind (mem_fun(*_route_list, &EditorRouteList::move_selected_tracks), true)); + act = ActionManager::register_action (editor_actions, "move-selected-tracks-up", _("Move Selected Tracks Up"), bind (mem_fun(*_routes, &EditorRoutes::move_selected_tracks), true)); ActionManager::session_sensitive_actions.push_back (act); - act = ActionManager::register_action (editor_actions, "move-selected-tracks-down", _("Move Selected Tracks Down"), bind (mem_fun(*_route_list, &EditorRouteList::move_selected_tracks), false)); + act = ActionManager::register_action (editor_actions, "move-selected-tracks-down", _("Move Selected Tracks Down"), bind (mem_fun(*_routes, &EditorRoutes::move_selected_tracks), false)); ActionManager::session_sensitive_actions.push_back (act); act = ActionManager::register_action (editor_actions, "scroll-tracks-up", _("Scroll Tracks Up"), mem_fun(*this, &Editor::scroll_tracks_up)); diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index d85390383f..498a6cc0fd 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -42,7 +42,7 @@ #include "editor_drag.h" #include "region_view.h" #include "editor_group_tabs.h" -#include "editor_route_list.h" +#include "editor_routes.h" #include "i18n.h" diff --git a/gtk2_ardour/editor_component.cc b/gtk2_ardour/editor_component.cc new file mode 100644 index 0000000000..e45b8f61ef --- /dev/null +++ b/gtk2_ardour/editor_component.cc @@ -0,0 +1,48 @@ +/* + Copyright (C) 2009 Paul Davis + + This program 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. + + This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "ardour/session.h" +#include "editor_component.h" + +using namespace std; +using namespace sigc; +using namespace ARDOUR; + +EditorComponent::EditorComponent (Editor* e) + : _editor (e), + _session (0) +{ + +} + +void +EditorComponent::connect_to_session (Session* s) +{ + _session = s; + + _session_connections.push_back (_session->GoingAway.connect (mem_fun (*this, &EditorComponent::session_going_away))); +} + +void +EditorComponent::session_going_away () +{ + for (list::iterator i = _session_connections.begin(); i != _session_connections.end(); ++i) { + i->disconnect (); + } +} diff --git a/gtk2_ardour/editor_component.h b/gtk2_ardour/editor_component.h new file mode 100644 index 0000000000..328bfb15b2 --- /dev/null +++ b/gtk2_ardour/editor_component.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2009 Paul Davis + + This program 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. + + This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_gtk_editor_component_h__ +#define __ardour_gtk_editor_component_h__ + +#include +#include + +namespace ARDOUR { + class Session; +} + +class Editor; + +class EditorComponent +{ +public: + EditorComponent (Editor *); + + virtual void connect_to_session (ARDOUR::Session *); + +protected: + + Editor* _editor; + ARDOUR::Session* _session; + std::list _session_connections; + +private: + + void session_going_away (); + +}; + +#endif diff --git a/gtk2_ardour/editor_edit_groups.cc b/gtk2_ardour/editor_edit_groups.cc deleted file mode 100644 index 50d6eb5733..0000000000 --- a/gtk2_ardour/editor_edit_groups.cc +++ /dev/null @@ -1,580 +0,0 @@ -/* - Copyright (C) 2000 Paul Davis - - This program 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. - - This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include - -#include -#include -#include "ardour/route_group.h" - -#include "editor.h" -#include "keyboard.h" -#include "marker.h" -#include "time_axis_view.h" -#include "prompter.h" -#include "gui_thread.h" -#include "editor_group_tabs.h" -#include "route_group_dialog.h" -#include "route_time_axis.h" -#include "editor_route_list.h" - -#include "ardour/route.h" - -#include "i18n.h" - -using namespace std; -using namespace sigc; -using namespace ARDOUR; -using namespace PBD; -using namespace Gtk; - -void -Editor::build_route_group_menu (RouteGroup* g) -{ - using namespace Gtk::Menu_Helpers; - - delete route_group_menu; - - Menu* new_from = new Menu; - MenuList& f = new_from->items (); - f.push_back (MenuElem (_("Selection..."), mem_fun (*this, &Editor::new_route_group_from_selection))); - f.push_back (MenuElem (_("Record Enabled..."), mem_fun (*this, &Editor::new_route_group_from_rec_enabled))); - f.push_back (MenuElem (_("Soloed..."), mem_fun (*this, &Editor::new_route_group_from_soloed))); - - route_group_menu = new Menu; - route_group_menu->set_name ("ArdourContextMenu"); - MenuList& items = route_group_menu->items(); - - items.push_back (MenuElem (_("New..."), mem_fun(*this, &Editor::new_route_group))); - items.push_back (MenuElem (_("New From"), *new_from)); - if (g) { - items.push_back (MenuElem (_("Edit..."), bind (mem_fun (*this, &Editor::edit_route_group), g))); - items.push_back (MenuElem (_("Fit to Window"), bind (mem_fun (*this, &Editor::fit_route_group), g))); - items.push_back (MenuElem (_("Subgroup"), bind (mem_fun (*this, &Editor::subgroup_route_group), g))); - } - items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Activate All"), mem_fun(*this, &Editor::activate_all_route_groups))); - items.push_back (MenuElem (_("Disable All"), mem_fun(*this, &Editor::disable_all_route_groups))); -} - -void -Editor::subgroup_route_group (RouteGroup* g) -{ - g->make_subgroup (); -} - -void -Editor::unsubgroup_route_group (RouteGroup* g) -{ - g->destroy_subgroup (); -} - -void -Editor::activate_all_route_groups () -{ - session->foreach_route_group (bind (mem_fun (*this, &Editor::set_route_group_activation), true)); -} - -void -Editor::disable_all_route_groups () -{ - session->foreach_route_group (bind (mem_fun (*this, &Editor::set_route_group_activation), false)); -} - -void -Editor::set_route_group_activation (RouteGroup* g, bool a) -{ - g->set_active (a, this); -} - -void -Editor::new_route_group () -{ - RouteGroup* g = new RouteGroup (*session, "", RouteGroup::Active, (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit)); - - RouteGroupDialog d (g, Gtk::Stock::NEW); - int const r = d.do_run (); - - if (r == Gtk::RESPONSE_OK) { - session->add_route_group (g); - } else { - delete g; - } -} - -void -Editor::new_route_group_from_selection () -{ - RouteGroup* g = new RouteGroup (*session, "", RouteGroup::Active, (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit | RouteGroup::Select)); - - RouteGroupDialog d (g, Gtk::Stock::NEW); - int const r = d.do_run (); - - if (r == Gtk::RESPONSE_OK) { - session->add_route_group (g); - - for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - RouteTimeAxisView* rtv = dynamic_cast (*i); - if (rtv) { - rtv->route()->set_route_group (g, this); - } - } - - } else { - delete g; - } -} - -void -Editor::new_route_group_from_rec_enabled () -{ - RouteGroup* g = new RouteGroup (*session, "", RouteGroup::Active, (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit | RouteGroup::RecEnable)); - - RouteGroupDialog d (g, Gtk::Stock::NEW); - int const r = d.do_run (); - - if (r == Gtk::RESPONSE_OK) { - session->add_route_group (g); - - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - RouteTimeAxisView* rtv = dynamic_cast (*i); - if (rtv && rtv->route()->record_enabled()) { - rtv->route()->set_route_group (g, this); - } - } - - } else { - delete g; - } -} - -void -Editor::new_route_group_from_soloed () -{ - RouteGroup* g = new RouteGroup (*session, "", RouteGroup::Active, (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit)); - - RouteGroupDialog d (g, Gtk::Stock::NEW); - int const r = d.do_run (); - - if (r == Gtk::RESPONSE_OK) { - session->add_route_group (g); - - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - RouteTimeAxisView* rtv = dynamic_cast (*i); - if (rtv && !rtv->route()->is_master() && rtv->route()->soloed()) { - rtv->route()->set_route_group (g, this); - } - } - - } else { - delete g; - } -} - -void -Editor::edit_route_group (RouteGroup* g) -{ - RouteGroupDialog d (g, Gtk::Stock::APPLY); - d.do_run (); -} - -void -Editor::remove_selected_route_group () -{ - Glib::RefPtr selection = route_group_display.get_selection(); - TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows (); - - if (rows.empty()) { - return; - } - - TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); - TreeIter iter; - - /* selection mode is single, so rows.begin() is it */ - - if ((iter = group_model->get_iter (*i))) { - - RouteGroup* rg = (*iter)[group_columns.routegroup]; - - if (rg) { - session->remove_route_group (*rg); - } - } -} - -void -Editor::route_group_list_button_clicked () -{ - new_route_group (); -} - -gint -Editor::route_group_list_button_press_event (GdkEventButton* ev) -{ - TreeModel::Path path; - TreeIter iter; - RouteGroup* group = 0; - TreeViewColumn* column; - int cellx; - int celly; - - bool const p = route_group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly); - - if (p) { - iter = group_model->get_iter (path); - } - - if (iter) { - group = (*iter)[group_columns.routegroup]; - } - - if (Keyboard::is_context_menu_event (ev)) { - build_route_group_menu (group); - route_group_menu->popup (1, ev->time); - return true; - } - - if (!p) { - return 1; - } - - switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) { - case 0: - if (Keyboard::is_edit_event (ev)) { - if ((iter = group_model->get_iter (path))) { - if ((group = (*iter)[group_columns.routegroup]) != 0) { - // edit_route_group (group); -#ifdef GTKOSX - route_group_display.queue_draw(); -#endif - return true; - } - } - - } - break; - - case 1: - if ((iter = group_model->get_iter (path))) { - bool gain = (*iter)[group_columns.gain]; - (*iter)[group_columns.gain] = !gain; -#ifdef GTKOSX - route_group_display.queue_draw(); -#endif - return true; - } - break; - - case 2: - if ((iter = group_model->get_iter (path))) { - bool record = (*iter)[group_columns.record]; - (*iter)[group_columns.record] = !record; -#ifdef GTKOSX - route_group_display.queue_draw(); -#endif - return true; - } - break; - - case 3: - if ((iter = group_model->get_iter (path))) { - bool mute = (*iter)[group_columns.mute]; - (*iter)[group_columns.mute] = !mute; -#ifdef GTKOSX - route_group_display.queue_draw(); -#endif - return true; - } - break; - - case 4: - if ((iter = group_model->get_iter (path))) { - bool solo = (*iter)[group_columns.solo]; - (*iter)[group_columns.solo] = !solo; -#ifdef GTKOSX - route_group_display.queue_draw(); -#endif - return true; - } - break; - - case 5: - if ((iter = group_model->get_iter (path))) { - bool select = (*iter)[group_columns.select]; - (*iter)[group_columns.select] = !select; -#ifdef GTKOSX - route_group_display.queue_draw(); -#endif - return true; - } - break; - - case 6: - if ((iter = group_model->get_iter (path))) { - bool edits = (*iter)[group_columns.edits]; - (*iter)[group_columns.edits] = !edits; -#ifdef GTKOSX - route_group_display.queue_draw(); -#endif - return true; - } - break; - - case 7: - if ((iter = group_model->get_iter (path))) { - bool visible = (*iter)[group_columns.is_visible]; - (*iter)[group_columns.is_visible] = !visible; -#ifdef GTKOSX - route_group_display.queue_draw(); -#endif - return true; - } - break; - - default: - break; - } - - return false; - } - -void -Editor::route_group_row_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter) -{ - RouteGroup* group; - - if (in_route_group_row_change) { - return; - } - - if ((group = (*iter)[group_columns.routegroup]) == 0) { - return; - } - - if ((*iter)[group_columns.is_visible]) { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - _route_list->show_track_in_display (**j); - } - } - } else { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - hide_track_in_display (**j); - } - } - } - - if ((*iter)[group_columns.gain]) { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::Gain, true); - } - } - } else { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::Gain, false); - } - } - } - - if ((*iter)[group_columns.record]) { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::RecEnable, true); - } - } - } else { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::RecEnable, false); - } - } - } - - if ((*iter)[group_columns.mute]) { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::Mute, true); - } - } - } else { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::Mute, false); - } - } - } - - if ((*iter)[group_columns.solo]) { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::Solo, true); - } - } - } else { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::Solo, false); - } - } - } - - if ((*iter)[group_columns.select]) { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::Select, true); - } - } - } else { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::Select, false); - } - } - } - - if ((*iter)[group_columns.edits]) { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::Edit, true); - } - } - } else { - for (TrackViewList::iterator j = track_views.begin(); j != track_views.end(); ++j) { - if ((*j)->route_group() == group) { - group->set_property (RouteGroup::Edit, false); - } - } - } - - string name = (*iter)[group_columns.text]; - - if (name != group->name()) { - group->set_name (name); - } -} - -void -Editor::add_route_group (RouteGroup* group) -{ - ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::add_route_group), group)); - bool focus = false; - - TreeModel::Row row = *(group_model->append()); - - row[group_columns.is_visible] = !group->is_hidden(); - row[group_columns.gain] = group->property(RouteGroup::Gain); - row[group_columns.record] = group->property(RouteGroup::RecEnable); - row[group_columns.mute] = group->property(RouteGroup::Mute); - row[group_columns.solo] = group->property(RouteGroup::Solo); - row[group_columns.select] = group->property(RouteGroup::Select); - row[group_columns.edits] = group->property(RouteGroup::Edit); - - in_route_group_row_change = true; - - row[group_columns.routegroup] = group; - - if (!group->name().empty()) { - row[group_columns.text] = group->name(); - } else { - row[group_columns.text] = _("unnamed"); - focus = true; - } - - group->FlagsChanged.connect (bind (mem_fun(*this, &Editor::group_flags_changed), group)); - - if (focus) { - TreeViewColumn* col = route_group_display.get_column (0); - CellRendererText* name_cell = dynamic_cast(route_group_display.get_column_cell_renderer (0)); - route_group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true); - } - - in_route_group_row_change = false; - - _group_tabs->set_dirty (); -} - -void -Editor::route_groups_changed () -{ - ENSURE_GUI_THREAD (mem_fun (*this, &Editor::route_groups_changed)); - - /* just rebuild the while thing */ - - group_model->clear (); - - { - TreeModel::Row row; - row = *(group_model->append()); - row[group_columns.is_visible] = true; - row[group_columns.text] = (_("-all-")); - row[group_columns.routegroup] = 0; - } - - session->foreach_route_group (mem_fun (*this, &Editor::add_route_group)); -} - -void -Editor::group_flags_changed (void* src, RouteGroup* group) -{ - ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::group_flags_changed), src, group)); - - in_route_group_row_change = true; - - Gtk::TreeModel::Children children = group_model->children(); - - for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) { - if (group == (*iter)[group_columns.routegroup]) { - (*iter)[group_columns.is_visible] = !group->is_hidden(); - (*iter)[group_columns.text] = group->name(); - (*iter)[group_columns.gain] = group->property(RouteGroup::Gain); - (*iter)[group_columns.record] = group->property(RouteGroup::RecEnable); - (*iter)[group_columns.mute] = group->property(RouteGroup::Mute); - (*iter)[group_columns.solo] = group->property(RouteGroup::Solo); - (*iter)[group_columns.select] = group->property(RouteGroup::Select); - (*iter)[group_columns.edits] = group->property(RouteGroup::Edit); - } - } - - in_route_group_row_change = false; - - _group_tabs->set_dirty (); -} - -void -Editor::route_group_name_edit (const Glib::ustring& path, const Glib::ustring& new_text) -{ - RouteGroup* group; - TreeIter iter; - - if ((iter = group_model->get_iter (path))) { - - if ((group = (*iter)[group_columns.routegroup]) == 0) { - return; - } - - if (new_text != group->name()) { - group->set_name (new_text); - } - } -} diff --git a/gtk2_ardour/editor_group_tabs.cc b/gtk2_ardour/editor_group_tabs.cc index ec279e2bc6..7007c37a05 100644 --- a/gtk2_ardour/editor_group_tabs.cc +++ b/gtk2_ardour/editor_group_tabs.cc @@ -22,12 +22,13 @@ #include "editor.h" #include "route_time_axis.h" #include "utils.h" +#include "editor_route_groups.h" using namespace std; using namespace ARDOUR; EditorGroupTabs::EditorGroupTabs (Editor* e) - : _editor (e) + : GroupTabs (e) { } @@ -157,6 +158,5 @@ EditorGroupTabs::reflect_tabs (list const & tabs) Gtk::Menu* EditorGroupTabs::get_menu (RouteGroup *g) { - _editor->build_route_group_menu (g); - return _editor->route_group_menu; + return _editor->_route_groups->menu (g); } diff --git a/gtk2_ardour/editor_group_tabs.h b/gtk2_ardour/editor_group_tabs.h index a0ea2183f0..9e37992902 100644 --- a/gtk2_ardour/editor_group_tabs.h +++ b/gtk2_ardour/editor_group_tabs.h @@ -36,6 +36,4 @@ private: return _height; } Gtk::Menu* get_menu (ARDOUR::RouteGroup* g); - - Editor* _editor; }; diff --git a/gtk2_ardour/editor_mixer.cc b/gtk2_ardour/editor_mixer.cc index 61b5e2f143..d4b9681c93 100644 --- a/gtk2_ardour/editor_mixer.cc +++ b/gtk2_ardour/editor_mixer.cc @@ -31,7 +31,8 @@ #include "selection.h" #include "audio_time_axis.h" #include "actions.h" -#include "editor_route_list.h" +#include "editor_routes.h" +#include "editor_route_groups.h" #include "i18n.h" @@ -364,22 +365,20 @@ Editor::session_going_away () /* hide all tracks */ - _route_list->hide_all_tracks (false); + _routes->hide_all_tracks (false); /* rip everything out of the list displays */ region_list_display.set_model (Glib::RefPtr(0)); - _route_list->clear (); + _routes->clear (); + _route_groups->clear (); named_selection_display.set_model (Glib::RefPtr(0)); - route_group_display.set_model (Glib::RefPtr(0)); region_list_model->clear (); named_selection_model->clear (); - group_model->clear (); region_list_display.set_model (region_list_model); named_selection_display.set_model (named_selection_model); - route_group_display.set_model (group_model); edit_point_clock_connection_a.disconnect(); edit_point_clock_connection_b.disconnect(); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 47ef27dc28..be87baeafd 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -77,7 +77,7 @@ #include "utils.h" #include "editor_drag.h" #include "strip_silence_dialog.h" -#include "editor_route_list.h" +#include "editor_routes.h" #include "i18n.h" @@ -1745,7 +1745,7 @@ Editor::temporal_zoom_region (bool both_axes) /* hide irrelevant tracks */ - _route_list->suspend_redisplay (); + _routes->suspend_redisplay (); for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) { @@ -1753,7 +1753,7 @@ Editor::temporal_zoom_region (bool both_axes) } } - _route_list->resume_redisplay (); + _routes->resume_redisplay (); vertical_adjustment.set_value (0.0); no_save_visual = false; @@ -6376,13 +6376,6 @@ Editor::fit_selected_tracks () fit_tracks (selection->tracks); } -void -Editor::fit_route_group (RouteGroup *g) -{ - TrackSelection ts = axis_views_from_routes (g->route_list ()); - fit_tracks (ts); -} - void Editor::fit_tracks (TrackSelection & tracks) { diff --git a/gtk2_ardour/editor_route_groups.cc b/gtk2_ardour/editor_route_groups.cc new file mode 100644 index 0000000000..a9abf4889d --- /dev/null +++ b/gtk2_ardour/editor_route_groups.cc @@ -0,0 +1,668 @@ +/* + Copyright (C) 2000 Paul Davis + + This program 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. + + This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include +#include +#include "ardour/route_group.h" + +#include "editor.h" +#include "keyboard.h" +#include "marker.h" +#include "time_axis_view.h" +#include "prompter.h" +#include "gui_thread.h" +#include "editor_group_tabs.h" +#include "route_group_dialog.h" +#include "route_time_axis.h" +#include "editor_routes.h" +#include "editor_route_groups.h" + +#include "ardour/route.h" + +#include "i18n.h" + +using namespace std; +using namespace sigc; +using namespace ARDOUR; +using namespace PBD; +using namespace Gtk; + +EditorRouteGroups::EditorRouteGroups (Editor* e) + : EditorComponent (e), + _menu (0), + _in_row_change (false) + +{ + _model = ListStore::create (_columns); + _display.set_model (_model); + + _display.append_column (_("Name"), _columns.text); + + _display.append_column (_("G"), _columns.gain); + _display.append_column (_("R"), _columns.record); + _display.append_column (_("M"), _columns.mute); + _display.append_column (_("S"), _columns.solo); + _display.append_column (_("Sel"), _columns.select); + _display.append_column (_("E"), _columns.edits); + + _display.append_column (_("Show"), _columns.is_visible); + + _display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0)); + _display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1)); + _display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2)); + _display.get_column (3)->set_data (X_("colnum"), GUINT_TO_POINTER(3)); + _display.get_column (4)->set_data (X_("colnum"), GUINT_TO_POINTER(4)); + _display.get_column (5)->set_data (X_("colnum"), GUINT_TO_POINTER(5)); + _display.get_column (6)->set_data (X_("colnum"), GUINT_TO_POINTER(6)); + _display.get_column (7)->set_data (X_("colnum"), GUINT_TO_POINTER(7)); + + _display.get_column (0)->set_expand (true); + _display.get_column (1)->set_expand (false); + _display.get_column (2)->set_expand (false); + _display.get_column (3)->set_expand (false); + _display.get_column (4)->set_expand (false); + _display.get_column (5)->set_expand (false); + _display.get_column (6)->set_expand (false); + _display.get_column (7)->set_expand (false); + + _display.set_headers_visible (true); + + /* name is directly editable */ + + CellRendererText* name_cell = dynamic_cast(_display.get_column_cell_renderer (0)); + name_cell->property_editable() = true; + name_cell->signal_edited().connect (mem_fun (*this, &EditorRouteGroups::name_edit)); + + /* use checkbox for the active + visible columns */ + + CellRendererToggle* active_cell = dynamic_cast(_display.get_column_cell_renderer (1)); + active_cell->property_activatable() = true; + active_cell->property_radio() = false; + + active_cell = dynamic_cast(_display.get_column_cell_renderer (2)); + active_cell->property_activatable() = true; + active_cell->property_radio() = false; + + active_cell = dynamic_cast(_display.get_column_cell_renderer (3)); + active_cell->property_activatable() = true; + active_cell->property_radio() = false; + + active_cell = dynamic_cast(_display.get_column_cell_renderer (4)); + active_cell->property_activatable() = true; + active_cell->property_radio() = false; + + active_cell = dynamic_cast(_display.get_column_cell_renderer (5)); + active_cell->property_activatable() = true; + active_cell->property_radio() = false; + + active_cell = dynamic_cast(_display.get_column_cell_renderer (6)); + active_cell->property_activatable() = true; + active_cell->property_radio() = false; + + active_cell = dynamic_cast(_display.get_column_cell_renderer (7)); + active_cell->property_activatable() = true; + active_cell->property_radio() = false; + + _model->signal_row_changed().connect (mem_fun (*this, &EditorRouteGroups::row_change)); + + _display.set_name ("EditGroupList"); + _display.get_selection()->set_mode (SELECTION_SINGLE); + _display.set_headers_visible (true); + _display.set_reorderable (false); + _display.set_rules_hint (true); + _display.set_size_request (75, -1); + + _scroller.add (_display); + _scroller.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC); + + _display.signal_button_press_event().connect (mem_fun(*this, &EditorRouteGroups::button_press_event), false); + + _display_packer = new VBox; + HBox* button_box = manage (new HBox()); + button_box->set_homogeneous (true); + + Button* add_button = manage (new Button ()); + Button* remove_button = manage (new Button ()); + + Widget* w; + + w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON)); + w->show(); + add_button->add (*w); + + w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON)); + w->show(); + remove_button->add (*w); + + add_button->signal_clicked().connect (mem_fun (*this, &EditorRouteGroups::new_route_group)); + remove_button->signal_clicked().connect (mem_fun (*this, &EditorRouteGroups::remove_selected)); + + button_box->pack_start (*add_button); + button_box->pack_start (*remove_button); + + _display_packer->pack_start (_scroller, true, true); + _display_packer->pack_start (*button_box, false, false); +} + + +Gtk::Menu* +EditorRouteGroups::menu (RouteGroup* g) +{ + using namespace Gtk::Menu_Helpers; + + delete _menu; + + Menu* new_from = new Menu; + MenuList& f = new_from->items (); + f.push_back (MenuElem (_("Selection..."), mem_fun (*this, &EditorRouteGroups::new_from_selection))); + f.push_back (MenuElem (_("Record Enabled..."), mem_fun (*this, &EditorRouteGroups::new_from_rec_enabled))); + f.push_back (MenuElem (_("Soloed..."), mem_fun (*this, &EditorRouteGroups::new_from_soloed))); + + _menu = new Menu; + _menu->set_name ("ArdourContextMenu"); + MenuList& items = _menu->items(); + + items.push_back (MenuElem (_("New..."), mem_fun(*this, &EditorRouteGroups::new_route_group))); + items.push_back (MenuElem (_("New From"), *new_from)); + if (g) { + items.push_back (MenuElem (_("Edit..."), bind (mem_fun (*this, &EditorRouteGroups::edit), g))); + items.push_back (MenuElem (_("Fit to Window"), bind (mem_fun (*_editor, &Editor::fit_route_group), g))); + items.push_back (MenuElem (_("Subgroup"), bind (mem_fun (*this, &EditorRouteGroups::subgroup), g))); + } + items.push_back (SeparatorElem()); + items.push_back (MenuElem (_("Activate All"), mem_fun(*this, &EditorRouteGroups::activate_all))); + items.push_back (MenuElem (_("Disable All"), mem_fun(*this, &EditorRouteGroups::disable_all))); + + return _menu; +} + +void +EditorRouteGroups::subgroup (RouteGroup* g) +{ + g->make_subgroup (); +} + +void +EditorRouteGroups::unsubgroup (RouteGroup* g) +{ + g->destroy_subgroup (); +} + +void +EditorRouteGroups::activate_all () +{ + _session->foreach_route_group ( + bind (mem_fun (*this, &EditorRouteGroups::set_activation), true) + ); +} + +void +EditorRouteGroups::disable_all () +{ + _session->foreach_route_group ( + bind (mem_fun (*this, &EditorRouteGroups::set_activation), false) + ); +} + +void +EditorRouteGroups::set_activation (RouteGroup* g, bool a) +{ + g->set_active (a, this); +} + +void +EditorRouteGroups::new_route_group () +{ + RouteGroup* g = new RouteGroup ( + *_session, + "", + RouteGroup::Active, + (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit) + ); + + RouteGroupDialog d (g, Gtk::Stock::NEW); + int const r = d.do_run (); + + if (r == Gtk::RESPONSE_OK) { + _session->add_route_group (g); + } else { + delete g; + } +} + +void +EditorRouteGroups::new_from_selection () +{ + RouteGroup* g = new RouteGroup ( + *_session, + "", + RouteGroup::Active, + (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit | RouteGroup::Select) + ); + + RouteGroupDialog d (g, Gtk::Stock::NEW); + int const r = d.do_run (); + + if (r == Gtk::RESPONSE_OK) { + _session->add_route_group (g); + + for (TrackSelection::iterator i = _editor->get_selection().tracks.begin(); i != _editor->get_selection().tracks.end(); ++i) { + RouteTimeAxisView* rtv = dynamic_cast (*i); + if (rtv) { + rtv->route()->set_route_group (g, this); + } + } + + } else { + delete g; + } +} + +void +EditorRouteGroups::new_from_rec_enabled () +{ + RouteGroup* g = new RouteGroup ( + *_session, + "", + RouteGroup::Active, + (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit | RouteGroup::RecEnable) + ); + + RouteGroupDialog d (g, Gtk::Stock::NEW); + int const r = d.do_run (); + + if (r == Gtk::RESPONSE_OK) { + _session->add_route_group (g); + + for (Editor::TrackViewList::const_iterator i = _editor->get_track_views().begin(); i != _editor->get_track_views().end(); ++i) { + RouteTimeAxisView* rtv = dynamic_cast (*i); + if (rtv && rtv->route()->record_enabled()) { + rtv->route()->set_route_group (g, this); + } + } + + } else { + delete g; + } +} + +void +EditorRouteGroups::new_from_soloed () +{ + RouteGroup* g = new RouteGroup ( + *_session, + "", + RouteGroup::Active, + (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit) + ); + + RouteGroupDialog d (g, Gtk::Stock::NEW); + int const r = d.do_run (); + + if (r == Gtk::RESPONSE_OK) { + _session->add_route_group (g); + + for (Editor::TrackViewList::const_iterator i = _editor->get_track_views().begin(); i != _editor->get_track_views().end(); ++i) { + RouteTimeAxisView* rtv = dynamic_cast (*i); + if (rtv && !rtv->route()->is_master() && rtv->route()->soloed()) { + rtv->route()->set_route_group (g, this); + } + } + + } else { + delete g; + } +} + +void +EditorRouteGroups::edit (RouteGroup* g) +{ + RouteGroupDialog d (g, Gtk::Stock::APPLY); + d.do_run (); +} + +void +EditorRouteGroups::remove_selected () +{ + Glib::RefPtr selection = _display.get_selection(); + TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows (); + + if (rows.empty()) { + return; + } + + TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); + TreeIter iter; + + /* selection mode is single, so rows.begin() is it */ + + if ((iter = _model->get_iter (*i))) { + + RouteGroup* rg = (*iter)[_columns.routegroup]; + + if (rg) { + _session->remove_route_group (*rg); + } + } +} + +void +EditorRouteGroups::button_clicked () +{ + new_route_group (); +} + +gint +EditorRouteGroups::button_press_event (GdkEventButton* ev) +{ + TreeModel::Path path; + TreeIter iter; + RouteGroup* group = 0; + TreeViewColumn* column; + int cellx; + int celly; + + bool const p = _display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly); + + if (p) { + iter = _model->get_iter (path); + } + + if (iter) { + group = (*iter)[_columns.routegroup]; + } + + if (Keyboard::is_context_menu_event (ev)) { + menu(group)->popup (1, ev->time); + return true; + } + + if (!p) { + return 1; + } + + switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) { + case 0: + if (Keyboard::is_edit_event (ev)) { + if ((iter = _model->get_iter (path))) { + if ((group = (*iter)[_columns.routegroup]) != 0) { + // edit_route_group (group); +#ifdef GTKOSX + _display.queue_draw(); +#endif + return true; + } + } + + } + break; + + case 1: + if ((iter = _model->get_iter (path))) { + bool gain = (*iter)[_columns.gain]; + (*iter)[_columns.gain] = !gain; +#ifdef GTKOSX + _display.queue_draw(); +#endif + return true; + } + break; + + case 2: + if ((iter = _model->get_iter (path))) { + bool record = (*iter)[_columns.record]; + (*iter)[_columns.record] = !record; +#ifdef GTKOSX + _display.queue_draw(); +#endif + return true; + } + break; + + case 3: + if ((iter = _model->get_iter (path))) { + bool mute = (*iter)[_columns.mute]; + (*iter)[_columns.mute] = !mute; +#ifdef GTKOSX + _display.queue_draw(); +#endif + return true; + } + break; + + case 4: + if ((iter = _model->get_iter (path))) { + bool solo = (*iter)[_columns.solo]; + (*iter)[_columns.solo] = !solo; +#ifdef GTKOSX + _display.queue_draw(); +#endif + return true; + } + break; + + case 5: + if ((iter = _model->get_iter (path))) { + bool select = (*iter)[_columns.select]; + (*iter)[_columns.select] = !select; +#ifdef GTKOSX + _display.queue_draw(); +#endif + return true; + } + break; + + case 6: + if ((iter = _model->get_iter (path))) { + bool edits = (*iter)[_columns.edits]; + (*iter)[_columns.edits] = !edits; +#ifdef GTKOSX + _display.queue_draw(); +#endif + return true; + } + break; + + case 7: + if ((iter = _model->get_iter (path))) { + bool visible = (*iter)[_columns.is_visible]; + (*iter)[_columns.is_visible] = !visible; +#ifdef GTKOSX + _display.queue_draw(); +#endif + return true; + } + break; + + default: + break; + } + + return false; + } + +void +EditorRouteGroups::row_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter) +{ + RouteGroup* group; + + if (_in_row_change) { + return; + } + + if ((group = (*iter)[_columns.routegroup]) == 0) { + return; + } + + if ((*iter)[_columns.is_visible]) { + for (Editor::TrackViewList::const_iterator j = _editor->get_track_views().begin(); j != _editor->get_track_views().end(); ++j) { + if ((*j)->route_group() == group) { + _editor->_routes->show_track_in_display (**j); + } + } + } else { + for (Editor::TrackViewList::const_iterator j = _editor->get_track_views().begin(); j != _editor->get_track_views().end(); ++j) { + if ((*j)->route_group() == group) { + _editor->hide_track_in_display (**j); + } + } + } + + group->set_property (RouteGroup::Gain, (*iter)[_columns.gain]); + group->set_property (RouteGroup::RecEnable, (*iter)[_columns.record]); + group->set_property (RouteGroup::Mute, (*iter)[_columns.mute]); + group->set_property (RouteGroup::Solo, (*iter)[_columns.solo]); + group->set_property (RouteGroup::Select, (*iter)[_columns.select]); + group->set_property (RouteGroup::Edit, (*iter)[_columns.edits]); + + string name = (*iter)[_columns.text]; + + if (name != group->name()) { + group->set_name (name); + } +} + +void +EditorRouteGroups::add (RouteGroup* group) +{ + ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRouteGroups::add), group)); + bool focus = false; + + TreeModel::Row row = *(_model->append()); + + row[_columns.is_visible] = !group->is_hidden(); + row[_columns.gain] = group->property(RouteGroup::Gain); + row[_columns.record] = group->property(RouteGroup::RecEnable); + row[_columns.mute] = group->property(RouteGroup::Mute); + row[_columns.solo] = group->property(RouteGroup::Solo); + row[_columns.select] = group->property(RouteGroup::Select); + row[_columns.edits] = group->property(RouteGroup::Edit); + + _in_row_change = true; + + row[_columns.routegroup] = group; + + if (!group->name().empty()) { + row[_columns.text] = group->name(); + } else { + row[_columns.text] = _("unnamed"); + focus = true; + } + + group->FlagsChanged.connect (bind (mem_fun (*this, &EditorRouteGroups::flags_changed), group)); + + if (focus) { + TreeViewColumn* col = _display.get_column (0); + CellRendererText* name_cell = dynamic_cast(_display.get_column_cell_renderer (0)); + _display.set_cursor (_model->get_path (row), *col, *name_cell, true); + } + + _in_row_change = false; + + _editor->_group_tabs->set_dirty (); +} + +void +EditorRouteGroups::groups_changed () +{ + ENSURE_GUI_THREAD (mem_fun (*this, &EditorRouteGroups::groups_changed)); + + /* just rebuild the while thing */ + + _model->clear (); + + { + TreeModel::Row row; + row = *(_model->append()); + row[_columns.is_visible] = true; + row[_columns.text] = (_("-all-")); + row[_columns.routegroup] = 0; + } + + _session->foreach_route_group (mem_fun (*this, &EditorRouteGroups::add)); +} + +void +EditorRouteGroups::flags_changed (void* src, RouteGroup* group) +{ + ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRouteGroups::flags_changed), src, group)); + + _in_row_change = true; + + Gtk::TreeModel::Children children = _model->children(); + + for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) { + if (group == (*iter)[_columns.routegroup]) { + (*iter)[_columns.is_visible] = !group->is_hidden(); + (*iter)[_columns.text] = group->name(); + (*iter)[_columns.gain] = group->property(RouteGroup::Gain); + (*iter)[_columns.record] = group->property(RouteGroup::RecEnable); + (*iter)[_columns.mute] = group->property(RouteGroup::Mute); + (*iter)[_columns.solo] = group->property(RouteGroup::Solo); + (*iter)[_columns.select] = group->property(RouteGroup::Select); + (*iter)[_columns.edits] = group->property(RouteGroup::Edit); + } + } + + _in_row_change = false; + + _editor->_group_tabs->set_dirty (); +} + +void +EditorRouteGroups::name_edit (const Glib::ustring& path, const Glib::ustring& new_text) +{ + RouteGroup* group; + TreeIter iter; + + if ((iter = _model->get_iter (path))) { + + if ((group = (*iter)[_columns.routegroup]) == 0) { + return; + } + + if (new_text != group->name()) { + group->set_name (new_text); + } + } +} + +void +EditorRouteGroups::clear () +{ + _display.set_model (Glib::RefPtr (0)); + _model->clear (); + _display.set_model (_model); +} + +void +EditorRouteGroups::connect_to_session (Session* s) +{ + EditorComponent::connect_to_session (s); + + _session_connections.push_back (_session->route_group_added.connect (mem_fun (*this, &EditorRouteGroups::add))); + _session_connections.push_back (_session->route_group_removed.connect (mem_fun (*this, &EditorRouteGroups::groups_changed))); + + groups_changed (); +} + + diff --git a/gtk2_ardour/editor_route_groups.h b/gtk2_ardour/editor_route_groups.h new file mode 100644 index 0000000000..5235a6a7e4 --- /dev/null +++ b/gtk2_ardour/editor_route_groups.h @@ -0,0 +1,77 @@ +#include "editor_component.h" + +class EditorRouteGroups : public EditorComponent +{ +public: + EditorRouteGroups (Editor *); + + void connect_to_session (ARDOUR::Session *); + + Gtk::Widget& widget () { + return *_display_packer; + } + + Gtk::Menu* menu (ARDOUR::RouteGroup *); + + void clear (); + +private: + + struct Columns : public Gtk::TreeModel::ColumnRecord { + + Columns () { + add (is_visible); + add (gain); + add (record); + add (mute); + add (solo); + add (select); + add (edits); + add (text); + add (routegroup); + } + + Gtk::TreeModelColumn is_visible; + Gtk::TreeModelColumn gain; + Gtk::TreeModelColumn record; + Gtk::TreeModelColumn mute; + Gtk::TreeModelColumn solo; + Gtk::TreeModelColumn select; + Gtk::TreeModelColumn edits; + Gtk::TreeModelColumn text; + Gtk::TreeModelColumn routegroup; + }; + + Columns _columns; + + void activate_all (); + void disable_all (); + void subgroup (ARDOUR::RouteGroup*); + void unsubgroup (ARDOUR::RouteGroup*); + + void row_change (const Gtk::TreeModel::Path&,const Gtk::TreeModel::iterator&); + void name_edit (const Glib::ustring&, const Glib::ustring&); + void new_route_group (); + void new_from_selection (); + void new_from_rec_enabled (); + void new_from_soloed (); + void edit (ARDOUR::RouteGroup *); + void button_clicked (); + gint button_press_event (GdkEventButton* ev); + void add (ARDOUR::RouteGroup* group); + void remove_route_group (); + void groups_changed (); + void flags_changed (void*, ARDOUR::RouteGroup*); + void set_activation (ARDOUR::RouteGroup *, bool); + void remove_selected (); + + Gtk::Menu* _menu; + Glib::RefPtr _model; + Glib::RefPtr _selection; + Gtk::TreeView _display; + Gtk::ScrolledWindow _scroller; + Gtk::VBox* _display_packer; + bool _in_row_change; +}; + + diff --git a/gtk2_ardour/editor_route_list.cc b/gtk2_ardour/editor_route_list.cc deleted file mode 100644 index c597adf86f..0000000000 --- a/gtk2_ardour/editor_route_list.cc +++ /dev/null @@ -1,842 +0,0 @@ -/* - Copyright (C) 2000-2009 Paul Davis - - This program 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. - - This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include - -#include "gtkmm2ext/cell_renderer_pixbuf_toggle.h" - -#include "ardour/diskstream.h" - -#include "editor.h" -#include "keyboard.h" -#include "ardour_ui.h" -#include "audio_time_axis.h" -#include "midi_time_axis.h" -#include "mixer_strip.h" -#include "gui_thread.h" -#include "actions.h" -#include "utils.h" -#include "editor_group_tabs.h" -#include "editor_route_list.h" - -#include "pbd/unknown_type.h" - -#include "ardour/route.h" - -#include "i18n.h" - -using namespace std; -using namespace sigc; -using namespace ARDOUR; -using namespace PBD; -using namespace Gtk; -using namespace Gtkmm2ext; -using namespace Glib; - -EditorRouteList::EditorRouteList (Editor* e) - : _editor (e), - _ignore_reorder (false), - _no_redisplay (false), - _redisplay_does_not_sync_order_keys (false), - _redisplay_does_not_reset_order_keys (false), - _menu (0) -{ - _scroller.add (_display); - _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC); - - _model = ListStore::create (_columns); - _display.set_model (_model); - - CellRendererPixbufToggle* rec_col_renderer = manage (new CellRendererPixbufToggle()); - - rec_col_renderer->set_active_pixbuf (::get_icon("record_normal_red")); - rec_col_renderer->set_inactive_pixbuf (::get_icon("record_disabled_grey")); - - rec_col_renderer->signal_toggled().connect (mem_fun (*this, &EditorRouteList::on_tv_rec_enable_toggled)); - - Gtk::TreeViewColumn* rec_state_column = manage (new TreeViewColumn("Rec", *rec_col_renderer)); - rec_state_column->add_attribute(rec_col_renderer->property_active(), _columns.rec_enabled); - rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track); - - _display.append_column (*rec_state_column); - _display.append_column (_("Show"), _columns.visible); - _display.append_column (_("Name"), _columns.text); - - _display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0)); - _display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1)); - _display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2)); - - _display.set_headers_visible (true); - _display.set_name ("TrackListDisplay"); - _display.get_selection()->set_mode (SELECTION_NONE); - _display.set_reorderable (true); - _display.set_rules_hint (true); - _display.set_size_request (100, -1); - _display.add_object_drag (_columns.route.index(), "routes"); - - CellRendererToggle* visible_cell = dynamic_cast(_display.get_column_cell_renderer (1)); - - visible_cell->property_activatable() = true; - visible_cell->property_radio() = false; - - _model->signal_row_deleted().connect (mem_fun (*this, &EditorRouteList::route_deleted)); - _model->signal_row_changed().connect (mem_fun (*this, &EditorRouteList::changed)); - _model->signal_rows_reordered().connect (mem_fun (*this, &EditorRouteList::reordered)); - _display.signal_button_press_event().connect (mem_fun (*this, &EditorRouteList::button_press), false); - - Route::SyncOrderKeys.connect (mem_fun (*this, &EditorRouteList::sync_order_keys)); -} - -void -EditorRouteList::on_tv_rec_enable_toggled (Glib::ustring const & path_string) -{ - // Get the model row that has been toggled. - Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string)); - - TimeAxisView *tv = row[_columns.tv]; - AudioTimeAxisView *atv = dynamic_cast (tv); - - if (atv != 0 && atv->is_audio_track()){ - atv->get_diskstream()->set_record_enabled(!atv->get_diskstream()->record_enabled()); - } -} - -void -EditorRouteList::build_menu () -{ - using namespace Menu_Helpers; - using namespace Gtk; - - _menu = new Menu; - - MenuList& items = _menu->items(); - _menu->set_name ("ArdourContextMenu"); - - items.push_back (MenuElem (_("Show All"), mem_fun (*this, &EditorRouteList::show_all_routes))); - items.push_back (MenuElem (_("Hide All"), mem_fun (*this, &EditorRouteList::hide_all_routes))); - items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun (*this, &EditorRouteList::show_all_audiotracks))); - items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun (*this, &EditorRouteList::hide_all_audiotracks))); - items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun (*this, &EditorRouteList::show_all_audiobus))); - items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun (*this, &EditorRouteList::hide_all_audiobus))); - -} - -void -EditorRouteList::show_menu () -{ - if (_menu == 0) { - build_menu (); - } - - _menu->popup (1, gtk_get_current_event_time()); -} - -const char* _order_key = N_("editor"); - -void -EditorRouteList::redisplay () -{ - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator i; - uint32_t position; - int n; - - if (_no_redisplay) { - return; - } - - for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) { - TimeAxisView *tv = (*i)[_columns.tv]; - boost::shared_ptr route = (*i)[_columns.route]; - - if (tv == 0) { - // just a "title" row - continue; - } - - if (!_redisplay_does_not_reset_order_keys) { - - /* this reorder is caused by user action, so reassign sort order keys - to tracks. - */ - - route->set_order_key (_order_key, n); - } - - bool visible = (*i)[_columns.visible]; - - /* show or hide the TimeAxisView */ - if (visible) { - tv->set_marked_for_display (true); - position += tv->show_at (position, n, &_editor->edit_controls_vbox); - tv->clip_to_viewport (); - } else { - tv->set_marked_for_display (false); - tv->hide (); - } - - n++; - } - - /* whenever we go idle, update the track view list to reflect the new order. - we can't do this here, because we could mess up something that is traversing - the track order and has caused a redisplay of the list. - */ - - Glib::signal_idle().connect (mem_fun (*_editor, &Editor::sync_track_view_list_and_route_list)); - - _editor->full_canvas_height = position + _editor->canvas_timebars_vsize; - _editor->vertical_adjustment.set_upper (_editor->full_canvas_height); - - if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) { - /* - We're increasing the size of the canvas while the bottom is visible. - We scroll down to keep in step with the controls layout. - */ - _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height); - } - - if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) { - _editor->current_session()->sync_order_keys (_order_key); - } -} - -void -EditorRouteList::route_deleted (Gtk::TreeModel::Path const & path) -{ - /* this could require an order reset & sync */ - _editor->current_session()->set_remote_control_ids(); - _ignore_reorder = true; - redisplay (); - _ignore_reorder = false; -} - - -void -EditorRouteList::changed (Gtk::TreeModel::Path const & path, Gtk::TreeModel::iterator const & iter) -{ - /* never reset order keys because of a property change */ - _redisplay_does_not_reset_order_keys = true; - _editor->current_session()->set_remote_control_ids(); - redisplay (); - _redisplay_does_not_reset_order_keys = false; -} - -void -EditorRouteList::routes_added (list routes) -{ - TreeModel::Row row; - - _redisplay_does_not_sync_order_keys = true; - suspend_redisplay (); - - for (list::iterator x = routes.begin(); x != routes.end(); ++x) { - - row = *(_model->append ()); - - row[_columns.text] = (*x)->route()->name(); - row[_columns.visible] = (*x)->marked_for_display(); - row[_columns.tv] = *x; - row[_columns.route] = (*x)->route (); - row[_columns.is_track] = (boost::dynamic_pointer_cast ((*x)->route()) != 0); - - _ignore_reorder = true; - - /* added a new fresh one at the end */ - if ((*x)->route()->order_key(_order_key) == -1) { - (*x)->route()->set_order_key (_order_key, _model->children().size()-1); - } - - _ignore_reorder = false; - - boost::weak_ptr wr ((*x)->route()); - (*x)->route()->gui_changed.connect (mem_fun (*this, &EditorRouteList::handle_gui_changes)); - (*x)->route()->NameChanged.connect (bind (mem_fun (*this, &EditorRouteList::route_name_changed), wr)); - (*x)->GoingAway.connect (bind (mem_fun (*this, &EditorRouteList::route_removed), *x)); - - if ((*x)->is_track()) { - boost::shared_ptr t = boost::dynamic_pointer_cast ((*x)->route()); - t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &EditorRouteList::update_rec_display)); - } - } - - resume_redisplay (); - _redisplay_does_not_sync_order_keys = false; -} - -void -EditorRouteList::handle_gui_changes (string const & what, void *src) -{ - ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRouteList::handle_gui_changes), what, src)); - - if (what == "track_height") { - /* Optional :make tracks change height while it happens, instead - of on first-idle - */ - //update_canvas_now (); - redisplay (); - } - - if (what == "visible_tracks") { - redisplay (); - } -} - -void -EditorRouteList::route_removed (TimeAxisView *tv) -{ - ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRouteList::route_removed), tv)); - - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator ri; - - /* the core model has changed, there is no need to sync - view orders. - */ - - _redisplay_does_not_sync_order_keys = true; - - for (ri = rows.begin(); ri != rows.end(); ++ri) { - if ((*ri)[_columns.tv] == tv) { - _model->erase (ri); - break; - } - } - - _redisplay_does_not_sync_order_keys = false; -} - -void -EditorRouteList::route_name_changed (boost::weak_ptr r) -{ - ENSURE_GUI_THREAD (bind (mem_fun (*this, &EditorRouteList::route_name_changed), r)); - - boost::shared_ptr route = r.lock (); - if (!route) { - return; - } - - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator i; - - for (i = rows.begin(); i != rows.end(); ++i) { - boost::shared_ptr t = (*i)[_columns.route]; - if (t == route) { - (*i)[_columns.text] = route->name(); - break; - } - } -} - -void -EditorRouteList::update_visibility () -{ - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator i; - - suspend_redisplay (); - - for (i = rows.begin(); i != rows.end(); ++i) { - TimeAxisView *tv = (*i)[_columns.tv]; - (*i)[_columns.visible] = tv->marked_for_display (); - cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl; - } - - resume_redisplay (); -} - -void -EditorRouteList::hide_track_in_display (TimeAxisView& tv) -{ - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator i; - - for (i = rows.begin(); i != rows.end(); ++i) { - if ((*i)[_columns.tv] == &tv) { - (*i)[_columns.visible] = false; - break; - } - } -} - -void -EditorRouteList::show_track_in_display (TimeAxisView& tv) -{ - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator i; - - for (i = rows.begin(); i != rows.end(); ++i) { - if ((*i)[_columns.tv] == &tv) { - (*i)[_columns.visible] = true; - break; - } - } -} - -void -EditorRouteList::reordered (TreeModel::Path const & path, TreeModel::iterator const & iter, int* what) -{ - redisplay (); -} - - -void -EditorRouteList::sync_order_keys (char const * src) -{ - vector neworder; - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator ri; - - ARDOUR::Session* s = _editor->current_session (); - - if ((strcmp (src, _order_key) == 0) || !s || (s->state_of_the_state() & Session::Loading) || rows.empty()) { - return; - } - - for (ri = rows.begin(); ri != rows.end(); ++ri) { - neworder.push_back (0); - } - - bool changed = false; - int order; - - for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) { - boost::shared_ptr route = (*ri)[_columns.route]; - - int old_key = order; - int new_key = route->order_key (_order_key); - - neworder[new_key] = old_key; - - if (new_key != old_key) { - changed = true; - } - } - - if (changed) { - _redisplay_does_not_reset_order_keys = true; - _model->reorder (neworder); - _redisplay_does_not_reset_order_keys = false; - } -} - - -void -EditorRouteList::hide_all_tracks (bool with_select) -{ - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator i; - - suspend_redisplay (); - - for (i = rows.begin(); i != rows.end(); ++i) { - - TreeModel::Row row = (*i); - TimeAxisView *tv = row[_columns.tv]; - - if (tv == 0) { - continue; - } - - row[_columns.visible] = false; - } - - resume_redisplay (); - - /* XXX this seems like a hack and half, but its not clear where to put this - otherwise. - */ - - //reset_scrolling_region (); -} - -void -EditorRouteList::set_all_tracks_visibility (bool yn) -{ - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator i; - - suspend_redisplay (); - - for (i = rows.begin(); i != rows.end(); ++i) { - - TreeModel::Row row = (*i); - TimeAxisView* tv = row[_columns.tv]; - - if (tv == 0) { - continue; - } - - (*i)[_columns.visible] = yn; - } - - resume_redisplay (); -} - -void -EditorRouteList::set_all_audio_visibility (int tracks, bool yn) -{ - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator i; - - suspend_redisplay (); - - for (i = rows.begin(); i != rows.end(); ++i) { - TreeModel::Row row = (*i); - TimeAxisView* tv = row[_columns.tv]; - AudioTimeAxisView* atv; - - if (tv == 0) { - continue; - } - - if ((atv = dynamic_cast(tv)) != 0) { - switch (tracks) { - case 0: - (*i)[_columns.visible] = yn; - break; - - case 1: - if (atv->is_audio_track()) { - (*i)[_columns.visible] = yn; - } - break; - - case 2: - if (!atv->is_audio_track()) { - (*i)[_columns.visible] = yn; - } - break; - } - } - } - - resume_redisplay (); -} - -void -EditorRouteList::hide_all_routes () -{ - set_all_tracks_visibility (false); -} - -void -EditorRouteList::show_all_routes () -{ - set_all_tracks_visibility (true); -} - -void -EditorRouteList::show_all_audiobus () -{ - set_all_audio_visibility (2, true); -} -void -EditorRouteList::hide_all_audiobus () -{ - set_all_audio_visibility (2, false); -} - -void -EditorRouteList::show_all_audiotracks() -{ - set_all_audio_visibility (1, true); -} -void -EditorRouteList::hide_all_audiotracks () -{ - set_all_audio_visibility (1, false); -} - -bool -EditorRouteList::button_press (GdkEventButton* ev) -{ - if (Keyboard::is_context_menu_event (ev)) { - show_menu (); - return true; - } - - TreeIter iter; - TreeModel::Path path; - TreeViewColumn* column; - int cellx; - int celly; - - if (!_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) { - return false; - } - - switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) { - - case 0: - /* allow normal processing to occur */ - return false; - case 1: - if ((iter = _model->get_iter (path))) { - TimeAxisView* tv = (*iter)[_columns.tv]; - if (tv) { - bool visible = (*iter)[_columns.visible]; - (*iter)[_columns.visible] = !visible; - } - } - return true; - - case 2: - /* allow normal processing to occur */ - return false; - - default: - break; - } - - return false; -} - -bool -EditorRouteList::selection_filter (Glib::RefPtr const &, TreeModel::Path const &, bool) -{ - return true; -} - -struct EditorOrderRouteSorter { - bool operator() (boost::shared_ptr a, boost::shared_ptr b) { - /* use of ">" forces the correct sort order */ - return a->order_key (_order_key) < b->order_key (_order_key); - } -}; - -void -EditorRouteList::initial_display () -{ - boost::shared_ptr routes = _editor->current_session()->get_routes(); - RouteList r (*routes); - EditorOrderRouteSorter sorter; - - r.sort (sorter); - - suspend_redisplay (); - - _model->clear (); - _editor->handle_new_route (r); - - /* don't show master bus in a new session */ - - if (ARDOUR_UI::instance()->session_is_new ()) { - - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator i; - - _no_redisplay = true; - - for (i = rows.begin(); i != rows.end(); ++i) { - TimeAxisView *tv = (*i)[_columns.tv]; - RouteTimeAxisView *rtv; - - if ((rtv = dynamic_cast(tv)) != 0) { - if (rtv->route()->is_master()) { - _display.get_selection()->unselect (i); - } - } - } - - _no_redisplay = false; - redisplay (); - } - - resume_redisplay (); -} - -void -EditorRouteList::track_list_reorder (Gtk::TreeModel::Path const & path, Gtk::TreeModel::iterator const & iter, int* new_order) -{ - _redisplay_does_not_sync_order_keys = true; - _editor->current_session()->set_remote_control_ids(); - redisplay (); - _redisplay_does_not_sync_order_keys = false; -} - -void -EditorRouteList::display_drag_data_received (const RefPtr& context, - int x, int y, - const SelectionData& data, - guint info, guint time) -{ - if (data.get_target() == "GTK_TREE_MODEL_ROW") { - _display.on_drag_data_received (context, x, y, data, info, time); - return; - } - - context->drag_finish (true, false, time); -} - -void -EditorRouteList::move_selected_tracks (bool up) -{ - if (_editor->selection->tracks.empty()) { - return; - } - - typedef std::pair > ViewRoute; - std::list view_routes; - std::vector neworder; - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator ri; - - for (ri = rows.begin(); ri != rows.end(); ++ri) { - TimeAxisView* tv = (*ri)[_columns.tv]; - boost::shared_ptr route = (*ri)[_columns.route]; - - view_routes.push_back (ViewRoute (tv, route)); - } - - list::iterator trailing; - list::iterator leading; - - if (up) { - - trailing = view_routes.begin(); - leading = view_routes.begin(); - - ++leading; - - while (leading != view_routes.end()) { - if (_editor->selection->selected (leading->first)) { - view_routes.insert (trailing, ViewRoute (leading->first, leading->second)); - leading = view_routes.erase (leading); - } else { - ++leading; - ++trailing; - } - } - - } else { - - /* if we could use reverse_iterator in list::insert, this code - would be a beautiful reflection of the code above. but we can't - and so it looks like a bit of a mess. - */ - - trailing = view_routes.end(); - leading = view_routes.end(); - - --leading; if (leading == view_routes.begin()) { return; } - --leading; - --trailing; - - while (1) { - - if (_editor->selection->selected (leading->first)) { - list::iterator tmp; - - /* need to insert *after* trailing, not *before* it, - which is what insert (iter, val) normally does. - */ - - tmp = trailing; - tmp++; - - view_routes.insert (tmp, ViewRoute (leading->first, leading->second)); - - /* can't use iter = cont.erase (iter); form here, because - we need iter to move backwards. - */ - - tmp = leading; - --tmp; - - bool done = false; - - if (leading == view_routes.begin()) { - /* the one we've just inserted somewhere else - was the first in the list. erase this copy, - and then break, because we're done. - */ - done = true; - } - - view_routes.erase (leading); - - if (done) { - break; - } - - leading = tmp; - - } else { - if (leading == view_routes.begin()) { - break; - } - --leading; - --trailing; - } - }; - } - - for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) { - neworder.push_back (leading->second->order_key (_order_key)); - } - - _model->reorder (neworder); - - _editor->current_session()->sync_order_keys (_order_key); -} - -void -EditorRouteList::update_rec_display () -{ - TreeModel::Children rows = _model->children(); - TreeModel::Children::iterator i; - - for (i = rows.begin(); i != rows.end(); ++i) { - boost::shared_ptr route = (*i)[_columns.route]; - - if (boost::dynamic_pointer_cast(route)) { - - if (route->record_enabled()){ - (*i)[_columns.rec_enabled] = true; - } else { - (*i)[_columns.rec_enabled] = false; - } - } - } -} - -list -EditorRouteList::views () const -{ - list v; - for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) { - v.push_back ((*i)[_columns.tv]); - } - - return v; -} - -void -EditorRouteList::clear () -{ - _display.set_model (Glib::RefPtr (0)); - _model->clear (); - _display.set_model (_model); -} diff --git a/gtk2_ardour/editor_route_list.h b/gtk2_ardour/editor_route_list.h deleted file mode 100644 index 48c9bec019..0000000000 --- a/gtk2_ardour/editor_route_list.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Copyright (C) 2009 Paul Davis - - This program 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. - - This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -class EditorRouteList -{ -public: - EditorRouteList (Editor *); - - Gtk::Widget& widget () { - return _scroller; - } - - void move_selected_tracks (bool); - void initial_display (); - void show_track_in_display (TimeAxisView &); - void suspend_redisplay () { - _no_redisplay = true; - } - void resume_redisplay () { - _no_redisplay = false; - redisplay (); - } - void redisplay (); - void update_visibility (); - void routes_added (std::list routes); - void hide_track_in_display (TimeAxisView &); - std::list views () const; - void hide_all_tracks (bool); - void clear (); - -private: - - void on_tv_rec_enable_toggled (Glib::ustring const &); - void build_menu (); - void show_menu (); - void route_deleted (Gtk::TreeModel::Path const &); - void changed (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &); - void reordered (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int *); - bool button_press (GdkEventButton *); - void route_name_changed (boost::weak_ptr); - void sync_order_keys (char const *); - void route_removed (TimeAxisView *); - void handle_gui_changes (std::string const &, void *); - void update_rec_display (); - void set_all_tracks_visibility (bool); - void set_all_audio_visibility (int, bool); - void show_all_routes (); - void hide_all_routes (); - void show_all_audiotracks (); - void hide_all_audiotracks (); - void show_all_audiobus (); - void hide_all_audiobus (); - void display_drag_data_received ( - Glib::RefPtr const &, gint, gint, Gtk::SelectionData const &, guint, guint - ); - void track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const & iter, int* new_order); - bool selection_filter (Glib::RefPtr const &, Gtk::TreeModel::Path const &, bool); - - struct ModelColumns : public Gtk::TreeModel::ColumnRecord { - ModelColumns() { - add (text); - add (visible); - add (rec_enabled); - add (is_track); - add (tv); - add (route); - } - Gtk::TreeModelColumn text; - Gtk::TreeModelColumn visible; - Gtk::TreeModelColumn rec_enabled; - Gtk::TreeModelColumn is_track; - Gtk::TreeModelColumn tv; - Gtk::TreeModelColumn > route; - }; - - Editor* _editor; - Gtk::ScrolledWindow _scroller; - Gtkmm2ext::DnDTreeView > _display; - Glib::RefPtr _model; - ModelColumns _columns; - bool _ignore_reorder; - bool _no_redisplay; - bool _redisplay_does_not_sync_order_keys; - bool _redisplay_does_not_reset_order_keys; - Gtk::Menu* _menu; -}; diff --git a/gtk2_ardour/editor_routes.cc b/gtk2_ardour/editor_routes.cc new file mode 100644 index 0000000000..23e12b1135 --- /dev/null +++ b/gtk2_ardour/editor_routes.cc @@ -0,0 +1,842 @@ +/* + Copyright (C) 2000-2009 Paul Davis + + This program 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. + + This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "gtkmm2ext/cell_renderer_pixbuf_toggle.h" + +#include "ardour/diskstream.h" + +#include "editor.h" +#include "keyboard.h" +#include "ardour_ui.h" +#include "audio_time_axis.h" +#include "midi_time_axis.h" +#include "mixer_strip.h" +#include "gui_thread.h" +#include "actions.h" +#include "utils.h" +#include "editor_group_tabs.h" +#include "editor_routes.h" + +#include "pbd/unknown_type.h" + +#include "ardour/route.h" + +#include "i18n.h" + +using namespace std; +using namespace sigc; +using namespace ARDOUR; +using namespace PBD; +using namespace Gtk; +using namespace Gtkmm2ext; +using namespace Glib; + +EditorRoutes::EditorRoutes (Editor* e) + : EditorComponent (e), + _ignore_reorder (false), + _no_redisplay (false), + _redisplay_does_not_sync_order_keys (false), + _redisplay_does_not_reset_order_keys (false), + _menu (0) +{ + _scroller.add (_display); + _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC); + + _model = ListStore::create (_columns); + _display.set_model (_model); + + CellRendererPixbufToggle* rec_col_renderer = manage (new CellRendererPixbufToggle()); + + rec_col_renderer->set_active_pixbuf (::get_icon("record_normal_red")); + rec_col_renderer->set_inactive_pixbuf (::get_icon("record_disabled_grey")); + + rec_col_renderer->signal_toggled().connect (mem_fun (*this, &EditorRoutes::on_tv_rec_enable_toggled)); + + Gtk::TreeViewColumn* rec_state_column = manage (new TreeViewColumn("Rec", *rec_col_renderer)); + rec_state_column->add_attribute(rec_col_renderer->property_active(), _columns.rec_enabled); + rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track); + + _display.append_column (*rec_state_column); + _display.append_column (_("Show"), _columns.visible); + _display.append_column (_("Name"), _columns.text); + + _display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0)); + _display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1)); + _display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2)); + + _display.set_headers_visible (true); + _display.set_name ("TrackListDisplay"); + _display.get_selection()->set_mode (SELECTION_NONE); + _display.set_reorderable (true); + _display.set_rules_hint (true); + _display.set_size_request (100, -1); + _display.add_object_drag (_columns.route.index(), "routes"); + + CellRendererToggle* visible_cell = dynamic_cast(_display.get_column_cell_renderer (1)); + + visible_cell->property_activatable() = true; + visible_cell->property_radio() = false; + + _model->signal_row_deleted().connect (mem_fun (*this, &EditorRoutes::route_deleted)); + _model->signal_row_changed().connect (mem_fun (*this, &EditorRoutes::changed)); + _model->signal_rows_reordered().connect (mem_fun (*this, &EditorRoutes::reordered)); + _display.signal_button_press_event().connect (mem_fun (*this, &EditorRoutes::button_press), false); + + Route::SyncOrderKeys.connect (mem_fun (*this, &EditorRoutes::sync_order_keys)); +} + +void +EditorRoutes::on_tv_rec_enable_toggled (Glib::ustring const & path_string) +{ + // Get the model row that has been toggled. + Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string)); + + TimeAxisView *tv = row[_columns.tv]; + AudioTimeAxisView *atv = dynamic_cast (tv); + + if (atv != 0 && atv->is_audio_track()){ + atv->get_diskstream()->set_record_enabled(!atv->get_diskstream()->record_enabled()); + } +} + +void +EditorRoutes::build_menu () +{ + using namespace Menu_Helpers; + using namespace Gtk; + + _menu = new Menu; + + MenuList& items = _menu->items(); + _menu->set_name ("ArdourContextMenu"); + + items.push_back (MenuElem (_("Show All"), mem_fun (*this, &EditorRoutes::show_all_routes))); + items.push_back (MenuElem (_("Hide All"), mem_fun (*this, &EditorRoutes::hide_all_routes))); + items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun (*this, &EditorRoutes::show_all_audiotracks))); + items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun (*this, &EditorRoutes::hide_all_audiotracks))); + items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun (*this, &EditorRoutes::show_all_audiobus))); + items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun (*this, &EditorRoutes::hide_all_audiobus))); + +} + +void +EditorRoutes::show_menu () +{ + if (_menu == 0) { + build_menu (); + } + + _menu->popup (1, gtk_get_current_event_time()); +} + +const char* _order_key = N_("editor"); + +void +EditorRoutes::redisplay () +{ + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator i; + uint32_t position; + int n; + + if (_no_redisplay) { + return; + } + + for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) { + TimeAxisView *tv = (*i)[_columns.tv]; + boost::shared_ptr route = (*i)[_columns.route]; + + if (tv == 0) { + // just a "title" row + continue; + } + + if (!_redisplay_does_not_reset_order_keys) { + + /* this reorder is caused by user action, so reassign sort order keys + to tracks. + */ + + route->set_order_key (_order_key, n); + } + + bool visible = (*i)[_columns.visible]; + + /* show or hide the TimeAxisView */ + if (visible) { + tv->set_marked_for_display (true); + position += tv->show_at (position, n, &_editor->edit_controls_vbox); + tv->clip_to_viewport (); + } else { + tv->set_marked_for_display (false); + tv->hide (); + } + + n++; + } + + /* whenever we go idle, update the track view list to reflect the new order. + we can't do this here, because we could mess up something that is traversing + the track order and has caused a redisplay of the list. + */ + + Glib::signal_idle().connect (mem_fun (*_editor, &Editor::sync_track_view_list_and_routes)); + + _editor->full_canvas_height = position + _editor->canvas_timebars_vsize; + _editor->vertical_adjustment.set_upper (_editor->full_canvas_height); + + if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) { + /* + We're increasing the size of the canvas while the bottom is visible. + We scroll down to keep in step with the controls layout. + */ + _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height); + } + + if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) { + _editor->current_session()->sync_order_keys (_order_key); + } +} + +void +EditorRoutes::route_deleted (Gtk::TreeModel::Path const & path) +{ + /* this could require an order reset & sync */ + _editor->current_session()->set_remote_control_ids(); + _ignore_reorder = true; + redisplay (); + _ignore_reorder = false; +} + + +void +EditorRoutes::changed (Gtk::TreeModel::Path const & path, Gtk::TreeModel::iterator const & iter) +{ + /* never reset order keys because of a property change */ + _redisplay_does_not_reset_order_keys = true; + _editor->current_session()->set_remote_control_ids(); + redisplay (); + _redisplay_does_not_reset_order_keys = false; +} + +void +EditorRoutes::routes_added (list routes) +{ + TreeModel::Row row; + + _redisplay_does_not_sync_order_keys = true; + suspend_redisplay (); + + for (list::iterator x = routes.begin(); x != routes.end(); ++x) { + + row = *(_model->append ()); + + row[_columns.text] = (*x)->route()->name(); + row[_columns.visible] = (*x)->marked_for_display(); + row[_columns.tv] = *x; + row[_columns.route] = (*x)->route (); + row[_columns.is_track] = (boost::dynamic_pointer_cast ((*x)->route()) != 0); + + _ignore_reorder = true; + + /* added a new fresh one at the end */ + if ((*x)->route()->order_key(_order_key) == -1) { + (*x)->route()->set_order_key (_order_key, _model->children().size()-1); + } + + _ignore_reorder = false; + + boost::weak_ptr wr ((*x)->route()); + (*x)->route()->gui_changed.connect (mem_fun (*this, &EditorRoutes::handle_gui_changes)); + (*x)->route()->NameChanged.connect (bind (mem_fun (*this, &EditorRoutes::route_name_changed), wr)); + (*x)->GoingAway.connect (bind (mem_fun (*this, &EditorRoutes::route_removed), *x)); + + if ((*x)->is_track()) { + boost::shared_ptr t = boost::dynamic_pointer_cast ((*x)->route()); + t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &EditorRoutes::update_rec_display)); + } + } + + resume_redisplay (); + _redisplay_does_not_sync_order_keys = false; +} + +void +EditorRoutes::handle_gui_changes (string const & what, void *src) +{ + ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRoutes::handle_gui_changes), what, src)); + + if (what == "track_height") { + /* Optional :make tracks change height while it happens, instead + of on first-idle + */ + //update_canvas_now (); + redisplay (); + } + + if (what == "visible_tracks") { + redisplay (); + } +} + +void +EditorRoutes::route_removed (TimeAxisView *tv) +{ + ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRoutes::route_removed), tv)); + + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator ri; + + /* the core model has changed, there is no need to sync + view orders. + */ + + _redisplay_does_not_sync_order_keys = true; + + for (ri = rows.begin(); ri != rows.end(); ++ri) { + if ((*ri)[_columns.tv] == tv) { + _model->erase (ri); + break; + } + } + + _redisplay_does_not_sync_order_keys = false; +} + +void +EditorRoutes::route_name_changed (boost::weak_ptr r) +{ + ENSURE_GUI_THREAD (bind (mem_fun (*this, &EditorRoutes::route_name_changed), r)); + + boost::shared_ptr route = r.lock (); + if (!route) { + return; + } + + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator i; + + for (i = rows.begin(); i != rows.end(); ++i) { + boost::shared_ptr t = (*i)[_columns.route]; + if (t == route) { + (*i)[_columns.text] = route->name(); + break; + } + } +} + +void +EditorRoutes::update_visibility () +{ + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator i; + + suspend_redisplay (); + + for (i = rows.begin(); i != rows.end(); ++i) { + TimeAxisView *tv = (*i)[_columns.tv]; + (*i)[_columns.visible] = tv->marked_for_display (); + cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl; + } + + resume_redisplay (); +} + +void +EditorRoutes::hide_track_in_display (TimeAxisView& tv) +{ + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator i; + + for (i = rows.begin(); i != rows.end(); ++i) { + if ((*i)[_columns.tv] == &tv) { + (*i)[_columns.visible] = false; + break; + } + } +} + +void +EditorRoutes::show_track_in_display (TimeAxisView& tv) +{ + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator i; + + for (i = rows.begin(); i != rows.end(); ++i) { + if ((*i)[_columns.tv] == &tv) { + (*i)[_columns.visible] = true; + break; + } + } +} + +void +EditorRoutes::reordered (TreeModel::Path const & path, TreeModel::iterator const & iter, int* what) +{ + redisplay (); +} + + +void +EditorRoutes::sync_order_keys (char const * src) +{ + vector neworder; + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator ri; + + ARDOUR::Session* s = _editor->current_session (); + + if ((strcmp (src, _order_key) == 0) || !s || (s->state_of_the_state() & Session::Loading) || rows.empty()) { + return; + } + + for (ri = rows.begin(); ri != rows.end(); ++ri) { + neworder.push_back (0); + } + + bool changed = false; + int order; + + for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) { + boost::shared_ptr route = (*ri)[_columns.route]; + + int old_key = order; + int new_key = route->order_key (_order_key); + + neworder[new_key] = old_key; + + if (new_key != old_key) { + changed = true; + } + } + + if (changed) { + _redisplay_does_not_reset_order_keys = true; + _model->reorder (neworder); + _redisplay_does_not_reset_order_keys = false; + } +} + + +void +EditorRoutes::hide_all_tracks (bool with_select) +{ + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator i; + + suspend_redisplay (); + + for (i = rows.begin(); i != rows.end(); ++i) { + + TreeModel::Row row = (*i); + TimeAxisView *tv = row[_columns.tv]; + + if (tv == 0) { + continue; + } + + row[_columns.visible] = false; + } + + resume_redisplay (); + + /* XXX this seems like a hack and half, but its not clear where to put this + otherwise. + */ + + //reset_scrolling_region (); +} + +void +EditorRoutes::set_all_tracks_visibility (bool yn) +{ + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator i; + + suspend_redisplay (); + + for (i = rows.begin(); i != rows.end(); ++i) { + + TreeModel::Row row = (*i); + TimeAxisView* tv = row[_columns.tv]; + + if (tv == 0) { + continue; + } + + (*i)[_columns.visible] = yn; + } + + resume_redisplay (); +} + +void +EditorRoutes::set_all_audio_visibility (int tracks, bool yn) +{ + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator i; + + suspend_redisplay (); + + for (i = rows.begin(); i != rows.end(); ++i) { + TreeModel::Row row = (*i); + TimeAxisView* tv = row[_columns.tv]; + AudioTimeAxisView* atv; + + if (tv == 0) { + continue; + } + + if ((atv = dynamic_cast(tv)) != 0) { + switch (tracks) { + case 0: + (*i)[_columns.visible] = yn; + break; + + case 1: + if (atv->is_audio_track()) { + (*i)[_columns.visible] = yn; + } + break; + + case 2: + if (!atv->is_audio_track()) { + (*i)[_columns.visible] = yn; + } + break; + } + } + } + + resume_redisplay (); +} + +void +EditorRoutes::hide_all_routes () +{ + set_all_tracks_visibility (false); +} + +void +EditorRoutes::show_all_routes () +{ + set_all_tracks_visibility (true); +} + +void +EditorRoutes::show_all_audiobus () +{ + set_all_audio_visibility (2, true); +} +void +EditorRoutes::hide_all_audiobus () +{ + set_all_audio_visibility (2, false); +} + +void +EditorRoutes::show_all_audiotracks() +{ + set_all_audio_visibility (1, true); +} +void +EditorRoutes::hide_all_audiotracks () +{ + set_all_audio_visibility (1, false); +} + +bool +EditorRoutes::button_press (GdkEventButton* ev) +{ + if (Keyboard::is_context_menu_event (ev)) { + show_menu (); + return true; + } + + TreeIter iter; + TreeModel::Path path; + TreeViewColumn* column; + int cellx; + int celly; + + if (!_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) { + return false; + } + + switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) { + + case 0: + /* allow normal processing to occur */ + return false; + case 1: + if ((iter = _model->get_iter (path))) { + TimeAxisView* tv = (*iter)[_columns.tv]; + if (tv) { + bool visible = (*iter)[_columns.visible]; + (*iter)[_columns.visible] = !visible; + } + } + return true; + + case 2: + /* allow normal processing to occur */ + return false; + + default: + break; + } + + return false; +} + +bool +EditorRoutes::selection_filter (Glib::RefPtr const &, TreeModel::Path const &, bool) +{ + return true; +} + +struct EditorOrderRouteSorter { + bool operator() (boost::shared_ptr a, boost::shared_ptr b) { + /* use of ">" forces the correct sort order */ + return a->order_key (_order_key) < b->order_key (_order_key); + } +}; + +void +EditorRoutes::initial_display () +{ + boost::shared_ptr routes = _editor->current_session()->get_routes(); + RouteList r (*routes); + EditorOrderRouteSorter sorter; + + r.sort (sorter); + + suspend_redisplay (); + + _model->clear (); + _editor->handle_new_route (r); + + /* don't show master bus in a new session */ + + if (ARDOUR_UI::instance()->session_is_new ()) { + + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator i; + + _no_redisplay = true; + + for (i = rows.begin(); i != rows.end(); ++i) { + TimeAxisView *tv = (*i)[_columns.tv]; + RouteTimeAxisView *rtv; + + if ((rtv = dynamic_cast(tv)) != 0) { + if (rtv->route()->is_master()) { + _display.get_selection()->unselect (i); + } + } + } + + _no_redisplay = false; + redisplay (); + } + + resume_redisplay (); +} + +void +EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const & path, Gtk::TreeModel::iterator const & iter, int* new_order) +{ + _redisplay_does_not_sync_order_keys = true; + _editor->current_session()->set_remote_control_ids(); + redisplay (); + _redisplay_does_not_sync_order_keys = false; +} + +void +EditorRoutes::display_drag_data_received (const RefPtr& context, + int x, int y, + const SelectionData& data, + guint info, guint time) +{ + if (data.get_target() == "GTK_TREE_MODEL_ROW") { + _display.on_drag_data_received (context, x, y, data, info, time); + return; + } + + context->drag_finish (true, false, time); +} + +void +EditorRoutes::move_selected_tracks (bool up) +{ + if (_editor->selection->tracks.empty()) { + return; + } + + typedef std::pair > ViewRoute; + std::list view_routes; + std::vector neworder; + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator ri; + + for (ri = rows.begin(); ri != rows.end(); ++ri) { + TimeAxisView* tv = (*ri)[_columns.tv]; + boost::shared_ptr route = (*ri)[_columns.route]; + + view_routes.push_back (ViewRoute (tv, route)); + } + + list::iterator trailing; + list::iterator leading; + + if (up) { + + trailing = view_routes.begin(); + leading = view_routes.begin(); + + ++leading; + + while (leading != view_routes.end()) { + if (_editor->selection->selected (leading->first)) { + view_routes.insert (trailing, ViewRoute (leading->first, leading->second)); + leading = view_routes.erase (leading); + } else { + ++leading; + ++trailing; + } + } + + } else { + + /* if we could use reverse_iterator in list::insert, this code + would be a beautiful reflection of the code above. but we can't + and so it looks like a bit of a mess. + */ + + trailing = view_routes.end(); + leading = view_routes.end(); + + --leading; if (leading == view_routes.begin()) { return; } + --leading; + --trailing; + + while (1) { + + if (_editor->selection->selected (leading->first)) { + list::iterator tmp; + + /* need to insert *after* trailing, not *before* it, + which is what insert (iter, val) normally does. + */ + + tmp = trailing; + tmp++; + + view_routes.insert (tmp, ViewRoute (leading->first, leading->second)); + + /* can't use iter = cont.erase (iter); form here, because + we need iter to move backwards. + */ + + tmp = leading; + --tmp; + + bool done = false; + + if (leading == view_routes.begin()) { + /* the one we've just inserted somewhere else + was the first in the list. erase this copy, + and then break, because we're done. + */ + done = true; + } + + view_routes.erase (leading); + + if (done) { + break; + } + + leading = tmp; + + } else { + if (leading == view_routes.begin()) { + break; + } + --leading; + --trailing; + } + }; + } + + for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) { + neworder.push_back (leading->second->order_key (_order_key)); + } + + _model->reorder (neworder); + + _editor->current_session()->sync_order_keys (_order_key); +} + +void +EditorRoutes::update_rec_display () +{ + TreeModel::Children rows = _model->children(); + TreeModel::Children::iterator i; + + for (i = rows.begin(); i != rows.end(); ++i) { + boost::shared_ptr route = (*i)[_columns.route]; + + if (boost::dynamic_pointer_cast(route)) { + + if (route->record_enabled()){ + (*i)[_columns.rec_enabled] = true; + } else { + (*i)[_columns.rec_enabled] = false; + } + } + } +} + +list +EditorRoutes::views () const +{ + list v; + for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) { + v.push_back ((*i)[_columns.tv]); + } + + return v; +} + +void +EditorRoutes::clear () +{ + _display.set_model (Glib::RefPtr (0)); + _model->clear (); + _display.set_model (_model); +} diff --git a/gtk2_ardour/editor_routes.h b/gtk2_ardour/editor_routes.h new file mode 100644 index 0000000000..b493b0a905 --- /dev/null +++ b/gtk2_ardour/editor_routes.h @@ -0,0 +1,101 @@ +/* + Copyright (C) 2009 Paul Davis + + This program 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. + + This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +class EditorRoutes : public EditorComponent +{ +public: + EditorRoutes (Editor *); + + Gtk::Widget& widget () { + return _scroller; + } + + void move_selected_tracks (bool); + void initial_display (); + void show_track_in_display (TimeAxisView &); + void suspend_redisplay () { + _no_redisplay = true; + } + void resume_redisplay () { + _no_redisplay = false; + redisplay (); + } + void redisplay (); + void update_visibility (); + void routes_added (std::list routes); + void hide_track_in_display (TimeAxisView &); + std::list views () const; + void hide_all_tracks (bool); + void clear (); + +private: + + void on_tv_rec_enable_toggled (Glib::ustring const &); + void build_menu (); + void show_menu (); + void route_deleted (Gtk::TreeModel::Path const &); + void changed (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &); + void reordered (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int *); + bool button_press (GdkEventButton *); + void route_name_changed (boost::weak_ptr); + void sync_order_keys (char const *); + void route_removed (TimeAxisView *); + void handle_gui_changes (std::string const &, void *); + void update_rec_display (); + void set_all_tracks_visibility (bool); + void set_all_audio_visibility (int, bool); + void show_all_routes (); + void hide_all_routes (); + void show_all_audiotracks (); + void hide_all_audiotracks (); + void show_all_audiobus (); + void hide_all_audiobus (); + void display_drag_data_received ( + Glib::RefPtr const &, gint, gint, Gtk::SelectionData const &, guint, guint + ); + void track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const & iter, int* new_order); + bool selection_filter (Glib::RefPtr const &, Gtk::TreeModel::Path const &, bool); + + struct ModelColumns : public Gtk::TreeModel::ColumnRecord { + ModelColumns() { + add (text); + add (visible); + add (rec_enabled); + add (is_track); + add (tv); + add (route); + } + Gtk::TreeModelColumn text; + Gtk::TreeModelColumn visible; + Gtk::TreeModelColumn rec_enabled; + Gtk::TreeModelColumn is_track; + Gtk::TreeModelColumn tv; + Gtk::TreeModelColumn > route; + }; + + Gtk::ScrolledWindow _scroller; + Gtkmm2ext::DnDTreeView > _display; + Glib::RefPtr _model; + ModelColumns _columns; + bool _ignore_reorder; + bool _no_redisplay; + bool _redisplay_does_not_sync_order_keys; + bool _redisplay_does_not_reset_order_keys; + Gtk::Menu* _menu; +}; diff --git a/gtk2_ardour/editor_summary.cc b/gtk2_ardour/editor_summary.cc index b7ae937a40..a9cc524b15 100644 --- a/gtk2_ardour/editor_summary.cc +++ b/gtk2_ardour/editor_summary.cc @@ -35,8 +35,7 @@ using namespace ARDOUR; * @param e Editor to represent. */ EditorSummary::EditorSummary (Editor* e) - : _editor (e), - _session (0), + : EditorComponent (e), _x_scale (1), _y_scale (1), _last_playhead (-1), @@ -48,19 +47,19 @@ EditorSummary::EditorSummary (Editor* e) } -/** Set the session. +/** Connect to a session. * @param s Session. */ void -EditorSummary::set_session (Session* s) +EditorSummary::connect_to_session (Session* s) { - _session = s; + EditorComponent::connect_to_session (s); Region::RegionPropertyChanged.connect (sigc::hide (mem_fun (*this, &EditorSummary::set_dirty))); - _session->RegionRemoved.connect (sigc::hide (mem_fun (*this, &EditorSummary::set_dirty))); - _session->EndTimeChanged.connect (mem_fun (*this, &EditorSummary::set_dirty)); - _session->StartTimeChanged.connect (mem_fun (*this, &EditorSummary::set_dirty)); + _session_connections.push_back (_session->RegionRemoved.connect (sigc::hide (mem_fun (*this, &EditorSummary::set_dirty)))); + _session_connections.push_back (_session->EndTimeChanged.connect (mem_fun (*this, &EditorSummary::set_dirty))); + _session_connections.push_back (_session->StartTimeChanged.connect (mem_fun (*this, &EditorSummary::set_dirty))); _editor->playhead_cursor->PositionChanged.connect (mem_fun (*this, &EditorSummary::playhead_position_changed)); set_dirty (); diff --git a/gtk2_ardour/editor_summary.h b/gtk2_ardour/editor_summary.h index 1d68e3b793..96d20fffa6 100644 --- a/gtk2_ardour/editor_summary.h +++ b/gtk2_ardour/editor_summary.h @@ -21,6 +21,7 @@ #define __gtk_ardour_editor_summary_h__ #include "cairo_widget.h" +#include "editor_component.h" namespace ARDOUR { class Session; @@ -31,12 +32,12 @@ class Editor; /** Class to provide a visual summary of the contents of an editor window; represents * the whole session as a set of lines, one per region view. */ -class EditorSummary : public CairoWidget +class EditorSummary : public CairoWidget, public EditorComponent { public: EditorSummary (Editor *); - void set_session (ARDOUR::Session *); + void connect_to_session (ARDOUR::Session *); void set_overlays_dirty (); private: @@ -54,8 +55,6 @@ private: void set_editor (std::pair const &, std::pair const &); void playhead_position_changed (nframes64_t); - Editor* _editor; ///< our editor - ARDOUR::Session* _session; ///< our session double _x_scale; ///< pixels per frame for the x axis of the pixmap double _y_scale; double _last_playhead; diff --git a/gtk2_ardour/group_tabs.cc b/gtk2_ardour/group_tabs.cc index 03554f72eb..995d41dfef 100644 --- a/gtk2_ardour/group_tabs.cc +++ b/gtk2_ardour/group_tabs.cc @@ -29,18 +29,19 @@ using namespace std; using namespace Gtk; using namespace ARDOUR; -GroupTabs::GroupTabs () - : _session (0), +GroupTabs::GroupTabs (Editor* e) + : EditorComponent (e), _dragging (0) { } void -GroupTabs::set_session (Session* s) +GroupTabs::connect_to_session (Session* s) { - _session = s; - s->RouteGroupChanged.connect (mem_fun (*this, &GroupTabs::set_dirty)); + EditorComponent::connect_to_session (s); + + _session_connections.push_back (_session->RouteGroupChanged.connect (mem_fun (*this, &GroupTabs::set_dirty))); } diff --git a/gtk2_ardour/group_tabs.h b/gtk2_ardour/group_tabs.h index c4ea5f1f31..2cff160426 100644 --- a/gtk2_ardour/group_tabs.h +++ b/gtk2_ardour/group_tabs.h @@ -18,6 +18,7 @@ */ #include +#include "editor_component.h" #include "cairo_widget.h" namespace ARDOUR { @@ -30,12 +31,12 @@ class Editor; /** Parent class for tabs which represent route groups as coloured tabs; * Currently used on the left-hand side of the editor and at the top of the mixer. */ -class GroupTabs : public CairoWidget +class GroupTabs : public CairoWidget, public EditorComponent { public: - GroupTabs (); + GroupTabs (Editor *); - void set_session (ARDOUR::Session *); + void connect_to_session (ARDOUR::Session *); protected: @@ -48,8 +49,6 @@ protected: double last_ui_size; ///< GUI size of the last route in the group }; - ARDOUR::Session* _session; ///< our session - private: /** Compute all the tabs for this widget. * @return Tabs. diff --git a/gtk2_ardour/mixer_group_tabs.cc b/gtk2_ardour/mixer_group_tabs.cc index 566671f027..aaaefae17d 100644 --- a/gtk2_ardour/mixer_group_tabs.cc +++ b/gtk2_ardour/mixer_group_tabs.cc @@ -31,7 +31,8 @@ using namespace Gtk; using namespace ARDOUR; MixerGroupTabs::MixerGroupTabs (Mixer_UI* m) - : _mixer (m), + : GroupTabs (0), + _mixer (m), _menu (0) { diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc index 156947a709..d43bd92401 100644 --- a/gtk2_ardour/mixer_ui.cc +++ b/gtk2_ardour/mixer_ui.cc @@ -486,7 +486,7 @@ Mixer_UI::connect_to_session (Session* sess) show_window(); } - _group_tabs->set_session (sess); + _group_tabs->connect_to_session (sess); start_updating (); } diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index accc7cdd72..3adac59e09 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -103,9 +103,10 @@ def build(bld): editor_audiotrack.cc editor_canvas.cc editor_canvas_events.cc + editor_component.cc editor_cursors.cc editor_drag.cc - editor_edit_groups.cc + editor_route_groups.cc editor_export_audio.cc editor_group_tabs.cc editor_hscroller.cc @@ -117,7 +118,7 @@ def build(bld): editor_nudge.cc editor_ops.cc editor_region_list.cc - editor_route_list.cc + editor_routes.cc editor_rulers.cc editor_scrub.cc editor_selection.cc -- cgit v1.2.3