commit 730f48c80662130e3f9ec37d32fc358bfc0f9ed4 Author: David Edmundson 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 +#include +#include +#include + +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(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(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 +#include + +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 m_trackedItem; + QPointer 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 + } + } + } +}