11#include <QQmlProperty> 
   13#include <QQuickRenderControl> 
   14#include <QQuickWindow> 
   17#include <KAcceleratorManager> 
   22QMenuProxy::QMenuProxy(
QObject *parent)
 
   26    , m_placement(LeftPosedTopAlignedPopup)
 
   27    , m_preferSeamlessEdges(false)
 
   30        m_menu = 
new QMenu(
nullptr);
 
   40            Q_EMIT statusChanged();
 
   45QMenuProxy::~QMenuProxy()
 
   52    return QQmlListProperty<QMenuItem>(
this, &m_items);
 
   55int QMenuProxy::actionCount()
 const 
   57    return m_items.count();
 
   60QMenuItem *QMenuProxy::action(
int index)
 const 
   62    return m_items.at(index);
 
   65QMenuProxy::Status QMenuProxy::status()
 const 
   70QObject *QMenuProxy::visualParent()
 const 
   72    return m_visualParent.data();
 
   75void QMenuProxy::setVisualParent(
QObject *parent)
 
   77    if (m_visualParent.data() == 
parent) {
 
   84        action->setMenu(
nullptr);
 
   90        action->setMenu(m_menu);
 
   92        for (QMenuItem *item : std::as_const(m_items)) {
 
   93            if (item->section()) {
 
   94                if (!item->isVisible()) {
 
   98                m_menu->addSection(item->text());
 
  100                m_menu->addAction(item->action());
 
  103        m_menu->updateGeometry();
 
  107    Q_EMIT visualParentChanged();
 
  110QWindow *QMenuProxy::transientParent()
 
  112    if (!m_menu || !m_menu->windowHandle()) {
 
  118void QMenuProxy::setTransientParent(
QWindow *parent)
 
  120    if (!m_menu || !m_menu->windowHandle() || 
parent == m_menu->windowHandle()->transientParent()) {
 
  124    m_menu->windowHandle()->setTransientParent(
parent);
 
  125    Q_EMIT transientParentChanged();
 
  128QMenuProxy::PopupPlacement QMenuProxy::placement()
 const 
  133void QMenuProxy::setPlacement(QMenuProxy::PopupPlacement placement)
 
  135    if (m_placement != placement) {
 
  136        m_placement = placement;
 
  138        Q_EMIT placementChanged();
 
  142bool QMenuProxy::preferSeamlessEdges()
 const 
  144    return m_preferSeamlessEdges;
 
  147void QMenuProxy::setPreferSeamlessEdges(
bool request)
 
  149    if (m_preferSeamlessEdges != request) {
 
  150        m_preferSeamlessEdges = request;
 
  152        Q_EMIT preferSeamlessEdgesChanged();
 
  156int QMenuProxy::minimumWidth()
 const 
  158    return m_menu->minimumWidth();
 
  161void QMenuProxy::setMinimumWidth(
int width)
 
  163    if (m_menu->minimumWidth() != width) {
 
  164        m_menu->setMinimumWidth(width);
 
  166        Q_EMIT minimumWidthChanged();
 
  170int QMenuProxy::maximumWidth()
 const 
  172    return m_menu->maximumWidth();
 
  175void QMenuProxy::setMaximumWidth(
int width)
 
  177    if (m_menu->maximumWidth() != width) {
 
  178        m_menu->setMaximumWidth(width);
 
  180        Q_EMIT maximumWidthChanged();
 
  184void QMenuProxy::resetMaximumWidth()
 
  186    setMaximumWidth(QWIDGETSIZE_MAX);
 
  189bool QMenuProxy::event(
QEvent *event)
 
  191    switch (event->type()) {
 
  193        QChildEvent *ce = 
static_cast<QChildEvent *
>(event);
 
  196        if (mi && !m_items.contains(mi)) {
 
  197            if (mi->separator()) {
 
  198                m_menu->addSection(mi->text());
 
  200                m_menu->addAction(mi->action());
 
  208        QChildEvent *ce = 
static_cast<QChildEvent *
>(event);
 
  213            m_menu->removeAction(mi->action());
 
  214            m_items.removeAll(mi);
 
  226void QMenuProxy::clearMenuItems()
 
  232void QMenuProxy::addMenuItem(
const QString &text)
 
  234    QMenuItem *item = 
new QMenuItem();
 
  236    m_menu->addAction(item->action());
 
  240void QMenuProxy::addMenuItem(QMenuItem *item, QMenuItem *before)
 
  243        if (m_items.contains(item)) {
 
  244            m_menu->removeAction(item->action());
 
  245            m_items.removeAll(item);
 
  248        m_menu->insertAction(before->action(), item->action());
 
  250        const int index = m_items.indexOf(before);
 
  253            m_items.insert(index, item);
 
  258    } 
else if (!m_items.contains(item)) {
 
  259        m_menu->addAction(item->action());
 
  263        removeMenuItem(item);
 
  267void QMenuProxy::addSection(
const QString &text)
 
  269    m_menu->addSection(text);
 
  272void QMenuProxy::removeMenuItem(QMenuItem *item)
 
  278    m_menu->removeAction(item->action());
 
  279    m_items.removeOne(item);
 
  282void QMenuProxy::itemTriggered(
QAction *action)
 
  284    for (
int i = 0; i < m_items.count(); ++i) {
 
  285        QMenuItem *item = m_items.at(i);
 
  286        if (item->action() == action) {
 
  294void QMenuProxy::rebuildMenu()
 
  298    for (QMenuItem *item : std::as_const(m_items)) {
 
  299        if (item->section()) {
 
  300            if (!item->isVisible()) {
 
  304            m_menu->addSection(item->text());
 
  306            m_menu->addAction(item->action());
 
  307            if (item->action()->
menu()) {
 
  316    m_menu->adjustSize();
 
  326            QPoint relativePos = pos + offset;
 
  327            return renderWindow->mapToGlobal(relativePos);
 
  329            return quickWindow->mapToGlobal(pos);
 
  336void QMenuProxy::open(
int x, 
int y)
 
  338    QQuickItem *parentItem = 
nullptr;
 
  340    if (m_visualParent) {
 
  352    QPointF posLocal = parentItem->mapToScene(QPointF(x, y));
 
  354    QPoint posGlobal = mapToGlobalUsingRenderWindowOfItem(parentItem, posLocal);
 
  356    setupSeamlessEdges(std::nullopt);
 
  358    openInternal(posGlobal);
 
  361void QMenuProxy::openRelative()
 
  363    QQuickItem *parentItem = 
nullptr;
 
  365    if (m_visualParent) {
 
  380    auto boundaryCorrection = [
this, &posLocal, &posGlobal, parentItem](
int hDelta, 
int vDelta) {
 
  381        if (
auto window = parentItem->window(); 
 
  383            QRect 
geo = screen->geometry();
 
  385            QPoint pos = mapToGlobalUsingRenderWindowOfItem(parentItem, posLocal);
 
  387            if (pos.
x() < 
geo.x()) {
 
  388                pos.
setX(pos.
x() + hDelta);
 
  390            if (pos.
y() < 
geo.y()) {
 
  391                pos.
setY(pos.
y() + vDelta);
 
  394            if (
geo.x() + 
geo.width() < pos.
x() + this->m_menu->width()) {
 
  395                pos.
setX(pos.
x() + hDelta);
 
  397            if (
geo.y() + 
geo.height() < pos.
y() + this->m_menu->height()) {
 
  398                pos.
setY(pos.
y() + vDelta);
 
  402            posGlobal = posLocal.
toPoint();
 
  406    const QQmlProperty enabledProp(parentItem, QStringLiteral(
"LayoutMirroring.enabled"), qmlContext(parentItem));
 
  407    const bool mirrored(enabledProp.read().toBool());
 
  410    using namespace Plasma;
 
  413    case TopPosedLeftAlignedPopup: {
 
  414        posLocal = parentItem->mapToScene(QPointF(0, -m_menu->height()));
 
  415        boundaryCorrection(-m_menu->width() + parentItem->width(), m_menu->height() + parentItem->height());
 
  418    case LeftPosedTopAlignedPopup: {
 
  419        posLocal = parentItem->mapToScene(QPointF(-m_menu->width(), 0));
 
  420        boundaryCorrection(m_menu->width() + parentItem->width(), -m_menu->height() + parentItem->height());
 
  423    case TopPosedRightAlignedPopup:
 
  424        posLocal = parentItem->mapToScene(QPointF(parentItem->width() - m_menu->width(), -m_menu->height()));
 
  425        boundaryCorrection(m_menu->width() - parentItem->width(), m_menu->height() + parentItem->height());
 
  427    case RightPosedTopAlignedPopup: {
 
  428        posLocal = parentItem->mapToScene(QPointF(parentItem->width(), 0));
 
  429        boundaryCorrection(-m_menu->width() - parentItem->width(), -m_menu->height() + parentItem->height());
 
  432    case LeftPosedBottomAlignedPopup:
 
  433        posLocal = parentItem->mapToScene(QPointF(-m_menu->width(), -m_menu->height() + parentItem->height()));
 
  434        boundaryCorrection(m_menu->width() + parentItem->width(), m_menu->height() - parentItem->height());
 
  436    case BottomPosedLeftAlignedPopup: {
 
  437        posLocal = parentItem->mapToScene(QPointF(0, parentItem->height()));
 
  438        boundaryCorrection(-m_menu->width() + parentItem->width(), -m_menu->height() - parentItem->height());
 
  441    case BottomPosedRightAlignedPopup: {
 
  442        posLocal = parentItem->mapToScene(QPointF(parentItem->width() - m_menu->width(), parentItem->height()));
 
  443        boundaryCorrection(m_menu->width() - parentItem->width(), -m_menu->height() - parentItem->height());
 
  446    case RightPosedBottomAlignedPopup: {
 
  447        posLocal = parentItem->mapToScene(QPointF(parentItem->width(), -m_menu->height() + parentItem->height()));
 
  448        boundaryCorrection(-m_menu->width() - parentItem->width(), m_menu->height() - parentItem->height());
 
  456    setupSeamlessEdges(std::optional(placement));
 
  458    openInternal(posGlobal);
 
  461void QMenuProxy::openInternal(
QPoint pos)
 
  463    QQuickItem *parentItem = this->parentItem();
 
  465    if (parentItem && parentItem->window()) {
 
  468        m_menu->windowHandle()->setTransientParent(parentItem->window());
 
  476                QQuickItem *parentItem = this->parentItem();
 
  477                if (parentItem && parentItem->window() && parentItem->window()->mouseGrabberItem()) {
 
  478                    parentItem->window()->mouseGrabberItem()->ungrabMouse();
 
  492    if (m_visualParent) {
 
  499void QMenuProxy::close()
 
  504QMenuProxy::PopupPlacement QMenuProxy::visualPopupPlacement(PopupPlacement placement, 
Qt::LayoutDirection layoutDirection)
 
  513    case TopPosedLeftAlignedPopup:
 
  514        return TopPosedRightAlignedPopup;
 
  515    case TopPosedRightAlignedPopup:
 
  516        return TopPosedLeftAlignedPopup;
 
  517    case LeftPosedTopAlignedPopup:
 
  518        return RightPosedTopAlignedPopup;
 
  519    case LeftPosedBottomAlignedPopup:
 
  520        return RightPosedBottomAlignedPopup;
 
  521    case BottomPosedLeftAlignedPopup:
 
  522        return BottomPosedRightAlignedPopup;
 
  523    case BottomPosedRightAlignedPopup:
 
  524        return BottomPosedLeftAlignedPopup;
 
  525    case RightPosedTopAlignedPopup:
 
  526        return LeftPosedTopAlignedPopup;
 
  527    case RightPosedBottomAlignedPopup:
 
  528        return LeftPosedBottomAlignedPopup;
 
  535Qt::Edges QMenuProxy::seamlessEdgesForPlacement(std::optional<PopupPlacement> placement)
 
  537    if (m_preferSeamlessEdges && placement.has_value()) {
 
  538        switch (placement.value()) {
 
  539        case TopPosedLeftAlignedPopup:
 
  540        case TopPosedRightAlignedPopup:
 
  543        case LeftPosedTopAlignedPopup:
 
  544        case LeftPosedBottomAlignedPopup:
 
  547        case BottomPosedLeftAlignedPopup:
 
  548        case BottomPosedRightAlignedPopup:
 
  551        case RightPosedTopAlignedPopup:
 
  552        case RightPosedBottomAlignedPopup:
 
  564void QMenuProxy::setupSeamlessEdges(std::optional<PopupPlacement> placement)
 
  567    auto edges = seamlessEdgesForPlacement(placement);
 
  571#include "moc_qmenu.cpp" 
static void manage(QWidget *widget, bool programmers_mode=false)
 
GeoCoordinates geo(const QVariant &location)
 
QObject * child() const const
 
QCoreApplication * instance()
 
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
 
void destroyed(QObject *obj)
 
virtual bool event(QEvent *e)
 
QObject * parent() const const
 
T qobject_cast(QObject *object)
 
QPoint toPoint() const const
 
QQuickWindow * window() const const
 
QWindow * renderWindowFor(QQuickWindow *win, QPoint *offset)
 
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
 
QVariant fromValue(T &&value)