LibWebView+UI: Add an option to toggle a menu's visibility

This requires setting up an observer interface akin to menu actions.
This commit is contained in:
Timothy Flynn 2026-05-28 16:36:11 -04:00 committed by Tim Flynn
parent a1b545e179
commit 11d80c122e
4 changed files with 98 additions and 0 deletions

View file

@ -134,4 +134,28 @@ void Menu::add_action(NonnullRefPtr<Action> action)
m_items.append(move(action));
}
void Menu::set_visible(bool visible)
{
if (m_visible == visible)
return;
m_visible = visible;
for (auto& observer : m_observers)
observer->on_visible_state_changed(*this);
}
void Menu::add_observer(NonnullOwnPtr<Observer> observer)
{
observer->on_visible_state_changed(*this);
m_observers.append(move(observer));
}
void Menu::remove_observer(Observer const& observer)
{
m_observers.remove_first_matching([&](auto const& candidate) {
return candidate.ptr() == &observer;
});
}
}

View file

@ -224,6 +224,9 @@ public:
void set_render_group_icon(bool render_group_icon) { m_render_group_icon = render_group_icon; }
bool render_group_icon() const { return m_render_group_icon; }
bool visible() const { return m_visible; }
void set_visible(bool);
template<typename Callback>
void for_each_action(Callback const& callback)
{
@ -235,6 +238,15 @@ public:
}
}
struct Observer {
virtual ~Observer() = default;
virtual void on_visible_state_changed(Menu&) { }
};
void add_observer(NonnullOwnPtr<Observer>);
void remove_observer(Observer const& observer);
Function<void(Gfx::IntPoint)> on_activation;
private:
@ -247,9 +259,11 @@ private:
Vector<MenuItem> m_items;
HashMap<StringView, String> m_properties;
Vector<NonnullOwnPtr<Observer>, 1> m_observers;
bool m_is_group { false };
bool m_render_group_icon { false };
bool m_visible { true };
};
}

View file

@ -187,6 +187,27 @@ private:
__weak id m_control { nil };
};
class MenuObserver final : public WebView::Menu::Observer {
public:
static NonnullOwnPtr<MenuObserver> create(NSMenuItem* item)
{
return adopt_own(*new MenuObserver(item));
}
virtual void on_visible_state_changed(WebView::Menu& menu) override
{
[m_item setHidden:!menu.visible()];
}
private:
explicit MenuObserver(NSMenuItem* item)
: m_item(item)
{
}
__weak NSMenuItem* m_item { nil };
};
static void initialize_native_icon(WebView::Action& action, id control)
{
static constexpr CGFloat const MENU_ICON_SIZE = 16;
@ -357,6 +378,21 @@ static void initialize_native_control(WebView::Action& action, id control)
action.add_observer(move(observer));
}
static void initialize_native_menu(WebView::Menu& menu, NSMenuItem* item)
{
auto observer = MenuObserver::create(item);
auto* guard = [[DeallocGuard alloc] init:[menu = menu.make_weak_ptr(), observer = observer.ptr()]() {
if (menu)
menu->remove_observer(*observer);
}];
static char guard_key = 0;
objc_setAssociatedObject(item, &guard_key, guard, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
menu.add_observer(move(observer));
}
static void add_items_to_menu(NSMenu* nsmenu, WebView::Menu& menu)
{
for (auto& menu_item : menu.items()) {
@ -421,6 +457,7 @@ NSMenuItem* create_application_menu_item(WebView::Menu& menu)
action:nil
keyEquivalent:@""];
[item setSubmenu:create_application_menu(menu)];
initialize_native_menu(menu, item);
if (menu.render_group_icon())
set_control_image(item, @"folder");

View file

@ -97,6 +97,28 @@ private:
IncludeActionIcon m_include_action_icon { IncludeActionIcon::Yes };
};
class MenuObserver final : public WebView::Menu::Observer {
public:
static NonnullOwnPtr<MenuObserver> create(QMenu& qmenu)
{
return adopt_own(*new MenuObserver(qmenu));
}
virtual void on_visible_state_changed(WebView::Menu& menu) override
{
if (m_menu && m_menu->menuAction())
m_menu->menuAction()->setVisible(menu.visible());
}
private:
explicit MenuObserver(QMenu& qmenu)
: m_menu(&qmenu)
{
}
QPointer<QMenu> m_menu;
};
template<typename T>
static void add_properties(QObject& object, T& menu_or_action)
{
@ -224,6 +246,7 @@ static void initialize_native_control(WebView::Action& action, QAction& qaction,
static void add_items_to_menu(QMenu& qmenu, QWidget& parent, WebView::Menu& menu)
{
menu.add_observer(MenuObserver::create(qmenu));
add_properties(qmenu, menu);
for (auto& menu_item : menu.items()) {