| @@ -31,6 +31,7 @@ int Loggable::_level = 0; | |||
| int Loggable::_undo_index = 1; | |||
| vector <Loggable *> Loggable::_loggables; | |||
| map <string, create_func*> Loggable::_class_map; | |||
| bool | |||
| Loggable::open ( const char *filename ) | |||
| @@ -45,6 +46,7 @@ Loggable::open ( const char *filename ) | |||
| } | |||
| /** sigh. parse a string of ":name value :name value" pairs into an array of strings, one per pair */ | |||
| // FIXME: doesn't handle the case of :name ":foo bar". Also, quotes should be removed here, not in client code. | |||
| static | |||
| char ** | |||
| parse_alist( const char *s ) | |||
| @@ -94,6 +96,17 @@ parse_alist( const char *s ) | |||
| } | |||
| static | |||
| void free_sa ( char **sa ) | |||
| { | |||
| char **a = sa; | |||
| for ( ; *a; a++ ) | |||
| free( *a ); | |||
| free( sa ); | |||
| } | |||
| void | |||
| Loggable::undo ( void ) | |||
| { | |||
| @@ -113,18 +126,22 @@ Loggable::undo ( void ) | |||
| // FIXME: handle blocks | |||
| int i = 1; | |||
| /* move back _undo_index lines from the end */ | |||
| /* move back _undo_index items from the end */ | |||
| for ( int j = _undo_index; j-- ; ) | |||
| for ( --s; *s && s >= buf; --s, ++i ) | |||
| { | |||
| if ( *s == '\n' ) | |||
| { | |||
| // s++; | |||
| if ( *(s + 1) == '\t' ) | |||
| continue; | |||
| break; | |||
| } | |||
| } | |||
| s++; | |||
| strtok( s, "\n" ); | |||
| buf[ len ] = NULL; | |||
| // fsync( fileno( _fp ) ); | |||
| @@ -144,23 +161,58 @@ Loggable::undo ( void ) | |||
| int id; | |||
| sscanf( s, "%*s %X ", &id ); | |||
| Loggable *l = find( id ); | |||
| assert( l ); | |||
| // assert( l ); | |||
| char classname[40]; | |||
| char command[40]; | |||
| char *arguments; | |||
| sscanf( s, "%*s %*X %s %*[^\n<] << %a[^\n]", command, &arguments ); | |||
| sscanf( s, "%s %*X %s %*[^\n<] << %a[^\n]", classname, command, &arguments ); | |||
| int ui = _undo_index; | |||
| if ( ! strcmp( command, "set" ) ) | |||
| if ( ! l ) | |||
| { | |||
| printf( "corrupt undo?\n" ); | |||
| abort(); | |||
| } | |||
| printf( "got set command.\n" ); | |||
| char **sa = parse_alist( arguments ); | |||
| l->set( sa ); | |||
| if ( ! strcmp( command, "destroy" ) ) | |||
| { | |||
| printf( "should create new %s here\n", classname ); | |||
| char **sa = parse_alist( arguments ); | |||
| _class_map[ string( classname ) ]( sa ); | |||
| } | |||
| else | |||
| if ( ! strcmp( command, "set" ) ) | |||
| { | |||
| printf( "got set command.\n" ); | |||
| char **sa = parse_alist( arguments ); | |||
| l->log_start(); | |||
| l->set( sa ); | |||
| l->log_end(); | |||
| } | |||
| else | |||
| if ( ! strcmp( command, "create" ) ) | |||
| { | |||
| int id = l->id(); | |||
| delete l; | |||
| _loggables[ id ] = NULL; | |||
| } | |||
| // FIXME: bogus... needs to account for multiple events. | |||
| _undo_index = ui + 1; | |||
| ++_undo_index; | |||
| @@ -184,17 +236,6 @@ Loggable::log ( const char *fmt, ... ) | |||
| } | |||
| static | |||
| void free_sa ( char **sa ) | |||
| { | |||
| char **a = sa; | |||
| for ( ; *a; a++ ) | |||
| free( *a ); | |||
| free( sa ); | |||
| } | |||
| void | |||
| Loggable::log_print( char **o, char **n ) | |||
| { | |||
| @@ -244,10 +285,6 @@ log_diff ( char **sa1, char **sa2 ) | |||
| return w == 0 ? false : true; | |||
| } | |||
| void | |||
| Loggable::log_start ( void ) | |||
| { | |||
| @@ -256,6 +293,7 @@ Loggable::log_start ( void ) | |||
| ++_nest; | |||
| _undo_index = 1; | |||
| } | |||
| void | |||
| @@ -300,7 +338,7 @@ void | |||
| Loggable::log_create ( void ) | |||
| { | |||
| indent(); | |||
| log( "%s 0x%X new ", class_name(), _id ); | |||
| log( "%s 0x%X create ", class_name(), _id ); | |||
| char **sa = log_dump(); | |||
| @@ -317,11 +355,12 @@ void | |||
| Loggable::log_destroy ( void ) | |||
| { | |||
| indent(); | |||
| log( "%s 0x%X destroy ", class_name(), _id ); | |||
| log( "%s 0x%X destroy (nothing) << ", class_name(), _id ); | |||
| char **sa = log_dump(); | |||
| log_print( sa, NULL ); | |||
| // log_print( sa, NULL ); | |||
| log_print( NULL, sa ); | |||
| free_sa( sa ); | |||
| } | |||
| @@ -28,6 +28,13 @@ | |||
| #include <vector> | |||
| using std::vector; | |||
| #include <map> | |||
| using std::map; | |||
| #include <string> | |||
| using std::string; | |||
| class Loggable; | |||
| typedef Loggable *(create_func)(char **); | |||
| class Logger; | |||
| class Loggable | |||
| @@ -40,6 +47,8 @@ class Loggable | |||
| static vector <Loggable *> _loggables; | |||
| static map <string, create_func*> _class_map; | |||
| private: | |||
| int _id; | |||
| @@ -65,13 +74,14 @@ public: | |||
| static bool open ( const char *filename ); | |||
| static void undo ( void ); | |||
| static int undo_index ( void ) { return _undo_index; } | |||
| static | |||
| void | |||
| block_start ( void ) | |||
| { | |||
| indent(); | |||
| log( "{\n" ); | |||
| // log( "{\n" ); | |||
| ++Loggable::_level; | |||
| } | |||
| static | |||
| @@ -80,7 +90,7 @@ public: | |||
| { | |||
| assert( --Loggable::_level >= 0 ); | |||
| indent(); | |||
| log( "}\n" ); | |||
| // log( "}\n" ); | |||
| } | |||
| static | |||
| @@ -102,6 +112,21 @@ public: | |||
| _loggables.push_back( this ); | |||
| } | |||
| virtual ~Loggable ( ) | |||
| { | |||
| } | |||
| static | |||
| void | |||
| register_create ( const char *name, create_func *func ) | |||
| { | |||
| printf( "registering %s to %p\n", name, func ); | |||
| _class_map[ string( name ) ] = func; | |||
| } | |||
| /* log messages for journal */ | |||
| virtual const char *class_name ( void ) = 0; | |||
| @@ -63,15 +63,18 @@ protected: | |||
| char ** log_dump ( void ) | |||
| { | |||
| // char *r; | |||
| char **sa = (char**)malloc( sizeof( char* ) * 6 ); | |||
| char **sa = (char**)malloc( sizeof( char* ) * 7 ); | |||
| sa[5] = NULL; | |||
| int i = 0; | |||
| asprintf( &sa[0], ":x %lu", _offset ); | |||
| asprintf( &sa[1], ":l %lu", _start ); | |||
| asprintf( &sa[2], ":r %lu", _end ); | |||
| asprintf( &sa[3], ":selected %d", _selected ); | |||
| asprintf( &sa[4], ":gain %f", _scale ); | |||
| asprintf( &sa[ i++ ], ":source \"%s\"", _clip->name() ); | |||
| asprintf( &sa[ i++ ], ":x %lu", _offset ); | |||
| asprintf( &sa[ i++ ], ":l %lu", _start ); | |||
| asprintf( &sa[ i++ ], ":r %lu", _end ); | |||
| asprintf( &sa[ i++ ], ":selected %d", _selected ); | |||
| asprintf( &sa[ i++ ], ":gain %f", _scale ); | |||
| sa[ i ] = NULL; | |||
| // asprintf( &sa[4], ":track 0x%X", _track->id() ); | |||
| // asprintf( &r, ":x %lu\n:l %lu\n:r %lu\n:selected %d\n:gain %f", _offset, _start, _end, _selected, _scale ); | |||
| @@ -90,6 +93,12 @@ protected: | |||
| char *v = s + strlen( s ) + 1; | |||
| if ( *v == '"' ) | |||
| { | |||
| v++; | |||
| v[ strlen( v ) - 2 ] = '\0'; | |||
| } | |||
| if ( ! strcmp( s, ":x" ) ) | |||
| _offset = atol( v ); | |||
| else | |||
| @@ -104,7 +113,9 @@ protected: | |||
| else | |||
| if ( ! strcmp( s, ":gain" ) ) | |||
| _scale = atof( v ); | |||
| else | |||
| if ( ! strcmp( s, ":source" ) ) | |||
| _clip = Audio_File::from_file( v ); | |||
| /* else */ | |||
| /* if ( ! strcmp( s, ":track" ) ) */ | |||
| /* { */ | |||
| @@ -123,11 +134,29 @@ protected: | |||
| free( sa ); | |||
| _track->redraw(); | |||
| if ( _track ) | |||
| _track->redraw(); | |||
| } | |||
| Region ( ) | |||
| { | |||
| init(); | |||
| } | |||
| public: | |||
| /* for loggable */ | |||
| static Loggable * | |||
| create ( char **sa ) | |||
| { | |||
| Region *r = new Region; | |||
| r->set( sa ); | |||
| return (Loggable *)r; | |||
| } | |||
| Fl_Boxtype box ( void ) const { return Region::_box; } | |||
| Fl_Align align ( void ) const { return (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_BOTTOM /*| FL_ALIGN_CLIP*/ | FL_ALIGN_INSIDE); } | |||
| @@ -55,7 +55,9 @@ cb_vscroll ( Fl_Widget *w, void *v ) | |||
| timeline->tracks->position( timeline->tracks->x(), (timeline->rulers->y() + timeline->rulers->h()) - sb->value() ); | |||
| timeline->yposition = sb->value(); | |||
| timeline->vscroll->range( 0, timeline->tracks->h() - timeline->h() - timeline->rulers->h() ); | |||
| // timeline->vscroll->range( 0, timeline->tracks->h() - timeline->h() - timeline->rulers->h() ); | |||
| sb->value( sb->value(), 30, 0, min( timeline->tracks->h(), timeline->tracks->h() - timeline->h() - timeline->rulers->h() ) ); | |||
| timeline->damage( FL_DAMAGE_SCROLL ); | |||
| } | |||
| @@ -91,8 +91,11 @@ public: | |||
| log_create(); | |||
| } | |||
| ~Track ( ) | |||
| virtual ~Track ( ) | |||
| { | |||
| /* FIXME: what to do with regions? */ | |||
| parent()->redraw(); | |||
| parent()->remove( this ); | |||
| log_destroy(); | |||
| } | |||
| @@ -53,6 +53,12 @@ public: | |||
| _selected = false; | |||
| } | |||
| virtual ~Track_Widget ( ) | |||
| { | |||
| redraw(); | |||
| _track->remove( this ); | |||
| } | |||
| Fl_Group * parent ( void ) const { return _track; } | |||
| int scroll_x ( void ) const { return timeline->ts_to_x( timeline->xoffset ); } | |||
| @@ -53,7 +53,13 @@ Timeline *timeline; | |||
| void cb_undo ( Fl_Widget *w, void *v ) | |||
| { | |||
| static char pat[20]; | |||
| Loggable::undo(); | |||
| sprintf( pat, "undo %d", Loggable::undo_index() ); | |||
| w->label( pat ); | |||
| } | |||
| int | |||
| @@ -65,6 +71,8 @@ main ( int argc, char **argv ) | |||
| Fl::scheme( "plastic" ); | |||
| Loggable::open( "history" ); | |||
| Loggable::register_create( "Region", &Region::create ); | |||
| timeline = new Timeline( 0, 0, 800, 600, "Timeline" ); | |||