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 ();
{
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);
cairo_line_to (cr, 0, tab.from + arc_radius);
cairo_fill (cr);
- pair<string, double> 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<string, double> 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
return y;
}
-void
-EditorGroupTabs::reflect_tabs (list<Tab> const & tabs)
+RouteList
+EditorGroupTabs::routes_for_tab (Tab const * t) const
{
- list<Tab>::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) {
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
if (rtv) {
- if (j == tabs.end()) {
-
- /* 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 (y >= t->to) {
+ /* tab finishes before this track starts */
+ break;
+ }
- 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;
}
{
return _editor->_route_groups->menu (g);
}
+
+ARDOUR::RouteGroup *
+EditorGroupTabs::new_route_group () const
+{
+ return _editor->_route_groups->new_route_group ();
+}
std::list<Tab> compute_tabs () const;
void draw_tab (cairo_t *, Tab const &) const;
double primary_coordinate (double, double) const;
- void reflect_tabs (std::list<Tab> 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;
};
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);
_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)));
g->set_active (a, this);
}
-void
-EditorRouteGroups::new_route_group ()
+ARDOUR::RouteGroup *
+EditorRouteGroups::new_route_group () const
{
RouteGroup* g = new RouteGroup (
*_session,
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)
{
Gtk::Menu* menu (ARDOUR::RouteGroup *);
void clear ();
+ ARDOUR::RouteGroup* new_route_group () const;
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 ();
#include <gtkmm/stock.h>
#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"
GroupTabs::GroupTabs (Editor* e)
: EditorComponent (e),
- _dragging (0)
+ _dragging (0),
+ _dragging_new_tab (0)
{
}
double const p = primary_coordinate (ev->x, ev->y);
- Tab* prev;
- Tab* next;
+ list<Tab>::iterator prev;
+ list<Tab>::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<Tab>::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) {
double const p = primary_coordinate (ev->x, ev->y);
- if (p != _drag_last) {
+ if (p != _drag_first) {
_drag_moved = true;
}
- if (_drag_from) {
-
- double f = _dragging->from + p - _drag_last;
+ _drag_moving = p - _drag_offset;
- 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 = min (_drag_moving, _drag_fixed);
+ _dragging->to = max (_drag_moving, _drag_fixed);
- _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;
}
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<RouteList> 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;
}
*/
GroupTabs::Tab *
-GroupTabs::click_to_tab (double c, Tab** prev, Tab** next)
+GroupTabs::click_to_tab (double c, list<Tab>::iterator* prev, list<Tab>::iterator* next)
{
- *prev = 0;
+ *prev = *next = _tabs.end ();
+ Tab* under = 0;
list<Tab>::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;
- list<Tab>::iterator j = i;
- ++j;
- if (j == _tabs.end()) {
- *next = 0;
- } else {
- *next = &(*j);
+ if (under) {
+ *next++;
+ }
}
- return &(*i);
+ return under;
}
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:
*/
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<Tab> 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;
*/
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<Tab>::iterator *, std::list<Tab>::iterator *);
std::list<Tab> _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
};
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 ();
{
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);
cairo_line_to (cr, tab.from, _height);
cairo_fill (cr);
- pair<string, double> 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<string, double> 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
return x;
}
-void
-MixerGroupTabs::reflect_tabs (list<Tab> const & tabs)
+RouteList
+MixerGroupTabs::routes_for_tab (Tab const * t) const
{
- list<Tab>::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 (j == tabs.end()) {
-
- /* already run out of tabs, so no edit group */
- s->route()->set_route_group (0, this);
+ if (s->route()->is_master() || s->route()->is_control() || !s->marked_for_display()) {
+ continue;
+ }
- } 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 (x >= t->to) {
+ /* tab finishes before this track starts */
+ break;
+ }
- 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*
{
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;
+}
std::list<Tab> compute_tabs () const;
void draw_tab (cairo_t *, Tab const &) const;
double primary_coordinate (double, double) const;
- void reflect_tabs (std::list<Tab> 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 *);
_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());
add_button (Stock::CANCEL, RESPONSE_CANCEL);
add_button (s, RESPONSE_OK);
+ set_default_response (RESPONSE_OK);
show_all_children ();
}