From b48d8fc49b6534a5c938c7e1722b5bb7fb8812df Mon Sep 17 00:00:00 2001 From: Joel Holdsworth Date: Mon, 5 Jan 2009 20:03:52 +0000 Subject: [PATCH] Tidied up, simplified and documented expand animation code --- .../timeline/timeline-layout-helper.cpp | 24 +++--- src/gui/widgets/timeline/timeline-track.cpp | 81 +++++++++--------- src/gui/widgets/timeline/timeline-track.hpp | 84 +++++++++++++++++-- 3 files changed, 130 insertions(+), 59 deletions(-) diff --git a/src/gui/widgets/timeline/timeline-layout-helper.cpp b/src/gui/widgets/timeline/timeline-layout-helper.cpp index 75974cc6c..4ee0824e9 100644 --- a/src/gui/widgets/timeline/timeline-layout-helper.cpp +++ b/src/gui/widgets/timeline/timeline-layout-helper.cpp @@ -185,12 +185,6 @@ TimelineLayoutHelper::layout_headers_recursive( shared_ptr timeline_track = lookup_timeline_track(model_track); - // Is the track animating? - const int track_animation_state = - timeline_track->get_expand_animation_state(); - if(track_animation_state != Track::NoAnimationState) - is_animating = true; - // Is the track going to be shown? if(parent_expanded) { @@ -207,6 +201,11 @@ TimelineLayoutHelper::layout_headers_recursive( // Offset for the next header child_offset += track_height + TimelineWidget::TrackPadding; } + + // Is the track animating? + const bool is_track_animating = + timeline_track->is_expand_animating(); + is_animating |= is_track_animating; // Recurse to children const bool expand_child = @@ -218,15 +217,11 @@ TimelineLayoutHelper::layout_headers_recursive( header_width, indent_width, depth + 1, expand_child); // Do collapse animation as necessary - if(track_animation_state != Track::NoAnimationState) - { - // Tick the track expand animation - timeline_track->tick_expand_animation(); - + if(is_track_animating) + { // Calculate the height of te area which will be // shown as expanded - const float a = ((float)track_animation_state / - (float)Track::MaxExpandAnimation); + const float a = timeline_track->get_expand_animation_state(); child_branch_height *= a * a; const int y_limit = branch_offset + child_offset + child_branch_height; @@ -248,6 +243,9 @@ TimelineLayoutHelper::layout_headers_recursive( if(rect.get_y() + rect.get_height() > y_limit) headerBoxes.erase(track); } + + // Tick the track expand animation + timeline_track->tick_expand_animation(); } child_offset += child_branch_height; diff --git a/src/gui/widgets/timeline/timeline-track.cpp b/src/gui/widgets/timeline/timeline-track.cpp index be692f296..7b1f526d5 100644 --- a/src/gui/widgets/timeline/timeline-track.cpp +++ b/src/gui/widgets/timeline/timeline-track.cpp @@ -36,26 +36,19 @@ namespace gui { namespace widgets { namespace timeline { -const int Track::NoAnimationState = -1; -const int Track::MaxExpandAnimation = 65536; -const double Track::ExpandAnimationPeriod = 0.15; - -Glib::Timer Track::timer; +const float Track::ExpandAnimationPeriod = 0.15; Track::Track(TimelineWidget &timeline_widget, shared_ptr track) : timelineWidget(timeline_widget), model_track(track), expanded(true), - expandAnimationState(Track::NoAnimationState), + expandDirection(None), enableButton(Gtk::StockID("track_enabled")), lockButton(Gtk::StockID("track_unlocked")) { REQUIRE(model_track); - // Ensure that the timer is running - timer.start(); - titleMenuButton.set_relief(RELIEF_HALF); buttonBar.append(enableButton); @@ -121,71 +114,81 @@ Track::get_expanded() const void Track::expand_collapse(ExpandDirection direction) { + REQUIRE(direction != None); + expandDirection = direction; if(direction == Expand) { expanded = true; - expandAnimationState = 0; + expandAnimationState = 0.0; } else { expanded = false; - expandAnimationState = MaxExpandAnimation; + expandAnimationState = 1.0; } - - lastTickTime = timer.elapsed(); + + // Create a timer if we don't already have one + if(!expand_timer) + { + expand_timer.reset(new Glib::Timer()); + expand_timer->start(); + } + else // Reset the timer if we do + expand_timer->reset(); } -int +float Track::get_expand_animation_state() const { - ENSURE((expandAnimationState >= 0 && - expandAnimationState <= MaxExpandAnimation) || - expandAnimationState == NoAnimationState); + ENSURE(expandAnimationState >= 0.0 && + expandAnimationState <= 1.0); return expandAnimationState; } + +bool +Track::is_expand_animating() const +{ + return expandDirection != None; +} void Track::tick_expand_animation() { - if(expandAnimationState <= NoAnimationState) - { - WARN(gui, "tick_expand_animation() was called when" - " expandAnimationState was set to NoAnimationState"); - return; - } - - const double delta = MaxExpandAnimation * (timer.elapsed() - lastTickTime) / ExpandAnimationPeriod; + REQUIRE(expandDirection != None); // tick_expand_animation should not + // be unless is_expand_animating + // returns true + REQUIRE(expand_timer); + const float delta = + (float)expand_timer->elapsed() / ExpandAnimationPeriod; + expand_timer->reset(); // reset the timer to t=0 if(expandDirection == Expand) { expandAnimationState += delta; - if(expandAnimationState >= MaxExpandAnimation) - expandAnimationState = NoAnimationState; + if(expandAnimationState >= 1.0) + expandDirection = None; } else { expandAnimationState -= delta; - if(expandAnimationState <= 0) - expandAnimationState = NoAnimationState; + if(expandAnimationState <= 0.0) + expandDirection = None; } - lastTickTime = timer.elapsed(); - - ENSURE((expandAnimationState >= 0 && - expandAnimationState <= MaxExpandAnimation) || - expandAnimationState == NoAnimationState); + if(expandDirection == None) + expand_timer.reset(); // We've finished with the timer - delete it } Gtk::ExpanderStyle Track::get_expander_style() const { - const int notch = Track::MaxExpandAnimation / 3; + const int notch = 1.0 / 3.0; if(expanded) { - if(expandAnimationState == Track::NoAnimationState) + if(expandDirection == None) return EXPANDER_EXPANDED; - else if(expandAnimationState >= notch * 2) + else if(expandAnimationState >= notch * 2.0) return EXPANDER_SEMI_EXPANDED; else if(expandAnimationState >= notch) return EXPANDER_SEMI_COLLAPSED; @@ -194,11 +197,11 @@ Track::get_expander_style() const } else { - if(expandAnimationState == Track::NoAnimationState) + if(expandDirection == None) return EXPANDER_COLLAPSED; else if(expandAnimationState <= notch) return EXPANDER_SEMI_COLLAPSED; - else if(expandAnimationState <= notch * 2) + else if(expandAnimationState <= notch * 2.0) return EXPANDER_SEMI_EXPANDED; else return EXPANDER_EXPANDED; diff --git a/src/gui/widgets/timeline/timeline-track.hpp b/src/gui/widgets/timeline/timeline-track.hpp index 8c20d9c26..385001da3 100644 --- a/src/gui/widgets/timeline/timeline-track.hpp +++ b/src/gui/widgets/timeline/timeline-track.hpp @@ -37,12 +37,23 @@ namespace timeline { class TimelineViewWindow; +/** + * Timeline tracks are created by the timeline widget to correspond to + * model tracks. Timeline tracks are used to store UI specific state + * data. + **/ class Track : public sigc::trackable { public: + /** + * An enum used by the branch expand/collapse animation. + * ExpandDirection represents whether the branch us being expanded or + * collapsed, or neither. + **/ enum ExpandDirection { + None, Expand, Collapse }; @@ -57,15 +68,48 @@ public: int get_height() const; + /** + * Gets whether the descendant tracks are expanded or collapsed. + * @return Returns true if the branch is expanded, false if it's + * collapsed. + * @see expand_collapse + **/ bool get_expanded() const; + /** + * Expands or collapses this branch. + * @param direction Specifies whether this branch should be expanded + * or collapse. direction must not equal None + **/ void expand_collapse(ExpandDirection direction); - // -1 for no animation - int get_expand_animation_state() const; + /** + * The current expand state. + * @return Returns the expand state value, this value is a number + * between 0 and 1.0, and is recalculated by tick_expand_animation(). + * @remarks A value of 1.0 is given when the branch is fully expanded + * (and animating), 0.0 is given when the branch is fully collapsed + * (and animating). When the branch is not animating this value has + * an indeterminate value. + * @see tick_expand_animation + **/ + float get_expand_animation_state() const; + /** + * Gets whether the branch is animation. + * @return Returns true if the branch is animating, false if not. + **/ + bool is_expand_animating() const; + + /** + * When this track is being animated, tick_expand_animation must be + * called repeatedly to cause the animation to progress. + **/ void tick_expand_animation(); + /** + * Calculates the expander style, given the animation state. + **/ Gtk::ExpanderStyle get_expander_style() const; void show_header_context_menu(guint button, guint32 time); @@ -75,9 +119,12 @@ public: const = 0; public: - static const int NoAnimationState; - static const int MaxExpandAnimation; - static const double ExpandAnimationPeriod; + //----- Constants -----// + + /** + * Specifies the period of the expand animation in seconds. + **/ + static const float ExpandAnimationPeriod; private: //----- Internals -----// @@ -96,13 +143,36 @@ protected: boost::shared_ptr model_track; private: + + /** + * This bool is true if this branch is expanded. false if it is + * collapsed. + **/ bool expanded; + /** + * This enum specifies which direction the expand/collapse animation + * is moving - if any. + * @remarks If no animation is occuring, expandDirection is set to + * None. + **/ ExpandDirection expandDirection; + + /** + * The current expand state. + * @remarks This value is a number between 0 and 1.0, + * and is recalculated by tick_expand_animation(). This variable is + * set to 1.0 when the branch is fully expanded (and animating) and + * 0.0 when the branch is fully collapsed (and animating). When the + * branch is not animating this value has an indeterminate value. + * @see tick_expand_animation + **/ double expandAnimationState; - static Glib::Timer timer; - double lastTickTime; + /** + * An internal timer used for the expand/collapse animation. + **/ + boost::scoped_ptr expand_timer; //----- Header Widgets ------//