diff --git a/Mixer/Gain_Module.H b/Mixer/Gain_Module.H index 3f52ae1..6988788 100644 --- a/Mixer/Gain_Module.H +++ b/Mixer/Gain_Module.H @@ -26,6 +26,7 @@ class Gain_Module : public Module public: Gain_Module ( ); + Gain_Module ( const Gain_Module & rhs ); virtual ~Gain_Module ( ); const char *name ( void ) const { return "Gain"; } @@ -35,6 +36,8 @@ public: LOG_CREATE_FUNC( Gain_Module ); + MODULE_CLONE_FUNC( Gain_Module ); + protected: virtual void process ( nframes_t nframes ); diff --git a/Mixer/Module.C b/Mixer/Module.C index 6333f5c..27d6b15 100644 --- a/Mixer/Module.C +++ b/Mixer/Module.C @@ -40,6 +40,11 @@ +Module *Module::_copied_module_empty = 0; +char *Module::_copied_module_settings = 0; + + + Module::Module ( int W, int H, const char *L ) : Fl_Group( 0, 0, W, H, L ) { init(); @@ -109,9 +114,70 @@ Module::get ( Log_Entry &e ) const } e.add( ":is_default", is_default() ); e.add( ":chain", chain() ); - e.add( ":active", bypass() ); + e.add( ":active", ! bypass() ); +} + +void +Module::copy ( void ) const +{ + Module *m = clone_empty(); + + if ( ! m ) + { + DMESSAGE( "Module \"%s\" doesn't support cloning", name() ); + } + + Log_Entry *ne = new Log_Entry(); + + _copied_module_empty = m; + + { + Log_Entry e; + get( e ); + + for ( int i = 0; i < e.size(); ++i ) + { + const char *s, *v; + + e.get( i, &s, &v ); + + /* we don't want this module to get added to the current + chain... */ + if ( !( !strcmp( s, ":chain" ) || + !strcmp( s, ":is_default" ) ) ) + { + DMESSAGE( "%s = %s", s, v ); + ne->add_raw( s, v ); + } + } + } + + _copied_module_settings = ne->print(); } +void +Module::paste_before ( void ) +{ + Module *m = _copied_module_empty; + + m->chain( chain() ); + Log_Entry le( _copied_module_settings ); + m->set( le ); + + if ( ! chain()->insert( this, m ) ) + { + fl_alert( "Copied module cannot be inserted at this point in the chain" ); + } + + free( _copied_module_settings ); + _copied_module_settings = NULL; + _copied_module_empty = NULL; + + /* set up for another copy */ + m->copy(); +} + + void Module::set ( Log_Entry &e ) { @@ -153,7 +219,7 @@ Module::set ( Log_Entry &e ) } else if ( ! ( strcmp( s, ":active" ) ) ) { - bypass( atoi( v ) ); + bypass( ! atoi( v ) ); } else if ( ! strcmp( s, ":chain" ) ) { @@ -197,10 +263,9 @@ void Module::set_parameters ( const char *parameters ) { char *s = strdup( parameters ); - char *sp = s; char *start = s; - int i = 0; + unsigned int i = 0; for ( char *sp = s; ; ++sp ) { if ( ':' == *sp || '\0' == *sp ) @@ -289,6 +354,7 @@ Module::draw_label ( void ) Fl_Color c = FL_FOREGROUND_COLOR; if ( bypass() || ! active() ) + c = FL_BLACK; fl_color( c ); @@ -406,6 +472,21 @@ Module::menu_cb ( const Fl_Menu_ *m ) command_activate(); else if ( ! strcmp( picked, "Deactivate" ) ) command_deactivate(); + else if ( ! strcmp( picked, "Cut" ) ) + { + copy(); + + chain()->remove( this ); + Fl::delete_widget( this ); + } + else if ( ! strcmp( picked, "Copy" ) ) + { + copy(); + } + else if ( ! strcmp( picked, "Paste" ) ) + { + paste_before(); + } else if ( ! strcmp( picked, "Remove" ) ) command_remove(); } @@ -444,6 +525,9 @@ Module::menu ( void ) const m.add( "Edit Parameters", 0, &Module::menu_cb, (void*)this, 0 ); m.add( "Activate", 0, &Module::menu_cb, (void*)this, ! bypass() ? FL_MENU_INACTIVE : 0 ); m.add( "Deactivate", 0, &Module::menu_cb, (void*)this, bypass() ? FL_MENU_INACTIVE : 0 ); + m.add( "Cut", FL_CTRL + 'x', &Module::menu_cb, (void*)this, is_default() ? FL_MENU_INACTIVE : 0 ); + m.add( "Copy", FL_CTRL + 'c', &Module::menu_cb, (void*)this, is_default() ? FL_MENU_INACTIVE : 0 ); + m.add( "Paste", FL_CTRL + 'v', &Module::menu_cb, (void*)this, _copied_module_empty ? 0 : FL_MENU_INACTIVE ); m.add( "Remove", 0, &Module::menu_cb, (void*)this ); // menu_set_callback( menu, &Module::menu_cb, (void*)this ); diff --git a/Mixer/Module.H b/Mixer/Module.H index e30edbe..a4c443d 100644 --- a/Mixer/Module.H +++ b/Mixer/Module.H @@ -49,6 +49,9 @@ class Module : public Fl_Group, public Loggable { Module_Parameter_Editor *_editor; + static Module *_copied_module_empty; + static char *_copied_module_settings; + void init ( void ); void insert_menu_cb ( const Fl_Menu_ *m ); @@ -58,6 +61,9 @@ class Module : public Fl_Group, public Loggable { static void menu_cb ( Fl_Widget *w, void *v ); Fl_Menu_Button & menu ( void ) const; + void copy ( void ) const; + void paste_before ( void ); + public: /* true if this module was added by default and not under normal user control */ @@ -339,6 +345,16 @@ public: virtual void handle_port_connection_change () {} +#define MODULE_CLONE_FUNC(class) \ + virtual Module *clone_empty ( void ) const \ + { \ + return new class (); \ + } + + virtual Module *clone_empty ( void ) const { return NULL; } + Module *clone ( Chain *dest ) const; + Module *clone ( void ) const; + protected: void draw_connections ( void ); diff --git a/Mixer/Mono_Pan_Module.H b/Mixer/Mono_Pan_Module.H index d7ec37a..f585aac 100644 --- a/Mixer/Mono_Pan_Module.H +++ b/Mixer/Mono_Pan_Module.H @@ -35,6 +35,8 @@ public: LOG_CREATE_FUNC( Mono_Pan_Module ); + MODULE_CLONE_FUNC( Mono_Pan_Module ); + protected: virtual void process ( nframes_t nframes ); diff --git a/Mixer/Plugin_Module.H b/Mixer/Plugin_Module.H index 1764999..15e85c0 100644 --- a/Mixer/Plugin_Module.H +++ b/Mixer/Plugin_Module.H @@ -114,6 +114,8 @@ public: LOG_CREATE_FUNC( Plugin_Module ); + MODULE_CLONE_FUNC( Plugin_Module ); + protected: void get ( Log_Entry &e ) const; diff --git a/nonlib/Log_Entry.H b/nonlib/Log_Entry.H index ba6e91d..eb4e0d7 100644 --- a/nonlib/Log_Entry.H +++ b/nonlib/Log_Entry.H @@ -49,14 +49,20 @@ public: void grow ( ); -#define ADD( type, format, exp ) \ - void add ( const char *name, type v ) \ - { \ - grow(); \ - if ( -1 == asprintf( &_sa[ _i ], "%s " format, name, (exp) ) ) \ - abort(); \ - strtok( _sa[ _i++ ], " " ); \ - } \ +#define ADD( type, format, exp ) \ + void add ( const char *name, type v ) \ + { \ + grow(); \ + asprintf( &_sa[ _i ], "%s " format, name, (exp) ); \ + strtok( _sa[ _i++ ], " " ); \ + } + + void add_raw ( const char *name, const char *v ) + { + grow(); + asprintf( &_sa[ _i ], "%s %s", name, v ); + strtok( _sa[ _i++ ], " " ); + } /***************/ /* Examination */ diff --git a/nonlib/Loggable.C b/nonlib/Loggable.C index af26fce..61e0062 100644 --- a/nonlib/Loggable.C +++ b/nonlib/Loggable.C @@ -699,6 +699,7 @@ Loggable::log_end ( void ) /** Log object creation. *Must* be called at the end of all public * constructors for leaf classes */ + void Loggable::log_create ( void ) const { diff --git a/nonlib/Loggable.H b/nonlib/Loggable.H index f423b82..66c4d32 100644 --- a/nonlib/Loggable.H +++ b/nonlib/Loggable.H @@ -46,20 +46,20 @@ typedef Loggable *(create_func)(Log_Entry &, unsigned int id); #define LOG_NAME_FUNC( class ) \ virtual const char *class_name ( void ) const { return #class ; } -#define LOG_CREATE_FUNC( class ) \ - static Loggable * \ - create ( Log_Entry &e, unsigned int id ) \ - { \ - class *r = new class; \ - r->update_id( id ); \ - r->set( e ); \ - return (Loggable *)r; \ - } \ - LOG_NAME_FUNC( class ); \ +#define LOG_CREATE_FUNC( class ) \ + static Loggable * \ + create ( Log_Entry &e, unsigned int id ) \ + { \ + class *r = new class; \ + r->update_id( id ); \ + r->set( e ); \ + return (Loggable *)r; \ + } \ + LOG_NAME_FUNC( class ); #define LOG_NOT_LOGGABLE_FUNC( class ) \ - virtual const char *class_name ( void ) const { return #class ; } \ + virtual const char *class_name ( void ) const { return #class ; } class Logger; class Loggable