diff --git a/src/citron/CMakeLists.txt b/src/citron/CMakeLists.txt
index c3b1c552d..e7b481cec 100644
--- a/src/citron/CMakeLists.txt
+++ b/src/citron/CMakeLists.txt
@@ -158,6 +158,8 @@ add_executable(citron
configuration/shared_translation.h
configuration/shared_widget.cpp
configuration/shared_widget.h
+ configuration/style_animation_event_filter.cpp
+ configuration/style_animation_event_filter.h
configuration/qt_config.cpp
configuration/qt_config.h
debugger/console.cpp
diff --git a/src/citron/configuration/configure.ui b/src/citron/configuration/configure.ui
index 6b300940f..d21be9c5e 100644
--- a/src/citron/configuration/configure.ui
+++ b/src/citron/configuration/configure.ui
@@ -1,875 +1,637 @@
- ConfigureDialog
-
-
-
- 0
- 0
- 1400
- 900
-
+ ConfigureDialog
+
+
+
+ 0
+ 0
+ 1400
+ 900
+
+
+
+
+ 0
+ 0
+
+
+
+ Qt::ApplicationModal
+
+
+ citron Configuration
+
+
+
+
+
+ QDialog {
+ background-color: %%BACKGROUND_COLOR%%;
+ color: %%TEXT_COLOR%%;
+ }
+
+ QWidget#nav_container {
+ background-color: %%SECONDARY_BG_COLOR%%;
+ border-right: 1px solid %%TERTIARY_BG_COLOR%%;
+ }
+
+ QStackedWidget {
+ background-color: transparent;
+ border: none;
+ }
+
+ QScrollArea {
+ background-color: transparent;
+ border: none;
+ }
+
+ QPushButton.tabButton {
+ background-color: transparent;
+ color: %%TEXT_COLOR%%;
+ padding: 10px;
+ padding-left: 10px;
+ margin: 0px 4px;
+ border-radius: 6px;
+ font-weight: 500;
+ border: 2px solid transparent;
+ text-align: left;
+ }
+
+ QPushButton.tabButton:hover {
+ background-color: %%HOVER_BG_COLOR%%;
+ }
+
+ QPushButton.tabButton:checked {
+ color: %%ACCENT_COLOR%%;
+ font-weight: bold;
+ background-color: %%FOCUS_BG_COLOR%%;
+ border-left: 2px solid %%ACCENT_COLOR%%;
+ }
+
+ /* All other styles remain the same... just paste this block at the top */
+
+ QWidget {
+ background-color: %%BACKGROUND_COLOR%%;
+ color: %%TEXT_COLOR%%;
+ }
+
+ QScrollBar:vertical {
+ background-color: %%SECONDARY_BG_COLOR%%;
+ width: 14px;
+ border-radius: 7px;
+ margin: 2px;
+ }
+
+ QScrollBar::handle:vertical {
+ background-color: %%TERTIARY_BG_COLOR%%;
+ border-radius: 6px;
+ min-height: 30px;
+ margin: 1px;
+ }
+
+ QScrollBar::handle:vertical:hover {
+ background-color: %%ACCENT_COLOR%%;
+ }
+
+ QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
+ border: none;
+ background: none;
+ height: 0px;
+ }
+
+ QScrollBar:horizontal {
+ background-color: %%SECONDARY_BG_COLOR%%;
+ height: 14px;
+ border-radius: 7px;
+ margin: 2px;
+ }
+
+ QScrollBar::handle:horizontal {
+ background-color: %%TERTIARY_BG_COLOR%%;
+ border-radius: 6px;
+ min-width: 30px;
+ margin: 1px;
+ }
+
+ QScrollBar::handle:horizontal:hover {
+ background-color: %%ACCENT_COLOR%%;
+ }
+
+ QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
+ border: none;
+ background: none;
+ width: 0px;
+ }
+
+ QPushButton.tabButton:pressed {
+ background-color: %%ACCENT_COLOR_PRESSED%%;
+ }
+
+ QGroupBox {
+ font-weight: bold;
+ border: 1px solid %%SECONDARY_BG_COLOR%%;
+ border-radius: 8px;
+ margin-top: 12px;
+ padding-top: 12px;
+ background-color: %%BACKGROUND_COLOR%%;
+ color: %%TEXT_COLOR%%;
+ }
+
+ QGroupBox::title {
+ subcontrol-origin: margin;
+ left: 12px;
+ padding: 0 8px 0 8px;
+ color: %%TEXT_COLOR%%;
+ font-weight: bold;
+ }
+
+ QCheckBox {
+ color: %%TEXT_COLOR%%;
+ spacing: 10px;
+ padding: 4px;
+ background-color: transparent;
+ }
+
+ QCheckBox::indicator {
+ width: 18px;
+ height: 18px;
+ border: 2px solid %%TERTIARY_BG_COLOR%%;
+ border-radius: 4px;
+ background-color: %%SECONDARY_BG_COLOR%%;
+ }
+
+ QCheckBox::indicator:checked {
+ background-color: %%ACCENT_COLOR%%;
+ border-color: %%ACCENT_COLOR%%;
+ }
+
+ QCheckBox::indicator:hover {
+ border-color: %%ACCENT_COLOR%%;
+ }
+
+ QComboBox {
+ background-color: %%SECONDARY_BG_COLOR%%;
+ border: 1px solid %%TERTIARY_BG_COLOR%%;
+ border-radius: 6px;
+ padding: 8px 12px;
+ color: %%TEXT_COLOR%%;
+ min-width: 120px;
+ min-height: 28px;
+ selection-background-color: %%ACCENT_COLOR%%;
+ }
+
+ QComboBox:hover {
+ border-color: %%ACCENT_COLOR%%;
+ background-color: %%HOVER_BG_COLOR%%;
+ }
+
+ QComboBox:focus {
+ border-color: %%ACCENT_COLOR%%;
+ background-color: %%FOCUS_BG_COLOR%%;
+ }
+
+ QComboBox::drop-down {
+ border: none;
+ width: 25px;
+ subcontrol-origin: padding;
+ subcontrol-position: top right;
+ background-color: transparent;
+ }
+
+ QComboBox QAbstractItemView {
+ background-color: %%SECONDARY_BG_COLOR%%;
+ border: 1px solid %%ACCENT_COLOR%%;
+ selection-background-color: %%ACCENT_COLOR%%;
+ color: %%TEXT_COLOR%%;
+ outline: none;
+ }
+
+ QLineEdit {
+ background-color: %%SECONDARY_BG_COLOR%%;
+ border: 1px solid %%TERTIARY_BG_COLOR%%;
+ border-radius: 6px;
+ padding: 8px 12px;
+ color: %%TEXT_COLOR%%;
+ min-height: 20px;
+ selection-background-color: %%ACCENT_COLOR%%;
+ }
+
+ QPushButton {
+ background-color: %%ACCENT_COLOR%%;
+ color: #ffffff;
+ border: none;
+ padding: 10px 20px;
+ border-radius: 6px;
+ font-weight: bold;
+ min-height: 20px;
+ }
+
+ QPushButton:hover {
+ background-color: %%ACCENT_COLOR_HOVER%%;
+ }
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 220
+
+
+ 220
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ true
-
-
- 0
- 0
-
-
-
- Qt::ApplicationModal
-
-
- citron Configuration
-
-
-
-
-
- QDialog {
- background-color: %%BACKGROUND_COLOR%%;
- color: %%TEXT_COLOR%%;
- }
-
- QWidget {
- background-color: %%BACKGROUND_COLOR%%;
- color: %%TEXT_COLOR%%;
- }
-
- QStackedWidget {
- background-color: %%BACKGROUND_COLOR%%;
- border: 1px solid %%SECONDARY_BG_COLOR%%;
- border-radius: 8px;
- margin: 0px;
- padding: 0px;
- }
-
- QScrollArea {
- background-color: %%BACKGROUND_COLOR%%;
- border: none;
- border-radius: 8px;
- }
-
- QScrollArea > QWidget > QWidget {
- background-color: %%BACKGROUND_COLOR%%;
- }
-
- QScrollBar:vertical {
- background-color: %%SECONDARY_BG_COLOR%%;
- width: 14px;
- border-radius: 7px;
- margin: 2px;
- }
-
- QScrollBar::handle:vertical {
- background-color: %%TERTIARY_BG_COLOR%%;
- border-radius: 6px;
- min-height: 30px;
- margin: 1px;
- }
-
- QScrollBar::handle:vertical:hover {
- background-color: %%ACCENT_COLOR%%;
- }
-
- QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
- border: none;
- background: none;
- height: 0px;
- }
-
- QScrollBar:horizontal {
- background-color: %%SECONDARY_BG_COLOR%%;
- height: 14px;
- border-radius: 7px;
- margin: 2px;
- }
-
- QScrollBar::handle:horizontal {
- background-color: %%TERTIARY_BG_COLOR%%;
- border-radius: 6px;
- min-width: 30px;
- margin: 1px;
- }
-
- QScrollBar::handle:horizontal:hover {
- background-color: %%ACCENT_COLOR%%;
- }
-
- QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
- border: none;
- background: none;
- width: 0px;
- }
-
- QPushButton.tabButton {
- background-color: %%BUTTON_BG_COLOR%%;
- color: %%TEXT_COLOR%%;
- padding: 10px 14px;
- margin: 2px;
- border-top-left-radius: 8px;
- border-top-right-radius: 8px;
- border-bottom-left-radius: 8px;
- border-bottom-right-radius: 8px;
- min-width: 85px;
- max-width: 160px;
- font-weight: 500;
- border: 1px solid %%SECONDARY_BG_COLOR%%;
- text-align: center;
- }
-
- QPushButton.tabButton:checked {
- background-color: %%ACCENT_COLOR%%;
- color: #ffffff;
- font-weight: bold;
- border-color: %%ACCENT_COLOR%%;
- }
-
- QPushButton.tabButton:hover:!checked {
- background-color: %%HOVER_BG_COLOR%%;
- border-color: %%TERTIARY_BG_COLOR%%;
- }
-
- QPushButton.tabButton:pressed {
- background-color: %%ACCENT_COLOR_PRESSED%%;
- }
-
- QTabWidget {
- background-color: %%BACKGROUND_COLOR%%;
- border: none;
- }
-
- QTabWidget::pane {
- border: 1px solid %%SECONDARY_BG_COLOR%%;
- background-color: %%BACKGROUND_COLOR%%;
- border-radius: 8px;
- margin: 0px;
- padding: 0px;
- }
-
- QTabWidget::tab-bar {
- alignment: left;
- }
-
- QTabBar {
- background-color: %%BACKGROUND_COLOR%%;
- border: none;
- }
-
- QTabBar::tab {
- background-color: %%BUTTON_BG_COLOR%%;
- color: %%TEXT_COLOR%%;
- padding: 12px 20px;
- margin-right: 2px;
- margin-bottom: 2px;
- border-top-left-radius: 8px;
- border-top-right-radius: 8px;
- min-width: 100px;
- font-weight: 500;
- border: 1px solid %%SECONDARY_BG_COLOR%%;
- border-bottom: none;
- }
-
- QTabBar::tab:selected {
- background-color: %%ACCENT_COLOR%%;
- color: #ffffff;
- font-weight: bold;
- border-color: %%ACCENT_COLOR%%;
- }
-
- QTabBar::tab:hover:!selected {
- background-color: %%HOVER_BG_COLOR%%;
- border-color: %%TERTIARY_BG_COLOR%%;
- }
-
- QTabBar QToolButton {
- background-color: %%BUTTON_BG_COLOR%%;
- border: 1px solid %%SECONDARY_BG_COLOR%%;
- border-radius: 4px;
- padding: 4px;
- margin: 2px;
- }
-
- QTabBar QToolButton:hover {
- background-color: %%HOVER_BG_COLOR%%;
- border-color: %%ACCENT_COLOR%%;
- }
-
- QTabBar::scroller {
- width: 30px;
- }
-
- QGroupBox {
- font-weight: bold;
- border: 1px solid %%SECONDARY_BG_COLOR%%;
- border-radius: 8px;
- margin-top: 12px;
- padding-top: 12px;
- background-color: %%BACKGROUND_COLOR%%;
- color: %%TEXT_COLOR%%;
- }
-
- QGroupBox::title {
- subcontrol-origin: margin;
- left: 12px;
- padding: 0 8px 0 8px;
- color: %%TEXT_COLOR%%;
- font-weight: bold;
- }
-
- QCheckBox {
- color: %%TEXT_COLOR%%;
- spacing: 10px;
- padding: 4px;
- background-color: transparent;
- }
-
- QCheckBox::indicator {
- width: 18px;
- height: 18px;
- border: 2px solid %%TERTIARY_BG_COLOR%%;
- border-radius: 4px;
- background-color: %%SECONDARY_BG_COLOR%%;
- }
-
- QCheckBox::indicator:checked {
- background-color: %%ACCENT_COLOR%%;
- border-color: %%ACCENT_COLOR%%;
- }
-
- QCheckBox::indicator:hover {
- border-color: %%ACCENT_COLOR%%;
- }
-
- QComboBox {
- background-color: %%SECONDARY_BG_COLOR%%;
- border: 1px solid %%TERTIARY_BG_COLOR%%;
- border-radius: 6px;
- padding: 8px 12px;
- color: %%TEXT_COLOR%%;
- min-width: 120px;
- min-height: 28px;
- selection-background-color: %%ACCENT_COLOR%%;
- }
-
- QComboBox:hover {
- border-color: %%ACCENT_COLOR%%;
- background-color: %%HOVER_BG_COLOR%%;
- }
-
- QComboBox:focus {
- border-color: %%ACCENT_COLOR%%;
- background-color: %%FOCUS_BG_COLOR%%;
- }
-
- QComboBox::drop-down {
- border: none;
- width: 25px;
- subcontrol-origin: padding;
- subcontrol-position: top right;
- background-color: transparent;
- }
-
-
- QComboBox QAbstractItemView {
- background-color: %%SECONDARY_BG_COLOR%%;
- border: 1px solid %%ACCENT_COLOR%%;
- selection-background-color: %%ACCENT_COLOR%%;
- color: %%TEXT_COLOR%%;
- outline: none;
- }
-
- QComboBox QAbstractItemView::item {
- padding: 8px;
- border: none;
- background-color: transparent;
- }
-
- QComboBox QAbstractItemView::item:selected {
- background-color: %%ACCENT_COLOR%%;
- color: #ffffff;
- }
-
- QComboBox QAbstractItemView::item:hover {
- background-color: %%ACCENT_COLOR_HOVER%%;
- color: #ffffff;
- }
-
- QLineEdit {
- background-color: %%SECONDARY_BG_COLOR%%;
- border: 1px solid %%TERTIARY_BG_COLOR%%;
- border-radius: 6px;
- padding: 8px 12px;
- color: %%TEXT_COLOR%%;
- min-height: 20px;
- selection-background-color: %%ACCENT_COLOR%%;
- }
-
- QLineEdit:focus {
- border-color: %%ACCENT_COLOR%%;
- background-color: %%FOCUS_BG_COLOR%%;
- }
-
- QPushButton {
- background-color: %%ACCENT_COLOR%%;
- color: #ffffff;
- border: none;
- padding: 10px 20px;
- border-radius: 6px;
- font-weight: bold;
- min-height: 20px;
- }
-
- QPushButton:hover {
- background-color: %%ACCENT_COLOR_HOVER%%;
- }
-
- QPushButton:pressed {
- background-color: %%ACCENT_COLOR_PRESSED%%;
- }
-
- QPushButton:disabled {
- background-color: %%TERTIARY_BG_COLOR%%;
- color: %%DISABLED_TEXT_COLOR%%;
- }
-
- QToolButton {
- background-color: %%ACCENT_COLOR%%;
- color: #ffffff;
- border: none;
- padding: 8px 12px;
- border-radius: 6px;
- font-weight: bold;
- min-width: 32px;
- min-height: 24px;
- }
-
- QToolButton:hover {
- background-color: %%ACCENT_COLOR_HOVER%%;
- }
-
- QToolButton:pressed {
- background-color: %%ACCENT_COLOR_PRESSED%%;
- }
-
- QLabel {
- color: %%TEXT_COLOR%%;
- background-color: transparent;
- padding: 2px;
- }
-
- QListWidget {
- background-color: %%SECONDARY_BG_COLOR%%;
- border: 1px solid %%TERTIARY_BG_COLOR%%;
- border-radius: 6px;
- color: %%TEXT_COLOR%%;
- padding: 4px;
- }
-
- QListWidget::item {
- padding: 8px;
- border-radius: 4px;
- margin: 1px;
- }
-
- QListWidget::item:selected {
- background-color: %%ACCENT_COLOR%%;
- color: #ffffff;
- }
-
- QListWidget::item:hover:!selected {
- background-color: %%HOVER_BG_COLOR%%;
- }
-
- QSlider::groove:horizontal {
- border: 1px solid %%TERTIARY_BG_COLOR%%;
- height: 8px;
- background-color: %%SECONDARY_BG_COLOR%%;
- border-radius: 4px;
- }
-
- QSlider::handle:horizontal {
- background-color: %%ACCENT_COLOR%%;
- border: 1px solid %%ACCENT_COLOR%%;
- width: 18px;
- margin: -5px 0;
- border-radius: 9px;
- }
-
- QSlider::handle:horizontal:hover {
- background-color: %%ACCENT_COLOR_HOVER%%;
- }
-
- QSpinBox, QDoubleSpinBox {
- background-color: %%SECONDARY_BG_COLOR%%;
- border: 1px solid %%TERTIARY_BG_COLOR%%;
- border-radius: 6px;
- padding: 6px;
- color: %%TEXT_COLOR%%;
- min-height: 20px;
- }
-
- QSpinBox:focus, QDoubleSpinBox:focus {
- border-color: %%ACCENT_COLOR%%;
- background-color: %%FOCUS_BG_COLOR%%;
- }
-
- QRadioButton {
- color: %%TEXT_COLOR%%;
- spacing: 8px;
- padding: 4px;
- }
-
- QRadioButton::indicator {
- width: 16px;
- height: 16px;
- border: 2px solid %%TERTIARY_BG_COLOR%%;
- border-radius: 8px;
- background-color: %%SECONDARY_BG_COLOR%%;
- }
-
- QRadioButton::indicator:checked {
- background-color: %%ACCENT_COLOR%%;
- border-color: %%ACCENT_COLOR%%;
- }
-
- QRadioButton::indicator:hover {
- border-color: %%ACCENT_COLOR%%;
- }
-
- /* High DPI specific styles */
- @media (min-resolution: 192dpi) {
- QPushButton.tabButton {
- padding: 12px 16px;
- min-width: 90px;
- max-width: 170px;
- font-size: 14px;
- }
-
- QComboBox {
- min-width: 140px;
- min-height: 32px;
- padding: 10px 14px;
- }
-
- QLineEdit {
- min-height: 24px;
- padding: 10px 14px;
- }
-
- QPushButton {
- min-height: 24px;
- padding: 12px 24px;
- }
-
- QCheckBox::indicator {
- width: 20px;
- height: 20px;
- }
-
- QRadioButton::indicator {
- width: 18px;
- height: 18px;
- }
- }
-
- @media (min-resolution: 240dpi) {
- QPushButton.tabButton {
- padding: 14px 18px;
- min-width: 95px;
- max-width: 180px;
- font-size: 16px;
- }
-
- QComboBox {
- min-width: 160px;
- min-height: 36px;
- padding: 12px 16px;
- }
-
- QLineEdit {
- min-height: 28px;
- padding: 12px 16px;
- }
-
- QPushButton {
- min-height: 28px;
- padding: 14px 28px;
- }
-
- QCheckBox::indicator {
- width: 22px;
- height: 22px;
- }
-
- QRadioButton::indicator {
- width: 20px;
- height: 20px;
- }
- }
-
-
-
-
- 8
+
+
+
+ 0
+ 0
+ 220
+ 856
+
+
+
+
-
+
+
+ General
-
- 12
+
+ true
-
- 12
+
+ true
-
- 12
+
+ tabButton
-
- 12
+
+
+ -
+
+
+ UI
-
-
-
-
- 8
-
-
-
-
-
-
- 0
- 0
-
-
-
- Qt::ScrollBarAlwaysOff
-
-
- Qt::ScrollBarAsNeeded
-
-
- true
-
-
-
-
- 0
- 0
- 1376
- 51
-
-
-
-
- 4
-
-
-
-
-
- General
-
-
- true
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- UI
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- System
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- CPU
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Graphics
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Graphics (Adv)
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Audio
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Input
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Hotkeys
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Network
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Web
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Filesystem
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Profiles
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Applets
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Logging
-
-
- true
-
-
- tabButton
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
-
-
- -
-
-
- true
-
-
-
-
- 0
- 0
- 1376
- 745
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- 0
-
-
-
-
-
-
-
-
-
- -
-
-
- 12
-
-
- 8
-
-
- 8
-
-
- 8
-
-
- 0
-
-
-
-
-
- QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
-
-
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ System
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ CPU
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ Graphics
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ Graphics (Adv)
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ Audio
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ Input
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ Hotkeys
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ Network
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ Web
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ Filesystem
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ Profiles
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ Applets
+
+
+ true
+
+
+ tabButton
+
+
+
+ -
+
+
+ Logging
+
+
+ true
+
+
+ tabButton
+
+
+
+
+
+
+
+
-
-
-
- buttonBox
- accepted()
- ConfigureDialog
- accept()
-
-
- 20
- 20
-
-
- 20
- 20
-
-
-
-
- buttonBox
- rejected()
- ConfigureDialog
- reject()
-
-
- 20
- 20
-
-
- 20
- 20
-
-
-
-
+
+ -
+
+
+ 8
+
+
+ 12
+
+
+ 12
+
+
+ 12
+
+
+ 12
+
+
-
+
+
+
+ 16777215
+ 55
+
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 1168
+ 55
+
+
+
+
+
+
+ -
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 1168
+ 777
+
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 0
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ ConfigureDialog
+ accept()
+
+
+ 20
+ 20
+
+
+ 20
+ 20
+
+
+
+
+ buttonBox
+ rejected()
+ ConfigureDialog
+ reject()
+
+
+ 20
+ 20
+
+
+ 20
+ 20
+
+
+
+
diff --git a/src/citron/configuration/configure_dialog.cpp b/src/citron/configuration/configure_dialog.cpp
index 545c8f878..3e60d1cae 100644
--- a/src/citron/configuration/configure_dialog.cpp
+++ b/src/citron/configuration/configure_dialog.cpp
@@ -14,7 +14,7 @@
#include
#include
#include
-#include
+#include
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/settings_enums.h"
@@ -38,89 +38,29 @@
#include "citron/configuration/configure_system.h"
#include "citron/configuration/configure_ui.h"
#include "citron/configuration/configure_web.h"
+#include "citron/configuration/style_animation_event_filter.h"
#include "citron/hotkeys.h"
#include "citron/theme.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(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) {
auto* scroll_area = new QScrollArea();
scroll_area->setWidget(widget);
scroll_area->setWidgetResizable(true);
scroll_area->setFrameShape(QFrame::NoFrame);
- scroll_area->setHorizontalScrollBarPolicy(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;
}
-// Helper function to detect if the application should be in a dark theme state
static bool IsDarkMode() {
const std::string& theme_name = UISettings::values.theme;
-
- // Priority 1: Check for explicitly chosen dark themes.
if (theme_name == "qdarkstyle" || theme_name == "colorful_dark" ||
theme_name == "qdarkstyle_midnight_blue" || theme_name == "colorful_midnight_blue") {
return true;
}
-
- // Priority 2: Check for adaptive themes ("default" and "colorful").
- // For these, we fall back to checking the OS palette.
if (theme_name == "default" || theme_name == "colorful") {
- const QPalette palette = qApp->palette();
- const QColor text_color = palette.color(QPalette::WindowText);
- const QColor base_color = palette.color(QPalette::Window);
- return text_color.value() > base_color.value();
+ return qApp->palette().color(QPalette::WindowText).value() >
+ qApp->palette().color(QPalette::Window).value();
}
-
- // Fallback for any other unknown theme (assumed light).
return false;
}
@@ -128,61 +68,60 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_,
InputCommon::InputSubsystem* input_subsystem,
std::vector& vk_device_records,
Core::System& system_, bool enable_web_config)
-: QDialog(parent), ui{std::make_unique()},
-registry(registry_), system{system_}, builder{std::make_unique(
- this, !system_.IsPoweredOn())},
- applets_tab{std::make_unique(system_, nullptr, *builder, this)},
- audio_tab{std::make_unique(system_, nullptr, *builder, this)},
- cpu_tab{std::make_unique(system_, nullptr, *builder, this)},
- debug_tab_tab{std::make_unique(system_, this)},
- filesystem_tab{std::make_unique(this)},
- general_tab{std::make_unique(system_, nullptr, *builder, this)},
- graphics_advanced_tab{
- std::make_unique(system_, nullptr, *builder, this)},
- ui_tab{std::make_unique(system_, this)},
- graphics_tab{std::make_unique(
- system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
- [this](Settings::AspectRatio ratio, Settings::ResolutionSetup setup) {
- ui_tab->UpdateScreenshotInfo(ratio, setup);
- },
- nullptr, *builder, this)},
-hotkeys_tab{std::make_unique(system_.HIDCore(), this)},
-input_tab{std::make_unique(system_, this)},
-network_tab{std::make_unique(system_, this)},
-profile_tab{std::make_unique(system_, this)},
-system_tab{std::make_unique(system_, nullptr, *builder, this)},
-web_tab{std::make_unique(this)},
-rainbow_timer{new QTimer(this)} {
+ : QDialog(parent), ui{std::make_unique()}, registry(registry_),
+ system{system_},
+ builder{std::make_unique(this, !system_.IsPoweredOn())},
+ applets_tab{std::make_unique(system_, nullptr, *builder, this)},
+ audio_tab{std::make_unique(system_, nullptr, *builder, this)},
+ cpu_tab{std::make_unique(system_, nullptr, *builder, this)},
+ debug_tab_tab{std::make_unique(system_, this)},
+ filesystem_tab{std::make_unique(this)},
+ general_tab{std::make_unique(system_, nullptr, *builder, this)},
+ graphics_advanced_tab{
+ std::make_unique(system_, nullptr, *builder, this)},
+ ui_tab{std::make_unique(system_, this)},
+ graphics_tab{std::make_unique(
+ system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); },
+ [this](Settings::AspectRatio ratio, Settings::ResolutionSetup setup) {
+ ui_tab->UpdateScreenshotInfo(ratio, setup);
+ },
+ nullptr, *builder, this)},
+ hotkeys_tab{std::make_unique(system_.HIDCore(), this)},
+ input_tab{std::make_unique(system_, this)},
+ network_tab{std::make_unique(system_, this)},
+ profile_tab{std::make_unique(system_, this)},
+ system_tab{std::make_unique(system_, nullptr, *builder, this)},
+ web_tab{std::make_unique(this)}, rainbow_timer{new QTimer(this)} {
Settings::SetConfiguringGlobal(true);
-
setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::WindowSystemMenuHint |
- Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
-
- setAttribute(Qt::WA_TranslucentBackground, false);
- setAttribute(Qt::WA_NoSystemBackground, false);
- setAttribute(Qt::WA_DontShowOnScreen, false);
-
+ Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
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);
+ auto* animation_filter = new StyleAnimationEventFilter(this);
+ const auto button_qlist = ui->topButtonWidget->findChildren();
+ tab_buttons = std::vector(button_qlist.begin(), button_qlist.end());
+ auto* nav_layout = new QVBoxLayout();
+ nav_layout->setContentsMargins(8, 8, 8, 8);
+ nav_layout->setSpacing(4);
+ for (QPushButton* button : tab_buttons) {
+ button->setParent(ui->topButtonWidget);
+ // Buttons are added to a layout in SetUIPositioning
+ if (button->property("class").toString() == QStringLiteral("tabButton")) {
+ button->installEventFilter(animation_filter);
+ }
+ }
+ delete ui->topButtonWidget->layout();
+ ui->topButtonWidget->setLayout(nav_layout);
last_palette_text_color = qApp->palette().color(QPalette::WindowText);
-
if (!UISettings::values.configure_dialog_geometry.isEmpty()) {
restoreGeometry(UISettings::values.configure_dialog_geometry);
}
-
UpdateTheme();
- setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-
tab_button_group = std::make_unique(this);
tab_button_group->setExclusive(true);
-
tab_button_group->addButton(ui->generalTabButton, 0);
tab_button_group->addButton(ui->uiTabButton, 1);
tab_button_group->addButton(ui->systemTabButton, 2);
@@ -217,36 +156,25 @@ rainbow_timer{new QTimer(this)} {
connect(tab_button_group.get(), qOverload(&QButtonGroup::idClicked), this, [this](int id) {
ui->stackedWidget->setCurrentIndex(id);
- if (id == 14) {
- debug_tab_tab->SetCurrentIndex(0);
- }
});
-
connect(ui_tab.get(), &ConfigureUi::themeChanged, this, &ConfigureDialog::UpdateTheme);
+ connect(ui_tab.get(), &ConfigureUi::UIPositioningChanged, this, &ConfigureDialog::SetUIPositioning);
connect(rainbow_timer, &QTimer::timeout, this, &ConfigureDialog::UpdateTheme);
-
web_tab->SetWebServiceConfigEnabled(enable_web_config);
hotkeys_tab->Populate(registry);
-
input_tab->Initialize(input_subsystem);
-
general_tab->SetResetCallback([&] { this->close(); });
-
SetConfiguration();
-
connect(ui_tab.get(), &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged);
-
if (system.IsPoweredOn()) {
- QPushButton* apply_button = ui->buttonBox->button(QDialogButtonBox::Apply);
- if (apply_button) {
- connect(apply_button, &QAbstractButton::clicked, this,
- &ConfigureDialog::HandleApplyButtonClicked);
+ if (auto* apply_button = ui->buttonBox->button(QDialogButtonBox::Apply)) {
+ connect(apply_button, &QAbstractButton::clicked, this, &ConfigureDialog::HandleApplyButtonClicked);
}
}
-
ui->stackedWidget->setCurrentIndex(0);
ui->generalTabButton->setChecked(true);
- ui->buttonBox->setFocus();
+
+ SetUIPositioning(QString::fromStdString(UISettings::values.ui_positioning.GetValue()));
}
ConfigureDialog::~ConfigureDialog() {
@@ -257,25 +185,17 @@ void ConfigureDialog::UpdateTheme() {
QString accent_color_str;
if (UISettings::values.enable_rainbow_mode.GetValue()) {
rainbow_hue += 0.003f;
- if (rainbow_hue > 1.0f) {
- rainbow_hue = 0.0f;
- }
+ if (rainbow_hue > 1.0f) rainbow_hue = 0.0f;
QColor accent_color = QColor::fromHsvF(rainbow_hue, 0.8f, 1.0f);
accent_color_str = accent_color.name(QColor::HexRgb);
- if (!rainbow_timer->isActive()) {
- rainbow_timer->start(150);
- }
+ if (!rainbow_timer->isActive()) rainbow_timer->start(150);
} else {
- if (rainbow_timer->isActive()) {
- rainbow_timer->stop();
- }
+ if (rainbow_timer->isActive()) rainbow_timer->stop();
accent_color_str = Theme::GetAccentColor();
}
-
QColor accent_color(accent_color_str);
const QString accent_color_hover = accent_color.lighter(115).name(QColor::HexRgb);
const QString accent_color_pressed = accent_color.darker(120).name(QColor::HexRgb);
-
const bool is_dark = IsDarkMode();
const QString bg_color = is_dark ? QStringLiteral("#2b2b2b") : QStringLiteral("#ffffff");
const QString text_color = is_dark ? QStringLiteral("#ffffff") : QStringLiteral("#000000");
@@ -285,20 +205,14 @@ void ConfigureDialog::UpdateTheme() {
const QString hover_bg_color = is_dark ? QStringLiteral("#4d4d4d") : QStringLiteral("#e8f0fe");
const QString focus_bg_color = is_dark ? QStringLiteral("#404040") : QStringLiteral("#e8f0fe");
const QString disabled_text_color = is_dark ? QStringLiteral("#8d8d8d") : QStringLiteral("#a0a0a0");
-
static QString cached_template_style_sheet;
if (cached_template_style_sheet.isEmpty()) {
cached_template_style_sheet = property("templateStyleSheet").toString();
}
-
QString style_sheet = cached_template_style_sheet;
-
- // Replace accent colors (existing logic)
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR%%"), accent_color_str);
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR_HOVER%%"), accent_color_hover);
style_sheet.replace(QStringLiteral("%%ACCENT_COLOR_PRESSED%%"), accent_color_pressed);
-
- // Replace base theme colors (new logic)
style_sheet.replace(QStringLiteral("%%BACKGROUND_COLOR%%"), bg_color);
style_sheet.replace(QStringLiteral("%%TEXT_COLOR%%"), text_color);
style_sheet.replace(QStringLiteral("%%SECONDARY_BG_COLOR%%"), secondary_bg_color);
@@ -307,10 +221,7 @@ void ConfigureDialog::UpdateTheme() {
style_sheet.replace(QStringLiteral("%%HOVER_BG_COLOR%%"), hover_bg_color);
style_sheet.replace(QStringLiteral("%%FOCUS_BG_COLOR%%"), focus_bg_color);
style_sheet.replace(QStringLiteral("%%DISABLED_TEXT_COLOR%%"), disabled_text_color);
-
setStyleSheet(style_sheet);
-
- // This part is crucial to pass the theme to child tabs
graphics_tab->SetTemplateStyleSheet(style_sheet);
system_tab->SetTemplateStyleSheet(style_sheet);
audio_tab->SetTemplateStyleSheet(style_sheet);
@@ -318,6 +229,50 @@ void ConfigureDialog::UpdateTheme() {
graphics_advanced_tab->SetTemplateStyleSheet(style_sheet);
}
+void ConfigureDialog::SetUIPositioning(const QString& positioning) {
+ auto* v_layout = qobject_cast(ui->topButtonWidget->layout());
+ auto* h_layout = qobject_cast(ui->horizontalNavWidget->layout());
+
+ if (!v_layout || !h_layout) {
+ LOG_ERROR(Frontend, "Could not find navigation layouts to rearrange");
+ return;
+ }
+
+ if (positioning == QStringLiteral("Horizontal")) {
+ ui->nav_container->hide();
+ ui->horizontalNavScrollArea->show();
+ // Remove stretch from vertical layout if it exists
+ if (v_layout->count() > 0) {
+ if (auto* item = v_layout->itemAt(v_layout->count() - 1); item && item->spacerItem()) {
+ v_layout->takeAt(v_layout->count() - 1);
+ delete item;
+ }
+ }
+ for (QPushButton* button : tab_buttons) {
+ v_layout->removeWidget(button);
+ h_layout->addWidget(button);
+ button->setStyleSheet(QStringLiteral("text-align: center;"));
+ }
+ h_layout->addStretch(1);
+ } else { // Vertical
+ ui->horizontalNavScrollArea->hide();
+ ui->nav_container->show();
+ // Remove stretch from horizontal layout if it exists
+ if (h_layout->count() > 0) {
+ if (auto* item = h_layout->itemAt(h_layout->count() - 1); item && item->spacerItem()) {
+ h_layout->takeAt(h_layout->count() - 1);
+ delete item;
+ }
+ }
+ for (QPushButton* button : tab_buttons) {
+ h_layout->removeWidget(button);
+ v_layout->addWidget(button);
+ button->setStyleSheet(QStringLiteral("")); // Reset to parent stylesheet
+ }
+ v_layout->addStretch(1);
+ }
+}
+
void ConfigureDialog::SetConfiguration() {}
void ConfigureDialog::ApplyConfiguration() {
@@ -344,23 +299,18 @@ void ConfigureDialog::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
-
if (event->type() == QEvent::PaletteChange) {
- const QColor current_color = qApp->palette().color(QPalette::WindowText);
- if (current_color != last_palette_text_color) {
- last_palette_text_color = current_color;
+ if (qApp->palette().color(QPalette::WindowText) != last_palette_text_color) {
+ last_palette_text_color = qApp->palette().color(QPalette::WindowText);
UpdateTheme();
}
}
-
QDialog::changeEvent(event);
}
void ConfigureDialog::RetranslateUI() {
const int old_index = ui->stackedWidget->currentIndex();
-
ui->retranslateUi(this);
-
SetConfiguration();
ui->stackedWidget->setCurrentIndex(old_index);
}
diff --git a/src/citron/configuration/configure_dialog.h b/src/citron/configuration/configure_dialog.h
index 409dab386..45bbd0073 100644
--- a/src/citron/configuration/configure_dialog.h
+++ b/src/citron/configuration/configure_dialog.h
@@ -9,24 +9,17 @@
#include
#include
#include "common/settings_enums.h"
-#include "citron/configuration/shared_widget.h" // <-- Correct header for Builder
+#include "citron/configuration/shared_widget.h"
-// Forward declarations for other types
+// Forward declarations
class HotkeyRegistry;
class QButtonGroup;
+class QPushButton;
class QTimer;
-namespace InputCommon {
- class InputSubsystem;
-}
-namespace Core {
- class System;
-}
-namespace VkDeviceInfo {
- class Record;
-}
-namespace Ui {
- class ConfigureDialog;
-}
+namespace InputCommon { class InputSubsystem; }
+namespace Core { class System; }
+namespace VkDeviceInfo { class Record; }
+namespace Ui { class ConfigureDialog; }
class ConfigureApplets;
class ConfigureAudio;
class ConfigureCpu;
@@ -62,18 +55,17 @@ public slots:
signals:
void LanguageChanged(const QString& locale);
+private slots:
+ void SetUIPositioning(const QString& positioning);
+
private:
void SetConfiguration();
void HandleApplyButtonClicked();
-
void changeEvent(QEvent* event) override;
void RetranslateUI();
-
void OnLanguageChanged(const QString& locale);
QColor last_palette_text_color;
-
- // All members are now in the EXACT correct order to match the constructor
std::unique_ptr ui;
HotkeyRegistry& registry;
Core::System& system;
@@ -94,6 +86,7 @@ private:
std::unique_ptr system_tab;
std::unique_ptr web_tab;
std::unique_ptr tab_button_group;
+ std::vector tab_buttons;
QTimer* rainbow_timer;
float rainbow_hue = 0.0f;
};
diff --git a/src/citron/configuration/configure_ui.cpp b/src/citron/configuration/configure_ui.cpp
index da8e6ba85..3ab3673ca 100644
--- a/src/citron/configuration/configure_ui.cpp
+++ b/src/citron/configuration/configure_ui.cpp
@@ -17,6 +17,8 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -115,6 +117,19 @@ resolution_setting{Settings::values.resolution_setup.GetValue()}, system{system_
QString::fromUtf8(theme.second));
}
+ ui_positioning_combo = new QComboBox(this);
+ ui_positioning_combo->addItem(tr("Vertical"), QStringLiteral("Vertical"));
+ ui_positioning_combo->addItem(tr("Horizontal"), QStringLiteral("Horizontal"));
+ if (auto* layout = qobject_cast(ui->theme_combobox->parentWidget()->layout())) {
+ layout->addRow(tr("UI Positioning"), ui_positioning_combo);
+ } else if (auto* group_layout = qobject_cast(ui->theme_combobox->parentWidget()->layout())) {
+ group_layout->addWidget(ui_positioning_combo);
+ }
+
+ connect(ui_positioning_combo, &QComboBox::currentTextChanged, this, [this](const QString& text){
+ emit UIPositioningChanged(text);
+ });
+
InitializeIconSizeComboBox();
InitializeRowComboBoxes();
@@ -174,6 +189,7 @@ ConfigureUi::~ConfigureUi() = default;
void ConfigureUi::ApplyConfiguration() {
UISettings::values.theme =
ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString().toStdString();
+ UISettings::values.ui_positioning = ui_positioning_combo->currentData().toString().toStdString();
UISettings::values.enable_rainbow_mode = ui->rainbowModeCheckBox->isChecked();
UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
UISettings::values.show_compat = ui->show_compat->isChecked();
@@ -205,6 +221,8 @@ void ConfigureUi::SetConfiguration() {
ui->theme_combobox->findData(QString::fromStdString(UISettings::values.theme)));
ui->language_combobox->setCurrentIndex(ui->language_combobox->findData(
QString::fromStdString(UISettings::values.language.GetValue())));
+ ui_positioning_combo->setCurrentIndex(ui_positioning_combo->findData(
+ QString::fromStdString(UISettings::values.ui_positioning.GetValue())));
ui->rainbowModeCheckBox->setChecked(UISettings::values.enable_rainbow_mode.GetValue());
ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue());
ui->show_compat->setChecked(UISettings::values.show_compat.GetValue());
@@ -252,6 +270,11 @@ void ConfigureUi::changeEvent(QEvent* event) {
void ConfigureUi::RetranslateUI() {
ui->retranslateUi(this);
+ const int pos_index = ui_positioning_combo->currentIndex();
+ ui_positioning_combo->setItemText(0, tr("Vertical"));
+ ui_positioning_combo->setItemText(1, tr("Horizontal"));
+ ui_positioning_combo->setCurrentIndex(pos_index);
+
for (int i = 0; i < ui->game_icon_size_combobox->count(); i++) {
ui->game_icon_size_combobox->setItemText(i,
GetTranslatedGameIconSize(static_cast(i)));
diff --git a/src/citron/configuration/configure_ui.h b/src/citron/configuration/configure_ui.h
index a66c12cb9..6f2b4e2cc 100644
--- a/src/citron/configuration/configure_ui.h
+++ b/src/citron/configuration/configure_ui.h
@@ -8,6 +8,8 @@
#include
#include "common/settings_enums.h"
+class QComboBox;
+
namespace Core {
class System;
}
@@ -31,6 +33,7 @@ public:
signals:
void LanguageChanged(const QString& locale);
void themeChanged();
+ void UIPositioningChanged(const QString& positioning);
private slots:
void OnLanguageChanged(int index);
@@ -54,6 +57,7 @@ private:
void UpdateWidthText();
std::unique_ptr ui;
+ QComboBox* ui_positioning_combo;
Settings::AspectRatio ratio;
Settings::ResolutionSetup resolution_setting;
diff --git a/src/citron/configuration/style_animation_event_filter.cpp b/src/citron/configuration/style_animation_event_filter.cpp
new file mode 100644
index 000000000..eafb74641
--- /dev/null
+++ b/src/citron/configuration/style_animation_event_filter.cpp
@@ -0,0 +1,20 @@
+// SPDX-FileCopyrightText: 2016 Citra Emulator Project
+// SPDX-FileCopyrightText: 2025 citron Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "citron/configuration/style_animation_event_filter.h"
+#include
+#include
+#include
+
+StyleAnimationEventFilter::StyleAnimationEventFilter(QObject* parent) : QObject(parent) {}
+
+bool StyleAnimationEventFilter::eventFilter(QObject* obj, QEvent* event) {
+ if (event->type() == QEvent::Enter || event->type() == QEvent::Leave) {
+ if (auto* widget = qobject_cast(obj)) {
+ // Trigger style update for hover effects
+ widget->update();
+ }
+ }
+ return QObject::eventFilter(obj, event);
+}
diff --git a/src/citron/configuration/style_animation_event_filter.h b/src/citron/configuration/style_animation_event_filter.h
new file mode 100644
index 000000000..1502d96ff
--- /dev/null
+++ b/src/citron/configuration/style_animation_event_filter.h
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: 2016 Citra Emulator Project
+// SPDX-FileCopyrightText: 2025 citron Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include
+
+class StyleAnimationEventFilter : public QObject {
+ Q_OBJECT
+
+public:
+ explicit StyleAnimationEventFilter(QObject* parent = nullptr);
+
+protected:
+ bool eventFilter(QObject* obj, QEvent* event) override;
+};
diff --git a/src/citron/uisettings.h b/src/citron/uisettings.h
index 682339793..a375f9b43 100644
--- a/src/citron/uisettings.h
+++ b/src/citron/uisettings.h
@@ -169,6 +169,7 @@ namespace UISettings {
Setting language{linkage, {}, "language", Category::Paths};
std::string theme;
+ Setting ui_positioning{linkage, "Vertical", "ui_positioning", Category::Ui};
Setting accent_color{linkage, "#4a9eff", "accent_color", Category::Ui};
Setting enable_rainbow_mode{linkage, false, "enable_rainbow_mode", Category::Ui};