Changeset 890
- Timestamp:
- 07/11/07 11:16:47 (1 year ago)
- Location:
- trunk
- Files:
-
- 1 added
- 7 modified
-
jahplayer/control.py (modified) (1 diff)
-
jahwidgets/src/qt3/python/py.cpp (modified) (2 diffs)
-
jahwidgets/src/qt3/python/python.pro (modified) (1 diff)
-
jahwidgets/src/qt3/python/python_vc80.vcproj (modified) (1 diff)
-
jahwidgets/src/qt3/python/timeline.cpp (added)
-
jahwidgets/src/qt3/widgets/timelineSlider.cpp (modified) (34 diffs)
-
jahwidgets/src/qt3/widgets/timelineSlider.h (modified) (10 diffs)
-
jahwidgets/test/timelineSlider-test.ui (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/jahplayer/control.py
r511 r890 139 139 # In/out point handling 140 140 self.ignore_points = False 141 self.in_point = utilities.create_property_and_attach( self.handle, "timeline: inValue", utilities.call_method_observer( self.in_changed ) )142 self.out_point = utilities.create_property_and_attach( self.handle, "timeline: outValue", utilities.call_method_observer( self.out_changed ) )141 self.in_point = utilities.create_property_and_attach( self.handle, "timeline:activeInValue", utilities.call_method_observer( self.in_changed ) ) 142 self.out_point = utilities.create_property_and_attach( self.handle, "timeline:activeOutValue", utilities.call_method_observer( self.out_changed ) ) 143 143 self.in_prop = utilities.create_property_and_attach( self.handle, "pb_in:clicked", utilities.call_method_observer( self.set_in ) ) 144 144 self.out_prop = utilities.create_property_and_attach( self.handle, "pb_out:clicked", utilities.call_method_observer( self.set_out ) ) -
trunk/jahwidgets/src/qt3/python/py.cpp
r833 r890 40 40 extern void register_scrollview(); 41 41 extern void register_settings(); 42 extern void register_timeline(); 42 43 43 44 #ifdef MAC_OSX … … 79 80 register_scrollview(); 80 81 register_settings(); 82 register_timeline(); 81 83 82 84 #ifdef MAC_OSX -
trunk/jahwidgets/src/qt3/python/python.pro
r833 r890 65 65 messagebox.cpp \ 66 66 scrollview.cpp \ 67 settings.cpp 67 settings.cpp \ 68 timeline.cpp 68 69 69 70 mac: SOURCES += macutils.cpp -
trunk/jahwidgets/src/qt3/python/python_vc80.vcproj
r865 r890 287 287 </File> 288 288 <File 289 RelativePath=".\timeline.cpp" 290 > 291 </File> 292 <File 289 293 RelativePath=".\splitter.cpp" 290 294 > -
trunk/jahwidgets/src/qt3/widgets/timelineSlider.cpp
r849 r890 5 5 // Released under the GPL. 6 6 // For more information, see http://www.jahshaka.org. 7 8 // Custom geometry classes, with minimal interfaces.9 7 10 8 #include "timelineSlider.h" … … 26 24 // std 27 25 #include <algorithm> 26 #include <set> 27 #include <memory> 28 29 // boost 30 #include <boost/shared_ptr.hpp> 28 31 29 32 namespace jahwidgets { namespace qt3 { … … 33 36 public: 34 37 IconSet() : 35 _isActive(false) 38 _isActive(false), 39 _isSelected(false) 36 40 {} 37 41 38 42 QPixmap pixmap() const { 39 return (_isActive && !active.isNull()) ? active : normal; 43 if ( _isActive && !active.isNull() ) { 44 return active; 45 } 46 else if ( _isSelected && !selected.isNull() ) { 47 return selected; 48 } 49 else { 50 return normal; 51 } 40 52 } 41 53 … … 55 67 } 56 68 69 void setSelected( bool s ) { 70 _isSelected = s; 71 } 72 73 bool isSelected() const { 74 return _isSelected; 75 } 76 57 77 QPixmap normal; 58 78 QPixmap active; 79 QPixmap selected; 59 80 60 81 private: 61 82 bool _isActive; 83 bool _isSelected; 62 84 }; 63 85 64 struct TimelineSlider::PrivateTimelineSlider 86 int TimelineSlider::Range::id_count = 0; 87 88 typedef boost::shared_ptr<TimelineSlider::Range> RangePtr; 89 90 struct RangeCompare 91 { 92 bool operator()( RangePtr lhs, RangePtr rhs ) const 93 { 94 // Ordered by in-point - or out point if in points are equal 95 return lhs->in < rhs->in || (lhs->in == rhs->in && lhs->out < rhs->out); 96 } 97 }; 98 99 // We use a multiset because it is legal to contain sets with duplicate in points 100 typedef std::multiset<RangePtr, RangeCompare> RangeSet; 101 102 struct RangeIdentity 103 { 104 public: 105 RangeIdentity( int an_id ) : id(an_id) {} 106 107 bool operator()( RangePtr range ) const { 108 return range->id() == id; 109 } 110 111 int id; 112 }; 113 114 struct RangeContains 115 { 116 public: 117 RangeContains( int an_pt ) : pt(an_pt) {} 118 119 bool operator()( RangePtr range ) const { 120 return range->contains( pt ); 121 } 122 123 int pt; 124 }; 125 126 struct TimelineSlider::PrivateTimeline 65 127 { 66 128 enum Tracking { NONE, VALUE, IN, OUT }; 67 129 68 PrivateTimeline Slider( TimelineSlider* p )130 PrivateTimeline( TimelineSlider* p ) 69 131 : parent( p ), 70 132 min( 0 ), 71 133 max( 1000 ), 72 134 v( 0 ), 73 inValue( min ), 74 outValue( max ), 135 thumbnailFrame( -1 ), 75 136 showInOut( true ), 76 137 fps( 30 ), … … 81 142 showTimecodes( false ), 82 143 showTicks( false ) 83 {} 84 85 int clamp( int i ) 144 { 145 rangeContainer.insert( RangePtr( Range::create( min, max ) ) ); 146 activeRange = *rangeContainer.begin(); 147 } 148 149 int clamp( int i ) const 86 150 { 87 151 return std::max( std::min( i, max ), min ); 88 152 } 89 153 90 int inClamp( int i ) 91 { 92 return std::max( std::min( i, outValue ), min ); 93 } 94 95 int outClamp( int i ) 96 { 97 return std::max( std::min( i, max ), inValue ); 98 } 99 100 void updateValue() 101 { 102 // ensure min and max are the right way around... 103 if ( min > max ) 104 { 105 std::swap( min, max ); 106 } 107 108 // clamp value to range. Perfer in-point over out-point 109 int nv = inClamp( outClamp( clamp( v ) ) ); 110 if ( nv != v ) 111 { 112 v = nv; 113 emit parent->valueChanged( v ); 114 emit parent->value_changed(); 115 } 154 int inClamp( int i ) const 155 { 156 i = std::max( std::min( i, activeRange->out ), min ); 157 158 // And clamp above neighbouring out point 159 for ( RangeSet::const_iterator I = rangeContainer.begin(); 160 I != rangeContainer.end(); 161 ++I ) 162 { 163 if ( *I == activeRange ) continue; 164 165 if ( (*I)->out > activeRange->out ) break; 166 167 if ( i <= (*I)->out ) { 168 i = (*I)->out + 1; 169 break; 170 } 171 } 172 173 return i; 174 } 175 176 int outClamp( int i ) const 177 { 178 i = std::max( std::min( i, max ), activeRange->in ); 179 180 // And clamp below neighbouring in point 181 for ( RangeSet::const_reverse_iterator I = rangeContainer.rbegin(); 182 I != rangeContainer.rend(); 183 ++I ) 184 { 185 if ( *I == activeRange ) continue; 186 187 if ( (*I)->out < activeRange->in ) break; 188 189 if ( i >= (*I)->in ) { 190 i = (*I)->in - 1; 191 break; 192 } 193 } 194 195 return i; 116 196 } 117 197 118 198 int convertToValue( int pt ) const 119 199 { 120 return min + (int)( length() * ((double)(pt - xoffset())/trackLength()) );200 return clamp( min + (int)( length() * ((double)(pt - xoffset())/trackLength()) ) ); 121 201 } 122 202 … … 137 217 { 138 218 // Should include the yoffset(), but this interacts badly with the outRect() offset... 139 int width = parent->width() - xoffset() ; // - yoffset();219 int width = parent->width() - xoffset() - (outThumb.normal.isNull() ? 0 : outThumb.normal.width() / 2); 140 220 // Ensure it's a multiple of the thumb width 141 return width - width % thumbWidth();221 return width; // - width % thumbWidth(); 142 222 } 143 223 144 224 int xoffset() const 145 225 { 146 return inThumb.normal.isNull() ? 0 : inThumb.normal.width(); 147 } 148 149 int yoffset() const 150 { 151 return outThumb.normal.isNull() ? 0 : outThumb.normal.width(); 226 return inThumb.normal.isNull() ? 0 : inThumb.normal.width() / 2; 152 227 } 153 228 … … 159 234 QRect inRect() const 160 235 { 161 int v = convertToPixel( inValue ); 236 // center in and out rects horizontally to allow for various marker positions 237 int v = convertToPixel( activeRange->in ); 162 238 QSize size = inThumb.normal.isNull() ? inOutSize( parent->height() ) : inThumb.normal.size(); 163 return QRect( QPoint( v - size.width() , (parent->height() - size.height())/2 ), size );239 return QRect( QPoint( v - size.width() / 2, (parent->height() - size.height())/2 ), size ); 164 240 } 165 241 166 242 QRect outRect() const 167 243 { 244 // center in and out rects horizontally to allow for various marker positions 168 245 QSize size = outThumb.normal.isNull() ? inOutSize( parent->height() ) : outThumb.normal.size(); 169 246 int x; 170 if ( outValue != inValue)171 x = convertToPixel( outValue );247 if ( activeRange->out != activeRange->in ) 248 x = convertToPixel( activeRange->out ) - size.width() / 2; 172 249 else 173 x = parent->width() - size.width() ;250 x = parent->width() - size.width() / 2; 174 251 175 252 // x should be v + size.width(), but this interacts badly when trackLength() is calculated correctly... … … 177 254 } 178 255 256 QRect thumbnailMarkerRect() const 257 { 258 if ( thumbnailFrame == -1 || thumbnailMarker.normal.isNull() ) return QRect(); 259 260 QSize size = thumbnailMarker.normal.size(); 261 int markerPos = convertToPixel( thumbnailFrame ); 262 return QRect( markerPos - size.width() / 2, (parent->height() - size.height()) / 2, 263 size.width(), size.height() ); 264 } 265 179 266 QRect currentMarkerRect() const 180 267 { … … 186 273 return QRect( convertToPixel( v ) - width/2, (parent->height()-thumb.normal.height())/2, 187 274 width, thumb.normal.height() ); 275 } 276 277 bool hitInRect( QPoint pos ) const 278 { 279 // We've got to be in the thumb rect and outside the currentMarkerRect region 280 if ( inRect().contains( pos ) == false ) return false; 281 282 // else check the marker rect 283 QRect markerRect = currentMarkerRect(); 284 return (pos.y() > markerRect.bottom() || pos.y() < markerRect.top()); 285 } 286 287 bool hitOutRect( QPoint pos ) const 288 { 289 // We've got to be in the thumb rect and outside the currentMarkerRect region 290 if ( outRect().contains( pos ) == false ) return false; 291 292 // else check the marker rect 293 QRect markerRect = currentMarkerRect(); 294 return (pos.y() > markerRect.bottom() || pos.y() < markerRect.top()); 188 295 } 189 296 … … 232 339 } 233 340 341 void paintTray() 342 { 343 buffer = QPixmap(); 344 tray_full.resize( parent->size() ); 345 346 if ( !tray.isNull() ) 347 { 348 // assume we can split in the middle and stretch 349 // pixmap should always be horizontal; we will rotate 350 // for vertical sliders 351 const int half_width = tray.width()/2; 352 const int height = tray.height(); 353 354 QPixmap filler( 1, height ); 355 356 // get filler 357 copyBlt( &filler, 0, 0, &tray, half_width, 0, 1, height ); 358 359 // work out how much filler we need 360 const int fillerDistance = parent->width() - 2*half_width; 361 362 // get left 363 copyBlt( &tray_full, 0, 0, &tray, 0, 0, half_width, height ); 364 365 // filler 366 int i = 0; 367 while ( i < fillerDistance ) 368 { 369 copyBlt( &tray_full, half_width + i++, 0, &filler, 0, 0, 1, height ); 370 } 371 372 // right 373 copyBlt( &tray_full, half_width + fillerDistance, 0, 374 &tray, half_width, 0, half_width, height ); 375 } 376 else 377 { 378 tray_full.fill( parent, 0, 0 ); 379 } 380 381 // And the full duration/elapsed pixmaps 382 if ( !duration.isNull() ) 383 { 384 const int h = duration.height(); 385 const int w = parent->width(); 386 duration_full.resize( w, h ); 387 copyBlt( &duration_full, 0, 0, 388 &tray_full, 0, (parent->height()-h)/2, w, h ); 389 390 QPainter p( &duration_full ); 391 p.drawTiledPixmap( 0, 0, w, h, duration ); 392 } 393 394 if ( !elapsed.isNull() ) 395 { 396 const int h = elapsed.height(); 397 const int w = parent->width(); 398 elapsed_full.resize( w, h ); 399 copyBlt( &elapsed_full, 0, 0, 400 &tray_full, 0, (parent->height()-h)/2, w, h ); 401 402 QPainter p( &elapsed_full ); 403 p.drawTiledPixmap( 0, 0, w, h, elapsed ); 404 } 405 } 406 234 407 TimelineSlider* parent; 235 408 … … 239 412 int v; 240 413 414 int thumbnailFrame; 415 241 416 // in, out are in frames also 242 int inValue; 243 int outValue; 417 RangeSet rangeContainer; 418 RangePtr activeRange; 419 244 420 bool showInOut; 245 421 … … 267 443 IconSet inThumb; 268 444 IconSet outThumb; 445 IconSet thumbnailMarker; 269 446 QPixmap duration; 270 447 QPixmap elapsed; … … 278 455 // for drawing 279 456 QPixmap buffer; 457 458 std::auto_ptr<Delegate> delegate; 280 459 }; 281 460 282 461 TimelineSlider::TimelineSlider( QWidget* parent, const char* name ) 283 462 : QWidget( parent, name ), 284 m_impl( new PrivateTimeline Slider( this ) )463 m_impl( new PrivateTimeline( this ) ) 285 464 { 286 465 setBackgroundMode( Qt::NoBackground ); … … 295 474 } 296 475 297 void TimelineSlider::setRange( int minval, int maxval ) 298 { 299 setMinValue( minval ); 300 setMaxValue( maxval ); 476 void TimelineSlider::setMaxRange( int minval, int maxval ) 477 { 478 if ( minval > maxval ) { 479 int tmp = minval; 480 minval = maxval; 481 maxval = tmp; 482 } 483 484 m_impl->min = minval; 485 m_impl->max = maxval; 486 487 // Reset ranges 488 m_impl->rangeContainer.clear(); 489 m_impl->rangeContainer.insert( RangePtr(Range::create(minval, maxval)) ); 490 491 // Update value 492 m_impl->v = m_impl->clamp( m_impl->v ); 493 494 emit valueChanged( m_impl->v ); 495 emit value_changed(); 496 497 emit minValueChanged( minval ); 498 emit minimum_changed(); 499 500 emit maxValueChanged( maxval ); 501 emit maximum_changed(); 502 503 // Update active range 504 setActiveRangeId( (*(m_impl->rangeContainer.begin()))->id() ); 301 505 } 302 506 … … 308 512 void TimelineSlider::setLength( int l ) 309 513 { 310 setMinValue( 0 ); 311 setMaxValue( l - 1 ); 514 setMaxRange( 0, l - 1 ); 312 515 } 313 516 … … 319 522 } 320 523 321 m_impl->min = val; 322 m_impl->inValue = val; 323 m_impl->updateValue(); 524 setMaxRange( val, m_impl->max ); 324 525 325 526 emit minValueChanged( m_impl->min ); 326 emit inValueChanged( m_impl->inValue );327 emit valueChanged( m_impl->v );328 329 527 emit minimum_changed(); 330 emit value_changed();331 emit inValue_changed();332 333 update();334 528 } 335 529 … … 341 535 } 342 536 343 m_impl->max = val; 344 m_impl->outValue = val; 345 m_impl->updateValue(); 537 setMaxRange( m_impl->min, val ); 346 538 347 539 emit maxValueChanged( m_impl->max ); 348 emit outValueChanged( m_impl->outValue );349 emit valueChanged( m_impl->v );350 351 540 emit maximum_changed(); 352 emit value_changed();353 emit outValue_changed();354 355 update();356 541 } 357 542 … … 371 556 } 372 557 373 int TimelineSlider::inValue() const 374 { 375 return m_impl->inValue; 376 } 377 378 void TimelineSlider::setInValue( int v ) 379 { 380 m_impl->inValue = m_impl->inClamp( v ); 381 emit inValueChanged( m_impl->inValue ); 382 emit inValue_changed(); 383 384 update(); 385 } 386 387 int TimelineSlider::outValue() const 388 { 389 return m_impl->outValue; 390 } 391 392 void TimelineSlider::setOutValue( int v ) 393 { 394 m_impl->outValue = m_impl->outClamp( v ); 395 emit outValueChanged( m_impl->outValue ); 396 emit outValue_changed(); 558 int TimelineSlider::activeInValue() const 559 { 560 return m_impl->activeRange->in; 561 } 562 563 void TimelineSlider::setActiveInValue( int v ) 564 { 565 m_impl->activeRange->in = m_impl->inClamp( v ); 566 emit activeInValueChanged( m_impl->activeRange->in ); 567 emit activeInValue_changed(); 568 569 if ( m_impl->inThumb.isSelected() ) { 570 emit selectedPointChanged( m_impl->activeRange->in ); 571 emit selectedPoint_changed(); 572 } 573 574 update(); 575 } 576 577 int TimelineSlider::insertRange( int in, int out ) 578 { 579 qDebug( "insertRange: %d %d", in, out ); 580 581 // Clamp to min/max, but otherwise leave as-is 582 RangePtr range( Range::create( m_impl->clamp(in), m_impl->clamp(out) ) ); 583 m_impl->rangeContainer.insert( range ); 584 585 update(); 586 587 return range->id(); 588 } 589 590 void TimelineSlider::removeRangeWithId( int id ) 591 { 592 qDebug( "removeRangeWithId: %d", id ); 593 594 RangeSet::iterator I = std::find_if( m_impl->rangeContainer.begin(), 595 m_impl->rangeContainer.end(), 596 RangeIdentity( id ) ); 597 598 if ( I == m_impl->rangeContainer.end() ) { 599 qWarning( "Remove: unable to find range with id: %d", id ); 600 return; 601 } 602 603 m_impl->rangeContainer.erase( I ); 604 605 if ( m_impl->activeRange->id() == id ) { 606 if ( m_impl->rangeContainer.empty() ) { 607 m_impl->rangeContainer.insert( RangePtr( Range::create( m_impl->min, m_impl->max ) ) ); 608 } 609 610 setActiveRangeId( (*m_impl->rangeContainer.begin())->id() ); 611 } 612 613 update(); 614 } 615 616 TimelineSlider::RangeArray TimelineSlider::allRanges() const 617 { 618 RangeArray allRanges; 619 620 for ( RangeSet::const_iterator I = m_impl->rangeContainer.begin(); 621 I != m_impl->rangeContainer.end(); 622 ++I ) 623 { 624 allRanges.push_back( *(I->get()) ); 625 } 626 627 return allRanges; 628 } 629
