Add new rectangular selection to canvas.
Add commands to invert selection. Make middle click toggle note selection instead of set it.
This commit is contained in:
parent
5f8d98cb92
commit
d8fe1ad003
4
TODO
4
TODO
|
@ -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
|
||||||
|
|
61
canvas.C
61
canvas.C
|
@ -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
|
||||||
|
|
14
canvas.H
14
canvas.H
|
@ -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 );
|
||||||
|
|
||||||
|
|
31
event_list.C
31
event_list.C
|
@ -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 );
|
||||||
|
|
32
grid.C
32
grid.C
|
@ -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 )
|
if ( e->selected() )
|
||||||
e->select();
|
|
||||||
else
|
|
||||||
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 )
|
||||||
{
|
{
|
||||||
|
|
4
grid.H
4
grid.H
|
@ -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:
|
||||||
|
|
10
gui/draw.H
10
gui/draw.H
|
@ -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_PLAYHEAD = 1 << 0, /* playhead is on item */
|
||||||
F_P1 = 1 << 1,
|
F_P1 = 1 << 1,
|
||||||
F_P2 = 1 << 2,
|
F_P2 = 1 << 2,
|
||||||
F_SELECTED = 1 << 3 /* item is selected */
|
F_SELECTION = 1 << 3 /* item is part of the selection box */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
14
gui/input.C
14
gui/input.C
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue