LCOV - code coverage report
Current view: top level - muse/framework/uicomponents/qml/Muse/UiComponents/internal - popupviewclosecontroller.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 103 0
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : 
      23              : #include "popupviewclosecontroller.h"
      24              : 
      25              : #include <QGuiApplication>
      26              : #include <QQuickWindow>
      27              : 
      28              : using namespace muse::uicomponents;
      29              : 
      30            0 : PopupViewCloseController::PopupViewCloseController(const modularity::ContextPtr& iocCtx, QObject* parent)
      31            0 :     : QObject(parent), muse::Contextable(iocCtx)
      32              : {
      33            0 : }
      34              : 
      35            0 : void PopupViewCloseController::init()
      36              : {
      37            0 :     connect(qApp, &QGuiApplication::applicationStateChanged, this, &PopupViewCloseController::onApplicationStateChanged);
      38              : 
      39            0 :     interactive()->currentUriAboutToBeChanged().onNotify(this, [this]() {
      40            0 :         notifyAboutClose();
      41            0 :     });
      42            0 : }
      43              : 
      44            0 : bool PopupViewCloseController::active() const
      45              : {
      46            0 :     return m_active;
      47              : }
      48              : 
      49            0 : void PopupViewCloseController::setActive(bool active)
      50              : {
      51            0 :     if (m_active == active) {
      52            0 :         return;
      53              :     }
      54              : 
      55            0 :     m_active = active;
      56              : 
      57            0 :     doUpdateEventFilters();
      58              : }
      59              : 
      60            0 : QQuickItem* PopupViewCloseController::parentItem() const
      61              : {
      62            0 :     return m_parentItem;
      63              : }
      64              : 
      65            0 : void PopupViewCloseController::setParentItem(QQuickItem* parentItem)
      66              : {
      67            0 :     if (m_parentItem) {
      68            0 :         m_parentItem->disconnect(this);
      69              :     }
      70              : 
      71            0 :     m_parentItem = parentItem;
      72              : 
      73            0 :     connect(m_parentItem, &QQuickItem::visibleChanged, this, [this]() {
      74            0 :         if (!m_parentItem || !m_parentItem->isVisible()) {
      75            0 :             notifyAboutClose();
      76              :         }
      77            0 :     });
      78              : 
      79            0 :     connect(m_parentItem, &QQuickItem::destroyed, this, [this]() {
      80            0 :         qApp->removeEventFilter(this);
      81            0 :         notifyAboutClose();
      82            0 :     });
      83            0 : }
      84              : 
      85            0 : void PopupViewCloseController::setWindow(QWindow* window)
      86              : {
      87            0 :     m_popupWindow = window;
      88            0 : }
      89              : 
      90            0 : void PopupViewCloseController::setIsCloseOnPressOutsideParent(bool arg)
      91              : {
      92            0 :     m_isCloseOnPressOutsideParent = arg;
      93            0 : }
      94              : 
      95            0 : void PopupViewCloseController::setCanClose(bool arg)
      96              : {
      97            0 :     m_canClose = arg;
      98            0 : }
      99              : 
     100            0 : muse::async::Notification PopupViewCloseController::closeNotification() const
     101              : {
     102            0 :     return m_closeNotification;
     103              : }
     104              : 
     105            0 : bool PopupViewCloseController::eventFilter(QObject* watched, QEvent* event)
     106              : {
     107            0 :     if (QEvent::Close == event->type() && watched == parentWindow()) {
     108            0 :         notifyAboutClose();
     109            0 :     } else if (QEvent::MouseButtonPress == event->type()) {
     110            0 :         doFocusOut(static_cast<QMouseEvent*>(event)->globalPosition());
     111            0 :     } else if (QEvent::FocusOut == event->type() && watched == popupWindow()) {
     112            0 :         doFocusOut(QCursor::pos());
     113            0 :     } else if (QEvent::Close == event->type() && watched == popupWindow()) {
     114            0 :         if (!m_canClose) {
     115            0 :             event->ignore();
     116              :         }
     117              :     }
     118              : 
     119            0 :     return QObject::eventFilter(watched, event);
     120              : }
     121              : 
     122            0 : void PopupViewCloseController::onApplicationStateChanged(Qt::ApplicationState state)
     123              : {
     124            0 :     if (!m_active || !m_isCloseOnPressOutsideParent) {
     125            0 :         return;
     126              :     }
     127              : 
     128              :     // Hack for https://github.com/musescore/MuseScore/issues/29656 on Linux
     129            0 :     if (interactive()->isSelectColorOpened()) {
     130            0 :         return;
     131              :     }
     132              : 
     133            0 :     if (state != Qt::ApplicationActive) {
     134            0 :         notifyAboutClose();
     135              :     }
     136              : }
     137              : 
     138            0 : void PopupViewCloseController::doFocusOut(const QPointF& mousePos)
     139              : {
     140            0 :     if (m_isCloseOnPressOutsideParent) {
     141            0 :         if (!isMouseWithinBoundaries(mousePos)) {
     142            0 :             notifyAboutClose();
     143              :         }
     144              :     }
     145            0 : }
     146              : 
     147            0 : void PopupViewCloseController::doUpdateEventFilters()
     148              : {
     149            0 :     if (active()) {
     150            0 :         qApp->installEventFilter(this);
     151              :     } else {
     152            0 :         qApp->removeEventFilter(this);
     153              :     }
     154            0 : }
     155              : 
     156            0 : bool PopupViewCloseController::isMouseWithinBoundaries(const QPointF& mousePos) const
     157              : {
     158            0 :     QWindow* window = popupWindow();
     159            0 :     if (!window) {
     160            0 :         return false;
     161              :     }
     162              : 
     163            0 :     QRectF viewRect = window->geometry();
     164            0 :     if (viewRect.contains(mousePos)) {
     165            0 :         return true;
     166              :     }
     167              : 
     168              :     //! NOTE We also check the parent because often clicking on the parent should toggle the popup,
     169              :     //! but if we don't check a parent here, the popup will be closed and reopened.
     170            0 :     QQuickItem* parent = parentItem();
     171            0 :     QPointF localPos = parent->mapFromGlobal(mousePos);
     172            0 :     QRectF parentRect = QRectF(0, 0, parent->width(), parent->height());
     173            0 :     if (parentRect.contains(localPos)) {
     174            0 :         return true;
     175              :     }
     176              : 
     177              :     //! NOTE We also check child windows
     178            0 :     for (QWindow* child : QGuiApplication::allWindows()) {
     179            0 :         if (!child->isVisible()) {
     180            0 :             continue;
     181              :         }
     182              : 
     183            0 :         if (!window->isAncestorOf(child, QWindow::IncludeTransients)) {
     184            0 :             continue;
     185              :         }
     186              : 
     187            0 :         QRectF childRect = child->geometry();
     188            0 :         if (childRect.contains(mousePos)) {
     189            0 :             return true;
     190              :         }
     191            0 :     }
     192              : 
     193              :     // Hack for https://github.com/musescore/MuseScore/issues/29656
     194            0 :     if (interactive()->isSelectColorOpened()) {
     195            0 :         return true;
     196              :     }
     197              : 
     198            0 :     return false;
     199              : }
     200              : 
     201            0 : void PopupViewCloseController::notifyAboutClose()
     202              : {
     203            0 :     m_closeNotification.notify();
     204            0 : }
     205              : 
     206            0 : QWindow* PopupViewCloseController::parentWindow() const
     207              : {
     208            0 :     if (m_parentItem && m_parentItem->window()) {
     209            0 :         return m_parentItem->window();
     210              :     }
     211              : 
     212            0 :     return mainWindow()->qWindow();
     213              : }
     214              : 
     215            0 : QWindow* PopupViewCloseController::popupWindow() const
     216              : {
     217            0 :     return m_popupWindow;
     218              : }
        

Generated by: LCOV version 2.0-1