Commit 555f3024 authored by Felix Ernst's avatar Felix Ernst 🇺🇦
Browse files

Fix scrolling on the ZoomComboBox

Scrolling on the ZoomComboBox should go through the list of
predefined zoom values of the box. Before this patch this
was very unreliable. For example it didn't work as expected when
the current zoom value wasn't one of the predefined values.

With this commit, scrolling should work exactly as expected.

There is one change that also affects people that aren't scrolling:
The smallest zoom value is no longer generated in the list of
predefined zoom values because this value is already covered by
the zoom value "fit" (and by "100%" if the image is very small).
parent 9cbff7bf
......@@ -10,6 +10,7 @@
#include <QLineEdit>
#include <QMouseEvent>
#include <QSignalBlocker>
#include <QWheelEvent>
#include <cmath>
......@@ -153,7 +154,7 @@ void ZoomComboBoxPrivate::setActions(QAction *zoomToFitAction, QAction *zoomToFi
q->clear();
q->addItem(zoomToFitAction->iconText(), QVariant::fromValue(zoomToFitAction)); // index = 0
q->addItem(zoomToFillAction->iconText(), QVariant::fromValue(zoomToFillAction)); // index = 1
q->addItem(actualSizeAction->iconText(), QVariant::fromValue(actualSizeAction)); // index = 2
q->addItem(actualSizeAction->iconText(), QVariant::fromValue(actualSizeAction)); // index will change later
mZoomToFitAction = zoomToFitAction;
mZoomToFillAction = zoomToFillAction;
......@@ -195,7 +196,7 @@ void ZoomComboBox::setMinimum(qreal minimum)
for (int i = actualSizeActionIndex - 1; i > zoomToFillActionIndex; --i) {
removeItem(i);
}
qreal value = minimum;
qreal value = minimum * 2; // The minimum zoom value itself is already available through "fit".
for (int i = zoomToFillActionIndex + 1; value < 1.0; ++i) {
insertItem(i, textFromValue(value), QVariant::fromValue(value));
value *= 2;
......@@ -268,31 +269,10 @@ void ZoomComboBox::updateDisplayedText()
void Gwenview::ZoomComboBox::showPopup()
{
Q_D(ZoomComboBox);
if (d->mZoomToFitAction->isChecked()) {
setCurrentIndex(0);
d->lastSelectedIndex = 0;
} else if (d->mZoomToFillAction->isChecked()) {
setCurrentIndex(1);
d->lastSelectedIndex = 1;
} else if (d->mActualSizeAction->isChecked()) {
const int actualSizeActionIndex = findData(QVariant::fromValue(d->mActualSizeAction));
setCurrentIndex(actualSizeActionIndex);
d->lastSelectedIndex = actualSizeActionIndex;
} else {
// Now is a good time to save the zoom value that was selected before the user changes it through the popup.
d->lastCustomZoomValue = d->value;
// Highlight the correct index if the current zoom value exists as an option in the popup.
// If it doesn't exist, it is set to -1.
d->lastSelectedIndex = findText(textFromValue(d->value));
setCurrentIndex(d->lastSelectedIndex);
}
updateCurrentIndex();
// We don't want to emit a QComboBox::highlighted event just because the popup is opened.
const QSignalBlocker blocker(this);
QComboBox::showPopup();
}
......@@ -335,6 +315,68 @@ void ZoomComboBox::focusOutEvent(QFocusEvent *)
setValue(d->lastCustomZoomValue);
}
void ZoomComboBox::wheelEvent(QWheelEvent *event)
{
updateCurrentIndex();
if (currentIndex() != -1) {
// Everything should work as expected.
return QComboBox::wheelEvent(event);
}
// There is no exact match for the current zoom value in the
// ComboBox. We need to find the closest matches, so scrolling
// works as expected.
Q_D(ZoomComboBox);
int closestZoomValueSmallerThanCurrent = 1; // = "fill" action
int closestZoomValueBiggerThanCurrent = count() - 1;
for (int i = 2; itemData(i) != QVariant::Invalid; i++) {
bool isValidConversion;
const qreal zoomValue = valueFromText(itemText(i), &isValidConversion);
if (!isValidConversion) {
continue;
}
if (zoomValue < d->value) {
closestZoomValueSmallerThanCurrent = i;
} else {
closestZoomValueBiggerThanCurrent = i;
break;
}
}
if (event->angleDelta().y() > 0) {
setCurrentIndex(closestZoomValueBiggerThanCurrent);
} else {
setCurrentIndex(closestZoomValueSmallerThanCurrent);
}
return QComboBox::wheelEvent(event);
}
void ZoomComboBox::updateCurrentIndex()
{
Q_D(ZoomComboBox);
if (d->mZoomToFitAction->isChecked()) {
setCurrentIndex(0);
d->lastSelectedIndex = 0;
} else if (d->mZoomToFillAction->isChecked()) {
setCurrentIndex(1);
d->lastSelectedIndex = 1;
} else if (d->mActualSizeAction->isChecked()) {
const int actualSizeActionIndex = findData(QVariant::fromValue(d->mActualSizeAction));
setCurrentIndex(actualSizeActionIndex);
d->lastSelectedIndex = actualSizeActionIndex;
} else {
// Now is a good time to save the zoom value that was selected before the user changes it through the popup.
d->lastCustomZoomValue = d->value;
// Highlight the correct index if the current zoom value exists as an option in the popup.
// If it doesn't exist, it is set to -1.
d->lastSelectedIndex = findText(textFromValue(d->value));
setCurrentIndex(d->lastSelectedIndex);
}
}
void ZoomComboBox::changeZoomTo(int index)
{
if (index < 0) {
......
......@@ -7,6 +7,8 @@
#include <QComboBox>
#include <lib/gwenviewlib_export.h>
class QWheelEvent;
namespace Gwenview
{
class ZoomComboBoxPrivate;
......@@ -64,6 +66,25 @@ protected:
bool eventFilter(QObject *watched, QEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
/**
* Makes sure using the mouse wheel on the combobox works as
* expected even though we sometimes programmatically change
* the currentIndex() of this ComboBox.
* @see updateCurrentIndex()
*/
void wheelEvent(QWheelEvent *event) override;
private:
/**
* The current index is the row in the popup of the ComboBox that is
* highlighted.
* This method updates the current index so it matches the current zoom
* state of the application.
* If the zoom value that is currently used doesn't exist as a row in
* the ComboBox, the currentIndex is set to -1 which hides the highlight.
*/
void updateCurrentIndex();
private Q_SLOTS:
/**
* This method changes the zoom mode or value of the currently displayed image in response to
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment