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.
This commit is contained in:
Jonathan Moore Liles 2013-04-21 23:14:52 -07:00
parent 52f016abed
commit 455c93683c
26 changed files with 919 additions and 90 deletions

View File

@ -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 );
}
};

View File

@ -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;
}
};

View File

@ -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;

View File

@ -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

View File

@ -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());

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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 )

View File

@ -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 );
};

View File

@ -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 )
@ -151,6 +382,11 @@ 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);
}
/**********/

View File

@ -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 );

View File

@ -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;
}
/************/

View File

@ -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 );

View File

@ -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 )
{
@ -441,7 +441,6 @@ Mixer_Strip::init ( )
o->end();
} // 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;
}
int b = _button;
_button = 0;
if ( Fl_Group::handle( m ) )
return 1;
else if ( test_press( FL_BUTTON3 ) )
/* 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;
}

View File

@ -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() );
@ -793,27 +796,34 @@ Module::handle ( int m )
return menu().test_shortcut() != 0;
}
case FL_PUSH:
{
take_focus();
if ( Fl_Group::handle( m ) )
_button = Fl::event_button();
return 1;
else if ( test_press( FL_BUTTON3 ) )
// 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;
}

View File

@ -295,6 +295,7 @@ main ( int argc, char **argv )
}
Fl::add_timeout( 0.1f, check_sigterm );
Fl::dnd_text_ops( 0 );
if ( ! no_ui )
{

View File

@ -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)? */

View File

@ -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 );

View File

@ -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 )

View File

@ -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 );

View File

@ -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;
}

View File

@ -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); }

View File

@ -389,8 +389,6 @@ Sequence::handle ( int m )
fl_cursor( FL_CURSOR_DEFAULT );
Fl_Group::handle( m );
return 1;
case FL_DND_DRAG:
return 1;
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:
if ( Fl::event_x() >= drawable_x() )
return 1;
else
return 0;
case FL_MOVE:
{
if ( Fl::event_x() >= drawable_x() )

View File

@ -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 );
@ -1033,6 +1042,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 )
{
case FL_KEYBOARD:
@ -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 );
}

View File

@ -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}