plugins/shakecursor: Make the cursor big enough upon the first shake

The current behavior is that the cursor size follows how hard or fast
the cursor is shaken. While this looks fancy, given the purpose of this
plugin, it should be possible to magnify the cursor as easy as possible
without interfering or false triggering.

This change implements a sort of a compromise. When the cursor is shaken
for the first time, the cursor is magnified by some certain scale factor.
Then every next shake magnifies the cursor further by a smaller amount.
This commit is contained in:
Vlad Zahorodnii 2024-01-17 22:42:37 +02:00
parent 8736e44e1a
commit 2ad896c71d
5 changed files with 56 additions and 30 deletions

View file

@ -21,17 +21,11 @@ ShakeCursorEffect::ShakeCursorEffect()
{
input()->installInputEventSpy(this);
m_resetCursorScaleTimer.setSingleShot(true);
connect(&m_resetCursorScaleTimer, &QTimer::timeout, this, [this]() {
m_resetCursorScaleAnimation.setStartValue(m_cursorMagnification);
m_resetCursorScaleAnimation.setEndValue(1.0);
m_resetCursorScaleAnimation.setDuration(animationTime(150));
m_resetCursorScaleAnimation.setEasingCurve(QEasingCurve::InOutCubic);
m_resetCursorScaleAnimation.start();
});
m_deflateTimer.setSingleShot(true);
connect(&m_deflateTimer, &QTimer::timeout, this, &ShakeCursorEffect::deflate);
connect(&m_resetCursorScaleAnimation, &QVariantAnimation::valueChanged, this, [this]() {
magnify(m_resetCursorScaleAnimation.currentValue().toReal());
connect(&m_scaleAnimation, &QVariantAnimation::valueChanged, this, [this]() {
magnify(m_scaleAnimation.currentValue().toReal());
});
ShakeCursorConfig::instance(effects->config());
@ -59,9 +53,36 @@ void ShakeCursorEffect::reconfigure(ReconfigureFlags flags)
m_shakeDetector.setSensitivity(ShakeCursorConfig::sensitivity());
}
bool ShakeCursorEffect::isActive() const
void ShakeCursorEffect::inflate()
{
return m_cursorMagnification != 1.0;
qreal magnification;
if (m_targetMagnification == 1.0) {
magnification = ShakeCursorConfig::magnification();
} else {
magnification = m_targetMagnification + ShakeCursorConfig::overMagnification();
}
animateTo(magnification);
}
void ShakeCursorEffect::deflate()
{
animateTo(1.0);
}
void ShakeCursorEffect::animateTo(qreal magnification)
{
if (m_targetMagnification != magnification) {
m_scaleAnimation.stop();
m_scaleAnimation.setStartValue(m_currentMagnification);
m_scaleAnimation.setEndValue(magnification);
m_scaleAnimation.setDuration(animationTime(200));
m_scaleAnimation.setEasingCurve(QEasingCurve::InOutCubic);
m_scaleAnimation.start();
m_targetMagnification = magnification;
}
}
void ShakeCursorEffect::pointerEvent(MouseEvent *event)
@ -74,24 +95,22 @@ void ShakeCursorEffect::pointerEvent(MouseEvent *event)
return;
}
if (const auto shakeFactor = m_shakeDetector.update(event)) {
m_resetCursorScaleTimer.start(animationTime(2000));
m_resetCursorScaleAnimation.stop();
magnify(std::max(m_cursorMagnification, 1.0 + ShakeCursorConfig::magnification() * shakeFactor.value()));
if (m_shakeDetector.update(event)) {
inflate();
m_deflateTimer.start(animationTime(2000));
}
}
void ShakeCursorEffect::magnify(qreal magnification)
{
if (magnification == 1.0) {
m_cursorMagnification = 1.0;
m_currentMagnification = 1.0;
if (m_cursorItem) {
m_cursorItem.reset();
effects->showCursor();
}
} else {
m_cursorMagnification = magnification;
m_currentMagnification = magnification;
if (!m_cursorItem) {
effects->hideCursor();

View file

@ -31,18 +31,22 @@ public:
void reconfigure(ReconfigureFlags flags) override;
void pointerEvent(MouseEvent *event) override;
bool isActive() const override;
private:
void magnify(qreal magnification);
QTimer m_resetCursorScaleTimer;
QVariantAnimation m_resetCursorScaleAnimation;
void inflate();
void deflate();
void animateTo(qreal magnification);
QTimer m_deflateTimer;
QVariantAnimation m_scaleAnimation;
ShakeDetector m_shakeDetector;
Cursor *m_cursor;
std::unique_ptr<CursorItem> m_cursorItem;
qreal m_cursorMagnification = 1.0;
qreal m_targetMagnification = 1.0;
qreal m_currentMagnification = 1.0;
};
} // namespace KWin

View file

@ -12,7 +12,10 @@
<default>4</default>
</entry>
<entry name="Magnification" type="Double">
<default>2</default>
<default>3</default>
</entry>
<entry name="OverMagnification" type="Double">
<default>1</default>
</entry>
</group>
</kcfg>

View file

@ -32,7 +32,7 @@ void ShakeDetector::setSensitivity(qreal sensitivity)
m_sensitivity = sensitivity;
}
std::optional<qreal> ShakeDetector::update(QMouseEvent *event)
bool ShakeDetector::update(QMouseEvent *event)
{
// Prune the old entries in the history.
auto it = m_history.begin();
@ -73,13 +73,14 @@ std::optional<qreal> ShakeDetector::update(QMouseEvent *event)
const qreal boundsHeight = bottom - top;
const qreal diagonal = std::sqrt(boundsWidth * boundsWidth + boundsHeight * boundsHeight);
if (diagonal < 100) {
return std::nullopt;
return false;
}
const qreal shakeFactor = distance / diagonal;
if (shakeFactor > m_sensitivity) {
return shakeFactor - m_sensitivity;
m_history.clear();
return true;
}
return std::nullopt;
return false;
}

View file

@ -9,7 +9,6 @@
#include <QMouseEvent>
#include <deque>
#include <optional>
/**
* The ShakeDetector type provides a way to detect pointer shake gestures.
@ -23,7 +22,7 @@ class ShakeDetector
public:
ShakeDetector();
std::optional<qreal> update(QMouseEvent *event);
bool update(QMouseEvent *event);
quint64 interval() const;
void setInterval(quint64 interval);