1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 06:47:34 +00:00

WindowServer: Add a more generic mechanism for animations

This patch adds the WindowServer::Animation class, which represents
a simple animation driven by the compositor.

An animation has a length (in milliseconds) and two hooks:

- on_update: called whenever the animation should render something.
- on_stop: called when the animation is finished and/or stopped.

This patch also ports the window minimization animation to this new
mechanism. :^)
This commit is contained in:
Andreas Kling 2021-06-27 16:47:52 +02:00
parent 1f33c517df
commit 75f870a93f
7 changed files with 171 additions and 70 deletions

View file

@ -1,10 +1,11 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "Window.h"
#include "Animation.h"
#include "AppletManager.h"
#include "ClientConnection.h"
#include "Compositor.h"
@ -306,6 +307,21 @@ void Window::set_taskbar_rect(const Gfx::IntRect& rect)
m_have_taskbar_rect = !m_taskbar_rect.is_empty();
}
static Gfx::IntRect interpolate_rect(Gfx::IntRect const& from_rect, Gfx::IntRect const& to_rect, float progress)
{
auto dx = to_rect.x() - from_rect.x();
auto dy = to_rect.y() - from_rect.y();
auto dw = to_rect.width() - from_rect.width();
auto dh = to_rect.height() - from_rect.height();
return Gfx::IntRect {
from_rect.x() + ((float)dx * progress),
from_rect.y() + ((float)dy * progress),
from_rect.width() + ((float)dw * progress),
from_rect.height() + ((float)dh * progress),
};
}
void Window::start_minimize_animation()
{
if (!m_have_taskbar_rect) {
@ -327,7 +343,26 @@ void Window::start_minimize_animation()
return IterationDecision::Continue;
});
}
m_minimize_animation_step = 0;
m_animation = Animation::create();
m_animation->set_length(150);
m_animation->on_update = [this](float progress, Gfx::Painter& painter, Screen& screen, Gfx::DisjointRectSet& flush_rects) {
Gfx::PainterStateSaver saver(painter);
painter.set_draw_op(Gfx::Painter::DrawOp::Invert);
auto from_rect = is_minimized() ? frame().rect() : taskbar_rect();
auto to_rect = is_minimized() ? taskbar_rect() : frame().rect();
auto rect = interpolate_rect(from_rect, to_rect, progress);
painter.draw_rect(rect, Color::Transparent); // Color doesn't matter, we draw inverted
flush_rects.add(rect.intersected(screen.rect()));
Compositor::the().invalidate_screen(rect);
};
m_animation->on_stop = [this] {
m_animation = nullptr;
};
m_animation->start();
}
void Window::set_opacity(float opacity)
@ -1071,5 +1106,4 @@ String Window::computed_title() const
return String::formatted("{} (Not responding)", title);
return title;
}
}