Paste P183

Masterwork From Distant Lands
ActivePublic

Authored by davidedmundson on Apr 1 2018, 9:09 PM.
commit 730f48c80662130e3f9ec37d32fc358bfc0f9ed4
Author: David Edmundson <kde@davidedmundson.co.uk>
Date: Sun Apr 1 22:08:42 2018 +0100
WIP: DelayedMenuThing
QML implementation of http://bjk5.com/post/44698559168/breaking-down-
amazons-mega-dropdown
diff --git a/src/qmlcontrols/kquickcontrolsaddons/delayedselectionmousefilter.cpp b/src/qmlcontrols/kquickcontrolsaddons/delayedselectionmousefilter.cpp
new file mode 100644
index 0000000..97e2eaf
--- /dev/null
+++ b/src/qmlcontrols/kquickcontrolsaddons/delayedselectionmousefilter.cpp
@@ -0,0 +1,101 @@
+#include "delayedselectionmousefilter.h"
+
+#include <QHoverEvent>
+#include <QDebug>
+#include <QPolygonF>
+#include <QGuiApplication>
+
+DelayedSelectionMouseFilter::DelayedSelectionMouseFilter(QQuickItem *parent)
+ : QQuickItem(parent)
+{
+ setFiltersChildMouseEvents(true);
+}
+
+DelayedSelectionMouseFilter::~DelayedSelectionMouseFilter()
+{}
+
+
+void DelayedSelectionMouseFilter::replaceTracking(const QPointF &point)
+{
+ if (m_trackedItem == m_naturalOwner) {
+ return;
+ }
+ // send leave to m_trackedItem
+ if (m_trackedItem) {
+ QHoverEvent ev(QEvent::HoverLeave, mapToItem(m_trackedItem.data(), point), mapToItem(m_trackedItem.data(), point));
+ QGuiApplication::sendEvent(m_trackedItem.data(), &ev);
+ m_trackedItem = nullptr;
+ }
+
+ //if relevant deliver a hoverEnter to the item that should have it and start tracking that
+ if (m_naturalOwner) {
+ QHoverEvent ev(QEvent::HoverEnter, mapToItem(m_naturalOwner.data(), point), mapToItem(m_naturalOwner.data(), point));
+ QGuiApplication::sendEvent(m_naturalOwner.data(), &ev);
+ m_trackedItem = m_naturalOwner;
+ m_lastMousePoint = point;
+ }
+}
+
+bool DelayedSelectionMouseFilter::childMouseEventFilter(QQuickItem *item, QEvent *event)
+{
+ if (event->type() == QEvent::HoverEnter || event->type() == QEvent::HoverMove) {
+ auto hover = static_cast<QHoverEvent*>(event);
+ QPointF point = mapFromItem(item, hover->posF());
+ if (event->type() == QEvent::HoverEnter) {
+ m_naturalOwner = item;
+ }
+
+ if (item == m_trackedItem) {
+ if (withinTrackSpace(point)) {
+ return false;
+ } else {
+ m_lastMousePoint = point;
+ return false;
+ }
+ } else {
+ if (withinTrackSpace(point)) {
+ return true;
+ } else {
+ replaceTracking(point);
+ return true;
+ }
+ }
+ }
+ if (event->type() == QEvent::HoverLeave) {
+ auto hover = static_cast<QHoverEvent*>(event);
+ QPointF point = mapFromItem(item, hover->posF());
+ if (item == m_naturalOwner) {
+ m_naturalOwner = nullptr;
+ }
+ if (withinTrackSpace(point)) {
+ return true;
+ } else {
+ replaceTracking(point);
+ return true; //as we've already send a fake leave event there
+ }
+ }
+
+ return false;
+}
+
+//TODO
+//What if a mouse exits the whole area
+//What if a user clicks
+//What if a
+
+bool DelayedSelectionMouseFilter::withinTrackSpace(const QPointF &point) const
+{
+ if (!m_trackedItem) {
+ return false;
+ }
+ //we can do this manually maybe? It's just a triangle..
+ QPolygonF poly;
+// if (edge == Left) {
+// poly << m_lastMousePoint << QPointF(width()+1, 0) << QPointF(width()+1, height()) << m_lastMousePoint;
+// }
+// if (edge == top)
+ poly << m_lastMousePoint << QPointF(0, -1) << QPointF(width(), -1) << m_lastMousePoint;
+// }
+
+ return poly.containsPoint(point, Qt::OddEvenFill);
+}
diff --git a/src/qmlcontrols/kquickcontrolsaddons/delayedselectionmousefilter.h b/src/qmlcontrols/kquickcontrolsaddons/delayedselectionmousefilter.h
new file mode 100644
index 0000000..6062e71
--- /dev/null
+++ b/src/qmlcontrols/kquickcontrolsaddons/delayedselectionmousefilter.h
@@ -0,0 +1,29 @@
+#include <QQuickItem>
+#include <QPointer>
+
+class QHoverEvent;
+
+class DelayedSelectionMouseFilter : public QQuickItem
+{
+ Q_OBJECT
+
+
+public:
+ DelayedSelectionMouseFilter(QQuickItem *parent=nullptr);
+ ~DelayedSelectionMouseFilter();
+
+// void setTargetEdge(); //north, east, south, west DAVE: at what level should we be handling LTR?
+
+protected:
+ bool childMouseEventFilter(QQuickItem *item, QEvent *event);
+
+private:
+ void replaceTracking(const QPointF &point);
+ /* returns true if a given point is within our triangle between the last mouse point and the edge*/
+ bool withinTrackSpace(const QPointF &point) const;
+
+ QPointF m_lastMousePoint;
+ QPointer<QQuickItem> m_trackedItem;
+ QPointer<QQuickItem> m_naturalOwner;
+
+};
diff --git a/tests/menu.qml b/tests/menu.qml
new file mode 100644
index 0000000..025696f
--- /dev/null
+++ b/tests/menu.qml
@@ -0,0 +1,57 @@
+import QtQuick 2.4
+import QtQuick.Layouts 1.1
+import org.kde.kquickcontrolsaddons 2.0
+
+Rectangle
+{
+ id: root
+ color: "white"
+ width: 500
+ height: 500
+
+ property int currentMouseOver: -1
+
+ RowLayout {
+ anchors.fill: parent
+ DelayedSelectionMouseFilter {
+ implicitWidth: layout.implicitWidth
+ Layout.fillHeight: true
+ ColumnLayout {
+ anchors.fill: parent
+ id: layout
+ spacing: 0
+ Repeater {
+ model: 5
+ delegate: Rectangle {
+ Layout.fillHeight: true
+ implicitWidth: 150
+ color: ma.containsMouse ? "red" : "white"
+ border.color: "black"
+ border.width: 2
+ Text {
+ anchors.centerIn: parent
+ text: model.index
+ }
+ MouseArea {
+ id: ma
+ hoverEnabled: true
+ anchors.fill: parent
+ onEntered: root.currentMouseOver = model.index
+// onExited: root.currentMouseOver = -1
+ }
+ }
+ }
+ }
+ }
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ color: "blue"
+ Text {
+ anchors.centerIn: parent
+ text: root.currentMouseOver
+ color: white
+ }
+ }
+ }
+}
davidedmundson edited the content of this paste. (Show Details)Apr 1 2018, 9:09 PM
davidedmundson changed the title of this paste from untitled to Masterwork From Distant Lands.
davidedmundson updated the paste's language from autodetect to autodetect.