effects: Move the TogglableState class into a reusable space

master
Aleix Pol 1 year ago committed by Aleix Pol Gonzalez
parent bb8e5458a7
commit 1b7a48de40

@ -17,6 +17,9 @@ set(kwin_EFFECTSLIB_SRCS
kwinoffscreenquickview.cpp
kwinquickeffect.cpp
logging.cpp
rendertarget.cpp
renderviewport.cpp
togglablestate.cpp
)
add_library(kwineffects SHARED ${kwin_EFFECTSLIB_SRCS})

@ -0,0 +1,245 @@
/*
SPDX-FileCopyrightText: 2023 Aleix Pol Gonzalez <aleixpol@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "togglablestate.h"
#include "kwineffects.h"
namespace KWin
{
TogglableState::TogglableState(Effect *effect)
: QObject(effect)
, m_deactivateAction(std::make_unique<QAction>())
, m_activateAction(std::make_unique<QAction>())
, m_toggleAction(std::make_unique<QAction>())
{
connect(m_activateAction.get(), &QAction::triggered, this, [this]() {
if (m_status == Status::Activating) {
if (m_partialActivationFactor > 0.5) {
activate();
Q_EMIT activated();
} else {
deactivate();
Q_EMIT deactivated();
}
}
});
connect(m_deactivateAction.get(), &QAction::triggered, this, [this]() {
if (m_status == Status::Deactivating) {
if (m_partialActivationFactor < 0.5) {
deactivate();
Q_EMIT deactivated();
} else {
activate();
Q_EMIT activated();
}
}
});
connect(m_toggleAction.get(), &QAction::triggered, this, &TogglableState::toggle);
}
void TogglableState::activate()
{
setStatus(Status::Active);
setInProgress(false);
setPartialActivationFactor(0.0);
}
void TogglableState::setPartialActivationFactor(qreal factor)
{
if (m_partialActivationFactor != factor) {
m_partialActivationFactor = factor;
Q_EMIT partialActivationFactorChanged();
}
}
void TogglableState::deactivate()
{
setInProgress(false);
setPartialActivationFactor(0.0);
}
bool TogglableState::inProgress() const
{
return m_inProgress;
}
void TogglableState::setInProgress(bool gesture)
{
if (m_inProgress != gesture) {
m_inProgress = gesture;
Q_EMIT inProgressChanged();
}
}
void TogglableState::setStatus(Status status)
{
if (m_status != status) {
m_status = status;
Q_EMIT statusChanged(status);
}
}
void TogglableState::partialActivate(qreal factor)
{
if (effects->isScreenLocked()) {
return;
}
setStatus(Status::Activating);
setPartialActivationFactor(factor);
setInProgress(true);
}
void TogglableState::partialDeactivate(qreal factor)
{
setStatus(Status::Deactivating);
setPartialActivationFactor(1.0 - factor);
setInProgress(true);
}
void TogglableState::toggle()
{
if (m_status == Status::Inactive || m_partialActivationFactor > 0.5) {
activate();
Q_EMIT activated();
} else {
deactivate();
Q_EMIT deactivated();
}
}
void TogglableState::setProgress(qreal progress)
{
if (!effects->hasActiveFullScreenEffect() || effects->activeFullScreenEffect() == parent()) {
switch (m_status) {
case Status::Inactive:
case Status::Activating:
partialActivate(progress);
break;
default:
break;
}
}
}
void TogglableState::setRegress(qreal regress)
{
if (!effects->hasActiveFullScreenEffect() || effects->activeFullScreenEffect() == parent()) {
switch (m_status) {
case Status::Active:
case Status::Deactivating:
partialDeactivate(regress);
break;
default:
break;
}
}
}
TogglableGesture::TogglableGesture(TogglableState *state)
: QObject(state)
, m_state(state)
{
}
static PinchDirection opposite(PinchDirection direction)
{
switch (direction) {
case PinchDirection::Contracting:
return PinchDirection::Expanding;
case PinchDirection::Expanding:
return PinchDirection::Contracting;
}
}
static SwipeDirection opposite(SwipeDirection direction)
{
switch (direction) {
case SwipeDirection::Invalid:
return SwipeDirection::Invalid;
case SwipeDirection::Down:
return SwipeDirection::Up;
case SwipeDirection::Up:
return SwipeDirection::Down;
case SwipeDirection::Left:
return SwipeDirection::Right;
case SwipeDirection::Right:
return SwipeDirection::Left;
}
}
std::function<void(qreal progress)> TogglableState::progressCallback()
{
return [this](qreal progress) {
setProgress(progress);
};
}
std::function<void(qreal progress)> TogglableState::regressCallback()
{
return [this](qreal progress) {
setRegress(progress);
};
}
void TogglableGesture::addTouchpadPinchGesture(PinchDirection direction, uint fingerCount)
{
effects->registerTouchpadPinchShortcut(direction, fingerCount, m_state->activateAction(), m_state->progressCallback());
effects->registerTouchpadPinchShortcut(opposite(direction), fingerCount, m_state->deactivateAction(), m_state->regressCallback());
}
void TogglableGesture::addTouchpadSwipeGesture(SwipeDirection direction, uint fingerCount)
{
effects->registerTouchpadSwipeShortcut(direction, fingerCount, m_state->activateAction(), m_state->progressCallback());
effects->registerTouchpadSwipeShortcut(opposite(direction), fingerCount, m_state->deactivateAction(), m_state->regressCallback());
}
void TogglableGesture::addTouchscreenSwipeGesture(SwipeDirection direction, uint fingerCount)
{
effects->registerTouchscreenSwipeShortcut(direction, fingerCount, m_state->activateAction(), m_state->progressCallback());
effects->registerTouchscreenSwipeShortcut(opposite(direction), fingerCount, m_state->deactivateAction(), m_state->regressCallback());
}
TogglableTouchBorder::TogglableTouchBorder(TogglableState *state)
: QObject(state)
, m_state(state)
{
}
TogglableTouchBorder::~TogglableTouchBorder()
{
for (const ElectricBorder &border : std::as_const(m_touchBorderActivate)) {
effects->unregisterTouchBorder(border, m_state->toggleAction());
}
}
void TogglableTouchBorder::setBorders(const QList<int> &touchActivateBorders)
{
for (const ElectricBorder &border : std::as_const(m_touchBorderActivate)) {
effects->unregisterTouchBorder(border, m_state->toggleAction());
}
m_touchBorderActivate.clear();
for (const int &border : touchActivateBorders) {
m_touchBorderActivate.append(ElectricBorder(border));
effects->registerRealtimeTouchBorder(ElectricBorder(border), m_state->toggleAction(), [this](ElectricBorder border, const QPointF &deltaProgress, const EffectScreen *screen) {
if (m_state->status() == TogglableState::Status::Active) {
return;
}
const int maxDelta = 500; // Arbitrary logical pixels value seems to behave better than scaledScreenSize
qreal progress = 0;
if (border == ElectricTop || border == ElectricBottom) {
progress = std::min(1.0, std::abs(deltaProgress.y()) / maxDelta);
} else {
progress = std::min(1.0, std::abs(deltaProgress.x()) / maxDelta);
}
m_state->setProgress(progress);
});
}
}
}

@ -0,0 +1,120 @@
/*
SPDX-FileCopyrightText: 2023 Aleix Pol Gonzalez <aleixpol@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include "libkwineffects/kwineffects_export.h"
#include <QAction>
#include <QObject>
#include <kwinglobals.h>
namespace KWin
{
class Effect;
class KWINEFFECTS_EXPORT TogglableState : public QObject
{
Q_OBJECT
public:
enum class Status {
Inactive,
Activating,
Deactivating,
Active
};
Q_ENUM(Status);
TogglableState(Effect *parent);
bool inProgress() const;
void setInProgress(bool gesture);
qreal partialActivationFactor() const
{
return m_partialActivationFactor;
}
void setPartialActivationFactor(qreal factor);
QAction *activateAction() const
{
return m_activateAction.get();
}
QAction *deactivateAction() const
{
return m_deactivateAction.get();
}
QAction *toggleAction() const
{
return m_toggleAction.get();
}
void activate();
void deactivate();
void toggle();
void setStatus(Status status);
Status status() const
{
return m_status;
}
Q_SIGNALS:
void inProgressChanged();
void partialActivationFactorChanged();
void activated();
void deactivated();
void statusChanged(Status status);
protected:
std::function<void(qreal progress)> progressCallback();
std::function<void(qreal progress)> regressCallback();
void setProgress(qreal progress);
/// regress being the progress when on an active state
void setRegress(qreal regress);
private:
void partialActivate(qreal factor);
void partialDeactivate(qreal factor);
std::unique_ptr<QAction> m_deactivateAction;
std::unique_ptr<QAction> m_activateAction;
std::unique_ptr<QAction> m_toggleAction;
Status m_status = Status::Inactive;
bool m_inProgress = false;
qreal m_partialActivationFactor = 0;
friend class TogglableGesture;
friend class TogglableTouchBorder;
};
class KWINEFFECTS_EXPORT TogglableGesture : public QObject
{
public:
TogglableGesture(TogglableState *state);
void addTouchpadPinchGesture(PinchDirection dir, uint fingerCount);
void addTouchpadSwipeGesture(SwipeDirection dir, uint fingerCount);
void addTouchscreenSwipeGesture(SwipeDirection direction, uint fingerCount);
private:
TogglableState *const m_state;
};
class KWINEFFECTS_EXPORT TogglableTouchBorder : public QObject
{
public:
TogglableTouchBorder(TogglableState *state);
~TogglableTouchBorder();
void setBorders(const QList<int> &borders);
private:
QList<ElectricBorder> m_touchBorderActivate;
TogglableState *const m_state;
};
}

@ -18,235 +18,13 @@
namespace KWin
{
TogglableState::TogglableState(QObject *effect)
: QObject(effect)
{
m_activateAction = new QAction(this);
connect(m_activateAction, &QAction::triggered, this, [this]() {
if (m_status == Status::Activating) {
if (m_partialActivationFactor > 0.5) {
activate();
Q_EMIT activated();
} else {
deactivate();
Q_EMIT deactivated();
}
}
});
m_deactivateAction = new QAction(this);
connect(m_deactivateAction, &QAction::triggered, this, [this]() {
if (m_status == Status::Deactivating) {
if (m_partialActivationFactor < 0.5) {
deactivate();
Q_EMIT deactivated();
} else {
activate();
Q_EMIT activated();
}
}
});
m_toggleAction = new QAction(this);
connect(m_toggleAction, &QAction::triggered, this, &TogglableState::toggle);
}
void TogglableState::activate()
{
setStatus(Status::Active);
setInProgress(false);
setPartialActivationFactor(0.0);
}
void TogglableState::setPartialActivationFactor(qreal factor)
{
if (m_partialActivationFactor != factor) {
m_partialActivationFactor = factor;
Q_EMIT partialActivationFactorChanged();
}
}
void TogglableState::deactivate()
{
setInProgress(false);
setPartialActivationFactor(0.0);
}
bool TogglableState::inProgress() const
{
return m_inProgress;
}
void TogglableState::setInProgress(bool gesture)
{
if (m_inProgress != gesture) {
m_inProgress = gesture;
Q_EMIT inProgressChanged();
}
}
void TogglableState::setStatus(Status status)
{
if (m_status != status) {
m_status = status;
Q_EMIT statusChanged(status);
}
}
void TogglableState::partialActivate(qreal factor)
{
if (effects->isScreenLocked()) {
return;
}
setStatus(Status::Activating);
setPartialActivationFactor(factor);
setInProgress(true);
}
void TogglableState::partialDeactivate(qreal factor)
{
setStatus(Status::Deactivating);
setPartialActivationFactor(1.0 - factor);
setInProgress(true);
}
void TogglableState::toggle()
{
if (m_status == Status::Inactive || m_partialActivationFactor > 0.5) {
activate();
Q_EMIT activated();
} else {
deactivate();
Q_EMIT deactivated();
}
}
void TogglableState::setProgress(qreal progress)
{
if (!effects->hasActiveFullScreenEffect() || effects->activeFullScreenEffect() == parent()) {
switch (m_status) {
case Status::Inactive:
case Status::Activating:
partialActivate(progress);
break;
}
}
}
void TogglableState::setRegress(qreal regress)
{
if (!effects->hasActiveFullScreenEffect() || effects->activeFullScreenEffect() == parent()) {
switch (m_status) {
case Status::Active:
case Status::Deactivating:
partialDeactivate(regress);
break;
}
}
}
TogglableGesture::TogglableGesture(TogglableState *state)
: QObject(state)
, m_state(state)
{
}
static PinchDirection opposite(PinchDirection direction)
{
switch (direction) {
case PinchDirection::Contracting:
return PinchDirection::Expanding;
case PinchDirection::Expanding:
return PinchDirection::Contracting;
}
}
void TogglableGesture::addTouchpadGesture(PinchDirection direction, uint fingerCount)
{
auto progressCallback = [this](qreal progress) {
m_state->setProgress(progress);
};
auto progressCallbackInv = [this](qreal progress) {
m_state->setRegress(progress);
};
effects->registerTouchpadPinchShortcut(direction, 4, m_state->activateAction(), progressCallback);
effects->registerTouchpadPinchShortcut(opposite(direction), 4, m_state->deactivateAction(), progressCallbackInv);
}
static SwipeDirection opposite(SwipeDirection direction)
{
switch (direction) {
case SwipeDirection::Invalid:
return SwipeDirection::Invalid;
case SwipeDirection::Down:
return SwipeDirection::Up;
case SwipeDirection::Up:
return SwipeDirection::Down;
case SwipeDirection::Left:
return SwipeDirection::Right;
case SwipeDirection::Right:
return SwipeDirection::Left;
}
}
void TogglableGesture::addTouchscreenSwipeGesture(SwipeDirection direction, uint fingerCount)
{
auto progressCallback = [this](qreal progress) {
m_state->setProgress(progress);
};
auto progressCallbackInv = [this](qreal progress) {
m_state->setRegress(progress);
};
effects->registerTouchscreenSwipeShortcut(direction, 3, m_state->activateAction(), progressCallback);
effects->registerTouchscreenSwipeShortcut(opposite(direction), 3, m_state->deactivateAction(), progressCallbackInv);
}
TogglableTouchBorder::TogglableTouchBorder(TogglableState *state)
: QObject(state)
, m_state(state)
{
}
TogglableTouchBorder::~TogglableTouchBorder()
{
for (const ElectricBorder &border : std::as_const(m_touchBorderActivate)) {
effects->unregisterTouchBorder(border, m_state->toggleAction());
}
}
void TogglableTouchBorder::setBorders(const QList<int> &touchActivateBorders)
{
for (const ElectricBorder &border : std::as_const(m_touchBorderActivate)) {
effects->unregisterTouchBorder(border, m_state->toggleAction());
}
m_touchBorderActivate.clear();
for (const int &border : touchActivateBorders) {
m_touchBorderActivate.append(ElectricBorder(border));
effects->registerRealtimeTouchBorder(ElectricBorder(border), m_state->toggleAction(), [this](ElectricBorder border, const QPointF &deltaProgress, const EffectScreen *screen) {
if (m_state->status() == TogglableState::Status::Active) {
return;
}
const int maxDelta = 500; // Arbitrary logical pixels value seems to behave better than scaledScreenSize
qreal progress = 0;
if (border == ElectricTop || border == ElectricBottom) {
progress = std::min(1.0, std::abs(deltaProgress.y()) / maxDelta);
} else {
progress = std::min(1.0, std::abs(deltaProgress.x()) / maxDelta);
}
m_state->setProgress(progress);
});
}
}
OverviewEffect::OverviewEffect()
: m_state(new TogglableState(this))
, m_border(new TogglableTouchBorder(m_state))
, m_shutdownTimer(new QTimer(this))
{
auto gesture = new TogglableGesture(m_state);
gesture->addTouchpadGesture(PinchDirection::Contracting, 4);
gesture->addTouchpadPinchGesture(PinchDirection::Contracting, 4);
gesture->addTouchscreenSwipeGesture(SwipeDirection::Up, 3);
connect(m_state, &TogglableState::activated, this, &OverviewEffect::activate);

@ -7,108 +7,11 @@
#pragma once
#include "libkwineffects/kwinquickeffect.h"
#include "libkwineffects/togglablestate.h"
namespace KWin
{
class TogglableState : public QObject
{
Q_OBJECT
public:
enum class Status {
Inactive,
Activating,
Deactivating,
Active
};
Q_ENUM(Status);
TogglableState(QObject *parent);
bool inProgress() const;
void setInProgress(bool gesture);
qreal partialActivationFactor() const
{
return m_partialActivationFactor;
}
void setPartialActivationFactor(qreal factor);
QAction *activateAction() const
{
return m_activateAction;
}
QAction *deactivateAction() const
{
return m_deactivateAction;
}
QAction *toggleAction() const
{
return m_toggleAction;
}
void activate();
void deactivate();
void toggle();
void setStatus(Status status);
Status status() const
{
return m_status;
}
Q_SIGNALS:
void inProgressChanged();
void partialActivationFactorChanged();
void activated();
void deactivated();
void statusChanged(Status status);
protected:
void setProgress(qreal progress);
/// regress being the progress when on an active state
void setRegress(qreal regress);
private:
void partialActivate(qreal factor);
void partialDeactivate(qreal factor);
QAction *m_deactivateAction = nullptr;
QAction *m_activateAction = nullptr;
QAction *m_toggleAction = nullptr;
Status m_status = Status::Inactive;
bool m_inProgress = false;
qreal m_partialActivationFactor = 0;
friend class TogglableGesture;
friend class TogglableTouchBorder;
};
class TogglableGesture : public QObject
{
public:
TogglableGesture(TogglableState *state);
void addTouchpadGesture(PinchDirection dir, uint fingerCount);
void addTouchscreenSwipeGesture(SwipeDirection direction, uint fingerCount);
private:
TogglableState *const m_state;
};
class TogglableTouchBorder : public QObject
{
public:
TogglableTouchBorder(TogglableState *state);
~TogglableTouchBorder();
void setBorders(const QList<int> &borders);
private:
QList<ElectricBorder> m_touchBorderActivate;
TogglableState *const m_state;
};
class OverviewEffect : public QuickSceneEffect
{
Q_OBJECT

Loading…
Cancel
Save