egui::Popup::menu closes on any click inside the popup, so the "More Colors… #" field of every colour drop-down closed the menu before a value could be typed. The colour drop-downs now open through widgets::color_popup (CloseOnClickOutside): picking a colour still closes them (color_grid calls ui.close()), and the other buttons in them (Gradient…, the Weight, Dashes and Arrows submenus of Shape Outline) close them explicitly. generated with Claude Code
This commit is contained in:
parent
788831834b
commit
a8c983ba6b
|
|
@ -276,7 +276,7 @@ pub fn gradient_editor(ui: &mut Ui, id: &str, g: &Gradient, sc: &ColorScheme) ->
|
|||
let (sw, _) = ui.allocate_exact_size(vec2(18.0, 18.0), Sense::hover());
|
||||
ui.painter().rect(sw, CornerRadius::same(3), c32(&s.color, sc), Stroke::new(1.0, t.border), egui::StrokeKind::Inside);
|
||||
let r = widgets::drop_button(ui, "", vec2(24.0, 20.0), true);
|
||||
egui::Popup::menu(&r).show(|ui| {
|
||||
widgets::color_popup(&r).show(|ui| {
|
||||
if let Some(Some(c)) = widgets::color_grid(ui, sc, None) {
|
||||
let mut ng = g.clone();
|
||||
ng.stops[sel].color = with_alpha(c, alpha_of(&s.color));
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ fn color_button(
|
|||
ui.label(label);
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
let r = widgets::drop_button(ui, "Color", vec2(70.0, 22.0), true);
|
||||
egui::Popup::menu(&r).show(|ui| {
|
||||
widgets::color_popup(&r).show(|ui| {
|
||||
if let Some(c) = widgets::color_grid(ui, &sc, none_label) {
|
||||
let (id, p) = on_pick(c);
|
||||
run(app, &id, p);
|
||||
|
|
@ -391,7 +391,7 @@ fn background(app: &mut SlideApp, ui: &mut Ui) {
|
|||
ui.horizontal(|ui| {
|
||||
ui.label("Color");
|
||||
let r = widgets::drop_button(ui, "Color", vec2(70.0, 20.0), true);
|
||||
egui::Popup::menu(&r).show(|ui| {
|
||||
widgets::color_popup(&r).show(|ui| {
|
||||
if let Some(Some(c)) = widgets::color_grid(ui, &sc, None) {
|
||||
run(app, "design.background", json!({"color": cref_param(&c)}));
|
||||
}
|
||||
|
|
@ -417,7 +417,7 @@ fn background(app: &mut SlideApp, ui: &mut Ui) {
|
|||
ui.horizontal(|ui| {
|
||||
ui.label(label);
|
||||
let r = widgets::drop_button(ui, "Color", vec2(70.0, 20.0), true);
|
||||
egui::Popup::menu(&r).show(|ui| {
|
||||
widgets::color_popup(&r).show(|ui| {
|
||||
if let Some(Some(c)) = widgets::color_grid(ui, &sc, None) {
|
||||
let (f, b) = if fg { (c, pt.bg.clone()) } else { (pt.fg.clone(), c) };
|
||||
run(app, "design.background", json!({"pattern": {"preset": pt.preset, "fg": cref_param(&f), "bg": cref_param(&b)}}));
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@ fn font_group(app: &mut SlideApp, ui: &mut Ui, st: &Value) {
|
|||
if m.clicked() {
|
||||
run(app, "format.highlight", json!({"color": "#FFFF00"}));
|
||||
}
|
||||
egui::Popup::menu(&a).show(|ui| {
|
||||
widgets::color_popup(&a).show(|ui| {
|
||||
if let Some(c) = widgets::color_grid(ui, &sc, Some("No Color")) {
|
||||
run(app, "format.highlight", json!({"color": c.map(|c| serde_json::to_value(cref_param(&c)).unwrap_or_default())}));
|
||||
}
|
||||
|
|
@ -482,7 +482,7 @@ fn font_group(app: &mut SlideApp, ui: &mut Ui, st: &Value) {
|
|||
if m.clicked() {
|
||||
run(app, "format.color", json!({"color": "#C00000"}));
|
||||
}
|
||||
egui::Popup::menu(&a).show(|ui| {
|
||||
widgets::color_popup(&a).show(|ui| {
|
||||
if let Some(Some(c)) = widgets::color_grid(ui, &sc, None) {
|
||||
run(app, "format.color", json!({"color": cref_param(&c)}));
|
||||
}
|
||||
|
|
@ -743,7 +743,7 @@ fn drawing_group(app: &mut SlideApp, ui: &mut Ui) {
|
|||
run(app, "shape.fill", json!({"color": "accent1"}));
|
||||
}
|
||||
if let Some(a) = a {
|
||||
egui::Popup::menu(&a).show(|ui| {
|
||||
widgets::color_popup(&a).show(|ui| {
|
||||
if let Some(c) = widgets::color_grid(ui, &sc, Some("No Fill")) {
|
||||
match c {
|
||||
Some(c) => run(app, "shape.fill", json!({"color": cref_param(&c)})),
|
||||
|
|
@ -757,7 +757,7 @@ fn drawing_group(app: &mut SlideApp, ui: &mut Ui) {
|
|||
run(app, "shape.line", json!({"color": "tx1", "width": 1}));
|
||||
}
|
||||
if let Some(a) = a {
|
||||
egui::Popup::menu(&a).show(|ui| outline_menu(app, ui, &sc));
|
||||
widgets::color_popup(&a).show(|ui| outline_menu(app, ui, &sc));
|
||||
}
|
||||
let (_, a) = small_button_ex(ui, Icon::ShapeEffects, "Shape Effects", sel, false, true);
|
||||
if let Some(a) = a {
|
||||
|
|
@ -778,6 +778,7 @@ pub fn outline_menu(app: &mut SlideApp, ui: &mut Ui, sc: &deckcraft_color::Color
|
|||
for w in [0.25, 0.5, 0.75, 1.0, 1.5, 2.25, 3.0, 4.5, 6.0] {
|
||||
if ui.button(format!("{w} pt")).clicked() {
|
||||
run(app, "shape.line", json!({"width": w}));
|
||||
ui.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -793,6 +794,7 @@ pub fn outline_menu(app: &mut SlideApp, ui: &mut Ui, sc: &deckcraft_color::Color
|
|||
] {
|
||||
if ui.button(l).clicked() {
|
||||
run(app, "shape.line", json!({"dash": d}));
|
||||
ui.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -807,6 +809,7 @@ pub fn outline_menu(app: &mut SlideApp, ui: &mut Ui, sc: &deckcraft_color::Color
|
|||
] {
|
||||
if ui.button(l).clicked() {
|
||||
run(app, "shape.line", json!({"head": h, "tail": tl}));
|
||||
ui.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -1881,7 +1884,7 @@ fn shape_format(app: &mut SlideApp, ui: &mut Ui) {
|
|||
run(app, "shape.fill", json!({"color": "accent1"}));
|
||||
}
|
||||
if let Some(a) = a {
|
||||
egui::Popup::menu(&a).show(|ui| {
|
||||
widgets::color_popup(&a).show(|ui| {
|
||||
if let Some(c) = widgets::color_grid(ui, &sc, Some("No Fill")) {
|
||||
match c {
|
||||
Some(c) => run(app, "shape.fill", json!({"color": cref_param(&c)})),
|
||||
|
|
@ -1890,12 +1893,13 @@ fn shape_format(app: &mut SlideApp, ui: &mut Ui) {
|
|||
}
|
||||
if ui.button("Gradient…").clicked() {
|
||||
let _ = app.run("view.pane", json!({"pane": "format", "tab": "fill"}));
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
let (_, a) = small_button_ex(ui, Icon::ShapeOutline, "Shape Outline", sel, false, true);
|
||||
if let Some(a) = a {
|
||||
egui::Popup::menu(&a).show(|ui| outline_menu(app, ui, &sc));
|
||||
widgets::color_popup(&a).show(|ui| outline_menu(app, ui, &sc));
|
||||
}
|
||||
let (_, a) = small_button_ex(ui, Icon::ShapeEffects, "Shape Effects", sel, false, true);
|
||||
if let Some(a) = a {
|
||||
|
|
@ -1907,7 +1911,7 @@ fn shape_format(app: &mut SlideApp, ui: &mut Ui) {
|
|||
rows(ui, |ui| {
|
||||
let (_, a) = small_button_ex(ui, Icon::TextFill, "Text Fill", sel, false, true);
|
||||
if let Some(a) = a {
|
||||
egui::Popup::menu(&a).show(|ui| {
|
||||
widgets::color_popup(&a).show(|ui| {
|
||||
if let Some(Some(c)) = widgets::color_grid(ui, &sc, None) {
|
||||
run(app, "format.color", json!({"color": cref_param(&c)}));
|
||||
}
|
||||
|
|
@ -1915,7 +1919,7 @@ fn shape_format(app: &mut SlideApp, ui: &mut Ui) {
|
|||
}
|
||||
let (_, a) = small_button_ex(ui, Icon::TextOutline, "Text Outline", sel, false, true);
|
||||
if let Some(a) = a {
|
||||
egui::Popup::menu(&a).show(|ui| {
|
||||
widgets::color_popup(&a).show(|ui| {
|
||||
if let Some(c) = widgets::color_grid(ui, &sc, Some("No Outline")) {
|
||||
run(app, "format.textOutline", json!({"color": c.map(|c| cref_param(&c))}));
|
||||
}
|
||||
|
|
@ -2183,7 +2187,7 @@ fn table_design(app: &mut SlideApp, ui: &mut Ui) {
|
|||
if m.clicked() {
|
||||
run(app, "table.cellFill", json!({"color": "accent1"}));
|
||||
}
|
||||
egui::Popup::menu(&a).show(|ui| {
|
||||
widgets::color_popup(&a).show(|ui| {
|
||||
if let Some(c) = widgets::color_grid(ui, &sc, Some("No Fill")) {
|
||||
match c {
|
||||
Some(c) => run(app, "table.cellFill", json!({"color": cref_param(&c)})),
|
||||
|
|
|
|||
|
|
@ -239,6 +239,13 @@ pub fn dropdown(ui: &mut Ui, id: &str, current: &str, width: f32, enabled: bool,
|
|||
resp
|
||||
}
|
||||
|
||||
/// The drop-down for a `color_grid`: a menu that stays open when its hex field is clicked
|
||||
/// (egui menus close on any click inside). Picking a colour closes it (`color_grid` calls
|
||||
/// `ui.close()`); other buttons in it must close it themselves.
|
||||
pub fn color_popup(button: &Response) -> egui::Popup<'_> {
|
||||
egui::Popup::menu(button).close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside)
|
||||
}
|
||||
|
||||
/// The colour grid popup body: theme colours with tints/shades, standard colours, extra entries.
|
||||
/// Returns the picked colour (`Some(None)` = "No Fill"/"Automatic" when `none_label` is given).
|
||||
pub fn color_grid(ui: &mut Ui, scheme: &ColorScheme, none_label: Option<&str>) -> Option<Option<ColorRef>> {
|
||||
|
|
@ -440,3 +447,42 @@ pub fn drop_button(ui: &mut Ui, label: &str, size: egui::Vec2, enabled: bool) ->
|
|||
chevron(ui.painter(), egui::pos2(r.rect.max.x - 8.0, r.rect.center().y), 3.0, col);
|
||||
r
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#![allow(clippy::unwrap_used, clippy::expect_used)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::*;
|
||||
use egui::accesskit::Role;
|
||||
use egui_kittest::kittest::Queryable;
|
||||
|
||||
/// #32: clicking the "More Colors" hex field closed the colour menu before anything could be
|
||||
/// typed. It stays open now; Enter picks the colour and closes it.
|
||||
#[test]
|
||||
fn the_hex_field_keeps_the_color_menu_open() {
|
||||
let picked = RefCell::new(None);
|
||||
let scheme = deckcraft_model::Theme::default().colors;
|
||||
let mut harness = egui_kittest::Harness::builder().with_size(vec2(400.0, 500.0)).build_ui(|ui| {
|
||||
theme::install_fonts(ui.ctx());
|
||||
let r = ui.button("Pick");
|
||||
color_popup(&r).show(|ui| {
|
||||
if let Some(c) = color_grid(ui, &scheme, None) {
|
||||
*picked.borrow_mut() = Some(c);
|
||||
}
|
||||
});
|
||||
});
|
||||
harness.get_by_label("Pick").click();
|
||||
harness.run();
|
||||
harness.get_by_role(Role::TextInput).click();
|
||||
harness.run();
|
||||
assert!(harness.query_by_role(Role::TextInput).is_some(), "the menu is still open after clicking the hex field");
|
||||
harness.get_by_role(Role::TextInput).type_text("00FF00");
|
||||
harness.run();
|
||||
harness.key_press(egui::Key::Enter);
|
||||
harness.run();
|
||||
assert_eq!(*picked.borrow(), Some(Some(ColorRef::rgb(Rgba::from_hex("00FF00").unwrap()))));
|
||||
assert!(harness.query_by_role(Role::TextInput).is_none(), "picking a colour closes the menu");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue