Commit 53e9ce51 authored by Dmitry Kazakov's avatar Dmitry Kazakov
Browse files

Made the zooming steps consistent in Krita

1) Now the wheel and hotkey zooming in Krita is done using KoZoomAction
   instead of hardcoded code
2) The zoom levels are changed to be in consistency with other
   applications (checked in Adobe Reader and Adobe Photoshop).
   Such change was demanded in bug 302775

BUG:302775
parent 84a48c95
......@@ -68,6 +68,9 @@ public:
void addKeyShortcut(KisAbstractInputAction* action, int index,
const QList<Qt::Key> &modifiers,
Qt::Key key);
void addWheelShortcut(KisAbstractInputAction* action, int index,
const QList<Qt::Key> &modifiers,
KisKeyShortcut::WheelAction wheelAction);
bool processUnhandledEvent(QEvent *event);
void setupActions();
......@@ -121,6 +124,16 @@ void KisInputManager::Private::addKeyShortcut(KisAbstractInputAction* action, in
matcher.addShortcut(keyShortcut);
}
void KisInputManager::Private::addWheelShortcut(KisAbstractInputAction* action, int index,
const QList<Qt::Key> &modifiers,
KisKeyShortcut::WheelAction wheelAction)
{
KisKeyShortcut *keyShortcut =
new KisKeyShortcut(action, index);
keyShortcut->setWheel(modifiers, wheelAction);
matcher.addShortcut(keyShortcut);
}
void KisInputManager::Private::setupActions()
{
#if QT_VERSION >= 0x040700
......@@ -174,21 +187,8 @@ void KisInputManager::Private::setupActions()
addStrokeShortcut(action, KisZoomAction::ZoomToggleShortcut, KEYS(Qt::Key_Control, Qt::Key_Space), BUTTONS(Qt::LeftButton));
addStrokeShortcut(action, KisZoomAction::ZoomToggleShortcut, KEYS(Qt::Key_Control), BUTTONS(middleButton));
/**
* FIXME: Zooming with Wheel is implemented on a level of
* KoCanvasControllerWidget and is done in a bit different way than
* usual zoom-in/out actions, because it tries to zoom around
* the mouse pointer. If you want to implement it in
* KisInputManager, please implement additional action that
* takes mouse position into account.
*
* Don't forget to disable wheel-zooming in KoCanvasControllerWidget
* before activation of this shortcut.
*/
// shortcut = createShortcut(action, KisZoomAction::ZoomInShortcut);
// shortcut->setWheel(KisShortcut::WheelUp);
// shortcut = createShortcut(action, KisZoomAction::ZoomOutShortcut);
// shortcut->setWheel(KisShortcut::WheelDown);
addWheelShortcut(action, KisZoomAction::ZoomInShortcut, KEYS(), KisKeyShortcut::WheelUp);
addWheelShortcut(action, KisZoomAction::ZoomOutShortcut, KEYS(), KisKeyShortcut::WheelDown);
addKeyShortcut(action, KisZoomAction::ZoomInShortcut, KEYS(), Qt::Key_Plus);
addKeyShortcut(action, KisZoomAction::ZoomOutShortcut, KEYS(), Qt::Key_Minus);
......@@ -363,7 +363,7 @@ bool KisInputManager::eventFilter(QObject* object, QEvent* event)
wheelEvent->delta() > 0 ?
KisKeyShortcut::WheelUp : KisKeyShortcut::WheelDown;
retval = d->matcher.wheelEvent(action);
retval = d->matcher.wheelEvent(action, wheelEvent);
break;
}
case QEvent::Enter:
......
......@@ -19,7 +19,6 @@
#include "kis_shortcut_matcher.h"
#include <QMouseEvent>
#include <QTabletEvent>
#include "kis_abstract_input_action.h"
#include "kis_stroke_shortcut.h"
......@@ -80,7 +79,7 @@ bool KisShortcutMatcher::keyPressed(Qt::Key key)
if (m_d->keys.contains(key)) reset();
if (!m_d->runningShortcut) {
retval = tryRunKeyShortcut(key);
retval = tryRunKeyShortcut(key, 0);
}
m_d->keys.append(key);
......@@ -145,11 +144,11 @@ bool KisShortcutMatcher::buttonReleased(Qt::MouseButton button, QMouseEvent *eve
return retval;
}
bool KisShortcutMatcher::wheelEvent(KisKeyShortcut::WheelAction wheelAction)
bool KisShortcutMatcher::wheelEvent(KisKeyShortcut::WheelAction wheelAction, QWheelEvent *event)
{
if (m_d->runningShortcut) return false;
return tryRunWheelShortcut(wheelAction);
return tryRunWheelShortcut(wheelAction, event);
}
bool KisShortcutMatcher::mouseMoved(QMouseEvent *event)
......@@ -171,18 +170,18 @@ void KisShortcutMatcher::suppressAllActions(bool value)
m_d->suppressAllActions = value;
}
bool KisShortcutMatcher::tryRunWheelShortcut(KisKeyShortcut::WheelAction wheelAction)
bool KisShortcutMatcher::tryRunWheelShortcut(KisKeyShortcut::WheelAction wheelAction, QWheelEvent *event)
{
return tryRunKeyShortcutImpl(wheelAction);
return tryRunKeyShortcutImpl(wheelAction, event);
}
bool KisShortcutMatcher::tryRunKeyShortcut(Qt::Key key)
bool KisShortcutMatcher::tryRunKeyShortcut(Qt::Key key, QKeyEvent *event)
{
return tryRunKeyShortcutImpl(key);
return tryRunKeyShortcutImpl(key, event);
}
template<typename T>
bool KisShortcutMatcher::tryRunKeyShortcutImpl(T param)
template<typename T, typename U>
bool KisShortcutMatcher::tryRunKeyShortcutImpl(T param, U *event)
{
if (m_d->suppressAllActions) return false;
......@@ -197,7 +196,7 @@ bool KisShortcutMatcher::tryRunKeyShortcutImpl(T param)
}
if (goodCandidate) {
goodCandidate->action()->begin(goodCandidate->shortcutIndex(), 0);
goodCandidate->action()->begin(goodCandidate->shortcutIndex(), event);
goodCandidate->action()->end(0);
}
......
......@@ -25,7 +25,8 @@
#include "kis_key_shortcut.h"
class QMouseEvent;
class QTabletEvent;
class QKeyEvent;
class QWheelEvent;
class KisStrokeShortcut;
class KisAbstractInputAction;
......@@ -93,7 +94,7 @@ public:
* \return whether the event has been handled successfully and
* should be eaten by the events filter
*/
bool wheelEvent(KisKeyShortcut::WheelAction wheelAction);
bool wheelEvent(KisKeyShortcut::WheelAction wheelAction, QWheelEvent *event);
/**
* Handles the mouse move event
......@@ -125,9 +126,9 @@ public:
private:
friend class KisInputManagerTest;
bool tryRunKeyShortcut(Qt::Key key);
bool tryRunWheelShortcut(KisKeyShortcut::WheelAction wheelAction);
template<typename T> bool tryRunKeyShortcutImpl(T param);
bool tryRunKeyShortcut(Qt::Key key, QKeyEvent *event);
bool tryRunWheelShortcut(KisKeyShortcut::WheelAction wheelAction, QWheelEvent *event);
template<typename T, typename U> bool tryRunKeyShortcutImpl(T param, U *event);
void prepareReadyShortcuts();
......
......@@ -22,15 +22,59 @@
#include <kis_canvas2.h>
#include "kis_input_manager.h"
#include <kis_view2.h>
#include <kis_zoom_manager.h>
#include <KoCanvasController.h>
#include <KoCanvasControllerWidget.h>
#include <KoZoomController.h>
#include <kis_view2.h>
#include "kis_input_manager.h"
class KisZoomAction::Private
{
public:
Private(KisZoomAction *qq) : q(qq) {}
KisZoomAction *q;
void zoomTo(bool zoomIn, QEvent *event);
};
void KisZoomAction::Private::zoomTo(bool zoomIn, QEvent *event)
{
KoZoomAction *zoomAction = q->inputManager()->canvas()->view()->zoomController()->zoomAction();
if (event) {
QPoint pos;
QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event);
if (mouseEvent) {
pos = mouseEvent->pos();
} else {
QWheelEvent *wheelEvent = dynamic_cast<QWheelEvent*>(event);
if (wheelEvent) {
pos = wheelEvent->pos();
} else {
qWarning() << "Unhandled type of event";
}
}
float oldZoom = zoomAction->effectiveZoom();
float newZoom = zoomIn ?
zoomAction->nextZoomLevel() : zoomAction->prevZoomLevel();
KoCanvasControllerWidget *controller =
dynamic_cast<KoCanvasControllerWidget*>(
q->inputManager()->canvas()->canvasController());
controller->zoomRelativeToPoint(pos, newZoom / oldZoom);
} else {
if (zoomIn) {
zoomAction->zoomIn();
} else {
zoomAction->zoomOut();
}
}
}
KisZoomAction::KisZoomAction(KisInputManager* manager)
: KisAbstractInputAction(manager)
: KisAbstractInputAction(manager), d(new Private(this))
{
setName(i18n("Zoom Canvas"));
......@@ -46,6 +90,7 @@ KisZoomAction::KisZoomAction(KisInputManager* manager)
KisZoomAction::~KisZoomAction()
{
delete d;
}
void KisZoomAction::activate()
......@@ -65,34 +110,12 @@ void KisZoomAction::begin(int shortcut, QEvent *event)
switch(shortcut) {
case ZoomToggleShortcut:
break;
case ZoomInShortcut: {
float zoom = inputManager()->canvas()->view()->zoomController()->zoomAction()->effectiveZoom();
if( zoom >= 10 ) {
zoom += 1.0;
} else if (zoom >= 5) {
zoom += 0.5;
} else if (zoom >= 2) {
zoom += 0.2;
} else {
zoom += 0.1;
}
inputManager()->canvas()->view()->zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, zoom);
case ZoomInShortcut:
d->zoomTo(true, event);
break;
}
case ZoomOutShortcut: {
float zoom = inputManager()->canvas()->view()->zoomController()->zoomAction()->effectiveZoom();
if( zoom >= 10 ) {
zoom -= 1.0;
} else if (zoom >= 5) {
zoom -= 0.5;
} else if (zoom >= 2) {
zoom -= 0.2;
} else {
zoom -= 0.1;
}
inputManager()->canvas()->view()->zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, zoom);
case ZoomOutShortcut:
d->zoomTo(false, event);
break;
}
case ZoomResetShortcut:
inputManager()->canvas()->view()->zoomController()->setZoom(KoZoomMode::ZOOM_CONSTANT, 1.0);
break;
......
......@@ -48,6 +48,10 @@ public:
void begin(int shortcut, QEvent *event = 0);
void mouseMoved(const QPointF &lastPos, const QPointF &pos);
private:
class Private;
Private * const d;
};
#endif // KIS_ZOOM_ACTION_H
......@@ -91,8 +91,12 @@ KisZoomManager::~KisZoomManager()
void KisZoomManager::setup(KActionCollection * actionCollection)
{
KoZoomMode::setMinimumZoom(0.06);
KoZoomMode::setMaximumZoom(64.0);
QSize imageSize = m_view->image()->size();
qreal minDimension = qMin(imageSize.width(), imageSize.height());
qreal minZoom = qMin(100.0 / minDimension, 0.1);
KoZoomMode::setMinimumZoom(minZoom);
KoZoomMode::setMaximumZoom(90.0);
KisCoordinatesConverter *converter =
dynamic_cast<KisCoordinatesConverter*>(m_zoomHandler);
......
......@@ -113,6 +113,12 @@ public:
virtual void zoomTo(const QRect &rect);
/**
* Zoom document keeping point \p widgetPoint unchanged
* \param widgetPoint sticky point in widget pixels
*/
virtual void zoomRelativeToPoint(const QPoint &widgetPoint, qreal zoomCoeff);
virtual void recenterPreferred();
virtual void setPreferredCenter(const QPointF &viewPoint);
......@@ -166,12 +172,6 @@ private slots:
protected:
friend class KisZoomAndPanTest;
/**
* Zoom document keeping point \p widgetPoint unchanged
* \param widgetPoint sticky point in widget pixels
*/
virtual void zoomRelativeToPoint(const QPoint &widgetPoint, qreal zoomCoeff);
/// reimplemented from QWidget
virtual void paintEvent(QPaintEvent *event);
/// reimplemented from QWidget
......
......@@ -52,15 +52,76 @@ class KoZoomAction::Private
public:
KoZoomMode::Modes zoomModes;
QSlider *slider;
qreal sliderLookup[33];
QList<qreal> sliderLookup;
KoZoomInput* input;
QToolButton* aspectButton;
qreal effectiveZoom;
KoZoomAction::SpecialButtons specialButtons;
QList<qreal> generateSliderZoomLevels() const;
QList<qreal> filterMenuZoomLevels(const QList<qreal> &zoomLevels) const;
void syncSliderWithZoom();
};
QList<qreal> KoZoomAction::Private::generateSliderZoomLevels() const
{
QList<qreal> zoomLevels;
qreal defaultZoomStep = sqrt(2);
zoomLevels << 0.25 / 2.0;
zoomLevels << 0.25 / 1.5;
zoomLevels << 0.25;
zoomLevels << 1.0 / 3.0;
zoomLevels << 0.5;
zoomLevels << 2.0 / 3.0;
zoomLevels << 1.0;
for (qreal zoom = zoomLevels.first() / defaultZoomStep;
zoom > KoZoomMode::minimumZoom();
zoom /= defaultZoomStep) {
zoomLevels.prepend(zoom);
}
for (qreal zoom = zoomLevels.last() * defaultZoomStep;
zoom < KoZoomMode::maximumZoom();
zoom *= defaultZoomStep) {
zoomLevels.append(zoom);
}
return zoomLevels;
}
QList<qreal> KoZoomAction::Private::filterMenuZoomLevels(const QList<qreal> &zoomLevels) const
{
QList<qreal> filteredZoomLevels;
foreach(qreal zoom, zoomLevels) {
if (zoom >= 0.2 && zoom <= 10) {
filteredZoomLevels << zoom;
}
}
return filteredZoomLevels;
}
void KoZoomAction::Private::syncSliderWithZoom()
{
if(slider) {
const qreal eps = 1e-5;
int i = sliderLookup.size() - 1;
while (effectiveZoom < sliderLookup[i] + eps && i > 0) i--;
slider->blockSignals(true);
slider->setValue(i); // causes sliderValueChanged to be called which does the rest
slider->blockSignals(false);
}
}
KoZoomAction::KoZoomAction( KoZoomMode::Modes zoomModes, const QString& text, QObject *parent)
: KSelectAction(text, parent)
,d(new Private)
......@@ -73,15 +134,7 @@ KoZoomAction::KoZoomAction( KoZoomMode::Modes zoomModes, const QString& text, QO
setEditable( true );
setMaxComboViewCount( 15 );
d->sliderLookup[0] = KoZoomMode::minimumZoom();
d->sliderLookup[32] = KoZoomMode::maximumZoom();
int steps = 32;
int halfSteps = steps / 2;
qreal zoomStep = pow(1.0 / KoZoomMode::minimumZoom(), 1.0/halfSteps);
for(int i = 1; i < steps; ++i) {
d->sliderLookup[i] = pow(zoomStep, i - halfSteps);
}
d->sliderLookup = d->generateSliderZoomLevels();
d->effectiveZoom = 1.0;
regenerateItems(d->effectiveZoom, true);
......@@ -138,23 +191,10 @@ void KoZoomAction::setZoomModes( KoZoomMode::Modes zoomModes )
void KoZoomAction::regenerateItems(const qreal zoom, bool asCurrent)
{
// where we'll store sorted new zoom values
QList<qreal> zoomLevels;
zoomLevels << 33;
zoomLevels << 50;
zoomLevels << 75;
zoomLevels << 100;
zoomLevels << 125;
zoomLevels << 150;
zoomLevels << 200;
zoomLevels << 250;
zoomLevels << 350;
zoomLevels << 400;
zoomLevels << 450;
zoomLevels << 500;
if( !zoomLevels.contains( zoom*100 ) )
zoomLevels << zoom*100;
QList<qreal> zoomLevels = d->filterMenuZoomLevels(d->sliderLookup);
if( !zoomLevels.contains( zoom ) )
zoomLevels << zoom;
qSort(zoomLevels.begin(), zoomLevels.end());
......@@ -171,9 +211,9 @@ void KoZoomAction::regenerateItems(const qreal zoom, bool asCurrent)
foreach(qreal value, zoomLevels) {
if(value>10.0)
values << i18n("%1%", KGlobal::locale()->formatNumber(value, 0));
values << i18n("%1%", KGlobal::locale()->formatNumber(value * 100, 0));
else
values << i18n("%1%", KGlobal::locale()->formatNumber(value, 1));
values << i18n("%1%", KGlobal::locale()->formatNumber(value * 100, 1));
}
setItems( values );
......@@ -203,33 +243,43 @@ void KoZoomAction::sliderValueChanged(int value)
emit zoomChanged( KoZoomMode::ZOOM_CONSTANT, d->sliderLookup[value] );
}
void KoZoomAction::zoomIn()
qreal KoZoomAction::nextZoomLevel() const
{
const qreal eps = 1e-5;
int i = 0;
while (d->effectiveZoom > d->sliderLookup[i] - eps &&
i < d->sliderLookup.size() - 1) i++;
return qMax(d->effectiveZoom, d->sliderLookup[i]);
}
qreal KoZoomAction::prevZoomLevel() const
{
int i=0;
while(i <= 32 && d->sliderLookup[i] < d->effectiveZoom)
i++;
const qreal eps = 1e-5;
int i = d->sliderLookup.size() - 1;
while (d->effectiveZoom < d->sliderLookup[i] + eps && i > 0) i--;
return qMin(d->effectiveZoom, d->sliderLookup[i]);
}
if(i < 32 && d->sliderLookup[i] == d->effectiveZoom)
i++;
// else i is the next zoom level already
void KoZoomAction::zoomIn()
{
qreal zoom = nextZoomLevel();
qreal zoom = d->sliderLookup[i];
setZoom(zoom);
emit zoomChanged( KoZoomMode::ZOOM_CONSTANT, d->effectiveZoom);
if (zoom > d->effectiveZoom) {
setZoom(zoom);
emit zoomChanged( KoZoomMode::ZOOM_CONSTANT, d->effectiveZoom);
}
}
void KoZoomAction::zoomOut()
{
int i=0;
while(i <= 32 && d->sliderLookup[i] < d->effectiveZoom)
i++;
qreal zoom = prevZoomLevel();
if(i>0)
i--;
qreal zoom = d->sliderLookup[i];
setZoom(zoom);
emit zoomChanged( KoZoomMode::ZOOM_CONSTANT, d->effectiveZoom);
if (zoom < d->effectiveZoom) {
setZoom(zoom);
emit zoomChanged( KoZoomMode::ZOOM_CONSTANT, d->effectiveZoom);
}
}
QWidget * KoZoomAction::createWidget(QWidget *parent)
......@@ -255,12 +305,13 @@ QWidget * KoZoomAction::createWidget(QWidget *parent)
d->slider = new QSlider(Qt::Horizontal);
d->slider->setToolTip(i18n("Zoom"));
d->slider->setMinimum(0);
d->slider->setMaximum(32);
d->slider->setValue(16);
d->slider->setMaximum(d->sliderLookup.size() - 1);
d->slider->setValue(0);
d->slider->setSingleStep(1);
d->slider->setPageStep(1);
d->slider->setMinimumWidth(80);
d->slider->setMaximumWidth(80);
d->syncSliderWithZoom();
layout->addWidget(d->slider);
if (d->specialButtons & AspectMode) {
......@@ -305,16 +356,7 @@ void KoZoomAction::setEffectiveZoom(qreal zoom)
zoom = KoZoomMode::clampZoom(zoom);
d->effectiveZoom = zoom;
if(d->slider) {
int i = 0;
while(i <= 32 && d->sliderLookup[i] < zoom)
i++;
d->slider->blockSignals(true);
d->slider->setValue(i); // causes sliderValueChanged to be called which does the rest
d->slider->blockSignals(false);
}
d->syncSliderWithZoom();
}
void KoZoomAction::setSelectedZoomMode( KoZoomMode::Mode mode )
......
......@@ -114,6 +114,26 @@ public slots:
*/
void setAspectMode(bool status);
/**
* Returns next preferred zoom level that should be used for
* zoom in operations.
*
* This can be used by the caller, when he needs some special
* mode of zooming (e.g. relative to point) and needs
* KoCanvasControllerWidget to accomplish this.
*/
qreal nextZoomLevel() const;
/**
* Returns previous preferred zoom level that should be used for
* zoom out operations.
*
* This can be used by the caller, when he needs some special
* mode of zooming (e.g. relative to point) and needs
* KoCanvasControllerWidget to accomplish this.
*/
qreal prevZoomLevel() const;
protected slots:
void triggered( const QString& text );
......@@ -149,7 +169,6 @@ signals:
void zoomedToAll();
protected:
/// Regenerates the action's items
void regenerateItems( const qreal zoom, bool asCurrent = false );
......
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