mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
servoshell: Port alert/confirm dialog code to use egui intead of tinyfiledialogs (#35399)
Signed-off-by: L Ashwin B <lashwinib@gmail.com>
This commit is contained in:
parent
87069e9f47
commit
82df628a11
2 changed files with 140 additions and 91 deletions
|
@ -21,7 +21,7 @@ use servo::{
|
||||||
GamepadHapticEffectType, LoadStatus, PermissionRequest, PromptDefinition, PromptOrigin,
|
GamepadHapticEffectType, LoadStatus, PermissionRequest, PromptDefinition, PromptOrigin,
|
||||||
PromptResult, Servo, ServoDelegate, ServoError, TouchEventType, WebView, WebViewDelegate,
|
PromptResult, Servo, ServoDelegate, ServoError, TouchEventType, WebView, WebViewDelegate,
|
||||||
};
|
};
|
||||||
use tinyfiledialogs::{self, MessageBoxIcon, OkCancel};
|
use tinyfiledialogs::{self, MessageBoxIcon};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use super::app::{Present, PumpResult};
|
use super::app::{Present, PumpResult};
|
||||||
|
@ -142,7 +142,7 @@ impl RunningAppState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently, egui-file-dialog dialogs need to be constantly presented or animations aren't fluid.
|
// Currently, egui-file-dialog dialogs need to be constantly presented or animations aren't fluid.
|
||||||
let need_present = need_present || self.has_active_file_dialog();
|
let need_present = need_present || self.has_active_dialog();
|
||||||
|
|
||||||
let present = if need_present {
|
let present = if need_present {
|
||||||
Present::Deferred
|
Present::Deferred
|
||||||
|
@ -230,7 +230,18 @@ impl RunningAppState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_active_file_dialog(&self) -> bool {
|
fn add_dialog(&self, webview: servo::WebView, dialog: Dialog) {
|
||||||
|
let mut inner_mut = self.inner_mut();
|
||||||
|
inner_mut
|
||||||
|
.dialogs
|
||||||
|
.entry(webview.id())
|
||||||
|
.or_default()
|
||||||
|
.push(dialog);
|
||||||
|
inner_mut.need_update = true;
|
||||||
|
inner_mut.need_present = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_active_dialog(&self) -> bool {
|
||||||
let Some(webview) = self.focused_webview() else {
|
let Some(webview) = self.focused_webview() else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -238,7 +249,7 @@ impl RunningAppState {
|
||||||
let Some(dialogs) = inner.dialogs.get(&webview.id()) else {
|
let Some(dialogs) = inner.dialogs.get(&webview.id()) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
dialogs.iter().any(Dialog::is_file_dialog)
|
!dialogs.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_focused_webview_index(&self) -> Option<usize> {
|
pub(crate) fn get_focused_webview_index(&self) -> Option<usize> {
|
||||||
|
@ -347,44 +358,29 @@ impl WebViewDelegate for RunningAppState {
|
||||||
definition: PromptDefinition,
|
definition: PromptDefinition,
|
||||||
origin: PromptOrigin,
|
origin: PromptOrigin,
|
||||||
) {
|
) {
|
||||||
let res = if self.inner().headless {
|
if self.inner().headless {
|
||||||
match definition {
|
let _ = match definition {
|
||||||
PromptDefinition::Alert(_message, sender) => sender.send(()),
|
PromptDefinition::Alert(_message, sender) => sender.send(()),
|
||||||
PromptDefinition::OkCancel(_message, sender) => sender.send(PromptResult::Primary),
|
PromptDefinition::OkCancel(_message, sender) => sender.send(PromptResult::Primary),
|
||||||
PromptDefinition::Input(_message, default, sender) => {
|
PromptDefinition::Input(_message, default, sender) => {
|
||||||
sender.send(Some(default.to_owned()))
|
sender.send(Some(default.to_owned()))
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
match definition {
|
||||||
thread::Builder::new()
|
PromptDefinition::Alert(message, sender) => {
|
||||||
|
let alert_dialog = Dialog::new_alert_dialog(message, sender);
|
||||||
|
self.add_dialog(webview, alert_dialog);
|
||||||
|
},
|
||||||
|
PromptDefinition::OkCancel(message, sender) => {
|
||||||
|
let okcancel_dialog = Dialog::new_okcancel_dialog(message, sender);
|
||||||
|
self.add_dialog(webview, okcancel_dialog);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
let _ = thread::Builder::new()
|
||||||
.name("AlertDialog".to_owned())
|
.name("AlertDialog".to_owned())
|
||||||
.spawn(move || match definition {
|
.spawn(move || match definition {
|
||||||
PromptDefinition::Alert(mut message, sender) => {
|
|
||||||
if origin == PromptOrigin::Untrusted {
|
|
||||||
message = tiny_dialog_escape(&message);
|
|
||||||
}
|
|
||||||
tinyfiledialogs::message_box_ok(
|
|
||||||
"Alert!",
|
|
||||||
&message,
|
|
||||||
MessageBoxIcon::Warning,
|
|
||||||
);
|
|
||||||
sender.send(())
|
|
||||||
},
|
|
||||||
PromptDefinition::OkCancel(mut message, sender) => {
|
|
||||||
if origin == PromptOrigin::Untrusted {
|
|
||||||
message = tiny_dialog_escape(&message);
|
|
||||||
}
|
|
||||||
let result = tinyfiledialogs::message_box_ok_cancel(
|
|
||||||
"",
|
|
||||||
&message,
|
|
||||||
MessageBoxIcon::Warning,
|
|
||||||
OkCancel::Cancel,
|
|
||||||
);
|
|
||||||
sender.send(match result {
|
|
||||||
OkCancel::Ok => PromptResult::Primary,
|
|
||||||
OkCancel::Cancel => PromptResult::Secondary,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
PromptDefinition::Input(mut message, mut default, sender) => {
|
PromptDefinition::Input(mut message, mut default, sender) => {
|
||||||
if origin == PromptOrigin::Untrusted {
|
if origin == PromptOrigin::Untrusted {
|
||||||
message = tiny_dialog_escape(&message);
|
message = tiny_dialog_escape(&message);
|
||||||
|
@ -393,14 +389,13 @@ impl WebViewDelegate for RunningAppState {
|
||||||
let result = tinyfiledialogs::input_box("", &message, &default);
|
let result = tinyfiledialogs::input_box("", &message, &default);
|
||||||
sender.send(result)
|
sender.send(result)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_ => Ok(()),
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.join()
|
.join()
|
||||||
.expect("Thread spawning failed")
|
.expect("Thread spawning failed");
|
||||||
};
|
},
|
||||||
|
|
||||||
if let Err(e) = res {
|
|
||||||
webview.send_error(format!("Failed to send Prompt response: {e}"))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,18 +497,9 @@ impl WebViewDelegate for RunningAppState {
|
||||||
allow_select_mutiple: bool,
|
allow_select_mutiple: bool,
|
||||||
response_sender: IpcSender<Option<Vec<PathBuf>>>,
|
response_sender: IpcSender<Option<Vec<PathBuf>>>,
|
||||||
) {
|
) {
|
||||||
let mut inner_mut = self.inner_mut();
|
let file_dialog =
|
||||||
inner_mut
|
Dialog::new_file_dialog(allow_select_mutiple, response_sender, filter_pattern);
|
||||||
.dialogs
|
self.add_dialog(webview, file_dialog);
|
||||||
.entry(webview.id())
|
|
||||||
.or_default()
|
|
||||||
.push(Dialog::new_file_dialog(
|
|
||||||
allow_select_mutiple,
|
|
||||||
response_sender,
|
|
||||||
filter_pattern,
|
|
||||||
));
|
|
||||||
inner_mut.need_update = true;
|
|
||||||
inner_mut.need_present = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_permission(&self, _webview: servo::WebView, request: PermissionRequest) {
|
fn request_permission(&self, _webview: servo::WebView, request: PermissionRequest) {
|
||||||
|
|
|
@ -5,21 +5,26 @@
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use egui::Modal;
|
||||||
use egui_file_dialog::{DialogState, FileDialog as EguiFileDialog};
|
use egui_file_dialog::{DialogState, FileDialog as EguiFileDialog};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use servo::ipc_channel::ipc::IpcSender;
|
use servo::ipc_channel::ipc::IpcSender;
|
||||||
use servo::FilterPattern;
|
use servo::{FilterPattern, PromptResult};
|
||||||
|
|
||||||
#[derive(Debug)]
|
pub enum Dialog {
|
||||||
pub struct FileDialog {
|
File {
|
||||||
dialog: EguiFileDialog,
|
dialog: EguiFileDialog,
|
||||||
multiple: bool,
|
multiple: bool,
|
||||||
response_sender: IpcSender<Option<Vec<PathBuf>>>,
|
response_sender: IpcSender<Option<Vec<PathBuf>>>,
|
||||||
}
|
},
|
||||||
|
Alert {
|
||||||
#[derive(Debug)]
|
message: String,
|
||||||
pub enum Dialog {
|
sender: IpcSender<()>,
|
||||||
File(FileDialog),
|
},
|
||||||
|
OkCancel {
|
||||||
|
message: String,
|
||||||
|
sender: IpcSender<PromptResult>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dialog {
|
impl Dialog {
|
||||||
|
@ -45,44 +50,53 @@ impl Dialog {
|
||||||
.default_file_filter("All Supported Types");
|
.default_file_filter("All Supported Types");
|
||||||
}
|
}
|
||||||
|
|
||||||
let dialog = FileDialog {
|
Dialog::File {
|
||||||
dialog,
|
dialog,
|
||||||
multiple,
|
multiple,
|
||||||
response_sender,
|
response_sender,
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Dialog::File(dialog)
|
pub fn new_alert_dialog(message: String, sender: IpcSender<()>) -> Self {
|
||||||
|
Dialog::Alert { message, sender }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_okcancel_dialog(message: String, sender: IpcSender<PromptResult>) -> Self {
|
||||||
|
Dialog::OkCancel { message, sender }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, ctx: &egui::Context) -> bool {
|
pub fn update(&mut self, ctx: &egui::Context) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Dialog::File(dialog) => {
|
Dialog::File {
|
||||||
if dialog.dialog.state() == DialogState::Closed {
|
dialog,
|
||||||
if dialog.multiple {
|
multiple,
|
||||||
dialog.dialog.pick_multiple();
|
response_sender,
|
||||||
|
} => {
|
||||||
|
if dialog.state() == DialogState::Closed {
|
||||||
|
if *multiple {
|
||||||
|
dialog.pick_multiple();
|
||||||
} else {
|
} else {
|
||||||
dialog.dialog.pick_file();
|
dialog.pick_file();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = dialog.dialog.update(ctx).state();
|
let state = dialog.update(ctx).state();
|
||||||
|
|
||||||
match state {
|
match state {
|
||||||
DialogState::Open => true,
|
DialogState::Open => true,
|
||||||
DialogState::Picked(path) => {
|
DialogState::Picked(path) => {
|
||||||
if let Err(e) = dialog.response_sender.send(Some(vec![path])) {
|
if let Err(e) = response_sender.send(Some(vec![path])) {
|
||||||
warn!("Failed to send file selection response: {}", e);
|
warn!("Failed to send file selection response: {}", e);
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
DialogState::PickedMultiple(paths) => {
|
DialogState::PickedMultiple(paths) => {
|
||||||
if let Err(e) = dialog.response_sender.send(Some(paths)) {
|
if let Err(e) = response_sender.send(Some(paths)) {
|
||||||
warn!("Failed to send file selection response: {}", e);
|
warn!("Failed to send file selection response: {}", e);
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
DialogState::Cancelled => {
|
DialogState::Cancelled => {
|
||||||
if let Err(e) = dialog.response_sender.send(None) {
|
if let Err(e) = response_sender.send(None) {
|
||||||
warn!("Failed to send cancellation response: {}", e);
|
warn!("Failed to send cancellation response: {}", e);
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
@ -90,10 +104,59 @@ impl Dialog {
|
||||||
DialogState::Closed => false,
|
DialogState::Closed => false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Dialog::Alert { message, sender } => {
|
||||||
|
let mut is_open = true;
|
||||||
|
let modal = Modal::new("alert".into());
|
||||||
|
modal.show(ctx, |ui| {
|
||||||
|
make_dialog_label(message, ui);
|
||||||
|
egui::Sides::new().show(
|
||||||
|
ui,
|
||||||
|
|_ui| {},
|
||||||
|
|ui| {
|
||||||
|
if ui.button("Close").clicked() {
|
||||||
|
is_open = false;
|
||||||
|
if let Err(e) = sender.send(()) {
|
||||||
|
warn!("Failed to send alert dialog response: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
pub(crate) fn is_file_dialog(&self) -> bool {
|
);
|
||||||
matches!(self, Dialog::File(..))
|
});
|
||||||
|
is_open
|
||||||
|
},
|
||||||
|
Dialog::OkCancel { message, sender } => {
|
||||||
|
let mut is_open = true;
|
||||||
|
let modal = Modal::new("OkCancel".into());
|
||||||
|
modal.show(ctx, |ui| {
|
||||||
|
make_dialog_label(message, ui);
|
||||||
|
egui::Sides::new().show(
|
||||||
|
ui,
|
||||||
|
|_ui| {},
|
||||||
|
|ui| {
|
||||||
|
if ui.button("Ok").clicked() {
|
||||||
|
is_open = false;
|
||||||
|
if let Err(e) = sender.send(PromptResult::Primary) {
|
||||||
|
warn!("Failed to send alert dialog response: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ui.button("Cancel").clicked() {
|
||||||
|
is_open = false;
|
||||||
|
if let Err(e) = sender.send(PromptResult::Secondary) {
|
||||||
|
warn!("Failed to send alert dialog response: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
is_open
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_dialog_label(message: &str, ui: &mut egui::Ui) {
|
||||||
|
let mut frame = egui::Frame::default().inner_margin(10.0).begin(ui);
|
||||||
|
frame.content_ui.set_min_width(150.0);
|
||||||
|
frame.content_ui.label(message);
|
||||||
|
frame.end(ui);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue