12#include <QtCore/QtDebug>
21#include <QtCore/private/qcore_mac_p.h>
22#include <QtCore/qpointer.h>
30 m_parentEnabled(true),
41 for (
auto *
item : std::as_const(m_menuItems)) {
42 if (
item->menuParent() ==
this)
43 item->setMenuParent(
nullptr);
55 m_nativeMenu.title =
stripped.toNSString();
60 m_nativeMenu.minimumWidth =
width;
66 NSFont *customMenuFont = [NSFont fontWithName:
font.
families().constFirst().toNSString()
68 m_nativeMenu.font = customMenuFont;
74 return static_cast<NSMenu *
>(m_nativeMenu);
94 qCWarning(lcQpaMenus) << beforeItem <<
"not in" << m_menuItems;
99 m_menuItems.
append(cocoaItem);
102 insertNative(cocoaItem, beforeItem);
107 if (
auto *mb = qobject_cast<QCocoaMenuBar *>(
menuParent()))
114 item->resolveTargetAction();
115 NSMenuItem *nativeItem =
item->nsItem();
118 item->menu()->setAttachedItem(nativeItem);
122 if (
item->isMerged())
127 while (beforeItem && beforeItem->isMerged()) {
128 beforeItem = itemOrNull(m_menuItems.
indexOf(beforeItem) + 1);
131 if (nativeItem.menu) {
132 qCWarning(lcQpaMenus) <<
"Menu item" <<
item->text() <<
"already in menu" << QString::fromNSString(nativeItem.menu.title);
137 if (beforeItem->isMerged()) {
138 qCWarning(lcQpaMenus,
"No non-merged before menu item found");
141 const NSInteger nativeIndex = [m_nativeMenu indexOfItem:beforeItem->nsItem()];
142 [m_nativeMenu insertItem:nativeItem atIndex:nativeIndex];
144 [m_nativeMenu
addItem:nativeItem];
146 item->setMenuParent(
this);
161 return m_isAboutToShow;
166 m_isAboutToShow = isAbout;
173 if (!m_menuItems.
contains(cocoaItem)) {
174 qCWarning(lcQpaMenus) << m_menuItems <<
"does not contain" << cocoaItem;
178 if (cocoaItem->menuParent() ==
this)
179 cocoaItem->setMenuParent(
nullptr);
182 cocoaItem->setParentEnabled(
true);
185 if (!cocoaItem->isMerged()) {
186 if (m_nativeMenu != cocoaItem->nsItem().menu) {
187 qCWarning(lcQpaMenus) << cocoaItem <<
"does not belong to" << m_nativeMenu;
190 [m_nativeMenu removeItem:cocoaItem->nsItem()];
202void QCocoaMenu::scheduleUpdate()
210 if (e->
timerId() == m_updateTimer) {
213 [m_nativeMenu update];
226 if (!m_menuItems.
contains(cocoaItem)) {
227 qCWarning(lcQpaMenus) << cocoaItem <<
"does not belong to" <<
this;
231 const bool wasMerged = cocoaItem->isMerged();
232 NSMenuItem *oldItem = cocoaItem->nsItem();
233 NSMenuItem *syncedItem = cocoaItem->sync();
235 if (syncedItem != oldItem) {
239 oldItem.enabled = NO;
240 oldItem.hidden = YES;
241 oldItem.keyEquivalent =
@"";
242 oldItem.keyEquivalentModifierMask = NSEventModifierFlagCommand;
245 [m_nativeMenu removeItem:oldItem];
250 insertNative(cocoaItem, beforeItem);
263 submenu->setAttachedItem(syncedItem);
270 bool previousIsSeparator =
true;
271 NSMenuItem *lastVisibleItem = nil;
273 for (NSMenuItem *
item in m_nativeMenu.itemArray) {
274 if (
item.separatorItem) {
276 bool hideItem = previousIsSeparator;
277 if (
auto *cocoaItem = qt_objc_cast<QCocoaNSMenuItem *>(
item).platformMenuItem)
278 hideItem = previousIsSeparator || !cocoaItem->isVisible();
283 lastVisibleItem =
item;
284 previousIsSeparator = lastVisibleItem.separatorItem;
289 if (lastVisibleItem && lastVisibleItem.separatorItem)
290 lastVisibleItem.hidden = YES;
292 for (
auto *
item : std::as_const(m_menuItems)) {
293 if (!
item->isSeparator())
307 const bool wasParentEnabled = m_parentEnabled;
309 m_parentEnabled = wasParentEnabled;
314 return m_enabled && m_parentEnabled;
326 QPointer<QCocoaMenu> guard =
this;
328 QPoint pos =
QPoint(targetRect.left(), targetRect.top() + targetRect.height());
331 QPointer<QCocoaWindow> cocoaWindow = parentWindow ?
static_cast<QCocoaWindow *
>(parentWindow->handle()) :
nullptr;
332 NSView *
view = cocoaWindow ? cocoaWindow->view() : nil;
336 bool resetMenuParent =
false;
339 resetMenuParent =
true;
348 screen = parentWindow->screen();
363 NSPopUpButtonCell *popupCell = [[[NSPopUpButtonCell alloc] initTextCell:
@"" pullsDown:NO]
365 popupCell.altersStateOfSelectedItem = NO;
366 popupCell.transparent = YES;
367 popupCell.menu = m_nativeMenu;
368 [popupCell selectItem:nsItem];
372 const QPoint globalPos = cocoaWindow ? cocoaWindow->mapToGlobal(
pos) :
pos;
373 int menuHeight = m_nativeMenu.size.height;
374 if (globalPos.
y() + menuHeight > availableHeight) {
379 float idx = ([m_nativeMenu indexOfItem:nsItem] + 1.0f) / m_nativeMenu.numberOfItems;
380 float heightBelowPos = (1.0 - idx) * menuHeight;
381 if (globalPos.
y() + heightBelowPos > availableHeight)
382 pos.setY(
pos.y() - globalPos.
y() + availableHeight - heightBelowPos);
385 NSRect cellFrame = NSMakeRect(
pos.x(),
pos.y(), m_nativeMenu.minimumWidth, 10);
386 [popupCell performClickWithFrame:cellFrame inView:
view];
389 NSPoint nsPos = NSMakePoint(
pos.x() - 1,
pos.y());
392 nsPos = [
view convertPoint:nsPos toView:nil];
399 NSEvent *menuEvent = [NSEvent mouseEventWithType:NSEventTypeRightMouseDown
403 windowNumber:
view ?
view.window.windowNumber : 0
408 [NSMenu popUpContextMenu:m_nativeMenu withEvent:menuEvent forView:
view];
410 [m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:nil];
415 menuParentGuard.dismiss();
421 if (cocoaWindow && !cocoaWindow->isForeignWindow())
427 [m_nativeMenu cancelTracking];
440 for (
auto *
item : std::as_const(m_menuItems)) {
455 QList<QCocoaMenuItem *>
result;
456 for (
auto *
item : std::as_const(m_menuItems)) {
462 if (
item->isMerged())
477 for (
auto *
item : std::as_const(m_menuItems)) {
487 if (
item == m_attachedItem)
491 m_attachedItem.submenu = nil;
493 m_attachedItem =
item;
496 m_attachedItem.submenu = m_nativeMenu;
501 m_attachedItem.enabled = m_attachedItem.hasSubmenu;
506 return m_attachedItem;
QRect availableGeometry() const override
Reimplement in subclass to return the pixel geometry of the available space This normally is the desk...
QStringList families() const
int pointSize() const
Returns the point size of the font.
static QList< QScreen * > screens()
Returns a list of all the screens associated with the windowing system the application is connected t...
qsizetype size() const noexcept
iterator insert(qsizetype i, parameter_type t)
bool removeOne(const AT &t)
const_reference at(qsizetype i) const noexcept
qsizetype count() const noexcept
void append(parameter_type t)
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
This is an overloaded function that will start a timer of type timerType and a timeout of interval mi...
void killTimer(int id)
Kills the timer with timer identifier, id.
\inmodule QtCore\reentrant
constexpr int y() const noexcept
Returns the y coordinate of this point.
\inmodule QtCore\reentrant
constexpr int height() const noexcept
Returns the height of the rectangle.
The QScreen class is used to query screen properties. \inmodule QtGui.
QSize availableVirtualSize
the available size of the virtual desktop to which this screen belongs
QPlatformScreen * handle() const
Get the platform screen handle.
constexpr int height() const noexcept
Returns the height.
\macro QT_RESTRICTED_CAST_FROM_ASCII
int timerId() const
Returns the unique timer identifier, which is the same identifier as returned from QObject::startTime...
Combined button and popup list for selecting options.
QNSView * qnsview_cast(NSView *view)
Returns the view cast to a QNSview if possible.
QString qt_mac_removeAmpersandEscapes(QString s)
AudioChannelLayoutTag tag
static glyph_t stripped(glyph_t glyph)
#define qCWarning(category,...)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLenum GLsizei const GLuint GLboolean enabled
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
bool contains(const AT &t) const noexcept