desktop: Fix context menu, use new approach rather than trying to hack activate egui's menu
This commit is contained in:
parent
941e60aef5
commit
e778e5ed58
|
@ -221,7 +221,7 @@ impl App {
|
|||
ElementState::Pressed => PlayerEvent::MouseDown { x, y, button },
|
||||
ElementState::Released => PlayerEvent::MouseUp { x, y, button },
|
||||
};
|
||||
if state == ElementState::Pressed && button == RuffleMouseButton::Right
|
||||
if state == ElementState::Released && button == RuffleMouseButton::Right
|
||||
{
|
||||
// Show context menu.
|
||||
// TODO: Should be squelched if player consumes the right click event.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
mod context_menu;
|
||||
mod controller;
|
||||
mod movie;
|
||||
mod open_dialog;
|
||||
|
@ -8,6 +9,7 @@ use std::borrow::Cow;
|
|||
use url::Url;
|
||||
|
||||
use crate::custom_event::RuffleEvent;
|
||||
use crate::gui::context_menu::ContextMenu;
|
||||
use crate::gui::open_dialog::OpenDialog;
|
||||
use crate::player::PlayerOptions;
|
||||
use chrono::DateTime;
|
||||
|
@ -68,7 +70,7 @@ pub struct RuffleGui {
|
|||
is_volume_visible: bool,
|
||||
volume_controls: VolumeControls,
|
||||
is_open_dialog_visible: bool,
|
||||
context_menu: Vec<ruffle_core::ContextMenuItem>,
|
||||
context_menu: Option<ContextMenu>,
|
||||
open_dialog: OpenDialog,
|
||||
locale: LanguageIdentifier,
|
||||
default_player_options: PlayerOptions,
|
||||
|
@ -97,7 +99,7 @@ impl RuffleGui {
|
|||
is_open_dialog_visible: false,
|
||||
was_suspended_before_debug: false,
|
||||
|
||||
context_menu: vec![],
|
||||
context_menu: None,
|
||||
open_dialog: OpenDialog::new(
|
||||
default_player_options.clone(),
|
||||
default_path,
|
||||
|
@ -159,17 +161,21 @@ impl RuffleGui {
|
|||
self.volume_window(egui_ctx, None);
|
||||
}
|
||||
|
||||
if !self.context_menu.is_empty() {
|
||||
self.context_menu(egui_ctx);
|
||||
if let Some(context_menu) = &mut self.context_menu {
|
||||
if !context_menu.show(egui_ctx, &self.event_loop) {
|
||||
self.context_menu = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show_context_menu(&mut self, menu: Vec<ruffle_core::ContextMenuItem>) {
|
||||
self.context_menu = menu;
|
||||
if !menu.is_empty() {
|
||||
self.context_menu = Some(ContextMenu::new(menu));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_context_menu_visible(&self) -> bool {
|
||||
!self.context_menu.is_empty()
|
||||
self.context_menu.is_some()
|
||||
}
|
||||
|
||||
/// Notifies the GUI that a new player was created.
|
||||
|
@ -451,46 +457,6 @@ impl RuffleGui {
|
|||
});
|
||||
}
|
||||
|
||||
/// Renders the right-click context menu.
|
||||
fn context_menu(&mut self, egui_ctx: &egui::Context) {
|
||||
let mut item_clicked = false;
|
||||
let mut menu_visible = false;
|
||||
// TODO: What is the proper way in egui to spawn a random context menu?
|
||||
egui::CentralPanel::default()
|
||||
.frame(Frame::none())
|
||||
.show(egui_ctx, |_| {})
|
||||
.response
|
||||
.context_menu(|ui| {
|
||||
menu_visible = true;
|
||||
for (i, item) in self.context_menu.iter().enumerate() {
|
||||
if i != 0 && item.separator_before {
|
||||
ui.separator();
|
||||
}
|
||||
let clicked = if item.checked {
|
||||
Checkbox::new(&mut true, &item.caption).ui(ui).clicked()
|
||||
} else {
|
||||
let button = Button::new(&item.caption).wrap(false);
|
||||
|
||||
ui.add_enabled(item.enabled, button).clicked()
|
||||
};
|
||||
if clicked {
|
||||
let _ = self
|
||||
.event_loop
|
||||
.send_event(RuffleEvent::ContextMenuItemClicked(i));
|
||||
item_clicked = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if item_clicked
|
||||
|| !menu_visible
|
||||
|| egui_ctx.input_mut(|input| input.consume_key(Modifiers::NONE, Key::Escape))
|
||||
{
|
||||
// Hide menu.
|
||||
self.context_menu.clear();
|
||||
}
|
||||
}
|
||||
|
||||
fn open_file(&mut self, ui: &mut egui::Ui) {
|
||||
ui.close_menu();
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
use crate::custom_event::RuffleEvent;
|
||||
use egui::{
|
||||
vec2, Align, Area, Button, Checkbox, Color32, Frame, Id, Key, Layout, Modifiers, Order, Pos2,
|
||||
Stroke, Style, Widget,
|
||||
};
|
||||
use ruffle_core::ContextMenuItem;
|
||||
use winit::event_loop::EventLoopProxy;
|
||||
|
||||
pub struct ContextMenu {
|
||||
items: Vec<ContextMenuItem>,
|
||||
position: Option<Pos2>,
|
||||
}
|
||||
|
||||
impl ContextMenu {
|
||||
pub fn new(items: Vec<ContextMenuItem>) -> Self {
|
||||
Self {
|
||||
items,
|
||||
position: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn show(
|
||||
&mut self,
|
||||
egui_ctx: &egui::Context,
|
||||
event_loop: &EventLoopProxy<RuffleEvent>,
|
||||
) -> bool {
|
||||
let mut item_clicked = false;
|
||||
self.position = self.position.or(egui_ctx.pointer_latest_pos());
|
||||
|
||||
let area = Area::new(Id::new("context_menu"))
|
||||
.order(Order::Foreground)
|
||||
.fixed_pos(self.position.unwrap_or_default())
|
||||
.constrain_to(egui_ctx.screen_rect())
|
||||
.interactable(true)
|
||||
.show(egui_ctx, |ui| {
|
||||
set_menu_style(ui.style_mut());
|
||||
Frame::menu(ui.style()).show(ui, |ui| {
|
||||
ui.set_max_width(150.0);
|
||||
ui.with_layout(Layout::top_down_justified(Align::Min), |ui| {
|
||||
for (i, item) in self.items.iter().enumerate() {
|
||||
if i != 0 && item.separator_before {
|
||||
ui.separator();
|
||||
}
|
||||
let clicked = if item.checked {
|
||||
Checkbox::new(&mut true, &item.caption).ui(ui).clicked()
|
||||
} else {
|
||||
let button = Button::new(&item.caption).wrap(false);
|
||||
|
||||
ui.add_enabled(item.enabled, button).clicked()
|
||||
};
|
||||
if clicked {
|
||||
let _ =
|
||||
event_loop.send_event(RuffleEvent::ContextMenuItemClicked(i));
|
||||
item_clicked = true;
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
let should_close = item_clicked
|
||||
|| area.response.clicked_elsewhere()
|
||||
|| egui_ctx.input_mut(|input| input.consume_key(Modifiers::NONE, Key::Escape));
|
||||
|
||||
!should_close
|
||||
}
|
||||
}
|
||||
|
||||
// Shamelessly stolen from egui menu::set_menu_style, a private internal function
|
||||
fn set_menu_style(style: &mut Style) {
|
||||
style.spacing.button_padding = vec2(2.0, 0.0);
|
||||
style.visuals.widgets.active.bg_stroke = Stroke::NONE;
|
||||
style.visuals.widgets.hovered.bg_stroke = Stroke::NONE;
|
||||
style.visuals.widgets.inactive.weak_bg_fill = Color32::TRANSPARENT;
|
||||
style.visuals.widgets.inactive.bg_stroke = Stroke::NONE;
|
||||
}
|
Loading…
Reference in New Issue