If starting a second animation of the same type then cancel the first one

0.8
Bruno Van de Velde 2015-12-26 16:56:21 +01:00
parent 5a2c27d8e9
commit dea305b324
4 changed files with 182 additions and 81 deletions

View File

@ -56,13 +56,17 @@ namespace tgui
public:
enum class Type
{
None,
Move,
Fade,
Scale
None = 0,
Move = 1,
Resize = 2,
Fade = 4
};
bool update(sf::Time elapsedTime);
Type getType() const;
virtual bool update(sf::Time elapsedTime) = 0;
virtual void finish();
protected:
Type m_type = Type::None;
@ -71,15 +75,6 @@ namespace tgui
sf::Time m_totalDuration;
sf::Time m_elapsedTime;
sf::Vector2f m_startPos;
sf::Vector2f m_endPos;
sf::Vector2f m_startSize;
sf::Vector2f m_endSize;
float m_startOpacity;
float m_endOpacity;
std::function<void()> m_finishedCallback;
friend class tgui::Widget;
@ -87,26 +82,50 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class TGUI_API FadeAnimation : public Animation
{
public:
FadeAnimation(Widget::Ptr widget, float start, float end, sf::Time duration, std::function<void()> finishedCallback = nullptr);
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class TGUI_API MoveAnimation : public Animation
{
public:
MoveAnimation(Widget::Ptr widget, sf::Vector2f start, sf::Vector2f end, sf::Time duration, std::function<void()> finishedCallback = nullptr);
virtual bool update(sf::Time elapsedTime) override;
virtual void finish() override;
private:
sf::Vector2f m_startPos;
sf::Vector2f m_endPos;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class TGUI_API ScaleAnimation : public Animation
class TGUI_API ResizeAnimation : public Animation
{
public:
ScaleAnimation(Widget::Ptr widget, sf::Vector2f startPos, sf::Vector2f endPos, sf::Vector2f startSize, sf::Vector2f endSize, sf::Time duration, std::function<void()> finishedCallback = nullptr);
ResizeAnimation(Widget::Ptr widget, sf::Vector2f start, sf::Vector2f end, sf::Time duration, std::function<void()> finishedCallback = nullptr);
virtual bool update(sf::Time elapsedTime) override;
virtual void finish() override;
private:
sf::Vector2f m_startSize;
sf::Vector2f m_endSize;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class TGUI_API FadeAnimation : public Animation
{
public:
FadeAnimation(Widget::Ptr widget, float start, float end, sf::Time duration, std::function<void()> finishedCallback = nullptr);
virtual bool update(sf::Time elapsedTime) override;
virtual void finish() override;
private:
float m_startOpacity;
float m_endOpacity;
};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -33,43 +33,17 @@ namespace tgui
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Animation::update(sf::Time elapsedTime)
Animation::Type Animation::getType() const
{
m_elapsedTime += elapsedTime;
if (m_elapsedTime > m_totalDuration)
m_elapsedTime = m_totalDuration;
if (m_type == Type::Fade)
m_widget->setOpacity(m_startOpacity + ((m_elapsedTime.asSeconds() / m_totalDuration.asSeconds()) * (m_endOpacity - m_startOpacity)));
else if (m_type == Type::Move)
m_widget->setPosition(m_startPos + ((m_elapsedTime.asSeconds() / m_totalDuration.asSeconds()) * (m_endPos - m_startPos)));
else if (m_type == Type::Scale)
{
m_widget->setPosition(m_startPos + ((m_elapsedTime.asSeconds() / m_totalDuration.asSeconds()) * (m_endPos - m_startPos)));
m_widget->setSize(m_startSize + ((m_elapsedTime.asSeconds() / m_totalDuration.asSeconds()) * (m_endSize - m_startSize)));
}
if (m_elapsedTime == m_totalDuration)
{
if (m_finishedCallback != nullptr)
m_finishedCallback();
return true;
}
return false;
return m_type;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FadeAnimation::FadeAnimation(Widget::Ptr widget, float start, float end, sf::Time duration, std::function<void()> finishedCallback)
void Animation::finish()
{
m_type = Type::Fade;
m_widget = widget;
m_startOpacity = std::max(0.f, std::min(1.f, start));
m_endOpacity = std::max(0.f, std::min(1.f, end));
m_totalDuration = duration;
m_finishedCallback = finishedCallback;
if (m_finishedCallback != nullptr)
m_finishedCallback();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -86,19 +60,98 @@ namespace tgui
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ScaleAnimation::ScaleAnimation(Widget::Ptr widget, sf::Vector2f startPos, sf::Vector2f endPos, sf::Vector2f startSize, sf::Vector2f endSize, sf::Time duration, std::function<void()> finishedCallback)
bool MoveAnimation::update(sf::Time elapsedTime)
{
m_type = Type::Scale;
m_elapsedTime += elapsedTime;
if (m_elapsedTime >= m_totalDuration)
{
finish();
return true;
}
m_widget->setPosition(m_startPos + ((m_elapsedTime.asSeconds() / m_totalDuration.asSeconds()) * (m_endPos - m_startPos)));
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void MoveAnimation::finish()
{
m_widget->setPosition(m_endPos);
Animation::finish();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ResizeAnimation::ResizeAnimation(Widget::Ptr widget, sf::Vector2f start, sf::Vector2f end, sf::Time duration, std::function<void()> finishedCallback)
{
m_type = Type::Resize;
m_widget = widget;
m_startPos = startPos;
m_endPos = endPos;
m_startSize = startSize;
m_endSize = endSize;
m_startSize = start;
m_endSize = end;
m_totalDuration = duration;
m_finishedCallback = finishedCallback;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ResizeAnimation::update(sf::Time elapsedTime)
{
m_elapsedTime += elapsedTime;
if (m_elapsedTime >= m_totalDuration)
{
finish();
return true;
}
m_widget->setSize(m_startSize + ((m_elapsedTime.asSeconds() / m_totalDuration.asSeconds()) * (m_endSize - m_startSize)));
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ResizeAnimation::finish()
{
m_widget->setSize(m_endSize);
Animation::finish();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FadeAnimation::FadeAnimation(Widget::Ptr widget, float start, float end, sf::Time duration, std::function<void()> finishedCallback)
{
m_type = Type::Fade;
m_widget = widget;
m_startOpacity = std::max(0.f, std::min(1.f, start));
m_endOpacity = std::max(0.f, std::min(1.f, end));
m_totalDuration = duration;
m_finishedCallback = finishedCallback;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool FadeAnimation::update(sf::Time elapsedTime)
{
m_elapsedTime += elapsedTime;
if (m_elapsedTime >= m_totalDuration)
{
finish();
return true;
}
m_widget->setOpacity(m_startOpacity + ((m_elapsedTime.asSeconds() / m_totalDuration.asSeconds()) * (m_endOpacity - m_startOpacity)));
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void FadeAnimation::finish()
{
m_widget->setOpacity(m_endOpacity);
Animation::finish();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -32,6 +32,31 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace
{
void addAnimation(std::vector<std::shared_ptr<tgui::priv::Animation>>& existingAnimations, std::shared_ptr<tgui::priv::Animation> newAnimation)
{
auto type = newAnimation->getType();
// If another animation is already running with the same type then instantly finish it
unsigned int i = 0;
while (i < existingAnimations.size())
{
if (existingAnimations[i]->getType() == type)
{
existingAnimations[i]->finish();
existingAnimations.erase(existingAnimations.begin() + i);
}
else
++i;
}
existingAnimations.push_back(newAnimation);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace tgui
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -204,50 +229,51 @@ namespace tgui
{
case ShowAnimationType::Fade:
{
m_showAnimations.push_back(std::make_shared<priv::FadeAnimation>(shared_from_this(), 0.f, getOpacity(), duration));
addAnimation(m_showAnimations, std::make_shared<priv::FadeAnimation>(shared_from_this(), 0.f, getOpacity(), duration));
setOpacity(0);
break;
}
case ShowAnimationType::Scale:
{
m_showAnimations.push_back(std::make_shared<priv::ScaleAnimation>(shared_from_this(), getPosition() + (getSize() / 2.f), getPosition(), sf::Vector2f{0, 0}, getSize(), duration));
addAnimation(m_showAnimations, std::make_shared<priv::MoveAnimation>(shared_from_this(), getPosition() + (getSize() / 2.f), getPosition(), duration));
addAnimation(m_showAnimations, std::make_shared<priv::ResizeAnimation>(shared_from_this(), sf::Vector2f{0, 0}, getSize(), duration));
setPosition(getPosition() + (getSize() / 2.f));
setSize(0, 0);
break;
}
case ShowAnimationType::SlideToRight:
case ShowAnimationType::SlideFromLeft:
{
m_showAnimations.push_back(std::make_shared<priv::MoveAnimation>(shared_from_this(), sf::Vector2f{-getFullSize().x, getPosition().y}, getPosition(), duration));
addAnimation(m_showAnimations, std::make_shared<priv::MoveAnimation>(shared_from_this(), sf::Vector2f{-getFullSize().x, getPosition().y}, getPosition(), duration));
setPosition({-getFullSize().x, getPosition().y});
break;
}
case ShowAnimationType::SlideToLeft:
case ShowAnimationType::SlideFromRight:
{
if (getParent())
{
m_showAnimations.push_back(std::make_shared<priv::MoveAnimation>(shared_from_this(), sf::Vector2f{getParent()->getSize().x + getWidgetOffset().x, getPosition().y}, getPosition(), duration));
addAnimation(m_showAnimations, std::make_shared<priv::MoveAnimation>(shared_from_this(), sf::Vector2f{getParent()->getSize().x + getWidgetOffset().x, getPosition().y}, getPosition(), duration));
setPosition({getParent()->getSize().x + getWidgetOffset().x, getPosition().y});
}
else
sf::err() << "TGUI Warning: showWithEffect(SlideToLeft) does not work before widget has a parent." << std::endl;
sf::err() << "TGUI Warning: showWithEffect(SlideFromRight) does not work before widget has a parent." << std::endl;
break;
}
case ShowAnimationType::SlideToBottom:
case ShowAnimationType::SlideFromTop:
{
m_showAnimations.push_back(std::make_shared<priv::MoveAnimation>(shared_from_this(), sf::Vector2f{getPosition().x, -getFullSize().y}, getPosition(), duration));
addAnimation(m_showAnimations, std::make_shared<priv::MoveAnimation>(shared_from_this(), sf::Vector2f{getPosition().x, -getFullSize().y}, getPosition(), duration));
setPosition({getPosition().x, -getFullSize().y});
break;
}
case ShowAnimationType::SlideToTop:
case ShowAnimationType::SlideFromBottom:
{
if (getParent())
{
m_showAnimations.push_back(std::make_shared<priv::MoveAnimation>(shared_from_this(), sf::Vector2f{getPosition().x, getParent()->getSize().y + getWidgetOffset().y}, getPosition(), duration));
addAnimation(m_showAnimations, std::make_shared<priv::MoveAnimation>(shared_from_this(), sf::Vector2f{getPosition().x, getParent()->getSize().y + getWidgetOffset().y}, getPosition(), duration));
setPosition({getPosition().x, getParent()->getSize().y + getWidgetOffset().y});
}
else
sf::err() << "TGUI Warning: showWithEffect(SlideToTop) does not work before widget has a parent." << std::endl;
sf::err() << "TGUI Warning: showWithEffect(SlideFromBottom) does not work before widget has a parent." << std::endl;
break;
}
@ -276,40 +302,41 @@ namespace tgui
{
case ShowAnimationType::Fade:
{
m_showAnimations.push_back(std::make_shared<priv::FadeAnimation>(shared_from_this(), opacity, 0.f, duration, [=](){ hide(); setOpacity(opacity); }));
addAnimation(m_showAnimations, std::make_shared<priv::FadeAnimation>(shared_from_this(), opacity, 0.f, duration, [=](){ hide(); setOpacity(opacity); }));
break;
}
case ShowAnimationType::Scale:
{
m_showAnimations.push_back(std::make_shared<priv::ScaleAnimation>(shared_from_this(), position, position + (size / 2.f), size, sf::Vector2f{0, 0}, duration, [=](){ hide(); setPosition(position); setSize(size); }));
addAnimation(m_showAnimations, std::make_shared<priv::MoveAnimation>(shared_from_this(), position, position + (size / 2.f), duration, [=](){ hide(); setPosition(position); setSize(size); }));
addAnimation(m_showAnimations, std::make_shared<priv::ResizeAnimation>(shared_from_this(), size, sf::Vector2f{0, 0}, duration, [=](){ hide(); setPosition(position); setSize(size); }));
break;
}
case ShowAnimationType::SlideToRight:
{
if (getParent())
m_showAnimations.push_back(std::make_shared<priv::MoveAnimation>(shared_from_this(), position, sf::Vector2f{getParent()->getSize().x + getWidgetOffset().x, position.y}, duration, [=](){ hide(); setPosition(position); }));
addAnimation(m_showAnimations, std::make_shared<priv::MoveAnimation>(shared_from_this(), position, sf::Vector2f{getParent()->getSize().x + getWidgetOffset().x, position.y}, duration, [=](){ hide(); setPosition(position); }));
else
sf::err() << "TGUI Warning: showWithEffect(SlideToRight) does not work before widget has a parent." << std::endl;
sf::err() << "TGUI Warning: hideWithEffect(SlideToRight) does not work before widget has a parent." << std::endl;
break;
}
case ShowAnimationType::SlideToLeft:
{
m_showAnimations.push_back(std::make_shared<priv::MoveAnimation>(shared_from_this(), position, sf::Vector2f{-getFullSize().x, position.y}, duration, [=](){ hide(); setPosition(position); }));
addAnimation(m_showAnimations, std::make_shared<priv::MoveAnimation>(shared_from_this(), position, sf::Vector2f{-getFullSize().x, position.y}, duration, [=](){ hide(); setPosition(position); }));
break;
}
case ShowAnimationType::SlideToBottom:
{
if (getParent())
m_showAnimations.push_back(std::make_shared<priv::MoveAnimation>(shared_from_this(), position, sf::Vector2f{position.x, getParent()->getSize().y + getWidgetOffset().y}, duration, [=](){ hide(); setPosition(position); }));
addAnimation(m_showAnimations, std::make_shared<priv::MoveAnimation>(shared_from_this(), position, sf::Vector2f{position.x, getParent()->getSize().y + getWidgetOffset().y}, duration, [=](){ hide(); setPosition(position); }));
else
sf::err() << "TGUI Warning: showWithEffect(SlideToBottom) does not work before widget has a parent." << std::endl;
sf::err() << "TGUI Warning: hideWithEffect(SlideToBottom) does not work before widget has a parent." << std::endl;
break;
}
case ShowAnimationType::SlideToTop:
{
m_showAnimations.push_back(std::make_shared<priv::MoveAnimation>(shared_from_this(), position, sf::Vector2f{position.x, -getFullSize().y}, duration, [=](){ hide(); setPosition(position); }));
addAnimation(m_showAnimations, std::make_shared<priv::MoveAnimation>(shared_from_this(), position, sf::Vector2f{position.x, -getFullSize().y}, duration, [=](){ hide(); setPosition(position); }));
break;
}
}

View File

@ -196,5 +196,7 @@ TEST_CASE("[Animation]") {
REQUIRE(widget->getOpacity() == 0.9f);
REQUIRE(!widget->isVisible());
}
// TODO: Add tests for simultaneous animations (tests for both same type and different types)
}
}