From 451e948a17c431ad38fd2e21ebd6947e6afb3211 Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Tue, 7 May 2013 15:24:54 -0700 Subject: [PATCH] Sequencer: GUI tweaks. --- nonlib/MIDI/event.C | 2 + nonlib/MIDI/event.H | 1 + nonlib/MIDI/event_list.C | 84 +++++++- nonlib/MIDI/event_list.H | 10 +- sequencer/src/canvas.C | 414 +++++++++++++++++++++++++++++--------- sequencer/src/canvas.H | 25 ++- sequencer/src/grid.C | 116 ++++++++--- sequencer/src/grid.H | 19 +- sequencer/src/gui/ui.fl | 309 ++++++++++++++-------------- sequencer/src/transport.C | 2 +- 10 files changed, 687 insertions(+), 295 deletions(-) diff --git a/nonlib/MIDI/event.C b/nonlib/MIDI/event.C index 7614787..6e488f2 100644 --- a/nonlib/MIDI/event.C +++ b/nonlib/MIDI/event.C @@ -149,6 +149,7 @@ namespace MIDI p->duration = note_duration(); p->velocity = note_velocity(); p->note = note(); + p->selected = selected(); } void @@ -158,5 +159,6 @@ namespace MIDI note_duration( p->duration ); note_velocity( p->velocity ); note( p->note ); + selected( p->selected ); } } diff --git a/nonlib/MIDI/event.H b/nonlib/MIDI/event.H index 1de9d42..e6ac346 100644 --- a/nonlib/MIDI/event.H +++ b/nonlib/MIDI/event.H @@ -36,6 +36,7 @@ namespace MIDI tick_t duration; int note; int velocity; + bool selected; }; class event : public midievent diff --git a/nonlib/MIDI/event_list.C b/nonlib/MIDI/event_list.C index e0c7e09..229622f 100644 --- a/nonlib/MIDI/event_list.C +++ b/nonlib/MIDI/event_list.C @@ -350,6 +350,59 @@ namespace MIDI } } + + /** copy selected events into event list /el/ */ + void + event_list::copy_selected ( event_list *el ) const + { + event *fi = first(); + + if ( ! fi ) + return; + + tick_t offset = fi->timestamp(); + + FOR_SELECTED( e ) + { + event *nel = 0; + + if ( e->linked() ) + nel = new event(*e->link()); + + event *ne = new event(*e); + ne->timestamp( ne->timestamp() - offset ); + + if ( nel ) + { + nel->link( ne ); + ne->link( nel ); + nel->timestamp( nel->timestamp() - offset ); + } + + el->mix(ne); + } + } + + /** add events from list /el/ */ + void + event_list::paste ( tick_t offset, const event_list *el ) + { + event *n; + + for ( event *e = el->_head; e; e = n ) + { + n = e->_next; + + event *ne = new event(*e); + ne->link( NULL ); + ne->timestamp( ne->timestamp() + offset ); + + insert( ne ); + } + + relink(); + } + /** transpose selected notes (ignoring other event types) by /n/ tones * (may span octaves) */ void @@ -377,7 +430,7 @@ namespace MIDI /** get timestamp of earliest selected event */ tick_t - event_list::selection_min ( void ) + event_list::selection_min ( void ) const { FOR_SELECTED( e ) return e->timestamp(); @@ -386,7 +439,7 @@ namespace MIDI } tick_t - event_list::selection_max ( void ) + event_list::selection_max ( void ) const { RFOR_SELECTED( e ) return e->timestamp(); @@ -396,7 +449,7 @@ namespace MIDI /** move selected events by offset /o/ */ void - event_list::move_selected ( long o ) + event_list::nudge_selected ( long o ) { if ( o < 0 ) if ( selection_min() < (tick_t)( 0 - o ) ) @@ -414,6 +467,31 @@ namespace MIDI } } + /** move block of selected events to tick /tick/ */ + void + event_list::move_selected ( tick_t tick ) + { + /* if ( o < 0 ) */ + /* if ( selection_min() < (tick_t)( 0 - o ) ) */ + /* return; */ + + tick_t min = selection_min(); + + tick_t offset = tick - min; + + nudge_selected( offset ); + + /* FOR_SELECTED( e ) */ + /* { */ + /* e->timestamp( e->timestamp() + offset ); */ + + /* sort( e ); */ + + /* move( e, o ); */ + /* } */ + + } + void event_list::push_selection ( void ) { diff --git a/nonlib/MIDI/event_list.H b/nonlib/MIDI/event_list.H index 47c43f3..b06bc5b 100644 --- a/nonlib/MIDI/event_list.H +++ b/nonlib/MIDI/event_list.H @@ -57,12 +57,15 @@ namespace MIDI { void select_all ( void ); void select_none ( void ); void invert_selection ( void ); + void copy_selected ( event_list *el ) const; + void paste ( tick_t offset, const event_list *el ); void remove_selected ( void ); void transpose_selected ( int n ); - tick_t selection_min ( void ); - tick_t selection_max ( void ); - void move_selected ( long o ); + tick_t selection_min ( void ) const; + tick_t selection_max ( void ) const; + void move_selected ( tick_t tick ); + void nudge_selected ( long o ); void push_selection ( void ); void pop_selection ( void ); bool verify ( void ) const; @@ -81,7 +84,6 @@ namespace MIDI { void rewrite_selected ( int from, int to ); void selected_hi_lo_note ( int *hi, int *lo ) const; - event_list & operator= ( const event_list &rhs ); event_list & operator= ( const list &rhs ); event *operator[] ( unsigned int index ); diff --git a/sequencer/src/canvas.C b/sequencer/src/canvas.C index 1d5f659..e491cb7 100644 --- a/sequencer/src/canvas.C +++ b/sequencer/src/canvas.C @@ -154,6 +154,8 @@ static note_properties *ghost_note = 0; Canvas::Canvas ( int X, int Y, int W, int H, const char *L ) : Fl_Group( X,Y,W,H,L ) { + _selection_mode = SELECT_NONE; + _move_mode = false; { Fl_Box *o = new Fl_Box( X, Y, W, H - 75 ); /* this is a dummy group where the canvas goes */ @@ -218,7 +220,10 @@ Canvas::handle_event_change ( void ) /* mark the song as dirty and pass the signal on */ song.set_dirty(); -// panzoomer->redraw(); + Grid *g = grid(); + panzoomer->x_value( g->x_to_ts( m.vp->x), g->x_to_ts( m.vp->w ), 0, g->length()); + + // panzoomer->redraw(); redraw(); } @@ -255,7 +260,7 @@ Canvas::grid ( Grid *g ) redraw(); // parent()->redraw(); -// signal_settings_change(); + signal_settings_change(); } /** keep row compaction tables up-to-date */ @@ -401,6 +406,7 @@ gui_draw_ruler ( int x, int y, int w, int div_w, int div, int ofs, int p1, int p { /* Across the top */ + fl_font( FL_TIMES, ruler_height ); int h = ruler_height; @@ -412,6 +418,7 @@ gui_draw_ruler ( int x, int y, int w, int div_w, int div, int ofs, int p1, int p // fl_rectf( x, y, x + (div_w * w), y + h ); fl_rectf( x, y, (div_w * w), h ); + fl_color( FL_FOREGROUND_COLOR ); fl_line( x + div_w / 2, y, x + div_w * w, y ); @@ -437,28 +444,28 @@ gui_draw_ruler ( int x, int y, int w, int div_w, int div, int ofs, int p1, int p } } - /* if ( p1 != p2 ) */ - /* { */ - /* if ( p1 >= 0 ) */ - /* { */ - /* if ( p1 < p2 ) */ - /* fl_color( FL_GREEN ); */ - /* else */ - /* fl_color( FL_RED ); */ + if ( p1 != p2 ) + { + if ( p1 >= 0 ) + { + if ( p1 < p2 ) + fl_color( fl_color_add_alpha( FL_GREEN, 100 ) ); + else + fl_color( fl_color_add_alpha( FL_GREEN, 100 ) ); - /* fl_rectf( x + (div_w * p1), y + h / 2, div_w, h / 2 ); */ + fl_rectf( x + (div_w * p1), y + h / 2, div_w, h / 2 ); - /* } */ - /* if ( p2 >= 0 ) */ - /* { */ - /* if ( p2 < p1 ) */ - /* fl_color( FL_GREEN ); */ - /* else */ - /* fl_color( FL_RED ); */ - /* fl_rectf( x + (div_w * p2), y + h / 2, div_w, h / 2 ); */ + } + if ( p2 >= 0 ) + { + if ( p2 < p1 ) + fl_color( fl_color_add_alpha( FL_GREEN, 100 ) ); + else + fl_color( fl_color_add_alpha( FL_RED, 100 ) ); + fl_rectf( x + (div_w * p2), y + h / 2, div_w, h / 2 ); - /* } */ - /* } */ + } + } return h; } @@ -614,8 +621,17 @@ Canvas::draw_dash ( tick_t x, int y, tick_t w, int color, int selected ) const if ( w > 4 ) { fl_draw_box( FL_ROUNDED_BOX, x, y + 1, w, m.div_h - 1, color ); + if ( selected ) - fl_draw_box( FL_ROUNDED_FRAME, x, y + 1, w, m.div_h - 1, FL_MAGENTA ); + { + cairo_set_operator( Fl::cairo_cc(),CAIRO_OPERATOR_HSL_COLOR ); + + fl_draw_box( FL_ROUNDED_BOX, x, y + 1, w, m.div_h - 1, FL_MAGENTA ); + + cairo_set_operator( Fl::cairo_cc(),CAIRO_OPERATOR_OVER); + } + /* if ( selected ) */ + /* fl_draw_box( FL_ROUNDED_FRAME, x, y + 1, w, m.div_h - 1, FL_MAGENTA ); */ } // fl_color_add_alpha( color, 170 )); @@ -677,11 +693,29 @@ Canvas::draw_overlay ( void ) draw_playhead(); + if ( _selection_mode ) + { + int X,Y,W,H; + + SelectionRect &s = _selection_rect; + + X = s.x1 < s.x2 ? s.x1 : s.x2; + Y = s.y1 < s.y2 ? s.y1 : s.y2; + W = s.x1 < s.x2 ? s.x2 - s.x1 : s.x1 - s.x2; + H = s.y1 < s.y2 ? s.y2 - s.y1 : s.y1 - s.y2; + + /* fl_rectf( X,Y,W,H, fl_color_add_alpha( FL_MAGENTA, 50 ) ); */ + + fl_rect( X,Y,W,H, FL_MAGENTA ); + + } + fl_pop_clip(); panzoomer->draw_overlay(); fl_pop_clip(); + } /** draw only the playhead--without reexamining the grid */ @@ -962,6 +996,12 @@ Canvas::is_row_press ( void ) const return -1; } +bool +Canvas::is_ruler_click ( void ) const +{ + return Fl::event_y() < m.origin_y + m.margin_top; +} + void Canvas::start_cursor ( int x, int y ) { @@ -971,7 +1011,9 @@ Canvas::start_cursor ( int x, int y ) m.ruler_drawn = false; m.p1 = x; - m.p3 = ntr( y ); + + + /* m.p3 = ntr( y ); */ _lr(); @@ -987,7 +1029,8 @@ Canvas::end_cursor ( int x, int y ) m.ruler_drawn = false; m.p2 = x; - m.p4 = ntr( y ); + + /* m.p4 = ntr( y ); */ _lr(); @@ -1036,10 +1079,10 @@ Canvas::move_selected ( int dir, int n ) switch ( dir ) { case RIGHT: - m.grid->move_selected( n ); + m.grid->nudge_selected( n ); break; case LEFT: - m.grid->move_selected( 0 - n ); + m.grid->nudge_selected( 0 - n ); break; case UP: case DOWN: @@ -1158,6 +1201,27 @@ Canvas::duplicate_range ( void ) g->viewport.x = 0; } +void +Canvas::cut ( void ) +{ + m.grid->cut(); +} + +void +Canvas::copy ( void ) +{ + m.grid->copy(); +} + +void +Canvas::paste ( void ) +{ + if ( m.p1 != m.p2 && m.p1 > m.vp->x && m.p1 < m.vp->x + m.vp->w ) + m.grid->paste( m.p1 ); + else + m.grid->paste( m.vp->x ); +} + void Canvas::row_compact ( int n ) { @@ -1289,12 +1353,18 @@ Canvas::notes ( void ) { return m.grid->notes(); } - + + int Canvas::handle ( int m ) { Canvas *c = this; + static int last_move_x = 0; + static int last_move_y = 0; + + static bool range_select; + int ow, oh; int x, y; @@ -1307,9 +1377,6 @@ Canvas::handle ( int m ) static int drag_y; static bool delete_note; static note_properties *drag_note; - static int adjusting_velocity; - -// static note_properties; ow = c->grid()->viewport.w; oh = c->grid()->viewport.h; @@ -1318,6 +1385,7 @@ Canvas::handle ( int m ) { case FL_FOCUS: case FL_UNFOCUS: + damage( FL_DAMAGE_ALL ); return 1; case FL_ENTER: case FL_LEAVE: @@ -1338,12 +1406,11 @@ Canvas::handle ( int m ) } case FL_KEYBOARD: { - + /* if ( Fl::event_state() & FL_ALT || Fl::event_state() & FL_CTRL ) */ /* // this is more than a simple keypress. */ /* return 0; */ - if ( Fl::event_state() & FL_CTRL ) { switch ( Fl::event_key() ) @@ -1459,12 +1526,40 @@ Canvas::handle ( int m ) } case FL_PUSH: { + Fl::focus(this); + switch ( Fl::event_button() ) { case 1: { + if ( is_ruler_click() ) + { + c->start_cursor( x, y ); + // return 1; + _selection_mode = SELECT_RANGE; + + } + + if ( _selection_mode ) + { + drag_x = Fl::event_x(); + drag_y = Fl::event_y(); + + _selection_rect.x1 = drag_x; + _selection_rect.y1 = drag_y; + _selection_rect.x2 = drag_x; + _selection_rect.y2 = drag_y; + + if ( _selection_mode == SELECT_RANGE ) + { + _selection_rect.y1 = 0; + _selection_rect.y2 = 2000; + } + + return 1; + } + delete_note = true; - adjusting_velocity = 0; if ( Fl::event_ctrl() ) { @@ -1497,12 +1592,20 @@ Canvas::handle ( int m ) if ( ! this->m.grid->is_set( dx,dy )) { ghost_note = new note_properties; - + drag_note = new note_properties; + ghost_note->start = this->m.grid->x_to_ts( dx ); ghost_note->note = dy; ghost_note->duration = this->m.grid->default_length(); ghost_note->velocity = 64; + + drag_note->start = this->m.grid->x_to_ts( dx ); + drag_note->note = dy; + drag_note->duration = this->m.grid->default_length(); + drag_note->velocity = 64; + + delete_note = false; processed = 1; @@ -1510,13 +1613,26 @@ Canvas::handle ( int m ) } else { - ghost_note = new note_properties; - drag_note = new note_properties; - this->m.grid->get_note_properties( dx, dy, ghost_note ); - this->m.grid->get_note_properties( dx, dy, drag_note ); - this->m.grid->del( dx, dy ); + note_properties np; + this->m.grid->get_note_properties( dx, dy, &np ); - delete_note = true; + if ( np.selected ) + { + _move_mode = true; + /* initiate move */ + last_move_x = dx; + last_move_y = ntr( dy ); + } + else + { + ghost_note = new note_properties; + drag_note = new note_properties; + this->m.grid->get_note_properties( dx, dy, ghost_note ); + this->m.grid->get_note_properties( dx, dy, drag_note ); + this->m.grid->del( dx, dy ); + + delete_note = true; + } } this->m.grid->get_start( &dx, &dy ); @@ -1552,11 +1668,31 @@ Canvas::handle ( int m ) } } else - if ( Fl::event_state() & FL_SHIFT ) + { + _selection_mode = SELECT_RECTANGLE; { - c->end_cursor( x, y ); - break; + drag_x = Fl::event_x(); + drag_y = Fl::event_y(); + + _selection_rect.x1 = drag_x; + _selection_rect.y1 = drag_y; + _selection_rect.x2 = drag_x; + _selection_rect.y2 = drag_y; + signal_settings_change(); + return 1; } + + return 1; + break; + + + } + + /* if ( Fl::event_state() & FL_SHIFT ) */ + /* { */ + /* c->end_cursor( x, y ); */ + /* break; */ + /* } */ break; } default: @@ -1565,63 +1701,156 @@ Canvas::handle ( int m ) break; } case FL_RELEASE: - switch ( Fl::event_button() ) + { + _move_mode = false; + + if ( SELECT_RANGE == _selection_mode ) { - case 1: + select_range(); + _selection_mode = SELECT_NONE; + return 1; + } + else if ( SELECT_RECTANGLE == _selection_mode ) + { + int X,Y,W,H; + + SelectionRect &s = _selection_rect; + + X = s.x1 < s.x2 ? s.x1 : s.x2; + Y = s.y1 < s.y2 ? s.y1 : s.y2; + W = s.x1 < s.x2 ? s.x2 - s.x1 : s.x1 - s.x2; + H = s.y1 < s.y2 ? s.y2 - s.y1 : s.y1 - s.y2; + + int endx = X + W; + int endy = Y + H; + int beginx = X; + int beginy = Y; + + grid_pos( &beginx, &beginy ); + grid_pos( &endx, &endy ); + + /* if ( is_ruler_click() ) */ + /* { */ + /* grid()->select( beginx, endx ); */ + /* } */ + /* else */ { - int dx = x; - int dy = y; - grid_pos( &dx, &dy ); + grid()->select( beginx, endx, beginy, endy ); + } - if ( IS_PATTERN && Fl::event_state() & ( FL_ALT | FL_CTRL ) ) - c->randomize_row( y ); - else - { - if ( delete_note ) - { + _selection_mode = SELECT_NONE; + + _selection_rect.x1 = 0; + _selection_rect.y1 = 0; + _selection_rect.x2 = 0; + _selection_rect.y2 = 0; + + damage(FL_DAMAGE_OVERLAY); + signal_settings_change(); + return 1; + } + + int dx = x; + int dy = y; + grid_pos( &dx, &dy ); + + if ( IS_PATTERN && Fl::event_state() & ( FL_ALT | FL_CTRL ) ) + c->randomize_row( y ); + else + { + if ( delete_note ) + { // this->m.grid->del( dx, dy ); - if ( ghost_note ) - { - damage_grid( ghost_note->start, ghost_note->note, ghost_note->duration, 1 ); + if ( ghost_note ) + { + damage_grid( ghost_note->start, ghost_note->note, ghost_note->duration, 1 ); - delete ghost_note; - } - ghost_note = 0; - } - else - if ( ghost_note ) - { - this->m.grid->put( this->m.grid->ts_to_x( ghost_note->start ), - ghost_note->note, - ghost_note->duration, - ghost_note->velocity); + delete ghost_note; + } + ghost_note = 0; + } + else + if ( ghost_note ) + { + this->m.grid->put( this->m.grid->ts_to_x( ghost_note->start ), + ghost_note->note, + ghost_note->duration, + ghost_note->velocity); - delete_note = false; + delete_note = false; - delete ghost_note; - ghost_note = 0; - } + delete ghost_note; + ghost_note = 0; + } + } + + if ( drag_note ) + delete drag_note; + drag_note = 0; + + break; + } + + case FL_DRAG: + + if ( Fl::event_is_click() ) + return 1; + + { + if ( _selection_mode ) + { + grid()->select_none(); + + _selection_rect.x2 = x; + _selection_rect.y2 = y; + + if ( SELECT_RANGE == _selection_mode ) + { + _selection_rect.y2 = 2000; + c->end_cursor( x, y ); } - if ( drag_note ) - delete drag_note; - drag_note = 0; - - break; + damage(FL_DAMAGE_OVERLAY); + + return 1; } - default: - processed = 0; - break; - } - break; - case FL_DRAG: - if ( Fl::event_button1() ) - { + + int dx = x; int dy = y; grid_pos( &dx, &dy ); + if ( _move_mode ) + { + int odx = drag_x; + int ody = drag_y; + grid_pos( &odx, &ody ); + + if ( last_move_x != dx ) + { + //this->m.grid->move_selected( dx - move_xoffset ); + if ( dx > last_move_x ) + move_selected( RIGHT, dx - last_move_x ); + else + move_selected( LEFT, last_move_x - dx ); + } + + dy = ntr( dy ); + + if ( dy != last_move_y ) + { + if ( dy > last_move_y ) + move_selected( DOWN, dy - last_move_y ); + else + move_selected( UP, last_move_y - dy ); + } + + last_move_y = dy; + last_move_x = dx; + return 1; + } + if ( ghost_note ) { damage_grid( ghost_note->start, ghost_note->note, ghost_note->duration, 1 ); @@ -1635,8 +1864,6 @@ Canvas::handle ( int m ) if ( ody != dy ) { - adjusting_velocity = 1; - ghost_note->velocity = drag_note->velocity + ( (drag_y - y) / 3.0f ); @@ -1648,17 +1875,12 @@ Canvas::handle ( int m ) } } - if ( ! adjusting_velocity ) + if ( dx > this->m.grid->ts_to_x( ghost_note->start ) ) { - if ( dx > this->m.grid->ts_to_x( ghost_note->start ) ) - { - ghost_note->duration = this->m.grid->x_to_ts( dx ) - ghost_note->start; - } - - damage_grid( ghost_note->start, ghost_note->note, ghost_note->duration, 1 ); + ghost_note->duration = this->m.grid->x_to_ts( dx ) - ghost_note->start; } - else - ghost_note->duration = drag_note->duration; + + damage_grid( ghost_note->start, ghost_note->note, ghost_note->duration, 1 ); delete_note = false; diff --git a/sequencer/src/canvas.H b/sequencer/src/canvas.H index e7bde2a..7c6fc35 100644 --- a/sequencer/src/canvas.H +++ b/sequencer/src/canvas.H @@ -35,7 +35,15 @@ class Fl_Slider; class Canvas : public Fl_Group, public trackable { class Canvas_Panzoomer; + + struct SelectionRect { + int x1,y1,x2,y2; + }; + SelectionRect _selection_rect; + + int _selection_mode; + bool _move_mode; Canvas_Panzoomer *panzoomer; Fl_Slider *vzoom; @@ -84,6 +92,7 @@ class Canvas : public Fl_Group, public trackable uint p3, p4; /* row cursors */ } m; + bool is_ruler_click ( void ) const; int rtn ( int r ) const; int ntr ( int n ) const; @@ -104,15 +113,29 @@ class Canvas : public Fl_Group, public trackable static void draw_clip ( void *v, int X, int Y, int W, int H ); void draw_clip ( int X, int Y, int W, int H ); +enum { + SELECT_NONE = 0, + SELECT_RECTANGLE, + SELECT_RANGE +}; + public: + bool selection_mode ( void ) const { return _selection_mode; } + void selection_mode ( bool b ) + { + _selection_mode = b ? SELECT_RECTANGLE : SELECT_NONE; + } + enum { OFF, ON, TOGGLE }; signal signal_settings_change; Canvas ( int X, int Y, int W, int H, const char *L=0 ); virtual ~Canvas ( ); - + + void cut ( void ); + void paste ( void ); void redraw_playhead ( void ); void handle_event_change ( void ); void set ( int x, int y ); diff --git a/sequencer/src/grid.C b/sequencer/src/grid.C index b567916..a5e4771 100644 --- a/sequencer/src/grid.C +++ b/sequencer/src/grid.C @@ -27,6 +27,8 @@ using namespace MIDI; +MIDI::event_list Grid::_clipboard; + Grid::Grid ( void ) { _name = NULL; @@ -139,11 +141,13 @@ Grid::_event ( int x, int y, bool write ) const const event_list *r = write ? &_rw->events : &d->events; - if ( r->empty() || x_to_ts( x ) > _rd->length ) + tick_t xt = x_to_ts(x); + + if ( r->empty() ) +/* || xt > _rd->length ) */ return NULL; int note = y_to_note( y ); - tick_t xt = x_to_ts( x ); for ( event *e = r->first(); e; e = e->next() ) { @@ -153,14 +157,14 @@ Grid::_event ( int x, int y, bool write ) const if ( e->note() != note ) continue; - unsigned long ts = e->timestamp(); - unsigned long l = 0; + tick_t ts = e->timestamp(); + tick_t l = 0; if ( e->linked() ) l = e->link()->timestamp() - ts; else WARNING( "found unlinked event... event list is corrupt." ); - + if ( xt >= ts && xt < ts + l ) // this is a little nasty return const_cast(e); @@ -307,7 +311,8 @@ Grid::put ( int x, int y, tick_t l, int velocity ) event *off = new event; // Don't allow overlap (Why not?) - if ( _event( x, y, false ) || _event( x + xl - 1, y, false ) ) + if ( _event( x, y, false ) || + _event( x + xl, y, false ) ) return; DMESSAGE( "put %d,%d", x, y ); @@ -541,6 +546,37 @@ Grid::toggle_select ( int x, int y ) unlock(); } +/** copy selected notes to clipboard */ +void +Grid::copy ( void ) +{ + _rd->events.copy_selected( &_clipboard ); +} + +void +Grid::cut ( void ) +{ + _rd->events.copy_selected( &_clipboard ); + + lock(); + + _rw->events.remove_selected(); + + unlock(); +} + +void +Grid::paste ( int offset ) +{ + lock(); + + _rw->events.paste( x_to_ts( offset ), &_clipboard ); + + expand(); + + unlock(); + +} /** insert /l/ ticks of time after /x/ */ void @@ -641,9 +677,8 @@ Grid::delete_selected ( void ) } void -Grid::move_selected ( int l ) +Grid::nudge_selected ( int l ) { - long o = x_to_ts( abs( l ) ); if ( l < 0 ) @@ -651,6 +686,20 @@ Grid::move_selected ( int l ) lock(); +// MESSAGE( "moving by %ld", o ); + + _rw->events.nudge_selected( o ); + + unlock(); +} + +void +Grid::move_selected ( int l ) +{ + tick_t o = x_to_ts( l ); + + lock(); + // MESSAGE( "moving by %ld", o ); _rw->events.move_selected( o ); @@ -692,6 +741,11 @@ Grid::crop ( int l, int r, int t, int b ) unlock(); } +int +Grid::min_selected ( void ) const +{ + return ts_to_x( _rd->events.selection_min() ); +} void Grid::_relink ( void ) @@ -732,14 +786,6 @@ Grid::print ( void ) const void Grid::draw_notes ( draw_note_func_t draw_note, void *userdata ) const { - /* int bx = viewport.x; */ - /* int by = viewport.y; */ - /* int bw = viewport.w + 100; /\* FIXME: hack *\/ */ - /* int bh = viewport.h; */ - - /* const tick_t start = x_to_ts( bx ); */ - /* const tick_t end = x_to_ts( bx + bw ); */ - data *d = const_cast< data *>( _rd ); for ( const event *e = d->events.first(); e; e = e->next() ) @@ -753,8 +799,7 @@ Grid::draw_notes ( draw_note_func_t draw_note, void *userdata ) const const tick_t tse = e->link()->timestamp(); - /* if ( tse >= start && ts <= end ) */ - draw_note( // ts_to_x( ts ), + draw_note( ts, note_to_y( e->note() ), tse - ts, @@ -812,16 +857,32 @@ Grid::length ( tick_t l ) unlock(); } +void +Grid::bars ( int n ) +{ + lock(); + + _rw->length = n * _bpb * PPQN; + + _fix_length(); + + unlock(); + + // trim(); + + signal_events_change(); +} + int Grid::bars ( void ) const { - return ts_to_x( _rd->length ) / (_ppqn * _bpb); + return beats() / _bpb; } int Grid::beats ( void ) const { - return ts_to_x( _rd->length ) / _ppqn; + return _rd->length / PPQN; } int @@ -842,21 +903,16 @@ Grid::ppqn ( void ) const return _ppqn; } -/** set grid resolution to /n/, where 0 is 1/4 note, 1 is 1/8 note 2 is 1/16 note, etc. */ +/** set grid resolution to /n/, where /n/ is the denominator e.g. 1/n. */ void Grid::resolution ( unsigned int n ) { - /* if ( n < 4 ) */ - /* ASSERTION( "bad resolution: %d", n ); */ + float W = viewport.w / _ppqn; -// _ppqn = n / 4; _ppqn = n; - DMESSAGE( "%d setting resolution to %d", n, _ppqn ); - - /* ensure that the correct number of bars are in the viewport */ - - viewport.w = _ppqn * _bpb * 2; + viewport.w = _ppqn * W; + signal_events_change(); signal_settings_change(); @@ -865,7 +921,7 @@ Grid::resolution ( unsigned int n ) int Grid::resolution ( void ) const { - return _ppqn * 4; + return _ppqn; } int diff --git a/sequencer/src/grid.H b/sequencer/src/grid.H index 1c7027c..fda9b39 100644 --- a/sequencer/src/grid.H +++ b/sequencer/src/grid.H @@ -100,6 +100,8 @@ struct Viewport { class Grid : public trackable { + static MIDI::event_list _clipboard; + protected: unsigned int _height; @@ -161,7 +163,7 @@ public: int y_to_note ( int y ) const; int note_to_y ( int n ) const; tick_t x_to_ts ( unsigned long x ) const; - unsigned long ts_to_x ( tick_t ts ) const; + double ts_to_x ( tick_t ts ) const; virtual Grid * create ( void ) = 0; virtual Grid * clone ( void ) = 0; @@ -191,6 +193,8 @@ public: void height ( int h ); tick_t length ( void ) const; void length ( tick_t l ); + + void bars ( int n ); int bars ( void ) const; int beats ( void ) const; void trim ( void ); @@ -212,6 +216,7 @@ public: void delete_selected ( void ); void move_selected ( int l ); + void nudge_selected ( int l ); void crop ( int l, int r ); void crop ( int l, int r, int t, int b ); @@ -237,6 +242,12 @@ public: void get_note_properties ( int x, int y, MIDI::note_properties *p ) const; + int min_selected ( void ) const; + + void cut ( void ); + void copy ( void ); + void paste ( int offset ); + virtual tick_t default_length ( void ) const { return PPQN; @@ -261,14 +272,10 @@ inline tick_t Grid::x_to_ts ( unsigned long x ) const { return (x * PPQN) / _ppqn; - -// return x * (PPQN / _ppqn); } -inline unsigned long +inline double Grid::ts_to_x ( tick_t ts ) const { return (ts * _ppqn) / PPQN; - -// return ts / (PPQN / _ppqn); } diff --git a/sequencer/src/gui/ui.fl b/sequencer/src/gui/ui.fl index 802ddcf..0b0194d 100644 --- a/sequencer/src/gui/ui.fl +++ b/sequencer/src/gui/ui.fl @@ -109,7 +109,7 @@ Function {init_colors()} {open private C return_type {static void} } widget_class Visual_Metronome {open - xywh {1172 936 100 100} type Double visible + xywh {1242 936 100 100} type Double visible } { Fl_Slider progress { private xywh {139 115 1149 23} type Horizontal box FLAT_BOX color 7 selection_color 54 @@ -362,7 +362,9 @@ Fl::visible_focus( 0 ); Fl::add_timeout( TRANSPORT_POLL_INTERVAL, update_transport ); -playlist->signal_new_song.connect( sigc::mem_fun( this, &UI::update_sequence_widgets ) );} {} +playlist->signal_new_song.connect( sigc::mem_fun( this, &UI::update_sequence_widgets ) ); +pattern_canvas_widget->signal_settings_change.connect( sigc::mem_fun( this, &UI::update_pattern_widgets ) ); +phrase_canvas_widget->signal_settings_change.connect( sigc::mem_fun( this, &UI::update_phrase_widgets ) );} {} } Function {~UI()} {open } { @@ -412,7 +414,7 @@ if ( Fl::event() == FL_SHORTCUT && Fl::event_key() == FL_Escape ) if ( maybe_save_song() ) quit();} open - xywh {706 149 865 805} type Double color 47 resizable + xywh {492 227 865 805} type Double color 47 resizable code0 {o->color( FL_BACKGROUND_COLOR );} code1 {o->draw_overlay_callback( &UI::draw_overlay, this );} code2 {o->xclass( APP_NAME );} @@ -422,32 +424,33 @@ if ( maybe_save_song() ) xywh {0 25 865 65} box FLAT_BOX } { Fl_Group {} {open - xywh {665 36 195 52} + xywh {552 26 312 69} + code0 {o->resizable(0);} } { Fl_Value_Input {} { label BPM callback {transport.set_beats_per_minute( o->value() );} - xywh {825 68 35 19} labelsize 9 align 1 when 8 textsize 10 + xywh {825 39 35 19} labelsize 9 align 1 when 8 textsize 10 code1 {transport.signal_tempo_change.connect( sigc::mem_fun( o, static_cast(&Fl_Valuator::value) ) );} code2 {o->value( transport.beats_per_minute );} } Fl_Group {} { label {Time Sig.} open - xywh {756 67 64 21} labelsize 9 + xywh {756 38 64 21} labelsize 9 } { Fl_Value_Input {} { callback {transport.set_beats_per_bar( o->value() );} - xywh {756 68 24 19} textsize 10 + xywh {756 39 24 19} textsize 10 code0 {transport.signal_bpb_change.connect( sigc::mem_fun( o, static_cast(&Fl_Valuator::value) ) );} code1 {o->value( transport.beats_per_bar );} } Fl_Box {} { label {/} - xywh {780 67 14 21} + xywh {780 38 14 21} } Fl_Value_Input {} { callback {transport.set_beat_type( o->value() );} - xywh {795 68 24 19} textsize 10 + xywh {795 39 24 19} textsize 10 code0 {transport.signal_beat_change.connect( sigc::mem_fun( o, static_cast(&Fl_Valuator::value) ) );} code1 {o->value( transport.beat_type );} } @@ -458,7 +461,7 @@ if ( maybe_save_song() ) config.record_mode = (record_mode_e)o->value(); else o->value( config.record_mode );} - xywh {755 36 105 19} box DOWN_BOX down_box BORDER_BOX color 37 labelsize 9 align 1 textsize 9 + xywh {555 39 105 19} box DOWN_BOX down_box BORDER_BOX color 37 labelsize 9 align 1 textsize 9 } { MenuItem {} { label Merge @@ -479,7 +482,7 @@ else } Fl_Choice playback_mode_menu { label {Playback &Mode} - xywh {665 68 85 19} box DOWN_BOX down_box BORDER_BOX color 37 labelsize 9 align 1 + xywh {665 39 85 19} box DOWN_BOX down_box BORDER_BOX color 37 labelsize 9 align 1 } { MenuItem {} { label Pattern @@ -502,46 +505,40 @@ else xywh {0 0 40 24} labelfont 3 labelsize 10 } } - Fl_Choice edit_mode_menu { - label {Edit Mode} - xywh {665 36 85 19} box DOWN_BOX down_box BORDER_BOX color 37 labelsize 9 align 1 + Fl_Pack {} {open + xywh {555 60 305 30} type HORIZONTAL + class Fl_Scalepack } { - MenuItem {} { - label Pattern - callback {tabs->value( pattern_tab ); - - -edit_menu->activate(); -menu_bar->redraw();} - xywh {15 15 40 25} shortcut 0x80031 labelfont 3 labelsize 10 - } - MenuItem {} { - label Phrase - callback {tabs->value( phrase_tab ); - -edit_menu->activate(); -menu_bar->redraw();} - xywh {25 25 40 25} shortcut 0x80032 labelfont 3 labelsize 11 - } - MenuItem {} { + Fl_Button {} { label Sequence callback {tabs->value( sequence_tab ); edit_menu->deactivate(); menu_bar->redraw();} - xywh {25 25 40 25} shortcut 0x80033 labelfont 3 labelsize 10 + xywh {565 70 68 15} type Radio shortcut 0x80031 selection_color 69 } - MenuItem {} { - label Trigger - callback {song.play_mode = TRIGGER;} - xywh {35 35 40 25} labelfont 3 labelsize 10 hide deactivate + Fl_Button {} { + label Phrase + callback {tabs->value( phrase_tab ); + +edit_menu->activate(); +menu_bar->redraw();} + xywh {575 80 68 5} type Radio shortcut 0x80032 selection_color 69 + } + Fl_Button {} { + label Pattern + callback {tabs->value( pattern_tab ); + +edit_menu->activate(); +menu_bar->redraw();} + xywh {585 90 68 0} type Radio shortcut 0x80033 value 1 selection_color 69 } } } Fl_Pack vmetro_widget { label Metronome - xywh {160 27 500 60} type HORIZONTAL box UP_BOX color 40 selection_color 48 labelsize 33 align 0 resizable + xywh {160 27 390 61} type HORIZONTAL box UP_BOX color 40 selection_color 48 labelsize 33 align 0 resizable code0 {o->box( FL_FLAT_BOX );} class Visual_Metronome } {} @@ -591,19 +588,19 @@ else } Fl_Tabs tabs { callback {((Fl_Group*)o->value())->child( 0 )->take_focus();} open - xywh {0 91 865 694} box FLAT_BOX color 47 labeltype SHADOW_LABEL labelsize 19 when 1 resizable + xywh {-1 91 868 694} box FLAT_BOX color 47 labeltype SHADOW_LABEL labelsize 19 when 1 resizable code0 {canvas_background_color = fl_rgb_color( 18, 18, 18 );} } { Fl_Group sequence_tab {open - xywh {0 91 865 678} box FLAT_BOX color 37 labeltype NO_LABEL hide resizable + xywh {0 91 865 692} box FLAT_BOX color 37 labeltype NO_LABEL labelsize 12 hide resizable code0 {update_sequence_widgets();} } { Fl_Group {} {open - xywh {10 118 233 502} labelsize 12 + xywh {5 118 240 502} labelsize 12 } { Fl_Browser playlist_browser { label Playlist - xywh {10 118 233 435} type Hold box EMBOSSED_BOX color 39 selection_color 30 labelcolor 55 align 1 when 4 textsize 18 textcolor 95 resizable + xywh {5 155 240 398} type Hold box EMBOSSED_BOX color 39 selection_color 30 labelsize 12 labelcolor 55 align 1 when 4 textsize 18 textcolor 95 resizable code0 {static int widths[] = { 40, 30, 0 };} code1 {o->column_widths( widths ); o->column_char( '\\t' );} code2 {o->value( 1 );} @@ -623,7 +620,7 @@ if ( val > 1 ) if ( ! playlist_browser->value() ) playlist_browser->value( playlist_browser->size() ); }} - xywh {14 559 73 25} shortcut 0xffff color 88 labelcolor 23 + xywh {6 559 64 25} shortcut 0xffff color 88 labelcolor 23 } Fl_Button sequence_phrase_up_button { label Up @@ -633,7 +630,7 @@ if ( val > 1 ) playlist_browser->value( playlist_browser->value() - 1 ); update_sequence_widgets(); }} - xywh {97 559 65 25} shortcut 0xffbf + xywh {135 559 45 25} shortcut 0xffbf } Fl_Button sequence_phrase_down_button { label Down @@ -643,7 +640,7 @@ if ( val > 1 ) playlist_browser->value( playlist_browser->value() + 1 ); update_sequence_widgets(); }} - xywh {169 559 74 25} shortcut 0xffc0 + xywh {185 559 58 25} shortcut 0xffc0 } Fl_Menu_Button sequence_phrase_choice { label {Insert Phrase} @@ -657,13 +654,13 @@ if ( val ) playlist_browser->value( playlist_browser->value() + 1 ); else playlist_browser->value( playlist_browser->size() );} open - xywh {11 590 232 30} color 63 + xywh {5 590 235 30} color 63 } {} } Fl_Input sequence_name_field { - label {name:} + label Name callback {playlist->name( o->value() );} - xywh {91 733 158 26} color 36 align 20 when 1 textcolor 32 + xywh {10 109 235 27} color 48 labelsize 12 align 1 when 1 } Fl_Light_Button detach_button { label Detach @@ -683,17 +680,17 @@ else sequence_tab->resize( pattern_tab->x(), pattern_tab->y(), pattern_tab->w(), pattern_tab->h() ); tabs->do_callback(); }} - xywh {7 733 78 26} + xywh {7 749 78 26} } Fl_Text_Editor sequence_notes_edit { label {Notes:} callback {playlist->notes( o->buffer()->text() );} - xywh {254 684 606 73} selection_color 48 labelsize 12 align 5 textcolor 94 + xywh {254 732 606 48} selection_color 48 labelsize 12 align 5 textcolor 94 code0 {o->buffer( sequence_notes_buffer = new Fl_Text_Buffer );} } Fl_Box triggers_widget { label Patterns - xywh {253 118 607 549} box FLAT_BOX color 48 align 1 resizable + xywh {253 118 607 598} box FLAT_BOX color 48 labelsize 12 align 1 resizable code0 {o->color( FL_BACKGROUND_COLOR );} code1 {o->rows( 32 );} class Triggers @@ -722,17 +719,17 @@ if ( playlist->length() ) } } } - Fl_Group phrase_tab {open - xywh {0 91 865 678} box FLAT_BOX color 47 labeltype NO_LABEL hide + Fl_Group phrase_tab { + xywh {0 91 865 693} box FLAT_BOX color 47 labeltype NO_LABEL hide code0 {update_phrase_widgets();} } { Fl_Box phrase_canvas_widget { label Phrase - xywh {1 91 863 592} box FLAT_BOX color 37 labelsize 100 align 16 resizable + xywh {0 91 865 637} box FLAT_BOX color 37 labelsize 100 align 16 resizable class Canvas } - Fl_Group {} {open - xywh {5 690 856 77} box FLAT_BOX color 47 + Fl_Group phrase_settings_group {open + xywh {0 728 865 55} box FLAT_BOX color 47 } { Fl_Input phrase_name_field { label {name:} @@ -740,38 +737,38 @@ if ( playlist->length() ) // if the name changed.. update_sequence_widgets();} - xywh {5 697 155 24} box ROUNDED_BOX color 49 labelfont 2 labelcolor 55 align 20 textfont 2 + xywh {5 734 185 21} box ROUNDED_BOX color 49 labelfont 2 labelsize 12 labelcolor 55 align 20 textfont 2 textsize 12 code0 {o->up_box( FL_ROUNDED_BOX );} class Fl_Sometimes_Input } Fl_Light_Button phrase_mute_button { label Mute - xywh {5 733 93 23} color 37 hide + xywh {0 751 93 23} color 37 hide } Fl_Light_Button phrase_solo_button { label Solo - xywh {111 733 87 23} color 37 hide + xywh {106 751 87 23} color 37 hide } Fl_Text_Editor phrase_notes_edit { label {Notes:} callback {phrase_canvas_widget->grid()->notes( o->buffer()->text() );} - xywh {170 702 685 58} selection_color 48 labelsize 12 textcolor 94 resizable + xywh {200 742 660 36} selection_color 48 labelsize 12 textcolor 94 resizable code0 {o->buffer( phrase_notes_buffer = new Fl_Text_Buffer );} } Fl_Value_Slider phrase_number_spinner { - label Phrase + label {Phrase:} callback {phrase *p = ((phrase *)phrase_canvas_widget->grid())->by_number( o->value() ); if ( p ) phrase_canvas_widget->grid( p ); o->maximum( phrase::phrases() );} - xywh {5 737 155 24} type Horizontal labelsize 10 align 1 minimum 1 maximum 128 step 1 value 1 textsize 14 + xywh {45 760 140 18} type Horizontal labelsize 10 align 4 minimum 1 maximum 128 step 1 value 1 textsize 14 } } } Fl_Group pattern_tab {open - xywh {0 91 865 694} box FLAT_BOX color 47 labeltype NO_LABEL + xywh {0 91 867 694} box FLAT_BOX color 47 labeltype NO_LABEL code0 {update_pattern_widgets();} } { Fl_Box pattern_canvas_widget { @@ -779,64 +776,64 @@ o->maximum( phrase::phrases() );} xywh {0 91 865 637} box FLAT_BOX color 37 labelsize 100 align 16 resizable class Canvas } - Fl_Group pattern_settings_group { - xywh {0 731 865 54} box FLAT_BOX color 47 + Fl_Group pattern_settings_group {open + xywh {0 730 867 55} box FLAT_BOX color 47 } { - Fl_Input pattern_name_field { - label {name:} - callback {pattern_canvas_widget->grid()->name( strdup( o->value() ) );} - xywh {5 734 185 21} box ROUNDED_BOX color 49 labelsize 12 align 20 when 8 textfont 2 textsize 12 textcolor 55 - code0 {o->up_box( FL_ROUNDED_BOX );} - class Fl_Sometimes_Input - } - Fl_Light_Button pattern_mute_button { - label Mute - callback {Grid *g = pattern_canvas_widget->grid(); + Fl_Group {} {open + xywh {5 733 300 44} + code0 {o->resizable(0);} + } { + Fl_Input pattern_name_field { + label {name:} + callback {pattern_canvas_widget->grid()->name( strdup( o->value() ) );} + xywh {5 734 185 21} box BORDER_BOX color 49 labelsize 12 align 20 when 8 textsize 12 textcolor 55 + code0 {o->up_box( FL_BORDER_BOX );} + class Fl_Sometimes_Input + } + Fl_Light_Button pattern_mute_button { + label Mute + callback {Grid *g = pattern_canvas_widget->grid(); g->mode( g->mode() == MUTE ? PLAY : MUTE ); o->value( g->mode() == MUTE ); pattern_solo_button->value( 0 );} - xywh {195 734 58 19} type Normal shortcut 0x6d color 37 labelsize 12 - } - Fl_Light_Button pattern_solo_button { - label Solo - callback {Grid *g = pattern_canvas_widget->grid(); + xywh {195 734 58 19} type Normal shortcut 0x6d color 37 labelsize 12 + } + Fl_Light_Button pattern_solo_button { + label Solo + callback {Grid *g = pattern_canvas_widget->grid(); g->mode( g->mode() == SOLO ? PLAY : SOLO ); o->value( g->mode() == SOLO ); pattern_mute_button->value( 0 );} - xywh {195 758 58 19} type Normal shortcut 0x73 color 37 labelsize 12 - } - Fl_Text_Editor pattern_notes_edit { - label {Notes:} - callback {pattern_canvas_widget->grid()->notes( o->buffer()->text() );} - xywh {310 734 240 46} color 40 selection_color 48 labeltype NO_LABEL labelsize 10 textsize 11 textcolor 63 resizable - code0 {o->buffer( pattern_notes_buffer = new Fl_Text_Buffer );} - code1 {o->wrap_mode( Fl_Text_Editor::WRAP_AT_BOUNDS, 0 );} + xywh {195 758 58 19} type Normal shortcut 0x73 color 37 labelsize 12 + } + Fl_Value_Slider pattern_number_spinner { + label Pattern + callback {pattern *p = ((pattern *)pattern_canvas_widget->grid())->by_number( o->value() ); + +if ( p ) + pattern_canvas_widget->grid( p ); + +o->maximum( pattern::patterns() );} + xywh {45 759 140 18} type Horizontal labelsize 10 align 4 minimum 1 maximum 128 step 1 value 1 + } + Fl_Button pattern_selection_mode { + label Select + callback {pattern_canvas_widget->selection_mode( o->value() );} + tooltip {Enable selection mode (you can also just hold down shift and drag the mouse)} xywh {260 733 45 44} type Toggle selection_color 5 labelsize 10 + } } Fl_Group {} {open - xywh {555 731 310 49} + xywh {315 731 549 54} } { - Fl_Spinner pattern_channel_spinner { - label Channel - callback {((pattern *)pattern_canvas_widget->grid())->channel( o->value() - 1 );} - xywh {820 735 40 19} color 36 labelsize 10 when 1 textsize 12 - code0 {\#include "../pattern.H"} - code1 {o->maximum( 16 );} - } - Fl_Spinner pattern_port_spinner { - label Port - callback {((pattern *)pattern_canvas_widget->grid())->port( o->value() - 1 );} - xywh {820 758 40 19} color 36 labelsize 10 when 1 textsize 12 - code0 {o->maximum( 16 );} - } Fl_Output mapping_text { label Mapping - xywh {555 758 105 19} labelsize 10 align 20 textsize 11 + xywh {535 761 105 19} labelsize 10 align 20 textsize 11 } Fl_Menu_Button mapping_menu { label {@>} @@ -863,7 +860,7 @@ if ( 0 == strncmp( picked, "Scale", strlen( "Scale" ) ) ) pattern_key_combo->activate(); }} open - xywh {660 758 30 19} labeltype NO_LABEL labelsize 10 textsize 12 + xywh {640 761 30 19} labeltype NO_LABEL labelsize 10 textsize 12 code0 {update_mapping_menu();} } { Submenu mapping_scale_menu { @@ -880,7 +877,7 @@ if ( 0 == strncmp( picked, "Scale", strlen( "Scale" ) ) ) callback {((pattern*)pattern_canvas_widget->grid())->mapping.key( o->value() ); pattern_canvas_widget->changed_mapping();} open - xywh {720 758 75 19} down_box BORDER_BOX labelsize 10 when 1 textsize 11 + xywh {700 761 75 19} down_box BORDER_BOX labelsize 10 when 1 textsize 11 } { MenuItem {} { label C @@ -934,7 +931,7 @@ pattern_canvas_widget->changed_mapping();} open Fl_Choice pattern_note_combo { label {&Note 1/} callback {((pattern*)pattern_canvas_widget->grid())->note( atoi( o->menu()[ o->value() ].text ));} open - xywh {730 735 45 19} down_box BORDER_BOX labelsize 10 when 1 textsize 12 + xywh {715 736 45 19} down_box BORDER_BOX labelsize 10 when 1 textsize 12 } { MenuItem {} { label 1 @@ -984,7 +981,7 @@ pattern_canvas_widget->changed_mapping();} open Fl_Choice pattern_res_combo { label {&Resolution 1/} callback {pattern_canvas_widget->grid()->resolution( atoi( o->menu()[ o->value() ].text ));} open - xywh {625 735 55 19} down_box BORDER_BOX labelsize 10 when 1 textsize 12 + xywh {615 736 55 19} down_box BORDER_BOX labelsize 10 when 1 textsize 12 } { MenuItem {} { label 1 @@ -1035,24 +1032,28 @@ pattern_canvas_widget->changed_mapping();} open xywh {100 100 40 25} labelsize 11 } } - } - Fl_Value_Slider pattern_number_spinner { - label Pattern - callback {pattern *p = ((pattern *)pattern_canvas_widget->grid())->by_number( o->value() ); - -if ( p ) - pattern_canvas_widget->grid( p ); - -update_pattern_widgets(); - -o->maximum( pattern::patterns() ); - -pattern_settings_group->redraw();} - xywh {45 759 140 18} type Horizontal labelsize 10 align 4 minimum 1 maximum 128 step 1 value 1 - } - Fl_Button {} { - label Select - tooltip {Enable selection mode (you can also just hold down shift and drag the mouse)} xywh {260 735 45 45} type Toggle selection_color 5 labelsize 10 + Fl_Choice pattern_channel_choice { + label {Channel:} + callback {((pattern *)pattern_canvas_widget->grid())->channel( o->value() );} open + xywh {810 735 47 19} down_box BORDER_BOX labelsize 10 textsize 12 + code0 {char pat[3]; for ( int i = 1; i <= 16; i++ ) { snprintf( pat, 3, "%i", i ); o->add( pat ); }} + } {} + Fl_Choice pattern_port_choice { + label {Port:} + callback {((pattern *)pattern_canvas_widget->grid())->port( o->value() );} open + xywh {810 760 47 19} down_box BORDER_BOX labelsize 10 textsize 12 + code0 {char pat[3]; for ( int i = 1; i <= 16; i++ ) { snprintf( pat, 3, "%i", i ); o->add( pat ); }} + } {} + Fl_Input_Choice pattern_bars_choice { + label {Bars:} + callback {((pattern *)pattern_canvas_widget->grid())->bars( atoi( o->value() ) );} open + xywh {486 736 55 19} labelsize 10 textsize 12 + code0 {char pat[4]; for ( int i = 1; i <= 16; i++ ) { snprintf( pat, 3, "%i", i ); o->add( pat ); }} + code1 {for ( int i = 32; i <= 256; i <<= 1 ) { snprintf( pat, sizeof(pat), "%i", i ); o->add( pat ); }} + } {} + Fl_Box {} { + xywh {315 735 135 46} resizable + } } } } @@ -1310,7 +1311,7 @@ ab.run();} } } Submenu edit_menu { - label {&Edit} open + label {&Edit} open selected xywh {0 0 68 18} } { MenuItem {} { @@ -1349,7 +1350,7 @@ else { phrase_number_spinner->value( min( 127, (int)phrase_number_spinner->value() + 1 )); phrase_number_spinner->do_callback(); -}} selected +}} xywh {20 20 34 18} shortcut 0x5d } MenuItem {} { @@ -1362,16 +1363,6 @@ w->grid( w->grid()->clone() ); ui->update_sequence_widgets();} xywh {30 30 34 18} shortcut 0x64 } - MenuItem {} { - label {Duplicate Range} - callback {Canvas *w = current_canvas(); - -w->duplicate_range(); - -// number of phrases may have changed. -ui->update_sequence_widgets();} - xywh {40 40 34 18} shortcut 0x10064 - } MenuItem {} { label {Delete Selected} callback {Canvas *w = current_canvas(); @@ -1395,42 +1386,42 @@ w->grid()->clear();} label {Select All} callback {Canvas *w = current_canvas(); -w->grid()->clear();} +w->grid()->select_all();} xywh {70 70 34 18} shortcut 0x40061 } MenuItem {} { label {Select None} callback {Canvas *w = current_canvas(); -w->grid()->clear();} +w->grid()->select_none();} xywh {80 80 34 18} shortcut 0x50061 } MenuItem {} { label {Invert Selection} callback {Canvas *w = current_canvas(); -w->grid()->clear();} +w->grid()->invert_selection();} xywh {90 90 34 18} shortcut 0x50069 } - MenuItem {} { - label Copy - callback {Canvas *w = current_canvas(); - -w->grid()->clear();} - xywh {100 100 34 18} shortcut 0x40063 - } MenuItem {} { label Cut callback {Canvas *w = current_canvas(); -w->grid()->clear();} +w->cut();} xywh {110 110 34 18} shortcut 0x40078 } + MenuItem {} { + label Copy + callback {Canvas *w = current_canvas(); + +w->copy();} + xywh {100 100 34 18} shortcut 0x40063 + } MenuItem {} { label Paste callback {Canvas *w = current_canvas(); -w->grid()->clear();} +w->paste();} xywh {120 120 34 18} shortcut 0x40076 } } @@ -1507,10 +1498,16 @@ if ( !g ) pattern_number_spinner->value( g->number() ); pattern_name_field->value( g->name() ); -pattern_channel_spinner->value( 1 + g->channel() ); -pattern_port_spinner->value( 1 + g->port() ); +pattern_channel_choice->value( g->channel() ); +pattern_port_choice->value( g->port() ); pattern_solo_button->value( g->mode() == SOLO ); pattern_mute_button->value( g->mode() == MUTE ); +pattern_selection_mode->value( pattern_canvas_widget->selection_mode() ); +{ + char pat[5]; + snprintf( pat, sizeof(pat), "%i", g->bars() ); + pattern_bars_choice->value( pat ); +} if ( g->mapping.key() == -1 ) pattern_key_combo->deactivate(); @@ -1526,11 +1523,13 @@ mapping_text->value( g->mapping.name() ); pattern_note_combo->value( find_numeric_menu_item( menu_pattern_note_combo, g->note() )); pattern_res_combo->value( find_numeric_menu_item( menu_pattern_res_combo, g->resolution() )); - +/* if ( g->notes() ) pattern_notes_buffer->text( g->notes() ); else - pattern_notes_buffer->text( strdup( "" ) );} {} + pattern_notes_buffer->text( strdup( "" ) ); +*/ +pattern_settings_group->redraw();} {} } Function {update_phrase_widgets()} {open } { @@ -1554,7 +1553,9 @@ phrase_mute_button->value( g->mode() == MUTE ); if ( g->notes() ) phrase_notes_buffer->text( g->notes() ); else - phrase_notes_buffer->text( strdup( "" ) );} {} + phrase_notes_buffer->text( strdup( "" ) ); + +phrase_settings_group->redraw();} {} } Function {update_sequence_widgets()} {open } { diff --git a/sequencer/src/transport.C b/sequencer/src/transport.C index 25d9e0b..e00ab67 100644 --- a/sequencer/src/transport.C +++ b/sequencer/src/transport.C @@ -187,7 +187,7 @@ Transport::locate ( tick_t ticks ) { jack_nframes_t frame = trunc( ticks * transport.frames_per_tick ); - MESSAGE( "Relocating transport to %lu, %lu", ticks, frame ); + MESSAGE( "Relocating transport to %f, %lu", ticks, frame ); jack_transport_locate( client, frame ); }