2018-11-15 10:21:55 -05:00
/*
2019-08-02 17:26:43 -04:00
* Copyright ( C ) 2018 - 2019 Ben Loftis < ben @ harrisonconsoles . com >
*
* 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 . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2018-11-15 10:21:55 -05:00
# include <cstdlib>
# include <cmath>
# include <algorithm>
# include <string>
# include <sstream>
# include "pbd/basename.h"
# include "pbd/enumwriter.h"
2019-08-01 17:04:55 -04:00
# include "pbd/file_utils.h"
2018-11-15 10:21:55 -05:00
# include "ardour/audioregion.h"
# include "ardour/source.h"
# include "ardour/audiofilesource.h"
# include "ardour/silentfilesource.h"
2019-08-01 17:04:55 -04:00
# include "ardour/smf_source.h"
2018-11-15 10:21:55 -05:00
# include "ardour/region_factory.h"
# include "ardour/session.h"
2018-12-07 13:44:15 -05:00
# include "ardour/session_directory.h"
2018-11-15 10:21:55 -05:00
# include "ardour/profile.h"
# include "gtkmm2ext/treeutils.h"
# include "gtkmm2ext/utils.h"
# include "widgets/choice.h"
# include "widgets/tooltips.h"
# include "audio_clock.h"
2019-05-31 14:36:46 -04:00
# include "context_menu_helper.h"
2018-11-15 10:21:55 -05:00
# include "editor.h"
# include "editing.h"
# include "editing_convert.h"
# include "keyboard.h"
# include "ardour_ui.h"
# include "gui_thread.h"
# include "actions.h"
# include "region_view.h"
# include "utils.h"
# include "editor_drag.h"
# include "main_clock.h"
# include "ui_config.h"
# include "pbd/i18n.h"
# include "editor_sources.h"
using namespace std ;
using namespace ARDOUR ;
using namespace ArdourWidgets ;
using namespace ARDOUR_UI_UTILS ;
using namespace PBD ;
using namespace Gtk ;
using namespace Glib ;
using namespace Editing ;
using Gtkmm2ext : : Keyboard ;
struct ColumnInfo {
int index ;
const char * label ;
const char * tooltip ;
} ;
EditorSources : : EditorSources ( Editor * e )
: EditorComponent ( e )
, old_focus ( 0 )
2019-08-01 16:27:21 -04:00
, tags_editable ( 0 )
2020-07-14 09:26:42 -04:00
, name_editable ( 0 )
2018-11-15 10:21:55 -05:00
{
_display . set_size_request ( 100 , - 1 ) ;
_display . set_rules_hint ( true ) ;
_display . set_name ( " SourcesList " ) ;
_display . set_fixed_height_mode ( true ) ;
/* Try to prevent single mouse presses from initiating edits.
This relies on a hack in gtktreeview . c : gtk_treeview_button_press ( )
*/
_display . set_data ( " mouse-edits-require-mod1 " , ( gpointer ) 0x1 ) ;
_model = TreeStore : : create ( _columns ) ;
_model - > set_sort_column ( 0 , SORT_ASCENDING ) ;
/* column widths */
2020-07-13 17:07:59 -04:00
int bbt_width , date_width , chan_width , height ;
2018-11-08 11:43:39 -05:00
2018-11-15 10:21:55 -05:00
Glib : : RefPtr < Pango : : Layout > layout = _display . create_pango_layout ( X_ ( " 000|000|000 " ) ) ;
Gtkmm2ext : : get_pixel_size ( layout , bbt_width , height ) ;
Glib : : RefPtr < Pango : : Layout > layout2 = _display . create_pango_layout ( X_ ( " 2018-10-14 12:12:30 " ) ) ;
Gtkmm2ext : : get_pixel_size ( layout2 , date_width , height ) ;
2020-07-14 08:58:12 -04:00
Glib : : RefPtr < Pango : : Layout > layout3 = _display . create_pango_layout ( X_ ( " Chans " ) ) ;
2020-07-13 17:07:59 -04:00
Gtkmm2ext : : get_pixel_size ( layout3 , chan_width , height ) ;
2018-11-15 10:21:55 -05:00
TreeViewColumn * col_name = manage ( new TreeViewColumn ( " " , _columns . name ) ) ;
col_name - > set_fixed_width ( bbt_width * 2 ) ;
col_name - > set_sizing ( TREE_VIEW_COLUMN_FIXED ) ;
2018-11-15 10:24:37 -05:00
col_name - > set_sort_column ( 0 ) ;
2018-11-15 10:21:55 -05:00
2020-07-13 17:07:59 -04:00
TreeViewColumn * col_chans = manage ( new TreeViewColumn ( " " , _columns . channels ) ) ;
col_chans - > set_fixed_width ( chan_width ) ;
col_chans - > set_sizing ( TREE_VIEW_COLUMN_FIXED ) ;
col_chans - > set_sort_column ( 1 ) ;
2020-07-14 08:58:12 -04:00
TreeViewColumn * captd_for = manage ( new TreeViewColumn ( " " , _columns . captd_for ) ) ;
captd_for - > set_fixed_width ( date_width ) ;
captd_for - > set_sizing ( TREE_VIEW_COLUMN_FIXED ) ;
captd_for - > set_sort_column ( 2 ) ;
2019-08-01 16:27:21 -04:00
TreeViewColumn * col_tags = manage ( new TreeViewColumn ( " " , _columns . tags ) ) ;
2020-07-14 08:58:12 -04:00
col_tags - > set_fixed_width ( date_width ) ;
2019-08-01 16:27:21 -04:00
col_tags - > set_sizing ( TREE_VIEW_COLUMN_FIXED ) ;
2020-07-14 08:58:12 -04:00
col_tags - > set_sort_column ( 3 ) ;
2019-08-01 16:27:21 -04:00
2018-11-15 10:21:55 -05:00
TreeViewColumn * col_take_id = manage ( new TreeViewColumn ( " " , _columns . take_id ) ) ;
col_take_id - > set_fixed_width ( date_width ) ;
col_take_id - > set_sizing ( TREE_VIEW_COLUMN_FIXED ) ;
2020-07-14 08:58:12 -04:00
col_take_id - > set_sort_column ( 4 ) ;
2018-11-15 10:24:37 -05:00
TreeViewColumn * col_nat_pos = manage ( new TreeViewColumn ( " " , _columns . natural_pos ) ) ;
col_nat_pos - > set_fixed_width ( bbt_width ) ;
col_nat_pos - > set_sizing ( TREE_VIEW_COLUMN_FIXED ) ;
2020-07-14 08:58:12 -04:00
col_nat_pos - > set_sort_column ( 9 ) ;
2018-11-15 10:21:55 -05:00
TreeViewColumn * col_path = manage ( new TreeViewColumn ( " " , _columns . path ) ) ;
col_path - > set_fixed_width ( bbt_width ) ;
col_path - > set_sizing ( TREE_VIEW_COLUMN_FIXED ) ;
2020-07-14 08:58:12 -04:00
col_path - > set_sort_column ( 6 ) ;
2018-11-15 10:21:55 -05:00
2021-02-14 10:20:36 -05:00
TreeViewColumn * captd_xruns = manage ( new TreeViewColumn ( " " , _columns . captd_xruns ) ) ;
captd_xruns - > set_fixed_width ( chan_width * 1.25 ) ;
captd_xruns - > set_sizing ( TREE_VIEW_COLUMN_FIXED ) ;
captd_xruns - > set_sort_column ( 10 ) ;
2018-11-15 10:21:55 -05:00
_display . append_column ( * col_name ) ;
2020-07-13 17:07:59 -04:00
_display . append_column ( * col_chans ) ;
2020-07-14 08:58:12 -04:00
_display . append_column ( * captd_for ) ;
2021-02-14 10:20:36 -05:00
_display . append_column ( * captd_xruns ) ;
2019-08-01 16:27:21 -04:00
_display . append_column ( * col_tags ) ;
2018-11-15 10:21:55 -05:00
_display . append_column ( * col_take_id ) ;
_display . append_column ( * col_nat_pos ) ;
_display . append_column ( * col_path ) ;
TreeViewColumn * col ;
Gtk : : Label * l ;
ColumnInfo ci [ ] = {
2021-02-14 10:20:36 -05:00
{ 0 , _ ( " Name " ) , _ ( " Region name " ) } ,
{ 1 , _ ( " # Ch " ) , _ ( " # Channels " ) } ,
2020-07-14 08:58:12 -04:00
{ 2 , _ ( " Captured For " ) , _ ( " Original Track this was recorded on " ) } ,
2021-02-14 10:20:36 -05:00
{ 3 , _ ( " # Xruns " ) , _ ( " Number of dropouts that occured during recording " ) } ,
{ 4 , _ ( " Tags " ) , _ ( " Tags " ) } ,
{ 5 , _ ( " Take ID " ) , _ ( " Take ID " ) } ,
{ 6 , _ ( " Orig Pos " ) , _ ( " Original Position of the file on timeline, when it was recorded " ) } ,
{ 7 , _ ( " Path " ) , _ ( " Path (folder) of the file location " ) } ,
2018-11-15 10:21:55 -05:00
{ - 1 , 0 , 0 }
} ;
2020-07-20 01:10:43 -04:00
/* make Name and Path columns manually resizable */
_display . get_column ( 0 ) - > set_resizable ( true ) ;
2021-02-14 10:20:36 -05:00
_display . get_column ( 5 ) - > set_resizable ( true ) ;
2020-07-20 01:10:43 -04:00
2018-11-15 10:21:55 -05:00
for ( int i = 0 ; ci [ i ] . index > = 0 ; + + i ) {
col = _display . get_column ( ci [ i ] . index ) ;
l = manage ( new Label ( ci [ i ] . label ) ) ;
set_tooltip ( * l , ci [ i ] . tooltip ) ;
col - > set_widget ( * l ) ;
l - > show ( ) ;
}
_display . set_model ( _model ) ;
_display . set_headers_visible ( true ) ;
_display . set_rules_hint ( ) ;
2020-07-14 10:57:53 -04:00
if ( UIConfiguration : : instance ( ) . get_use_tooltips ( ) ) {
/* show path as the row tooltip */
_display . set_tooltip_column ( 6 ) ; /* path */
}
2020-10-19 14:37:54 -04:00
2020-02-25 09:42:01 -05:00
/* set the color of the name field */
2018-11-15 10:21:55 -05:00
TreeViewColumn * tv_col = _display . get_column ( 0 ) ;
CellRendererText * renderer = dynamic_cast < CellRendererText * > ( _display . get_column_cell_renderer ( 0 ) ) ;
tv_col - > add_attribute ( renderer - > property_text ( ) , _columns . name ) ;
tv_col - > add_attribute ( renderer - > property_foreground_gdk ( ) , _columns . color_ ) ;
2018-11-15 10:24:37 -05:00
2020-07-14 09:26:42 -04:00
/* Name cell: make editable */
CellRendererText * region_name_cell = dynamic_cast < CellRendererText * > ( _display . get_column_cell_renderer ( 0 ) ) ;
region_name_cell - > property_editable ( ) = true ;
region_name_cell - > signal_edited ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : name_edit ) ) ;
region_name_cell - > signal_editing_started ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : name_editing_started ) ) ;
2020-02-25 09:42:01 -05:00
/* Tags cell: make editable */
2021-02-14 10:20:36 -05:00
CellRendererText * region_tags_cell = dynamic_cast < CellRendererText * > ( _display . get_column_cell_renderer ( 4 ) ) ;
2019-08-01 16:27:21 -04:00
region_tags_cell - > property_editable ( ) = true ;
region_tags_cell - > signal_edited ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : tag_edit ) ) ;
region_tags_cell - > signal_editing_started ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : tag_editing_started ) ) ;
2020-02-25 09:42:01 -05:00
/* right-align the Natural Pos column */
2021-02-14 10:20:36 -05:00
TreeViewColumn * nat_col = _display . get_column ( 6 ) ;
2018-11-15 10:24:37 -05:00
nat_col - > set_alignment ( ALIGN_RIGHT ) ;
2021-02-14 10:20:36 -05:00
renderer = dynamic_cast < CellRendererText * > ( _display . get_column_cell_renderer ( 6 ) ) ;
2018-11-15 10:24:37 -05:00
if ( renderer ) {
2020-07-26 11:17:33 -04:00
renderer - > property_xalign ( ) = 1.0 ;
2018-11-15 10:24:37 -05:00
}
2018-11-15 10:21:55 -05:00
2020-02-25 09:42:01 -05:00
/* the PATH field should expand when the pane is opened wider */
2021-02-14 10:20:36 -05:00
tv_col = _display . get_column ( 7 ) ;
renderer = dynamic_cast < CellRendererText * > ( _display . get_column_cell_renderer ( 7 ) ) ;
2018-11-15 10:21:55 -05:00
tv_col - > add_attribute ( renderer - > property_text ( ) , _columns . path ) ;
tv_col - > set_expand ( true ) ;
_display . get_selection ( ) - > set_mode ( SELECTION_MULTIPLE ) ;
2022-01-10 15:29:29 -05:00
_display . add_object_drag ( _columns . region . index ( ) , " x-ardour/region.esl " , TARGET_SAME_APP ) ;
2018-11-15 10:21:55 -05:00
_display . set_drag_column ( _columns . name . index ( ) ) ;
/* setup DnD handling */
2018-11-15 10:30:22 -05:00
list < TargetEntry > source_list_target_table ;
2018-11-15 10:21:55 -05:00
2018-11-15 10:30:22 -05:00
source_list_target_table . push_back ( TargetEntry ( " text/plain " ) ) ;
source_list_target_table . push_back ( TargetEntry ( " text/uri-list " ) ) ;
source_list_target_table . push_back ( TargetEntry ( " application/x-rootwin-drop " ) ) ;
2018-11-15 10:21:55 -05:00
2018-11-15 10:30:22 -05:00
_display . add_drop_targets ( source_list_target_table ) ;
2018-11-15 10:21:55 -05:00
_display . signal_drag_data_received ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : drag_data_received ) ) ;
_scroller . add ( _display ) ;
_scroller . set_policy ( POLICY_AUTOMATIC , POLICY_AUTOMATIC ) ;
_display . signal_button_press_event ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : button_press ) , false ) ;
_change_connection = _display . get_selection ( ) - > signal_changed ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : selection_changed ) ) ;
_scroller . signal_key_press_event ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : key_press ) , false ) ;
_scroller . signal_focus_in_event ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : focus_in ) , false ) ;
_scroller . signal_focus_out_event ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : focus_out ) ) ;
_display . signal_enter_notify_event ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : enter_notify ) , false ) ;
_display . signal_leave_notify_event ( ) . connect ( sigc : : mem_fun ( * this , & EditorSources : : leave_notify ) , false ) ;
2018-10-18 19:51:45 -04:00
ARDOUR_UI : : instance ( ) - > primary_clock - > mode_changed . connect ( sigc : : mem_fun ( * this , & EditorSources : : clock_format_changed ) ) ;
2018-11-15 10:21:55 -05:00
e - > EditorFreeze . connect ( editor_freeze_connection , MISSING_INVALIDATOR , boost : : bind ( & EditorSources : : freeze_tree_model , this ) , gui_context ( ) ) ;
e - > EditorThaw . connect ( editor_thaw_connection , MISSING_INVALIDATOR , boost : : bind ( & EditorSources : : thaw_tree_model , this ) , gui_context ( ) ) ;
}
bool
EditorSources : : focus_in ( GdkEventFocus * )
{
Window * win = dynamic_cast < Window * > ( _scroller . get_toplevel ( ) ) ;
if ( win ) {
old_focus = win - > get_focus ( ) ;
} else {
old_focus = 0 ;
}
2019-08-01 16:27:21 -04:00
tags_editable = 0 ;
2020-07-14 09:26:42 -04:00
name_editable = 0 ;
2019-08-01 16:27:21 -04:00
2018-11-15 10:21:55 -05:00
/* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
return true ;
}
bool
EditorSources : : focus_out ( GdkEventFocus * )
{
if ( old_focus ) {
old_focus - > grab_focus ( ) ;
old_focus = 0 ;
}
2019-08-01 16:27:21 -04:00
tags_editable = 0 ;
2020-07-14 09:26:42 -04:00
name_editable = 0 ;
2019-08-01 16:27:21 -04:00
2018-11-15 10:21:55 -05:00
return false ;
}
bool
EditorSources : : enter_notify ( GdkEventCrossing * )
{
2020-07-14 09:26:42 -04:00
if ( tags_editable | | name_editable ) {
2019-08-01 16:27:21 -04:00
return true ;
}
2018-11-15 10:21:55 -05:00
Keyboard : : magic_widget_grab_focus ( ) ;
return false ;
}
bool
EditorSources : : leave_notify ( GdkEventCrossing * )
{
if ( old_focus ) {
old_focus - > grab_focus ( ) ;
old_focus = 0 ;
}
Keyboard : : magic_widget_drop_focus ( ) ;
return false ;
}
void
EditorSources : : set_session ( ARDOUR : : Session * s )
{
SessionHandlePtr : : set_session ( s ) ;
2018-11-08 11:43:39 -05:00
2018-11-15 10:21:55 -05:00
if ( s ) {
2021-05-07 16:45:28 -04:00
ARDOUR : : Region : : RegionsPropertyChanged . connect ( source_property_connection , MISSING_INVALIDATOR , boost : : bind ( & EditorSources : : regions_changed , this , _1 , _2 ) , gui_context ( ) ) ;
2020-07-13 15:31:41 -04:00
2019-07-30 14:43:14 -04:00
ARDOUR : : RegionFactory : : CheckNewRegion . connect ( add_source_connection , MISSING_INVALIDATOR , boost : : bind ( & EditorSources : : add_source , this , _1 ) , gui_context ( ) ) ;
2019-12-25 12:00:57 -05:00
s - > SourceRemoved . connect ( remove_source_connection , MISSING_INVALIDATOR , boost : : bind ( & EditorSources : : remove_weak_source , this , _1 ) , gui_context ( ) ) ;
2019-05-31 14:36:46 -04:00
redisplay ( ) ;
2018-11-15 10:21:55 -05:00
} else {
2021-09-18 22:55:35 -04:00
source_property_connection . disconnect ( ) ;
add_source_connection . disconnect ( ) ;
remove_source_connection . disconnect ( ) ;
2018-11-08 11:43:39 -05:00
clear ( ) ;
2018-11-15 10:21:55 -05:00
}
}
2019-12-25 12:00:57 -05:00
void
EditorSources : : remove_weak_source ( boost : : weak_ptr < ARDOUR : : Source > src )
{
boost : : shared_ptr < ARDOUR : : Source > source = src . lock ( ) ;
if ( source ) {
remove_source ( source ) ;
}
}
2018-11-15 10:21:55 -05:00
void
2019-07-30 14:43:14 -04:00
EditorSources : : remove_source ( boost : : shared_ptr < ARDOUR : : Source > source )
2018-11-15 10:21:55 -05:00
{
TreeModel : : iterator i ;
TreeModel : : Children rows = _model - > children ( ) ;
for ( i = rows . begin ( ) ; i ! = rows . end ( ) ; + + i ) {
2019-05-31 14:36:46 -04:00
boost : : shared_ptr < ARDOUR : : Region > rr = ( * i ) [ _columns . region ] ;
2019-07-30 14:43:14 -04:00
if ( rr - > source ( ) = = source ) {
2018-11-15 10:21:55 -05:00
_model - > erase ( i ) ;
break ;
}
}
}
2020-02-25 09:36:53 -05:00
void
EditorSources : : remove_weak_region ( boost : : weak_ptr < ARDOUR : : Region > r )
{
boost : : shared_ptr < ARDOUR : : Region > region = r . lock ( ) ;
if ( ! region ) {
return ;
}
TreeModel : : Children rows = _model - > children ( ) ;
for ( TreeModel : : iterator i = rows . begin ( ) ; i ! = rows . end ( ) ; + + i ) {
boost : : shared_ptr < ARDOUR : : Region > rr = ( * i ) [ _columns . region ] ;
2020-03-06 17:51:00 -05:00
if ( rr = = region ) {
2020-02-25 09:36:53 -05:00
_model - > erase ( i ) ;
break ;
}
}
}
2018-11-15 10:21:55 -05:00
void
2019-05-31 14:36:46 -04:00
EditorSources : : populate_row ( TreeModel : : Row row , boost : : shared_ptr < ARDOUR : : Region > region )
2018-11-15 10:21:55 -05:00
{
2019-05-31 14:36:46 -04:00
ENSURE_GUI_THREAD ( * this , & ARDOUR_UI : : record_state_changed , row , region ) ;
2018-11-15 10:21:55 -05:00
2019-05-31 14:36:46 -04:00
if ( ! region ) {
2018-11-15 10:21:55 -05:00
return ;
}
2018-11-08 11:43:39 -05:00
2020-02-25 09:42:01 -05:00
boost : : shared_ptr < ARDOUR : : Source > source = region - > source ( ) ; // ToDo: is it OK to use only the first source?
2018-11-15 10:21:55 -05:00
2020-02-25 09:42:01 -05:00
/* COLOR (for missing files) */
2019-05-31 14:36:46 -04:00
Gdk : : Color c ;
2018-11-15 10:21:55 -05:00
bool missing_source = boost : : dynamic_pointer_cast < SilentFileSource > ( source ) ! = NULL ;
if ( missing_source ) {
set_color_from_rgba ( c , UIConfiguration : : instance ( ) . color ( " region list missing source " ) ) ;
} else {
set_color_from_rgba ( c , UIConfiguration : : instance ( ) . color ( " region list whole file " ) ) ;
}
row [ _columns . color_ ] = c ;
2020-02-25 09:42:01 -05:00
/* NAME */
2020-07-13 17:07:59 -04:00
row [ _columns . name ] = region - > name ( ) ;
2020-07-14 08:58:12 -04:00
/* N CHANNELS */
2020-07-14 10:57:53 -04:00
if ( region - > data_type ( ) = = DataType : : MIDI ) {
row [ _columns . channels ] = 0 ; /*TODO: some better recognition of midi regions*/
} else {
2020-10-19 14:37:54 -04:00
row [ _columns . channels ] = region - > sources ( ) . size ( ) ;
2020-07-14 10:57:53 -04:00
}
2020-10-19 14:37:54 -04:00
2020-07-14 08:58:12 -04:00
/* CAPTURED FOR */
row [ _columns . captd_for ] = source - > captured_for ( ) ;
2021-02-14 10:20:36 -05:00
/* CAPTURED DROPOUTS */
row [ _columns . captd_xruns ] = source - > n_captured_xruns ( ) ;
2020-02-25 09:42:01 -05:00
/* TAGS */
2019-08-01 16:27:21 -04:00
row [ _columns . tags ] = region - > tags ( ) ;
2019-05-31 14:36:46 -04:00
row [ _columns . region ] = region ;
row [ _columns . take_id ] = source - > take_id ( ) ;
2020-02-25 09:42:01 -05:00
/* PATH */
2019-08-01 17:04:55 -04:00
string pathstr = source - > name ( ) ;
2018-11-15 10:21:55 -05:00
if ( missing_source ) {
2019-08-01 17:04:55 -04:00
pathstr = _ ( " (MISSING) " ) + Gtkmm2ext : : markup_escape_text ( source - > name ( ) ) ;
2018-11-15 10:21:55 -05:00
} else {
2020-02-25 09:42:01 -05:00
/* is it a file? */
2018-11-15 10:21:55 -05:00
boost : : shared_ptr < FileSource > fs = boost : : dynamic_pointer_cast < FileSource > ( source ) ;
2019-08-01 17:04:55 -04:00
if ( ! fs ) {
2020-02-25 09:42:01 -05:00
pathstr = Gtkmm2ext : : markup_escape_text ( source - > name ( ) ) ; // someday: sequence region(?)
2018-11-15 10:21:55 -05:00
} else {
2020-02-25 09:42:01 -05:00
/* audio file? */
2019-08-01 17:04:55 -04:00
boost : : shared_ptr < AudioFileSource > afs = boost : : dynamic_pointer_cast < AudioFileSource > ( source ) ;
if ( afs ) {
const string audio_directory = _session - > session_directory ( ) . sound_path ( ) ;
2020-07-26 11:17:33 -04:00
if ( ! PBD : : path_is_within ( audio_directory , fs - > path ( ) ) ) {
2019-08-01 17:04:55 -04:00
pathstr = Gtkmm2ext : : markup_escape_text ( fs - > path ( ) ) ;
}
}
2020-02-25 09:42:01 -05:00
/* midi file? */
2019-08-01 17:04:55 -04:00
boost : : shared_ptr < SMFSource > mfs = boost : : dynamic_pointer_cast < SMFSource > ( source ) ;
if ( mfs ) {
const string midi_directory = _session - > session_directory ( ) . midi_path ( ) ;
2020-07-26 11:17:33 -04:00
if ( ! PBD : : path_is_within ( midi_directory , fs - > path ( ) ) ) {
2019-08-01 17:04:55 -04:00
pathstr = Gtkmm2ext : : markup_escape_text ( fs - > path ( ) ) ;
}
}
2018-11-15 10:21:55 -05:00
}
}
2020-02-25 09:42:01 -05:00
2019-08-01 17:04:55 -04:00
row [ _columns . path ] = pathstr ;
2018-11-15 10:21:55 -05:00
2020-02-25 09:42:01 -05:00
/* Natural Position (samples, an invisible column for sorting) */
2018-11-15 10:24:37 -05:00
row [ _columns . natural_s ] = source - > natural_position ( ) ;
2020-02-25 09:42:01 -05:00
/* Natural Position (text representation) */
2018-11-15 10:33:44 -05:00
if ( source - > have_natural_position ( ) ) {
char buf [ 64 ] ;
2018-11-15 10:21:55 -05:00
format_position ( source - > natural_position ( ) , buf , sizeof ( buf ) ) ;
2018-11-15 10:33:44 -05:00
row [ _columns . natural_pos ] = buf ;
} else {
row [ _columns . natural_pos ] = X_ ( " -- " ) ;
2018-11-15 10:21:55 -05:00
}
}
void
2019-05-31 14:36:46 -04:00
EditorSources : : redisplay ( )
2018-11-15 10:21:55 -05:00
{
2020-02-25 09:36:53 -05:00
remove_region_connections . drop_connections ( ) ;
2019-05-31 14:36:46 -04:00
_display . set_model ( Glib : : RefPtr < Gtk : : TreeStore > ( 0 ) ) ;
_model - > clear ( ) ;
2020-02-25 09:42:01 -05:00
_model - > set_sort_column ( - 2 , SORT_ASCENDING ) ; // Disable sorting to gain performance
2019-05-31 14:36:46 -04:00
2020-02-25 09:42:01 -05:00
/* Ask the region factory to fill our list of whole-file regions */
2019-05-31 14:36:46 -04:00
RegionFactory : : foreach_region ( sigc : : mem_fun ( * this , & EditorSources : : add_source ) ) ;
_model - > set_sort_column ( 0 , SORT_ASCENDING ) ; // re-enable sorting
_display . set_model ( _model ) ;
}
2018-11-15 10:21:55 -05:00
2019-05-31 14:36:46 -04:00
void
EditorSources : : add_source ( boost : : shared_ptr < ARDOUR : : Region > region )
{
2020-07-26 11:17:33 -04:00
if ( ! region | | ! _session ) {
2019-05-31 14:36:46 -04:00
return ;
}
2020-02-25 09:42:01 -05:00
/* by definition, the Source List only shows whole-file regions
* this roughly equates to Source objects , but preserves the stereo - ness
* ( or multichannel - ness ) of a stereo source file .
*/
2020-07-26 11:17:33 -04:00
if ( ! region - > whole_file ( ) ) {
2019-05-31 14:36:46 -04:00
return ;
}
2020-02-25 09:42:01 -05:00
/* we only show files-on-disk.
* if there ' s some other kind of source , we ignore it ( for now )
*/
2019-05-31 14:36:46 -04:00
boost : : shared_ptr < FileSource > fs = boost : : dynamic_pointer_cast < FileSource > ( region - > source ( ) ) ;
2021-08-28 17:28:41 -04:00
if ( ! fs ) {
2018-11-15 10:21:55 -05:00
return ;
}
2021-08-28 17:28:41 -04:00
if ( fs - > empty ( ) ) {
/* MIDI sources are allowed to be empty */
if ( ! boost : : dynamic_pointer_cast < MidiSource > ( region - > source ( ) ) ) {
return ;
}
}
2020-02-25 09:36:53 -05:00
region - > DropReferences . connect ( remove_region_connections , MISSING_INVALIDATOR , boost : : bind ( & EditorSources : : remove_weak_region , this , boost : : weak_ptr < Region > ( region ) ) , gui_context ( ) ) ;
2021-08-28 17:29:44 -04:00
PropertyChange pc ;
boost : : shared_ptr < RegionList > rl ( new RegionList ) ;
rl - > push_back ( region ) ;
regions_changed ( rl , pc ) ;
2018-11-15 10:21:55 -05:00
}
void
2021-05-07 16:45:28 -04:00
EditorSources : : regions_changed ( boost : : shared_ptr < ARDOUR : : RegionList > rl , PBD : : PropertyChange const & )
2018-11-15 10:21:55 -05:00
{
2021-05-07 17:15:47 -04:00
bool freeze = rl - > size ( ) > 2 ;
if ( freeze ) {
freeze_tree_model ( ) ;
}
2021-08-28 17:29:44 -04:00
2021-05-07 16:45:28 -04:00
for ( RegionList : : const_iterator r = rl - > begin ( ) ; r ! = rl - > end ( ) ; + + r ) {
boost : : shared_ptr < Region > region = * r ;
2020-02-25 09:42:01 -05:00
2021-05-07 16:45:28 -04:00
if ( ! region - > whole_file ( ) ) {
/*this isn't on our list anyway; we can ignore it*/
2021-05-25 16:51:44 -04:00
break ;
2021-05-07 16:45:28 -04:00
}
2018-11-15 10:33:44 -05:00
2021-05-07 16:45:28 -04:00
TreeModel : : iterator i ;
TreeModel : : Children rows = _model - > children ( ) ;
for ( i = rows . begin ( ) ; i ! = rows . end ( ) ; + + i ) {
boost : : shared_ptr < ARDOUR : : Region > rr = ( * i ) [ _columns . region ] ;
if ( region = = rr ) {
populate_row ( * i , region ) ;
break ;
}
2018-11-15 10:21:55 -05:00
}
2021-08-28 17:29:44 -04:00
if ( i = = rows . end ( ) ) {
TreeModel : : Row row = * ( _model - > append ( ) ) ;
populate_row ( row , region ) ;
}
2018-11-15 10:21:55 -05:00
}
2021-08-28 17:29:44 -04:00
2021-05-07 17:15:47 -04:00
if ( freeze ) {
thaw_tree_model ( ) ;
}
2018-11-15 10:21:55 -05:00
}
void
EditorSources : : selection_changed ( )
{
if ( _display . get_selection ( ) - > count_selected_rows ( ) > 0 ) {
TreeIter iter ;
TreeView : : Selection : : ListHandle_Path rows = _display . get_selection ( ) - > get_selected_rows ( ) ;
_editor - > get_selection ( ) . clear_regions ( ) ;
for ( TreeView : : Selection : : ListHandle_Path : : iterator i = rows . begin ( ) ; i ! = rows . end ( ) ; + + i ) {
if ( ( iter = _model - > get_iter ( * i ) ) ) {
2020-02-25 09:42:01 -05:00
/* highlight any regions in the editor that use this region's source */
2020-10-19 14:37:54 -04:00
boost : : shared_ptr < ARDOUR : : Region > region = ( * iter ) [ _columns . region ] ;
if ( ! region ) continue ;
2019-05-31 14:36:46 -04:00
2020-10-19 14:37:54 -04:00
boost : : shared_ptr < ARDOUR : : Source > source = region - > source ( ) ;
2018-11-15 10:24:37 -05:00
if ( source ) {
2018-11-15 10:21:55 -05:00
2018-11-15 10:24:37 -05:00
set < boost : : shared_ptr < Region > > regions ;
2020-07-26 11:17:33 -04:00
RegionFactory : : get_regions_using_source ( source , regions ) ;
2018-11-15 10:21:55 -05:00
2020-07-26 11:17:33 -04:00
for ( set < boost : : shared_ptr < Region > > : : iterator region = regions . begin ( ) ; region ! = regions . end ( ) ; region + + ) {
2018-11-15 10:24:37 -05:00
_change_connection . block ( true ) ;
_editor - > set_selected_regionview_from_region_list ( * region , Selection : : Add ) ;
_change_connection . block ( false ) ;
2018-11-08 11:43:39 -05:00
2018-11-15 10:24:37 -05:00
}
2018-11-15 10:21:55 -05:00
}
}
}
} else {
_editor - > get_selection ( ) . clear_regions ( ) ;
}
}
void
2018-10-18 19:51:45 -04:00
EditorSources : : clock_format_changed ( )
2018-11-15 10:21:55 -05:00
{
2018-11-15 10:24:37 -05:00
TreeModel : : iterator i ;
TreeModel : : Children rows = _model - > children ( ) ;
for ( i = rows . begin ( ) ; i ! = rows . end ( ) ; + + i ) {
2019-05-31 14:36:46 -04:00
boost : : shared_ptr < ARDOUR : : Region > rr = ( * i ) [ _columns . region ] ;
populate_row ( * i , rr ) ;
2018-11-15 10:21:55 -05:00
}
}
void
2020-10-19 14:37:54 -04:00
EditorSources : : format_position ( timepos_t const & pos , char * buf , size_t bufsize , bool onoff )
2018-11-15 10:21:55 -05:00
{
2020-07-23 19:46:49 -04:00
Temporal : : BBT_Time bbt ;
2018-11-15 10:21:55 -05:00
Timecode : : Time timecode ;
2021-12-11 09:51:31 -05:00
if ( pos . is_negative ( ) ) {
2018-11-15 10:21:55 -05:00
error < < string_compose ( _ ( " EditorSources::format_position: negative timecode position: %1 " ) , pos ) < < endmsg ;
snprintf ( buf , bufsize , " invalid " ) ;
return ;
}
switch ( ARDOUR_UI : : instance ( ) - > primary_clock - > mode ( ) ) {
case AudioClock : : BBT :
2021-01-15 02:59:12 -05:00
bbt = Temporal : : TempoMap : : use ( ) - > bbt_at ( pos ) ;
if ( onoff ) {
snprintf ( buf , bufsize , " %03d|%02d|%04d " , bbt . bars , bbt . beats , bbt . ticks ) ;
} else {
snprintf ( buf , bufsize , " (%03d|%02d|%04d) " , bbt . bars , bbt . beats , bbt . ticks ) ;
}
2018-11-15 10:21:55 -05:00
break ;
case AudioClock : : MinSec :
samplepos_t left ;
int hrs ;
int mins ;
float secs ;
2020-10-19 14:37:54 -04:00
left = pos . samples ( ) ;
2018-11-15 10:21:55 -05:00
hrs = ( int ) floor ( left / ( _session - > sample_rate ( ) * 60.0f * 60.0f ) ) ;
left - = ( samplecnt_t ) floor ( hrs * _session - > sample_rate ( ) * 60.0f * 60.0f ) ;
mins = ( int ) floor ( left / ( _session - > sample_rate ( ) * 60.0f ) ) ;
left - = ( samplecnt_t ) floor ( mins * _session - > sample_rate ( ) * 60.0f ) ;
secs = left / ( float ) _session - > sample_rate ( ) ;
if ( onoff ) {
snprintf ( buf , bufsize , " %02d:%02d:%06.3f " , hrs , mins , secs ) ;
} else {
snprintf ( buf , bufsize , " (%02d:%02d:%06.3f) " , hrs , mins , secs ) ;
}
break ;
case AudioClock : : Seconds :
if ( onoff ) {
2020-10-19 14:37:54 -04:00
snprintf ( buf , bufsize , " %.1f " , pos . samples ( ) / ( float ) _session - > sample_rate ( ) ) ;
2018-11-15 10:21:55 -05:00
} else {
2020-10-19 14:37:54 -04:00
snprintf ( buf , bufsize , " (%.1f) " , pos . samples ( ) / ( float ) _session - > sample_rate ( ) ) ;
2018-11-15 10:21:55 -05:00
}
break ;
case AudioClock : : Samples :
if ( onoff ) {
2020-10-19 14:37:54 -04:00
snprintf ( buf , bufsize , " % " PRId64 , pos . samples ( ) ) ;
2018-11-15 10:21:55 -05:00
} else {
2020-10-19 14:37:54 -04:00
snprintf ( buf , bufsize , " (% " PRId64 " ) " , pos . samples ( ) ) ;
2018-11-15 10:21:55 -05:00
}
break ;
case AudioClock : : Timecode :
default :
2020-10-19 14:37:54 -04:00
_session - > timecode_time ( pos . samples ( ) , timecode ) ;
2018-11-15 10:21:55 -05:00
if ( onoff ) {
snprintf ( buf , bufsize , " %02d:%02d:%02d:%02d " , timecode . hours , timecode . minutes , timecode . seconds , timecode . frames ) ;
} else {
snprintf ( buf , bufsize , " (%02d:%02d:%02d:%02d) " , timecode . hours , timecode . minutes , timecode . seconds , timecode . frames ) ;
}
break ;
}
}
void
EditorSources : : show_context_menu ( int button , int time )
{
2019-05-31 14:36:46 -04:00
using namespace Gtk : : Menu_Helpers ;
Gtk : : Menu * menu = ARDOUR_UI_UTILS : : shared_popup_menu ( ) ;
MenuList & items = menu - > items ( ) ;
2019-06-06 21:28:40 -04:00
# ifdef RECOVER_REGIONS_IS_WORKING
2019-05-31 14:36:46 -04:00
items . push_back ( MenuElem ( _ ( " Recover the selected Sources to their original Track & Position " ) ,
sigc : : mem_fun ( * this , & EditorSources : : recover_selected_sources ) ) ) ;
2019-06-06 21:28:40 -04:00
# endif
2019-05-31 14:36:46 -04:00
items . push_back ( MenuElem ( _ ( " Remove the selected Sources " ) ,
sigc : : mem_fun ( * this , & EditorSources : : remove_selected_sources ) ) ) ;
menu - > popup ( 1 , time ) ;
}
2018-11-15 10:21:55 -05:00
2019-05-31 14:36:46 -04:00
void
EditorSources : : recover_selected_sources ( )
{
2019-06-06 21:28:40 -04:00
ARDOUR : : RegionList to_be_recovered ;
2020-02-25 09:42:01 -05:00
2019-05-31 14:36:46 -04:00
if ( _display . get_selection ( ) - > count_selected_rows ( ) > 0 ) {
TreeIter iter ;
TreeView : : Selection : : ListHandle_Path rows = _display . get_selection ( ) - > get_selected_rows ( ) ;
for ( TreeView : : Selection : : ListHandle_Path : : iterator i = rows . begin ( ) ; i ! = rows . end ( ) ; + + i ) {
if ( ( iter = _model - > get_iter ( * i ) ) ) {
boost : : shared_ptr < ARDOUR : : Region > region = ( * iter ) [ _columns . region ] ;
if ( region ) {
to_be_recovered . push_back ( region ) ;
}
}
}
}
/* ToDo */
2020-02-25 09:42:01 -05:00
_editor - > recover_regions ( to_be_recovered ) ; // this operation should be undo-able
2018-11-15 10:21:55 -05:00
}
2018-10-22 17:46:44 -04:00
void
EditorSources : : remove_selected_sources ( )
{
vector < string > choices ;
string prompt ;
2018-11-08 14:07:52 -05:00
prompt = _ ( " Do you want to remove the selected Sources? "
" \n This operation cannot be undone. "
" \n The source files will not actually be deleted until you execute Session->Cleanup. " ) ;
2018-10-22 17:46:44 -04:00
choices . push_back ( _ ( " No, do nothing. " ) ) ;
2018-11-08 14:07:52 -05:00
choices . push_back ( _ ( " Only remove the Regions that use these Sources. " ) ) ;
2020-04-15 12:02:21 -04:00
choices . push_back ( _ ( " Yes, remove the Regions and Sources (cannot be undone!) " ) ) ;
2018-10-22 17:46:44 -04:00
2018-11-08 14:07:52 -05:00
Choice prompter ( _ ( " Remove selected Sources " ) , prompt , choices ) ;
2018-10-22 17:46:44 -04:00
int opt = prompter . run ( ) ;
2020-07-26 11:17:33 -04:00
if ( opt > = 1 ) {
2020-02-25 09:42:01 -05:00
2018-11-08 14:07:52 -05:00
std : : list < boost : : weak_ptr < ARDOUR : : Source > > to_be_removed ;
2020-02-25 09:42:01 -05:00
2018-10-22 17:46:44 -04:00
if ( _display . get_selection ( ) - > count_selected_rows ( ) > 0 ) {
TreeIter iter ;
TreeView : : Selection : : ListHandle_Path rows = _display . get_selection ( ) - > get_selected_rows ( ) ;
_editor - > get_selection ( ) . clear_regions ( ) ;
for ( TreeView : : Selection : : ListHandle_Path : : iterator i = rows . begin ( ) ; i ! = rows . end ( ) ; + + i ) {
if ( ( iter = _model - > get_iter ( * i ) ) ) {
2019-05-31 14:36:46 -04:00
boost : : shared_ptr < ARDOUR : : Region > region = ( * iter ) [ _columns . region ] ;
2020-02-25 09:42:01 -05:00
2020-10-19 14:37:54 -04:00
if ( ! region ) continue ;
2018-10-22 17:46:44 -04:00
2020-10-19 14:37:54 -04:00
boost : : shared_ptr < ARDOUR : : Source > source = region - > source ( ) ;
2019-05-31 14:36:46 -04:00
if ( source ) {
2018-10-22 17:46:44 -04:00
set < boost : : shared_ptr < Region > > regions ;
2020-07-26 11:17:33 -04:00
RegionFactory : : get_regions_using_source ( source , regions ) ;
2018-10-22 17:46:44 -04:00
2020-07-26 11:17:33 -04:00
for ( set < boost : : shared_ptr < Region > > : : iterator region = regions . begin ( ) ; region ! = regions . end ( ) ; region + + ) {
2018-10-22 17:46:44 -04:00
_change_connection . block ( true ) ;
_editor - > set_selected_regionview_from_region_list ( * region , Selection : : Add ) ;
_change_connection . block ( false ) ;
}
2020-02-25 09:42:01 -05:00
2018-11-08 14:07:52 -05:00
to_be_removed . push_back ( source ) ;
2018-10-22 17:46:44 -04:00
}
}
}
2021-11-19 10:14:46 -05:00
_editor - > remove_regions ( _editor - > get_regions_from_selection_and_entered ( ) , false /*can_ripple*/ , false /*as_part_of_other_command*/ ) ; // this operation is undo-able
2018-11-08 14:07:52 -05:00
2020-02-25 09:42:01 -05:00
if ( opt = = 2 ) {
2018-11-08 14:07:52 -05:00
for ( std : : list < boost : : weak_ptr < ARDOUR : : Source > > : : iterator i = to_be_removed . begin ( ) ; i ! = to_be_removed . end ( ) ; + + i ) {
2020-02-25 09:42:01 -05:00
_session - > remove_source ( * i ) ; // this operation is (currently) not undo-able
2018-11-08 14:07:52 -05:00
}
}
2018-10-22 17:46:44 -04:00
}
}
}
2018-11-15 10:21:55 -05:00
bool
EditorSources : : key_press ( GdkEventKey * ev )
{
2019-08-01 16:27:21 -04:00
TreeViewColumn * col ;
2018-10-22 17:46:44 -04:00
switch ( ev - > keyval ) {
2019-08-01 16:27:21 -04:00
case GDK_Tab :
case GDK_ISO_Left_Tab :
if ( tags_editable ) {
tags_editable - > editing_done ( ) ;
tags_editable = 0 ;
}
2020-07-14 09:26:42 -04:00
if ( name_editable ) {
name_editable - > editing_done ( ) ;
name_editable = 0 ;
}
2019-08-01 16:27:21 -04:00
col = _display . get_column ( 1 ) ; // select&focus on tags column
if ( Keyboard : : modifier_state_equals ( ev - > state , Keyboard : : TertiaryModifier ) ) {
treeview_select_previous ( _display , _model , col ) ;
} else {
treeview_select_next ( _display , _model , col ) ;
}
return true ;
break ;
2018-10-22 17:46:44 -04:00
case GDK_BackSpace :
2018-11-08 14:07:52 -05:00
remove_selected_sources ( ) ;
2020-02-25 09:42:01 -05:00
return true ;
2019-08-01 16:27:21 -04:00
default :
break ;
2018-10-22 17:46:44 -04:00
}
2018-11-08 11:43:39 -05:00
2018-11-15 10:24:37 -05:00
return false ;
2018-11-15 10:21:55 -05:00
}
bool
EditorSources : : button_press ( GdkEventButton * ev )
{
if ( Keyboard : : is_context_menu_event ( ev ) ) {
show_context_menu ( ev - > button , ev - > time ) ;
2020-03-31 15:00:45 -04:00
return true ;
2018-11-15 10:21:55 -05:00
}
return false ;
}
2019-08-01 16:27:21 -04:00
void
EditorSources : : tag_editing_started ( CellEditable * ce , const Glib : : ustring & path )
{
tags_editable = ce ;
/* give it a special name */
Gtk : : Entry * e = dynamic_cast < Gtk : : Entry * > ( ce ) ;
if ( e ) {
e - > set_name ( X_ ( " SourceTagEditorEntry " ) ) ;
TreeIter iter ;
if ( ( iter = _model - > get_iter ( path ) ) ) {
boost : : shared_ptr < Region > region = ( * iter ) [ _columns . region ] ;
if ( region ) {
e - > set_text ( region - > tags ( ) ) ;
}
}
}
}
void
EditorSources : : tag_edit ( const std : : string & path , const std : : string & new_text )
{
tags_editable = 0 ;
boost : : shared_ptr < Region > region ;
TreeIter row_iter ;
if ( ( row_iter = _model - > get_iter ( path ) ) ) {
region = ( * row_iter ) [ _columns . region ] ;
( * row_iter ) [ _columns . tags ] = new_text ;
}
if ( region ) {
region - > set_tags ( new_text ) ;
2020-02-25 09:42:01 -05:00
_session - > set_dirty ( ) ; // whole-file regions aren't in a playlist to catch property changes, so we need to explicitly set the session dirty
2020-07-14 09:26:42 -04:00
populate_row ( ( * row_iter ) , region ) ;
}
}
void
EditorSources : : name_editing_started ( CellEditable * ce , const Glib : : ustring & path )
{
name_editable = ce ;
/* give it a special name */
Gtk : : Entry * e = dynamic_cast < Gtk : : Entry * > ( ce ) ;
if ( e ) {
e - > set_name ( X_ ( " SourceNameEditorEntry " ) ) ;
TreeIter iter ;
if ( ( iter = _model - > get_iter ( path ) ) ) {
boost : : shared_ptr < Region > region = ( * iter ) [ _columns . region ] ;
if ( region ) {
e - > set_text ( region - > name ( ) ) ;
}
}
}
}
void
EditorSources : : name_edit ( const std : : string & path , const std : : string & new_text )
{
name_editable = 0 ;
boost : : shared_ptr < Region > region ;
TreeIter row_iter ;
if ( ( row_iter = _model - > get_iter ( path ) ) ) {
region = ( * row_iter ) [ _columns . region ] ;
( * row_iter ) [ _columns . name ] = new_text ;
}
if ( region ) {
region - > set_name ( new_text ) ;
_session - > set_dirty ( ) ; // whole-file regions aren't in a playlist to catch property changes, so we need to explicitly set the session dirty
2019-08-01 16:27:21 -04:00
populate_row ( ( * row_iter ) , region ) ;
}
}
2018-11-15 10:21:55 -05:00
void
EditorSources : : drag_data_received ( const RefPtr < Gdk : : DragContext > & context ,
int x , int y ,
const SelectionData & data ,
2022-01-10 17:53:07 -05:00
guint info , guint dtime )
2018-11-15 10:21:55 -05:00
{
2022-01-10 17:53:07 -05:00
vector < string > paths ;
if ( data . get_target ( ) = = " GTK_TREE_MODEL_ROW " ) {
/* something is being dragged over the source list */
_editor - > _drags - > abort ( ) ;
_display . on_drag_data_received ( context , x , y , data , info , dtime ) ;
return ;
}
if ( _session & & convert_drop_to_paths ( paths , data ) ) {
timepos_t pos ;
bool copy = ( ( context - > get_actions ( ) & ( Gdk : : ACTION_COPY | Gdk : : ACTION_LINK | Gdk : : ACTION_MOVE ) ) = = Gdk : : ACTION_COPY ) ;
if ( UIConfiguration : : instance ( ) . get_only_copy_imported_files ( ) | | copy ) {
_editor - > do_import ( paths , Editing : : ImportDistinctFiles , Editing : : ImportAsRegion ,
SrcBest , SMFTrackName , SMFTempoIgnore , pos ) ;
} else {
_editor - > do_embed ( paths , Editing : : ImportDistinctFiles , ImportAsRegion , pos ) ;
}
context - > drag_finish ( true , false , dtime ) ;
}
2018-11-15 10:21:55 -05:00
}
/** @return Region that has been dragged out of the list, or 0 */
2019-05-31 14:36:46 -04:00
boost : : shared_ptr < ARDOUR : : Region >
EditorSources : : get_dragged_region ( )
2018-11-15 10:21:55 -05:00
{
2019-05-31 14:36:46 -04:00
list < boost : : shared_ptr < ARDOUR : : Region > > regions ;
TreeView * region ;
_display . get_object_drag_data ( regions , & region ) ;
2018-11-15 10:21:55 -05:00
2019-05-31 14:36:46 -04:00
if ( regions . empty ( ) ) {
return boost : : shared_ptr < ARDOUR : : Region > ( ) ;
2018-11-15 10:24:37 -05:00
}
2019-05-31 14:36:46 -04:00
assert ( regions . size ( ) = = 1 ) ;
return regions . front ( ) ;
2018-11-15 10:21:55 -05:00
}
void
EditorSources : : clear ( )
{
2020-02-25 09:36:53 -05:00
remove_region_connections . drop_connections ( ) ;
2018-11-15 10:21:55 -05:00
_display . set_model ( Glib : : RefPtr < Gtk : : TreeStore > ( 0 ) ) ;
_model - > clear ( ) ;
_display . set_model ( _model ) ;
}
2019-05-31 14:36:46 -04:00
boost : : shared_ptr < ARDOUR : : Region >
2018-11-15 10:21:55 -05:00
EditorSources : : get_single_selection ( )
{
2018-11-15 10:24:37 -05:00
Glib : : RefPtr < TreeSelection > selected = _display . get_selection ( ) ;
if ( selected - > count_selected_rows ( ) ! = 1 ) {
2019-05-31 14:36:46 -04:00
return boost : : shared_ptr < ARDOUR : : Region > ( ) ;
2018-11-15 10:24:37 -05:00
}
TreeView : : Selection : : ListHandle_Path rows = selected - > get_selected_rows ( ) ;
/* only one row selected, so rows.begin() is it */
2018-11-15 10:21:55 -05:00
2018-11-15 10:24:37 -05:00
TreeIter iter = _model - > get_iter ( * rows . begin ( ) ) ;
if ( ! iter ) {
2019-05-31 14:36:46 -04:00
return boost : : shared_ptr < ARDOUR : : Region > ( ) ;
2018-11-15 10:24:37 -05:00
}
2019-05-31 14:36:46 -04:00
return ( * iter ) [ _columns . region ] ;
2018-11-15 10:21:55 -05:00
}
void
EditorSources : : freeze_tree_model ( )
{
2021-05-07 17:15:47 -04:00
/* store sort column id and type for later */
_model - > get_sort_column_id ( _sort_col_id , _sort_type ) ;
_change_connection . block ( true ) ;
2018-11-15 10:21:55 -05:00
_display . set_model ( Glib : : RefPtr < Gtk : : TreeStore > ( 0 ) ) ;
2020-02-25 09:42:01 -05:00
_model - > set_sort_column ( - 2 , SORT_ASCENDING ) ; // Disable sorting to gain performance
2018-11-15 10:21:55 -05:00
}
void
2021-05-07 17:15:47 -04:00
EditorSources : : thaw_tree_model ( )
{
_model - > set_sort_column ( _sort_col_id , _sort_type ) ; // re-enabale sorting
2018-11-15 10:21:55 -05:00
_display . set_model ( _model ) ;
2021-05-07 17:15:47 -04:00
_change_connection . block ( false ) ;
2018-11-15 10:21:55 -05:00
}
XMLNode &
EditorSources : : get_state ( ) const
{
XMLNode * node = new XMLNode ( X_ ( " SourcesList " ) ) ;
2020-02-25 09:42:01 -05:00
//TODO: save sort state?
2018-11-15 10:21:55 -05:00
return * node ;
}
void
EditorSources : : set_state ( const XMLNode & node )
{
}