mirror of
https://github.com/stenzek/duckstation.git
synced 2026-07-08 17:46:19 +00:00
Qt: Add animation to setup wizard
This commit is contained in:
@@ -23,6 +23,8 @@ set(SRCS
|
||||
advancedsettingswidget.cpp
|
||||
advancedsettingswidget.h
|
||||
advancedsettingswidget.ui
|
||||
animatedstackedwidget.cpp
|
||||
animatedstackedwidget.h
|
||||
asynchttprequest.cpp
|
||||
asynchttprequest.h
|
||||
asyncpixmaploader.cpp
|
||||
|
||||
122
src/duckstation-qt/animatedstackedwidget.cpp
Normal file
122
src/duckstation-qt/animatedstackedwidget.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "animatedstackedwidget.h"
|
||||
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtWidgets/QStyle>
|
||||
#include <utility>
|
||||
|
||||
#include "moc_animatedstackedwidget.cpp"
|
||||
|
||||
class SlideTransitionOverlay final : public QWidget
|
||||
{
|
||||
public:
|
||||
explicit SlideTransitionOverlay(QWidget* parent) : QWidget(parent) { setAttribute(Qt::WA_TransparentForMouseEvents); }
|
||||
|
||||
void start(QPixmap outgoing, QPixmap incoming, bool forward)
|
||||
{
|
||||
m_outgoing = std::move(outgoing);
|
||||
m_incoming = std::move(incoming);
|
||||
m_direction = forward ? 1 : -1;
|
||||
m_progress = 0.0;
|
||||
show();
|
||||
raise();
|
||||
}
|
||||
|
||||
void setProgress(qreal progress)
|
||||
{
|
||||
m_progress = progress;
|
||||
update();
|
||||
}
|
||||
|
||||
void finish()
|
||||
{
|
||||
hide();
|
||||
m_outgoing = {};
|
||||
m_incoming = {};
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QPainter painter(this);
|
||||
const int offset = qRound(static_cast<qreal>(width()) * m_progress);
|
||||
painter.drawPixmap(QPoint(-m_direction * offset, 0), m_outgoing);
|
||||
painter.drawPixmap(QPoint(m_direction * (width() - offset), 0), m_incoming);
|
||||
}
|
||||
|
||||
private:
|
||||
QPixmap m_outgoing;
|
||||
QPixmap m_incoming;
|
||||
qreal m_progress = 0.0;
|
||||
int m_direction = 1;
|
||||
};
|
||||
|
||||
static QPixmap GrabPage(QWidget* page)
|
||||
{
|
||||
const qreal dpr = page->devicePixelRatioF();
|
||||
QPixmap pixmap((QSizeF(page->size()) * dpr).toSize());
|
||||
pixmap.setDevicePixelRatio(dpr);
|
||||
pixmap.fill(page->palette().window().color());
|
||||
page->render(&pixmap);
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
AnimatedStackedWidget::AnimatedStackedWidget(QWidget* parent) : QStackedWidget(parent), m_animation(this)
|
||||
{
|
||||
m_overlay = new SlideTransitionOverlay(this);
|
||||
m_overlay->hide();
|
||||
|
||||
m_animation.setDuration(150);
|
||||
m_animation.setEasingCurve(QEasingCurve::OutCubic);
|
||||
connect(&m_animation, &QVariantAnimation::valueChanged, this,
|
||||
[this](const QVariant& value) { m_overlay->setProgress(value.toReal()); });
|
||||
connect(&m_animation, &QVariantAnimation::finished, this, &AnimatedStackedWidget::finishAnimation);
|
||||
}
|
||||
|
||||
AnimatedStackedWidget::~AnimatedStackedWidget() = default;
|
||||
|
||||
void AnimatedStackedWidget::setCurrentIndex(int index)
|
||||
{
|
||||
const int previous_index = currentIndex();
|
||||
if (index == previous_index || index < 0 || index >= count())
|
||||
return;
|
||||
|
||||
finishAnimation();
|
||||
|
||||
if (!isVisible() || !style()->styleHint(QStyle::SH_Widget_Animate, nullptr, this))
|
||||
{
|
||||
QStackedWidget::setCurrentIndex(index);
|
||||
return;
|
||||
}
|
||||
|
||||
const QPixmap outgoing = GrabPage(currentWidget());
|
||||
QStackedWidget::setCurrentIndex(index);
|
||||
const QPixmap incoming = GrabPage(currentWidget());
|
||||
|
||||
m_overlay->setGeometry(contentsRect());
|
||||
m_overlay->start(outgoing, incoming, index > previous_index);
|
||||
m_animation.setStartValue(0.0);
|
||||
m_animation.setEndValue(1.0);
|
||||
m_animation.start();
|
||||
}
|
||||
|
||||
void AnimatedStackedWidget::setCurrentWidget(QWidget* widget)
|
||||
{
|
||||
setCurrentIndex(indexOf(widget));
|
||||
}
|
||||
|
||||
void AnimatedStackedWidget::resizeEvent(QResizeEvent* event)
|
||||
{
|
||||
finishAnimation();
|
||||
QStackedWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void AnimatedStackedWidget::finishAnimation()
|
||||
{
|
||||
m_animation.stop();
|
||||
m_overlay->finish();
|
||||
}
|
||||
31
src/duckstation-qt/animatedstackedwidget.h
Normal file
31
src/duckstation-qt/animatedstackedwidget.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QVariantAnimation>
|
||||
#include <QtWidgets/QStackedWidget>
|
||||
|
||||
class SlideTransitionOverlay;
|
||||
|
||||
class AnimatedStackedWidget final : public QStackedWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AnimatedStackedWidget(QWidget* parent = nullptr);
|
||||
~AnimatedStackedWidget() override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setCurrentIndex(int index);
|
||||
void setCurrentWidget(QWidget* widget);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
private:
|
||||
void finishAnimation();
|
||||
|
||||
QVariantAnimation m_animation;
|
||||
SlideTransitionOverlay* m_overlay = nullptr;
|
||||
};
|
||||
@@ -6,6 +6,7 @@
|
||||
<ClCompile Include="achievementsettingswidget.cpp" />
|
||||
<ClCompile Include="achievementlogindialog.cpp" />
|
||||
<ClCompile Include="advancedsettingswidget.cpp" />
|
||||
<ClCompile Include="animatedstackedwidget.cpp" />
|
||||
<ClCompile Include="asynchttprequest.cpp" />
|
||||
<ClCompile Include="asyncpixmaploader.cpp" />
|
||||
<ClCompile Include="audiosettingswidget.cpp" />
|
||||
@@ -113,6 +114,7 @@
|
||||
<QtMoc Include="selectdiscdialog.h" />
|
||||
<ClInclude Include="settingwidgetbinder.h" />
|
||||
<QtMoc Include="cardradiobutton.h" />
|
||||
<QtMoc Include="animatedstackedwidget.h" />
|
||||
<QtMoc Include="consolesettingswidget.h" />
|
||||
<QtMoc Include="emulationsettingswidget.h" />
|
||||
<QtMoc Include="gamelistsettingswidget.h" />
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<ClCompile Include="qtprogresscallback.cpp" />
|
||||
<ClCompile Include="interfacesettingswidget.cpp" />
|
||||
<ClCompile Include="advancedsettingswidget.cpp" />
|
||||
<ClCompile Include="animatedstackedwidget.cpp" />
|
||||
<ClCompile Include="aboutdialog.cpp" />
|
||||
<ClCompile Include="memorycardsettingswidget.cpp" />
|
||||
<ClCompile Include="inputbindingdialog.cpp" />
|
||||
@@ -126,6 +127,7 @@
|
||||
<QtMoc Include="svgiconengine.h" />
|
||||
<QtMoc Include="svgwidget.h" />
|
||||
<QtMoc Include="cardradiobutton.h" />
|
||||
<QtMoc Include="animatedstackedwidget.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUi Include="consolesettingswidget.ui" />
|
||||
|
||||
@@ -201,7 +201,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QStackedWidget" name="pages">
|
||||
<widget class="AnimatedStackedWidget" name="pages">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@@ -1354,6 +1354,11 @@ You can change this option at a later time by using the toolbar in Desktop Mode
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>AnimatedStackedWidget</class>
|
||||
<extends>QStackedWidget</extends>
|
||||
<header>animatedstackedwidget.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CardRadioButton</class>
|
||||
<extends>QRadioButton</extends>
|
||||
|
||||
Reference in New Issue
Block a user