@@ -31,6 +31,7 @@ int Loggable::_level = 0; | |||||
int Loggable::_undo_index = 1; | int Loggable::_undo_index = 1; | ||||
vector <Loggable *> Loggable::_loggables; | vector <Loggable *> Loggable::_loggables; | ||||
map <string, create_func*> Loggable::_class_map; | |||||
bool | bool | ||||
Loggable::open ( const char *filename ) | 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 */ | /** 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 | static | ||||
char ** | char ** | ||||
parse_alist( const char *s ) | 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 | void | ||||
Loggable::undo ( void ) | Loggable::undo ( void ) | ||||
{ | { | ||||
@@ -113,18 +126,22 @@ Loggable::undo ( void ) | |||||
// FIXME: handle blocks | // FIXME: handle blocks | ||||
int i = 1; | 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 ( int j = _undo_index; j-- ; ) | ||||
for ( --s; *s && s >= buf; --s, ++i ) | for ( --s; *s && s >= buf; --s, ++i ) | ||||
{ | { | ||||
if ( *s == '\n' ) | if ( *s == '\n' ) | ||||
{ | { | ||||
// s++; | |||||
if ( *(s + 1) == '\t' ) | |||||
continue; | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
s++; | s++; | ||||
strtok( s, "\n" ); | |||||
buf[ len ] = NULL; | buf[ len ] = NULL; | ||||
// fsync( fileno( _fp ) ); | // fsync( fileno( _fp ) ); | ||||
@@ -144,23 +161,58 @@ Loggable::undo ( void ) | |||||
int id; | int id; | ||||
sscanf( s, "%*s %X ", &id ); | sscanf( s, "%*s %X ", &id ); | ||||
Loggable *l = find( id ); | Loggable *l = find( id ); | ||||
assert( l ); | |||||
// assert( l ); | |||||
char classname[40]; | |||||
char command[40]; | char command[40]; | ||||
char *arguments; | 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; | ++_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 | void | ||||
Loggable::log_print( char **o, char **n ) | Loggable::log_print( char **o, char **n ) | ||||
{ | { | ||||
@@ -244,10 +285,6 @@ log_diff ( char **sa1, char **sa2 ) | |||||
return w == 0 ? false : true; | return w == 0 ? false : true; | ||||
} | } | ||||
void | void | ||||
Loggable::log_start ( void ) | Loggable::log_start ( void ) | ||||
{ | { | ||||
@@ -256,6 +293,7 @@ Loggable::log_start ( void ) | |||||
++_nest; | ++_nest; | ||||
_undo_index = 1; | |||||
} | } | ||||
void | void | ||||
@@ -300,7 +338,7 @@ void | |||||
Loggable::log_create ( void ) | Loggable::log_create ( void ) | ||||
{ | { | ||||
indent(); | indent(); | ||||
log( "%s 0x%X new ", class_name(), _id ); | |||||
log( "%s 0x%X create ", class_name(), _id ); | |||||
char **sa = log_dump(); | char **sa = log_dump(); | ||||
@@ -317,11 +355,12 @@ void | |||||
Loggable::log_destroy ( void ) | Loggable::log_destroy ( void ) | ||||
{ | { | ||||
indent(); | indent(); | ||||
log( "%s 0x%X destroy ", class_name(), _id ); | |||||
log( "%s 0x%X destroy (nothing) << ", class_name(), _id ); | |||||
char **sa = log_dump(); | char **sa = log_dump(); | ||||
log_print( sa, NULL ); | |||||
// log_print( sa, NULL ); | |||||
log_print( NULL, sa ); | |||||
free_sa( sa ); | free_sa( sa ); | ||||
} | } |
@@ -28,6 +28,13 @@ | |||||
#include <vector> | #include <vector> | ||||
using std::vector; | using std::vector; | ||||
#include <map> | |||||
using std::map; | |||||
#include <string> | |||||
using std::string; | |||||
class Loggable; | |||||
typedef Loggable *(create_func)(char **); | |||||
class Logger; | class Logger; | ||||
class Loggable | class Loggable | ||||
@@ -40,6 +47,8 @@ class Loggable | |||||
static vector <Loggable *> _loggables; | static vector <Loggable *> _loggables; | ||||
static map <string, create_func*> _class_map; | |||||
private: | private: | ||||
int _id; | int _id; | ||||
@@ -65,13 +74,14 @@ public: | |||||
static bool open ( const char *filename ); | static bool open ( const char *filename ); | ||||
static void undo ( void ); | static void undo ( void ); | ||||
static int undo_index ( void ) { return _undo_index; } | |||||
static | static | ||||
void | void | ||||
block_start ( void ) | block_start ( void ) | ||||
{ | { | ||||
indent(); | indent(); | ||||
log( "{\n" ); | |||||
// log( "{\n" ); | |||||
++Loggable::_level; | ++Loggable::_level; | ||||
} | } | ||||
static | static | ||||
@@ -80,7 +90,7 @@ public: | |||||
{ | { | ||||
assert( --Loggable::_level >= 0 ); | assert( --Loggable::_level >= 0 ); | ||||
indent(); | indent(); | ||||
log( "}\n" ); | |||||
// log( "}\n" ); | |||||
} | } | ||||
static | static | ||||
@@ -102,6 +112,21 @@ public: | |||||
_loggables.push_back( this ); | _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 */ | /* log messages for journal */ | ||||
virtual const char *class_name ( void ) = 0; | virtual const char *class_name ( void ) = 0; | ||||
@@ -63,15 +63,18 @@ protected: | |||||
char ** log_dump ( void ) | char ** log_dump ( void ) | ||||
{ | { | ||||
// char *r; | // 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( &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 ); | // 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; | char *v = s + strlen( s ) + 1; | ||||
if ( *v == '"' ) | |||||
{ | |||||
v++; | |||||
v[ strlen( v ) - 2 ] = '\0'; | |||||
} | |||||
if ( ! strcmp( s, ":x" ) ) | if ( ! strcmp( s, ":x" ) ) | ||||
_offset = atol( v ); | _offset = atol( v ); | ||||
else | else | ||||
@@ -104,7 +113,9 @@ protected: | |||||
else | else | ||||
if ( ! strcmp( s, ":gain" ) ) | if ( ! strcmp( s, ":gain" ) ) | ||||
_scale = atof( v ); | _scale = atof( v ); | ||||
else | |||||
if ( ! strcmp( s, ":source" ) ) | |||||
_clip = Audio_File::from_file( v ); | |||||
/* else */ | /* else */ | ||||
/* if ( ! strcmp( s, ":track" ) ) */ | /* if ( ! strcmp( s, ":track" ) ) */ | ||||
/* { */ | /* { */ | ||||
@@ -123,11 +134,29 @@ protected: | |||||
free( sa ); | free( sa ); | ||||
_track->redraw(); | |||||
if ( _track ) | |||||
_track->redraw(); | |||||
} | |||||
Region ( ) | |||||
{ | |||||
init(); | |||||
} | } | ||||
public: | 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_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); } | 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->tracks->position( timeline->tracks->x(), (timeline->rulers->y() + timeline->rulers->h()) - sb->value() ); | ||||
timeline->yposition = 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 ); | timeline->damage( FL_DAMAGE_SCROLL ); | ||||
} | } | ||||
@@ -91,8 +91,11 @@ public: | |||||
log_create(); | log_create(); | ||||
} | } | ||||
~Track ( ) | |||||
virtual ~Track ( ) | |||||
{ | { | ||||
/* FIXME: what to do with regions? */ | |||||
parent()->redraw(); | |||||
parent()->remove( this ); | |||||
log_destroy(); | log_destroy(); | ||||
} | } | ||||
@@ -53,6 +53,12 @@ public: | |||||
_selected = false; | _selected = false; | ||||
} | } | ||||
virtual ~Track_Widget ( ) | |||||
{ | |||||
redraw(); | |||||
_track->remove( this ); | |||||
} | |||||
Fl_Group * parent ( void ) const { return _track; } | Fl_Group * parent ( void ) const { return _track; } | ||||
int scroll_x ( void ) const { return timeline->ts_to_x( timeline->xoffset ); } | 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 ) | void cb_undo ( Fl_Widget *w, void *v ) | ||||
{ | { | ||||
static char pat[20]; | |||||
Loggable::undo(); | Loggable::undo(); | ||||
sprintf( pat, "undo %d", Loggable::undo_index() ); | |||||
w->label( pat ); | |||||
} | } | ||||
int | int | ||||
@@ -65,6 +71,8 @@ main ( int argc, char **argv ) | |||||
Fl::scheme( "plastic" ); | Fl::scheme( "plastic" ); | ||||
Loggable::open( "history" ); | Loggable::open( "history" ); | ||||
Loggable::register_create( "Region", &Region::create ); | |||||
timeline = new Timeline( 0, 0, 800, 600, "Timeline" ); | timeline = new Timeline( 0, 0, 800, 600, "Timeline" ); | ||||