[Accessibility] Bind card size sliders to Ctrl + Scroll

Ctrl+scroll over a card display now resizes the cards everywhere a card
size slider is shown, matching the standard way of resizing content.

CardSizeWidget learns to forward Ctrl+wheel events onto its slider via an
event filter that is installed on the display container and, when present,
on the scroll area's content widget so the resize intercepts the wheel
event before the view scrolls. The existing slider valueChanged wiring
then rescales the displayed cards.

Applied to the visual deck editor (per card group, covering flat and
overlapped layouts), visual database display, printing selector, sample
hand, visual and public deck storage, Archidekt previews and EDHRec card
displays.
This commit is contained in:
Lukas Brübach 2026-09-21 13:45:19 +02:00
parent 7a2492ac67
commit 5cfa97a117
12 changed files with 95 additions and 0 deletions

View file

@ -38,6 +38,8 @@ CardGroupDisplayWidget::CardGroupDisplayWidget(QWidget *parent,
}
connect(deckListModel, &QAbstractItemModel::rowsRemoved, this, &CardGroupDisplayWidget::onCardRemoval);
connect(deckListModel, &QAbstractItemModel::dataChanged, this, &CardGroupDisplayWidget::onDataChanged);
cardSizeWidget->enableCtrlScrollResize(this);
}
// Just here so it can get overwritten in subclasses.

View file

@ -3,6 +3,9 @@
#include "../printing_selector/printing_selector.h"
#include "../visual_deck_storage/visual_deck_storage_widget.h"
#include <QScrollArea>
#include <QWheelEvent>
/**
* @class CardSizeWidget
* @brief A widget for adjusting card sizes using a slider.
@ -58,3 +61,54 @@ QSlider *CardSizeWidget::getSlider() const
{
return cardSizeSlider;
}
/**
* @brief Resizes the cards on a Ctrl + scroll anywhere over the given host widget.
*
* The filter is installed on the host itself and, when the host contains a scroll
* area, on the scroll area's content widget. Filtering the content widget makes sure
* the resize still sees the wheel event before the surrounding scroll area scrolls.
*
* @param host The widget over which Ctrl + scroll should resize the cards.
*/
void CardSizeWidget::enableCtrlScrollResize(QWidget *host)
{
host->installEventFilter(this);
const auto scrollAreas = host->findChildren<QScrollArea *>();
for (QScrollArea *scrollArea : scrollAreas) {
if (QWidget *content = scrollArea->widget()) {
content->installEventFilter(this);
}
}
}
bool CardSizeWidget::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::Wheel && adjustSliderForWheel(static_cast<QWheelEvent *>(event))) {
return true;
}
return QWidget::eventFilter(watched, event);
}
/**
* @brief Adjusts the card size slider for a Ctrl + scroll wheel event.
*
* @param event The wheel event to examine.
* @return True if the event was handled (card size was changed), false otherwise.
*/
bool CardSizeWidget::adjustSliderForWheel(QWheelEvent *event)
{
if (!(event->modifiers() & Qt::ControlModifier)) {
return false;
}
const int angleDelta = event->angleDelta().y();
if (angleDelta == 0) {
return false;
}
const int wheelSteps = angleDelta > 0 ? qMax(1, angleDelta / 120) : qMin(-1, angleDelta / 120);
cardSizeSlider->setValue(cardSizeSlider->value() + wheelSteps * CARD_SIZE_WHEEL_STEP);
return true;
}

View file

@ -17,6 +17,8 @@
#include <QTimer>
#include <QWidget>
class QWheelEvent;
class CardSizeWidget : public QWidget
{
Q_OBJECT
@ -25,6 +27,18 @@ public:
explicit CardSizeWidget(QWidget *parent, FlowWidget *flowWidget = nullptr, int defaultValue = 100);
[[nodiscard]] QSlider *getSlider() const;
/**
* @brief Resizes the cards when the user Ctrl + scrolls over @p host or any of its descendants.
*
* Installs this widget as an event filter on the given host widget. If the host contains a
* scroll area the filter is also installed on the scroll area's content widget, so the resize
* intercepts the wheel event before the scroll area would scroll the view.
*/
void enableCtrlScrollResize(QWidget *host);
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
private slots:
void updateCardSizeSetting(int newValue);
@ -44,6 +58,10 @@ private:
QSlider *cardSizeSlider;
QTimer debounceTimer; // Debounce timer
int pendingValue; // Stores the latest slider value
bool adjustSliderForWheel(QWheelEvent *event);
static constexpr int CARD_SIZE_WHEEL_STEP = 10; ///< Slider step applied per Ctrl + scroll notch.
};
#endif // CARD_SIZE_WIDGET_H

View file

