Tidied up, simplified and documented expand animation code

This commit is contained in:
Joel Holdsworth 2009-01-05 20:03:52 +00:00
parent 22c9e8b082
commit b48d8fc49b
3 changed files with 130 additions and 59 deletions

View file

@ -185,12 +185,6 @@ TimelineLayoutHelper::layout_headers_recursive(
shared_ptr<timeline::Track> timeline_track = shared_ptr<timeline::Track> timeline_track =
lookup_timeline_track(model_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? // Is the track going to be shown?
if(parent_expanded) if(parent_expanded)
{ {
@ -207,6 +201,11 @@ TimelineLayoutHelper::layout_headers_recursive(
// Offset for the next header // Offset for the next header
child_offset += track_height + TimelineWidget::TrackPadding; 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 // Recurse to children
const bool expand_child = const bool expand_child =
@ -218,15 +217,11 @@ TimelineLayoutHelper::layout_headers_recursive(
header_width, indent_width, depth + 1, expand_child); header_width, indent_width, depth + 1, expand_child);
// Do collapse animation as necessary // Do collapse animation as necessary
if(track_animation_state != Track::NoAnimationState) if(is_track_animating)
{ {
// Tick the track expand animation
timeline_track->tick_expand_animation();
// Calculate the height of te area which will be // Calculate the height of te area which will be
// shown as expanded // shown as expanded
const float a = ((float)track_animation_state / const float a = timeline_track->get_expand_animation_state();
(float)Track::MaxExpandAnimation);
child_branch_height *= a * a; child_branch_height *= a * a;
const int y_limit = const int y_limit =
branch_offset + child_offset + child_branch_height; branch_offset + child_offset + child_branch_height;
@ -248,6 +243,9 @@ TimelineLayoutHelper::layout_headers_recursive(
if(rect.get_y() + rect.get_height() > y_limit) if(rect.get_y() + rect.get_height() > y_limit)
headerBoxes.erase(track); headerBoxes.erase(track);
} }
// Tick the track expand animation
timeline_track->tick_expand_animation();
} }
child_offset += child_branch_height; child_offset += child_branch_height;

View file

@ -36,26 +36,19 @@ namespace gui {
namespace widgets { namespace widgets {
namespace timeline { namespace timeline {
const int Track::NoAnimationState = -1; const float Track::ExpandAnimationPeriod = 0.15;
const int Track::MaxExpandAnimation = 65536;
const double Track::ExpandAnimationPeriod = 0.15;
Glib::Timer Track::timer;
Track::Track(TimelineWidget &timeline_widget, Track::Track(TimelineWidget &timeline_widget,
shared_ptr<model::Track> track) : shared_ptr<model::Track> track) :
timelineWidget(timeline_widget), timelineWidget(timeline_widget),
model_track(track), model_track(track),
expanded(true), expanded(true),
expandAnimationState(Track::NoAnimationState), expandDirection(None),
enableButton(Gtk::StockID("track_enabled")), enableButton(Gtk::StockID("track_enabled")),
lockButton(Gtk::StockID("track_unlocked")) lockButton(Gtk::StockID("track_unlocked"))
{ {
REQUIRE(model_track); REQUIRE(model_track);
// Ensure that the timer is running
timer.start();
titleMenuButton.set_relief(RELIEF_HALF); titleMenuButton.set_relief(RELIEF_HALF);
buttonBar.append(enableButton); buttonBar.append(enableButton);
@ -121,71 +114,81 @@ Track::get_expanded() const
void void
Track::expand_collapse(ExpandDirection direction) Track::expand_collapse(ExpandDirection direction)
{ {
REQUIRE(direction != None);
expandDirection = direction; expandDirection = direction;
if(direction == Expand) if(direction == Expand)
{ {
expanded = true; expanded = true;
expandAnimationState = 0; expandAnimationState = 0.0;
} }
else else
{ {
expanded = false; 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 Track::get_expand_animation_state() const
{ {
ENSURE((expandAnimationState >= 0 && ENSURE(expandAnimationState >= 0.0 &&
expandAnimationState <= MaxExpandAnimation) || expandAnimationState <= 1.0);
expandAnimationState == NoAnimationState);
return expandAnimationState; return expandAnimationState;
} }
bool
Track::is_expand_animating() const
{
return expandDirection != None;
}
void void
Track::tick_expand_animation() Track::tick_expand_animation()
{ {
if(expandAnimationState <= NoAnimationState) REQUIRE(expandDirection != None); // tick_expand_animation should not
{ // be unless is_expand_animating
WARN(gui, "tick_expand_animation() was called when" // returns true
" expandAnimationState was set to NoAnimationState"); REQUIRE(expand_timer);
return; const float delta =
} (float)expand_timer->elapsed() / ExpandAnimationPeriod;
expand_timer->reset(); // reset the timer to t=0
const double delta = MaxExpandAnimation * (timer.elapsed() - lastTickTime) / ExpandAnimationPeriod;
if(expandDirection == Expand) if(expandDirection == Expand)
{ {
expandAnimationState += delta; expandAnimationState += delta;
if(expandAnimationState >= MaxExpandAnimation) if(expandAnimationState >= 1.0)
expandAnimationState = NoAnimationState; expandDirection = None;
} }
else else
{ {
expandAnimationState -= delta; expandAnimationState -= delta;
if(expandAnimationState <= 0) if(expandAnimationState <= 0.0)
expandAnimationState = NoAnimationState; expandDirection = None;
} }
lastTickTime = timer.elapsed(); if(expandDirection == None)
expand_timer.reset(); // We've finished with the timer - delete it
ENSURE((expandAnimationState >= 0 &&
expandAnimationState <= MaxExpandAnimation) ||
expandAnimationState == NoAnimationState);
} }
Gtk::ExpanderStyle Gtk::ExpanderStyle
Track::get_expander_style() const Track::get_expander_style() const
{ {
const int notch = Track::MaxExpandAnimation / 3; const int notch = 1.0 / 3.0;
if(expanded) if(expanded)
{ {
if(expandAnimationState == Track::NoAnimationState) if(expandDirection == None)
return EXPANDER_EXPANDED; return EXPANDER_EXPANDED;
else if(expandAnimationState >= notch * 2) else if(expandAnimationState >= notch * 2.0)
return EXPANDER_SEMI_EXPANDED; return EXPANDER_SEMI_EXPANDED;
else if(expandAnimationState >= notch) else if(expandAnimationState >= notch)
return EXPANDER_SEMI_COLLAPSED; return EXPANDER_SEMI_COLLAPSED;
@ -194,11 +197,11 @@ Track::get_expander_style() const
} }
else else
{ {
if(expandAnimationState == Track::NoAnimationState) if(expandDirection == None)
return EXPANDER_COLLAPSED; return EXPANDER_COLLAPSED;
else if(expandAnimationState <= notch) else if(expandAnimationState <= notch)
return EXPANDER_SEMI_COLLAPSED; return EXPANDER_SEMI_COLLAPSED;
else if(expandAnimationState <= notch * 2) else if(expandAnimationState <= notch * 2.0)
return EXPANDER_SEMI_EXPANDED; return EXPANDER_SEMI_EXPANDED;
else else
return EXPANDER_EXPANDED; return EXPANDER_EXPANDED;

View file

@ -37,12 +37,23 @@ namespace timeline {
class TimelineViewWindow; 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 class Track : public sigc::trackable
{ {
public: public:
/**
* An enum used by the branch expand/collapse animation.
* ExpandDirection represents whether the branch us being expanded or
* collapsed, or neither.
**/
enum ExpandDirection enum ExpandDirection
{ {
None,
Expand, Expand,
Collapse Collapse
}; };
@ -57,15 +68,48 @@ public:
int get_height() const; 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; 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); 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(); void tick_expand_animation();
/**
* Calculates the expander style, given the animation state.
**/
Gtk::ExpanderStyle get_expander_style() const; Gtk::ExpanderStyle get_expander_style() const;
void show_header_context_menu(guint button, guint32 time); void show_header_context_menu(guint button, guint32 time);
@ -75,9 +119,12 @@ public:
const = 0; const = 0;
public: public:
static const int NoAnimationState; //----- Constants -----//
static const int MaxExpandAnimation;
static const double ExpandAnimationPeriod; /**
* Specifies the period of the expand animation in seconds.
**/
static const float ExpandAnimationPeriod;
private: private:
//----- Internals -----// //----- Internals -----//
@ -96,13 +143,36 @@ protected:
boost::shared_ptr<model::Track> model_track; boost::shared_ptr<model::Track> model_track;
private: private:
/**
* This bool is true if this branch is expanded. false if it is
* collapsed.
**/
bool expanded; 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; 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; double expandAnimationState;
static Glib::Timer timer; /**
double lastTickTime; * An internal timer used for the expand/collapse animation.
**/
boost::scoped_ptr<Glib::Timer> expand_timer;
//----- Header Widgets ------// //----- Header Widgets ------//