From: Paul Davis Date: Thu, 9 Mar 2006 23:44:39 +0000 (+0000) Subject: new mix group interface, not yet finished and still to propagate to edit_group X-Git-Tag: 2.0beta4~363 X-Git-Url: https://main.carlh.net/gitweb/?p=ardour.git;a=commitdiff_plain;h=8ca43d57fea4e10e20b331f13132dfd9721911a1 new mix group interface, not yet finished and still to propagate to edit_group git-svn-id: svn://localhost/trunk/ardour2@366 d708f5d6-7413-0410-9779-e7cbd77b26cf --- diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 4667cd45a2..dce87f5e1c 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -147,61 +147,6 @@ Gdk::Cursor* Editor::speaker_cursor = 0; Gdk::Cursor* Editor::wait_cursor = 0; Gdk::Cursor* Editor::timebar_cursor = 0; -bool -Editor::on_key_press_event (GdkEventKey* ev) -{ - GtkWindow* win = gobj(); - - /* This exists to allow us to override the way GTK handles - key events. The normal sequence is: - - a) event is delivered to a GtkWindow - b) accelerators/mnemonics are activated - c) if (b) didn't handle the event, propagate to - the focus widget and/or focus chain - - The problem with this is that if the accelerators include - keys without modifiers, such as the space bar or the - letter "e", then pressing the key while typing into - a text entry widget results in the accelerator being - activated, instead of the desired letter appearing - in the text entry. - - There is no good way of fixing this, but this - represents a compromise. The idea is that - key events involving modifiers (not Shift) - get routed into the activation pathway first, then - get propagated to the focus widget if necessary. - - If the key event doesn't involve modifiers, - we deliver to the focus widget first, thus allowing - it to get "normal text" without interference - from acceleration. - - Of course, this can also be problematic: if there - is a widget with focus, then it will swallow - all "normal text" accelerators. - */ - - if (ev->state & ~Gdk::SHIFT_MASK) { - /* modifiers in effect, accelerate first */ - if (!gtk_window_activate_key (win, ev)) { - return gtk_window_propagate_key_event (win, ev); - } else { - return true; - } - } - - /* no modifiers, propagate first */ - - if (!gtk_window_propagate_key_event (win, ev)) { - return gtk_window_activate_key (win, ev); - } - - - return true; -} - void show_me_the_size (Requisition* r, const char* what) { @@ -348,6 +293,7 @@ Editor::Editor (AudioEngine& eng) clear_entered_track = false; _new_regionviews_show_envelope = false; current_timestretch = 0; + in_edit_group_row_change = false; edit_cursor = 0; playhead_cursor = 0; @@ -563,6 +509,11 @@ Editor::Editor (AudioEngine& eng) active_cell->property_activatable() = true; active_cell->property_radio() = false; + /* name is directly editable */ + + CellRendererText* name_cell = dynamic_cast(edit_group_display.get_column_cell_renderer (2)); + name_cell->property_editable() = true; + edit_group_display.set_name ("EditGroupList"); group_model->signal_row_changed().connect (mem_fun (*this, &Editor::edit_group_row_change)); @@ -580,8 +531,9 @@ Editor::Editor (AudioEngine& eng) VBox* edit_group_display_packer = manage (new VBox()); HButtonBox* edit_group_display_button_box = manage (new HButtonBox()); - Button* edit_group_add_button = manage (new Button ("+")); - Button* edit_group_remove_button = manage (new Button("-")); + edit_group_display_button_box->set_homogeneous (true); + Button* edit_group_add_button = manage (new Button (Stock::ADD)); + Button* edit_group_remove_button = manage (new Button(Stock::REMOVE)); edit_group_add_button->signal_clicked().connect (mem_fun (*this, &Editor::new_edit_group)); edit_group_remove_button->signal_clicked().connect (mem_fun (*this, &Editor::remove_selected_edit_group)); @@ -4115,3 +4067,10 @@ Editor::mapped_clear_playlist (AudioTimeAxisView& atv, uint32_t sz) { atv.clear_playlist (); } + +bool +Editor::on_key_press_event (GdkEventKey* ev) +{ + return key_press_focus_accelerator_handler (*this, ev); +} + diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index f5cdcce900..956720747f 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1514,6 +1514,7 @@ class Editor : public PublicEditor void activate_all_edit_groups (); void disable_all_edit_groups (); + bool in_edit_group_row_change; void edit_group_row_change (const Gtk::TreeModel::Path&,const Gtk::TreeModel::iterator&); void new_edit_group (); diff --git a/gtk2_ardour/editor_edit_groups.cc b/gtk2_ardour/editor_edit_groups.cc index 49d6b13a0f..2e7179d940 100644 --- a/gtk2_ardour/editor_edit_groups.cc +++ b/gtk2_ardour/editor_edit_groups.cc @@ -192,6 +192,10 @@ Editor::edit_group_row_change (const Gtk::TreeModel::Path& path,const Gtk::TreeM { RouteGroup* group; + if (in_edit_group_row_change) { + return; + } + if ((group = (*iter)[group_columns.routegroup]) == 0) { return; } @@ -212,6 +216,15 @@ Editor::edit_group_row_change (const Gtk::TreeModel::Path& path,const Gtk::TreeM bool active = (*iter)[group_columns.is_active]; group->set_active (active, this); + + + string name = (*iter)[group_columns.text]; + + cerr << "Row change, name = " << name << endl; + + if (name != group->name()) { + group->set_name (name); + } } void @@ -221,7 +234,7 @@ Editor::add_edit_group (RouteGroup* group) TreeModel::Row row = *(group_model->append()); row[group_columns.is_active] = group->is_active(); - row[group_columns.is_visible] = true; + row[group_columns.is_visible] = !group->is_hidden(); row[group_columns.text] = group->name(); row[group_columns.routegroup] = group; @@ -256,12 +269,18 @@ Editor::group_flags_changed (void* src, RouteGroup* group) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::group_flags_changed), src, group)); + in_edit_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_active] = group->is_active(); + (*iter)[group_columns.is_visible] = !group->is_hidden(); + (*iter)[group_columns.text] = group->name(); } } + + in_edit_group_row_change = false; } diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index 65b0051eaf..e4d023e3a8 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -1440,3 +1440,9 @@ MixerStrip::route_active_changed () gpm.set_fader_name ("AudioBusFader"); } } + +RouteGroup* +MixerStrip::mix_group() const +{ + return _route.mix_group(); +} diff --git a/gtk2_ardour/mixer_strip.h b/gtk2_ardour/mixer_strip.h index 8945de21bb..1e18d42646 100644 --- a/gtk2_ardour/mixer_strip.h +++ b/gtk2_ardour/mixer_strip.h @@ -93,6 +93,8 @@ class MixerStrip : public RouteUI, public Gtk::EventBox void fast_update (); void set_embedded (bool); + ARDOUR::RouteGroup* mix_group() const; + protected: friend class Mixer_UI; void set_packed (bool yn); diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc index 0fd6b07a62..98e9a6c41c 100644 --- a/gtk2_ardour/mixer_ui.cc +++ b/gtk2_ardour/mixer_ui.cc @@ -59,7 +59,9 @@ Mixer_UI::Mixer_UI (AudioEngine& eng) { _strip_width = Wide; track_menu = 0; + mix_group_context_menu = 0; no_track_list_redisplay = false; + in_group_row_change = false; XMLNode* node = ARDOUR_UI::instance()->mixer_settings(); set_state (*node); @@ -73,10 +75,10 @@ Mixer_UI::Mixer_UI (AudioEngine& eng) scroller.add (strip_packer); scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); - track_display_model = ListStore::create (track_display_columns); - track_display.set_model (track_display_model); - track_display.append_column (_("Strips"), track_display_columns.text); - track_display.append_column (_("Visible"), track_display_columns.visible); + track_model = ListStore::create (track_columns); + track_display.set_model (track_model); + track_display.append_column (_("Strips"), track_columns.text); + track_display.append_column (_("Visible"), track_columns.visible); track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0)); track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1)); track_display.set_name (X_("MixerTrackDisplayList")); @@ -85,8 +87,8 @@ Mixer_UI::Mixer_UI (AudioEngine& eng) track_display.set_size_request (100, -1); track_display.set_headers_visible (true); - track_display_model->signal_row_deleted().connect (mem_fun (*this, &Mixer_UI::track_list_delete)); - track_display_model->signal_row_changed().connect (mem_fun (*this, &Mixer_UI::track_list_change)); + track_model->signal_row_deleted().connect (mem_fun (*this, &Mixer_UI::track_list_delete)); + track_model->signal_row_changed().connect (mem_fun (*this, &Mixer_UI::track_list_change)); CellRendererToggle* track_list_visible_cell = dynamic_cast(track_display.get_column_cell_renderer (1)); track_list_visible_cell->property_activatable() = true; @@ -97,18 +99,27 @@ Mixer_UI::Mixer_UI (AudioEngine& eng) track_display_scroller.add (track_display); track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - group_display_model = ListStore::create (group_display_columns); - group_display.set_model (group_display_model); - group_display.append_column (_("groupname"), group_display_columns.text); - group_display.append_column (_("active"), group_display_columns.active); + group_model = ListStore::create (group_columns); + group_display.set_model (group_model); + group_display.append_column (_("groupname"), group_columns.text); + group_display.append_column (_("active"), group_columns.active); + group_display.append_column (_("visible"), group_columns.visible); group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0)); group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1)); + group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2)); group_display.set_name ("MixerGroupList"); - group_display.get_selection()->set_mode (Gtk::SELECTION_NONE); + group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE); group_display.set_reorderable (true); group_display.set_size_request (150, -1); group_display.set_headers_visible (true); group_display.set_headers_clickable (false); + group_display.set_rules_hint (true); + + /* name is directly editable */ + + CellRendererText* name_cell = dynamic_cast(group_display.get_column_cell_renderer (0)); + name_cell->property_editable() = true; + name_cell->signal_edited().connect (mem_fun (*this, &Mixer_UI::mix_group_name_edit)); /* use checkbox for the active column */ @@ -116,22 +127,32 @@ Mixer_UI::Mixer_UI (AudioEngine& eng) active_cell->property_activatable() = true; active_cell->property_radio() = false; + /* use checkbox for the visible column */ + + active_cell = dynamic_cast(group_display.get_column_cell_renderer (2)); + active_cell->property_activatable() = true; + active_cell->property_radio() = false; + + group_model->signal_row_changed().connect (mem_fun (*this, &Mixer_UI::mix_group_row_change)); + group_display.signal_button_press_event().connect (mem_fun (*this, &Mixer_UI::group_display_button_press), false); - group_display.get_selection()->signal_changed().connect (mem_fun (*this, &Mixer_UI::group_display_selection_changed)); group_display_scroller.add (group_display); group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - group_display_button_label.set_name ("NewMixGroupLabel"); - group_display_button_label.set_text (_("New Mix Group")); - group_display_button.add (group_display_button_label); - group_display_button.set_name ("NewMixGroup"); - ARDOUR_UI::instance()->tooltips().set_tip (group_display_button, _("add a new mix group")); - group_display_button.signal_clicked().connect (mem_fun (*this, &Mixer_UI::new_mix_group)); + HButtonBox* mix_group_display_button_box = manage (new HButtonBox()); + mix_group_display_button_box->set_homogeneous (true); + Button* mix_group_add_button = manage (new Button (Stock::ADD)); + Button* mix_group_remove_button = manage (new Button (Stock::REMOVE)); + mix_group_add_button->signal_clicked().connect (mem_fun (*this, &Mixer_UI::new_mix_group)); + mix_group_remove_button->signal_clicked().connect (mem_fun (*this, &Mixer_UI::remove_selected_mix_group)); + + mix_group_display_button_box->pack_start (*mix_group_add_button); + mix_group_display_button_box->pack_start (*mix_group_remove_button); - group_display_vbox.pack_start (group_display_button, false, false); group_display_vbox.pack_start (group_display_scroller, true, true); + group_display_vbox.pack_start (*mix_group_display_button_box, false, false); track_display_frame.set_name("BaseFrame"); track_display_frame.set_shadow_type (Gtk::SHADOW_IN); @@ -201,11 +222,11 @@ Mixer_UI::show_window () /* now reset each strips width so the right widgets are shown */ MixerStrip* ms; - TreeModel::Children rows = track_display_model->children(); + TreeModel::Children rows = track_model->children(); TreeModel::Children::iterator ri; for (ri = rows.begin(); ri != rows.end(); ++ri) { - ms = (*ri)[track_display_columns.strip]; + ms = (*ri)[track_columns.strip]; ms->set_width (ms->get_width()); } } @@ -229,12 +250,12 @@ Mixer_UI::add_strip (Route* route) no_track_list_redisplay = true; - TreeModel::Row row = *(track_display_model->append()); - row[track_display_columns.text] = route->name(); + TreeModel::Row row = *(track_model->append()); + row[track_columns.text] = route->name(); - row[track_display_columns.visible] = true; - row[track_display_columns.route] = route; - row[track_display_columns.strip] = strip; + row[track_columns.visible] = true; + row[track_columns.route] = route; + row[track_columns.strip] = strip; no_track_list_redisplay = false; redisplay_track_list (); @@ -250,7 +271,7 @@ Mixer_UI::remove_strip (MixerStrip* strip) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::remove_strip), strip)); - TreeModel::Children rows = track_display_model->children(); + TreeModel::Children rows = track_model->children(); TreeModel::Children::iterator ri; list::iterator i; @@ -259,8 +280,8 @@ Mixer_UI::remove_strip (MixerStrip* strip) } for (ri = rows.begin(); ri != rows.end(); ++ri) { - if ((*ri)[track_display_columns.strip] == strip) { - track_display_model->erase (ri); + if ((*ri)[track_columns.strip] == strip) { + track_model->erase (ri); break; } } @@ -312,8 +333,9 @@ Mixer_UI::connect_to_session (Session* sess) session->going_away.connect (mem_fun(*this, &Mixer_UI::disconnect_from_session)); session->RouteAdded.connect (mem_fun(*this, &Mixer_UI::add_strip)); session->mix_group_added.connect (mem_fun(*this, &Mixer_UI::add_mix_group)); + session->mix_group_removed.connect (mem_fun(*this, &Mixer_UI::mix_groups_changed)); - session->foreach_mix_group (mem_fun (*this, &Mixer_UI::add_mix_group)); + mix_groups_changed (); _plugin_selector->set_session (session); @@ -325,7 +347,7 @@ Mixer_UI::disconnect_from_session () { ENSURE_GUI_THREAD(mem_fun(*this, &Mixer_UI::disconnect_from_session)); - group_display_model->clear (); + group_model->clear (); set_title (_("ardour: mixer")); stop_updating (); } @@ -333,14 +355,14 @@ Mixer_UI::disconnect_from_session () void Mixer_UI::show_strip (MixerStrip* ms) { - TreeModel::Children rows = track_display_model->children(); + TreeModel::Children rows = track_model->children(); TreeModel::Children::iterator i; for (i = rows.begin(); i != rows.end(); ++i) { - MixerStrip* strip = (*i)[track_display_columns.strip]; + MixerStrip* strip = (*i)[track_columns.strip]; if (strip == ms) { - (*i)[track_display_columns.visible] = true; + (*i)[track_columns.visible] = true; break; } } @@ -349,14 +371,14 @@ Mixer_UI::show_strip (MixerStrip* ms) void Mixer_UI::hide_strip (MixerStrip* ms) { - TreeModel::Children rows = track_display_model->children(); + TreeModel::Children rows = track_model->children(); TreeModel::Children::iterator i; for (i = rows.begin(); i != rows.end(); ++i) { - MixerStrip* strip = (*i)[track_display_columns.strip]; + MixerStrip* strip = (*i)[track_columns.strip]; if (strip == ms) { - (*i)[track_display_columns.visible] = false; + (*i)[track_columns.visible] = false; break; } } @@ -401,7 +423,7 @@ Mixer_UI::hide_strip (MixerStrip* ms) void Mixer_UI::set_all_strips_visibility (bool yn) { - TreeModel::Children rows = track_display_model->children(); + TreeModel::Children rows = track_model->children(); TreeModel::Children::iterator i; no_track_list_redisplay = true; @@ -409,7 +431,7 @@ Mixer_UI::set_all_strips_visibility (bool yn) for (i = rows.begin(); i != rows.end(); ++i) { TreeModel::Row row = (*i); - MixerStrip* strip = row[track_display_columns.strip]; + MixerStrip* strip = row[track_columns.strip]; if (strip == 0) { continue; @@ -419,7 +441,7 @@ Mixer_UI::set_all_strips_visibility (bool yn) continue; } - (*i)[track_display_columns.visible] = yn; + (*i)[track_columns.visible] = yn; } no_track_list_redisplay = false; @@ -430,14 +452,14 @@ Mixer_UI::set_all_strips_visibility (bool yn) void Mixer_UI::set_all_audio_visibility (int tracks, bool yn) { - TreeModel::Children rows = track_display_model->children(); + TreeModel::Children rows = track_model->children(); TreeModel::Children::iterator i; no_track_list_redisplay = true; for (i = rows.begin(); i != rows.end(); ++i) { TreeModel::Row row = (*i); - MixerStrip* strip = row[track_display_columns.strip]; + MixerStrip* strip = row[track_columns.strip]; if (strip == 0) { continue; @@ -451,18 +473,18 @@ Mixer_UI::set_all_audio_visibility (int tracks, bool yn) switch (tracks) { case 0: - (*i)[track_display_columns.visible] = yn; + (*i)[track_columns.visible] = yn; break; case 1: if (at) { /* track */ - (*i)[track_display_columns.visible] = yn; + (*i)[track_columns.visible] = yn; } break; case 2: if (!at) { /* bus */ - (*i)[track_display_columns.visible] = yn; + (*i)[track_columns.visible] = yn; } break; } @@ -521,7 +543,7 @@ Mixer_UI::track_list_delete (const Gtk::TreeModel::Path& path) void Mixer_UI::redisplay_track_list () { - TreeModel::Children rows = track_display_model->children(); + TreeModel::Children rows = track_model->children(); TreeModel::Children::iterator i; long order; @@ -530,15 +552,14 @@ Mixer_UI::redisplay_track_list () } for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) { - MixerStrip* strip = (*i)[track_display_columns.strip]; + MixerStrip* strip = (*i)[track_columns.strip]; if (strip == 0) { - cerr << "row with text = " << (*i)[track_display_columns.text] << " has no strip\n"; /* we're in the middle of changing a row, don't worry */ continue; } - bool visible = (*i)[track_display_columns.visible]; + bool visible = (*i)[track_columns.visible]; if (visible) { strip->set_marked_for_display (true); @@ -592,7 +613,7 @@ Mixer_UI::initial_track_display () no_track_list_redisplay = true; - track_display_model->clear (); + track_model->clear (); for (Session::RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { add_strip (*i); @@ -638,13 +659,13 @@ Mixer_UI::track_display_button_press (GdkEventButton* ev) case 1: /* visibility */ - if ((iter = track_display_model->get_iter (path))) { - MixerStrip* strip = (*iter)[track_display_columns.strip]; + if ((iter = track_model->get_iter (path))) { + MixerStrip* strip = (*iter)[track_columns.strip]; if (strip) { if (!strip->route().master() && !strip->route().control()) { - bool visible = (*iter)[track_display_columns.visible]; - (*iter)[track_display_columns.visible] = !visible; + bool visible = (*iter)[track_columns.visible]; + (*iter)[track_columns.visible] = !visible; } } } @@ -682,12 +703,12 @@ Mixer_UI::strip_name_changed (void* src, MixerStrip* mx) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::strip_name_changed), src, mx)); - TreeModel::Children rows = track_display_model->children(); + TreeModel::Children rows = track_model->children(); TreeModel::Children::iterator i; for (i = rows.begin(); i != rows.end(); ++i) { - if ((*i)[track_display_columns.strip] == mx) { - (*i)[track_display_columns.text] = mx->route().name(); + if ((*i)[track_columns.strip] == mx) { + (*i)[track_columns.text] = mx->route().name(); return; } } @@ -695,30 +716,36 @@ Mixer_UI::strip_name_changed (void* src, MixerStrip* mx) error << _("track display list item for renamed strip not found!") << endmsg; } + void -Mixer_UI::new_mix_group () +Mixer_UI::build_mix_group_context_menu () { - ArdourPrompter prompter; - string result; + using namespace Gtk::Menu_Helpers; - prompter.set_prompt (_("Name for new mix group")); - prompter.show_all (); + mix_group_context_menu = new Menu; + mix_group_context_menu->set_name ("ArdourContextMenu"); + MenuList& items = mix_group_context_menu->items(); + + items.push_back (MenuElem (_("Activate All"), mem_fun(*this, &Mixer_UI::activate_all_mix_groups))); + items.push_back (MenuElem (_("Disable All"), mem_fun(*this, &Mixer_UI::disable_all_mix_groups))); + items.push_back (SeparatorElem()); + items.push_back (MenuElem (_("Add group"), mem_fun(*this, &Mixer_UI::new_mix_group))); - switch (prompter.run ()) { - case Gtk::RESPONSE_ACCEPT: - prompter.get_result (result); - if (result.length()) { - session->add_mix_group (result); - } - break; - } } bool Mixer_UI::group_display_button_press (GdkEventButton* ev) { - RouteGroup* group; + if (Keyboard::is_context_menu_event (ev)) { + if (mix_group_context_menu == 0) { + build_mix_group_context_menu (); + } + mix_group_context_menu->popup (1, 0); + return true; + } + + RouteGroup* group; TreeIter iter; TreeModel::Path path; TreeViewColumn* column; @@ -728,73 +755,214 @@ Mixer_UI::group_display_button_press (GdkEventButton* ev) if (!group_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: if (Keyboard::is_edit_event (ev)) { - // RouteGroup* group = (RouteGroup *) group_display.row(row).get_data (); - // edit_mix_group (group); - - } else { - /* allow regular select to occur */ - return false; - } + if ((iter = group_model->get_iter (path))) { + if ((group = (*iter)[group_columns.group]) != 0) { + // edit_mix_group (group); + return true; + } + } + + } break; case 1: - /* active column click */ + if ((iter = group_model->get_iter (path))) { + bool active = (*iter)[group_columns.active]; + (*iter)[group_columns.active] = !active; + return true; + } + break; - if ((iter = group_display_model->get_iter (path))) { - /* path points to a valid node */ - if ((group = (*iter)[group_display_columns.group]) != 0) { - group->set_active (!group->is_active (), this); - (*iter)[group_display_columns.active] = group->is_active (); - } + case 2: + if ((iter = group_model->get_iter (path))) { + bool visible = (*iter)[group_columns.visible]; + (*iter)[group_columns.visible] = !visible; + return true; } break; + default: + break; + } + + return false; + } + +void +Mixer_UI::activate_all_mix_groups () +{ + Gtk::TreeModel::Children children = group_model->children(); + for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) { + (*iter)[group_columns.active] = true; } - - return true; } void -Mixer_UI::group_display_selection_changed () +Mixer_UI::disable_all_mix_groups () +{ + Gtk::TreeModel::Children children = group_model->children(); + for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) { + (*iter)[group_columns.active] = false; + } +} + +void +Mixer_UI::mix_groups_changed () +{ + ENSURE_GUI_THREAD (mem_fun (*this, &Mixer_UI::mix_groups_changed)); + + /* just rebuild the while thing */ + + group_display.set_model (Glib::RefPtr(0)); + group_model->clear (); + + { + TreeModel::Row row; + row = *(group_model->append()); + row[group_columns.active] = false; + row[group_columns.visible] = true; + row[group_columns.text] = (_("-all-")); + row[group_columns.group] = 0; + } + + session->foreach_mix_group (mem_fun (*this, &Mixer_UI::add_mix_group)); + group_display.set_model (group_model); +} + + +void +Mixer_UI::new_mix_group () +{ +#if 0 + ArdourPrompter prompter; + string result; + + prompter.set_prompt (_("Name for new mix group")); + prompter.show_all (); + + switch (prompter.run ()) { + case Gtk::RESPONSE_ACCEPT: + prompter.get_result (result); + if (result.length()) { + session->add_mix_group (result); + } + break; + } +#else + session->add_mix_group ("unnamed"); +#endif + +} + +void +Mixer_UI::remove_selected_mix_group () { - TreeModel::iterator i; - TreeModel::Children rows = group_display_model->children(); Glib::RefPtr selection = group_display.get_selection(); + TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows (); - for (i = rows.begin(); i != rows.end(); ++i) { - RouteGroup* group; + if (rows.empty()) { + return; + } - group = (*i)[group_display_columns.group]; + TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); + TreeIter iter; + + /* selection mode is single, so rows.begin() is it */ - if (selection->is_selected (i)) { - group->set_hidden (true, this); - } else { - group->set_hidden (true, this); + if ((iter = group_model->get_iter (*i))) { + + RouteGroup* rg = (*iter)[group_columns.group]; + + if (rg) { + session->remove_mix_group (*rg); } } - - redisplay_track_list (); } void Mixer_UI::group_flags_changed (void* src, RouteGroup* group) { + if (in_group_row_change) { + return; + } + ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::group_flags_changed), src, group)); TreeModel::iterator i; - TreeModel::Children rows = group_display_model->children(); + TreeModel::Children rows = group_model->children(); Glib::RefPtr selection = group_display.get_selection(); + + in_group_row_change = true; for (i = rows.begin(); i != rows.end(); ++i) { - if ((*i)[group_display_columns.group] == group) { - (*i)[group_display_columns.visible] = group->is_hidden (); + if ((*i)[group_columns.group] == group) { + (*i)[group_columns.visible] = !group->is_hidden (); + (*i)[group_columns.active] = group->is_active (); + (*i)[group_columns.text] = group->name (); break; } } + + in_group_row_change = false; +} + +void +Mixer_UI::mix_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.group]) == 0) { + return; + } + + if (new_text != group->name()) { + group->set_name (new_text); + } + } +} + +void +Mixer_UI::mix_group_row_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter) +{ + RouteGroup* group; + + if (in_group_row_change) { + return; + } + + if ((group = (*iter)[group_columns.group]) == 0) { + return; + } + + if ((*iter)[group_columns.visible]) { + for (list::iterator i = strips.begin(); i != strips.end(); ++i) { + if ((*i)->mix_group() == group) { + show_strip (*i); + } + } + } else { + for (list::iterator i = strips.begin(); i != strips.end(); ++i) { + if ((*i)->mix_group() == group) { + hide_strip (*i); + } + } + } + + bool active = (*iter)[group_columns.active]; + group->set_active (active, this); + + Glib::ustring name = (*iter)[group_columns.text]; + + if (name != group->name()) { + group->set_name (name); + } } void @@ -803,11 +971,11 @@ Mixer_UI::add_mix_group (RouteGroup* group) { ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::add_mix_group), group)); - TreeModel::Row row = *(group_display_model->append()); - row[group_display_columns.active] = group->is_active(); - row[group_display_columns.visible] = true; - row[group_display_columns.text] = group->name(); - row[group_display_columns.group] = group; + TreeModel::Row row = *(group_model->append()); + row[group_columns.active] = group->is_active(); + row[group_columns.visible] = true; + row[group_columns.text] = group->name(); + row[group_columns.group] = group; group->FlagsChanged.connect (bind (mem_fun(*this, &Mixer_UI::group_flags_changed), group)); } @@ -975,3 +1143,8 @@ Mixer_UI::pane_allocation_handler (Allocation& alloc, Gtk::Paned* which) } } +bool +Mixer_UI::on_key_press_event (GdkEventKey* ev) +{ + return key_press_focus_accelerator_handler (*this, ev); +} diff --git a/gtk2_ardour/mixer_ui.h b/gtk2_ardour/mixer_ui.h index 256757a97c..853304095f 100644 --- a/gtk2_ardour/mixer_ui.h +++ b/gtk2_ardour/mixer_ui.h @@ -102,6 +102,8 @@ class Mixer_UI : public Gtk::Window Gtk::HBox out_packer; Gtk::HPaned list_hpane; + bool on_key_press_event (GdkEventKey*); + void pane_allocation_handler (Gtk::Allocation&, Gtk::Paned*); list strips; @@ -156,11 +158,21 @@ class Mixer_UI : public Gtk::Window void show_all_audiotracks(); void hide_all_audiotracks (); + Gtk::Menu* mix_group_context_menu; + bool in_group_row_change; + void group_selected (gint row, gint col, GdkEvent *ev); void group_unselected (gint row, gint col, GdkEvent *ev); void group_display_active_clicked(); void new_mix_group (); + void remove_selected_mix_group (); + void build_mix_group_context_menu (); + void activate_all_mix_groups (); + void disable_all_mix_groups (); void add_mix_group (ARDOUR::RouteGroup *); + void mix_groups_changed (); + void mix_group_name_edit (const Glib::ustring&, const Glib::ustring&); + void mix_group_row_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter); Gtk::Menu *track_menu; void track_column_click (gint); @@ -200,14 +212,14 @@ class Mixer_UI : public Gtk::Window Gtk::TreeModelColumn group; }; - TrackDisplayModelColumns track_display_columns; - GroupDisplayModelColumns group_display_columns; + TrackDisplayModelColumns track_columns; + GroupDisplayModelColumns group_columns; Gtk::TreeView track_display; Gtk::TreeView group_display; - Glib::RefPtr track_display_model; - Glib::RefPtr group_display_model; + Glib::RefPtr track_model; + Glib::RefPtr group_model; bool group_display_button_press (GdkEventButton*); void group_display_selection_changed (); diff --git a/gtk2_ardour/utils.cc b/gtk2_ardour/utils.cc index 393f919d95..efb15a4d52 100644 --- a/gtk2_ardour/utils.cc +++ b/gtk2_ardour/utils.cc @@ -506,3 +506,59 @@ set_color (Gdk::Color& c, int rgb) { c.set_rgb((rgb >> 16)*256, ((rgb & 0xff00) >> 8)*256, (rgb & 0xff)*256); } + +bool +key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev) +{ + GtkWindow* win = window.gobj(); + + /* This exists to allow us to override the way GTK handles + key events. The normal sequence is: + + a) event is delivered to a GtkWindow + b) accelerators/mnemonics are activated + c) if (b) didn't handle the event, propagate to + the focus widget and/or focus chain + + The problem with this is that if the accelerators include + keys without modifiers, such as the space bar or the + letter "e", then pressing the key while typing into + a text entry widget results in the accelerator being + activated, instead of the desired letter appearing + in the text entry. + + There is no good way of fixing this, but this + represents a compromise. The idea is that + key events involving modifiers (not Shift) + get routed into the activation pathway first, then + get propagated to the focus widget if necessary. + + If the key event doesn't involve modifiers, + we deliver to the focus widget first, thus allowing + it to get "normal text" without interference + from acceleration. + + Of course, this can also be problematic: if there + is a widget with focus, then it will swallow + all "normal text" accelerators. + */ + + if (ev->state & ~Gdk::SHIFT_MASK) { + /* modifiers in effect, accelerate first */ + if (!gtk_window_activate_key (win, ev)) { + return gtk_window_propagate_key_event (win, ev); + } else { + return true; + } + } + + /* no modifiers, propagate first */ + + if (!gtk_window_propagate_key_event (win, ev)) { + return gtk_window_activate_key (win, ev); + } + + + return true; +} + diff --git a/gtk2_ardour/utils.h b/gtk2_ardour/utils.h index b607ebdb64..68cd16c779 100644 --- a/gtk2_ardour/utils.h +++ b/gtk2_ardour/utils.h @@ -75,4 +75,6 @@ bool canvas_item_visible (ArdourCanvas::Item* item); void set_color (Gdk::Color&, int); +bool key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev); + #endif /* __ardour_gtk_utils_h__ */ diff --git a/libs/ardour/ardour/route_group.h b/libs/ardour/ardour/route_group.h index f5c55e184f..c9f966666f 100644 --- a/libs/ardour/ardour/route_group.h +++ b/libs/ardour/ardour/route_group.h @@ -36,6 +36,7 @@ namespace ARDOUR { class Route; class AudioTrack; +class Session; class RouteGroup : public Stateful, public sigc::trackable { public: @@ -45,18 +46,19 @@ class RouteGroup : public Stateful, public sigc::trackable { Hidden = 0x4, }; - RouteGroup(const string &n, Flag f = Flag(0)) : _name (n), _flags (f) {} + RouteGroup (Session& s, const string &n, Flag f = Flag(0)); const string& name() { return _name; } + void set_name (std::string str); bool is_active () const { return _flags & Active; } bool is_relative () const { return _flags & Relative; } bool is_hidden () const { return _flags & Hidden; } bool empty() const {return routes.empty();} - gain_t get_max_factor(gain_t factor); - gain_t get_min_factor(gain_t factor); - + gain_t get_max_factor(gain_t factor); + gain_t get_min_factor(gain_t factor); + int size() { return routes.size();} ARDOUR::Route * first () const { return *routes.begin();} @@ -64,7 +66,6 @@ class RouteGroup : public Stateful, public sigc::trackable { void set_relative (bool yn, void *src); void set_hidden (bool yn, void *src); - int add (Route *); int remove (Route *); @@ -110,6 +111,7 @@ class RouteGroup : public Stateful, public sigc::trackable { int set_state (const XMLNode&); private: + Session& _session; list routes; string _name; uint32_t _flags; diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc index 3d40483634..b9d4972277 100644 --- a/libs/ardour/route_group.cc +++ b/libs/ardour/route_group.cc @@ -34,13 +34,28 @@ using namespace ARDOUR; using namespace sigc; +using namespace std; + +RouteGroup::RouteGroup (Session& s, const string &n, Flag f) + : _session (s), _name (n), _flags (f) +{ +} + +void +RouteGroup::set_name (string str) +{ + _name = str; + _session.set_dirty (); + FlagsChanged (0); /* EMIT SIGNAL */ +} int RouteGroup::add (Route *r) { routes.push_back (r); r->GoingAway.connect (sigc::bind (mem_fun (*this, &RouteGroup::remove_when_going_away), r)); - changed (); /* EMIT SIGNAL */ + _session.set_dirty (); + changed (); /* EMIT SIGNAL */ return 0; } @@ -57,7 +72,8 @@ RouteGroup::remove (Route *r) if ((i = find (routes.begin(), routes.end(), r)) != routes.end()) { routes.erase (i); - changed (); /* EMIT SIGNAL */ + _session.set_dirty (); + changed (); /* EMIT SIGNAL */ return 0; } return -1; @@ -145,7 +161,8 @@ RouteGroup::set_active (bool yn, void *src) } else { _flags &= ~Active; } - FlagsChanged (src); /* EMIT SIGNAL */ + _session.set_dirty (); + FlagsChanged (src); /* EMIT SIGNAL */ } void @@ -160,7 +177,8 @@ RouteGroup::set_relative (bool yn, void *src) } else { _flags &= ~Relative; } - FlagsChanged (src); /* EMIT SIGNAL */ + _session.set_dirty (); + FlagsChanged (src); /* EMIT SIGNAL */ } void @@ -181,7 +199,8 @@ RouteGroup::set_hidden (bool yn, void *src) _flags |= Active; } } - FlagsChanged (src); /* EMIT SIGNAL */ + _session.set_dirty (); + FlagsChanged (src); /* EMIT SIGNAL */ } void diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 731184e8d9..8c34386495 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -2398,7 +2398,7 @@ Session::auto_save() RouteGroup * Session::add_edit_group (string name) { - RouteGroup* rg = new RouteGroup (name); + RouteGroup* rg = new RouteGroup (*this, name); edit_groups.push_back (rg); edit_group_added (rg); /* EMIT SIGNAL */ set_dirty(); @@ -2408,7 +2408,7 @@ Session::add_edit_group (string name) RouteGroup * Session::add_mix_group (string name) { - RouteGroup* rg = new RouteGroup (name, RouteGroup::Relative); + RouteGroup* rg = new RouteGroup (*this, name, RouteGroup::Relative); mix_groups.push_back (rg); mix_group_added (rg); /* EMIT SIGNAL */ set_dirty();