| @@ -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 ); | |||
| } | |||
| } | |||
| @@ -36,6 +36,7 @@ namespace MIDI | |||
| tick_t duration; | |||
| int note; | |||
| int velocity; | |||
| bool selected; | |||
| }; | |||
| class event : public midievent | |||
| @@ -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 ) | |||
| { | |||
| @@ -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 <midievent> &rhs ); | |||
| event *operator[] ( unsigned int index ); | |||
| @@ -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 ); */ | |||
| /* 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 ( 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 ); | |||
| } | |||
| 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; | |||
| if ( drag_note ) | |||
| delete drag_note; | |||
| drag_note = 0; | |||
| break; | |||
| } | |||
| default: | |||
| processed = 0; | |||
| break; | |||
| } | |||
| break; | |||
| } | |||
| case FL_DRAG: | |||
| if ( Fl::event_button1() ) | |||
| 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 ); | |||
| } | |||
| damage(FL_DAMAGE_OVERLAY); | |||
| return 1; | |||
| } | |||
| 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; | |||
| @@ -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 <void> 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 ); | |||
| @@ -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<event *>(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 | |||
| @@ -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); | |||
| } | |||
| @@ -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<int (Fl_Valuator::*)(double)>(&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<int (Fl_Valuator::*)(double)>(&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<int (Fl_Valuator::*)(double)>(&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 ); | |||
| Fl_Button {} { | |||
| label Sequence | |||
| callback {tabs->value( sequence_tab ); | |||
| edit_menu->activate(); | |||
| edit_menu->deactivate(); | |||
| menu_bar->redraw();} | |||
| xywh {15 15 40 25} shortcut 0x80031 labelfont 3 labelsize 10 | |||
| xywh {565 70 68 15} type Radio shortcut 0x80031 selection_color 69 | |||
| } | |||
| MenuItem {} { | |||
| Fl_Button {} { | |||
| label Phrase | |||
| callback {tabs->value( phrase_tab ); | |||
| edit_menu->activate(); | |||
| menu_bar->redraw();} | |||
| xywh {25 25 40 25} shortcut 0x80032 labelfont 3 labelsize 11 | |||
| xywh {575 80 68 5} type Radio shortcut 0x80032 selection_color 69 | |||
| } | |||
| MenuItem {} { | |||
| label Sequence | |||
| callback {tabs->value( sequence_tab ); | |||
| Fl_Button {} { | |||
| label Pattern | |||
| callback {tabs->value( pattern_tab ); | |||
| edit_menu->deactivate(); | |||
| edit_menu->activate(); | |||
| menu_bar->redraw();} | |||
| xywh {25 25 40 25} shortcut 0x80033 labelfont 3 labelsize 10 | |||
| } | |||
| MenuItem {} { | |||
| label Trigger | |||
| callback {song.play_mode = TRIGGER;} | |||
| xywh {35 35 40 25} labelfont 3 labelsize 10 hide deactivate | |||
| 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 | |||
| label Cut | |||
| callback {Canvas *w = current_canvas(); | |||
| w->grid()->clear();} | |||
| xywh {100 100 34 18} shortcut 0x40063 | |||
| w->cut();} | |||
| xywh {110 110 34 18} shortcut 0x40078 | |||
| } | |||
| MenuItem {} { | |||
| label Cut | |||
| label Copy | |||
| callback {Canvas *w = current_canvas(); | |||
| w->grid()->clear();} | |||
| xywh {110 110 34 18} shortcut 0x40078 | |||
| 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 | |||
| } { | |||
| @@ -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 ); | |||
| } | |||