/* * Copyright (c) 2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace WebView { enum class ActionID { NavigateBack, NavigateForward, Reload, CopySelection, Paste, SelectAll, SearchSelectedText, TakeVisibleScreenshot, TakeFullScreenshot, OpenAboutPage, OpenProcessesPage, OpenSettingsPage, ToggleDevTools, ViewSource, OpenInNewTab, CopyURL, OpenImage, CopyImage, OpenAudio, OpenVideo, PlayMedia, PauseMedia, MuteMedia, UnmuteMedia, ShowControls, HideControls, ToggleMediaLoopState, ZoomIn, ZoomOut, ResetZoom, ResetZoomViaToolbar, PreferredColorScheme, PreferredContrast, PreferredMotion, DumpSessionHistoryTree, DumpDOMTree, DumpLayoutTree, DumpPaintTree, DumpStackingContextTree, DumpDisplayList, DumpStyleSheets, DumpStyles, DumpCSSErrors, DumpCookies, DumpLocalStorage, DumpGCGraph, ShowLineBoxBorders, CollectGarbage, ClearCache, ClearCookies, SpoofUserAgent, NavigatorCompatibilityMode, EnableScripting, EnableContentFiltering, BlockPopUps, }; class WEBVIEW_API Action : public RefCounted , public Weakable { public: static NonnullRefPtr create(Variant text, ActionID id, Function action); static NonnullRefPtr create_checkable(Variant text, ActionID id, Function action); void activate() { m_action(); } StringView text() const { return m_text.visit([](auto const& text) -> StringView { return text; }); } void set_text(Variant); StringView tooltip() const { return *m_tooltip; } void set_tooltip(StringView); ActionID id() const { return m_id; } bool enabled() const { return m_enabled; } void set_enabled(bool); bool visible() const { return m_visible; } void set_visible(bool); bool is_checkable() const { return m_checked.has_value(); } bool checked() const { return *m_checked; } void set_checked(bool); struct Observer { virtual ~Observer() = default; virtual void on_text_changed(Action&) { } virtual void on_tooltip_changed(Action&) { } virtual void on_enabled_state_changed(Action&) { } virtual void on_visible_state_changed(Action&) { } virtual void on_checked_state_changed(Action&) { } }; void add_observer(NonnullOwnPtr); void remove_observer(Observer const& observer); void set_group(Badge, Menu& group) { m_group = group; } private: Action(Variant text, ActionID id, Function action) : m_text(move(text)) , m_id(id) , m_action(move(action)) { } void set_checked_internal(bool checked); Variant m_text; Optional m_tooltip; ActionID m_id; bool m_enabled { true }; bool m_visible { true }; Optional m_checked; Function m_action; Vector, 1> m_observers; WeakPtr m_group; }; struct WEBVIEW_API Separator { }; class WEBVIEW_API Menu : public RefCounted , public Weakable { public: using MenuItem = Variant, NonnullRefPtr, Separator>; static NonnullRefPtr create(StringView name); static NonnullRefPtr create_group(StringView name); void add_action(NonnullRefPtr action); void add_submenu(NonnullRefPtr submenu) { m_items.append(move(submenu)); } void add_separator() { m_items.append(Separator {}); } StringView title() const { return m_title; } Span items() { return m_items; } ReadonlySpan items() const { return m_items; } template void for_each_action(Callback const& callback) { for (auto& item : m_items) { item.visit( [&](NonnullRefPtr& action) { callback(*action); }, [&](NonnullRefPtr& submenu) { submenu->for_each_action(callback); }, [&](Separator) {}); } } Function on_activation; private: explicit Menu(StringView title) : m_title(title) { } StringView m_title; Vector m_items; bool m_is_group { false }; }; }