Add commands to invert selection. Make middle click toggle note selection instead of set it.tags/non-sequencer-v1.9.4
| @@ -5,10 +5,6 @@ | |||||
| ; General | ; General | ||||
| * allow deselection of notes in pattern editor. | |||||
| * some way to select by row as well as column. preferably better than | |||||
| standard rubberband techniques. What I'd really like is a cross | |||||
| hair to select x1,y1 and x2,y2 coords of a bounding box. | |||||
| * add option to create new instrument defintion. | * add option to create new instrument defintion. | ||||
| * per phrase tempo setting? Perhaps a percentage of global tempo? | * per phrase tempo setting? Perhaps a percentage of global tempo? | ||||
| * add channel field to event list widget (but channel bits in pattern | * add channel field to event list widget (but channel bits in pattern | ||||
| @@ -63,7 +63,7 @@ Canvas::_alloc_array ( void ) | |||||
| Canvas::Canvas ( ) | Canvas::Canvas ( ) | ||||
| { | { | ||||
| m.origin_x = m.origin_y = m.height = m.width = m.div_w = m.div_h = m.playhead = m.margin_top = m.margin_left = m.playhead = m.w = m.h = m.p1 = m.p2 = 0; | |||||
| m.origin_x = m.origin_y = m.height = m.width = m.div_w = m.div_h = m.playhead = m.margin_top = m.margin_left = m.playhead = m.w = m.h = m.p1 = m.p2 = m.p3 = m.p4 = 0; | |||||
| m.margin_top = ruler_height; | m.margin_top = ruler_height; | ||||
| @@ -335,6 +335,12 @@ Canvas::flip ( void ) | |||||
| cell_t *c = &m.current[ x ][ y ]; | cell_t *c = &m.current[ x ][ y ]; | ||||
| cell_t *p = &m.previous[ x ][ y ]; | cell_t *p = &m.previous[ x ][ y ]; | ||||
| /* draw selection rect */ | |||||
| if ( m.p3 != m.p4 ) | |||||
| if ( y + m.vp->y >= m.p3 && x + m.vp->x >= m.p1 && | |||||
| y + m.vp->y < m.p4 && x + m.vp->x < m.p2 ) | |||||
| c->flags |= F_SELECTION; | |||||
| if ( *c != *p ) | if ( *c != *p ) | ||||
| gui_draw_shape( m.origin_x + m.margin_left + x * m.div_w, m.origin_y + m.margin_top + y * m.div_h, m.div_w, m.div_h, m.border_w, | gui_draw_shape( m.origin_x + m.margin_left + x * m.div_w, m.origin_y + m.margin_top + y * m.div_h, m.div_w, m.div_h, m.border_w, | ||||
| c->shape, c->state, c->flags, c->color ); | c->shape, c->state, c->flags, c->color ); | ||||
| @@ -438,7 +444,9 @@ Canvas::draw_shape ( int x, int y, int shape, int state, int color, bool selecte | |||||
| m.current[ x ][ y ].shape = shape; | m.current[ x ][ y ].shape = shape; | ||||
| m.current[ x ][ y ].color = color; | m.current[ x ][ y ].color = color; | ||||
| m.current[ x ][ y ].state = (uint)m.vp->x + x > m.grid->ts_to_x( m.grid->length() ) ? PARTIAL : state; | m.current[ x ][ y ].state = (uint)m.vp->x + x > m.grid->ts_to_x( m.grid->length() ) ? PARTIAL : state; | ||||
| m.current[ x ][ y ].flags = selected ? F_SELECTED : 0; | |||||
| if ( selected ) | |||||
| m.current[ x ][ y ].state = SELECTED; | |||||
| m.current[ x ][ y ].flags = 0; | |||||
| } | } | ||||
| /** callback used by Grid::draw() */ | /** callback used by Grid::draw() */ | ||||
| @@ -585,6 +593,38 @@ Canvas::is_row_name ( int x, int y ) | |||||
| return m.grid->y_to_note( y ); | return m.grid->y_to_note( y ); | ||||
| } | } | ||||
| void | |||||
| Canvas::start_cursor ( int x, int y ) | |||||
| { | |||||
| if ( ! grid_pos( &x, &y ) ) | |||||
| return; | |||||
| m.ruler_drawn = false; | |||||
| m.p1 = x; | |||||
| m.p3 = ntr( y ); | |||||
| _lr(); | |||||
| signal_draw(); | |||||
| } | |||||
| void | |||||
| Canvas::end_cursor ( int x, int y ) | |||||
| { | |||||
| if ( ! grid_pos( &x, &y ) ) | |||||
| return; | |||||
| m.ruler_drawn = false; | |||||
| m.p2 = x; | |||||
| m.p4 = ntr( y ); | |||||
| _lr(); | |||||
| signal_draw(); | |||||
| } | |||||
| void | void | ||||
| Canvas::set ( int x, int y ) | Canvas::set ( int x, int y ) | ||||
| { | { | ||||
| @@ -595,6 +635,8 @@ Canvas::set ( int x, int y ) | |||||
| { | { | ||||
| m.p1 = m.vp->x + ((x - m.margin_left - m.origin_x) / m.div_w); | m.p1 = m.vp->x + ((x - m.margin_left - m.origin_x) / m.div_w); | ||||
| m.ruler_drawn = false; | m.ruler_drawn = false; | ||||
| m.p3 = m.p4 = 0; | |||||
| } | } | ||||
| _lr(); | _lr(); | ||||
| @@ -620,6 +662,8 @@ Canvas::unset ( int x, int y ) | |||||
| { | { | ||||
| m.p2 = m.vp->x + ((x - m.margin_left - m.origin_x) / m.div_w); | m.p2 = m.vp->x + ((x - m.margin_left - m.origin_x) / m.div_w); | ||||
| m.ruler_drawn = false; | m.ruler_drawn = false; | ||||
| m.p3 = m.p4 = 0; | |||||
| } | } | ||||
| _lr(); | _lr(); | ||||
| @@ -659,7 +703,7 @@ Canvas::select ( int x, int y ) | |||||
| if ( ! grid_pos( &x, &y ) ) | if ( ! grid_pos( &x, &y ) ) | ||||
| return; | return; | ||||
| m.grid->select( x, y, true ); | |||||
| m.grid->toggle_select( x, y ); | |||||
| } | } | ||||
| void | void | ||||
| @@ -739,7 +783,16 @@ Canvas::_lr ( void ) | |||||
| void | void | ||||
| Canvas::select_range ( void ) | Canvas::select_range ( void ) | ||||
| { | { | ||||
| m.grid->select( m.p1, m.p2 ); | |||||
| if ( m.p3 == m.p4 ) | |||||
| m.grid->select( m.p1, m.p2 ); | |||||
| else | |||||
| m.grid->select( m.p1, m.p2, rtn( m.p3 ), rtn( m.p4 ) ); | |||||
| } | |||||
| void | |||||
| Canvas::invert_selection ( void ) | |||||
| { | |||||
| m.grid->invert_selection(); | |||||
| } | } | ||||
| void | void | ||||
| @@ -66,10 +66,6 @@ class Canvas : public trackable | |||||
| int playhead; /* where the playhead is for this canvas. only used for display. */ | int playhead; /* where the playhead is for this canvas. only used for display. */ | ||||
| /* /\* these are in logical units, not pixels *\/ */ | |||||
| /* int w, h; /\* viewport *\/ */ | |||||
| /* int x, y; /\* pan position *\/ */ | |||||
| enum { PATTERN, SEQUENCE } mode; | enum { PATTERN, SEQUENCE } mode; | ||||
| Grid *grid; /* grid currently connected to this canvas */ | Grid *grid; /* grid currently connected to this canvas */ | ||||
| @@ -81,7 +77,7 @@ class Canvas : public trackable | |||||
| int rule; | int rule; | ||||
| bool row_compact; /* use row-compaction? */ | |||||
| bool row_compact; /* use row-compaction? */ | |||||
| /* tables used for row-compaction */ | /* tables used for row-compaction */ | ||||
| int rtn[128]; /* row-to-note */ | int rtn[128]; /* row-to-note */ | ||||
| @@ -92,7 +88,8 @@ class Canvas : public trackable | |||||
| Viewport *vp; | Viewport *vp; | ||||
| int w, h; | int w, h; | ||||
| uint p1, p2; /* cursors */ | |||||
| uint p1, p2; /* range cursors */ | |||||
| uint p3, p4; /* row cursors */ | |||||
| } m; | } m; | ||||
| int rtn ( int r ) const; | int rtn ( int r ) const; | ||||
| @@ -146,6 +143,7 @@ public: | |||||
| void adj_length ( int x, int y, int n ); | void adj_length ( int x, int y, int n ); | ||||
| void select ( int x, int y ); | void select ( int x, int y ); | ||||
| void select_range ( void ); | void select_range ( void ); | ||||
| void invert_selection ( void ); | |||||
| void duplicate_range ( void ); | void duplicate_range ( void ); | ||||
| void crop ( void ); | void crop ( void ); | ||||
| void row_compact ( int n ); | void row_compact ( int n ); | ||||
| @@ -157,6 +155,10 @@ public: | |||||
| char * notes ( void ); | char * notes ( void ); | ||||
| void randomize_row ( int y ); | void randomize_row ( int y ); | ||||
| void start_cursor ( int x, int y ); | |||||
| void end_cursor ( int x, int y ); | |||||
| void delete_time ( void ); | void delete_time ( void ); | ||||
| void insert_time ( void ); | void insert_time ( void ); | ||||
| @@ -291,6 +291,24 @@ event_list::select ( tick_t start, tick_t end ) | |||||
| } | } | ||||
| } | } | ||||
| /** select note evenets from /start/ to /end/ within range /hi/ through /lo/ */ | |||||
| void | |||||
| event_list::select ( tick_t start, tick_t end, int hi, int lo ) | |||||
| { | |||||
| FOR_ALL( e ) | |||||
| { | |||||
| tick_t ts = e->timestamp(); | |||||
| /* don't count note offs exactly on start */ | |||||
| if ( ! e->is_note_on() ) | |||||
| continue; | |||||
| if ( ts >= start && ts < end && | |||||
| e->note() <= hi && e->note() >= lo ) | |||||
| e->select(); | |||||
| } | |||||
| } | |||||
| /** select ALL events */ | /** select ALL events */ | ||||
| void | void | ||||
| event_list::select_all ( void ) | event_list::select_all ( void ) | ||||
| @@ -306,6 +324,19 @@ event_list::select_none ( void ) | |||||
| e->deselect(); | e->deselect(); | ||||
| } | } | ||||
| void | |||||
| event_list::invert_selection ( void ) | |||||
| { | |||||
| FOR_ALL( e ) | |||||
| if ( ! e->is_note_off() ) | |||||
| { | |||||
| if ( e->selected() ) | |||||
| e->deselect(); | |||||
| else | |||||
| e->select(); | |||||
| } | |||||
| } | |||||
| /** remove all selected events */ | /** remove all selected events */ | ||||
| void | void | ||||
| event_list::remove_selected ( void ) | event_list::remove_selected ( void ) | ||||
| @@ -51,8 +51,11 @@ public: | |||||
| event * first ( void ) const; | event * first ( void ) const; | ||||
| event * last ( void ) const; | event * last ( void ) const; | ||||
| void select ( tick_t start, tick_t end ); | void select ( tick_t start, tick_t end ); | ||||
| void select ( tick_t start, tick_t end, int hi, int lo ); | |||||
| void select_all ( void ); | void select_all ( void ); | ||||
| void select_none ( void ); | void select_none ( void ); | ||||
| void invert_selection ( void ); | |||||
| void remove_selected ( void ); | void remove_selected ( void ); | ||||
| void transpose_selected ( int n ); | void transpose_selected ( int n ); | ||||
| @@ -457,17 +457,17 @@ Grid::adj_duration ( int x, int y, int l ) | |||||
| } | } | ||||
| void | void | ||||
| Grid::select ( int x, int y, bool b ) | |||||
| Grid::toggle_select ( int x, int y ) | |||||
| { | { | ||||
| lock(); | lock(); | ||||
| event *e = _event( x, y, true ); | event *e = _event( x, y, true ); | ||||
| if ( e ) | if ( e ) | ||||
| if ( b ) | |||||
| e->select(); | |||||
| else | |||||
| if ( e->selected() ) | |||||
| e->deselect(); | e->deselect(); | ||||
| else | |||||
| e->select(); | |||||
| unlock(); | unlock(); | ||||
| } | } | ||||
| @@ -503,6 +503,20 @@ Grid::select ( int l, int r ) | |||||
| unlock(); | unlock(); | ||||
| } | } | ||||
| /** select all (note) events in rectangle */ | |||||
| void | |||||
| Grid::select ( int l, int r, int t, int b ) | |||||
| { | |||||
| tick_t start = x_to_ts( l ); | |||||
| tick_t end = x_to_ts( r ); | |||||
| lock(); | |||||
| _rw->events.select( start, end, y_to_note( t) , y_to_note( b ) ); | |||||
| unlock(); | |||||
| } | |||||
| /** delete events from /x/ to /l/, compressing time. */ | /** delete events from /x/ to /l/, compressing time. */ | ||||
| void | void | ||||
| Grid::delete_time ( int l, int r ) | Grid::delete_time ( int l, int r ) | ||||
| @@ -527,6 +541,16 @@ Grid::select_none ( void ) | |||||
| unlock(); | unlock(); | ||||
| } | } | ||||
| void | |||||
| Grid::invert_selection ( void ) | |||||
| { | |||||
| lock(); | |||||
| _rw->events.invert_selection(); | |||||
| unlock(); | |||||
| } | |||||
| void | void | ||||
| Grid::delete_selected ( void ) | Grid::delete_selected ( void ) | ||||
| { | { | ||||
| @@ -214,11 +214,13 @@ public: | |||||
| void crop ( int l, int r ); | void crop ( int l, int r ); | ||||
| void select ( int x, int y, bool b ); | |||||
| void toggle_select ( int x, int y ); | |||||
| void insert_time ( int x, int r ); | void insert_time ( int x, int r ); | ||||
| void select ( int start, int end ); | void select ( int start, int end ); | ||||
| void select ( int start, int end, int t, int b ); | |||||
| void delete_time ( int start, int end ); | void delete_time ( int start, int end ); | ||||
| void select_none ( void ); | void select_none ( void ); | ||||
| void invert_selection ( void ); | |||||
| void resolution ( unsigned int n ); | void resolution ( unsigned int n ); | ||||
| int resolution ( void ) const; | int resolution ( void ) const; | ||||
| @@ -174,15 +174,15 @@ gui_draw_shape ( int x, int y, int w, int h, int bw, int shape, int state, int f | |||||
| if ( flags & F_PLAYHEAD ) | if ( flags & F_PLAYHEAD ) | ||||
| state = state == FULL ? HIT : PLAYHEAD; | state = state == FULL ? HIT : PLAYHEAD; | ||||
| else | |||||
| if ( flags & F_SELECTED ) | |||||
| state = SELECTED; | |||||
| if ( state == FULL && color ) | if ( state == FULL && color ) | ||||
| fl_color( velocity_colors[ color ] ); | fl_color( velocity_colors[ color ] ); | ||||
| else | else | ||||
| fl_color( state_colors[ state ] ); | fl_color( state_colors[ state ] ); | ||||
| if ( flags & F_SELECTION ) | |||||
| fl_color( fl_darker( fl_color() ) ); | |||||
| switch ( shape ) | switch ( shape ) | ||||
| { | { | ||||
| case CIRCLE: | case CIRCLE: | ||||
| @@ -20,11 +20,11 @@ enum { | |||||
| FULL, /* dot or dash head */ | FULL, /* dot or dash head */ | ||||
| PARTIAL, | PARTIAL, | ||||
| CONTINUED, /* dash tail */ | CONTINUED, /* dash tail */ | ||||
| SELECTED, | |||||
| /* virtual */ | /* virtual */ | ||||
| HIT, /* playhead hit */ | HIT, /* playhead hit */ | ||||
| LINE, /* beat line */ | LINE, /* beat line */ | ||||
| PLAYHEAD, | PLAYHEAD, | ||||
| SELECTED, | |||||
| MAX_STATE, | MAX_STATE, | ||||
| }; | }; | ||||
| @@ -35,10 +35,10 @@ enum { | |||||
| /* flags */ | /* flags */ | ||||
| enum { | enum { | ||||
| F_PLAYHEAD = 1 << 0, /* playhead is on item */ | |||||
| F_P1 = 1 << 1, | |||||
| F_P2 = 1 << 2, | |||||
| F_SELECTED = 1 << 3 /* item is selected */ | |||||
| F_PLAYHEAD = 1 << 0, /* playhead is on item */ | |||||
| F_P1 = 1 << 1, | |||||
| F_P2 = 1 << 2, | |||||
| F_SELECTION = 1 << 3 /* item is part of the selection box */ | |||||
| }; | }; | ||||
| @@ -128,6 +128,9 @@ canvas_input_callback ( O_Canvas *widget, Canvas *c, int m ) | |||||
| case 'q': | case 'q': | ||||
| c->grid()->select_none(); | c->grid()->select_none(); | ||||
| break; | break; | ||||
| case 'i': | |||||
| c->invert_selection(); | |||||
| break; | |||||
| case '1': | case '1': | ||||
| c->h_zoom( 2.0f ); | c->h_zoom( 2.0f ); | ||||
| break; | break; | ||||
| @@ -250,6 +253,11 @@ canvas_input_callback ( O_Canvas *widget, Canvas *c, int m ) | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| if ( Fl::event_state() & FL_SHIFT ) | |||||
| { | |||||
| c->start_cursor( x, y ); | |||||
| break; | |||||
| } | |||||
| if ( IS_PATTERN && Fl::event_state() & FL_CTRL ) | if ( IS_PATTERN && Fl::event_state() & FL_CTRL ) | ||||
| c->randomize_row( y ); | c->randomize_row( y ); | ||||
| @@ -258,6 +266,12 @@ canvas_input_callback ( O_Canvas *widget, Canvas *c, int m ) | |||||
| } | } | ||||
| break; | break; | ||||
| case 3: | case 3: | ||||
| if ( Fl::event_state() & FL_SHIFT ) | |||||
| { | |||||
| c->end_cursor( x, y ); | |||||
| break; | |||||
| } | |||||
| c->unset( x, y ); | c->unset( x, y ); | ||||
| break; | break; | ||||
| case 2: | case 2: | ||||