Closes #211.tags/non-daw-v1.2.0
@@ -253,99 +253,112 @@ Audio_Sequence::draw ( void ) | |||
fl_pop_clip(); | |||
} | |||
/** event handler that supports DND of audio clips */ | |||
int | |||
Audio_Sequence::handle ( int m ) | |||
Audio_Sequence::handle_paste ( const char *text ) | |||
{ | |||
switch ( m ) | |||
{ | |||
case FL_PASTE: | |||
{ | |||
if ( ! Fl::event_inside( this ) ) | |||
return 0; | |||
const char *text = Fl::event_text(); | |||
if ( ! strcmp( text, "Audio_Region" ) ) | |||
return 1; | |||
char *file; | |||
int X = Fl::event_x(); | |||
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; | |||
} | |||
if ( ! sscanf( text, "file://%m[^\r\n]\n", &file ) ) | |||
{ | |||
WARNING( "invalid drop \"%s\"\n", text ); | |||
return 0; | |||
} | |||
unescape_url( file ); | |||
unescape_url( file ); | |||
printf( "pasted file \"%s\"\n", file ); | |||
printf( "pasted file \"%s\"\n", file ); | |||
fl_cursor( FL_CURSOR_WAIT ); | |||
Fl::check(); | |||
fl_cursor( FL_CURSOR_WAIT ); | |||
Fl::check(); | |||
char *t = strdup( file ); | |||
char *t = strdup( file ); | |||
char *filebase = strdup( basename( t ) ); | |||
char *filebase = strdup( basename( t ) ); | |||
free( t ); | |||
free( t ); | |||
char *s = 0; | |||
char *s = 0; | |||
int i = 0; | |||
int i = 0; | |||
for ( ; ; i++ ) | |||
{ | |||
if ( i ) | |||
{ | |||
free( s ); | |||
asprintf( &s, "sources/%s-%i", filebase, i ); | |||
} | |||
else | |||
asprintf( &s, "sources/%s", filebase ); | |||
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; | |||
DMESSAGE( "Symlink %s -> %s", file, s ); | |||
if ( symlink( file, s ) == 0 ) | |||
break; | |||
if ( errno != EEXIST ) | |||
{ | |||
WARNING( "Failed to create symlink: %s", strerror( errno ) ); | |||
break; | |||
} | |||
} | |||
if ( errno != EEXIST ) | |||
{ | |||
WARNING( "Failed to create symlink: %s", strerror( errno ) ); | |||
break; | |||
} | |||
} | |||
Audio_File *c = Audio_File::from_file( basename( s ) ); | |||
Audio_File *c = Audio_File::from_file( basename( s ) ); | |||
free( s ); | |||
free( filebase ); | |||
free( s ); | |||
free( filebase ); | |||
fl_cursor( FL_CURSOR_DEFAULT ); | |||
Fl::check(); | |||
fl_cursor( FL_CURSOR_DEFAULT ); | |||
Fl::check(); | |||
if ( ! c || c->dummy() ) | |||
{ | |||
fl_alert( "Could not import file \"%s\"", file ); | |||
free( file ); | |||
if ( ! c || c->dummy() ) | |||
{ | |||
fl_alert( "Could not import file \"%s\"", file ); | |||
free( file ); | |||
if ( c ) | |||
{ | |||
delete c; | |||
c = NULL; | |||
} | |||
if ( c ) | |||
{ | |||
delete c; | |||
c = NULL; | |||
} | |||
return 0; | |||
} | |||
return 0; | |||
} | |||
free( file ); | |||
free( file ); | |||
Audio_Region *r = | |||
new Audio_Region( c, this, timeline->xoffset + timeline->x_to_ts( Fl::event_x() - drawable_x() ) ); | |||
Audio_Region *r = | |||
new Audio_Region( c, this, timeline->xoffset + timeline->x_to_ts( X - drawable_x() ) ); | |||
r->log_create(); | |||
r->log_create(); | |||
redraw(); | |||
redraw(); | |||
return 1; | |||
return 1; | |||
} | |||
/** event handler that supports DND of audio clips */ | |||
int | |||
Audio_Sequence::handle ( int m ) | |||
{ | |||
switch ( m ) | |||
{ | |||
case FL_PASTE: | |||
{ | |||
DMESSAGE("Got sequence paste"); | |||
if ( ! Fl::event_inside( this ) ) | |||
{ | |||
DMESSAGE("ignoring"); | |||
return 0; | |||
} | |||
return handle_paste(Fl::event_text()); | |||
} | |||
default: | |||
return Sequence::handle( m ); | |||
@@ -51,6 +51,8 @@ protected: | |||
public: | |||
int handle_paste ( const char *text ); | |||
int handle ( int m ); | |||
LOG_CREATE_FUNC( Audio_Sequence ); | |||
@@ -30,6 +30,7 @@ | |||
#include <FL/Fl_Menu_Button.H> | |||
#include <FL/Fl_Panzoomer.H> | |||
#include <FL/Fl_Tile.H> | |||
#include <FL/Fl_File_Chooser.H> | |||
#include "Timeline.H" | |||
#include "Tempo_Sequence.H" | |||
@@ -373,6 +374,9 @@ Timeline::add_take_for_armed_tracks ( void ) | |||
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 | |||
Timeline::menu_cb ( Fl_Menu_ *m ) | |||
{ | |||
@@ -570,6 +574,31 @@ Timeline::menu_cb ( Fl_Menu_ *m ) | |||
{ | |||
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 | |||
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( "Punch from edit", FL_CTRL + FL_SHIFT + 'p', 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_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 ) ) | |||
{ | |||
{ | |||
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 ); | |||
return 1; | |||
@@ -1738,59 +1782,59 @@ Timeline::handle ( int m ) | |||
return 0; | |||
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; | |||
case FL_DRAG: | |||
{ | |||
int ox = X - drag->x; | |||
int oy = Y - drag->y; | |||
_selection.w = abs( ox ); | |||
_selection.h = abs( oy ); | |||
if ( ox < 0 ) | |||
_selection.x = X; | |||
if ( oy < 0 ) | |||
_selection.y = Y; | |||
if ( range ) | |||
{ | |||
range_start( x_to_offset( _selection.x ) ); | |||
range_end( x_to_offset( _selection.x + _selection.w ) ); | |||
redraw(); | |||
} | |||
_selection.w = abs( ox ); | |||
_selection.h = abs( oy ); | |||
redraw_overlay(); | |||
return 1; | |||
if ( range ) | |||
{ | |||
range_start( x_to_offset( _selection.x ) ); | |||
range_end( x_to_offset( _selection.x + _selection.w ) ); | |||
redraw(); | |||
} | |||
break; | |||
} | |||
case FL_RELEASE: | |||
{ | |||
delete drag; | |||
drag = NULL; | |||
redraw_overlay(); | |||
return 1; | |||
if ( range ) | |||
{ | |||
range_start( x_to_offset( _selection.x ) ); | |||
range_end( x_to_offset( _selection.x + _selection.w ) ); | |||
redraw(); | |||
break; | |||
} | |||
else | |||
select( _selection ); | |||
case FL_RELEASE: | |||
{ | |||
delete drag; | |||
drag = NULL; | |||
_selection.x = _selection.y =_selection.w = _selection.h = 0; | |||
if ( range ) | |||
{ | |||
range_start( x_to_offset( _selection.x ) ); | |||
range_end( x_to_offset( _selection.x + _selection.w ) ); | |||
redraw(); | |||
} | |||
else | |||
select( _selection ); | |||
redraw_overlay(); | |||
return 1; | |||
_selection.x = _selection.y =_selection.w = _selection.h = 0; | |||
redraw_overlay(); | |||
return 1; | |||
} | |||
default: | |||
return 0; | |||
break; | |||
} | |||
default: | |||
return 0; | |||
break; | |||
} | |||
return 0; | |||
return 0; | |||
} | |||
} | |||
} | |||
} | |||
/** retrun a pointer to the track named /name/, or NULL if no track is named /name/ */ | |||
Track * | |||