From efd9ab771b02e731b0327ea509c2466f76ca2cbc Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Wed, 22 Oct 2008 23:11:23 +0100 Subject: [PATCH] Added track tree support and added widgets to headers --- icons/Makefile.am | 34 +- icons/svg/track-disabled.svg | 663 ++++++++++++ icons/svg/track-enabled.svg | 967 ++++++++++++++++++ icons/svg/track-locked.svg | 866 ++++++++++++++++ icons/svg/track-unlocked.svg | 655 ++++++++++++ src/gui/widgets/timeline-widget.cpp | 19 +- src/gui/widgets/timeline-widget.hpp | 8 +- src/gui/widgets/timeline/timeline-body.cpp | 49 +- src/gui/widgets/timeline/timeline-body.hpp | 6 + .../timeline/timeline-header-container.cpp | 139 ++- .../timeline/timeline-header-container.hpp | 33 +- src/gui/widgets/timeline/track.cpp | 42 +- src/gui/widgets/timeline/track.hpp | 35 +- src/gui/window-manager.cpp | 7 +- 14 files changed, 3405 insertions(+), 118 deletions(-) create mode 100644 icons/svg/track-disabled.svg create mode 100644 icons/svg/track-enabled.svg create mode 100644 icons/svg/track-locked.svg create mode 100644 icons/svg/track-unlocked.svg diff --git a/icons/Makefile.am b/icons/Makefile.am index 6693b6d1d..281901e78 100644 --- a/icons/Makefile.am +++ b/icons/Makefile.am @@ -33,18 +33,40 @@ iconcommand = python $(top_srcdir)/admin/render-icon.py 48x48pre = $(prerendereddir)/48x48 lumigui_DEPENDENCIES += \ - rsvg-convert \ - $(16x16)/tool-arrow.png $(22x22)/tool-arrow.png $(24x24)/tool-arrow.png $(32x32)/tool-arrow.png $(48x48)/tool-arrow.png \ - $(16x16)/tool-i-beam.png $(22x22)/tool-i-beam.png $(24x24)/tool-i-beam.png $(32x32)/tool-i-beam.png $(48x48)/tool-i-beam.png \ - $(16x16)/panel-assets.png $(22x22)/panel-assets.png $(32x32)/panel-assets.png \ - $(16x16)/panel-timeline.png \ - $(16x16)/panel-viewer.png $(22x22)/panel-viewer.png $(32x32)/panel-viewer.png + rsvg-convert \ + $(16x16)/tool-arrow.png $(22x22)/tool-arrow.png $(24x24)/tool-arrow.png $(32x32)/tool-arrow.png $(48x48)/tool-arrow.png \ + $(16x16)/tool-i-beam.png $(22x22)/tool-i-beam.png $(24x24)/tool-i-beam.png $(32x32)/tool-i-beam.png $(48x48)/tool-i-beam.png \ + $(16x16)/track-disabled.png \ + $(16x16)/track-enabled.png \ + $(16x16)/track-locked.png \ + $(16x16)/track-unlocked.png \ + $(16x16)/panel-assets.png $(22x22)/panel-assets.png $(32x32)/panel-assets.png \ + $(16x16)/panel-timeline.png \ + $(16x16)/panel-viewer.png $(22x22)/panel-viewer.png $(32x32)/panel-viewer.png + +# ========== SVG Icons ========== + +# Timeline Tools $(16x16)/tool-arrow.png $(22x22)/tool-arrow.png $(24x24)/tool-arrow.png $(32x32)/tool-arrow.png $(48x48)/tool-arrow.png : $(svgdir)/tool-arrow.svg $(iconcommand) $< $(icondir) $(16x16)/tool-i-beam.png $(22x22)/tool-i-beam.png $(24x24)/tool-i-beam.png $(32x32)/tool-i-beam.png $(48x48)/tool-i-beam.png : $(svgdir)/tool-i-beam.svg $(iconcommand) $< $(icondir) +# Timeline Tracks +$(16x16)/track-disabled.png : $(svgdir)/track-disabled.svg + $(iconcommand) $< $(icondir) +$(16x16)/track-enabled.png : $(svgdir)/track-enabled.svg + $(iconcommand) $< $(icondir) +$(16x16)/track-locked.png : $(svgdir)/track-locked.svg + $(iconcommand) $< $(icondir) +$(16x16)/track-unlocked.png : $(svgdir)/track-unlocked.svg + $(iconcommand) $< $(icondir) + +# ========== Prerendered Icons ========== + +# Panels + $(16x16)/panel-assets.png: cp $(16x16pre)/panel-assets.png $(16x16) $(22x22)/panel-assets.png: diff --git a/icons/svg/track-disabled.svg b/icons/svg/track-disabled.svg new file mode 100644 index 000000000..04e87768e --- /dev/null +++ b/icons/svg/track-disabled.svg @@ -0,0 +1,663 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/icons/svg/track-enabled.svg b/icons/svg/track-enabled.svg new file mode 100644 index 000000000..ab6af9f53 --- /dev/null +++ b/icons/svg/track-enabled.svg @@ -0,0 +1,967 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/icons/svg/track-locked.svg b/icons/svg/track-locked.svg new file mode 100644 index 000000000..3ff1d34a4 --- /dev/null +++ b/icons/svg/track-locked.svg @@ -0,0 +1,866 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/icons/svg/track-unlocked.svg b/icons/svg/track-unlocked.svg new file mode 100644 index 000000000..beea19846 --- /dev/null +++ b/icons/svg/track-unlocked.svg @@ -0,0 +1,655 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp index 6c397f9f1..40d0ad09f 100644 --- a/src/gui/widgets/timeline-widget.cpp +++ b/src/gui/widgets/timeline-widget.cpp @@ -69,6 +69,9 @@ TimelineWidget::TimelineWidget() : set_selection(2000000, 4000000); tracks.push_back(&video1); + video1.add_child_track(&video1a); + video1.add_child_track(&video1b); + video1b.add_child_track(&video1ba); tracks.push_back(&video2); update_tracks(); @@ -332,7 +335,7 @@ TimelineWidget::update_tracks() BOOST_FOREACH( Track* track, tracks ) { ASSERT(track != NULL); - totalHeight += track->get_height() + TrackPadding; + totalHeight += measure_branch_height(track); } } @@ -378,6 +381,20 @@ TimelineWidget::update_scroll() } +int +TimelineWidget::measure_branch_height(Track* track) +{ + REQUIRE(track != NULL); + + int height = track->get_height(); + + // Recurse through all the children + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + height += measure_branch_height(child); + + return height; +} + int TimelineWidget::get_y_scroll_offset() const { diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp index 7785e7bc8..b1b3b0600 100644 --- a/src/gui/widgets/timeline-widget.hpp +++ b/src/gui/widgets/timeline-widget.hpp @@ -202,6 +202,8 @@ private: void update_scroll(); + static int measure_branch_height(timeline::Track* track); + int get_y_scroll_offset() const; bool on_motion_in_body_notify_event(GdkEventMotion *event); @@ -224,6 +226,9 @@ protected: int totalHeight; timeline::Track video1; + timeline::Track video1a; + timeline::Track video1b; + timeline::Track video1ba; timeline::Track video2; std::vector tracks; @@ -239,8 +244,7 @@ protected: // Signals sigc::signal viewChangedSignal; sigc::signal mouseHoverSignal; - sigc::signal - playbackPeriodDragReleasedSignal; + sigc::signal playbackPeriodDragReleasedSignal; /* ===== Constants ===== */ public: diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp index 7fa0881c5..72d56fd24 100644 --- a/src/gui/widgets/timeline/timeline-body.cpp +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -276,28 +276,45 @@ TimelineBody::draw_tracks(Cairo::RefPtr cr) BOOST_FOREACH( Track* track, timelineWidget->tracks ) { ASSERT(track != NULL); - - const int height = track->get_height(); - ASSERT(height >= 0); - - // Draw the track background - cr->rectangle(0, 0, allocation.get_width(), height); - gdk_cairo_set_source_color(cr->cobj(), &backgroundColour); - cr->fill(); - - // Render the track - cr->save(); - track->draw_track(cr); - cr->restore(); - - // Shift for the next track - cr->translate(0, height + TimelineWidget::TrackPadding); + draw_track_recursive(cr, track, allocation.get_width()); } // Restore the view matrix cr->set_matrix(view_matrix); } +void +TimelineBody::draw_track_recursive(Cairo::RefPtr cr, + const Track *track, const int view_width) const +{ + REQUIRE(cr); + REQUIRE(track != NULL); + + const int height = track->get_height(); + ASSERT(height >= 0); + + // Draw the track background + cr->rectangle(0, 0, view_width, + height - TimelineWidget::TrackPadding); + GdkColor colour = backgroundColour; // Needed to preserve const qualifier + gdk_cairo_set_source_color(cr->cobj(), &colour); + cr->fill(); + + // Render the track + cr->save(); + track->draw_track(cr); + cr->restore(); + + // Shift for the next track + cr->translate(0, height); + + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + { + ASSERT(track != NULL); + draw_track_recursive(cr, child, view_width); + } +} + void TimelineBody::draw_selection(Cairo::RefPtr cr) { diff --git a/src/gui/widgets/timeline/timeline-body.hpp b/src/gui/widgets/timeline/timeline-body.hpp index 894cb9f09..9ce48f5e1 100644 --- a/src/gui/widgets/timeline/timeline-body.hpp +++ b/src/gui/widgets/timeline/timeline-body.hpp @@ -36,6 +36,8 @@ class TimelineWidget; namespace timeline { +class Track; + /** * Implementation of the timeline body subwidget. This widget is * displayed in the centre of the timeline widget, and displays the @@ -111,6 +113,10 @@ private: */ void draw_tracks(Cairo::RefPtr cr); + void draw_track_recursive(Cairo::RefPtr cr, + const gui::widgets::timeline::Track *track, + const int view_width) const; + /** * Draws the selected timeline period. * @param cr The cairo context to draw into. diff --git a/src/gui/widgets/timeline/timeline-header-container.cpp b/src/gui/widgets/timeline/timeline-header-container.cpp index ba8323aab..3c16d912e 100644 --- a/src/gui/widgets/timeline/timeline-header-container.cpp +++ b/src/gui/widgets/timeline/timeline-header-container.cpp @@ -55,32 +55,15 @@ TimelineHeaderContainer::TimelineHeaderContainer(gui::widgets::TimelineWidget // Install style properties register_styles(); } - + void TimelineHeaderContainer::update_headers() { REQUIRE(timelineWidget != NULL); - - // Remove any pre-exisitng headers - BOOST_FOREACH( RootHeader header, rootHeaders ) - { - header.widget->unparent(); - } - rootHeaders.clear(); - // Add fresh headers BOOST_FOREACH( Track* track, timelineWidget->tracks ) - { - ASSERT(track != NULL); - - const RootHeader header = { &track->get_header_widget(), track }; - header.widget->set_parent(*this); - - rootHeaders.push_back(header); - } - - layout_headers(); + set_parent_recursive(track); } void @@ -132,18 +115,14 @@ TimelineHeaderContainer::on_unrealize() void TimelineHeaderContainer::on_size_request (Requisition* requisition) { - // Initialize the output parameter: - *requisition = Gtk::Requisition(); - // We don't care about the size of all the child widgets, but if we // don't send the size request down the tree, some widgets fail to - // calculate their text layout correctly. - BOOST_FOREACH( RootHeader header, rootHeaders ) - { - if(header.widget != NULL && header.widget->is_visible()) - header.widget->size_request(); - } - + // calculate their text layout correctly. + BOOST_FOREACH( Track* track, timelineWidget->tracks ) + size_request_recursive(track); + + // Initialize the output parameter: + *requisition = Gtk::Requisition(); requisition->width = TimelineWidget::HeaderWidth; requisition->height = 0; } @@ -166,10 +145,12 @@ void TimelineHeaderContainer::forall_vfunc(gboolean /* include_internals */, GtkCallback callback, gpointer callback_data) { - BOOST_FOREACH( RootHeader &header, rootHeaders ) + REQUIRE(callback != NULL); + + BOOST_FOREACH( Track* track, timelineWidget->tracks ) { - ASSERT(header.widget); - callback(header.widget->gobj(), callback_data); + ASSERT(track != NULL); + forall_vfunc_recursive(track, callback, callback_data); } } @@ -187,12 +168,12 @@ TimelineHeaderContainer::on_expose_event(GdkEventExpose *event) read_styles(); // Paint a border underneath all the root headers - BOOST_FOREACH( RootHeader &header, rootHeaders ) + BOOST_FOREACH( Track* track, timelineWidget->tracks ) { - ASSERT(header.widget); - ASSERT(header.track != NULL); + ASSERT(track != NULL); - const int height = header.track->get_height(); + const int height = TimelineWidget::measure_branch_height( + track); ASSERT(height >= 0); style->paint_box( @@ -237,30 +218,82 @@ TimelineHeaderContainer::layout_headers() const int header_width = container_allocation.get_width () - margin * 2; - BOOST_FOREACH( RootHeader &header, rootHeaders ) + BOOST_FOREACH( Track* track, timelineWidget->tracks ) { - ASSERT(header.widget); - ASSERT(header.track != NULL); - - const int height = header.track->get_height(); - ASSERT(height >= 0); - - Gtk::Allocation header_allocation; - header_allocation.set_x (margin); - header_allocation.set_y (offset - y_scroll_offset + margin); - header_allocation.set_width (header_width); - header_allocation.set_height (height - margin * 2); - - if(header.widget->is_visible()) - header.widget->size_allocate (header_allocation); - - offset += height + TimelineWidget::TrackPadding; + ASSERT(track != NULL); + layout_headers_recursive(track, y_scroll_offset, offset, + header_width, 0); } // Repaint the background of our parenting queue_draw (); } +void +TimelineHeaderContainer::layout_headers_recursive(Track *track, + const int y_scroll_offset, int &offset, + const int header_width, int depth) const +{ + const int height = track->get_height(); + ASSERT(height >= 0); + + const int indent = depth * 10; + + Allocation header_allocation; + header_allocation.set_x (margin + indent); + header_allocation.set_y (offset - y_scroll_offset + margin); + header_allocation.set_width (header_width - indent); + header_allocation.set_height (height - margin * 2); + + Widget &widget = track->get_header_widget(); + if(widget.is_visible()) + widget.size_allocate (header_allocation); + + offset += height + TimelineWidget::TrackPadding; + + // Recurse through all the children + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + layout_headers_recursive(child, y_scroll_offset, offset, + header_width, depth + 1); +} + +void +TimelineHeaderContainer::set_parent_recursive(Track *track) +{ + REQUIRE(track != NULL); + track->get_header_widget().set_parent(*this); + + // Recurse through all the children + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + set_parent_recursive(child); +} + +void +TimelineHeaderContainer::size_request_recursive(Track *track) +{ + REQUIRE(track != NULL); + if(track->get_header_widget().is_visible()) + track->get_header_widget().size_request(); + + // Recurse through all the children + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + size_request_recursive(child); +} + +void +TimelineHeaderContainer::forall_vfunc_recursive(Track* track, + GtkCallback callback, gpointer callback_data) +{ + REQUIRE(track != NULL); + REQUIRE(callback != NULL); + + callback(track->get_header_widget().gobj(), callback_data); + + // Recurse through all the children + BOOST_FOREACH( Track* child, track->get_child_tracks() ) + forall_vfunc_recursive(child, callback, callback_data); +} + void TimelineHeaderContainer::register_styles() const { diff --git a/src/gui/widgets/timeline/timeline-header-container.hpp b/src/gui/widgets/timeline/timeline-header-container.hpp index 480ab6cde..d287f2056 100644 --- a/src/gui/widgets/timeline/timeline-header-container.hpp +++ b/src/gui/widgets/timeline/timeline-header-container.hpp @@ -119,6 +119,21 @@ private: */ void layout_headers(); + void layout_headers_recursive(Track *track, + const int y_scroll_offset, int &offset, + const int header_width, int depth) const; + + /** + * Recursively sets all the track header widgets to be child widgets + * of this widget. + **/ + void set_parent_recursive(Track *track); + + static void size_request_recursive(Track *track); + + static void forall_vfunc_recursive(Track* track, + GtkCallback callback, gpointer callback_data); + /** * Registers all the styles that this class will respond to. */ @@ -143,24 +158,6 @@ private: * widgets are scrolled. */ Glib::RefPtr gdkWindow; - - //----- Header List -----// - - /** - * A structure to represent a header widget and it's - * associated track - */ - struct RootHeader - { - Gtk::Widget *widget; - Track *track; - }; - - /** - * Contains a list of the root currently present on - * the timeline view - */ - std::vector< RootHeader > rootHeaders; //----- Style Values -----// diff --git a/src/gui/widgets/timeline/track.cpp b/src/gui/widgets/timeline/track.cpp index f8acb35de..bac443ced 100644 --- a/src/gui/widgets/timeline/track.cpp +++ b/src/gui/widgets/timeline/track.cpp @@ -29,12 +29,30 @@ namespace widgets { namespace timeline { Track::Track() : - label1("test1"), label2("test2"), label3("test3"), label4("test4") + enableButton(Gtk::StockID("track_enabled")), + lockButton(Gtk::StockID("track_unlocked")) { - headerWidget.pack_start(label1, PACK_EXPAND_WIDGET); - headerWidget.pack_start(label2, PACK_EXPAND_WIDGET); - headerWidget.pack_start(label3, PACK_EXPAND_WIDGET); - headerWidget.pack_start(label4, PACK_EXPAND_WIDGET); + buttonBar.append(enableButton); + buttonBar.append(lockButton); + + buttonBar.set_toolbar_style(TOOLBAR_ICONS); + buttonBar.set_icon_size(ICON_SIZE_MENU); + + headerWidget.pack_start(titleBox, PACK_SHRINK); + headerWidget.pack_start(buttonBar, PACK_SHRINK); +} + +void +Track::add_child_track(timeline::Track* child) +{ + REQUIRE(child != NULL); + children.push_back(child); +} + +const std::vector& +Track::get_child_tracks() const +{ + return children; } Gtk::Widget& @@ -43,20 +61,20 @@ Track::get_header_widget() return headerWidget; } +int +Track::get_height() const +{ + return 100; +} + Glib::ustring Track::get_title() { return "Hello"; } -int -Track::get_height() -{ - return 100; -} - void -Track::draw_track(Cairo::RefPtr cairo) +Track::draw_track(Cairo::RefPtr cairo) const { } diff --git a/src/gui/widgets/timeline/track.hpp b/src/gui/widgets/timeline/track.hpp index a1b6d48e8..9f7277dd1 100644 --- a/src/gui/widgets/timeline/track.hpp +++ b/src/gui/widgets/timeline/track.hpp @@ -32,25 +32,42 @@ namespace gui { namespace widgets { namespace timeline { +class Clip; + class Track { public: Track(); + void add_child_track(timeline::Track* child); + + const std::vector& get_child_tracks() const; + + Gtk::Widget& get_header_widget(); + + int get_height() const; + Glib::ustring get_title(); - Gtk::Widget& get_header_widget(); + void draw_track(Cairo::RefPtr cairo) const; + +private: + +private: - int get_height(); + //----- Data -----// + std::vector children; + std::vector clips; - void draw_track(Cairo::RefPtr cairo); - -protected: + //----- Header Widgets ------// + Gtk::VBox headerWidget; - Gtk::Label label1; - Gtk::Label label2; - Gtk::CheckButton label3; - Gtk::Button label4; + + Gtk::ToolButton enableButton; + Gtk::ToolButton lockButton; + + Gtk::Entry titleBox; + Gtk::Toolbar buttonBar; }; diff --git a/src/gui/window-manager.cpp b/src/gui/window-manager.cpp index 4a89158d7..c7cbb3c32 100644 --- a/src/gui/window-manager.cpp +++ b/src/gui/window-manager.cpp @@ -92,7 +92,12 @@ WindowManager::register_stock_items() add_stock_icon_set(factory, "panel-viewer", "panel_viewer", _("_Viewer")); add_stock_icon_set(factory, "tool-arrow", "tool_arrow", _("_Arrow")); - add_stock_icon_set(factory, "tool-i-beam", "tool_i_beam", _("_I-Beam")); + add_stock_icon_set(factory, "tool-i-beam", "tool_i_beam", _("_I-Beam")); + + add_stock_icon_set(factory, "track-disabled", "track_disabled", _("Track Disabled")); + add_stock_icon_set(factory, "track-enabled", "track_enabled", _("Track Enabled")); + add_stock_icon_set(factory, "track-locked", "track_locked", _("Track Locked")); + add_stock_icon_set(factory, "track-unlocked", "track_unlocked", _("Track Unlocked")); factory->add_default(); //Add factory to list of factories. }