From 455c93683c3d105b361a50899656be30fc9436a7 Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Sun, 21 Apr 2013 23:14:52 -0700 Subject: [PATCH] Implement drag and drop for making/breaking JACK connections in Non Mixer and Non Timeline. (Drag jack output module and drop on jack input module of another strip) In Non Mixer, all JACK modules (including Aux) will now list their connections. --- FL/Fl_Packscroller.H | 3 +- FL/Fl_Sometimes_Input.H | 24 +- FL/img_io_input_connector_10x10_png.h | 61 ++++ FL/img_io_output_connector_10x10_png.h | 63 ++++ lib/ntk | 2 +- mixer/src/AUX_Module.C | 1 + mixer/src/Chain.C | 41 +++ mixer/src/Chain.H | 7 + mixer/src/Engine/Engine.C | 17 ++ mixer/src/Engine/Engine.H | 6 +- mixer/src/JACK_Module.C | 381 ++++++++++++++++++++++++- mixer/src/JACK_Module.H | 17 +- mixer/src/Mixer.C | 16 -- mixer/src/Mixer.H | 4 - mixer/src/Mixer_Strip.C | 60 ++-- mixer/src/Module.C | 42 ++- mixer/src/main.C | 3 +- nonlib/JACK/Client.C | 7 +- nonlib/JACK/Client.H | 2 + nonlib/JACK/Port.C | 36 +++ nonlib/JACK/Port.H | 3 + timeline/src/Audio_Sequence.C | 4 +- timeline/src/Audio_Sequence.H | 3 +- timeline/src/Sequence.C | 10 +- timeline/src/Track.C | 159 +++++++++++ timeline/src/Track_Header.fl | 37 ++- 26 files changed, 919 insertions(+), 90 deletions(-) create mode 100644 FL/img_io_input_connector_10x10_png.h create mode 100644 FL/img_io_output_connector_10x10_png.h 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}