Skip to main content

orinium_browser/browser/core/ui/
context_menu.rs

1//! Abstraction for the context menu shown when the user right-clicks the web
2//! content.
3//!
4//! The browser core (`BrowserUi` / `BrowserRenderer`) detects right-clicks on
5//! the web view and hands them to any [`ContextMenu`] implementation through
6//! [`ClickContext`]: click position, the link under the cursor, and the
7//! document URL. The implementation draws itself as a window-space overlay
8//! (on top of the chrome) and reports selected items back as
9//! [`ChromeAction`]s, exactly like a [`Chrome`](super::Chrome) does, so it can
10//! be replaced by any user-designed menu without touching the core.
11//!
12//! All coordinates are logical pixels in window space.
13
14use crate::browser::core::ui::chrome::ChromeAction;
15use crate::engine::renderer_model::DrawCommand;
16use crate::engine::ui::PointerEvent;
17
18/// Information about the right-click that requested the context menu.
19#[derive(Debug, Clone, PartialEq)]
20pub struct ClickContext {
21    /// Click position in window logical coordinates.
22    pub window_pos: (f32, f32),
23    /// Click position relative to the web content area origin (page space).
24    pub page_pos: (f32, f32),
25    /// URL of the link under the cursor, if any.
26    pub link_url: Option<String>,
27    /// URL of the document shown in the web view, if any.
28    pub document_url: Option<String>,
29}
30
31/// The outcome of dispatching a pointer event to an open context menu.
32#[derive(Debug, Clone, PartialEq)]
33pub struct MenuEventResult {
34    /// `true` when the event hit the menu and must not reach the chrome or
35    /// the page.
36    pub consumed: bool,
37    /// Action the browser core should perform.
38    pub action: ChromeAction,
39}
40
41impl MenuEventResult {
42    /// A result that consumes nothing and requests nothing.
43    pub const fn none() -> Self {
44        Self {
45            consumed: false,
46            action: ChromeAction::None,
47        }
48    }
49
50    /// A result that consumes the event and requests `action`.
51    pub const fn consumed(action: ChromeAction) -> Self {
52        Self {
53            consumed: true,
54            action,
55        }
56    }
57}
58
59/// The context menu opened by right-clicking the web view.
60///
61/// The core opens the menu with [`open`](ContextMenu::open) when the web
62/// content is right-pressed; while the menu reports
63/// [`is_open`](ContextMenu::is_open), every pointer event over the window is
64/// routed to it before the chrome or the page. The menu renders above all
65/// other UI via [`draw`](ContextMenu::draw).
66pub trait ContextMenu: std::fmt::Debug {
67    /// Requests the menu at the given click position.
68    ///
69    /// Returns `true` when the menu opened (and consumed the click);
70    /// implementations may return `false` to decline (e.g. no items apply).
71    fn open(&mut self, ctx: &ClickContext) -> bool;
72
73    /// Closes the menu without running an action.
74    fn close(&mut self);
75
76    /// Whether the menu is currently open.
77    fn is_open(&self) -> bool;
78
79    /// Draws the open menu into `cmd_buf` in window coordinates.
80    ///
81    /// Called every frame after the chrome so the menu paints on top of
82    /// everything else. Implementations should emit nothing while closed.
83    fn draw(&self, cmd_buf: &mut Vec<DrawCommand>, width: f32, height: f32);
84
85    /// Dispatches a pointer event to the open menu.
86    ///
87    /// Only called while the menu is open. Returning
88    /// [`consumed`](MenuEventResult.consumed) keeps the event away from the
89    /// chrome and the page.
90    fn pointer_event(&mut self, width: f32, height: f32, event: PointerEvent) -> MenuEventResult;
91
92    /// Whether the menu changed its visual state since the last check.
93    ///
94    /// Consumes the flag, like [`crate::engine::ui::custom_node::CustomNode::needs_repaint`].
95    fn needs_repaint(&self) -> bool;
96}