(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.tags/non-daw-v1.2.0
@@ -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 ); | |||
} | |||
}; |
@@ -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; | |||
} | |||
}; |
@@ -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; |
@@ -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; |
@@ -1 +1 @@ | |||
Subproject commit fe832d3cbc807c475f4b6a51facf543aa7d9882d | |||
Subproject commit ed50ecc551d5e490f4acb1ec673c9e8f43e23fb0 |
@@ -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()); | |||
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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; | |||
@@ -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 ) | |||
@@ -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 ); | |||
}; |
@@ -22,6 +22,9 @@ | |||
#include <string.h> | |||
#include <FL/fl_ask.H> | |||
#include <FL/Fl_Box.H> | |||
#include <FL/Fl_Pack.H> | |||
#include <FL/Fl_Scalepack.H> | |||
#include "dsp.h" | |||
@@ -29,14 +32,30 @@ | |||
#include "Chain.H" | |||
#include "JACK_Module.H" | |||
#include <FL/fl_draw.H> | |||
#include <FL/Fl.H> | |||
#include <FL/Fl_Browser.H> | |||
#include <FL/Fl_PNG_Image.H> | |||
#include <FL/img_io_input_connector_10x10_png.h> | |||
#include <FL/img_io_output_connector_10x10_png.h> | |||
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<std::string> | |||
get_connections_for_ports ( std::vector<JACK::Port> ports ) | |||
{ | |||
std::list<std::string> 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<std::string>::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<std::string> output_names = get_connections_for_ports( jack_output ); | |||
std::list<std::string> input_names = get_connections_for_ports( jack_input ); | |||
connection_display->clear(); | |||
int n = 0; | |||
for ( std::list<std::string>::const_iterator j = input_names.begin(); | |||
j != input_names.end(); | |||
j++ ) | |||
{ | |||
connection_display->add( j->c_str() ); | |||
n++; | |||
} | |||
for ( std::list<std::string>::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<std::string> 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); | |||
} | |||
/**********/ | |||
@@ -19,6 +19,8 @@ | |||
#pragma once | |||
class Fl_Box; | |||
class Fl_Browser; | |||
#include "Module.H" | |||
#include "JACK/Port.H" | |||
#include <vector> | |||
@@ -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 ); | |||
@@ -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; | |||
} | |||
/************/ | |||
@@ -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 ); | |||
@@ -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; | |||
} | |||
@@ -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; | |||
} | |||
@@ -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..." ); | |||
@@ -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)? */ | |||
@@ -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 ); | |||
@@ -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 ) | |||
@@ -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 ); | |||
@@ -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; | |||
} | |||
@@ -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); } | |||
@@ -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() ) | |||
@@ -47,6 +47,7 @@ | |||
#include <FL/Fl_Menu_Button.H> | |||
#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<std::string> 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 ); | |||
} | |||
@@ -8,20 +8,35 @@ decl {\#include "FL/Fl_Sometimes_Input.H"} {public global | |||
decl {\#include "FL/Fl_Blink_Button.H"} {public global | |||
} | |||
decl {\#include <FL/Fl_PNG_Image.H>} {private local | |||
} | |||
decl {\#include <FL/img_io_input_connector_10x10_png.h>} {private local | |||
} | |||
decl {\#include <FL/img_io_output_connector_10x10_png.h>} {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} | |||