00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "timeline-widget.hpp"
00024
00025 #include <boost/foreach.hpp>
00026 #include <typeinfo>
00027
00028 using namespace Gtk;
00029 using namespace std;
00030 using namespace boost;
00031 using namespace util;
00032 using namespace gui::widgets::timeline;
00033
00034 namespace gui {
00035 namespace widgets {
00036
00037 const int TimelineWidget::TrackPadding = 1;
00038 const int TimelineWidget::HeaderWidth = 150;
00039 const double TimelineWidget::ZoomIncrement = 1.25;
00040 const int64_t TimelineWidget::MaxScale = 30000000;
00041
00042 TimelineWidget::TimelineWidget(
00043 shared_ptr<model::Sequence> source_sequence) :
00044 Table(2, 2),
00045 sequence(source_sequence),
00046 viewWindow(this, 0, 1),
00047 totalHeight(0),
00048 horizontalAdjustment(0, 0, 0),
00049 verticalAdjustment(0, 0, 0),
00050 selectionStart(0),
00051 selectionEnd(0),
00052 playbackPeriodStart(0),
00053 playbackPeriodEnd(0),
00054 playbackPoint(GAVL_TIME_UNDEFINED),
00055 horizontalScroll(horizontalAdjustment),
00056 verticalScroll(verticalAdjustment)
00057 {
00058 REQUIRE(sequence);
00059
00060 body = new TimelineBody(this);
00061 ENSURE(body != NULL);
00062 headerContainer = new TimelineHeaderContainer(this);
00063 ENSURE(headerContainer != NULL);
00064 ruler = new TimelineRuler(this);
00065 ENSURE(ruler != NULL);
00066
00067 horizontalAdjustment.signal_value_changed().connect( sigc::mem_fun(
00068 this, &TimelineWidget::on_scroll) );
00069 verticalAdjustment.signal_value_changed().connect( sigc::mem_fun(
00070 this, &TimelineWidget::on_scroll) );
00071 body->signal_motion_notify_event().connect( sigc::mem_fun(
00072 this, &TimelineWidget::on_motion_in_body_notify_event) );
00073 viewWindow.changed_signal().connect( sigc::mem_fun(
00074 this, &TimelineWidget::on_view_window_changed) );
00075
00076 viewWindow.set_time_scale(GAVL_TIME_SCALE / 200);
00077 set_selection(2000000, 4000000);
00078
00079 update_tracks();
00080
00081 attach(*body, 1, 2, 1, 2, FILL|EXPAND, FILL|EXPAND);
00082 attach(*ruler, 1, 2, 0, 1, FILL|EXPAND, SHRINK);
00083 attach(*headerContainer, 0, 1, 1, 2, SHRINK, FILL|EXPAND);
00084 attach(horizontalScroll, 1, 2, 2, 3, FILL|EXPAND, SHRINK);
00085 attach(verticalScroll, 2, 3, 1, 2, SHRINK, FILL|EXPAND);
00086
00087 set_tool(timeline::Arrow);
00088
00089
00090 sequence->get_child_track_list().signal_changed().connect(
00091 sigc::mem_fun( this, &TimelineWidget::on_track_list_changed ) );
00092 }
00093
00094 TimelineWidget::~TimelineWidget()
00095 {
00096
00097 REQUIRE(body != NULL);
00098 if(body != NULL)
00099 body->unreference();
00100
00101 REQUIRE(headerContainer != NULL);
00102 if(headerContainer != NULL)
00103 headerContainer->unreference();
00104
00105 REQUIRE(ruler != NULL);
00106 if(ruler != NULL)
00107 ruler->unreference();
00108 }
00109
00110
00111
00112 TimelineViewWindow&
00113 TimelineWidget::get_view_window()
00114 {
00115 return viewWindow;
00116 }
00117
00118 gavl_time_t
00119 TimelineWidget::get_selection_start() const
00120 {
00121 return selectionStart;
00122 }
00123
00124 gavl_time_t
00125 TimelineWidget::get_selection_end() const
00126 {
00127 return selectionEnd;
00128 }
00129
00130 void
00131 TimelineWidget::set_selection(gavl_time_t start, gavl_time_t end,
00132 bool reset_playback_period)
00133 {
00134 REQUIRE(ruler != NULL);
00135 REQUIRE(body != NULL);
00136
00137 if(start < end)
00138 {
00139 selectionStart = start;
00140 selectionEnd = end;
00141 }
00142 else
00143 {
00144
00145 selectionStart = end;
00146 selectionEnd = start;
00147 }
00148
00149 if(reset_playback_period)
00150 {
00151 playbackPeriodStart = selectionStart;
00152 playbackPeriodEnd = selectionEnd;
00153 }
00154
00155 ruler->queue_draw();
00156 body->queue_draw();
00157 }
00158
00159 gavl_time_t
00160 TimelineWidget::get_playback_period_start() const
00161 {
00162 return playbackPeriodStart;
00163 }
00164
00165 gavl_time_t
00166 TimelineWidget::get_playback_period_end() const
00167 {
00168 return playbackPeriodEnd;
00169 }
00170
00171 void
00172 TimelineWidget::set_playback_period(gavl_time_t start, gavl_time_t end)
00173 {
00174 REQUIRE(ruler != NULL);
00175 REQUIRE(body != NULL);
00176
00177 if(start < end)
00178 {
00179 playbackPeriodStart = start;
00180 playbackPeriodEnd = end;
00181 }
00182 else
00183 {
00184
00185 playbackPeriodStart = end;
00186 playbackPeriodEnd = start;
00187 }
00188
00189 ruler->queue_draw();
00190 body->queue_draw();
00191 }
00192
00193 void
00194 TimelineWidget::set_playback_point(gavl_time_t point)
00195 {
00196 playbackPoint = point;
00197 ruler->queue_draw();
00198 body->queue_draw();
00199 }
00200
00201 gavl_time_t
00202 TimelineWidget::get_playback_point() const
00203 {
00204 return playbackPoint;
00205 }
00206
00207 ToolType
00208 TimelineWidget::get_tool() const
00209 {
00210 REQUIRE(body != NULL);
00211 return body->get_tool();
00212 }
00213
00214 void
00215 TimelineWidget::set_tool(ToolType tool_type)
00216 {
00217 REQUIRE(body != NULL);
00218 body->set_tool(tool_type);
00219 }
00220
00221 shared_ptr<timeline::Track>
00222 TimelineWidget::get_hovering_track() const
00223 {
00224 return hoveringTrack;
00225 }
00226
00227
00228
00229 sigc::signal<void, gavl_time_t>
00230 TimelineWidget::mouse_hover_signal() const
00231 {
00232 return mouseHoverSignal;
00233 }
00234
00235 sigc::signal<void>
00236 TimelineWidget::playback_period_drag_released_signal() const
00237 {
00238 return playbackPeriodDragReleasedSignal;
00239 }
00240
00241 sigc::signal<void, shared_ptr<timeline::Track> >
00242 TimelineWidget::hovering_track_changed_signal() const
00243 {
00244 return hoveringTrackChangedSignal;
00245 }
00246
00247
00248
00249 void
00250 TimelineWidget::on_scroll()
00251 {
00252 viewWindow.set_time_offset(horizontalAdjustment.get_value());
00253 }
00254
00255 void
00256 TimelineWidget::on_size_allocate(Allocation& allocation)
00257 {
00258 Widget::on_size_allocate(allocation);
00259
00260 update_scroll();
00261 }
00262
00263 void
00264 TimelineWidget::on_view_window_changed()
00265 {
00266 REQUIRE(ruler != NULL);
00267
00268 const int view_width = body->get_allocation().get_width();
00269 horizontalAdjustment.set_page_size(
00270 viewWindow.get_time_scale() * view_width);
00271 horizontalAdjustment.set_value(
00272 viewWindow.get_time_offset());
00273 }
00274
00275 void
00276 TimelineWidget::on_add_track_command()
00277 {
00278 REQUIRE(sequence);
00279
00280
00281 sequence->get_child_track_list().push_back(
00282 shared_ptr<model::Track>(new model::ClipTrack()));
00283 }
00284
00285
00286
00287 void
00288 TimelineWidget::update_tracks()
00289 {
00290 REQUIRE(sequence);
00291
00292
00293 remove_orphaned_tracks();
00294
00295
00296 create_timeline_tracks();
00297
00298
00299 REQUIRE(headerContainer != NULL);
00300 headerContainer->show_all_children();
00301 headerContainer->update_headers();
00302
00303
00304 body->queue_draw();
00305
00306
00307 totalHeight = 0;
00308 BOOST_FOREACH(shared_ptr<model::Track> track,
00309 sequence->get_child_tracks())
00310 {
00311 REQUIRE(track);
00312 totalHeight += measure_branch_height(track);
00313 }
00314 }
00315
00316 void
00317 TimelineWidget::create_timeline_tracks()
00318 {
00319 REQUIRE(sequence);
00320 REQUIRE(headerContainer != NULL);
00321 REQUIRE(body != NULL);
00322
00323 BOOST_FOREACH(shared_ptr<model::Track> child,
00324 sequence->get_child_tracks())
00325 create_timeline_tracks_from_branch(child);
00326 }
00327
00328 void
00329 TimelineWidget::create_timeline_tracks_from_branch(
00330 shared_ptr<model::Track> model_track)
00331 {
00332 REQUIRE(model_track);
00333
00334
00335 if(!contains(trackMap, model_track))
00336 {
00337
00338
00339 trackMap[model_track] =
00340 create_timeline_track_from_model_track(model_track);
00341 }
00342
00343
00344 BOOST_FOREACH(shared_ptr<model::Track> child,
00345 model_track->get_child_tracks())
00346 create_timeline_tracks_from_branch(child);
00347 }
00348
00349 shared_ptr<timeline::Track>
00350 TimelineWidget::create_timeline_track_from_model_track(
00351 shared_ptr<model::Track> model_track)
00352 {
00353 REQUIRE(model_track);
00354
00355
00356
00357 if(typeid(*model_track) == typeid(model::ClipTrack))
00358 return shared_ptr<timeline::Track>(new timeline::ClipTrack(
00359 *this, model_track));
00360 else if(typeid(*model_track) == typeid(model::GroupTrack))
00361 return shared_ptr<timeline::Track>(new timeline::GroupTrack(
00362 *this, model_track));
00363
00364 ASSERT(NULL);
00365 return shared_ptr<timeline::Track>();
00366 }
00367
00368 void
00369 TimelineWidget::remove_orphaned_tracks()
00370 {
00371 REQUIRE(sequence);
00372 REQUIRE(headerContainer != NULL);
00373 REQUIRE(body != NULL);
00374
00375 std::map<boost::shared_ptr<model::Track>,
00376 boost::shared_ptr<timeline::Track> >
00377 orphan_track_map(trackMap);
00378
00379
00380 BOOST_FOREACH(shared_ptr<model::Track> child,
00381 sequence->get_child_tracks())
00382 search_orphaned_tracks_in_branch(child, orphan_track_map);
00383
00384
00385
00386 std::pair<shared_ptr<model::Track>, shared_ptr<timeline::Track> >
00387 pair;
00388 BOOST_FOREACH( pair, orphan_track_map )
00389 {
00390 ENSURE(pair.first);
00391 trackMap.erase(pair.first);
00392 }
00393 }
00394
00395 void
00396 TimelineWidget::search_orphaned_tracks_in_branch(
00397 boost::shared_ptr<model::Track> model_track,
00398 std::map<boost::shared_ptr<model::Track>,
00399 boost::shared_ptr<timeline::Track> > &orphan_track_map)
00400 {
00401 REQUIRE(model_track);
00402
00403
00404 if(contains(orphan_track_map, model_track))
00405 orphan_track_map.erase(model_track);
00406
00407
00408 BOOST_FOREACH(shared_ptr<model::Track> child,
00409 model_track->get_child_tracks())
00410 search_orphaned_tracks_in_branch(child, orphan_track_map);
00411 }
00412
00413 shared_ptr<timeline::Track>
00414 TimelineWidget::lookup_timeline_track(
00415 shared_ptr<model::Track> model_track) const
00416 {
00417 REQUIRE(sequence);
00418 std::map<shared_ptr<model::Track>, shared_ptr<timeline::Track> >::
00419 const_iterator iterator = trackMap.find(model_track);
00420 if(iterator == trackMap.end())
00421 {
00422
00423
00424
00425
00426 ENSURE(0);
00427 return shared_ptr<timeline::Track>();
00428 }
00429 ENSURE(iterator->second != NULL);
00430 return iterator->second;
00431 }
00432
00433 boost::shared_ptr<model::Track>
00434 TimelineWidget::lookup_model_track(
00435 const timeline::Track *timeline_track) const
00436 {
00437 REQUIRE(sequence);
00438
00439 std::pair<shared_ptr<model::Track>, shared_ptr<timeline::Track> >
00440 pair;
00441 BOOST_FOREACH( pair, trackMap )
00442 {
00443 if(pair.second.get() == timeline_track)
00444 {
00445 ENSURE(pair.first);
00446 return pair.first;
00447 }
00448 }
00449
00450
00451
00452
00453
00454 ENSURE(0);
00455 return shared_ptr<model::Track>();
00456 }
00457
00458 void
00459 TimelineWidget::update_scroll()
00460 {
00461 REQUIRE(body != NULL);
00462 const Allocation body_allocation = body->get_allocation();
00463
00464
00465
00466
00467 horizontalAdjustment.set_upper(1000 * GAVL_TIME_SCALE / 200);
00468 horizontalAdjustment.set_lower(-1000 * GAVL_TIME_SCALE / 200);
00469
00470
00471 horizontalAdjustment.set_page_size(
00472 viewWindow.get_time_scale() * body_allocation.get_width());
00473
00474
00475
00476
00477
00478 int y_scroll_length = totalHeight - body_allocation.get_height();
00479 if(y_scroll_length < 0) y_scroll_length = 0;
00480
00481
00482
00483 if((int)verticalAdjustment.get_value() > y_scroll_length)
00484 verticalAdjustment.set_value(y_scroll_length);
00485
00486 verticalAdjustment.set_upper(y_scroll_length);
00487
00488
00489 #if 0
00490
00491
00492 if(y_scroll_length <= 0 && verticalScroll.is_visible())
00493 verticalScroll.hide();
00494 else if(y_scroll_length > 0 && !verticalScroll.is_visible())
00495 verticalScroll.show();
00496 #endif
00497
00498 }
00499
00500 int
00501 TimelineWidget::measure_branch_height(
00502 shared_ptr<model::Track> model_track)
00503 {
00504 REQUIRE(model_track);
00505
00506 const shared_ptr<timeline::Track> timeline_track =
00507 lookup_timeline_track(model_track);
00508 ENSURE(timeline_track);
00509
00510 int height = timeline_track->get_height() + TrackPadding;
00511
00512
00513 BOOST_FOREACH( shared_ptr<model::Track> child,
00514 model_track->get_child_tracks() )
00515 {
00516 REQUIRE(child);
00517 height += measure_branch_height(child);
00518 }
00519
00520 return height;
00521 }
00522
00523 int
00524 TimelineWidget::get_y_scroll_offset() const
00525 {
00526 return (int)verticalAdjustment.get_value();
00527 }
00528
00529 bool
00530 TimelineWidget::on_motion_in_body_notify_event(GdkEventMotion *event)
00531 {
00532 REQUIRE(event != NULL);
00533 ruler->set_mouse_chevron_offset(event->x);
00534 mouseHoverSignal.emit(viewWindow.x_to_time(event->x));
00535
00536 return true;
00537 }
00538
00539 void
00540 TimelineWidget::on_track_list_changed()
00541 {
00542 update_tracks();
00543 }
00544
00545 void
00546 TimelineWidget::on_playback_period_drag_released()
00547 {
00548 playbackPeriodDragReleasedSignal.emit();
00549 }
00550
00551 void
00552 TimelineWidget::set_hovering_track(
00553 shared_ptr<timeline::Track> hovering_track)
00554 {
00555 hoveringTrack = hovering_track;
00556 hoveringTrackChangedSignal.emit(hovering_track);
00557 }
00558
00559 }
00560 }