2009-06-21 15:59:56 -04:00
/*
2009-10-14 12:10:01 -04:00
Copyright ( C ) 2009 Paul Davis
2009-06-21 15:59:56 -04:00
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 0213 9 , USA .
*/
# include <gtkmm/stock.h>
2016-05-19 10:45:55 -04:00
2009-06-21 15:59:56 -04:00
# include "ardour/session.h"
# include "ardour/route_group.h"
2009-12-01 10:32:42 -05:00
# include "ardour/route.h"
2016-05-19 10:45:55 -04:00
# include "ardour/vca_manager.h"
# include "ardour/vca.h"
2009-12-21 13:23:07 -05:00
# include "gui_thread.h"
2009-06-21 15:59:56 -04:00
# include "route_group_dialog.h"
# include "group_tabs.h"
2009-06-22 20:27:52 -04:00
# include "keyboard.h"
2009-06-21 15:59:56 -04:00
# include "i18n.h"
2011-08-30 05:48:53 -04:00
# include "ardour_ui.h"
2014-06-09 23:28:32 -04:00
# include "rgb_macros.h"
2015-01-04 10:58:46 -05:00
# include "ui_config.h"
2011-08-30 05:48:53 -04:00
# include "utils.h"
2009-06-21 15:59:56 -04:00
2009-06-21 18:17:17 -04:00
using namespace std ;
2009-06-21 15:59:56 -04:00
using namespace Gtk ;
using namespace ARDOUR ;
2014-06-25 15:27:37 -04:00
using namespace ARDOUR_UI_UTILS ;
2009-12-04 17:51:32 -05:00
using Gtkmm2ext : : Keyboard ;
2009-06-21 15:59:56 -04:00
2011-08-30 05:48:53 -04:00
list < Gdk : : Color > GroupTabs : : _used_colors ;
2010-07-19 17:47:07 -04:00
GroupTabs : : GroupTabs ( )
: _menu ( 0 )
, _dragging ( 0 )
, _dragging_new_tab ( 0 )
2009-06-21 15:59:56 -04:00
{
2013-07-16 20:35:02 -04:00
add_events ( Gdk : : BUTTON_PRESS_MASK | Gdk : : BUTTON_RELEASE_MASK | Gdk : : POINTER_MOTION_MASK ) ;
2015-01-02 09:44:54 -05:00
UIConfiguration : : instance ( ) . ColorsChanged . connect ( sigc : : mem_fun ( * this , & GroupTabs : : queue_draw ) ) ;
2009-06-21 15:59:56 -04:00
}
2010-07-19 17:47:07 -04:00
GroupTabs : : ~ GroupTabs ( )
{
delete _menu ;
}
2009-06-21 15:59:56 -04:00
void
2009-12-17 13:24:23 -05:00
GroupTabs : : set_session ( Session * s )
2009-06-21 15:59:56 -04:00
{
2010-07-19 17:47:07 -04:00
SessionHandlePtr : : set_session ( s ) ;
2009-07-03 14:37:15 -04:00
2009-12-17 13:24:23 -05:00
if ( _session ) {
2011-09-07 07:56:23 -04:00
_session - > RouteGroupPropertyChanged . connect (
_session_connections , invalidator ( * this ) , boost : : bind ( & GroupTabs : : route_group_property_changed , this , _1 ) , gui_context ( )
) ;
_session - > RouteAddedToRouteGroup . connect (
_session_connections , invalidator ( * this ) , boost : : bind ( & GroupTabs : : route_added_to_route_group , this , _1 , _2 ) , gui_context ( )
) ;
_session - > RouteRemovedFromRouteGroup . connect (
_session_connections , invalidator ( * this ) , boost : : bind ( & GroupTabs : : route_removed_from_route_group , this , _1 , _2 ) , gui_context ( )
) ;
2015-10-05 10:17:49 -04:00
2016-02-12 16:58:33 -05:00
_session - > route_group_removed . connect ( _session_connections , invalidator ( * this ) , boost : : bind ( & GroupTabs : : set_dirty , this , ( cairo_rectangle_t * ) 0 ) , gui_context ( ) ) ;
2009-12-17 13:24:23 -05:00
}
2009-06-21 15:59:56 -04:00
}
/** Handle a size request.
* @ param req GTK requisition
*/
void
GroupTabs : : on_size_request ( Gtk : : Requisition * req )
{
/* Use a dummy, small width and the actual height that we want */
req - > width = 16 ;
req - > height = 16 ;
}
bool
GroupTabs : : on_button_press_event ( GdkEventButton * ev )
{
using namespace Menu_Helpers ;
2009-06-21 18:17:17 -04:00
double const p = primary_coordinate ( ev - > x , ev - > y ) ;
2009-12-01 10:32:42 -05:00
list < Tab > : : iterator prev ;
list < Tab > : : iterator next ;
2009-06-21 18:17:17 -04:00
Tab * t = click_to_tab ( p , & prev , & next ) ;
2009-12-01 10:32:42 -05:00
_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 ) ;
}
2011-06-01 13:00:29 -04:00
2009-12-01 10:32:42 -05:00
} else {
_dragging_new_tab = false ;
2011-08-31 16:46:16 -04:00
_initial_dragging_routes = routes_for_tab ( t ) ;
2009-12-01 10:32:42 -05:00
}
2009-06-21 18:17:17 -04:00
_dragging = t ;
_drag_moved = false ;
2009-12-01 10:32:42 -05:00
_drag_first = p ;
2009-06-21 18:17:17 -04:00
double const h = ( t - > from + t - > to ) / 2 ;
2009-12-01 10:32:42 -05:00
if ( p < h ) {
_drag_moving = t - > from ;
_drag_fixed = t - > to ;
_drag_offset = p - t - > from ;
2009-06-21 18:17:17 -04:00
} else {
2009-12-01 10:32:42 -05:00
_drag_moving = t - > to ;
_drag_fixed = t - > from ;
_drag_offset = p - t - > to ;
2009-06-21 18:17:17 -04:00
}
} else if ( ev - > button = = 3 ) {
2009-06-21 15:59:56 -04:00
2009-06-22 19:17:46 -04:00
RouteGroup * g = t ? t - > group : 0 ;
2015-10-05 10:17:49 -04:00
2011-11-15 19:38:12 -05:00
if ( Keyboard : : modifier_state_equals ( ev - > state , Keyboard : : PrimaryModifier ) & & g ) {
/* edit */
RouteGroupDialog d ( g , false ) ;
d . do_run ( ) ;
} else {
2015-09-21 17:49:40 -04:00
Menu * m = get_menu ( g , true ) ;
2011-11-15 19:38:12 -05:00
if ( m ) {
m - > popup ( ev - > button , ev - > time ) ;
}
2009-06-23 19:05:14 -04:00
}
2009-06-21 15:59:56 -04:00
}
return true ;
}
2009-06-21 18:17:17 -04:00
bool
GroupTabs : : on_motion_notify_event ( GdkEventMotion * ev )
{
if ( _dragging = = 0 ) {
return false ;
}
double const p = primary_coordinate ( ev - > x , ev - > y ) ;
2009-10-14 12:10:01 -04:00
2009-12-01 10:32:42 -05:00
if ( p ! = _drag_first ) {
2009-06-21 18:17:17 -04:00
_drag_moved = true ;
}
2009-12-01 10:32:42 -05:00
_drag_moving = p - _drag_offset ;
2009-06-22 11:47:48 -04:00
2009-12-01 10:32:42 -05:00
_dragging - > from = min ( _drag_moving , _drag_fixed ) ;
_dragging - > to = max ( _drag_moving , _drag_fixed ) ;
2009-10-14 12:10:01 -04:00
2009-12-01 10:32:42 -05:00
_dragging - > from = max ( _dragging - > from , _drag_min ) ;
_dragging - > to = min ( _dragging - > to , _drag_max ) ;
2009-06-21 18:17:17 -04:00
set_dirty ( ) ;
queue_draw ( ) ;
2013-07-16 20:35:02 -04:00
gdk_event_request_motions ( ev ) ;
2009-06-21 18:17:17 -04:00
return true ;
}
bool
2012-05-02 16:29:46 -04:00
GroupTabs : : on_button_release_event ( GdkEventButton * )
2009-06-21 18:17:17 -04:00
{
if ( _dragging = = 0 ) {
return false ;
}
2015-10-05 10:17:49 -04:00
2009-06-21 18:17:17 -04:00
if ( ! _drag_moved ) {
2015-10-05 10:17:49 -04:00
2009-12-01 10:32:42 -05:00
if ( _dragging - > group ) {
2011-11-15 19:38:12 -05:00
/* toggle active state */
_dragging - > group - > set_active ( ! _dragging - > group - > is_active ( ) , this ) ;
2009-06-22 20:27:52 -04:00
}
2015-10-05 10:17:49 -04:00
2009-06-21 18:17:17 -04:00
} else {
2009-06-22 11:47:48 -04:00
/* finish drag */
2009-12-01 10:32:42 -05:00
RouteList routes = routes_for_tab ( _dragging ) ;
2015-10-05 10:17:49 -04:00
2009-12-01 10:32:42 -05:00
if ( ! routes . empty ( ) ) {
if ( _dragging_new_tab ) {
2010-07-19 17:47:07 -04:00
RouteGroup * g = create_and_add_group ( ) ;
2009-12-01 10:32:42 -05:00
if ( g ) {
for ( RouteList : : iterator i = routes . begin ( ) ; i ! = routes . end ( ) ; + + i ) {
2009-12-09 22:25:32 -05:00
g - > add ( * i ) ;
2009-12-01 10:32:42 -05:00
}
}
} else {
boost : : shared_ptr < RouteList > r = _session - > get_routes ( ) ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2015-10-05 10:17:49 -04:00
2011-08-31 16:46:16 -04:00
bool const was_in_tab = find (
_initial_dragging_routes . begin ( ) , _initial_dragging_routes . end ( ) , * i
) ! = _initial_dragging_routes . end ( ) ;
2015-10-05 10:17:49 -04:00
2011-08-31 16:46:16 -04:00
bool const now_in_tab = find ( routes . begin ( ) , routes . end ( ) , * i ) ! = routes . end ( ) ;
2015-10-05 10:17:49 -04:00
2011-08-31 16:46:16 -04:00
if ( was_in_tab & & ! now_in_tab ) {
_dragging - > group - > remove ( * i ) ;
} else if ( ! was_in_tab & & now_in_tab ) {
2009-12-09 22:25:32 -05:00
_dragging - > group - > add ( * i ) ;
2009-12-01 10:32:42 -05:00
}
}
}
}
2015-10-05 10:17:49 -04:00
2009-06-21 18:17:17 -04:00
set_dirty ( ) ;
queue_draw ( ) ;
}
2015-10-05 10:17:49 -04:00
2009-12-01 10:32:42 -05:00
_dragging = 0 ;
2011-08-31 16:46:16 -04:00
_initial_dragging_routes . clear ( ) ;
2009-12-01 10:32:42 -05:00
2009-06-21 18:17:17 -04:00
return true ;
}
void
2014-03-20 18:50:40 -04:00
GroupTabs : : render ( cairo_t * cr , cairo_rectangle_t * )
2009-06-21 18:17:17 -04:00
{
if ( _dragging = = 0 ) {
_tabs = compute_tabs ( ) ;
}
/* background */
2009-10-14 12:10:01 -04:00
2012-03-17 13:14:15 -04:00
Gdk : : Color c = get_style ( ) - > get_base ( Gtk : : STATE_NORMAL ) ;
cairo_set_source_rgb ( cr , c . get_red_p ( ) , c . get_green_p ( ) , c . get_blue_p ( ) ) ;
2011-11-18 10:35:58 -05:00
cairo_rectangle ( cr , 0 , 0 , get_width ( ) , get_height ( ) ) ;
2009-06-21 18:17:17 -04:00
cairo_fill ( cr ) ;
2015-10-05 10:17:49 -04:00
2009-06-21 18:17:17 -04:00
/* tabs */
for ( list < Tab > : : const_iterator i = _tabs . begin ( ) ; i ! = _tabs . end ( ) ; + + i ) {
draw_tab ( cr , * i ) ;
2009-10-14 12:10:01 -04:00
}
2009-06-21 18:17:17 -04:00
}
2009-06-22 11:47:48 -04:00
/** Convert a click position to a tab.
* @ param c Click position .
2011-08-15 10:08:01 -04:00
* @ param prev Filled in with the previous tab to the click , or _tabs . end ( ) .
* @ param next Filled in with the next tab after the click , or _tabs . end ( ) .
2009-06-22 11:47:48 -04:00
* @ return Tab under the click , or 0.
*/
2009-10-14 12:10:01 -04:00
2009-06-21 18:17:17 -04:00
GroupTabs : : Tab *
2009-12-01 10:32:42 -05:00
GroupTabs : : click_to_tab ( double c , list < Tab > : : iterator * prev , list < Tab > : : iterator * next )
2009-06-21 18:17:17 -04:00
{
2009-12-01 10:32:42 -05:00
* prev = * next = _tabs . end ( ) ;
Tab * under = 0 ;
2009-10-14 12:10:01 -04:00
2009-06-21 18:17:17 -04:00
list < Tab > : : iterator i = _tabs . begin ( ) ;
2009-12-01 10:32:42 -05:00
while ( i ! = _tabs . end ( ) ) {
if ( i - > from > c ) {
2011-08-15 10:08:01 -04:00
* next = i ;
2009-12-01 10:32:42 -05:00
break ;
}
if ( i - > to < c ) {
* prev = i ;
+ + i ;
continue ;
}
if ( i - > from < = c & & c < i - > to ) {
under = & ( * i ) ;
}
2009-06-21 18:17:17 -04:00
+ + i ;
}
2009-12-01 10:32:42 -05:00
return under ;
2009-06-21 18:17:17 -04:00
}
2009-06-21 21:01:43 -04:00
2016-05-19 13:11:10 -04:00
void
GroupTabs : : add_new_from_items ( Menu_Helpers : : MenuList & items )
2010-07-19 17:47:07 -04:00
{
using namespace Menu_Helpers ;
2016-05-19 13:11:10 -04:00
Menu * new_from ;
2015-09-21 17:49:40 -04:00
2016-05-19 10:45:55 -04:00
new_from = new Menu ;
2016-05-18 23:44:09 -04:00
{
MenuList & f = new_from - > items ( ) ;
2016-05-19 10:45:55 -04:00
f . push_back ( MenuElem ( _ ( " Selection... " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : new_from_selection ) , false ) ) ) ;
f . push_back ( MenuElem ( _ ( " Record Enabled... " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : new_from_rec_enabled ) , false ) ) ) ;
f . push_back ( MenuElem ( _ ( " Soloed... " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : new_from_soloed ) , false ) ) ) ;
2016-05-18 23:44:09 -04:00
}
2016-05-19 10:45:55 -04:00
items . push_back ( MenuElem ( _ ( " Create New Group From... " ) , * new_from ) ) ;
2011-06-01 13:00:29 -04:00
2016-05-18 23:44:09 -04:00
new_from = new Menu ;
{
MenuList & f = new_from - > items ( ) ;
2016-05-19 10:45:55 -04:00
f . push_back ( MenuElem ( _ ( " Selection... " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : new_from_selection ) , true ) ) ) ;
f . push_back ( MenuElem ( _ ( " Record Enabled... " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : new_from_rec_enabled ) , true ) ) ) ;
f . push_back ( MenuElem ( _ ( " Soloed... " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : new_from_soloed ) , true ) ) ) ;
2016-05-18 23:44:09 -04:00
}
2016-05-19 10:45:55 -04:00
items . push_back ( MenuElem ( _ ( " Create New Group with Master From... " ) , * new_from ) ) ;
2016-05-19 13:11:10 -04:00
}
Gtk : : Menu *
GroupTabs : : get_menu ( RouteGroup * g , bool in_tab_area )
{
using namespace Menu_Helpers ;
delete _menu ;
_menu = new Menu ;
_menu - > set_name ( " ArdourContextMenu " ) ;
2016-05-18 23:44:09 -04:00
2016-05-19 13:11:10 -04:00
MenuList & items = _menu - > items ( ) ;
2016-05-19 10:45:55 -04:00
Menu * vca_menu ;
2016-05-19 13:11:10 -04:00
2016-05-19 10:45:55 -04:00
const VCAList vcas = _session - > vca_manager ( ) . vcas ( ) ;
2016-05-19 13:11:10 -04:00
if ( ! in_tab_area ) {
items . push_back ( MenuElem ( _ ( " Create New Group ... " ) , hide_return ( sigc : : mem_fun ( * this , & GroupTabs : : create_and_add_group ) ) ) ) ;
items . push_back ( MenuElem ( _ ( " Create New Group with Control Master ... " ) , hide_return ( sigc : : mem_fun ( * this , & GroupTabs : : create_and_add_group_with_master ) ) ) ) ;
/* context menu is not for a group tab, show the "create new
from " items here
*/
add_new_from_items ( items ) ;
}
if ( g ) {
items . push_back ( SeparatorElem ( ) ) ;
items . push_back ( MenuElem ( _ ( " Edit Group... " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : edit_group ) , g ) ) ) ;
items . push_back ( MenuElem ( _ ( " Collect Group " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : collect ) , g ) ) ) ;
items . push_back ( MenuElem ( _ ( " Remove Group " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : remove_group ) , g ) ) ) ;
items . push_back ( SeparatorElem ( ) ) ;
vca_menu = new Menu ;
MenuList & f ( vca_menu - > items ( ) ) ;
2016-05-21 07:49:51 -04:00
f . push_back ( MenuElem ( " New " , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : assign_group_to_master ) , 0 , g , true ) ) ) ;
2016-05-19 13:11:10 -04:00
for ( VCAList : : const_iterator v = vcas . begin ( ) ; v ! = vcas . end ( ) ; + + v ) {
2016-05-21 07:49:51 -04:00
f . push_back ( MenuElem ( string_compose ( " VCA %1 " , ( * v ) - > number ( ) ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : assign_group_to_master ) , ( * v ) - > number ( ) , g , true ) ) ) ;
2016-05-19 13:11:10 -04:00
}
items . push_back ( MenuElem ( _ ( " Assign Group to Control Master... " ) , * vca_menu ) ) ;
items . push_back ( SeparatorElem ( ) ) ;
if ( g - > has_subgroup ( ) ) {
items . push_back ( MenuElem ( _ ( " Remove Subgroup Bus " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : un_subgroup ) , g ) ) ) ;
} else {
items . push_back ( MenuElem ( _ ( " Add New Subgroup Bus " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : subgroup ) , g , false , PreFader ) ) ) ;
}
items . push_back ( MenuElem ( _ ( " Add New Aux Bus (pre-fader) " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : subgroup ) , g , true , PreFader ) ) ) ;
items . push_back ( MenuElem ( _ ( " Add New Aux Bus (post-fader) " ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : subgroup ) , g , true , PostFader ) ) ) ;
items . push_back ( SeparatorElem ( ) ) ;
}
add_menu_items ( _menu , g ) ;
if ( in_tab_area ) {
/* context menu is for a group tab, show the "create new
from " items here
*/
add_new_from_items ( items ) ;
}
items . push_back ( SeparatorElem ( ) ) ;
2016-05-19 10:45:55 -04:00
vca_menu = new Menu ;
2016-05-18 23:44:09 -04:00
{
2016-05-19 10:45:55 -04:00
MenuList & f ( vca_menu - > items ( ) ) ;
f . push_back ( MenuElem ( " New " , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : assign_selection_to_master ) , 0 ) ) ) ;
for ( VCAList : : const_iterator v = vcas . begin ( ) ; v ! = vcas . end ( ) ; + + v ) {
f . push_back ( MenuElem ( string_compose ( " VCA %1 " , ( * v ) - > number ( ) ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : assign_selection_to_master ) , ( * v ) - > number ( ) ) ) ) ;
}
2016-05-18 23:44:09 -04:00
}
2016-05-19 10:45:55 -04:00
items . push_back ( MenuElem ( _ ( " Assign Selection to Control Master... " ) , * vca_menu ) ) ;
vca_menu = new Menu ;
{
MenuList & f ( vca_menu - > items ( ) ) ;
f . push_back ( MenuElem ( " New " , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : assign_selection_to_master ) , 0 ) ) ) ;
for ( VCAList : : const_iterator v = vcas . begin ( ) ; v ! = vcas . end ( ) ; + + v ) {
f . push_back ( MenuElem ( string_compose ( " VCA %1 " , ( * v ) - > number ( ) ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : assign_selection_to_master ) , ( * v ) - > number ( ) ) ) ) ;
}
}
items . push_back ( MenuElem ( _ ( " Assign Record Enabled to Control Master... " ) , * vca_menu ) ) ;
vca_menu = new Menu ;
{
MenuList & f ( vca_menu - > items ( ) ) ;
f . push_back ( MenuElem ( " New " , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : assign_selection_to_master ) , 0 ) ) ) ;
for ( VCAList : : const_iterator v = vcas . begin ( ) ; v ! = vcas . end ( ) ; + + v ) {
f . push_back ( MenuElem ( string_compose ( " VCA %1 " , ( * v ) - > number ( ) ) , sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : assign_selection_to_master ) , ( * v ) - > number ( ) ) ) ) ;
}
}
items . push_back ( MenuElem ( _ ( " Assign Soloed to Control Master... " ) ) ) ;
2016-05-18 23:44:09 -04:00
2010-07-19 17:47:07 -04:00
items . push_back ( SeparatorElem ( ) ) ;
2011-12-06 22:28:19 -05:00
items . push_back ( MenuElem ( _ ( " Enable All Groups " ) , sigc : : mem_fun ( * this , & GroupTabs : : activate_all ) ) ) ;
items . push_back ( MenuElem ( _ ( " Disable All Groups " ) , sigc : : mem_fun ( * this , & GroupTabs : : disable_all ) ) ) ;
2016-05-18 23:44:09 -04:00
2016-05-19 10:45:55 -04:00
return _menu ;
}
2016-05-18 23:44:09 -04:00
2016-05-19 10:45:55 -04:00
void
2016-05-21 07:49:51 -04:00
GroupTabs : : assign_group_to_master ( uint32_t which , RouteGroup * group , bool rename_master )
2016-05-19 10:45:55 -04:00
{
if ( ! _session | | ! group ) {
return ;
2016-05-18 23:44:09 -04:00
}
2016-05-19 10:45:55 -04:00
boost : : shared_ptr < VCA > master ;
2016-05-18 23:44:09 -04:00
2016-05-19 10:45:55 -04:00
if ( which = = 0 ) {
if ( _session - > vca_manager ( ) . create_vca ( 1 ) ) {
/* error */
return ;
}
2016-05-18 23:44:09 -04:00
2016-05-19 10:45:55 -04:00
/* VCAs use 1-based counting. Get most recently created VCA... */
which = _session - > vca_manager ( ) . n_vcas ( ) ;
2016-05-18 23:44:09 -04:00
}
2016-05-19 10:45:55 -04:00
master = _session - > vca_manager ( ) . vca_by_number ( which ) ;
2016-05-18 23:44:09 -04:00
2016-05-19 10:45:55 -04:00
if ( ! master ) {
/* should never happen; if it does, basically something deeply
odd happened , no reason to tell user because there ' s no
sensible explanation .
*/
return ;
2016-05-18 23:44:09 -04:00
}
2011-06-01 13:00:29 -04:00
2016-05-19 10:45:55 -04:00
group - > assign_master ( master ) ;
2016-05-21 07:49:51 -04:00
if ( rename_master ) {
master - > set_name ( group - > name ( ) ) ;
}
2010-07-19 17:47:07 -04:00
}
void
2016-05-19 10:45:55 -04:00
GroupTabs : : assign_some_to_master ( uint32_t which , RouteList rl )
2016-05-18 23:44:09 -04:00
{
2016-05-19 10:45:55 -04:00
if ( ! _session ) {
return ;
}
2016-05-18 23:44:09 -04:00
2016-05-19 10:45:55 -04:00
boost : : shared_ptr < VCA > master ;
if ( which = = 0 ) {
if ( _session - > vca_manager ( ) . create_vca ( 1 ) ) {
/* error */
return ;
}
/* VCAs use 1-based counting. Get most recently created VCA... */
which = _session - > vca_manager ( ) . n_vcas ( ) ;
}
master = _session - > vca_manager ( ) . vca_by_number ( which ) ;
if ( ! master ) {
/* should never happen; if it does, basically something deeply
odd happened , no reason to tell user because there ' s no
sensible explanation .
*/
return ;
}
2016-05-18 23:44:09 -04:00
2010-07-19 17:47:07 -04:00
if ( rl . empty ( ) ) {
return ;
}
2016-05-19 10:45:55 -04:00
for ( RouteList : : iterator r = rl . begin ( ) ; r ! = rl . end ( ) ; + + r ) {
( * r ) - > assign ( master ) ;
}
2010-07-19 17:47:07 -04:00
}
2016-05-19 10:45:55 -04:00
RouteList
GroupTabs : : get_rec_enabled ( )
2010-07-19 17:47:07 -04:00
{
RouteList rec_enabled ;
2016-05-19 10:45:55 -04:00
if ( ! _session ) {
return rec_enabled ;
}
boost : : shared_ptr < RouteList > rl = _session - > get_routes ( ) ;
2010-07-19 17:47:07 -04:00
for ( RouteList : : iterator i = rl - > begin ( ) ; i ! = rl - > end ( ) ; + + i ) {
2016-04-08 16:49:47 -04:00
boost : : shared_ptr < Track > trk ( boost : : dynamic_pointer_cast < Track > ( * i ) ) ;
if ( trk & & trk - > rec_enable_control ( ) - > get_value ( ) ) {
2010-07-19 17:47:07 -04:00
rec_enabled . push_back ( * i ) ;
}
}
2016-05-19 10:45:55 -04:00
return rec_enabled ;
2010-07-19 17:47:07 -04:00
}
2016-05-19 10:45:55 -04:00
RouteList
GroupTabs : : get_soloed ( )
2010-07-19 17:47:07 -04:00
{
boost : : shared_ptr < RouteList > rl = _session - > get_routes ( ) ;
RouteList soloed ;
for ( RouteList : : iterator i = rl - > begin ( ) ; i ! = rl - > end ( ) ; + + i ) {
if ( ! ( * i ) - > is_master ( ) & & ( * i ) - > soloed ( ) ) {
soloed . push_back ( * i ) ;
}
}
2016-05-19 10:45:55 -04:00
return soloed ;
}
void
GroupTabs : : assign_selection_to_master ( uint32_t which )
{
assign_some_to_master ( which , selected_routes ( ) ) ;
}
void
GroupTabs : : assign_recenabled_to_master ( uint32_t which )
{
assign_some_to_master ( which , get_rec_enabled ( ) ) ;
}
2010-07-19 17:47:07 -04:00
2016-05-19 10:45:55 -04:00
void
GroupTabs : : assign_soloed_to_master ( uint32_t which )
{
assign_some_to_master ( which , get_soloed ( ) ) ;
}
void
GroupTabs : : new_from_selection ( bool with_master )
{
run_new_group_dialog ( selected_routes ( ) , with_master ) ;
}
void
GroupTabs : : new_from_rec_enabled ( bool with_master )
{
run_new_group_dialog ( get_rec_enabled ( ) , with_master ) ;
}
void
GroupTabs : : new_from_soloed ( bool with_master )
{
run_new_group_dialog ( get_soloed ( ) , with_master ) ;
2010-07-19 17:47:07 -04:00
}
void
2016-05-18 23:44:09 -04:00
GroupTabs : : run_new_group_dialog ( RouteList const & rl , bool with_master )
2010-07-19 17:47:07 -04:00
{
2016-05-19 10:45:55 -04:00
if ( rl . empty ( ) ) {
return ;
}
2010-07-19 17:47:07 -04:00
RouteGroup * g = new RouteGroup ( * _session , " " ) ;
2011-01-07 21:35:46 -05:00
RouteGroupDialog d ( g , true ) ;
2010-07-19 17:47:07 -04:00
2011-01-07 21:35:46 -05:00
if ( d . do_run ( ) ) {
delete g ;
} else {
2010-07-19 17:47:07 -04:00
_session - > add_route_group ( g ) ;
for ( RouteList : : const_iterator i = rl . begin ( ) ; i ! = rl . end ( ) ; + + i ) {
g - > add ( * i ) ;
}
2016-05-21 07:49:51 -04:00
if ( with_master ) {
assign_group_to_master ( 0 , g , true ) ; /* zero => new master */
}
2010-07-19 17:47:07 -04:00
}
}
RouteGroup *
GroupTabs : : create_and_add_group ( ) const
2016-05-18 23:44:09 -04:00
{
RouteGroup * g = new RouteGroup ( * _session , " " ) ;
RouteGroupDialog d ( g , true ) ;
if ( d . do_run ( ) ) {
delete g ;
return 0 ;
}
_session - > add_route_group ( g ) ;
return g ;
}
RouteGroup *
GroupTabs : : create_and_add_master ( ) const
{
return 0 ;
}
RouteGroup *
GroupTabs : : create_and_add_group_with_master ( ) const
2010-07-19 17:47:07 -04:00
{
RouteGroup * g = new RouteGroup ( * _session , " " ) ;
2011-01-07 21:35:46 -05:00
RouteGroupDialog d ( g , true ) ;
2010-07-19 17:47:07 -04:00
2011-01-07 21:35:46 -05:00
if ( d . do_run ( ) ) {
2010-07-19 17:47:07 -04:00
delete g ;
return 0 ;
}
2011-06-01 13:00:29 -04:00
2010-07-19 17:47:07 -04:00
_session - > add_route_group ( g ) ;
return g ;
}
void
GroupTabs : : edit_group ( RouteGroup * g )
{
2011-01-07 21:35:46 -05:00
RouteGroupDialog d ( g , false ) ;
2010-07-19 17:47:07 -04:00
d . do_run ( ) ;
}
void
2011-01-03 21:36:29 -05:00
GroupTabs : : subgroup ( RouteGroup * g , bool aux , Placement placement )
2010-07-19 17:47:07 -04:00
{
2011-01-03 21:36:29 -05:00
g - > make_subgroup ( aux , placement ) ;
2010-07-19 17:47:07 -04:00
}
2013-01-03 14:34:07 -05:00
void
GroupTabs : : un_subgroup ( RouteGroup * g )
{
g - > destroy_subgroup ( ) ;
}
2010-07-19 17:47:07 -04:00
struct CollectSorter {
bool operator ( ) ( boost : : shared_ptr < Route > a , boost : : shared_ptr < Route > b ) {
2016-05-16 07:30:28 -04:00
return a - > presentation_info ( ) < b - > presentation_info ( ) ;
2010-07-19 17:47:07 -04:00
}
2011-11-21 17:38:44 -05:00
} ;
struct OrderSorter {
bool operator ( ) ( boost : : shared_ptr < Route > a , boost : : shared_ptr < Route > b ) {
2016-05-16 07:30:28 -04:00
return a - > presentation_info ( ) < b - > presentation_info ( ) ;
2011-11-21 17:38:44 -05:00
}
2010-07-19 17:47:07 -04:00
} ;
/** Collect all members of a RouteGroup so that they are together in the Editor or Mixer.
* @ param g Group to collect .
*/
void
GroupTabs : : collect ( RouteGroup * g )
{
boost : : shared_ptr < RouteList > group_routes = g - > route_list ( ) ;
2013-10-20 09:19:43 -04:00
group_routes - > sort ( CollectSorter ( ) ) ;
2010-07-19 17:47:07 -04:00
int const N = group_routes - > size ( ) ;
RouteList : : iterator i = group_routes - > begin ( ) ;
boost : : shared_ptr < RouteList > routes = _session - > get_routes ( ) ;
2013-10-20 09:19:43 -04:00
routes - > sort ( OrderSorter ( ) ) ;
2010-07-19 17:47:07 -04:00
RouteList : : const_iterator j = routes - > begin ( ) ;
int diff = 0 ;
int coll = - 1 ;
while ( i ! = group_routes - > end ( ) & & j ! = routes - > end ( ) ) {
2016-06-03 15:15:30 -04:00
PresentationInfo : : order_t const k = ( * j ) - > presentation_info ( ) . order ( ) ;
2010-07-19 17:47:07 -04:00
if ( * i = = * j ) {
if ( coll = = - 1 ) {
coll = k ;
diff = N - 1 ;
} else {
- - diff ;
}
2016-06-05 15:59:39 -04:00
( * j ) - > set_presentation_order_explicit ( coll ) ;
2010-07-19 17:47:07 -04:00
+ + coll ;
+ + i ;
} else {
2011-06-01 13:00:29 -04:00
2016-06-05 15:59:39 -04:00
( * j ) - > set_presentation_order_explicit ( k + diff ) ;
2011-06-01 13:00:29 -04:00
2010-07-19 17:47:07 -04:00
}
+ + j ;
}
2016-05-16 07:30:28 -04:00
_session - > notify_presentation_info_change ( ) ;
2010-07-19 17:47:07 -04:00
}
void
GroupTabs : : activate_all ( )
{
_session - > foreach_route_group (
sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : set_activation ) , true )
) ;
}
void
GroupTabs : : disable_all ( )
{
_session - > foreach_route_group (
sigc : : bind ( sigc : : mem_fun ( * this , & GroupTabs : : set_activation ) , false )
) ;
}
void
GroupTabs : : set_activation ( RouteGroup * g , bool a )
{
g - > set_active ( a , this ) ;
}
2011-06-01 13:00:29 -04:00
2010-07-19 19:26:40 -04:00
void
GroupTabs : : remove_group ( RouteGroup * g )
{
_session - > remove_route_group ( * g ) ;
}
2011-08-30 05:48:53 -04:00
/** Set the color of the tab of a route group */
void
2014-06-09 23:28:32 -04:00
GroupTabs : : set_group_color ( RouteGroup * group , uint32_t color )
2011-08-30 05:48:53 -04:00
{
assert ( group ) ;
2014-06-09 23:28:32 -04:00
uint32_t r , g , b , a ;
UINT_TO_RGBA ( color , & r , & g , & b , & a ) ;
2011-09-07 07:56:29 -04:00
/* Hack to disallow black route groups; force a dark grey instead */
2016-05-21 16:34:56 -04:00
const uint32_t dark_gray = 25 ;
2014-06-09 23:28:32 -04:00
2016-05-21 16:34:56 -04:00
if ( r < dark_gray & & g < dark_gray & & b < dark_gray ) {
r = dark_gray ;
g = dark_gray ;
b = dark_gray ;
2011-09-07 07:56:29 -04:00
}
2015-10-05 10:17:49 -04:00
2011-08-30 05:48:53 -04:00
GUIObjectState & gui_state = * ARDOUR_UI : : instance ( ) - > gui_object_state ;
char buf [ 64 ] ;
2015-10-05 10:17:49 -04:00
2014-06-09 23:28:32 -04:00
/* for historical reasons the colors must be stored as 16 bit color
* values . Ugh .
*/
snprintf ( buf , sizeof ( buf ) , " %d:%d:%d " , ( r < < 8 ) , ( g < < 8 ) , ( b < < 8 ) ) ;
2012-05-23 22:54:10 -04:00
gui_state . set_property ( group_gui_id ( group ) , " color " , buf ) ;
2015-10-05 10:17:49 -04:00
2011-12-06 16:40:11 -05:00
/* the group color change notification */
2015-10-05 10:17:49 -04:00
2011-12-06 16:40:11 -05:00
PBD : : PropertyChange change ;
change . add ( Properties : : color ) ;
group - > PropertyChanged ( change ) ;
2011-08-31 15:14:12 -04:00
/* This is a bit of a hack, but this might change
our route ' s effective color , so emit gui_changed
for our routes .
*/
2011-09-07 07:56:23 -04:00
emit_gui_changed_for_members ( group ) ;
2011-08-30 05:48:53 -04:00
}
/** @return the ID string to use for the GUI state of a route group */
string
GroupTabs : : group_gui_id ( RouteGroup * group )
{
assert ( group ) ;
char buf [ 64 ] ;
snprintf ( buf , sizeof ( buf ) , " route_group %s " , group - > id ( ) . to_s ( ) . c_str ( ) ) ;
return buf ;
}
/** @return the color to use for a route group tab */
2014-06-09 23:28:32 -04:00
uint32_t
2011-08-30 05:48:53 -04:00
GroupTabs : : group_color ( RouteGroup * group )
{
assert ( group ) ;
2015-10-05 10:17:49 -04:00
2011-08-30 05:48:53 -04:00
GUIObjectState & gui_state = * ARDOUR_UI : : instance ( ) - > gui_object_state ;
string const gui_id = group_gui_id ( group ) ;
bool empty ;
string const color = gui_state . get_string ( gui_id , " color " , & empty ) ;
2014-06-09 23:28:32 -04:00
2011-08-30 05:48:53 -04:00
if ( empty ) {
/* no color has yet been set, so use a random one */
2014-06-09 23:28:32 -04:00
uint32_t c = gdk_color_to_rgba ( unique_random_color ( _used_colors ) ) ;
set_group_color ( group , c ) ;
return c ;
2011-08-30 05:48:53 -04:00
}
int r , g , b ;
2014-06-09 23:28:32 -04:00
/* for historical reasons, colors are stored as 16 bit values.
*/
2011-08-30 05:48:53 -04:00
sscanf ( color . c_str ( ) , " %d:%d:%d " , & r , & g , & b ) ;
2014-06-09 23:28:32 -04:00
r / = 256 ;
g / = 256 ;
b / = 256 ;
return RGBA_TO_UINT ( r , g , b , 255 ) ;
2011-08-30 05:48:53 -04:00
}
2011-09-07 07:56:23 -04:00
void
GroupTabs : : route_group_property_changed ( RouteGroup * rg )
{
/* This is a bit of a hack, but this might change
our route ' s effective color , so emit gui_changed
for our routes .
*/
emit_gui_changed_for_members ( rg ) ;
2015-10-05 10:17:49 -04:00
2011-09-07 07:56:23 -04:00
set_dirty ( ) ;
}
void
2011-09-30 13:55:14 -04:00
GroupTabs : : route_added_to_route_group ( RouteGroup * , boost : : weak_ptr < Route > w )
2011-09-07 07:56:23 -04:00
{
/* Similarly-spirited hack as in route_group_property_changed */
2011-11-03 13:18:51 -04:00
2011-09-07 07:56:23 -04:00
boost : : shared_ptr < Route > r = w . lock ( ) ;
if ( ! r ) {
return ;
}
2016-06-05 17:16:20 -04:00
r - > presentation_info ( ) . PropertyChanged ( Properties : : color ) ;
2011-11-03 13:18:51 -04:00
set_dirty ( ) ;
2011-09-07 07:56:23 -04:00
}
void
2011-09-30 13:55:14 -04:00
GroupTabs : : route_removed_from_route_group ( RouteGroup * , boost : : weak_ptr < Route > w )
2011-09-07 07:56:23 -04:00
{
/* Similarly-spirited hack as in route_group_property_changed */
boost : : shared_ptr < Route > r = w . lock ( ) ;
if ( ! r ) {
return ;
}
2016-06-05 17:16:20 -04:00
r - > presentation_info ( ) . PropertyChanged ( Properties : : color ) ;
2011-11-03 13:18:51 -04:00
set_dirty ( ) ;
2011-09-07 07:56:23 -04:00
}
void
GroupTabs : : emit_gui_changed_for_members ( RouteGroup * rg )
{
for ( RouteList : : iterator i = rg - > route_list ( ) - > begin ( ) ; i ! = rg - > route_list ( ) - > end ( ) ; + + i ) {
( * i ) - > gui_changed ( X_ ( " color " ) , 0 ) ;
}
}