aerothemeplasma-kde6/KWin/decoration/breeze-v5.93.0/kstyle/animations/breezetransitionwidget.cpp
2024-06-13 16:59:18 +02:00

285 lines
7.5 KiB
C++
Executable file

//////////////////////////////////////////////////////////////////////////////
// breezetransitionwidget.cpp
// stores event filters and maps widgets to transitions for transitions
// -------------------
//
// SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
#include "breezetransitionwidget.h"
#include <QPaintEvent>
#include <QPainter>
#include <QStyleOption>
#include <QTextStream>
namespace Breeze
{
//________________________________________________
bool TransitionWidget::_paintEnabled = true;
bool TransitionWidget::paintEnabled()
{
return _paintEnabled;
}
int TransitionWidget::_steps = 0;
//________________________________________________
TransitionWidget::TransitionWidget(QWidget *parent, int duration)
: QWidget(parent)
, _animation(new Animation(duration, this))
{
// background flags
setAttribute(Qt::WA_NoSystemBackground);
setAutoFillBackground(false);
// setup animation
_animation.data()->setStartValue(0);
_animation.data()->setEndValue(1.0);
_animation.data()->setTargetObject(this);
_animation.data()->setPropertyName("opacity");
// hide when animation is finished
connect(_animation.data(), &QAbstractAnimation::finished, this, &QWidget::hide);
}
//________________________________________________
QPixmap TransitionWidget::grab(QWidget *widget, QRect rect)
{
// change rect
if (!rect.isValid()) {
rect = widget->rect();
}
if (!rect.isValid()) {
return QPixmap();
}
// initialize pixmap
QPixmap out(rect.size());
out.fill(Qt::transparent);
_paintEnabled = false;
if (testFlag(GrabFromWindow)) {
rect = rect.translated(widget->mapTo(widget->window(), widget->rect().topLeft()));
widget = widget->window();
out = widget->grab(rect);
} else {
if (!testFlag(Transparent)) {
grabBackground(out, widget, rect);
}
grabWidget(out, widget, rect);
}
_paintEnabled = true;
return out;
}
//________________________________________________
bool TransitionWidget::event(QEvent *event)
{
switch (event->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::KeyPress:
case QEvent::KeyRelease:
endAnimation();
hide();
event->ignore();
return false;
default:
return QWidget::event(event);
}
}
//________________________________________________
void TransitionWidget::paintEvent(QPaintEvent *event)
{
// fully transparent case
if (opacity() >= 1.0 && endPixmap().isNull()) {
return;
}
if (!_paintEnabled) {
return;
}
// get rect
QRect rect = event->rect();
if (!rect.isValid()) {
rect = this->rect();
}
// local pixmap
const bool paintOnWidget(testFlag(PaintOnWidget) && !testFlag(Transparent));
if (!paintOnWidget) {
if (_currentPixmap.isNull() || _currentPixmap.size() != size()) {
_currentPixmap = QPixmap(size());
}
}
// fill
_currentPixmap.fill(Qt::transparent);
// copy local pixmap to current
{
QPainter p;
// draw end pixmap first, provided that opacity is small enough
if (opacity() >= 0.004 && !_endPixmap.isNull()) {
// faded endPixmap if parent target is transparent and opacity is
if (opacity() <= 0.996 && testFlag(Transparent)) {
fade(_endPixmap, _currentPixmap, opacity(), rect);
p.begin(&_currentPixmap);
p.setClipRect(event->rect());
} else {
if (paintOnWidget) {
p.begin(this);
} else {
p.begin(&_currentPixmap);
}
p.setClipRect(event->rect());
p.drawPixmap(QPoint(), _endPixmap);
}
} else {
if (paintOnWidget) {
p.begin(this);
} else {
p.begin(&_currentPixmap);
}
p.setClipRect(event->rect());
}
// draw fading start pixmap
if (opacity() <= 0.996 && !_startPixmap.isNull()) {
if (opacity() >= 0.004) {
fade(_startPixmap, _localStartPixmap, 1.0 - opacity(), rect);
p.drawPixmap(QPoint(), _localStartPixmap);
} else {
p.drawPixmap(QPoint(), _startPixmap);
}
}
p.end();
}
// copy current pixmap on widget
if (!paintOnWidget) {
QPainter p(this);
p.setClipRect(event->rect());
p.drawPixmap(QPoint(0, 0), _currentPixmap);
p.end();
}
}
//________________________________________________
void TransitionWidget::grabBackground(QPixmap &pixmap, QWidget *widget, QRect &rect) const
{
if (!widget) {
return;
}
QWidgetList widgets;
if (widget->autoFillBackground()) {
widgets.append(widget);
}
QWidget *parent(nullptr);
// get highest level parent
for (parent = widget->parentWidget(); parent; parent = parent->parentWidget()) {
if (!(parent->isVisible() && parent->rect().isValid())) {
continue;
}
// store in list
widgets.append(parent);
// stop at topLevel
if (parent->isWindow() || parent->autoFillBackground()) {
break;
}
}
if (!parent) {
parent = widget;
}
// painting
QPainter p(&pixmap);
p.setClipRect(rect);
const QBrush backgroundBrush = parent->palette().brush(parent->backgroundRole());
if (backgroundBrush.style() == Qt::TexturePattern) {
p.drawTiledPixmap(rect, backgroundBrush.texture(), widget->mapTo(parent, rect.topLeft()));
} else {
p.fillRect(pixmap.rect(), backgroundBrush);
}
if (parent->isWindow() && parent->testAttribute(Qt::WA_StyledBackground)) {
QStyleOption option;
option.initFrom(parent);
option.rect = rect;
option.rect.translate(widget->mapTo(parent, rect.topLeft()));
p.translate(-option.rect.topLeft());
parent->style()->drawPrimitive(QStyle::PE_Widget, &option, &p, parent);
p.translate(option.rect.topLeft());
}
// draw all widgets in parent list
// backward
QPaintEvent event(rect);
for (int i = widgets.size() - 1; i >= 0; i--) {
QWidget *w = widgets.at(i);
w->render(&p, -widget->mapTo(w, rect.topLeft()), rect, {});
}
// end
p.end();
}
//________________________________________________
void TransitionWidget::grabWidget(QPixmap &pixmap, QWidget *widget, QRect &rect) const
{
widget->render(&pixmap, pixmap.rect().topLeft(), rect, QWidget::DrawChildren);
}
//________________________________________________
void TransitionWidget::fade(const QPixmap &source, QPixmap &target, qreal opacity, const QRect &rect) const
{
if (target.isNull() || target.size() != size()) {
target = QPixmap(size());
}
// erase target
target.fill(Qt::transparent);
// check opacity
if (opacity * 255 < 1) {
return;
}
QPainter p(&target);
p.setClipRect(rect);
// draw pixmap
p.drawPixmap(QPoint(0, 0), source);
// opacity mask (0.996 corresponds to 254/255)
if (opacity <= 0.996) {
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
QColor color(Qt::black);
color.setAlphaF(opacity);
p.fillRect(rect, color);
}
p.end();
}
}