00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <cairomm-1.0/cairomm/cairomm.h>
00024 #include <boost/foreach.hpp>
00025
00026 #include "timeline-body.hpp"
00027 #include "../timeline-widget.hpp"
00028 #include "../../window-manager.hpp"
00029
00030 #include "timeline-arrow-tool.hpp"
00031 #include "timeline-ibeam-tool.hpp"
00032
00033 using namespace Gtk;
00034 using namespace std;
00035 using namespace boost;
00036
00037 namespace gui {
00038 namespace widgets {
00039 namespace timeline {
00040
00041 TimelineBody::TimelineBody(gui::widgets::TimelineWidget
00042 *timeline_widget) :
00043 Glib::ObjectBase("TimelineBody"),
00044 tool(NULL),
00045 dragType(None),
00046 mouseDownX(0),
00047 mouseDownY(0),
00048 beginShiftTimeOffset(0),
00049 selectionAlpha(0.5),
00050 timelineWidget(timeline_widget)
00051 {
00052 REQUIRE(timelineWidget != NULL);
00053
00054
00055 timelineWidget->get_view_window().changed_signal().connect(
00056 sigc::mem_fun(this, &TimelineBody::on_update_view) );
00057
00058
00059 register_styles();
00060 }
00061
00062 TimelineBody::~TimelineBody()
00063 {
00064 REQUIRE(tool != NULL);
00065 if(tool != NULL)
00066 delete tool;
00067 }
00068
00069 ToolType
00070 TimelineBody::get_tool() const
00071 {
00072 REQUIRE(tool != NULL);
00073 if(tool != NULL)
00074 return tool->get_type();
00075 return gui::widgets::timeline::None;
00076 }
00077
00078 void
00079 TimelineBody::set_tool(timeline::ToolType tool_type)
00080 {
00081
00082 if(tool != NULL)
00083 {
00084
00085 if(tool->get_type() == tool_type)
00086 return;
00087
00088 delete tool;
00089 }
00090
00091
00092 switch(tool_type)
00093 {
00094 case timeline::Arrow:
00095 tool = new ArrowTool(this);
00096 break;
00097
00098 case timeline::IBeam:
00099 tool = new IBeamTool(this);
00100 break;
00101 }
00102
00103
00104 tool->apply_cursor();
00105 }
00106
00107 void
00108 TimelineBody::on_update_view()
00109 {
00110 queue_draw();
00111 }
00112
00113 void
00114 TimelineBody::on_realize()
00115 {
00116 Widget::on_realize();
00117
00118
00119 add_events(
00120 Gdk::POINTER_MOTION_MASK |
00121 Gdk::SCROLL_MASK |
00122 Gdk::BUTTON_PRESS_MASK |
00123 Gdk::BUTTON_RELEASE_MASK);
00124
00125
00126 tool->apply_cursor();
00127 }
00128
00129 bool
00130 TimelineBody::on_expose_event(GdkEventExpose* event)
00131 {
00132 REQUIRE(event != NULL);
00133 REQUIRE(timelineWidget != NULL);
00134
00135
00136 Glib::RefPtr<Gdk::Window> window = get_window();
00137 if(!window)
00138 return false;
00139
00140
00141 read_styles();
00142
00143
00144 const Allocation allocation = get_allocation();
00145 Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
00146
00147 REQUIRE(cr);
00148
00149
00150 draw_tracks(cr);
00151 draw_selection(cr);
00152 draw_playback_point(cr);
00153
00154 return true;
00155 }
00156
00157 bool
00158 TimelineBody::on_scroll_event (GdkEventScroll* event)
00159 {
00160 REQUIRE(event != NULL);
00161 REQUIRE(timelineWidget != NULL);
00162
00163 TimelineViewWindow &window = timelineWidget->get_view_window();
00164
00165 if(event->state & GDK_CONTROL_MASK)
00166 {
00167 switch(event->direction)
00168 {
00169 case GDK_SCROLL_UP:
00170
00171 window.zoom_view(event->x, 1);
00172 break;
00173
00174 case GDK_SCROLL_DOWN:
00175
00176 window.zoom_view(event->x, -1);
00177 break;
00178 }
00179 }
00180 else
00181 {
00182 switch(event->direction)
00183 {
00184 case GDK_SCROLL_UP:
00185
00186 window.shift_view(-16);
00187 break;
00188
00189 case GDK_SCROLL_DOWN:
00190
00191 window.shift_view(16);
00192 break;
00193 }
00194 }
00195 }
00196
00197 bool
00198 TimelineBody::on_button_press_event(GdkEventButton* event)
00199 {
00200 mouseDownX = event->x;
00201 mouseDownY = event->y;
00202
00203 switch(event->button)
00204 {
00205 case 2:
00206 begin_shift_drag();
00207 break;
00208
00209 default:
00210 dragType = None;
00211 break;
00212 }
00213
00214
00215 tool->on_button_press_event(event);
00216
00217 return true;
00218 }
00219
00220 bool
00221 TimelineBody::on_button_release_event(GdkEventButton* event)
00222 {
00223
00224 dragType = None;
00225
00226
00227 tool->on_button_release_event(event);
00228
00229 return true;
00230 }
00231
00232 bool
00233 TimelineBody::on_motion_notify_event(GdkEventMotion *event)
00234 {
00235 REQUIRE(event != NULL);
00236
00237
00238 switch(dragType)
00239 {
00240 case Shift:
00241 {
00242 TimelineViewWindow &window = timelineWidget->get_view_window();
00243
00244 const int64_t scale = window.get_time_scale();
00245 gavl_time_t offset = beginShiftTimeOffset +
00246 (int64_t)(mouseDownX - event->x) * scale;
00247 window.set_time_offset(offset);
00248
00249 set_vertical_offset((int)(mouseDownY - event->y) +
00250 beginShiftVerticalOffset);
00251 break;
00252 }
00253 }
00254
00255
00256 tool->on_motion_notify_event(event);
00257
00258
00259 shared_ptr<timeline::Track> new_hovering_track =
00260 track_from_point(event->y);
00261 if(timelineWidget->get_hovering_track() != new_hovering_track)
00262 timelineWidget->set_hovering_track(new_hovering_track);
00263
00264
00265 return false;
00266 }
00267
00268 void
00269 TimelineBody::draw_tracks(Cairo::RefPtr<Cairo::Context> cr)
00270 {
00271 REQUIRE(cr);
00272 REQUIRE(timelineWidget != NULL);
00273 REQUIRE(timelineWidget->sequence);
00274
00275
00276 const Allocation allocation = get_allocation();
00277
00278
00279 Cairo::Matrix view_matrix;
00280 cr->get_matrix(view_matrix);
00281
00282
00283 cr->translate(0, -get_vertical_offset());
00284
00285
00286 BOOST_FOREACH( shared_ptr<model::Track> model_track,
00287 timelineWidget->sequence->get_child_tracks() )
00288 draw_track_recursive(cr, model_track, allocation.get_width());
00289
00290
00291 cr->set_matrix(view_matrix);
00292 }
00293
00294 void
00295 TimelineBody::draw_track_recursive(Cairo::RefPtr<Cairo::Context> cr,
00296 shared_ptr<model::Track> model_track, const int view_width) const
00297 {
00298 REQUIRE(cr);
00299 REQUIRE(model_track != NULL);
00300 REQUIRE(timelineWidget != NULL);
00301
00302 shared_ptr<timeline::Track> timeline_track = timelineWidget->
00303 lookup_timeline_track(model_track);
00304
00305 const int height = timeline_track->get_height();
00306 REQUIRE(height >= 0);
00307
00308
00309 cr->rectangle(0, 0, view_width, height);
00310 GdkColor colour = backgroundColour;
00311 gdk_cairo_set_source_color(cr->cobj(), &colour);
00312 cr->fill();
00313
00314
00315 cr->save();
00316 timeline_track->draw_track(cr, &timelineWidget->get_view_window());
00317 cr->restore();
00318
00319
00320 cr->translate(0, height + TimelineWidget::TrackPadding);
00321
00322
00323 BOOST_FOREACH( shared_ptr<model::Track> child,
00324 model_track->get_child_tracks() )
00325 draw_track_recursive(cr, child, view_width);
00326 }
00327
00328 void
00329 TimelineBody::draw_selection(Cairo::RefPtr<Cairo::Context> cr)
00330 {
00331 REQUIRE(cr);
00332 REQUIRE(timelineWidget != NULL);
00333
00334
00335 const Allocation allocation = get_allocation();
00336
00337 const TimelineViewWindow &window = timelineWidget->get_view_window();
00338 const int start_x = window.time_to_x(
00339 timelineWidget->get_selection_start());
00340 const int end_x = window.time_to_x(
00341 timelineWidget->get_selection_end());
00342
00343
00344 if(end_x > 0 && start_x < allocation.get_width())
00345 {
00346 cr->set_source_rgba(
00347 (float)selectionColour.red / 0xFFFF,
00348 (float)selectionColour.green / 0xFFFF,
00349 (float)selectionColour.blue / 0xFFFF,
00350 selectionAlpha);
00351 cr->rectangle(start_x + 0.5, 0,
00352 end_x - start_x, allocation.get_height());
00353 cr->fill();
00354 }
00355
00356 gdk_cairo_set_source_color(cr->cobj(), &selectionColour);
00357 cr->set_line_width(1);
00358
00359
00360 if(start_x >= 0 && start_x < allocation.get_width())
00361 {
00362 cr->move_to(start_x + 0.5, 0);
00363 cr->line_to(start_x + 0.5, allocation.get_height());
00364 cr->stroke();
00365 }
00366
00367
00368 if(end_x >= 0 && end_x < allocation.get_width())
00369 {
00370 cr->move_to(end_x + 0.5, 0);
00371 cr->line_to(end_x + 0.5, allocation.get_height());
00372 cr->stroke();
00373 }
00374 }
00375
00376 void
00377 TimelineBody::draw_playback_point(Cairo::RefPtr<Cairo::Context> cr)
00378 {
00379 REQUIRE(cr);
00380 REQUIRE(timelineWidget != NULL);
00381
00382
00383 const Allocation allocation = get_allocation();
00384
00385 const gavl_time_t point = timelineWidget->get_playback_point();
00386 if(point == GAVL_TIME_UNDEFINED)
00387 return;
00388
00389 const int x = timelineWidget->get_view_window().time_to_x(point);
00390
00391
00392 gdk_cairo_set_source_color(cr->cobj(), &playbackPointColour);
00393 cr->set_line_width(1);
00394
00395
00396 if(x >= 0 && x < allocation.get_width())
00397 {
00398 cr->move_to(x + 0.5, 0);
00399 cr->line_to(x + 0.5, allocation.get_height());
00400 cr->stroke();
00401 }
00402 }
00403
00404 void
00405 TimelineBody::begin_shift_drag()
00406 {
00407 dragType = Shift;
00408 beginShiftTimeOffset =
00409 timelineWidget->get_view_window().get_time_offset();
00410 beginShiftVerticalOffset = get_vertical_offset();
00411 }
00412
00413 int
00414 TimelineBody::get_vertical_offset() const
00415 {
00416 return (int)timelineWidget->verticalAdjustment.get_value();
00417 }
00418
00419 void
00420 TimelineBody::set_vertical_offset(int offset)
00421 {
00422 timelineWidget->verticalAdjustment.set_value(offset);
00423 }
00424
00425 shared_ptr<timeline::Track>
00426 TimelineBody::track_from_point(const int y) const
00427 {
00428 REQUIRE(timelineWidget != NULL);
00429 REQUIRE(timelineWidget->sequence);
00430
00431 int offset = -get_vertical_offset();
00432
00433 BOOST_FOREACH( shared_ptr<model::Track> model_track,
00434 timelineWidget->sequence->get_child_tracks() )
00435 {
00436 shared_ptr<timeline::Track> result = track_from_branch(
00437 model_track, y, offset);
00438 if(result)
00439 return result;
00440 }
00441
00442
00443 return boost::shared_ptr<timeline::Track>();
00444 }
00445
00446 shared_ptr<timeline::Track> TimelineBody::track_from_branch(
00447 shared_ptr<model::Track> model_track,
00448 const int y, int &offset) const
00449 {
00450 REQUIRE(timelineWidget != NULL);
00451
00452 shared_ptr<timeline::Track> timeline_track = timelineWidget->
00453 lookup_timeline_track(model_track);
00454
00455 const int height = timeline_track->get_height();
00456 REQUIRE(height >= 0);
00457
00458
00459 if(offset <= y && y < offset + height)
00460 return timeline_track;
00461
00462
00463 offset += height;
00464
00465
00466 BOOST_FOREACH( shared_ptr<model::Track> child,
00467 model_track->get_child_tracks() )
00468 {
00469 shared_ptr<timeline::Track> result =
00470 track_from_branch(child, y, offset);
00471 if(result != NULL)
00472 return result;
00473 }
00474
00475
00476 return shared_ptr<timeline::Track>();
00477 }
00478
00479 void
00480 TimelineBody::register_styles() const
00481 {
00482 static bool registered = false;
00483 if(registered) return;
00484 registered = true;
00485
00486 GtkWidgetClass *klass = GTK_WIDGET_CLASS(G_OBJECT_GET_CLASS(gobj()));
00487
00488 gtk_widget_class_install_style_property(klass,
00489 g_param_spec_boxed("background", "Track Background",
00490 "The background colour of timeline tracks",
00491 GDK_TYPE_COLOR, G_PARAM_READABLE));
00492
00493 gtk_widget_class_install_style_property(klass,
00494 g_param_spec_boxed("selection", "End lines of a selection",
00495 "The colour of selection limit lines",
00496 GDK_TYPE_COLOR, G_PARAM_READABLE));
00497
00498 gtk_widget_class_install_style_property(klass,
00499 g_param_spec_float("selection_alpha", "Selection Alpha",
00500 "The transparency of the selection marque.",
00501 0, 1.0, 0.5, G_PARAM_READABLE));
00502
00503 gtk_widget_class_install_style_property(klass,
00504 g_param_spec_boxed("playback_point", "Playback Point",
00505 "The colour of the playback marker line",
00506 GDK_TYPE_COLOR, G_PARAM_READABLE));
00507 }
00508
00509 void
00510 TimelineBody::read_styles()
00511 {
00512 backgroundColour = WindowManager::read_style_colour_property(
00513 *this, "background", 0, 0, 0);
00514
00515 selectionColour = WindowManager::read_style_colour_property(
00516 *this, "selection", 0, 0, 0);
00517 get_style_property("selection_alpha", selectionAlpha);
00518
00519 playbackPointColour = WindowManager::read_style_colour_property(
00520 *this, "playback_point", 0, 0, 0);
00521 }
00522
00523 }
00524 }
00525 }