Qt: Add toggle button class

And use it for patches
pull/3576/head
Stenzek 1 month ago
parent f1fe00c1cb
commit 5e253d0c2a
No known key found for this signature in database

@ -149,6 +149,8 @@ set(SRCS
setupwizarddialog.h
setupwizarddialog.ui
texturereplacementsettingsdialog.ui
togglebutton.cpp
togglebutton.h
)
set(TS_FILES

@ -50,9 +50,11 @@
<ClCompile Include="selectdiscdialog.cpp" />
<ClCompile Include="settingswindow.cpp" />
<ClCompile Include="setupwizarddialog.cpp" />
<ClCompile Include="togglebutton.cpp" />
<ClCompile Include="vcruntimecheck.cpp" />
</ItemGroup>
<ItemGroup>
<QtMoc Include="togglebutton.h" />
<QtMoc Include="setupwizarddialog.h" />
<QtMoc Include="aboutdialog.h" />
<QtMoc Include="audiosettingswidget.h" />

@ -48,6 +48,7 @@
<ClCompile Include="gamepatchsettingswidget.cpp" />
<ClCompile Include="isobrowserwindow.cpp" />
<ClCompile Include="debuggercodeview.cpp" />
<ClCompile Include="togglebutton.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="qtutils.h" />
@ -108,6 +109,7 @@
<QtMoc Include="gamepatchsettingswidget.h" />
<QtMoc Include="isobrowserwindow.h" />
<QtMoc Include="debuggercodeview.h" />
<QtMoc Include="togglebutton.h" />
</ItemGroup>
<ItemGroup>
<QtUi Include="consolesettingswidget.ui" />

@ -24,7 +24,7 @@
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QCheckBox" name="enabled">
<widget class="ToggleButton" name="enabled">
<property name="text">
<string>Enabled</string>
</property>
@ -73,6 +73,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ToggleButton</class>
<extends>QAbstractButton</extends>
<header>togglebutton.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

@ -36,7 +36,7 @@ GamePatchDetailsWidget::GamePatchDetailsWidget(std::string name, const std::stri
DebugAssert(dialog->getSettingsInterface());
m_ui.enabled->setChecked(enabled);
connect(m_ui.enabled, &QCheckBox::checkStateChanged, this, &GamePatchDetailsWidget::onEnabledStateChanged);
connect(m_ui.enabled, &ToggleButton::checkStateChanged, this, &GamePatchDetailsWidget::onEnabledStateChanged);
}
GamePatchDetailsWidget::~GamePatchDetailsWidget() = default;

@ -0,0 +1,160 @@
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "togglebutton.h"
#include <QtGui/QKeyEvent>
#include <QtGui/QPainter>
#include <QtGui/QPainterPath>
#include <QtWidgets/QStyleOption>
#include "moc_togglebutton.cpp"
ToggleButton::ToggleButton(QWidget* parent) : QAbstractButton(parent), m_offset_animation(this, "offset")
{
setCheckable(true);
setCursor(Qt::PointingHandCursor);
setFocusPolicy(Qt::StrongFocus);
m_offset_animation.setDuration(150);
m_offset_animation.setEasingCurve(QEasingCurve::OutCubic);
}
ToggleButton::~ToggleButton() = default;
QSize ToggleButton::sizeHint() const
{
return QSize(50, 25);
}
void ToggleButton::showEvent(QShowEvent* event)
{
QAbstractButton::showEvent(event);
// Make sure the toggle position matches the current state when first shown
updateTogglePosition();
}
void ToggleButton::resizeEvent(QResizeEvent* event)
{
QAbstractButton::resizeEvent(event);
// Update position when resized since it depends on widget dimensions
updateTogglePosition();
}
void ToggleButton::updateTogglePosition()
{
// Immediately set the toggle to the correct position without animation
if (width() > 0)
{
m_offset_animation.stop();
m_offset = isChecked() ? width() - height() : 0;
update();
}
}
void ToggleButton::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QStyleOption opt;
opt.initFrom(this);
// Get colors from the current style
QColor background_color = isChecked() ? opt.palette.highlight().color() : opt.palette.dark().color();
QColor thumb_color = opt.palette.light().color();
if (m_hovered || hasFocus())
{
background_color = background_color.lighter(120);
}
if (!isEnabled())
{
background_color = opt.palette.mid().color();
thumb_color = opt.palette.midlight().color();
}
// Draw background
const int track_width = width() - 2;
const int track_height = height() - 2;
const int corner_radius = track_height / 2;
QPainterPath path;
path.addRoundedRect(1, 1, track_width, track_height, corner_radius, corner_radius);
painter.fillPath(path, background_color);
// Draw thumb
const int thumb_size = track_height - 4;
const int thumb_x = m_offset + 2;
const int thumb_y = 2;
QPainterPath thumbPath;
thumbPath.addEllipse(thumb_x, thumb_y, thumb_size, thumb_size);
painter.fillPath(thumbPath, thumb_color);
}
void ToggleButton::enterEvent(QEnterEvent* event)
{
Q_UNUSED(event);
m_hovered = true;
update();
}
void ToggleButton::leaveEvent(QEvent* event)
{
Q_UNUSED(event);
m_hovered = false;
update();
}
void ToggleButton::checkStateSet()
{
QAbstractButton::checkStateSet();
animateToggle(isChecked());
}
void ToggleButton::animateToggle(bool checked)
{
m_offset_animation.stop();
m_offset_animation.setStartValue(m_offset);
m_offset_animation.setEndValue(checked ? width() - height() : 0);
m_offset_animation.start();
}
void ToggleButton::nextCheckState()
{
QAbstractButton::nextCheckState();
animateToggle(isChecked());
update();
}
void ToggleButton::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_Space || event->key() == Qt::Key_Return)
{
setChecked(!isChecked());
event->accept();
}
else
{
QAbstractButton::keyPressEvent(event);
}
}
int ToggleButton::offset() const
{
return m_offset;
}
void ToggleButton::setOffset(int value)
{
m_offset = value;
update();
}

@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once
#include <QtCore/QPropertyAnimation>
#include <QtWidgets/QAbstractButton>
class ToggleButton : public QAbstractButton
{
Q_OBJECT
Q_PROPERTY(int offset READ offset WRITE setOffset)
public:
explicit ToggleButton(QWidget* parent = nullptr);
~ToggleButton() override;
QSize sizeHint() const override;
Q_SIGNALS:
void checkStateChanged(Qt::CheckState state);
protected:
void checkStateSet() override;
void nextCheckState() override;
void paintEvent(QPaintEvent* event) override;
void enterEvent(QEnterEvent* event) override;
void leaveEvent(QEvent* event) override;
void keyPressEvent(QKeyEvent* event) override;
void showEvent(QShowEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
private:
void animateToggle(bool checked);
void updateTogglePosition();
int offset() const;
void setOffset(int value);
int m_offset = 0;
bool m_hovered = false;
QPropertyAnimation m_offset_animation;
QPropertyAnimation m_background_animation;
};
Loading…
Cancel
Save