1
0
mirror of https://github.com/KDE/latte-dock.git synced 2025-03-09 00:58:15 +03:00

introduce View::EventsSink

This commit is contained in:
Michail Vourlakos 2020-12-29 19:32:25 +02:00
parent 60aa17dada
commit bc50b437e9
5 changed files with 356 additions and 147 deletions

View File

@ -3,6 +3,7 @@ set(lattedock-app_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/containmentinterface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/contextmenu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/effects.cpp
${CMAKE_CURRENT_SOURCE_DIR}/eventssink.cpp
${CMAKE_CURRENT_SOURCE_DIR}/padding.cpp
${CMAKE_CURRENT_SOURCE_DIR}/panelshadows.cpp
${CMAKE_CURRENT_SOURCE_DIR}/parabolic.cpp

251
app/view/eventssink.cpp Normal file
View File

@ -0,0 +1,251 @@
/*
* Copyright 2020 Michail Vourlakos <mvourlakos@gmail.com>
*
* This file is part of Latte-Dock
*
* Latte-Dock is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* Latte-Dock is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "eventssink.h"
// local
#include "view.h"
#include "positioner.h"
// Qt
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QMouseEvent>
#include <QPointF>
#include <QRectF>
namespace Latte {
namespace ViewPart {
EventsSink::EventsSink(Latte::View *parent)
: QObject(parent),
m_view(parent)
{
}
EventsSink::~EventsSink()
{
}
QQuickItem *EventsSink::originItem() const
{
return m_originItem;
}
QQuickItem *EventsSink::destinationItem() const
{
return m_destinationItem;
}
void EventsSink::setSink(QQuickItem *origin, QQuickItem *destination)
{
if ((m_originItem == origin) && (m_destinationItem == destination)) {
return;
}
m_originItem = origin;
m_destinationItem = destination;
emit itemsChanged();
}
bool EventsSink::isActive()
{
return ((m_originItem != nullptr) && (m_destinationItem != nullptr));
}
void EventsSink::release()
{
setSink(nullptr, nullptr);
}
QEvent *EventsSink::onEvent(QEvent *e)
{
if (!e) {
return nullptr;
}
if (!isActive()) {
return e;
}
QEvent *sunkevent = e;
switch (e->type()) {
case QEvent::Leave:
release();
break;
case QEvent::DragEnter:
if (auto de = static_cast<QDragEnterEvent *>(e)) {
QPointF point = de->posF();
QPointF originInternal = m_originItem->mapFromScene(point);
if (m_originItem->contains(originInternal)) {
auto de2 = new QDragEnterEvent(positionAdjustedForDestination(point).toPoint(),
de->possibleActions(),
de->mimeData(),
de->mouseButtons(),
de->keyboardModifiers());
sunkevent = de2;
} else {
release();
}
}
break;
case QEvent::DragMove:
if (auto de = static_cast<QDragMoveEvent *>(e)) {
QPointF point = de->posF();
QPointF originInternal = m_originItem->mapFromScene(point);
if (m_originItem->contains(originInternal)) {
auto de2 = new QDragMoveEvent(positionAdjustedForDestination(point).toPoint(),
de->possibleActions(),
de->mimeData(),
de->mouseButtons(),
de->keyboardModifiers());
sunkevent = de2;
} else {
release();
}
}
break;
case QEvent::Drop:
if (auto de = static_cast<QDropEvent *>(e)) {
QPointF point = de->posF();
QPointF originInternal = m_originItem->mapFromScene(point);
if (m_originItem->contains(originInternal)) {
auto de2 = new QDropEvent(positionAdjustedForDestination(point).toPoint(),
de->possibleActions(),
de->mimeData(),
de->mouseButtons(),
de->keyboardModifiers());
sunkevent = de2;
} else {
release();
}
}
break;
case QEvent::MouseMove:
if (auto me = dynamic_cast<QMouseEvent *>(e)) {
QPointF originInternal = m_originItem->mapFromScene(me->windowPos());
if (m_view->positioner() && m_view->positioner()->isCursorInsideView() && m_originItem->contains(originInternal)) {
auto positionadjusted = positionAdjustedForDestination(me->windowPos());
auto me2 = new QMouseEvent(me->type(),
positionadjusted,
positionadjusted,
positionadjusted + m_view->position(),
me->button(), me->buttons(), me->modifiers());
sunkevent = me2;
} else {
release();
}
}
break;
case QEvent::MouseButtonPress:
if (auto me = dynamic_cast<QMouseEvent *>(e)) {
QPointF originInternal = m_originItem->mapFromScene(me->windowPos());
if (m_originItem->contains(originInternal)) {
auto positionadjusted = positionAdjustedForDestination(me->windowPos());
auto me2 = new QMouseEvent(me->type(),
positionadjusted,
positionadjusted,
positionadjusted + m_view->position(),
me->button(), me->buttons(), me->modifiers());
qDebug() << "Sunk Event:: sunk event pressed...";
sunkevent = me2;
} else {
release();
}
}
break;
case QEvent::MouseButtonRelease:
if (auto me = dynamic_cast<QMouseEvent *>(e)) {
QPointF originInternal = m_originItem->mapFromScene(me->windowPos());
if (m_originItem->contains(originInternal)) {
auto positionadjusted = positionAdjustedForDestination(me->windowPos());
auto me2 = new QMouseEvent(me->type(),
positionadjusted,
positionadjusted,
positionadjusted + m_view->position(),
me->button(), me->buttons(), me->modifiers());
sunkevent = me2;
} else {
release();
}
}
break;
case QEvent::Wheel:
if (auto we = dynamic_cast<QWheelEvent *>(e)) {
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
QPoint pos = QPoint(we->x(), we->y());
#else
QPoint pos = we->position().toPoint();
#endif
QPointF originInternal = m_originItem->mapFromScene(pos);
if (m_originItem->contains(originInternal)) {
auto positionadjusted = positionAdjustedForDestination(pos);
auto we2 = new QWheelEvent(positionadjusted,
positionadjusted + m_view->position(),
we->pixelDelta(), we->angleDelta(), we->angleDelta().y(),
we->orientation(), we->buttons(), we->modifiers(), we->phase());
sunkevent = we2;
} else {
release();
}
}
break;
default:
break;
}
return sunkevent;
}
QPointF EventsSink::positionAdjustedForDestination(const QPointF &point) const
{
QRectF destinationRectToScene = m_destinationItem->mapRectToScene(QRectF(0, 0, m_destinationItem->width(), m_destinationItem->height()));
return QPointF(qBound(destinationRectToScene.left(), point.x(), destinationRectToScene.right()),
qBound(destinationRectToScene.top(), point.y(), destinationRectToScene.bottom()));
}
}
}

76
app/view/eventssink.h Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright 2020 Michail Vourlakos <mvourlakos@gmail.com>
*
* This file is part of Latte-Dock
*
* Latte-Dock is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* Latte-Dock is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef VIEWEVENTSSINK_H
#define VIEWEVENTSSINK_H
// Qt
#include <QEvent>
#include <QObject>
#include <QQuickItem>
namespace Latte {
class View;
}
namespace Latte {
namespace ViewPart {
class EventsSink: public QObject
{
Q_OBJECT
Q_PROPERTY(QQuickItem *originItem READ originItem NOTIFY itemsChanged)
Q_PROPERTY(QQuickItem *destinationItem READ destinationItem NOTIFY itemsChanged)
public:
EventsSink(Latte::View *parent);
virtual ~EventsSink();
bool isActive();
QQuickItem *originItem() const;
QQuickItem *destinationItem() const;
public slots:
Q_INVOKABLE void setSink(QQuickItem *origin, QQuickItem *destination);
QEvent *onEvent(QEvent *e);
signals:
void itemsChanged();
private slots:
void release();
private:
QPointF positionAdjustedForDestination(const QPointF &point) const;
private:
QPointer<Latte::View> m_view;
QQuickItem *m_originItem{nullptr};
QQuickItem *m_destinationItem{nullptr};
};
}
}
#endif

View File

@ -80,7 +80,8 @@ View::View(Plasma::Corona *corona, QScreen *targetScreen, bool byPassWM)
m_effects(new ViewPart::Effects(this)),
m_interface(new ViewPart::ContainmentInterface(this)),
m_padding(new ViewPart::Padding(this)),
m_parabolic(new ViewPart::Parabolic(this))
m_parabolic(new ViewPart::Parabolic(this)),
m_sink(new ViewPart::EventsSink(this))
{
//! needs to be created after Effects because it catches some of its signals
//! and avoid a crash from View::winId() at the same time
@ -313,9 +314,6 @@ void View::init(Plasma::Containment *plasma_containment)
emit availableScreenRectChangedFrom(this);
});
connect(this, &View::localGeometryChanged, this, &View::updateSinkedEventsGeometry);
connect(m_padding, &ViewPart::Padding::paddingsChanged, this, &View::updateSinkedEventsGeometry);
connect(m_contextMenu, &ViewPart::ContextMenu::menuChanged, this, &View::contextMenuIsShownChanged);
connect(m_interface, &ViewPart::ContainmentInterface::hasExpandedAppletChanged, this, &View::verticalUnityViewHasFocus);
@ -1309,6 +1307,11 @@ ViewPart::Positioner *View::positioner() const
return m_positioner;
}
ViewPart::EventsSink *View::sink() const
{
return m_sink;
}
ViewPart::VisibilityManager *View::visibility() const
{
return m_visibility;
@ -1345,11 +1348,13 @@ void View::setInterfacesGraphicObj(Latte::Interfaces *ifaces)
bool View::event(QEvent *e)
{
QEvent *adjustedevent = e;
QEvent *sunkevent = e;
if (!m_inDelete) {
emit eventTriggered(e);
bool sinkableevent{false};
switch (e->type()) {
case QEvent::Enter:
m_containsMouse = true;
@ -1358,22 +1363,12 @@ bool View::event(QEvent *e)
case QEvent::Leave:
m_containsMouse = false;
setContainsDrag(false);
sinkableevent = true;
break;
case QEvent::DragEnter:
setContainsDrag(true);
if (auto de = static_cast<QDragEnterEvent *>(e)) {
//! adjust event by taking into account paddings
if (m_padding
&& !m_padding->isEmpty()
&& !containmentContainsPosition(de->pos())) {
auto de2 = new QDragEnterEvent(positionAdjustedForContainment(de->pos()).toPoint(),
de->possibleActions(), de->mimeData(), de->mouseButtons(), de->keyboardModifiers());
adjustedevent = de2;
}
}
sinkableevent = true;
break;
case QEvent::DragLeave:
@ -1381,99 +1376,29 @@ bool View::event(QEvent *e)
break;
case QEvent::DragMove:
if (auto de = static_cast<QDragMoveEvent *>(e)) {
//! adjust event by taking into account paddings
if (m_padding
&& !m_padding->isEmpty()
&& !containmentContainsPosition(de->pos())) {
auto de2 = new QDragMoveEvent(positionAdjustedForContainment(de->pos()).toPoint(),
de->possibleActions(), de->mimeData(), de->mouseButtons(), de->keyboardModifiers());
adjustedevent = de2;
}
}
sinkableevent = true;
break;
case QEvent::Drop:
setContainsDrag(false);
if (auto de = static_cast<QDropEvent *>(e)) {
//! adjust event by taking into account paddings
if (m_padding
&& !m_padding->isEmpty()
&& !containmentContainsPosition(de->pos())) {
auto de2 = new QDropEvent(positionAdjustedForContainment(de->pos()).toPoint(),
de->possibleActions(), de->mimeData(), de->mouseButtons(), de->keyboardModifiers());
adjustedevent = de2;
}
}
sinkableevent = true;
break;
case QEvent::MouseMove:
if (auto me = dynamic_cast<QMouseEvent *>(e)) {
//! adjust event by taking into account paddings
if (m_padding
&& !m_padding->isEmpty()
&& m_positioner && m_positioner->isCursorInsideView() /*dont break drags when cursor is outside*/
&& !containmentContainsPosition(me->windowPos())) {
auto positionadjusted = positionAdjustedForContainment(me->windowPos());
auto me2 = new QMouseEvent(me->type(),
positionadjusted,
positionadjusted,
positionadjusted + position(),
me->button(), me->buttons(), me->modifiers());
adjustedevent = me2;
}
}
sinkableevent = true;
break;
case QEvent::MouseButtonPress:
if (auto me = dynamic_cast<QMouseEvent *>(e)) {
emit mousePressed(me->pos(), me->button());
//! adjust event by taking into account paddings
if (m_padding
&& !m_padding->isEmpty()
&& m_positioner && m_positioner->isCursorInsideView() /*dont break drags when cursor is outside*/
&& !containmentContainsPosition(me->windowPos())) {
auto positionadjusted = positionAdjustedForContainment(me->windowPos());
auto me2 = new QMouseEvent(me->type(),
positionadjusted,
positionadjusted,
positionadjusted + position(),
me->button(), me->buttons(), me->modifiers());
qDebug() << "Sinked Event:: adjusted event pressed...";
qDebug() << "Sinked Event:: pressed metrics :: " << me->windowPos() << " => " << me2->windowPos() << " | " << m_padding->margins();
adjustedevent = me2;
}
sinkableevent = true;
}
break;
case QEvent::MouseButtonRelease:
if (auto me = dynamic_cast<QMouseEvent *>(e)) {
emit mouseReleased(me->pos(), me->button());
//! adjust event by taking into account paddings
if (m_padding
&& !m_padding->isEmpty()
&& m_positioner && m_positioner->isCursorInsideView() /*dont break drags when cursor is outside*/
&& !containmentContainsPosition(me->windowPos())) {
auto positionadjusted = positionAdjustedForContainment(me->windowPos());
auto me2 = new QMouseEvent(me->type(),
positionadjusted,
positionadjusted,
positionadjusted + position(),
me->button(), me->buttons(), me->modifiers());
adjustedevent = me2;
}
sinkableevent = true;
}
break;
@ -1520,64 +1445,21 @@ bool View::event(QEvent *e)
#endif
emit wheelScrolled(pos, we->angleDelta(), we->buttons());
//! adjust event by taking into account paddings
if (m_padding
&& !m_padding->isEmpty()
&& !containmentContainsPosition(pos)) {
auto positionadjusted = positionAdjustedForContainment(pos);
auto we2 = new QWheelEvent(positionadjusted,
positionadjusted + position(),
we->pixelDelta(), we->angleDelta(), we->angleDelta().y(),
we->orientation(), we->buttons(), we->modifiers(), we->phase());
adjustedevent = we2;
}
sinkableevent = true;
}
break;
default:
break;
}
if (sinkableevent && m_sink->isActive()) {
sunkevent = m_sink->onEvent(e);
}
}
return ContainmentView::event(adjustedevent);
return ContainmentView::event(sunkevent);
}
void View::updateSinkedEventsGeometry()
{
if (m_inDelete || !m_padding) {
return;
}
QRectF sinked = m_localGeometry;
if (m_padding && !m_padding->isEmpty()) {
sinked -= m_padding->margins();
}
if (location() == Plasma::Types::TopEdge || location() == Plasma::Types::BottomEdge) {
/*remove the bottom pixel that is needed from dodge and touching edge algorithms*/
sinked -= QMargins(0,0,0,1);
} else if (location() == Plasma::Types::RightEdge || location() == Plasma::Types::LeftEdge) {
/*remove the right pixel that is needed from dodge and touching edge algorithms*/
sinked -= QMargins(0,0,1,0);
}
m_sinkedEventsGeometry = sinked;
}
bool View::containmentContainsPosition(const QPointF &point) const
{
return m_sinkedEventsGeometry.contains(point);
}
QPointF View::positionAdjustedForContainment(const QPointF &point) const
{
return QPointF(qBound(m_sinkedEventsGeometry.left(), point.x(), m_sinkedEventsGeometry.right()),
qBound(m_sinkedEventsGeometry.top(), point.y(), m_sinkedEventsGeometry.bottom()));
}
void View::releaseConfigView()
{
m_primaryConfigView = nullptr;

View File

@ -28,6 +28,7 @@
#include "padding.h"
#include "parabolic.h"
#include "positioner.h"
#include "eventssink.h"
#include "visibilitymanager.h"
#include "indicator/indicator.h"
#include "settings/primaryconfigview.h"
@ -126,6 +127,7 @@ class View : public PlasmaQuick::ContainmentView
Q_PROPERTY(Latte::ViewPart::Padding *padding READ padding NOTIFY paddingChanged)
Q_PROPERTY(Latte::ViewPart::Parabolic *parabolic READ parabolic NOTIFY parabolicChanged)
Q_PROPERTY(Latte::ViewPart::Positioner *positioner READ positioner NOTIFY positionerChanged)
Q_PROPERTY(Latte::ViewPart::EventsSink *sink READ sink NOTIFY sinkChanged)
Q_PROPERTY(Latte::ViewPart::VisibilityManager *visibility READ visibility NOTIFY visibilityChanged)
Q_PROPERTY(Latte::ViewPart::WindowsTracker *windowsTracker READ windowsTracker NOTIFY windowsTrackerChanged)
@ -242,6 +244,7 @@ public:
ViewPart::Padding *padding() const;
ViewPart::Parabolic *parabolic() const;
ViewPart::Positioner *positioner() const;
ViewPart::EventsSink *sink() const;
ViewPart::VisibilityManager *visibility() const;
ViewPart::WindowsTracker *windowsTracker() const;
@ -331,6 +334,7 @@ signals:
void screenEdgeMarginChanged();
void screenEdgeMarginEnabledChanged();
void screenGeometryChanged();
void sinkChanged();
void typeChanged();
void visibilityChanged();
void windowsTrackerChanged();
@ -361,8 +365,6 @@ private slots:
void addTransientWindow(QWindow *window);
void removeTransientWindow(const bool &visible);
void updateSinkedEventsGeometry();
//! workaround in order for top panels to be always on top
void topViewAlwaysOnTop();
void verticalUnityViewHasFocus();
@ -380,9 +382,6 @@ private:
void setContainsDrag(bool contains);
bool containmentContainsPosition(const QPointF &point) const;
QPointF positionAdjustedForContainment(const QPointF &point) const;
private:
Plasma::Containment *containmentById(uint id);
@ -413,7 +412,6 @@ private:
QRect m_localGeometry;
QRect m_absoluteGeometry;
QRectF m_sinkedEventsGeometry;
QStringList m_activities;
@ -445,6 +443,7 @@ private:
QPointer<ViewPart::Padding> m_padding;
QPointer<ViewPart::Parabolic> m_parabolic;
QPointer<ViewPart::Positioner> m_positioner;
QPointer<ViewPart::EventsSink> m_sink;
QPointer<ViewPart::VisibilityManager> m_visibility;
QPointer<ViewPart::WindowsTracker> m_windowsTracker;