From 0e99539dab4c059ba3c3750cfda42e246ce8b4f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20W=C3=BClker?= Date: Thu, 3 Apr 2025 14:11:55 +0200 Subject: Support single-value ` ``` --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] Part of https://github.com/servo/servo/issues/3551 - [ ] There are tests for these changes OR - [ ] These changes do not require tests because ___ --------- Signed-off-by: Simon Wülker --- ports/servoshell/desktop/dialog.rs | 114 ++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) (limited to 'ports/servoshell/desktop/dialog.rs') diff --git a/ports/servoshell/desktop/dialog.rs b/ports/servoshell/desktop/dialog.rs index 0ff8d4cd900..2bfccb523de 100644 --- a/ports/servoshell/desktop/dialog.rs +++ b/ports/servoshell/desktop/dialog.rs @@ -7,11 +7,14 @@ use std::sync::Arc; use egui::Modal; use egui_file_dialog::{DialogState, FileDialog as EguiFileDialog}; +use euclid::Length; use log::warn; use servo::ipc_channel::ipc::IpcSender; +use servo::servo_geometry::DeviceIndependentPixel; use servo::{ AlertResponse, AuthenticationRequest, ConfirmResponse, FilterPattern, PermissionRequest, - PromptResponse, SimpleDialog, + PromptResponse, SelectElement, SelectElementOption, SelectElementOptionOrOptgroup, + SimpleDialog, }; pub enum Dialog { @@ -36,6 +39,10 @@ pub enum Dialog { selected_device_index: usize, response_sender: IpcSender>, }, + SelectElement { + maybe_prompt: Option, + toolbar_offset: Length, + }, } impl Dialog { @@ -102,6 +109,16 @@ impl Dialog { } } + pub fn new_select_element_dialog( + prompt: SelectElement, + toolbar_offset: Length, + ) -> Self { + Dialog::SelectElement { + maybe_prompt: Some(prompt), + toolbar_offset, + } + } + pub fn update(&mut self, ctx: &egui::Context) -> bool { match self { Dialog::File { @@ -373,6 +390,101 @@ impl Dialog { }); is_open }, + Dialog::SelectElement { + maybe_prompt, + toolbar_offset, + } => { + let Some(prompt) = maybe_prompt else { + // Prompt was dismissed, so the dialog should be closed too. + return false; + }; + let mut is_open = true; + + let mut position = prompt.position(); + position.min.y += toolbar_offset.0 as i32; + position.max.y += toolbar_offset.0 as i32; + let area = egui::Area::new(egui::Id::new("select-window")) + .fixed_pos(egui::pos2(position.min.x as f32, position.max.y as f32)); + + let mut selected_option = prompt.selected_option(); + + fn display_option( + ui: &mut egui::Ui, + option: &SelectElementOption, + selected_option: &mut Option, + is_open: &mut bool, + in_group: bool, + ) { + let is_checked = + selected_option.is_some_and(|selected_index| selected_index == option.id); + + // TODO: Surely there's a better way to align text in a selectable label in egui. + let label_text = if in_group { + format!(" {}", option.label) + } else { + option.label.to_owned() + }; + let label = if option.is_disabled { + egui::RichText::new(&label_text).strikethrough() + } else { + egui::RichText::new(&label_text) + }; + let clickable_area = ui + .allocate_ui_with_layout( + [ui.available_width(), 0.0].into(), + egui::Layout::top_down_justified(egui::Align::LEFT), + |ui| ui.selectable_label(is_checked, label), + ) + .inner; + + if clickable_area.clicked() && !option.is_disabled { + *selected_option = Some(option.id); + *is_open = false; + } + + if clickable_area.hovered() && option.is_disabled { + ui.ctx().set_cursor_icon(egui::CursorIcon::NotAllowed); + } + } + + let modal = Modal::new("select_element_picker".into()).area(area); + modal.show(ctx, |ui| { + for option_or_optgroup in prompt.options() { + match &option_or_optgroup { + SelectElementOptionOrOptgroup::Option(option) => { + display_option( + ui, + option, + &mut selected_option, + &mut is_open, + false, + ); + }, + SelectElementOptionOrOptgroup::Optgroup { label, options } => { + ui.label(egui::RichText::new(label).strong()); + + for option in options { + display_option( + ui, + option, + &mut selected_option, + &mut is_open, + true, + ); + } + }, + } + } + }); + + prompt.select(selected_option); + + if !is_open { + maybe_prompt.take().unwrap().submit(); + } + + is_open + }, } } } -- cgit v1.2.3