diff --git a/gtk2_ardour/editor_group_tabs.cc b/gtk2_ardour/editor_group_tabs.cc index 61f3c50735..7776254833 100644 --- a/gtk2_ardour/editor_group_tabs.cc +++ b/gtk2_ardour/editor_group_tabs.cc @@ -54,14 +54,12 @@ EditorGroupTabs::compute_tabs () const if (g != tab.group) { if (tab.group) { tab.to = y; - tab.last_ui_size = (*i)->effective_height (); tabs.push_back (tab); } tab.from = y; tab.group = g; tab.colour = (*i)->color (); - tab.first_ui_size = (*i)->effective_height (); } y += (*i)->effective_height (); @@ -80,12 +78,12 @@ EditorGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const { double const arc_radius = _width; - if (tab.group->is_active()) { + if (tab.group && tab.group->is_active()) { cairo_set_source_rgba (cr, tab.colour.get_red_p (), tab.colour.get_green_p (), tab.colour.get_blue_p (), 1); } else { cairo_set_source_rgba (cr, 1, 1, 1, 0.2); } - + cairo_move_to (cr, 0, tab.from + arc_radius); cairo_arc (cr, _width, tab.from + arc_radius, arc_radius, M_PI, 3 * M_PI / 2); cairo_line_to (cr, _width, tab.to); @@ -93,17 +91,19 @@ EditorGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const cairo_line_to (cr, 0, tab.from + arc_radius); cairo_fill (cr); - pair const f = fit_to_pixels (cr, tab.group->name(), tab.to - tab.from - arc_radius * 2); - - cairo_text_extents_t ext; - cairo_text_extents (cr, tab.group->name().c_str(), &ext); - - cairo_set_source_rgb (cr, 1, 1, 1); - cairo_move_to (cr, _width - ext.height / 2, tab.from + (f.second + tab.to - tab.from) / 2); - cairo_save (cr); - cairo_rotate (cr, - M_PI / 2); - cairo_show_text (cr, f.first.c_str()); - cairo_restore (cr); + if (tab.group) { + pair const f = fit_to_pixels (cr, tab.group->name(), tab.to - tab.from - arc_radius * 2); + + cairo_text_extents_t ext; + cairo_text_extents (cr, tab.group->name().c_str(), &ext); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_move_to (cr, _width - ext.height / 2, tab.from + (f.second + tab.to - tab.from) / 2); + cairo_save (cr); + cairo_rotate (cr, - M_PI / 2); + cairo_show_text (cr, f.first.c_str()); + cairo_restore (cr); + } } double @@ -112,12 +112,12 @@ EditorGroupTabs::primary_coordinate (double, double y) const return y; } -void -EditorGroupTabs::reflect_tabs (list const & tabs) +RouteList +EditorGroupTabs::routes_for_tab (Tab const * t) const { - list::const_iterator j = tabs.begin (); - + RouteList routes; int32_t y = 0; + for (Editor::TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) { if ((*i)->marked_for_display() == false) { @@ -127,31 +127,22 @@ EditorGroupTabs::reflect_tabs (list const & tabs) RouteTimeAxisView* rtv = dynamic_cast (*i); if (rtv) { - if (j == tabs.end()) { + if (y >= t->to) { + /* tab finishes before this track starts */ + break; + } - /* already run out of tabs, so no edit group */ - rtv->route()->set_route_group (0, this); - - } else { - - if (y >= j->to) { - /* this tab finishes before this track starts, so onto the next tab */ - ++j; - } - - double const h = y + (*i)->effective_height() / 2; - - if (j->from < h && j->to > h) { - rtv->route()->set_route_group (j->group, this); - } else { - rtv->route()->set_route_group (0, this); - } + double const h = y + (*i)->effective_height() / 2; + if (t->from < h && t->to > h) { + routes.push_back (rtv->route ()); } } y += (*i)->effective_height (); } + + return routes; } @@ -160,3 +151,9 @@ EditorGroupTabs::get_menu (RouteGroup *g) { return _editor->_route_groups->menu (g); } + +ARDOUR::RouteGroup * +EditorGroupTabs::new_route_group () const +{ + return _editor->_route_groups->new_route_group (); +} diff --git a/gtk2_ardour/editor_group_tabs.h b/gtk2_ardour/editor_group_tabs.h index 2d1abcf46f..4dc447da17 100644 --- a/gtk2_ardour/editor_group_tabs.h +++ b/gtk2_ardour/editor_group_tabs.h @@ -31,9 +31,10 @@ private: std::list compute_tabs () const; void draw_tab (cairo_t *, Tab const &) const; double primary_coordinate (double, double) const; - void reflect_tabs (std::list const &); + ARDOUR::RouteList routes_for_tab (Tab const *) const; double extent () const { return _height; } Gtk::Menu* get_menu (ARDOUR::RouteGroup* g); + ARDOUR::RouteGroup* new_route_group () const; }; diff --git a/gtk2_ardour/editor_route_groups.cc b/gtk2_ardour/editor_route_groups.cc index 2a07ca89c1..1a2fb35f9e 100644 --- a/gtk2_ardour/editor_route_groups.cc +++ b/gtk2_ardour/editor_route_groups.cc @@ -154,7 +154,7 @@ EditorRouteGroups::EditorRouteGroups (Editor* e) w->show(); remove_button->add (*w); - add_button->signal_clicked().connect (mem_fun (*this, &EditorRouteGroups::new_route_group)); + add_button->signal_clicked().connect (hide_return (mem_fun (*this, &EditorRouteGroups::new_route_group))); remove_button->signal_clicked().connect (mem_fun (*this, &EditorRouteGroups::remove_selected)); button_box->pack_start (*add_button); @@ -182,7 +182,7 @@ EditorRouteGroups::menu (RouteGroup* g) _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..."), hide_return (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))); @@ -231,8 +231,8 @@ EditorRouteGroups::set_activation (RouteGroup* g, bool a) g->set_active (a, this); } -void -EditorRouteGroups::new_route_group () +ARDOUR::RouteGroup * +EditorRouteGroups::new_route_group () const { RouteGroup* g = new RouteGroup ( *_session, @@ -244,13 +244,14 @@ EditorRouteGroups::new_route_group () RouteGroupDialog d (g, Gtk::Stock::NEW); int const r = d.do_run (); - if (r == Gtk::RESPONSE_OK) { - _session->add_route_group (g); - } else { + if (r != Gtk::RESPONSE_OK) { delete g; + return 0; } + + _session->add_route_group (g); + return g; } - void EditorRouteGroups::run_new_group_dialog (const RouteList& rl) { diff --git a/gtk2_ardour/editor_route_groups.h b/gtk2_ardour/editor_route_groups.h index 3c93b96ed4..b1b82fb531 100644 --- a/gtk2_ardour/editor_route_groups.h +++ b/gtk2_ardour/editor_route_groups.h @@ -33,6 +33,7 @@ public: Gtk::Menu* menu (ARDOUR::RouteGroup *); void clear (); + ARDOUR::RouteGroup* new_route_group () const; private: @@ -71,7 +72,6 @@ private: 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 (); diff --git a/gtk2_ardour/group_tabs.cc b/gtk2_ardour/group_tabs.cc index 60b32520fe..9a10adf554 100644 --- a/gtk2_ardour/group_tabs.cc +++ b/gtk2_ardour/group_tabs.cc @@ -20,6 +20,7 @@ #include #include "ardour/session.h" #include "ardour/route_group.h" +#include "ardour/route.h" #include "route_group_dialog.h" #include "group_tabs.h" #include "keyboard.h" @@ -31,7 +32,8 @@ using namespace ARDOUR; GroupTabs::GroupTabs (Editor* e) : EditorComponent (e), - _dragging (0) + _dragging (0), + _dragging_new_tab (0) { } @@ -63,25 +65,45 @@ GroupTabs::on_button_press_event (GdkEventButton* ev) double const p = primary_coordinate (ev->x, ev->y); - Tab* prev; - Tab* next; + list::iterator prev; + list::iterator next; Tab* t = click_to_tab (p, &prev, &next); - if (ev->button == 1 && t) { + _drag_min = prev != _tabs.end() ? prev->to : 0; + _drag_max = next != _tabs.end() ? next->from : extent (); + + if (ev->button == 1) { + + if (t == 0) { + Tab n; + n.from = n.to = p; + _dragging_new_tab = true; + + if (next == _tabs.end()) { + _tabs.push_back (n); + t = &_tabs.back (); + } else { + list::iterator j = _tabs.insert (next, n); + t = &(*j); + } + + } else { + _dragging_new_tab = false; + } _dragging = t; _drag_moved = false; - _drag_last = p; + _drag_first = p; double const h = (t->from + t->to) / 2; - _drag_from = p < h; - - if (_drag_from) { - /* limit is the end of the previous tab */ - _drag_limit = prev ? prev->to : 0; + if (p < h) { + _drag_moving = t->from; + _drag_fixed = t->to; + _drag_offset = p - t->from; } else { - /* limit is the start of the next tab */ - _drag_limit = next ? next->from : extent (); + _drag_moving = t->to; + _drag_fixed = t->from; + _drag_offset = p - t->to; } } else if (ev->button == 3) { @@ -107,50 +129,21 @@ GroupTabs::on_motion_notify_event (GdkEventMotion* ev) double const p = primary_coordinate (ev->x, ev->y); - if (p != _drag_last) { + if (p != _drag_first) { _drag_moved = true; } - if (_drag_from) { + _drag_moving = p - _drag_offset; - double f = _dragging->from + p - _drag_last; + _dragging->from = min (_drag_moving, _drag_fixed); + _dragging->to = max (_drag_moving, _drag_fixed); - if (f < _drag_limit) { - /* limit drag in the `too big' direction */ - f = _drag_limit; - } - - double const t = _dragging->to - _dragging->last_ui_size; - if (f > t) { - /* limit drag in the `too small' direction */ - f = t; - } - - _dragging->from = f; - - } else { - - double t = _dragging->to + p - _drag_last; - - if (t > _drag_limit) { - /* limit drag in the `too big' direction */ - t = _drag_limit; - } - - double const f = _dragging->from + _dragging->first_ui_size; - if (t < f) { - /* limit drag in the `too small' direction */ - t = f; - } - - _dragging->to = t; - } + _dragging->from = max (_dragging->from, _drag_min); + _dragging->to = min (_dragging->to, _drag_max); set_dirty (); queue_draw (); - _drag_last = p; - return true; } @@ -164,28 +157,56 @@ GroupTabs::on_button_release_event (GdkEventButton* ev) if (!_drag_moved) { - if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { - - /* edit */ - RouteGroupDialog d (_dragging->group, Gtk::Stock::APPLY); - d.do_run (); - - } else { - - /* toggle active state */ - _dragging->group->set_active (!_dragging->group->is_active (), this); - _dragging = 0; - + if (_dragging->group) { + + if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { + + /* edit */ + RouteGroupDialog d (_dragging->group, Gtk::Stock::APPLY); + d.do_run (); + + } else { + + /* toggle active state */ + _dragging->group->set_active (!_dragging->group->is_active (), this); + + } } } else { /* finish drag */ - _dragging = 0; - reflect_tabs (_tabs); + RouteList routes = routes_for_tab (_dragging); + + if (!routes.empty()) { + if (_dragging_new_tab) { + RouteGroup* g = new_route_group (); + if (g) { + for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { + (*i)->set_route_group (g, this); + } + } + } else { + boost::shared_ptr r = _session->get_routes (); + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + + if (find (routes.begin(), routes.end(), *i) == routes.end()) { + /* this route is not on the list of those that should be in _dragging's group */ + if ((*i)->route_group() == _dragging->group) { + (*i)->drop_route_group (this); + } + } else { + (*i)->set_route_group (_dragging->group, this); + } + } + } + } + set_dirty (); queue_draw (); } + _dragging = 0; + return true; } @@ -218,29 +239,39 @@ GroupTabs::render (cairo_t* cr) */ GroupTabs::Tab * -GroupTabs::click_to_tab (double c, Tab** prev, Tab** next) +GroupTabs::click_to_tab (double c, list::iterator* prev, list::iterator* next) { - *prev = 0; + *prev = *next = _tabs.end (); + Tab* under = 0; list::iterator i = _tabs.begin (); - while (i != _tabs.end() && (c < i->from || c > i->to)) { - *prev = &(*i); + while (i != _tabs.end()) { + + if (i->from > c) { + break; + } + + if (i->to < c) { + *prev = i; + ++i; + continue; + } + + if (i->from <= c && c < i->to) { + under = &(*i); + } + ++i; } - if (i == _tabs.end()) { - *next = 0; - return 0; + if (i != _tabs.end()) { + *next = i; + + if (under) { + *next++; + } } - list::iterator j = i; - ++j; - if (j == _tabs.end()) { - *next = 0; - } else { - *next = &(*j); - } - - return &(*i); + return under; } diff --git a/gtk2_ardour/group_tabs.h b/gtk2_ardour/group_tabs.h index 3036cfcb39..bb764a02a5 100644 --- a/gtk2_ardour/group_tabs.h +++ b/gtk2_ardour/group_tabs.h @@ -41,12 +41,12 @@ public: protected: struct Tab { - double from; ///< start coordinate - double to; ///< end coordinate + Tab () : group (0) {} + + double from; + double to; Gdk::Color colour; ///< colour ARDOUR::RouteGroup* group; ///< route group - double first_ui_size; ///< GUI size of the first route in the group - double last_ui_size; ///< GUI size of the last route in the group }; private: @@ -67,10 +67,7 @@ private: */ virtual double primary_coordinate (double, double) const = 0; - /** Take a list of tabs and alter the route groups to reflect the tabs. - * @param tabs. - */ - virtual void reflect_tabs (std::list const & tabs) = 0; + virtual ARDOUR::RouteList routes_for_tab (Tab const * t) const = 0; /** @return Size of the widget along the primary axis */ virtual double extent () const = 0; @@ -80,18 +77,24 @@ private: */ virtual Gtk::Menu* get_menu (ARDOUR::RouteGroup* g) = 0; + virtual ARDOUR::RouteGroup* new_route_group () const = 0; + void render (cairo_t *); void on_size_request (Gtk::Requisition *); bool on_button_press_event (GdkEventButton *); bool on_motion_notify_event (GdkEventMotion *); bool on_button_release_event (GdkEventButton *); - Tab * click_to_tab (double, Tab**, Tab**); + Tab * click_to_tab (double, std::list::iterator *, std::list::iterator *); std::list _tabs; ///< current list of tabs Tab* _dragging; ///< tab being dragged, or 0 + bool _dragging_new_tab; ///< true if we're dragging a new tab bool _drag_moved; ///< true if there has been movement during any current drag - bool _drag_from; ///< true if the drag is of the `from' end of the tab, otherwise it's the `to' end - double _drag_last; ///< last mouse pointer position during drag - double _drag_limit; ///< limit of the current drag + double _drag_fixed; ///< the position of the fixed end of the tab being dragged + double _drag_moving; ///< the position of the moving end of the tab being dragged + double _drag_offset; ///< offset from the mouse to the end of the tab being dragged + double _drag_min; ///< minimum position for drag + double _drag_max; ///< maximum position for drag + double _drag_first; ///< first mouse pointer position during drag }; diff --git a/gtk2_ardour/mixer_group_tabs.cc b/gtk2_ardour/mixer_group_tabs.cc index f466381d2b..d0299cb959 100644 --- a/gtk2_ardour/mixer_group_tabs.cc +++ b/gtk2_ardour/mixer_group_tabs.cc @@ -63,14 +63,12 @@ MixerGroupTabs::compute_tabs () const if (g != tab.group) { if (tab.group) { tab.to = x; - tab.last_ui_size = s->get_width (); tabs.push_back (tab); } tab.from = x; tab.group = g; tab.colour = s->color (); - tab.first_ui_size = s->get_width (); } x += s->get_width (); @@ -89,7 +87,7 @@ MixerGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const { double const arc_radius = _height; - if (tab.group->is_active()) { + if (tab.group && tab.group->is_active()) { cairo_set_source_rgba (cr, tab.colour.get_red_p (), tab.colour.get_green_p (), tab.colour.get_blue_p (), 1); } else { cairo_set_source_rgba (cr, 1, 1, 1, 0.2); @@ -101,16 +99,18 @@ MixerGroupTabs::draw_tab (cairo_t* cr, Tab const & tab) const cairo_line_to (cr, tab.from, _height); cairo_fill (cr); - pair const f = fit_to_pixels (cr, tab.group->name(), tab.to - tab.from - arc_radius * 2); - - cairo_text_extents_t ext; - cairo_text_extents (cr, tab.group->name().c_str(), &ext); - - cairo_set_source_rgb (cr, 1, 1, 1); - cairo_move_to (cr, tab.from + (tab.to - tab.from - f.second) / 2, _height - ext.height / 2); - cairo_save (cr); - cairo_show_text (cr, f.first.c_str()); - cairo_restore (cr); + if (tab.group) { + pair const f = fit_to_pixels (cr, tab.group->name(), tab.to - tab.from - arc_radius * 2); + + cairo_text_extents_t ext; + cairo_text_extents (cr, tab.group->name().c_str(), &ext); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_move_to (cr, tab.from + (tab.to - tab.from - f.second) / 2, _height - ext.height / 2); + cairo_save (cr); + cairo_show_text (cr, f.first.c_str()); + cairo_restore (cr); + } } double @@ -119,45 +119,36 @@ MixerGroupTabs::primary_coordinate (double x, double) const return x; } -void -MixerGroupTabs::reflect_tabs (list const & tabs) +RouteList +MixerGroupTabs::routes_for_tab (Tab const * t) const { - list::const_iterator j = tabs.begin (); - + RouteList routes; int32_t x = 0; + TreeModel::Children rows = _mixer->track_model->children (); for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) { MixerStrip* s = (*i)[_mixer->track_columns.strip]; - if (s->route()->is_master() || s->route()->is_control() || !s->marked_for_display()) { - continue; + if (s->route()->is_master() || s->route()->is_control() || !s->marked_for_display()) { + continue; + } + + if (x >= t->to) { + /* tab finishes before this track starts */ + break; } - if (j == tabs.end()) { - - /* already run out of tabs, so no edit group */ - s->route()->set_route_group (0, this); - - } else { - - if (x >= j->to) { - /* this tab finishes before this track starts, so onto the next tab */ - ++j; - } - - double const h = x + s->get_width() / 2; - - if (j->from < h && j->to > h) { - s->route()->set_route_group (j->group, this); - } else { - s->route()->set_route_group (0, this); - } + double const h = x + s->get_width() / 2; + if (t->from < h && t->to > h) { + routes.push_back (s->route ()); } x += s->get_width (); } + + return routes; } Gtk::Menu* @@ -205,3 +196,25 @@ MixerGroupTabs::destroy_subgroup (RouteGroup* g) { g->destroy_subgroup (); } + +ARDOUR::RouteGroup * +MixerGroupTabs::new_route_group () const +{ + RouteGroup* g = new RouteGroup ( + *_session, + "", + RouteGroup::Active, + (RouteGroup::Property) (RouteGroup::Gain | RouteGroup::Mute | RouteGroup::Solo | RouteGroup::RecEnable) + ); + + RouteGroupDialog d (g, Gtk::Stock::NEW); + int const r = d.do_run (); + + if (r != Gtk::RESPONSE_OK) { + delete g; + return 0; + } + + _session->add_route_group (g); + return g; +} diff --git a/gtk2_ardour/mixer_group_tabs.h b/gtk2_ardour/mixer_group_tabs.h index eb604e3c92..272fb9234a 100644 --- a/gtk2_ardour/mixer_group_tabs.h +++ b/gtk2_ardour/mixer_group_tabs.h @@ -30,11 +30,12 @@ private: std::list compute_tabs () const; void draw_tab (cairo_t *, Tab const &) const; double primary_coordinate (double, double) const; - void reflect_tabs (std::list const &); + ARDOUR::RouteList routes_for_tab (Tab const *) const; double extent () const { return _width; } Gtk::Menu* get_menu (ARDOUR::RouteGroup* g); + ARDOUR::RouteGroup* new_route_group () const; void edit_group (ARDOUR::RouteGroup *); void remove_group (ARDOUR::RouteGroup *); diff --git a/gtk2_ardour/route_group_dialog.cc b/gtk2_ardour/route_group_dialog.cc index 4856d87f08..7f08077628 100644 --- a/gtk2_ardour/route_group_dialog.cc +++ b/gtk2_ardour/route_group_dialog.cc @@ -75,7 +75,7 @@ RouteGroupDialog::RouteGroupDialog (RouteGroup* g, StockID const & s) _name.set_text (_group->name ()); _active.set_active (_group->is_active ()); - _name.signal_activate ().connect (sigc::bind (mem_fun (*this, &Dialog::response), RESPONSE_ACCEPT)); + _name.signal_activate ().connect (sigc::bind (mem_fun (*this, &Dialog::response), RESPONSE_OK)); _gain.set_active (_group->property (RouteGroup::Gain)); _relative.set_active (_group->is_relative()); @@ -117,6 +117,7 @@ RouteGroupDialog::RouteGroupDialog (RouteGroup* g, StockID const & s) add_button (Stock::CANCEL, RESPONSE_CANCEL); add_button (s, RESPONSE_OK); + set_default_response (RESPONSE_OK); show_all_children (); }