diff --git a/FL/Fl_Packscroller.H b/FL/Fl_Packscroller.H index baebdb9..7e67a5f 100644 --- a/FL/Fl_Packscroller.H +++ b/FL/Fl_Packscroller.H @@ -157,7 +157,6 @@ public: { static int _button; - int r = 0; switch ( m ) { case FL_PUSH: @@ -217,6 +216,6 @@ public: } } - return Fl_Group::handle( m ) | r; + return Fl_Group::handle( m ); } }; diff --git a/FL/Fl_Sometimes_Input.H b/FL/Fl_Sometimes_Input.H index 75ad223..bb58c5e 100644 --- a/FL/Fl_Sometimes_Input.H +++ b/FL/Fl_Sometimes_Input.H @@ -69,7 +69,7 @@ public: virtual int handle ( int m ) { - int r = Fl_Input::handle( m ); + int r = 0; switch ( m ) { @@ -79,23 +79,31 @@ public: Fl::event_key() == FL_Tab ) ) { Fl::focus( NULL ); - return 1; + r = 1; } - else - return r; + break; } case FL_FOCUS: redraw(); - return 1; + r = 1; + break; case FL_UNFOCUS: do_callback(); - return 1; + r = 1; + break; case FL_PUSH: take_focus(); redraw(); - return 1; + r = 1; + break; + case FL_DND_ENTER: + return 0; + case FL_PASTE: + return 0; default: - return r; + break; } + + return Fl_Input::handle( m ) | r; } }; diff --git a/FL/img_io_input_connector_10x10_png.h b/FL/img_io_input_connector_10x10_png.h new file mode 100644 index 0000000..c58f485 --- /dev/null +++ b/FL/img_io_input_connector_10x10_png.h @@ -0,0 +1,61 @@ +/*******************************************************************************/ +/* Copyright (C) 2013 Jonathan Moore Liles */ +/* */ +/* 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; see the file COPYING. If not,write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/*******************************************************************************/ + +static unsigned char img_io_input_connector_10x10_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x32, 0xcf, 0xbd, 0x00, 0x00, 0x00, + 0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64, + 0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x00, + 0x9e, 0x00, 0x00, 0x00, 0x9e, 0x01, 0x22, 0xcb, 0xc6, 0x03, 0x00, 0x00, + 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, + 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, + 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x00, + 0x00, 0x01, 0x51, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x3d, 0xd0, 0xb1, + 0x6a, 0xdb, 0x40, 0x1c, 0xc0, 0xe1, 0x9f, 0x72, 0x7f, 0xcc, 0x21, 0xbc, + 0xc5, 0x87, 0xb0, 0xb7, 0x18, 0x6c, 0xa8, 0x49, 0x37, 0x1b, 0x8c, 0x26, + 0xdb, 0x19, 0xfb, 0x0e, 0x7e, 0x82, 0xee, 0x21, 0x53, 0xe9, 0x14, 0x42, + 0x37, 0x37, 0x7b, 0x9e, 0xa2, 0x63, 0x07, 0x6b, 0xd6, 0xec, 0xc5, 0xe0, + 0x80, 0xc1, 0x08, 0xac, 0x66, 0xf0, 0xa0, 0xb3, 0x90, 0x4e, 0xa7, 0x4e, + 0xed, 0xf6, 0xcd, 0x5f, 0xd0, 0xb6, 0x2d, 0x00, 0xfb, 0xfd, 0xfe, 0x4b, + 0x59, 0x96, 0x8f, 0x4d, 0xd3, 0xdc, 0x01, 0x4e, 0x44, 0xf2, 0x30, 0x0c, + 0x9f, 0x86, 0xc3, 0xe1, 0x6f, 0x80, 0xa0, 0x6d, 0x5b, 0x76, 0xbb, 0xdd, + 0xb7, 0xf3, 0xf9, 0xfc, 0x35, 0x4d, 0xd3, 0x5e, 0x96, 0x65, 0x78, 0xef, + 0x19, 0x0c, 0x06, 0x4c, 0xa7, 0xd3, 0x8f, 0x28, 0x8a, 0x7e, 0x4e, 0x26, + 0x93, 0xef, 0x6a, 0xbd, 0x5e, 0x3f, 0x9c, 0x4e, 0xa7, 0x1f, 0x49, 0x92, + 0xf4, 0x2e, 0x97, 0x0b, 0xdb, 0xed, 0x96, 0xe3, 0xf1, 0x88, 0x31, 0x86, + 0x2c, 0xcb, 0x42, 0x63, 0xcc, 0x7d, 0x5d, 0xd7, 0xbb, 0x1b, 0x6b, 0xed, + 0x73, 0x9a, 0xa6, 0xb7, 0x00, 0x4a, 0x29, 0x44, 0x04, 0x11, 0x41, 0x29, + 0x05, 0x40, 0x9a, 0xa6, 0xbd, 0xb2, 0x2c, 0x1f, 0xc5, 0x39, 0x67, 0xac, + 0xb5, 0x78, 0xef, 0x09, 0x82, 0x80, 0xd5, 0x6a, 0x45, 0x10, 0x04, 0xb4, + 0x6d, 0x8b, 0x73, 0x8e, 0xa2, 0x28, 0x68, 0x9a, 0xe6, 0x4e, 0x00, 0xf1, + 0xde, 0x93, 0x24, 0x09, 0x45, 0x51, 0x10, 0xc7, 0x31, 0x22, 0x42, 0x92, + 0x24, 0x68, 0xad, 0x59, 0x2e, 0x97, 0x00, 0xee, 0x46, 0x29, 0xf5, 0xde, + 0xed, 0x76, 0xb9, 0x5e, 0xaf, 0x78, 0xef, 0xa9, 0xaa, 0x8a, 0xaa, 0xaa, + 0xfe, 0x5b, 0x6b, 0x8d, 0x88, 0xe4, 0xa2, 0xb5, 0x7e, 0x99, 0xcd, 0x66, + 0x9f, 0xf2, 0x3c, 0xef, 0x59, 0x6b, 0x31, 0xc6, 0x00, 0x10, 0xc7, 0x31, + 0x9d, 0x4e, 0x87, 0xf9, 0x7c, 0xfe, 0x11, 0x86, 0xe1, 0x93, 0xda, 0x6c, + 0x36, 0x7b, 0x6b, 0x6d, 0xd8, 0xef, 0xf7, 0x3f, 0x5b, 0x6b, 0xc3, 0xba, + 0xae, 0x01, 0x30, 0xc6, 0xb0, 0x58, 0x2c, 0xfe, 0x44, 0x51, 0xf4, 0x3a, + 0x1e, 0x8f, 0xdf, 0x82, 0x7f, 0xe1, 0x87, 0xc3, 0xe1, 0xc1, 0x5a, 0xfb, + 0xec, 0x9c, 0x33, 0x80, 0x28, 0xa5, 0xde, 0xb5, 0xd6, 0x2f, 0xa3, 0xd1, + 0xe8, 0x17, 0xc0, 0x5f, 0xd1, 0x17, 0xa6, 0x12, 0x83, 0xc3, 0x30, 0x9b, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + +}; +static unsigned int img_io_input_connector_10x10_png_len = 468; diff --git a/FL/img_io_output_connector_10x10_png.h b/FL/img_io_output_connector_10x10_png.h new file mode 100644 index 0000000..1a0503f --- /dev/null +++ b/FL/img_io_output_connector_10x10_png.h @@ -0,0 +1,63 @@ + +/*******************************************************************************/ +/* Copyright (C) 2013 Jonathan Moore Liles */ +/* */ +/* 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; see the file COPYING. If not,write to the Free Software */ +/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/*******************************************************************************/ + +static unsigned char img_io_output_connector_10x10_png[] = { +0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x32, 0xcf, 0xbd, 0x00, 0x00, 0x00, + 0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64, + 0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x00, + 0x9e, 0x00, 0x00, 0x00, 0x9e, 0x01, 0x22, 0xcb, 0xc6, 0x03, 0x00, 0x00, + 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, + 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, + 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x00, + 0x00, 0x01, 0x61, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x35, 0xd0, 0xbf, + 0x6a, 0xc2, 0x40, 0x00, 0x07, 0xe0, 0xdf, 0xfd, 0x89, 0xe4, 0x32, 0xc4, + 0x40, 0xed, 0x22, 0x9c, 0x50, 0x24, 0x99, 0x1c, 0xdc, 0x33, 0x38, 0x64, + 0xec, 0x03, 0x14, 0x9c, 0xd4, 0xb9, 0x7b, 0xe9, 0x54, 0x3a, 0x95, 0xd2, + 0xb1, 0x1d, 0x74, 0xeb, 0xe4, 0xec, 0xd2, 0x31, 0x01, 0x9f, 0x40, 0x04, + 0xe9, 0x10, 0x85, 0x06, 0x1c, 0x6d, 0x40, 0x34, 0xe4, 0xd0, 0x0b, 0x5e, + 0xa7, 0x7e, 0x8f, 0xf0, 0x11, 0x63, 0x0c, 0x00, 0x60, 0xbd, 0x5e, 0xdf, + 0x96, 0x65, 0xf9, 0xa0, 0xb5, 0xbe, 0x21, 0x84, 0x54, 0x9c, 0xf3, 0x9d, + 0x10, 0xe2, 0x31, 0x08, 0x82, 0x18, 0x00, 0x88, 0x31, 0x06, 0xab, 0xd5, + 0xea, 0x69, 0xbb, 0xdd, 0xde, 0x27, 0x49, 0xd2, 0xb0, 0x6d, 0x1b, 0x8c, + 0x31, 0x14, 0x45, 0x81, 0x28, 0x8a, 0x72, 0x29, 0xe5, 0x7b, 0xa7, 0xd3, + 0x79, 0x66, 0xfd, 0x7e, 0x3f, 0xca, 0xb2, 0xec, 0x6d, 0x36, 0x9b, 0x35, + 0x84, 0x10, 0x18, 0x8d, 0x46, 0xe8, 0x76, 0xbb, 0x58, 0x2e, 0x97, 0x58, + 0x2c, 0x16, 0x4e, 0xb3, 0xd9, 0xec, 0x00, 0xf8, 0xa6, 0x4a, 0xa9, 0x97, + 0x38, 0x8e, 0xaf, 0x00, 0x40, 0x6b, 0x8d, 0xf3, 0xf9, 0x8c, 0xd3, 0xe9, + 0x04, 0xad, 0x35, 0x00, 0x20, 0x49, 0x92, 0x46, 0x59, 0x96, 0x0f, 0xbc, + 0xaa, 0xaa, 0xeb, 0xe3, 0xf1, 0x08, 0xc6, 0x18, 0x2e, 0x97, 0x0b, 0xc6, + 0xe3, 0x31, 0x8c, 0x31, 0xa0, 0x94, 0xa2, 0x56, 0xab, 0xe1, 0x70, 0x38, + 0x40, 0x6b, 0x7d, 0xc3, 0x8d, 0x31, 0x9c, 0x52, 0x8a, 0xe1, 0x70, 0x08, + 0xcf, 0xf3, 0x30, 0x9d, 0x4e, 0xa1, 0xb5, 0xc6, 0x60, 0x30, 0x40, 0x51, + 0x14, 0x98, 0x4c, 0x26, 0x20, 0x84, 0x54, 0xd4, 0xb2, 0xac, 0x1f, 0xd7, + 0x75, 0xe1, 0xba, 0x2e, 0x38, 0xe7, 0x70, 0x1c, 0x07, 0x42, 0x08, 0x30, + 0xc6, 0x60, 0xdb, 0x36, 0x3c, 0xcf, 0x03, 0xe7, 0x7c, 0x47, 0xd2, 0x34, + 0xbd, 0xdd, 0x6c, 0x36, 0x9f, 0xf3, 0xf9, 0xbc, 0x51, 0xaf, 0xd7, 0x91, + 0x65, 0x19, 0x00, 0xa0, 0xd5, 0x6a, 0x41, 0x29, 0x85, 0x30, 0x0c, 0xf3, + 0x76, 0xbb, 0x7d, 0x47, 0x7d, 0xdf, 0xff, 0x92, 0x52, 0x7e, 0xf4, 0x7a, + 0xbd, 0x3c, 0xcf, 0x73, 0xfc, 0xdb, 0xef, 0xf7, 0x08, 0xc3, 0xf0, 0x57, + 0x4a, 0xf9, 0x1e, 0x04, 0x41, 0x4c, 0xfe, 0xc3, 0xd3, 0x34, 0x8d, 0x94, + 0x52, 0x2f, 0x55, 0x55, 0x5d, 0x1b, 0x63, 0xb8, 0x65, 0x59, 0x3f, 0x8e, + 0xe3, 0xbc, 0xfa, 0xbe, 0xff, 0x05, 0x00, 0x7f, 0xb0, 0xa3, 0x9e, 0x20, + 0x9c, 0xde, 0x99, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, + 0xae, 0x42, 0x60, 0x82 +}; +static unsigned int img_io_output_connector_10x10_png_len = 484; diff --git a/lib/ntk b/lib/ntk index fe832d3..ed50ecc 160000 --- a/lib/ntk +++ b/lib/ntk @@ -1 +1 @@ -Subproject commit fe832d3cbc807c475f4b6a51facf543aa7d9882d +Subproject commit ed50ecc551d5e490f4acb1ec673c9e8f43e23fb0 diff --git a/mixer/src/AUX_Module.C b/mixer/src/AUX_Module.C index 2718e9a..af8415a 100644 --- a/mixer/src/AUX_Module.C +++ b/mixer/src/AUX_Module.C @@ -123,6 +123,7 @@ AUX_Module::draw ( void ) { int W = 5; + child(0)->size( w() - W, 18 ); Module::draw_box(x(),y(),w() - W,h()); Module::draw_label(x(),y(),w() - W,h()); diff --git a/mixer/src/Chain.C b/mixer/src/Chain.C index 9792a4b..2600037 100644 --- a/mixer/src/Chain.C +++ b/mixer/src/Chain.C @@ -458,6 +458,7 @@ Chain::name ( const char *name ) _engine = new Engine( &Chain::process, this ); engine()->buffer_size_callback( &Chain::buffer_size, this ); + engine()->port_connect_callback( &Chain::port_connect, this ); const char *jack_name = engine()->init( ename ); @@ -824,3 +825,43 @@ Chain::buffer_size ( nframes_t nframes ) m->resize_buffers( nframes ); } } + +void +Chain::port_connect ( jack_port_id_t a, jack_port_id_t b, int connect, void *v ) +{ + ((Chain*)v)->port_connect( a, b, connect ); +} + +/* handle jack port connection change */ +void +Chain::port_connect ( jack_port_id_t a, jack_port_id_t b, int connect ) +{ + /* this is called from JACK non-RT thread... */ + + if ( jack_port_is_mine( engine()->jack_client(), jack_port_by_id( engine()->jack_client(), a ) ) || + jack_port_is_mine( engine()->jack_client(), jack_port_by_id( engine()->jack_client(), b ) )) + { + Fl::awake( Chain::update_connection_status, this ); + } +} + +void +Chain::update_connection_status ( void *v ) +{ + ((Chain*)v)->update_connection_status(); +} + +void +Chain::update_connection_status ( void ) +{ + for ( int i = 0; i < modules(); i++ ) + { + Module *m = module(i); + + if ( !strcmp( m->name(), "JACK" ) || + !strcmp( m->name(), "AUX" )) + { + ((JACK_Module*)m)->update_connection_status(); + } + } +} diff --git a/mixer/src/Chain.H b/mixer/src/Chain.H index 502964b..5c477bf 100644 --- a/mixer/src/Chain.H +++ b/mixer/src/Chain.H @@ -73,6 +73,13 @@ private: static void buffer_size ( nframes_t nframes, void *v ); void buffer_size ( nframes_t nframes ); + + static void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect, void *v ); + void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect ); + + static void update_connection_status ( void *v ); + void update_connection_status ( void ); + protected: void get ( Log_Entry &e ) const; diff --git a/mixer/src/Engine/Engine.C b/mixer/src/Engine/Engine.C index ced044b..71874d8 100644 --- a/mixer/src/Engine/Engine.C +++ b/mixer/src/Engine/Engine.C @@ -36,6 +36,7 @@ Engine::Engine ( void (*process_callback)(nframes_t nframes, void *), void *user _process_callback_user_data = user_data; _buffer_size_callback = 0; _buffers_dropped = 0; + _port_connect_callback = 0; } Engine::~Engine ( ) @@ -52,6 +53,13 @@ Engine::buffer_size_callback ( void ( *buffer_size_callback ) ( nframes_t, void _buffer_size_callback_user_data = user_data; } +void +Engine::port_connect_callback ( void ( *port_connect_callback ) ( jack_port_id_t a, jack_port_id_t b, int connect, void *arg), void *user_data ) +{ + _port_connect_callback = port_connect_callback; + _port_connect_callback_user_data = user_data; +} + /*************/ /* Callbacks */ /*************/ @@ -91,6 +99,15 @@ Engine::buffer_size ( nframes_t nframes ) return 0; } +/* THREAD: ?? */ +void +Engine::port_connect( jack_port_id_t a, jack_port_id_t b, int connect ) +{ + if ( _port_connect_callback ) + _port_connect_callback( a, b, connect, _port_connect_callback_user_data ); +} + + /* THREAD: RT */ int Engine::process ( nframes_t nframes ) diff --git a/mixer/src/Engine/Engine.H b/mixer/src/Engine/Engine.H index b967c19..83bbaf6 100644 --- a/mixer/src/Engine/Engine.H +++ b/mixer/src/Engine/Engine.H @@ -40,13 +40,16 @@ class Engine : public JACK::Client, public Mutex void ( * _buffer_size_callback ) ( nframes_t, void * ); void *_buffer_size_callback_user_data; + void ( * _port_connect_callback ) ( jack_port_id_t a, jack_port_id_t b, int connect, void * ); + void *_port_connect_callback_user_data; + void shutdown ( void ); int process ( nframes_t nframes ); int xrun ( void ); void freewheel ( bool yes ); int buffer_size ( nframes_t nframes ); void thread_init ( void ); - + void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect ); Engine ( const Engine &rhs ); Engine & operator = ( const Engine &rhs ); @@ -64,4 +67,5 @@ public: int dropped ( void ) const { return _buffers_dropped; } void buffer_size_callback ( void ( *buffer_size_callback ) ( nframes_t, void * ), void *user_data ); + void port_connect_callback ( void ( *port_connect_callback ) ( jack_port_id_t a, jack_port_id_t b, int connect, void *arg), void *user_data ); }; diff --git a/mixer/src/JACK_Module.C b/mixer/src/JACK_Module.C index 60125b6..2a485f2 100644 --- a/mixer/src/JACK_Module.C +++ b/mixer/src/JACK_Module.C @@ -22,6 +22,9 @@ #include #include +#include +#include +#include #include "dsp.h" @@ -29,14 +32,30 @@ #include "Chain.H" #include "JACK_Module.H" +#include + +#include +#include + +#include +#include +#include + +static Fl_PNG_Image *input_connector_image = NULL; +static Fl_PNG_Image *output_connector_image = NULL; + +extern char *instance_name; +static JACK_Module *receptive_to_drop = NULL; JACK_Module::JACK_Module ( bool log ) - : Module ( 50, 24, name() ) + : Module ( 25, 25, name() ) { _prefix = 0; + align( FL_ALIGN_TOP | FL_ALIGN_INSIDE ); + if ( log ) { /* FIXME: how do Controls find out that a connected value has changed? How does this work in ladspa? */ @@ -72,6 +91,60 @@ JACK_Module::JACK_Module ( bool log ) log_create(); } + + { Fl_Scalepack *o = new Fl_Scalepack( x() + Fl::box_dx(box()), + y() + Fl::box_dy(box()), + w(), + 24 - Fl::box_dh(box()) ); + o->type( Fl_Pack::HORIZONTAL ); + + o->spacing( 0 ); + + + { Fl_Box *o = input_connection_handle = new Fl_Box( x(), y(), 18, 18 ); + o->tooltip( "Drag and drop to make and break JACK connections."); + o->hide(); + o->image( input_connector_image ? input_connector_image : input_connector_image = new Fl_PNG_Image( "input_connector", img_io_input_connector_10x10_png, img_io_input_connector_10x10_png_len ) ); + + } + + { Fl_Box *o = new Fl_Box( x() + 10, y(), w() - 20, h() ); + Fl_Group::current()->resizable(o); + } + + + { Fl_Button *o = dec_button = new Fl_Button( 0, 0, 12, h(), "-" ); + o->callback( cb_button, this ); + o->labelsize(10); + o->labelfont( FL_HELVETICA_BOLD ); + o->hide(); + } + { Fl_Button *o = inc_button = new Fl_Button( 0,0, 12, h(), "+" ); + o->labelsize(10); + o->labelfont( FL_HELVETICA_BOLD ); + o->callback( cb_button, this ); + o->hide(); + } + + { Fl_Box *o = output_connection_handle = new Fl_Box( x(), y(), 18, 18 ); + o->tooltip( "Drag and drop to make and break JACK connections."); + o->image( output_connector_image ? output_connector_image : output_connector_image = new Fl_PNG_Image( "output_connector", img_io_output_connector_10x10_png, img_io_output_connector_10x10_png_len ) ); + o->hide(); + } + + o->end(); + resizable(o); + } + + { + Fl_Browser *o = connection_display = new Fl_Browser( x() + Fl::box_dx(box()), y() + 25, w() - Fl::box_dw(box()), 300 ); + o->textsize( 11 ); + o->textcolor( FL_LIGHT3 ); + o->textfont( FL_COURIER ); + o->box( FL_FLAT_BOX ); + o->color( fl_color_add_alpha( fl_rgb_color( 10, 10, 10 ), 25 )); + } + end(); } @@ -86,6 +159,155 @@ JACK_Module::~JACK_Module ( ) +void +JACK_Module::draw ( void ) +{ + Module::draw(); + if ( this == receptive_to_drop ) + { + Fl_Widget *o = input_connection_handle; + fl_draw_box( FL_OVAL_BOX, o->x(), o->y(), o->w(), o->h(), fl_color_add_alpha( FL_GREEN, 127 ) ); + } +} + +static std::list +get_connections_for_ports ( std::vector ports ) +{ + std::list names; + + for ( unsigned int i = 0; i < ports.size(); ++i ) + { + const char **connections = ports[i].connections(); + + if ( ! connections ) + return names; + + bool is_output = ports[i].type() == JACK::Port::Output; + + for ( const char **c = connections; *c; c++ ) + { + char *client_id = 0; + char *strip_name = 0; + // char *client_name = 0; + + if ( 2 == sscanf( *c, "Non-Mixer.%a[^:/]/%a[^:]:", &client_id, &strip_name ) ) + { + free( client_id ); + char *s = NULL; + asprintf( &s, "%s%s", is_output ? "@r" : "", strip_name ); + free( strip_name ); + strip_name = s; + } + else + if ( 2 == sscanf( *c, "Non-Timeline.%a[^:/]:%a[^/]/", &client_id, &strip_name ) ) + { + free( client_id ); + char *s = NULL; + asprintf( &s, "@C2%s%s", is_output ? "@r" : "", strip_name ); + free( strip_name ); + strip_name = s; + } + else + if ( 2 == sscanf( *c, "Non-DAW.%a[^:/]:%a[^/]/", &client_id, &strip_name ) ) + { + free( client_id ); + char *s = NULL; + asprintf( &s, "@C2%s%s", is_output ? "@r" : "", strip_name ); + free( strip_name ); + strip_name = s; + } + else if ( 1 == sscanf( *c, "%a[^:]:", &strip_name ) ) + { + char *s = NULL; + asprintf( &s, "@C3%s%s", is_output ? "@r" : "", strip_name ); + free( strip_name ); + strip_name = s; + } + else + { + continue; + } + + for ( std::list::const_iterator j = names.begin(); + j != names.end(); + j++ ) + { + if ( !strcmp( j->c_str(), strip_name ) ) + { + goto skip; + } + } + + names.push_back( strip_name ); + + skip: + free( strip_name ); + + ; + + } + } + + names.sort(); + return names; +} + +void +JACK_Module::update_connection_status ( void ) +{ + std::list output_names = get_connections_for_ports( jack_output ); + std::list input_names = get_connections_for_ports( jack_input ); + + connection_display->clear(); + + int n = 0; + for ( std::list::const_iterator j = input_names.begin(); + j != input_names.end(); + j++ ) + { + connection_display->add( j->c_str() ); + n++; + } + for ( std::list::const_iterator j = output_names.begin(); + j != output_names.end(); + j++ ) + { + connection_display->add( j->c_str() ); + n++; + } + + h( 25 + ( n * 13 ) ); + + parent()->parent()->redraw(); +} + +void +JACK_Module::cb_button ( Fl_Widget *w, void *v ) +{ + ((JACK_Module*)v)->cb_button( w ); +} + +void +JACK_Module::cb_button( Fl_Widget *w ) +{ + int n = audio_output.size(); + + if ( w == dec_button ) + { + --n; + } + else if ( w == inc_button ) + { + ++n; + } + + if ( chain()->can_configure_outputs( this, n ) ) + { + configure_outputs( n ); + chain()->configure_ports(); + } +} + int JACK_Module::can_support_inputs ( int ) { @@ -95,6 +317,15 @@ JACK_Module::can_support_inputs ( int ) bool JACK_Module::configure_inputs ( int n ) { + if ( n > 0 ) + { + if ( is_default() ) + control_input[0].hints.minimum = 1; + + output_connection_handle->show(); + } + + int on = audio_input.size(); if ( n > on ) @@ -150,7 +381,12 @@ bool JACK_Module::configure_outputs ( int n ) { int on = audio_output.size(); - + + if ( n > 0 ) + { + input_connection_handle->show(); + } + if ( n > on ) { for ( int i = on; i < n; ++i ) @@ -191,6 +427,11 @@ JACK_Module::configure_outputs ( int n ) if ( is_default() ) control_input[1].control_value_no_callback( n ); + if ( n > 0 && is_default() ) + { + dec_button->show(); + inc_button->show(); + } return true; } @@ -244,6 +485,142 @@ JACK_Module::handle_chain_name_changed ( void ) Module::handle_chain_name_changed(); } +int +JACK_Module::handle ( int m ) +{ + static JACK_Module *drag_source = 0; + + switch ( m ) + { + case FL_PUSH: + return Module::handle(m) || 1; + case FL_RELEASE: + return Module::handle(m) || 1; + case FL_DRAG: + { + if ( ! Fl::event_inside( this ) && this != drag_source ) + { + DMESSAGE( "initiation of drag" ); + + char *s = (char*)malloc(256); + s[0] = 0; + + for ( unsigned int i = 0; i < jack_output.size(); ++i ) + { + char *s2; + asprintf(&s2, "jack.port://%s/%s:%s\r\n", instance_name, chain()->name(), jack_output[i].name() ); + + s = (char*)realloc( s, strlen( s ) + strlen( s2 ) + 1 ); + strcat( s, s2 ); + + free( s2 ); + } + + Fl::copy(s, strlen(s) + 1, 0); + + free( s ); + + Fl::dnd(); + + drag_source = this; + + return 1; + } + + return 1; + } + /* we have to prevent Fl_Group::handle() from getting these, otherwise it will mess up Fl::belowmouse() */ + case FL_MOVE: + return 0; + case FL_ENTER: + case FL_DND_ENTER: + return 1; + case FL_LEAVE: + case FL_DND_LEAVE: + if ( this == receptive_to_drop ) + { + receptive_to_drop = NULL; + redraw(); + } + return 1; + case FL_DND_RELEASE: + receptive_to_drop = NULL; + redraw(); + return 1; + case FL_DND_DRAG: + { + if ( this == drag_source ) + return 0; + + if ( this == receptive_to_drop ) + return 1; + + if ( jack_input.size() ) + { + + receptive_to_drop = this; + redraw(); + return 1; + } + + return 0; + } + case FL_PASTE: + { + receptive_to_drop = NULL; + redraw(); + + drag_source = NULL; + + /* NOW we get the text... */ + const char *text = Fl::event_text(); + + DMESSAGE( "Got drop text \"%s\"",text); + + if ( strncmp( text, "jack.port://", strlen( "jack.port://" ) ) ) + { + return 0; + } + + std::vector port_names; + + char *port_name; + int end; + while ( sscanf( text, "jack.port://%a[^\r\n]\r\n%n", &port_name, &end ) > 0 ) + { + DMESSAGE( "Scanning %s", port_name ); + port_names.push_back( port_name ); + free(port_name ); + + text += end; + } + + for ( unsigned int i = 0; i < jack_input.size() && i < port_names.size(); i++) + { + const char *pn = port_names[i].c_str(); + + JACK::Port *ji = &jack_input[i]; + + if ( ji->connected_to( pn ) ) + { + + DMESSAGE( "Disconnecting from \"%s\"", pn ); + ji->disconnect( pn ); + } + else + { + DMESSAGE( "Connecting to %s", pn ); + ji->connect( pn ); + } + } + + Fl::selection_owner(0); + return 1; + } + } + + return Module::handle(m); +} /**********/ diff --git a/mixer/src/JACK_Module.H b/mixer/src/JACK_Module.H index a866ad0..15aa074 100644 --- a/mixer/src/JACK_Module.H +++ b/mixer/src/JACK_Module.H @@ -19,6 +19,8 @@ #pragma once +class Fl_Box; +class Fl_Browser; #include "Module.H" #include "JACK/Port.H" #include @@ -45,15 +47,28 @@ protected: static void jack_port_activation_error ( JACK::Port *p ); + Fl_Button * dec_button; + Fl_Button * inc_button; + Fl_Browser * connection_display; + Fl_Box * input_connection_handle; + Fl_Box * output_connection_handle; + + static void cb_button ( Fl_Widget *w, void *v ); + void cb_button ( Fl_Widget *w ); + public: + void update_connection_status ( void ); + JACK_Module ( bool log = true ); virtual ~JACK_Module ( ); virtual const char *name ( void ) const { return "JACK"; } - virtual bool initialize ( void ); + virtual void draw ( void ); + virtual int handle ( int m ); + virtual int can_support_inputs ( int ); virtual bool configure_inputs ( int n ); virtual bool configure_outputs ( int n ); diff --git a/mixer/src/Mixer.C b/mixer/src/Mixer.C index 98c2029..70c7719 100644 --- a/mixer/src/Mixer.C +++ b/mixer/src/Mixer.C @@ -730,22 +730,6 @@ Mixer::update_menu ( void ) project_name->label( Project::name() ); } -int -Mixer::handle ( int m ) -{ - if ( Fl_Group::handle( m ) ) - return 1; - - switch ( m ) - { - case FL_ENTER: - case FL_LEAVE: - return 1; - } - - return 0; -} - /************/ diff --git a/mixer/src/Mixer.H b/mixer/src/Mixer.H index a46ce15..05fb464 100644 --- a/mixer/src/Mixer.H +++ b/mixer/src/Mixer.H @@ -73,10 +73,6 @@ private: static int osc_non_hello ( const char *, const char *, lo_arg **, int , lo_message msg, void * ); -protected: - - int handle ( int m ); - public: char * get_unique_track_name ( const char *name ); diff --git a/mixer/src/Mixer_Strip.C b/mixer/src/Mixer_Strip.C index ed52b8b..4ef75f3 100644 --- a/mixer/src/Mixer_Strip.C +++ b/mixer/src/Mixer_Strip.C @@ -211,7 +211,7 @@ Mixer_Strip::chain ( Chain *c ) void Mixer_Strip::cb_handle(Fl_Widget* o) { // parent()->parent()->damage( FL_DAMAGE_ALL, x(), y(), w(), h() ); - DMESSAGE( "Callback for %s", o->label() ); + // DMESSAGE( "Callback for %s", o->label() ); if ( o == tab_button ) { @@ -440,8 +440,7 @@ Mixer_Strip::init ( ) } // Fl_Button* o o->end(); - } // Fl_Group* o - + } // Fl_Group* o { Fl_Flip_Button* o = tab_button = new Fl_Flip_Button(61, 183, 45, 22, "fader/signal"); o->type(1); o->labelsize( 14 ); @@ -481,7 +480,6 @@ Mixer_Strip::init ( ) o->pad( false ); o->size( 33, 100 ); } - { Meter_Indicator_Module *o = meter_indicator = new Meter_Indicator_Module( true ); o->disable_context_menu( true ); o->pad( false ); @@ -693,15 +691,30 @@ Mixer_Strip::menu ( void ) const int Mixer_Strip::handle ( int m ) { + static int _button = 0; + Logger log( this ); + if ( Fl_Group::handle( m ) ) + return 1; + + switch ( m ) + { + case FL_FOCUS: + damage( FL_DAMAGE_USER1 ); + return 1; + case FL_UNFOCUS: + damage( FL_DAMAGE_USER1 ); + return 1; + } + + /* if ( m == FL_PUSH ) */ + /* take_focus(); */ + switch ( m ) { case FL_KEYBOARD: { - if ( Fl_Group::handle( m ) ) - return 1; - if ( Fl::event_key() == FL_Menu ) { menu_popup( &menu(), x(), y() ); @@ -712,34 +725,27 @@ Mixer_Strip::handle ( int m ) break; } case FL_PUSH: + _button = Fl::event_button(); + case FL_RELEASE: { - int r = 0; - if ( Fl::event_button1() ) - { - take_focus(); - r = 1; - } - - if ( Fl_Group::handle( m ) ) - return 1; - else if ( test_press( FL_BUTTON3 ) ) + int b = _button; + _button = 0; + + /* if ( 1 == b ) */ + /* { */ + /* take_focus(); */ + /* } */ + /* else */ + if ( 3 == b ) { menu_popup( &menu() ); return 1; } - else - return r; break; } - case FL_FOCUS: - damage( FL_DAMAGE_USER1 ); - return Fl_Group::handle( m ) || 1; - case FL_UNFOCUS: - damage( FL_DAMAGE_USER1 ); - return Fl_Group::handle( m ) || 1; } - - return Fl_Group::handle( m ); + + return 0; } diff --git a/mixer/src/Module.C b/mixer/src/Module.C index ec2d0ce..4f21afc 100644 --- a/mixer/src/Module.C +++ b/mixer/src/Module.C @@ -133,6 +133,7 @@ Module::init ( void ) box( FL_UP_BOX ); labeltype( FL_NO_LABEL ); + align( FL_ALIGN_CENTER | FL_ALIGN_INSIDE ); set_visible_focus(); selection_color( FL_RED ); color( fl_color_average( FL_WHITE, FL_CYAN, 0.40 ) ); @@ -599,7 +600,7 @@ Module::draw_label ( int tx, int ty, int tw, int th ) } - fl_draw( s ? s : lp, tx, ty, tw, th, (Fl_Align)(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP ) ); + fl_draw( s ? s : lp, tx, ty, tw, th, align() | FL_ALIGN_CLIP ); if ( s ) delete[] s; @@ -777,13 +778,15 @@ Module::handle_chain_name_changed ( ) int Module::handle ( int m ) { + static int _button = 0; + + if ( Fl_Group::handle( m ) ) + return 1; + switch ( m ) { case FL_KEYBOARD: { - if ( Fl_Group::handle( m ) ) - return 1; - if ( Fl::event_key() == FL_Menu ) { menu_popup( &menu(), x(), y() ); @@ -792,28 +795,35 @@ Module::handle ( int m ) else return menu().test_shortcut() != 0; } - case FL_PUSH: - { + case FL_PUSH: take_focus(); - - if ( Fl_Group::handle( m ) ) - return 1; - else if ( test_press( FL_BUTTON3 ) ) + _button = Fl::event_button(); + return 1; + // if ( Fl::visible_focus() && handle( FL_FOCUS )) Fl::focus(this); + case FL_DRAG: + _button = Fl::event_button(); + return 1; + case FL_RELEASE: + { + int b = _button; + _button = 0; + DMESSAGE( "Button %i", b); + if ( 3 == b ) { menu_popup( &menu() ); return 1; } - else if ( test_press( FL_BUTTON1 ) ) + else if ( 1 == b ) { command_open_parameter_editor(); return 1; } - else if ( test_press( FL_BUTTON3 | FL_CTRL ) ) + else if ( 3 == b && Fl::event_ctrl() ) { command_remove(); return 1; } - else if ( test_press( FL_BUTTON2 ) ) + else if ( 2 == b ) { if ( !bypassable() ) { @@ -826,6 +836,10 @@ Module::handle ( int m ) } return 1; } + /* else */ + /* { */ + /* take_focus(); */ + /* } */ return 0; } @@ -835,7 +849,7 @@ Module::handle ( int m ) return 1; } - return Fl_Group::handle( m ); + return 0; } diff --git a/mixer/src/main.C b/mixer/src/main.C index 8d270e3..b9acbc3 100644 --- a/mixer/src/main.C +++ b/mixer/src/main.C @@ -295,7 +295,8 @@ main ( int argc, char **argv ) } Fl::add_timeout( 0.1f, check_sigterm ); - + Fl::dnd_text_ops( 0 ); + if ( ! no_ui ) { DMESSAGE( "Running UI..." ); diff --git a/nonlib/JACK/Client.C b/nonlib/JACK/Client.C index 7362998..02a9316 100644 --- a/nonlib/JACK/Client.C +++ b/nonlib/JACK/Client.C @@ -108,7 +108,11 @@ namespace JACK ((Client*)arg)->shutdown(); } - + void + Client::port_connect ( jack_port_id_t a, jack_port_id_t b, int connect, void *arg ) + { + ((Client*)arg)->port_connect( a, b, connect ); + } /** Connect to JACK using client name /client_name/. Return a static * pointer to actual name as reported by JACK */ @@ -125,6 +129,7 @@ namespace JACK set_callback( xrun ); set_callback( freewheel ); set_callback( buffer_size ); + set_callback( port_connect ); /* FIXME: should we wait to register this until after the project has been loaded (and we have disk threads running)? */ diff --git a/nonlib/JACK/Client.H b/nonlib/JACK/Client.H index 697156e..93f804b 100644 --- a/nonlib/JACK/Client.H +++ b/nonlib/JACK/Client.H @@ -40,6 +40,8 @@ namespace JACK volatile bool _freewheeling; volatile bool _zombified; + static void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect, void *arg ); + virtual void port_connect ( jack_port_id_t a, jack_port_id_t b, int connect ) { } static void shutdown ( void *arg ); virtual void shutdown ( void ) = 0; static int process ( nframes_t nframes, void *arg ); diff --git a/nonlib/JACK/Port.C b/nonlib/JACK/Port.C index ad62300..7770318 100644 --- a/nonlib/JACK/Port.C +++ b/nonlib/JACK/Port.C @@ -298,6 +298,42 @@ namespace JACK return true; } + int + Port::connect ( const char *to ) + { + const char *name = jack_port_name( _port ); + + if ( _direction == Output ) + { + return jack_connect( _client->jack_client(), name, to ); + } + else + { + return jack_connect( _client->jack_client(), to, name ); + } + } + + + int + Port::disconnect ( const char *from ) + { + const char *name = jack_port_name( _port ); + + if ( _direction == Output ) + { + return jack_disconnect( _client->jack_client(), name, from ); + } + else + { + return jack_disconnect( _client->jack_client(), from, name ); + } + } + + bool + Port::connected_to ( const char *to ) + { + return jack_port_connected_to( _port, to ); + } void Port::freeze ( void ) diff --git a/nonlib/JACK/Port.H b/nonlib/JACK/Port.H index 24f3c4b..3d54d1b 100644 --- a/nonlib/JACK/Port.H +++ b/nonlib/JACK/Port.H @@ -74,6 +74,9 @@ namespace JACK void *buffer ( nframes_t nframes ); void silence ( nframes_t nframes ); + int connect ( const char *to ); + int disconnect ( const char *from ); + bool connected_to ( const char *to ); /* */ const char ** connections ( void ); bool connections ( const char **port_names ); diff --git a/timeline/src/Audio_Sequence.C b/timeline/src/Audio_Sequence.C index 5dce3d2..6fe702d 100644 --- a/timeline/src/Audio_Sequence.C +++ b/timeline/src/Audio_Sequence.C @@ -253,6 +253,8 @@ Audio_Sequence::handle ( int m ) { case FL_PASTE: { + if ( ! Fl::event_inside( this ) ) + return 0; const char *text = Fl::event_text(); if ( ! strcmp( text, "Audio_Region" ) ) @@ -262,7 +264,7 @@ Audio_Sequence::handle ( int m ) if ( ! sscanf( text, "file://%a[^\r\n]\n", &file ) ) { - printf( "invalid drop \"%s\"\n", text ); + WARNING( "invalid drop \"%s\"\n", text ); return 0; } diff --git a/timeline/src/Audio_Sequence.H b/timeline/src/Audio_Sequence.H index b2fe976..62c2646 100644 --- a/timeline/src/Audio_Sequence.H +++ b/timeline/src/Audio_Sequence.H @@ -43,7 +43,6 @@ protected: void handle_widget_change ( nframes_t start, nframes_t length ); void draw ( void ); - int handle ( int m ); static void cb_button ( Fl_Widget *w, void *v ); void cb_button ( Fl_Widget *w ); @@ -52,6 +51,8 @@ protected: public: + int handle ( int m ); + LOG_CREATE_FUNC( Audio_Sequence ); Audio_Sequence_Header * header ( void ) { return (Audio_Sequence_Header*)child(0); } diff --git a/timeline/src/Sequence.C b/timeline/src/Sequence.C index 9eb2946..df1850d 100644 --- a/timeline/src/Sequence.C +++ b/timeline/src/Sequence.C @@ -389,9 +389,7 @@ Sequence::handle ( int m ) fl_cursor( FL_CURSOR_DEFAULT ); Fl_Group::handle( m ); return 1; - case FL_DND_DRAG: - return 1; - case FL_ENTER: + case FL_ENTER: // DMESSAGE( "enter" ); if ( Fl::event_x() >= drawable_x() ) { @@ -424,10 +422,14 @@ Sequence::handle ( int m ) { return Fl_Group::handle(m); } + case FL_DND_DRAG: case FL_DND_ENTER: case FL_DND_LEAVE: case FL_DND_RELEASE: - return 1; + if ( Fl::event_x() >= drawable_x() ) + return 1; + else + return 0; case FL_MOVE: { if ( Fl::event_x() >= drawable_x() ) diff --git a/timeline/src/Track.C b/timeline/src/Track.C index 4613fee..31e897d 100644 --- a/timeline/src/Track.C +++ b/timeline/src/Track.C @@ -47,6 +47,7 @@ #include #include "FL/menu_popup.H" +extern char *instance_name; @@ -997,6 +998,8 @@ Track::menu ( void ) const #include "FL/event_name.H" #include "FL/test_press.H" +static Fl_Widget *receptive_to_drop = NULL; + void Track::draw ( void ) { @@ -1020,6 +1023,12 @@ Track::draw ( void ) else Fl_Group::draw(); + if ( ((Track_Header*)child(0))->input_connector_handle == receptive_to_drop ) + { + Fl_Widget *o = ((Track_Header*)child(0))->input_connector_handle; + fl_draw_box( FL_OVAL_BOX, o->x(), o->y(), o->w(), o->h(), fl_color_add_alpha( FL_GREEN, 127 ) ); + } + if ( ! Track::colored_tracks ) color( saved_color ); @@ -1032,6 +1041,19 @@ Track::handle ( int m ) /* if ( m != FL_NO_EVENT ) */ /* DMESSAGE( "%s", event_name( m ) ); */ + + switch ( m ) + { + case FL_DND_ENTER: + case FL_DND_LEAVE: + case FL_DND_DRAG: + case FL_DND_RELEASE: + case FL_PASTE: + if ( Fl::event_x() > Track::width() ) + return sequence()->handle(m); + default: + break; + } switch ( m ) { @@ -1065,6 +1087,9 @@ Track::handle ( int m ) } case FL_PUSH: { + if ( Fl::event_inside( ((Track_Header*)child(0))->output_connector_handle ) ) + return 1; + Logger log( this ); if ( Fl_Group::handle( m ) ) @@ -1078,6 +1103,140 @@ Track::handle ( int m ) return 0; } + /* we have to prevent Fl_Group::handle() from getting these, otherwise it will mess up Fl::belowmouse() */ + case FL_ENTER: + case FL_LEAVE: + case FL_MOVE: + if ( Fl::event_x() >= Track::width() ) + { + return sequence()->handle(m); + } + return 0; + case FL_DND_ENTER: + return 1; + case FL_DND_LEAVE: + + if ( ! Fl::event_inside(this) && this == receptive_to_drop ) + { + receptive_to_drop = 0; + redraw(); + Fl::selection_owner(0); + } + return 1; + case FL_DND_RELEASE: + receptive_to_drop = 0; + redraw(); + Fl::selection_owner(0); + return 1; + case FL_DND_DRAG: + { + + if ( receptive_to_drop == ((Track_Header*)child(0))->input_connector_handle ) + return 1; + + + + if ( Fl::event_inside( ((Track_Header*)child(0))->input_connector_handle ) + && receptive_to_drop != ((Track_Header*)child(0))->input_connector_handle ) + + { + receptive_to_drop = ((Track_Header*)child(0))->input_connector_handle; + redraw(); + return 1; + } + else + { + receptive_to_drop = NULL; + redraw(); + return 0; + } + } + case FL_PASTE: + { + receptive_to_drop = 0; + redraw(); + + if (! Fl::event_inside( ((Track_Header*)child(0))->input_connector_handle ) ) + return 0; + + /* NOW we get the text... */ + const char *text = Fl::event_text(); + + DMESSAGE( "Got drop text \"%s\"",text); + + if ( strncmp( text, "jack.port://", strlen( "jack.port://" ) ) ) + { + return 0; + } + + std::vector port_names; + + char *port_name; + int end; + while ( sscanf( text, "jack.port://%a[^\r\n]\r\n%n", &port_name, &end ) > 0 ) + { + DMESSAGE( "Scanning %s", port_name ); + port_names.push_back( port_name ); + free(port_name ); + + text += end; + } + + for ( unsigned int i = 0; i < input.size() && i < port_names.size(); i++) + { + const char *pn = port_names[i].c_str(); + + JACK::Port *ji = &input[i]; + + if ( ji->connected_to( pn ) ) + { + + DMESSAGE( "Disconnecting from \"%s\"", pn ); + ji->disconnect( pn ); + } + else + { + DMESSAGE( "Connecting to %s", pn ); + ji->connect( pn ); + } + } + + Fl::selection_owner(0); + + return 1; + } + case FL_DRAG: + { + if ( this != Fl::selection_owner() && + Fl::event_inside( ((Track_Header*)child(0))->output_connector_handle ) ) + { + char *s = (char*)malloc(256); + s[0] = 0; + + for ( unsigned int i = 0; i < output.size(); ++i ) + { + char *s2; + asprintf(&s2, "jack.port://%s:%s\r\n", instance_name, output[i].name() ); + + s = (char*)realloc( s, strlen( s ) + strlen( s2 ) + 1 ); + strcat( s, s2 ); + + free( s2 ); + } + + Fl::copy(s, strlen(s) + 1, 0); + Fl::selection_owner(this); + + free( s ); + + Fl::dnd(); + + return 1; + } + else + return 0; + + } default: return Fl_Group::handle( m ); } diff --git a/timeline/src/Track_Header.fl b/timeline/src/Track_Header.fl index e130784..da402ad 100644 --- a/timeline/src/Track_Header.fl +++ b/timeline/src/Track_Header.fl @@ -8,20 +8,35 @@ decl {\#include "FL/Fl_Sometimes_Input.H"} {public global decl {\#include "FL/Fl_Blink_Button.H"} {public global } +decl {\#include } {private local +} + +decl {\#include } {private local +} + +decl {\#include } {private local +} + +decl {Fl_PNG_Image *output_connector_image = NULL;} {private local +} + +decl {Fl_PNG_Image *input_connector_image = NULL;} {private local +} + widget_class Track_Header {open - xywh {897 224 525 60} type Double box NO_BOX resizable visible + xywh {680 695 525 60} type Double box NO_BOX resizable visible } { Fl_Group box_group {open private xywh {0 0 200 60} box THIN_UP_BOX color 63 code0 {o->resizable(0);} } { Fl_Group {} {open - xywh {0 0 200 51} + xywh {0 0 200 55} code0 {o->resizable(0);} } { Fl_Input name_input { label {input:} - xywh {0 2 200 23} labeltype NO_LABEL align 20 when 8 + xywh {4 2 151 22} labeltype NO_LABEL align 20 when 8 class Fl_Sometimes_Input } Fl_Button track_inputs_indicator { @@ -56,6 +71,16 @@ widget_class Track_Header {open label s tooltip solo xywh {172 26 24 24} type Toggle selection_color 91 labelfont 5 labelsize 12 } + Fl_Box input_connector_handle { + tooltip {Drag and drop this input connector to make or break JACK connections} xywh {157 4 18 18} box FLAT_BOX + code0 {o->image( input_connector_image ? input_connector_image : input_connector_image = new Fl_PNG_Image( "input-connector", img_io_input_connector_10x10_png, img_io_input_connector_10x10_png_len ) );} + code1 {o->box(FL_NO_BOX);} + } + Fl_Box output_connector_handle {selected + tooltip {Drag and drop this output connector to make or break JACK connections} xywh {177 4 18 18} box FLAT_BOX + code0 {o->image( output_connector_image ? output_connector_image : output_connector_image = new Fl_PNG_Image( "output-connector", img_io_output_connector_10x10_png, img_io_output_connector_10x10_png_len ) );} + code1 {o->box(FL_NO_BOX);} + } } } Fl_Box {} { @@ -72,7 +97,7 @@ Fl_Group::draw();} {} } widget_class Control_Sequence_Header {open - xywh {315 771 200 55} type Double box NO_BOX visible + xywh {325 886 200 55} type Double box NO_BOX visible } { Fl_Input name_input { label {input:} @@ -80,7 +105,7 @@ widget_class Control_Sequence_Header {open class Fl_Sometimes_Input } Fl_Button menu_button { - label menu selected + label menu tooltip {Expand controls} xywh {5 26 31 24} selection_color 3 labelfont 4 labelsize 10 } Fl_Button outputs_indicator { @@ -103,7 +128,7 @@ widget_class Control_Sequence_Header {open } widget_class Audio_Sequence_Header {open - xywh {332 613 200 50} type Double box NO_BOX resizable visible + xywh {404 670 200 50} type Double box NO_BOX resizable visible } { Fl_Group {} {open xywh {0 0 200 55}