Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-14739

QMenu: Dynamically populated submenus are incorrectly positioned near screen edges

    XMLWordPrintable

Details

    • 0848b860b9251e76b9319f65554f932ab68e33cc

    Description

      We've found that near the screen edges, these submenus are not correctly placed on the left side of the parent menu; they overlap the parent menu, causing usability problems (e.g., if the user accidentally invoked the submenu while navigating to a different menu item).

      A sample project is attached. To reproduce the issue, move the window to the right edge of the screen, and navigate to the "submenu" item. It should cover the parent item. Note that if you hover away from the submenu and move it back, the menu appears in the expected location.

      The problem appears to be that the code that determines where to place the submenu resides in internalDelayedPopup(), and is executed before the aboutToShow() signal is emitted. Thus, when the size of the submenu is queried, it is actually empty.

      Then, QMenu::popup() simply ensures that the menu is moved so that it doesn't fall offscreen, which causes it to obscure the underlying parent menu.

      Here is a potential fix:

      diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp
      index c05829a..b2ef545 100644
      --- a/src/gui/widgets/qmenu.cpp
      +++ b/src/gui/widgets/qmenu.cpp
      @@ -1935,6 +1935,30 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
                   }
               }
           }
      +
      +    const int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this);
      +    const QSize menuSize(sizeHint());
      +
      +    QMenu *caused = qobject_cast<QMenu*>(d_func()->causedPopup.widget);
      +    if (caused && caused->geometry().width() + menuSize.width() + subMenuOffset < screen.width()) {
      +        QRect parentActionRect(caused->d_func()->actionRect(caused->d_func()->currentAction));
      +        const QPoint actionTopLeft = caused->mapToGlobal(parentActionRect.topLeft());
      +        parentActionRect.moveTopLeft(actionTopLeft);
      +        if (isRightToLeft()) {
      +            if ((pos.x() + menuSize.width() > parentActionRect.left() - subMenuOffset)
      +                && (pos.x() < parentActionRect.right()))
      +            {
      +                    pos.rx() = parentActionRect.right();
      +            }
      +        } else {
      +            if ((pos.x() < parentActionRect.right() + subMenuOffset)
      +                && (pos.x() + menuSize.width() > parentActionRect.left()))
      +            {
      +                    pos.rx() = parentActionRect.left() - menuSize.width();
      +            }
      +        }
      +    }
      +
           setGeometry(QRect(pos, size));
       #ifndef QT_NO_EFFECTS
           int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
      -- 
      

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            ntg Pierre Rossi
            janichol Andy Nichols
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes