Move app::Tabs animation related stuff to app::AnimatedWidget

This commit is contained in:
David Capello 2015-03-27 18:35:42 -03:00
parent 2cfef9e250
commit 47948ee888
3 changed files with 115 additions and 55 deletions

View File

@ -0,0 +1,84 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
#ifndef APP_UI_ANIMATED_WIDGET_H_INCLUDED
#define APP_UI_ANIMATED_WIDGET_H_INCLUDED
#pragma once
#include "base/connection.h"
#include "ui/timer.h"
namespace app {
class AnimatedWidget {
public:
AnimatedWidget()
: m_timer(1000/60)
, m_animation(0)
{
m_scopedConn = m_timer.Tick.connect(&AnimatedWidget::onTick, this);
}
~AnimatedWidget() {
m_timer.stop();
}
// For each animation frame
virtual void onAnimationStart() { }
virtual void onAnimationStop() { }
virtual void onAnimationFrame() { }
protected:
void startAnimation(int animation, int lifespan) {
// Stop previous animation
if (m_animation)
stopAnimation();
m_animation = animation;
m_animationTime = 0;
m_animationLifespan = lifespan;
m_timer.start();
onAnimationStart();
}
void stopAnimation() {
m_animation = 0;
m_timer.stop();
onAnimationStop();
}
int animation() const {
return m_animation;
}
double animationTime() const {
return double(m_animationTime) / double(m_animationLifespan);
}
private:
void onTick() {
if (m_animation) {
if (m_animationTime == m_animationLifespan)
stopAnimation();
else
++m_animationTime;
onAnimationFrame();
}
}
ui::Timer m_timer;
int m_animation;
int m_animationTime;
int m_animationLifespan;
ScopedConnection m_scopedConn;
};
} // namespace app
#endif

View File

