12#include <QtCore/QtDebug>
21#include <QtCore/private/qcore_mac_p.h>
29 m_parentEnabled(true),
40 for (
auto *
item : std::as_const(m_menuItems)) {
41 if (
item->menuParent() ==
this)
42 item->setMenuParent(
nullptr);
52 m_nativeMenu.title =
stripped.toNSString();
57 m_nativeMenu.minimumWidth =
width;
63 NSFont *customMenuFont = [NSFont fontWithName:
font.
families().first().toNSString()
65 m_nativeMenu.font = customMenuFont;
71 return static_cast<NSMenu *
>(m_nativeMenu);
91 qCWarning(lcQpaMenus) << beforeItem <<
"not in" << m_menuItems;
96 m_menuItems.
append(cocoaItem);
99 insertNative(cocoaItem, beforeItem);
104 if (
auto *mb = qobject_cast<QCocoaMenuBar *>(
menuParent()))
111 item->resolveTargetAction();
112 NSMenuItem *nativeItem =
item->nsItem();
115 item->menu()->setAttachedItem(nativeItem);
119 if (
item->isMerged())
124 while (beforeItem && beforeItem->
isMerged()) {
125 beforeItem = itemOrNull(m_menuItems.
indexOf(beforeItem) + 1);
128 if (nativeItem.menu) {
129 qCWarning(lcQpaMenus) <<
"Menu item" <<
item->text() <<
"already in menu" << QString::fromNSString(nativeItem.menu.title);
135 qCWarning(lcQpaMenus,
"No non-merged before menu item found");
138 const NSInteger nativeIndex = [m_nativeMenu indexOfItem:beforeItem->
nsItem()];
139 [m_nativeMenu insertItem:nativeItem atIndex:nativeIndex];
141 [m_nativeMenu
addItem:nativeItem];
143 item->setMenuParent(
this);
158 return m_isAboutToShow;
163 m_isAboutToShow = isAbout;
170 if (!m_menuItems.
contains(cocoaItem)) {
171 qCWarning(lcQpaMenus) << m_menuItems <<
"does not contain" << cocoaItem;
183 if (m_nativeMenu != cocoaItem->
nsItem().menu) {
184 qCWarning(lcQpaMenus) << cocoaItem <<
"does not belong to" << m_nativeMenu;
187 [m_nativeMenu removeItem:cocoaItem->
nsItem()];
199void QCocoaMenu::scheduleUpdate()
207 if (
e->timerId() == m_updateTimer) {
210 [m_nativeMenu update];
223 if (!m_menuItems.
contains(cocoaItem)) {
224 qCWarning(lcQpaMenus) << cocoaItem <<
"does not belong to" <<
this;
228 const bool wasMerged = cocoaItem->
isMerged();
229 NSMenuItem *oldItem = cocoaItem->
nsItem();
230 NSMenuItem *syncedItem = cocoaItem->
sync();
232 if (syncedItem != oldItem) {
236 oldItem.enabled = NO;
237 oldItem.hidden = YES;
238 oldItem.keyEquivalent =
@"";
239 oldItem.keyEquivalentModifierMask = NSEventModifierFlagCommand;
242 [m_nativeMenu removeItem:oldItem];
247 insertNative(cocoaItem, beforeItem);
260 submenu->setAttachedItem(syncedItem);
267 bool previousIsSeparator =
true;
268 NSMenuItem *lastVisibleItem = nil;
270 for (NSMenuItem *
item in m_nativeMenu.itemArray) {
271 if (
item.separatorItem) {
273 bool hideItem = previousIsSeparator;
274 if (
auto *cocoaItem = qt_objc_cast<QCocoaNSMenuItem *>(
item).platformMenuItem)
275 hideItem = previousIsSeparator || !cocoaItem->isVisible();
280 lastVisibleItem =
item;
281 previousIsSeparator = lastVisibleItem.separatorItem;
286 if (lastVisibleItem && lastVisibleItem.separatorItem)
287 lastVisibleItem.hidden = YES;
289 for (
auto *
item : std::as_const(m_menuItems)) {
290 if (!
item->isSeparator())
304 const bool wasParentEnabled = m_parentEnabled;
306 m_parentEnabled = wasParentEnabled;
311 return m_enabled && m_parentEnabled;
325 NSView *
view = cocoaWindow ? cocoaWindow->
view() : nil;
329 bool resetMenuParent =
false;
332 resetMenuParent =
true;
341 screen = parentWindow->screen();
356 NSPopUpButtonCell *popupCell = [[[NSPopUpButtonCell alloc] initTextCell:
@"" pullsDown:NO]
358 popupCell.altersStateOfSelectedItem = NO;
359 popupCell.transparent = YES;
360 popupCell.menu = m_nativeMenu;
361 [popupCell selectItem:nsItem];
366 int menuHeight = m_nativeMenu.size.height;
367 if (globalPos.
y() + menuHeight > availableHeight) {
372 float idx = ([m_nativeMenu indexOfItem:nsItem] + 1.0f) / m_nativeMenu.numberOfItems;
373 float heightBelowPos = (1.0 - idx) * menuHeight;
374 if (globalPos.
y() + heightBelowPos > availableHeight)
375 pos.setY(
pos.y() - globalPos.
y() + availableHeight - heightBelowPos);
378 NSRect cellFrame = NSMakeRect(
pos.x(),
pos.y(), m_nativeMenu.minimumWidth, 10);
379 [popupCell performClickWithFrame:cellFrame inView:
view];
382 NSPoint nsPos = NSMakePoint(
pos.x() - 1,
pos.y());
385 nsPos = [
view convertPoint:nsPos toView:nil];
392 NSEvent *menuEvent = [NSEvent mouseEventWithType:NSEventTypeRightMouseDown
396 windowNumber:
view ?
view.window.windowNumber : 0
401 [NSMenu popUpContextMenu:m_nativeMenu withEvent:menuEvent forView:
view];
403 [m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:nil];
415 [m_nativeMenu cancelTracking];
428 for (
auto *
item : std::as_const(m_menuItems)) {
444 for (
auto *
item : std::as_const(m_menuItems)) {
450 if (
item->isMerged())
465 for (
auto *
item : std::as_const(m_menuItems)) {
475 if (
item == m_attachedItem)
479 m_attachedItem.submenu = nil;
481 m_attachedItem =
item;
484 m_attachedItem.submenu = m_nativeMenu;
489 m_attachedItem.enabled = m_attachedItem.hasSubmenu;
494 return m_attachedItem;
QRect availableGeometry() const override
Reimplement in subclass to return the pixel geometry of the available space This normally is the desk...
bool isForeignWindow() const override
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.
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
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
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