@ -58,6 +58,7 @@ PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deck
SettingsCache::instance().cardsDisplay().getPrintingSelectorCardSize());
connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance().cardsDisplay(),
&CardsDisplaySettings::setPrintingSelectorCardSize);
cardSizeWidget->enableCtrlScrollResize(flowWidget);
displayOptionsWidget->addSettingsWidget(sortToolBar);
displayOptionsWidget->addSettingsWidget(navigationCheckBox);

View file

@ -15,6 +15,8 @@ ArchidektApiResponseDeckListingsDisplayWidget::ArchidektApiResponseDeckListingsD
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
cardSizeSlider->enableCtrlScrollResize(flowWidget);
imageNetworkManager = new QNetworkAccessManager(this);
imageNetworkManager->setTransferTimeout(); // Use Qt's default timeout
imageNetworkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);

View file

@ -54,6 +54,7 @@ EdhrecApiResponseCardDetailsDisplayWidget::EdhrecApiResponseCardDetailsDisplayWi
&CardInfoPictureWidget::setScaleFactor);
connect(this, &EdhrecApiResponseCardDetailsDisplayWidget::requestUrl, parentTab,
&TabEdhRecMain::actNavigatePage);
parentTab->getCardSizeSlider()->enableCtrlScrollResize(this);
}
}

View file

@ -38,6 +38,7 @@ EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCom
connect(parentTab->getCardSizeSlider()->getSlider(), &QSlider::valueChanged, commanderPicture,
&CardInfoPictureWidget::setScaleFactor);
commanderPicture->setScaleFactor(parentTab->getCardSizeSlider()->getSlider()->value());
parentTab->getCardSizeSlider()->enableCtrlScrollResize(this);
}
commanderDetails.debugPrint();

View file

@ -2,6 +2,7 @@
#include "../../../client/settings/cache_settings.h"
#include "../../deck_loader/deck_loader.h"
#include "../cards/card_size_widget.h"
#include "../general/layout_containers/flow_widget.h"
#include "../visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.h"
#include "../visual_deck_storage/deck_preview/public_deck_preview_widget.h"
@ -107,6 +108,7 @@ TabPublicDecks::TabPublicDecks(TabSupervisor *_tabSupervisor, AbstractClient *_c
&TabPublicDecks::updateCardSize);
connect(quickSettingsWidget, &VisualDeckStorageQuickSettingsWidget::showTagFilterChanged, this,
&TabPublicDecks::updateTagsVisibility);
quickSettingsWidget->getCardSizeWidget()->enableCtrlScrollResize(flowWidget);
retranslateUi();
model->refresh(userName);

View file

@ -69,6 +69,7 @@ VisualDatabaseDisplayWidget::VisualDatabaseDisplayWidget(QWidget *parent,
SettingsCache::instance().cardsDisplay().getVisualDatabaseDisplayCardSize());
connect(cardSizeWidget, &CardSizeWidget::cardSizeSettingUpdated, &SettingsCache::instance().cardsDisplay(),
&CardsDisplaySettings::setVisualDatabaseDisplayCardSize);
cardSizeWidget->enableCtrlScrollResize(flowWidget);
searchContainer = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);

View file

@ -48,6 +48,7 @@ VisualDeckEditorSampleHandWidget::VisualDeckEditorSampleHandWidget(QWidget *pare
upperLayout->addWidget(flowWidget);
cardSizeWidget = new CardSizeWidget(this, flowWidget);
cardSizeWidget->enableCtrlScrollResize(flowWidget);
upperLayout->addWidget(cardSizeWidget);
auto upperLayoutWidget = new QWidget(this);

View file

@ -1,6 +1,7 @@
#include "visual_deck_storage_folder_display_widget.h"
#include "../cards/card_info_picture_widget.h"
#include "../cards/card_size_widget.h"
#include "../general/display/banner_widget.h"
#include "../general/layout_containers/flow_widget.h"
#include "deck_preview/deck_preview_widget.h"
@ -45,6 +46,8 @@ VisualDeckStorageFolderDisplayWidget::VisualDeckStorageFolderDisplayWidget(
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
containerLayout->addWidget(flowWidget);
visualDeckStorageWidget->settings()->getCardSizeWidget()->enableCtrlScrollResize(this);
auto *proxy = visualDeckStorageWidget->proxyModel();
// A burst of proxy changes (one dataChanged per finished deck load, plus the filter
// invalidations) coalesces into a single reconcile, so a scan of many decks doesn't

View file

@ -70,6 +70,15 @@ public:
[[nodiscard]] TooltipType getDeckPreviewTooltip() const;
[[nodiscard]] int getCardSize() const;
/**
* @return The card size widget, so card display hosts can resize the cards on
* Ctrl + scroll even though the slider itself lives inside this menu.
*/
[[nodiscard]] CardSizeWidget *getCardSizeWidget() const
{
return cardSizeWidget;
}
signals:
void showFoldersChanged(bool enabled);
void drawUnusedColorIdentitiesChanged(bool enabled);