@ -61,8 +61,6 @@ Tabs::Tabs(TabsDelegate* delegate)
, m_clickedCloseButton(false)
, m_selected(nullptr)
, m_delegate(delegate)
, m_timer(1000/60, this)
, m_ani(ANI_NONE)
, m_removedTab(nullptr)
, m_isDragging(false)
, m_floatingTab(nullptr)
@ -80,7 +78,7 @@ Tabs::~Tabs()
}
// Stop animation
stopAni();
stopAnimation();
// Remove all tabs
for (Tab* tab : m_list)
@ -91,7 +89,7 @@ Tabs::~Tabs()
void Tabs::addTab(TabView* tabView, int pos)
{
resetOldPositions();
startAni(ANI_ADDING_TAB, ANI_ADDING_TAB_TICKS);
startAnimation(ANI_ADDING_TAB, ANI_ADDING_TAB_TICKS);
Tab* tab = new Tab(tabView);
if (pos < 0)
@ -137,7 +135,7 @@ void Tabs::removeTab(TabView* tabView)
tab->view = nullptr; // The view will be destroyed after Tabs::removeTab() anyway
resetOldPositions();
startAni(ANI_REMOVING_TAB, ANI_REMOVING_TAB_TICKS);
startAnimation(ANI_REMOVING_TAB, ANI_REMOVING_TAB_TICKS);
updateTabs();
}
@ -270,9 +268,9 @@ bool Tabs::onProcessMessage(Message* msg)
m_list.insert(m_list.begin()+i, m_selected);
m_dragTabIndex = i;
resetOldPositions(double(m_ani_t) / double(m_ani_T));
resetOldPositions(animationTime());
updateTabs();
startAni(ANI_REORDER_TABS, ANI_REORDER_TABS_TICKS);
startAnimation(ANI_REORDER_TABS, ANI_REORDER_TABS_TICKS);
}
if (justDocked)
@ -367,18 +365,6 @@ bool Tabs::onProcessMessage(Message* msg)
return true;
}
case kTimerMessage: {
if (m_ani != ANI_NONE) {
if (m_ani_t == m_ani_T)
stopAni();
else
++m_ani_t;
invalidate();
}
break;
}
}
return Widget::onProcessMessage(msg);
@ -390,7 +376,7 @@ void Tabs::onPaint(PaintEvent& ev)
Graphics* g = ev.getGraphics();
gfx::Rect rect = getClientBounds();
gfx::Rect box(rect.x, rect.y, rect.w,
(m_list.empty() && m_ani == ANI_NONE ? 0:
(m_list.empty() && animation() == ANI_NONE ? 0:
theme->dimensions.tabsHeight() - theme->dimensions.tabsEmptyHeight()));
g->fillRect(theme->colors.windowFace(), g->getClipBounds());
@ -410,7 +396,7 @@ void Tabs::onPaint(PaintEvent& ev)
}
// Draw deleted tab
if (m_ani == ANI_REMOVING_TAB && m_removedTab) {
if (animation() == ANI_REMOVING_TAB && m_removedTab) {
m_removedTab->width = 0;
box = getTabBounds(m_removedTab);
drawTab(g, box, m_removedTab, 0,
@ -420,12 +406,12 @@ void Tabs::onPaint(PaintEvent& ev)
// Tab that is being dragged
if (m_selected && m_selected != m_floatingTab) {
double t = double(m_ani_t) / double(m_ani_T);
double t = animationTime();
Tab* tab = m_selected;
box = getTabBounds(tab);
int dy = 0;
if (m_ani == ANI_ADDING_TAB)
if (animation() == ANI_ADDING_TAB)
dy = int(box.h - box.h * t);
drawTab(g, box, m_selected, dy, (tab == m_hot), true);
@ -443,7 +429,7 @@ void Tabs::onPreferredSize(PreferredSizeEvent& ev)
SkinTheme* theme = static_cast<SkinTheme*>(this->getTheme());
gfx::Size reqsize(0, 0);
if (m_list.empty() && m_ani == ANI_NONE)
if (m_list.empty() && animation() == ANI_NONE)
reqsize.h = theme->dimensions.tabsEmptyHeight();
else
reqsize.h = theme->dimensions.tabsHeight();
@ -665,23 +651,13 @@ void Tabs::resetOldPositions(double t)
}
}
void Tabs::startAni(Ani ani, int T)
void Tabs::onAnimationFrame()
{
// Stop previous animation
if (m_ani != ANI_NONE)
stopAni();
m_ani = ani;
m_ani_t = 0;
m_ani_T = T;
m_timer.start();
invalidate();
}
void Tabs::stopAni()
void Tabs::onAnimationStop()
{
m_ani = ANI_NONE;
m_timer.stop();
if (m_list.empty()) {
Widget* root = getRoot();
if (root)
@ -711,9 +687,9 @@ void Tabs::stopDrag()
m_selected->oldWidth = m_selected->width;
}
resetOldPositions(double(m_ani_t) / double(m_ani_T));
resetOldPositions(animationTime());
updateTabs();
startAni(ANI_REORDER_TABS, ANI_REORDER_TABS_TICKS);
startAnimation(ANI_REORDER_TABS, ANI_REORDER_TABS_TICKS);
}
gfx::Rect Tabs::getTabBounds(Tab* tab)
@ -721,12 +697,12 @@ gfx::Rect Tabs::getTabBounds(Tab* tab)
SkinTheme* theme = static_cast<SkinTheme*>(this->getTheme());
gfx::Rect rect = getClientBounds();
gfx::Rect box(rect.x, rect.y, rect.w,
(m_list.empty() && m_ani == ANI_NONE ? 0:
(m_list.empty() && animation() == ANI_NONE ? 0:
theme->dimensions.tabsHeight() - theme->dimensions.tabsEmptyHeight()));
int startX = m_border*guiscale();
double t = double(m_ani_t) / double(m_ani_T);
double t = animationTime();
if (m_ani == ANI_NONE) {
if (animation() == ANI_NONE) {
box.x = startX + tab->x;
box.w = tab->width;
}
@ -773,7 +749,7 @@ void Tabs::createFloatingTab(Tab* tab)
m_floatingTab = tab;
m_removedTab = nullptr;
startAni(ANI_REMOVING_TAB, ANI_REMOVING_TAB_TICKS);
startAnimation(ANI_REMOVING_TAB, ANI_REMOVING_TAB_TICKS);
updateTabs();
}
@ -790,7 +766,7 @@ void Tabs::destroyFloatingTab()
m_floatingTab = nullptr;
resetOldPositions();
startAni(ANI_ADDING_TAB, ANI_ADDING_TAB_TICKS);
startAnimation(ANI_ADDING_TAB, ANI_ADDING_TAB_TICKS);
updateTabs();
tab->oldX = tab->x;

View File

@ -9,6 +9,7 @@
#define APP_UI_TABS_H_INCLUDED
#pragma once
#include "app/ui/animated_widget.h"
#include "ui/mouse_buttons.h"
#include "ui/timer.h"
#include "ui/widget.h"
@ -74,7 +75,8 @@ namespace app {
};
// Tabs control. Used to show opened documents.
class Tabs : public ui::Widget {
class Tabs : public ui::Widget
, public AnimatedWidget {
struct Tab {
TabView* view;
std::string text;
@ -90,10 +92,12 @@ namespace app {
typedef std::vector<Tab*> TabsList;
typedef TabsList::iterator TabsListIterator;
enum Ani { ANI_NONE,
ANI_ADDING_TAB,
ANI_REMOVING_TAB,
ANI_REORDER_TABS };
enum Ani : int {
ANI_NONE,
ANI_ADDING_TAB,
ANI_REMOVING_TAB,
ANI_REORDER_TABS
};
public:
Tabs(TabsDelegate* delegate);
@ -113,12 +117,12 @@ namespace app {
void onPaint(ui::PaintEvent& ev) override;
void onResize(ui::ResizeEvent& ev) override;
void onPreferredSize(ui::PreferredSizeEvent& ev) override;
void onAnimationFrame() override;
void onAnimationStop() override;
private:
void resetOldPositions();
void resetOldPositions(double t);
void startAni(Ani ani, int T);
void stopAni();
void selectTabInternal(Tab* tab);
void drawTab(ui::Graphics* g, const gfx::Rect& box, Tab* tab, int dy, bool hover, bool selected);
@ -146,10 +150,6 @@ namespace app {
TabsDelegate* m_delegate;
// Variables for animation purposes
ui::Timer m_timer;
Ani m_ani; // Current animation
int m_ani_t; // Number of ticks from the beginning of the transition/animation
int m_ani_T; // Number of ticks in total for the current transition/animation
Tab* m_removedTab;
// Drag-and-drop