Timeline: Add option to import source at mouse via timeline context menu (as an alternative to DND)
Closes #211.
This commit is contained in:
parent
1daf0f6150
commit
10c31e5729
|
@ -253,6 +253,95 @@ Audio_Sequence::draw ( void )
|
||||||
fl_pop_clip();
|
fl_pop_clip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Audio_Sequence::handle_paste ( const char *text )
|
||||||
|
{
|
||||||
|
int X = Fl::event_x();
|
||||||
|
|
||||||
|
if ( ! strcmp( text, "Audio_Region" ) )
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
char *file;
|
||||||
|
|
||||||
|
if ( ! sscanf( text, "file://%m[^\r\n]\n", &file ) )
|
||||||
|
{
|
||||||
|
WARNING( "invalid drop \"%s\"\n", text );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unescape_url( file );
|
||||||
|
|
||||||
|
printf( "pasted file \"%s\"\n", file );
|
||||||
|
|
||||||
|
fl_cursor( FL_CURSOR_WAIT );
|
||||||
|
Fl::check();
|
||||||
|
|
||||||
|
char *t = strdup( file );
|
||||||
|
|
||||||
|
char *filebase = strdup( basename( t ) );
|
||||||
|
|
||||||
|
free( t );
|
||||||
|
|
||||||
|
char *s = 0;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for ( ; ; i++ )
|
||||||
|
{
|
||||||
|
if ( i )
|
||||||
|
{
|
||||||
|
free( s );
|
||||||
|
asprintf( &s, "sources/%s-%i", filebase, i );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
asprintf( &s, "sources/%s", filebase );
|
||||||
|
|
||||||
|
DMESSAGE( "Symlink %s -> %s", file, s );
|
||||||
|
if ( symlink( file, s ) == 0 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ( errno != EEXIST )
|
||||||
|
{
|
||||||
|
WARNING( "Failed to create symlink: %s", strerror( errno ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Audio_File *c = Audio_File::from_file( basename( s ) );
|
||||||
|
|
||||||
|
free( s );
|
||||||
|
free( filebase );
|
||||||
|
|
||||||
|
fl_cursor( FL_CURSOR_DEFAULT );
|
||||||
|
Fl::check();
|
||||||
|
|
||||||
|
if ( ! c || c->dummy() )
|
||||||
|
{
|
||||||
|
fl_alert( "Could not import file \"%s\"", file );
|
||||||
|
free( file );
|
||||||
|
|
||||||
|
if ( c )
|
||||||
|
{
|
||||||
|
delete c;
|
||||||
|
c = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
free( file );
|
||||||
|
|
||||||
|
Audio_Region *r =
|
||||||
|
new Audio_Region( c, this, timeline->xoffset + timeline->x_to_ts( X - drawable_x() ) );
|
||||||
|
|
||||||
|
r->log_create();
|
||||||
|
|
||||||
|
redraw();
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/** event handler that supports DND of audio clips */
|
/** event handler that supports DND of audio clips */
|
||||||
int
|
int
|
||||||
Audio_Sequence::handle ( int m )
|
Audio_Sequence::handle ( int m )
|
||||||
|
@ -261,91 +350,15 @@ Audio_Sequence::handle ( int m )
|
||||||
{
|
{
|
||||||
case FL_PASTE:
|
case FL_PASTE:
|
||||||
{
|
{
|
||||||
if ( ! Fl::event_inside( this ) )
|
DMESSAGE("Got sequence paste");
|
||||||
return 0;
|
|
||||||
const char *text = Fl::event_text();
|
|
||||||
|
|
||||||
if ( ! strcmp( text, "Audio_Region" ) )
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
char *file;
|
|
||||||
|
|
||||||
if ( ! sscanf( text, "file://%a[^\r\n]\n", &file ) )
|
|
||||||
{
|
|
||||||
WARNING( "invalid drop \"%s\"\n", text );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unescape_url( file );
|
|
||||||
|
|
||||||
printf( "pasted file \"%s\"\n", file );
|
|
||||||
|
|
||||||
fl_cursor( FL_CURSOR_WAIT );
|
|
||||||
Fl::check();
|
|
||||||
|
|
||||||
char *t = strdup( file );
|
|
||||||
|
|
||||||
char *filebase = strdup( basename( t ) );
|
|
||||||
|
|
||||||
free( t );
|
|
||||||
|
|
||||||
char *s = 0;
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for ( ; ; i++ )
|
|
||||||
{
|
|
||||||
if ( i )
|
|
||||||
{
|
|
||||||
free( s );
|
|
||||||
asprintf( &s, "sources/%s-%i", filebase, i );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
asprintf( &s, "sources/%s", filebase );
|
|
||||||
|
|
||||||
DMESSAGE( "Symlink %s -> %s", file, s );
|
|
||||||
if ( symlink( file, s ) == 0 )
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ( errno != EEXIST )
|
if ( ! Fl::event_inside( this ) )
|
||||||
{
|
|
||||||
WARNING( "Failed to create symlink: %s", strerror( errno ) );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Audio_File *c = Audio_File::from_file( basename( s ) );
|
|
||||||
|
|
||||||
free( s );
|
|
||||||
free( filebase );
|
|
||||||
|
|
||||||
fl_cursor( FL_CURSOR_DEFAULT );
|
|
||||||
Fl::check();
|
|
||||||
|
|
||||||
if ( ! c || c->dummy() )
|
|
||||||
{
|
{
|
||||||
fl_alert( "Could not import file \"%s\"", file );
|
DMESSAGE("ignoring");
|
||||||
free( file );
|
|
||||||
|
|
||||||
if ( c )
|
|
||||||
{
|
|
||||||
delete c;
|
|
||||||
c = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
free( file );
|
return handle_paste(Fl::event_text());
|
||||||
|
|
||||||
Audio_Region *r =
|
|
||||||
new Audio_Region( c, this, timeline->xoffset + timeline->x_to_ts( Fl::event_x() - drawable_x() ) );
|
|
||||||
|
|
||||||
r->log_create();
|
|
||||||
|
|
||||||
redraw();
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return Sequence::handle( m );
|
return Sequence::handle( m );
|
||||||
|
|
|
@ -51,6 +51,8 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
int handle_paste ( const char *text );
|
||||||
|
|
||||||
int handle ( int m );
|
int handle ( int m );
|
||||||
|
|
||||||
LOG_CREATE_FUNC( Audio_Sequence );
|
LOG_CREATE_FUNC( Audio_Sequence );
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <FL/Fl_Menu_Button.H>
|
#include <FL/Fl_Menu_Button.H>
|
||||||
#include <FL/Fl_Panzoomer.H>
|
#include <FL/Fl_Panzoomer.H>
|
||||||
#include <FL/Fl_Tile.H>
|
#include <FL/Fl_Tile.H>
|
||||||
|
#include <FL/Fl_File_Chooser.H>
|
||||||
|
|
||||||
#include "Timeline.H"
|
#include "Timeline.H"
|
||||||
#include "Tempo_Sequence.H"
|
#include "Tempo_Sequence.H"
|
||||||
|
@ -373,6 +374,9 @@ Timeline::add_take_for_armed_tracks ( void )
|
||||||
track_lock.unlock();
|
track_lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* coordinates of mouse at time context menu is brought up. */
|
||||||
|
static int menu_event_x = 0;
|
||||||
|
static int menu_event_y = 0;
|
||||||
void
|
void
|
||||||
Timeline::menu_cb ( Fl_Menu_ *m )
|
Timeline::menu_cb ( Fl_Menu_ *m )
|
||||||
{
|
{
|
||||||
|
@ -570,6 +574,31 @@ Timeline::menu_cb ( Fl_Menu_ *m )
|
||||||
{
|
{
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
else if ( ! strcmp( picked, "Import source at mouse" ) )
|
||||||
|
{
|
||||||
|
Fl::e_x = menu_event_x;
|
||||||
|
Fl::e_y = menu_event_y;
|
||||||
|
|
||||||
|
Track *t = Timeline::event_inside();
|
||||||
|
|
||||||
|
if ( t )
|
||||||
|
{
|
||||||
|
const char *name = fl_file_chooser( "Import source", "*", NULL );
|
||||||
|
|
||||||
|
if ( name )
|
||||||
|
{
|
||||||
|
char *url;
|
||||||
|
asprintf( &url, "file:///%s\n", name );
|
||||||
|
|
||||||
|
Fl::e_x = menu_event_x;
|
||||||
|
Fl::e_y = menu_event_y;
|
||||||
|
|
||||||
|
t->sequence()->handle_paste(url);
|
||||||
|
|
||||||
|
free(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
WARNING( "programming error: Unknown menu item" );
|
WARNING( "programming error: Unknown menu item" );
|
||||||
}
|
}
|
||||||
|
@ -630,6 +659,7 @@ Timeline::Timeline ( int X, int Y, int W, int H, const char* L ) : BASE( X, Y, W
|
||||||
menu->add( "Edit end to playhead", FL_CTRL + ']', 0, 0 );
|
menu->add( "Edit end to playhead", FL_CTRL + ']', 0, 0 );
|
||||||
menu->add( "Punch from edit", FL_CTRL + FL_SHIFT + 'p', 0, 0 );
|
menu->add( "Punch from edit", FL_CTRL + FL_SHIFT + 'p', 0, 0 );
|
||||||
menu->add( "Playback from edit", FL_CTRL + FL_SHIFT + 'l', 0, 0 );
|
menu->add( "Playback from edit", FL_CTRL + FL_SHIFT + 'l', 0, 0 );
|
||||||
|
menu->add( "Import source at mouse", 0, 0, 0 );
|
||||||
menu->add( "Redraw", FL_CTRL + 'l', 0, 0 );
|
menu->add( "Redraw", FL_CTRL + 'l', 0, 0 );
|
||||||
|
|
||||||
menu_set_callback( const_cast<Fl_Menu_Item*>(menu->menu()), &Timeline::menu_cb, (void*)this );
|
menu_set_callback( const_cast<Fl_Menu_Item*>(menu->menu()), &Timeline::menu_cb, (void*)this );
|
||||||
|
@ -1730,6 +1760,20 @@ Timeline::handle ( int m )
|
||||||
}
|
}
|
||||||
else if ( test_press( FL_BUTTON3 ) )
|
else if ( test_press( FL_BUTTON3 ) )
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
menu_event_x = X;
|
||||||
|
menu_event_y = Y;
|
||||||
|
|
||||||
|
Track *t = Timeline::event_inside();
|
||||||
|
|
||||||
|
Fl_Menu_Item *mi = (Fl_Menu_Item*)menu->find_item("Import source at mouse");
|
||||||
|
|
||||||
|
if ( t )
|
||||||
|
mi->activate();
|
||||||
|
else
|
||||||
|
mi->deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
menu_popup( menu );
|
menu_popup( menu );
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1738,59 +1782,59 @@ Timeline::handle ( int m )
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case FL_DRAG:
|
case FL_DRAG:
|
||||||
{
|
|
||||||
int ox = X - drag->x;
|
|
||||||
int oy = Y - drag->y;
|
|
||||||
|
|
||||||
if ( ox < 0 )
|
|
||||||
_selection.x = X;
|
|
||||||
if ( oy < 0 )
|
|
||||||
_selection.y = Y;
|
|
||||||
|
|
||||||
_selection.w = abs( ox );
|
|
||||||
_selection.h = abs( oy );
|
|
||||||
|
|
||||||
if ( range )
|
|
||||||
{
|
{
|
||||||
range_start( x_to_offset( _selection.x ) );
|
int ox = X - drag->x;
|
||||||
range_end( x_to_offset( _selection.x + _selection.w ) );
|
int oy = Y - drag->y;
|
||||||
redraw();
|
|
||||||
|
if ( ox < 0 )
|
||||||
|
_selection.x = X;
|
||||||
|
if ( oy < 0 )
|
||||||
|
_selection.y = Y;
|
||||||
|
|
||||||
|
_selection.w = abs( ox );
|
||||||
|
_selection.h = abs( oy );
|
||||||
|
|
||||||
|
if ( range )
|
||||||
|
{
|
||||||
|
range_start( x_to_offset( _selection.x ) );
|
||||||
|
range_end( x_to_offset( _selection.x + _selection.w ) );
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw_overlay();
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case FL_RELEASE:
|
||||||
redraw_overlay();
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FL_RELEASE:
|
|
||||||
{
|
|
||||||
delete drag;
|
|
||||||
drag = NULL;
|
|
||||||
|
|
||||||
if ( range )
|
|
||||||
{
|
{
|
||||||
range_start( x_to_offset( _selection.x ) );
|
delete drag;
|
||||||
range_end( x_to_offset( _selection.x + _selection.w ) );
|
drag = NULL;
|
||||||
redraw();
|
|
||||||
|
if ( range )
|
||||||
|
{
|
||||||
|
range_start( x_to_offset( _selection.x ) );
|
||||||
|
range_end( x_to_offset( _selection.x + _selection.w ) );
|
||||||
|
redraw();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
select( _selection );
|
||||||
|
|
||||||
|
_selection.x = _selection.y =_selection.w = _selection.h = 0;
|
||||||
|
|
||||||
|
redraw_overlay();
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
default:
|
||||||
select( _selection );
|
return 0;
|
||||||
|
break;
|
||||||
_selection.x = _selection.y =_selection.w = _selection.h = 0;
|
|
||||||
|
|
||||||
redraw_overlay();
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** retrun a pointer to the track named /name/, or NULL if no track is named /name/ */
|
/** retrun a pointer to the track named /name/, or NULL if no track is named /name/ */
|
||||||
Track *
|
Track *
|
||||||
|
|
Loading…
Reference in New Issue