#include "pbd/convert.h"
#include "pbd/unwind.h"
-#include <glibmm/thread.h>
+#include <glibmm/threads.h>
#include <gtkmm2ext/gtk_ui.h>
#include <gtkmm2ext/utils.h>
#include <gtkmm2ext/window_title.h>
#include "ardour/debug.h"
+#include "ardour/midi_track.h"
#include "ardour/plugin_manager.h"
#include "ardour/route_group.h"
#include "ardour/session.h"
#include "ardour_ui.h"
#include "prompter.h"
#include "utils.h"
+#include "route_sorter.h"
#include "actions.h"
#include "gui_thread.h"
#include "mixer_group_tabs.h"
Mixer_UI::Mixer_UI ()
: Window (Gtk::WINDOW_TOPLEVEL)
+ , VisibilityTracker (*((Gtk::Window*) this))
, _visible (false)
, no_track_list_redisplay (false)
, in_group_row_change (false)
/* allow this window to become the key focus window */
set_flags (CAN_FOCUS);
- Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_order_keys, this, _1), gui_context());
+ Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_order_keys, this), gui_context());
+
+ scroller.set_can_default (true);
+ set_default (scroller);
scroller_base.set_flags (Gtk::CAN_FOCUS);
scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
group_display.get_column (0)->set_expand(true);
group_display.get_column (1)->set_expand(false);
- group_display.set_name ("LHSList");
+ group_display.set_name ("EditGroupList");
group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
group_display.set_reorderable (true);
group_display.set_headers_visible (true);
group_display.show();
_in_group_rebuild_or_clear = false;
+ _maximised = false;
MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context());
void
Mixer_UI::add_strips (RouteList& routes)
{
+ bool from_scratch = track_model->children().size() == 0;
+ Gtk::TreeModel::Children::iterator insert_iter = track_model->children().end();
+
+ for (Gtk::TreeModel::Children::iterator it = track_model->children().begin(); it != track_model->children().end(); ++it) {
+ boost::shared_ptr<Route> r = (*it)[track_columns.route];
+
+ if (r->order_key() == (routes.front()->order_key() + routes.size())) {
+ insert_iter = it;
+ break;
+ }
+ }
+
+ if(!from_scratch) {
+ _selection.clear_routes ();
+ }
+
MixerStrip* strip;
- {
- Unwinder<bool> uw (no_track_list_redisplay, true);
-
+ try {
+ no_track_list_redisplay = true;
+ track_display.set_model (Glib::RefPtr<ListStore>());
+
for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
boost::shared_ptr<Route> route = (*x);
- if (route->is_hidden()) {
+ if (route->is_auditioner()) {
continue;
}
strip = new MixerStrip (*this, _session, route);
strips.push_back (strip);
-
+
Config->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
if (strip->width_owner() != strip) {
show_strip (strip);
- TreeModel::Row row = *(track_model->append());
+ TreeModel::Row row = *(track_model->insert(insert_iter));
row[track_columns.text] = route->name();
row[track_columns.visible] = strip->route()->is_master() ? true : strip->marked_for_display();
row[track_columns.route] = route;
row[track_columns.strip] = strip;
+
+ if (!from_scratch) {
+ _selection.add (strip);
+ }
route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
}
+
+ } catch (...) {
}
+ no_track_list_redisplay = false;
+ track_display.set_model (track_model);
+
sync_order_keys_from_treeview ();
redisplay_track_list ();
}
void
Mixer_UI::reset_remote_control_ids ()
{
- if (Config->get_remote_model() != MixerOrdered || !_session || _session->deletion_in_progress()) {
+ if (Config->get_remote_model() == UserOrdered || !_session || _session->deletion_in_progress()) {
return;
}
uint32_t new_rid = (visible ? rid : invisible_key--);
if (new_rid != route->remote_control_id()) {
- route->set_remote_control_id_from_order_key (MixerSort, new_rid);
+ route->set_remote_control_id_explicit (new_rid);
rid_change = true;
}
boost::shared_ptr<Route> route = (*ri)[track_columns.route];
bool visible = (*ri)[track_columns.visible];
- uint32_t old_key = route->order_key (MixerSort);
+ uint32_t old_key = route->order_key ();
if (order != old_key) {
- route->set_order_key (MixerSort, order);
+ route->set_order_key (order);
changed = true;
}
uint32_t new_rid = (visible ? rid : invisible_key--);
if (new_rid != route->remote_control_id()) {
- route->set_remote_control_id_from_order_key (MixerSort, new_rid);
+ route->set_remote_control_id_explicit (new_rid);
rid_change = true;
}
if (changed) {
/* tell everyone that we changed the mixer sort keys */
- _session->sync_order_keys (MixerSort);
+ _session->sync_order_keys ();
}
if (rid_change) {
}
void
-Mixer_UI::sync_treeview_from_order_keys (RouteSortOrderKey src)
+Mixer_UI::sync_treeview_from_order_keys ()
{
if (!_session || _session->deletion_in_progress()) {
return;
}
- DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("mixer sync model from order keys, src = %1\n", enum_2_string (src)));
-
- if (src == EditorSort) {
-
- if (!Config->get_sync_all_route_ordering()) {
- /* editor sort keys changed - we don't care */
- return;
- }
-
- DEBUG_TRACE (DEBUG::OrderKeys, "reset mixer order key to match editor\n");
-
- /* editor sort keys were changed, update the mixer sort
- * keys since "sync mixer+editor order" is enabled.
- */
-
- boost::shared_ptr<RouteList> r = _session->get_routes ();
-
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- (*i)->sync_order_keys (src);
- }
- }
+ DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync model from order keys.\n");
/* we could get here after either a change in the Mixer or Editor sort
* order, but either way, the mixer order keys reflect the intended
return;
}
- neworder.assign (rows.size(), 0);
-
+ OrderKeySortedRoutes sorted_routes;
+
for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
boost::shared_ptr<Route> route = (*ri)[track_columns.route];
- uint32_t new_order = route->order_key (MixerSort);
+ sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key ()));
+ }
- neworder[new_order] = old_order;
+ SortByNewDisplayOrder cmp;
- if (old_order != new_order) {
+ sort (sorted_routes.begin(), sorted_routes.end(), cmp);
+ neworder.assign (sorted_routes.size(), 0);
+
+ uint32_t n = 0;
+
+ for (OrderKeySortedRoutes::iterator sr = sorted_routes.begin(); sr != sorted_routes.end(); ++sr, ++n) {
+
+ neworder[n] = sr->old_display_order;
+
+ if (sr->old_display_order != n) {
changed = true;
}
DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("MIXER change order for %1 from %2 to %3\n",
- route->name(), old_order, new_order));
+ sr->route->name(), sr->old_display_order, n));
}
if (changed) {
/* everything comes before b */
return true;
}
- return a->order_key (MixerSort) < b->order_key (MixerSort);
+ return a->order_key () < b->order_key ();
}
};
add_strips (copy);
}
- _session->sync_order_keys (MixerSort);
+ _session->sync_order_keys ();
redisplay_track_list ();
}
}
void
-Mixer_UI::set_strip_width (Width w)
+Mixer_UI::set_strip_width (Width w, bool save)
{
_strip_width = w;
for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
- (*i)->set_width_enum (w, this);
+ (*i)->set_width_enum (w, save ? (*i)->width_owner() : this);
}
}
}
}
+ if ((prop = node.property ("maximised"))) {
+ bool yn = string_is_affirmative (prop->value());
+ Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalMixer"));
+ assert (act);
+ Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
+ bool fs = tact && tact->get_active();
+ if (yn ^ fs) {
+ ActionManager::do_action ("Common",
+ "ToggleMaximalMixer");
+ }
+ }
+
+
return 0;
}
node->add_property ("show-mixer", _visible ? "yes" : "no");
+ node->add_property ("maximised", _maximised ? "yes" : "no");
+
return *node;
}
void
Mixer_UI::scroll_left ()
{
+ if (!scroller.get_hscrollbar()) return;
Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
/* stupid GTK: can't rely on clamping across versions */
scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
void
Mixer_UI::scroll_right ()
{
+ if (!scroller.get_hscrollbar()) return;
Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
/* stupid GTK: can't rely on clamping across versions */
scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
track_display.get_column (0)->set_expand(true);
track_display.get_column (1)->set_expand(false);
- track_display.set_name (X_("LHSList"));
+ track_display.set_name (X_("EditGroupList"));
track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
track_display.set_reorderable (true);
track_display.set_headers_visible (true);
return;
}
- /* try to get mixer strip at mouse */
+ /* nothing selected ... try to get mixer strip at mouse */
int x, y;
get_pointer (x, y);
_monitor_section->set_session (0);
}
}
+
+void
+Mixer_UI::toggle_midi_input_active (bool flip_others)
+{
+ boost::shared_ptr<RouteList> rl (new RouteList);
+ bool onoff = false;
+
+ set_route_targets_for_operation ();
+
+ for (RouteUISelection::iterator r = _route_targets.begin(); r != _route_targets.end(); ++r) {
+ boost::shared_ptr<MidiTrack> mt = (*r)->midi_track();
+
+ if (mt) {
+ rl->push_back ((*r)->route());
+ onoff = !mt->input_active();
+ }
+ }
+
+ _session->set_exclusive_input_active (rl, onoff, flip_others);
+}
+
+void
+Mixer_UI::maximise_mixer_space ()
+{
+ if (_maximised) {
+ return;
+ }
+
+ fullscreen ();
+
+ _maximised = true;
+}
+
+void
+Mixer_UI::restore_mixer_space ()
+{
+ if (!_maximised) {
+ return;
+ }
+
+ unfullscreen();
+
+ _maximised = false;
+}