/*******************************************************************************/ /* Copyright (C) 2008 Jonathan Moore Liles */ /* */ /* This program is free software; you can redistribute it and/or modify it */ /* under the terms of the GNU General Public License as published by the */ /* Free Software Foundation; either version 2 of the License, or (at your */ /* option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, but WITHOUT */ /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */ /* more details. */ /* */ /* You should have received a copy of the GNU General Public License along */ /* with This program; see the file COPYING. If not,write to the Free Software */ /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*******************************************************************************/ #include "Track.H" #include "Region.H" #include "Timeline.H" #include "Waveform.H" #include #include #include #include #include #include #include //using std::algorithm; using namespace std; extern Timeline timeline; Fl_Boxtype Region::_box = FL_PLASTIC_UP_BOX; void Region::init ( void ) { /* align( FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_BOTTOM | FL_ALIGN_CLIP ); */ /* labeltype( FL_SHADOW_LABEL ); */ /* labelcolor( FL_WHITE ); */ /* box( FL_PLASTIC_UP_BOX ); */ _track = NULL; _offset = 0; _start = 0; _end = 0; _scale = 1.0f; _clip = NULL; _box_color = FL_CYAN; _color = FL_BLUE; } Region::Region ( const Region & rhs ) { _offset = rhs._offset; _track = rhs._track; _clip = rhs._clip; _start = rhs._start; _end = rhs._end; _scale = rhs._scale; } Region::Region ( Clip *c ) { init(); _clip = c; _end = _clip->length(); } void Region::trim ( enum trim_e t, int X ) { switch ( t ) { case LEFT: { int d = X - x(); long td = timeline.x_to_ts( d ); if ( td < 0 && _start < 0 - td ) td = 0 - _start; _start += td; _offset += td; break; } case RIGHT: { int d = (x() + w()) - X; long td = timeline.x_to_ts( d ); _end -= td; break; } default: return; } _track->redraw(); } int Region::handle ( int m ) { static int ox, oy; static enum trim_e trimming; static bool copied = false; static nframes_t os; int X = Fl::event_x(); int Y = Fl::event_y(); int ret; switch ( m ) { case FL_PUSH: { if ( Fl::event_state() & FL_SHIFT && ! ( Fl::event_state() & FL_CTRL )) { switch ( Fl::event_button() ) { case 1: trim( trimming = LEFT, X ); break; case 3: trim( trimming = RIGHT, X ); break; default: return 0; } fl_cursor( FL_CURSOR_WE ); return 1; } else { ox = x() - X; oy = y() - Y; if ( Fl::event_state() && FL_CTRL ) { os = _start; // Fl::local_grab( this ); } if ( Fl::event_button() == 2 ) { normalize(); _track->redraw(); } ret = Track_Widget::handle( m ); return ret | 1; } break; } case FL_RELEASE: fl_cursor( FL_CURSOR_DEFAULT ); copied = false; trimming = NO; // Fl::release(); return 1; case FL_DRAG: if ( Fl::event_state() & FL_SHIFT && Fl::event_state() & FL_CTRL ) { int d = (ox + X) - x(); long td = timeline.x_to_ts( d ); nframes_t W = _end - _start; if ( td > 0 && os < td ) _start = 0; else _start = os - td; _end = _start + W; _track->redraw(); return 1; } if ( Fl::event_state() & FL_SHIFT ) if ( trimming ) { trim( trimming, X ); return 1; } else return 0; if ( Fl::event_state() & FL_CTRL ) { if ( ! copied ) { _track->add( new Region( *this ) ); copied = true; return 1; } } if ( Y > y() + h() ) { if ( _track->next() ) _track->next()->add( this ); } else if ( Y < y() ) { if ( _track->prev() ) _track->prev()->add( this ); } _track->redraw(); ret = Track_Widget::handle( m ); return ret | 1; /* if ( X >= timeline.scroll->x() + timeline.scroll->w() || */ /* X <= timeline.scroll->x() ) */ /* { */ /* /\* this drag needs to scroll *\/ */ /* long pos = timeline.scroll->xposition(); */ /* if ( X <= timeline.scroll->x() ) */ /* pos -= 100; */ /* else */ /* pos += 100; */ /* if ( pos < 0 ) */ /* pos = 0; */ /* timeline.scroll->position( pos, timeline.scroll->yposition() ); */ /* } */ // _offset = timeline.x_to_ts( x() ); default: return Track_Widget::handle( m ); break; } } void Region::draw_box( int X, int Y, int W, int H ) { /* dirty hack to keep the box from flipping to vertical at small sizes */ fl_push_clip( x(), Y, w(), H ); fl_draw_box( box(), x() - 10, Y, w() + 50, H, _box_color ); fl_pop_clip(); } /* Draw (part of) region. OX is pixel offset from start of timeline, X Y W and H are the portion of the widget to draw (arrived at by intersection of the clip and relative to OX) */ void Region::draw ( int X, int Y, int W, int H ) { if ( ! ( W > 0 && H > 0 ) ) return; int OX = scroll_x(); int ox = timeline.ts_to_x( _offset ); if ( ox > OX + _track->w() || ox < OX && ox + abs_w() < OX ) return; int rw = timeline.ts_to_x( _end - _start ); nframes_t end = _offset + ( _end - _start ); /* calculate waveform offset due to scrolling */ nframes_t offset = 0; if ( ox < OX ) { offset = timeline.x_to_ts( OX - ox ); rw = timeline.ts_to_x( (_end - _start) - offset ); } rw = min( rw, _track->w() ); int rx = x(); // printf( "rx %d, rw %d\n", rx, rw ); fl_push_clip( rx, Y, rw, H ); /* dirty hack to keep the box from flipping to vertical at small sizes */ // fl_draw_box( box(), rx - 10, Y, rw + 50, H, _box_color ); // fl_push_clip( x() + Fl::box_dx( box() ), y(), w() - Fl::box_dw( box() ), h() ); draw_waveform( rx, Y, rw, H, _clip, _start + offset, min( (_end - _start) - offset, _end), _scale, _color ); timeline.draw_measure_lines( rx, Y, rw, H, _box_color ); fl_color( FL_BLACK ); fl_line( rx, Y, rx, Y + H ); fl_line( rx + rw - 1, Y, rx + rw - 1, Y + H ); fl_pop_clip(); fl_font( FL_HELVETICA, 14 ); fl_color( FL_BLACK ); draw_label( _clip->name(), (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_BOTTOM | FL_ALIGN_CLIP | FL_ALIGN_INSIDE) ); /* fl_color( FL_RED ); */ /* fl_line( x(), y(), x(), y() + h() ); */ } void Region::normalize ( void ) { printf( "normalize: start=%lu end=%lu\n", _start, _end ); _scale = _clip->peaks()->normalization_factor( _start, _end ); }