41QQuickNativeMenuItem *QQuickNativeMenuItem::createFromNonNativeItem(
42 QQuickMenu *parentMenu, QQuickItem *nonNativeItem)
44 auto *menuItem = qobject_cast<QQuickMenuItem *>(nonNativeItem);
45 Type type = Type::Unknown;
47 if (menuItem->action()) {
49 }
else if (menuItem->subMenu()) {
53 type = Type::MenuItem;
55 }
else if (qobject_cast<QQuickMenuSeparator *>(nonNativeItem)) {
56 type = Type::Separator;
59 std::unique_ptr<QQuickNativeMenuItem> nativeMenuItemPtr(
new QQuickNativeMenuItem(
60 parentMenu, nonNativeItem, type));
61 if (type == Type::Unknown) {
65 return nativeMenuItemPtr.release();
68 qCDebug(lcNativeMenuItem) <<
"attemping to create native menu item for"
69 << nativeMenuItemPtr->debugText();
70 auto *parentMenuPrivate = QQuickMenuPrivate::get(parentMenu);
71 nativeMenuItemPtr->m_handle.reset(parentMenuPrivate->handle->createMenuItem());
72 if (!nativeMenuItemPtr->m_handle)
73 nativeMenuItemPtr->m_handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem());
74 if (!nativeMenuItemPtr->m_handle)
77 auto *nativeMenuItem = nativeMenuItemPtr.release();
81 connect(nativeMenuItem->m_handle.get(), &QPlatformMenuItem::activated,
82 nativeMenuItem->action(), [nativeMenuItem, parentMenu](){
83 nativeMenuItem->action()->trigger(parentMenu);
86 connect(nativeMenuItem->action(), &QQuickAction::textChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
87 connect(nativeMenuItem->action(), &QQuickAction::iconChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
88 connect(nativeMenuItem->action(), &QQuickAction::enabledChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
89 connect(nativeMenuItem->action(), &QQuickAction::checkedChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
90 connect(nativeMenuItem->action(), &QQuickAction::checkableChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
93 nativeMenuItem->m_handle->setMenu(QQuickMenuPrivate::get(
94 nativeMenuItem->subMenu())->handle.get());
97 connect(nativeMenuItem->subMenu(), &QQuickMenu::enabledChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
98 connect(nativeMenuItem->subMenu(), &QQuickMenu::titleChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
102 connect(nativeMenuItem->m_handle.get(), &QPlatformMenuItem::activated,
103 menuItem, [menuItem](){
104 if (menuItem->isCheckable()) {
110 QQuickAbstractButtonPrivate::get(menuItem)->click();
113 connect(menuItem, &QQuickMenuItem::textChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
114 connect(menuItem, &QQuickMenuItem::iconChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
115 connect(menuItem, &QQuickMenuItem::enabledChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
116 connect(menuItem, &QQuickMenuItem::checkedChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
117 connect(menuItem, &QQuickMenuItem::checkableChanged, nativeMenuItem, &QQuickNativeMenuItem::sync);
119 case Type::Separator:
124 return nativeMenuItem;
161void QQuickNativeMenuItem::sync()
163 if (m_type == Type::Unknown)
169 QScopedValueRollback recursionGuard(m_syncing,
true);
171 const auto *action =
this->action();
172 const auto *separator =
this->separator();
173 auto *subMenu =
this->subMenu();
174 auto *menuItem = qobject_cast<QQuickMenuItem *>(m_nonNativeItem);
177 const bool enabled = action ? action->isEnabled()
178 : subMenu ? subMenu->isEnabled()
179 : menuItem && menuItem->isEnabled();
180 m_handle->setEnabled(enabled);
183 const bool isSeparator = separator !=
nullptr;
184 m_handle->setIsSeparator(isSeparator);
186 const bool checkable = action ? action->isCheckable() : menuItem && menuItem->isCheckable();
187 m_handle->setCheckable(checkable);
189 const bool checked = action ? action->isChecked() : menuItem && menuItem->isChecked();
190 m_handle->setChecked(checked);
192 m_handle->setRole(QPlatformMenuItem::TextHeuristicRole);
194 const QString text = action ? action->text()
195 : subMenu ? subMenu->title()
196 : menuItem ? menuItem->text() : QString();
197 m_handle->setText(text);
201 m_handle->setHasExclusiveGroup(
false);
203 const QQuickIcon icon = effectiveIcon();
204 const auto *menuPrivate = QQuickMenuPrivate::get(m_parentMenu);
211 bool dprChanged =
false;
212 if (!qGuiApp->topLevelWindows().isEmpty()) {
213 const auto *window = qGuiApp->topLevelWindows().first();
214 dprChanged = !qFuzzyCompare(window->devicePixelRatio(), menuPrivate->lastDevicePixelRatio);
217 if (!icon.isEmpty() && (icon != iconLoader()->icon() || dprChanged)) {
224 auto *subMenuPrivate = QQuickMenuPrivate::get(subMenu);
225 subMenuPrivate->syncWithNativeMenu();
226 if (subMenuPrivate->handle)
227 m_handle->setMenu(subMenuPrivate->handle.get());
230#if QT_CONFIG(shortcut)
232 m_handle->setShortcut(action->shortcut());
236 auto *menuPrivate = QQuickMenuPrivate::get(m_parentMenu);
237 if (menuPrivate->handle)
238 menuPrivate->handle->syncMenuItem(m_handle.get());
241 qCDebug(lcNativeMenuItem) <<
"sync called on" << debugText() <<
"handle" << m_handle.get()
242 <<
"enabled:" << enabled <<
"isSeparator" << isSeparator <<
"checkable" << checkable
243 <<
"checked" << checked <<
"text" << text;
316QString QQuickNativeMenuItem::debugText()
const
319 QString text = QDebug::toString(m_handle.get());
323 return text.prepend(QString::fromLatin1(
"Action(text = %1) ").arg(action()->text()));
325 return text.prepend(QString::fromLatin1(
"Sub-menu(title = %1) ").arg(subMenu()->title()));
327 return text.prepend(QString::fromLatin1(
"MenuItem(text = %1) ").arg(
328 qobject_cast<QQuickMenuItem *>(m_nonNativeItem)->text()));
329 case Type::Separator:
330 return text.prepend(QStringLiteral(
"Separator "));
332 return text.prepend(QStringLiteral(
"(Unknown) "));