Changeset View
Changeset View
Standalone View
Standalone View
effects/minimizeanimation/minimizeanimation.cpp
Show All 13 Lines | |||||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | 15 | GNU General Public License for more details. | ||
16 | 16 | | |||
17 | You should have received a copy of the GNU General Public License | 17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | *********************************************************************/ | 19 | *********************************************************************/ | ||
20 | 20 | | |||
21 | #include "minimizeanimation.h" | 21 | #include "minimizeanimation.h" | ||
22 | #include <QTimeLine> | 22 | | ||
23 | #include <QVector2D> | 23 | #include <QVector2D> | ||
24 | 24 | | |||
25 | namespace KWin | 25 | namespace KWin | ||
26 | { | 26 | { | ||
27 | 27 | | |||
28 | MinimizeAnimationEffect::MinimizeAnimationEffect() | 28 | MinimizeAnimationEffect::MinimizeAnimationEffect() | ||
29 | { | 29 | { | ||
30 | mActiveAnimations = 0; | 30 | reconfigure(ReconfigureAll); | ||
31 | | ||||
31 | connect(effects, &EffectsHandler::windowDeleted, this, &MinimizeAnimationEffect::windowDeleted); | 32 | connect(effects, &EffectsHandler::windowDeleted, this, &MinimizeAnimationEffect::windowDeleted); | ||
32 | connect(effects, &EffectsHandler::windowMinimized, this, &MinimizeAnimationEffect::windowMinimized); | 33 | connect(effects, &EffectsHandler::windowMinimized, this, &MinimizeAnimationEffect::windowMinimized); | ||
33 | connect(effects, &EffectsHandler::windowUnminimized, this, &MinimizeAnimationEffect::windowUnminimized); | 34 | connect(effects, &EffectsHandler::windowUnminimized, this, &MinimizeAnimationEffect::windowUnminimized); | ||
34 | } | 35 | } | ||
35 | 36 | | |||
37 | void MinimizeAnimationEffect::reconfigure(ReconfigureFlags flags) | ||||
38 | { | ||||
39 | Q_UNUSED(flags) | ||||
40 | | ||||
41 | m_duration = std::chrono::milliseconds(static_cast<int>(animationTime(250))); | ||||
42 | } | ||||
43 | | ||||
36 | bool MinimizeAnimationEffect::supported() | 44 | bool MinimizeAnimationEffect::supported() | ||
37 | { | 45 | { | ||
38 | return effects->animationsSupported(); | 46 | return effects->animationsSupported(); | ||
39 | } | 47 | } | ||
40 | 48 | | |||
41 | void MinimizeAnimationEffect::prePaintScreen(ScreenPrePaintData& data, int time) | 49 | void MinimizeAnimationEffect::prePaintScreen(ScreenPrePaintData& data, int time) | ||
42 | { | 50 | { | ||
51 | const std::chrono::milliseconds delta(time); | ||||
43 | 52 | | |||
44 | QHash< EffectWindow*, QTimeLine* >::iterator entry = mTimeLineWindows.begin(); | 53 | auto animationIt = m_animations.begin(); | ||
45 | bool erase = false; | 54 | while (animationIt != m_animations.end()) { | ||
46 | while (entry != mTimeLineWindows.end()) { | 55 | (*animationIt).update(delta); | ||
47 | QTimeLine *timeline = entry.value(); | 56 | ++animationIt; | ||
48 | if (entry.key()->isMinimized()) { | | |||
49 | timeline->setCurrentTime(timeline->currentTime() + time); | | |||
50 | erase = (timeline->currentValue() >= 1.0f); | | |||
51 | } else { | | |||
52 | timeline->setCurrentTime(timeline->currentTime() - time); | | |||
53 | erase = (timeline->currentValue() <= 0.0f); | | |||
54 | } | | |||
55 | if (erase) { | | |||
56 | delete timeline; | | |||
57 | entry = mTimeLineWindows.erase(entry); | | |||
58 | } else | | |||
59 | ++entry; | | |||
60 | } | 57 | } | ||
61 | 58 | | |||
62 | mActiveAnimations = mTimeLineWindows.count(); | | |||
63 | if (mActiveAnimations > 0) | | |||
64 | // We need to mark the screen windows as transformed. Otherwise the | 59 | // We need to mark the screen windows as transformed. Otherwise the | ||
65 | // whole screen won't be repainted, resulting in artefacts | 60 | // whole screen won't be repainted, resulting in artefacts. | ||
66 | data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; | 61 | data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS; | ||
67 | 62 | | |||
68 | effects->prePaintScreen(data, time); | 63 | effects->prePaintScreen(data, time); | ||
69 | } | 64 | } | ||
70 | 65 | | |||
71 | void MinimizeAnimationEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) | 66 | void MinimizeAnimationEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) | ||
72 | { | 67 | { | ||
73 | // Schedule window for transformation if the animation is still in | 68 | // Schedule window for transformation if the animation is still in | ||
74 | // progress | 69 | // progress | ||
75 | if (mTimeLineWindows.contains(w)) { | 70 | if (m_animations.contains(w)) { | ||
76 | // We'll transform this window | 71 | // We'll transform this window | ||
77 | data.setTransformed(); | 72 | data.setTransformed(); | ||
78 | w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); | 73 | w->enablePainting(EffectWindow::PAINT_DISABLED_BY_MINIMIZE); | ||
79 | } | 74 | } | ||
80 | 75 | | |||
81 | effects->prePaintWindow(w, data, time); | 76 | effects->prePaintWindow(w, data, time); | ||
82 | } | 77 | } | ||
83 | 78 | | |||
84 | void MinimizeAnimationEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) | 79 | void MinimizeAnimationEffect::paintWindow(EffectWindow* w, int mask, QRegion region, WindowPaintData& data) | ||
85 | { | 80 | { | ||
86 | QHash< EffectWindow*, QTimeLine* >::const_iterator entry = mTimeLineWindows.constFind(w); | 81 | const auto animationIt = m_animations.constFind(w); | ||
87 | if (entry != mTimeLineWindows.constEnd()) { | 82 | if (animationIt != m_animations.constEnd()) { | ||
88 | // 0 = not minimized, 1 = fully minimized | 83 | // 0 = not minimized, 1 = fully minimized | ||
89 | double progress = entry.value()->currentValue(); | 84 | const qreal progress = (*animationIt).value(); | ||
90 | 85 | | |||
91 | QRect geo = w->geometry(); | 86 | QRect geo = w->geometry(); | ||
92 | QRect icon = w->iconGeometry(); | 87 | QRect icon = w->iconGeometry(); | ||
93 | // If there's no icon geometry, minimize to the center of the screen | 88 | // If there's no icon geometry, minimize to the center of the screen | ||
94 | if (!icon.isValid()) | 89 | if (!icon.isValid()) | ||
95 | icon = QRect(effects->virtualScreenGeometry().center(), QSize(0, 0)); | 90 | icon = QRect(effects->virtualScreenGeometry().center(), QSize(0, 0)); | ||
96 | 91 | | |||
97 | data *= QVector2D(interpolate(1.0, icon.width() / (double)geo.width(), progress), | 92 | data *= QVector2D(interpolate(1.0, icon.width() / (double)geo.width(), progress), | ||
98 | interpolate(1.0, icon.height() / (double)geo.height(), progress)); | 93 | interpolate(1.0, icon.height() / (double)geo.height(), progress)); | ||
99 | data.setXTranslation((int)interpolate(data.xTranslation(), icon.x() - geo.x(), progress)); | 94 | data.setXTranslation((int)interpolate(data.xTranslation(), icon.x() - geo.x(), progress)); | ||
100 | data.setYTranslation((int)interpolate(data.yTranslation(), icon.y() - geo.y(), progress)); | 95 | data.setYTranslation((int)interpolate(data.yTranslation(), icon.y() - geo.y(), progress)); | ||
101 | data.multiplyOpacity(0.1 + (1 - progress) * 0.9); | 96 | data.multiplyOpacity(0.1 + (1 - progress) * 0.9); | ||
102 | } | 97 | } | ||
103 | 98 | | |||
104 | // Call the next effect. | 99 | // Call the next effect. | ||
105 | effects->paintWindow(w, mask, region, data); | 100 | effects->paintWindow(w, mask, region, data); | ||
106 | } | 101 | } | ||
107 | 102 | | |||
108 | void MinimizeAnimationEffect::postPaintScreen() | 103 | void MinimizeAnimationEffect::postPaintScreen() | ||
109 | { | 104 | { | ||
110 | if (mActiveAnimations > 0) | 105 | auto animationIt = m_animations.begin(); | ||
111 | // Repaint the workspace so that everything would be repainted next time | 106 | while (animationIt != m_animations.end()) { | ||
107 | if ((*animationIt).done()) { | ||||
108 | animationIt = m_animations.erase(animationIt); | ||||
109 | } else { | ||||
110 | ++animationIt; | ||||
111 | } | ||||
112 | } | ||||
113 | | ||||
112 | effects->addRepaintFull(); | 114 | effects->addRepaintFull(); | ||
113 | mActiveAnimations = mTimeLineWindows.count(); | | |||
114 | 115 | | |||
115 | // Call the next effect. | 116 | // Call the next effect. | ||
116 | effects->postPaintScreen(); | 117 | effects->postPaintScreen(); | ||
117 | } | 118 | } | ||
118 | 119 | | |||
119 | void MinimizeAnimationEffect::windowDeleted(EffectWindow *w) | 120 | void MinimizeAnimationEffect::windowDeleted(EffectWindow *w) | ||
120 | { | 121 | { | ||
121 | delete mTimeLineWindows.take(w); | 122 | m_animations.remove(w); | ||
122 | } | 123 | } | ||
123 | 124 | | |||
124 | void MinimizeAnimationEffect::windowMinimized(EffectWindow *w) | 125 | void MinimizeAnimationEffect::windowMinimized(EffectWindow *w) | ||
125 | { | 126 | { | ||
126 | if (effects->activeFullScreenEffect()) | 127 | if (effects->activeFullScreenEffect()) | ||
127 | return; | 128 | return; | ||
128 | 129 | | |||
129 | if (!mTimeLineWindows.contains(w)) { | 130 | TimeLine &timeLine = m_animations[w]; | ||
130 | auto *timeline = new QTimeLine(animationTime(250), this); | 131 | | ||
131 | timeline->setCurrentTime(0); | 132 | if (timeLine.running()) { | ||
132 | timeline->setCurveShape(QTimeLine::EaseInOutCurve); | 133 | timeLine.toggleDirection(); | ||
133 | mTimeLineWindows.insert(w, timeline); | 134 | } else { | ||
135 | timeLine.setDirection(TimeLine::Forward); | ||||
136 | timeLine.setDuration(m_duration); | ||||
137 | timeLine.setEasingCurve(QEasingCurve::InOutSine); | ||||
134 | } | 138 | } | ||
139 | | ||||
140 | effects->addRepaintFull(); | ||||
135 | } | 141 | } | ||
136 | 142 | | |||
137 | void MinimizeAnimationEffect::windowUnminimized(EffectWindow *w) | 143 | void MinimizeAnimationEffect::windowUnminimized(EffectWindow *w) | ||
138 | { | 144 | { | ||
139 | if (effects->activeFullScreenEffect()) | 145 | if (effects->activeFullScreenEffect()) | ||
140 | return; | 146 | return; | ||
141 | 147 | | |||
142 | if (!mTimeLineWindows.contains(w)) { | 148 | TimeLine &timeLine = m_animations[w]; | ||
143 | auto *timeline = new QTimeLine(animationTime(250), this); | 149 | | ||
144 | timeline->setCurrentTime(timeline->duration()); | 150 | if (timeLine.running()) { | ||
145 | timeline->setCurveShape(QTimeLine::EaseInOutCurve); | 151 | timeLine.toggleDirection(); | ||
146 | mTimeLineWindows.insert(w, timeline); | 152 | } else { | ||
153 | timeLine.setDirection(TimeLine::Backward); | ||||
154 | timeLine.setDuration(m_duration); | ||||
155 | timeLine.setEasingCurve(QEasingCurve::InOutSine); | ||||
147 | } | 156 | } | ||
157 | | ||||
158 | effects->addRepaintFull(); | ||||
148 | } | 159 | } | ||
149 | 160 | | |||
150 | bool MinimizeAnimationEffect::isActive() const | 161 | bool MinimizeAnimationEffect::isActive() const | ||
151 | { | 162 | { | ||
152 | return !mTimeLineWindows.isEmpty(); | 163 | return !m_animations.isEmpty(); | ||
153 | } | 164 | } | ||
154 | 165 | | |||
155 | } // namespace | 166 | } // namespace | ||
156 | 167 | |