ladybird/UI/Qt/Menu.cpp

131 lines
3.9 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <UI/Qt/Icon.h>
#include <UI/Qt/Menu.h>
#include <UI/Qt/StringUtils.h>
#include <UI/Qt/WebContentView.h>
#include <QAction>
#include <QMenu>
#include <QPointer>
#include <QWidget>
namespace Ladybird {
class ActionObserver final : public WebView::Action::Observer {
public:
static NonnullOwnPtr<ActionObserver> create(WebView::Action& action, QAction& qaction)
{
return adopt_own(*new ActionObserver(action, qaction));
}
virtual void on_text_changed(WebView::Action& action) override
{
if (m_action)
m_action->setText(qstring_from_ak_string(action.text()));
}
virtual void on_tooltip_changed(WebView::Action& action) override
{
if (m_action)
m_action->setToolTip(qstring_from_ak_string(action.tooltip()));
}
virtual void on_enabled_state_changed(WebView::Action& action) override
{
if (m_action)
m_action->setEnabled(action.enabled());
}
virtual void on_visible_state_changed(WebView::Action& action) override
{
if (m_action)
m_action->setVisible(action.visible());
}
virtual void on_checked_state_changed(WebView::Action& action) override
{
if (m_action)
m_action->setChecked(action.checked());
}
private:
ActionObserver(WebView::Action& action, QAction& qaction)
: m_action(&qaction)
{
QObject::connect(m_action, &QAction::triggered, [weak_action = action.make_weak_ptr()](bool checked) {
if (auto action = weak_action.strong_ref()) {
if (action->is_checkable())
action->set_checked(checked);
action->activate();
}
});
QObject::connect(m_action->parent(), &QObject::destroyed, [this, weak_action = action.make_weak_ptr()]() {
if (auto action = weak_action.strong_ref())
action->remove_observer(*this);
});
}
QPointer<QAction> m_action;
};
static void initialize_native_control(WebView::Action& action, QAction& qaction)
{
if (action.is_checkable())
qaction.setCheckable(true);
action.add_observer(ActionObserver::create(action, qaction));
}
static void add_items_to_menu(QMenu& menu, QWidget& parent, Span<WebView::Menu::MenuItem> menu_items)
{
for (auto& menu_item : menu_items) {
menu_item.visit(
[&](NonnullRefPtr<WebView::Action>& action) {
auto* qaction = create_application_action(parent, action);
menu.addAction(qaction);
},
[&](NonnullRefPtr<WebView::Menu> const& submenu) {
auto* qsubmenu = new QMenu(qstring_from_ak_string(submenu->title()), &menu);
add_items_to_menu(*qsubmenu, parent, submenu->items());
menu.addMenu(qsubmenu);
},
[&](WebView::Separator) {
menu.addSeparator();
});
}
}
QMenu* create_application_menu(QWidget& parent, WebView::Menu& menu)
{
auto* application_menu = new QMenu(qstring_from_ak_string(menu.title()), &parent);
add_items_to_menu(*application_menu, parent, menu.items());
return application_menu;
}
QMenu* create_context_menu(QWidget& parent, WebContentView& view, WebView::Menu& menu)
{
auto* application_menu = create_application_menu(parent, menu);
menu.on_activation = [view = QPointer { &view }, application_menu = QPointer { application_menu }](Gfx::IntPoint position) {
if (view && application_menu)
application_menu->exec(view->map_point_to_global_position(position));
};
return application_menu;
}
QAction* create_application_action(QWidget& parent, WebView::Action& action)
{
auto* qaction = new QAction(&parent);
initialize_native_control(action, *qaction);
return qaction;
}
}