mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-19 10:43:33 +00:00
Improve mouse wheel scrolling in configuration dialogs
Enable mouse wheel scrolling throughout scroll areas instead of requiring hover over scrollbars. Add event filter to forward wheel events to scrollbars. Fix Input tab scrolling by only consuming wheel events in ConfigureInputPlayer when actively mapping inputs. Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "citron/configuration/configure_dialog.h"
|
#include "citron/configuration/configure_dialog.h"
|
||||||
|
#include <cmath>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
@@ -10,8 +11,10 @@
|
|||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
|
#include <QScrollBar>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QWheelEvent>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/settings_enums.h"
|
#include "common/settings_enums.h"
|
||||||
@@ -39,6 +42,50 @@
|
|||||||
#include "citron/theme.h"
|
#include "citron/theme.h"
|
||||||
#include "citron/uisettings.h"
|
#include "citron/uisettings.h"
|
||||||
|
|
||||||
|
// Event filter class to forward wheel events to scroll area's scrollbar
|
||||||
|
class ScrollAreaWheelEventFilter : public QObject {
|
||||||
|
public:
|
||||||
|
explicit ScrollAreaWheelEventFilter(QScrollArea* scroll_area, QObject* parent = nullptr,
|
||||||
|
bool prefer_horizontal = false)
|
||||||
|
: QObject(parent), scroll_area_(scroll_area), prefer_horizontal_(prefer_horizontal) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject* obj, QEvent* event) override {
|
||||||
|
if (event->type() == QEvent::Wheel && scroll_area_) {
|
||||||
|
auto* wheel_event = static_cast<QWheelEvent*>(event);
|
||||||
|
const QPoint angle_delta = wheel_event->angleDelta();
|
||||||
|
|
||||||
|
// Determine which scrollbar to use based on scroll direction and preference
|
||||||
|
bool use_horizontal = prefer_horizontal_ || (std::abs(angle_delta.x()) > std::abs(angle_delta.y()));
|
||||||
|
|
||||||
|
if (use_horizontal) {
|
||||||
|
// Try horizontal scrolling first
|
||||||
|
if (scroll_area_->horizontalScrollBar()->maximum() > 0) {
|
||||||
|
QApplication::sendEvent(scroll_area_->horizontalScrollBar(), wheel_event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try vertical scrolling
|
||||||
|
if (scroll_area_->verticalScrollBar()->maximum() > 0) {
|
||||||
|
QApplication::sendEvent(scroll_area_->verticalScrollBar(), wheel_event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If vertical didn't work and we didn't try horizontal, try it now
|
||||||
|
if (!use_horizontal && scroll_area_->horizontalScrollBar()->maximum() > 0) {
|
||||||
|
QApplication::sendEvent(scroll_area_->horizontalScrollBar(), wheel_event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QObject::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QScrollArea* scroll_area_;
|
||||||
|
bool prefer_horizontal_;
|
||||||
|
};
|
||||||
|
|
||||||
static QScrollArea* CreateScrollArea(QWidget* widget) {
|
static QScrollArea* CreateScrollArea(QWidget* widget) {
|
||||||
auto* scroll_area = new QScrollArea();
|
auto* scroll_area = new QScrollArea();
|
||||||
scroll_area->setWidget(widget);
|
scroll_area->setWidget(widget);
|
||||||
@@ -46,6 +93,11 @@ static QScrollArea* CreateScrollArea(QWidget* widget) {
|
|||||||
scroll_area->setFrameShape(QFrame::NoFrame);
|
scroll_area->setFrameShape(QFrame::NoFrame);
|
||||||
scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
scroll_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
|
|
||||||
|
// Install event filter on the widget to forward wheel events to scrollbar
|
||||||
|
auto* filter = new ScrollAreaWheelEventFilter(scroll_area, scroll_area);
|
||||||
|
widget->installEventFilter(filter);
|
||||||
|
|
||||||
return scroll_area;
|
return scroll_area;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +165,11 @@ rainbow_timer{new QTimer(this)} {
|
|||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
// Enable wheel event scrolling on the top button scroll area (horizontal scrolling)
|
||||||
|
auto* top_button_filter = new ScrollAreaWheelEventFilter(ui->topButtonScrollArea, this, true);
|
||||||
|
ui->topButtonScrollArea->widget()->installEventFilter(top_button_filter);
|
||||||
|
ui->topButtonScrollArea->installEventFilter(top_button_filter);
|
||||||
|
|
||||||
last_palette_text_color = qApp->palette().color(QPalette::WindowText);
|
last_palette_text_color = qApp->palette().color(QPalette::WindowText);
|
||||||
|
|
||||||
if (!UISettings::values.configure_dialog_geometry.isEmpty()) {
|
if (!UISettings::values.configure_dialog_geometry.isEmpty()) {
|
||||||
|
|||||||
@@ -5,12 +5,16 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <QApplication>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
#include <QScrollArea>
|
||||||
|
#include <QScrollBar>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QWheelEvent>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/param_package.h"
|
#include "common/param_package.h"
|
||||||
#include "configuration/qt_config.h"
|
#include "configuration/qt_config.h"
|
||||||
@@ -1536,9 +1540,56 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureInputPlayer::wheelEvent(QWheelEvent* event) {
|
void ConfigureInputPlayer::wheelEvent(QWheelEvent* event) {
|
||||||
const int x = event->angleDelta().x();
|
// Only handle wheel events for input mapping when in input mapping mode
|
||||||
const int y = event->angleDelta().y();
|
// Otherwise, forward to the scroll area for scrolling
|
||||||
input_subsystem->GetMouse()->MouseWheelChange(x, y);
|
if (input_setter) {
|
||||||
|
const int x = event->angleDelta().x();
|
||||||
|
const int y = event->angleDelta().y();
|
||||||
|
input_subsystem->GetMouse()->MouseWheelChange(x, y);
|
||||||
|
event->accept();
|
||||||
|
} else {
|
||||||
|
// Find the parent scroll area and forward the event to its scrollbar
|
||||||
|
// The widget hierarchy is: ConfigureInputPlayer -> QWidget (tab) -> QTabWidget ->
|
||||||
|
// ConfigureInput -> QWidget (viewport) -> QScrollArea
|
||||||
|
QWidget* current = this;
|
||||||
|
QScrollArea* scroll_area = nullptr;
|
||||||
|
|
||||||
|
// Traverse up the parent chain to find the scroll area
|
||||||
|
while (current) {
|
||||||
|
// Check if current widget is a scroll area
|
||||||
|
if (auto* sa = qobject_cast<QScrollArea*>(current)) {
|
||||||
|
scroll_area = sa;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Check if current widget's parent is a scroll area (for viewport case)
|
||||||
|
QWidget* parent = current->parentWidget();
|
||||||
|
if (parent) {
|
||||||
|
if (auto* sa = qobject_cast<QScrollArea*>(parent)) {
|
||||||
|
scroll_area = sa;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scroll_area) {
|
||||||
|
// Forward to vertical scrollbar if available
|
||||||
|
if (scroll_area->verticalScrollBar()->maximum() > 0) {
|
||||||
|
QApplication::sendEvent(scroll_area->verticalScrollBar(), event);
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Otherwise try horizontal scrollbar
|
||||||
|
if (scroll_area->horizontalScrollBar()->maximum() > 0) {
|
||||||
|
QApplication::sendEvent(scroll_area->horizontalScrollBar(), event);
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no scroll area found, let the event propagate normally
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
|
void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
|
||||||
|
|||||||
Reference in New Issue
Block a user