diff --git a/crates/ui-egui/src/comments_tests.rs b/crates/ui-egui/src/comments_tests.rs index 696ff322..eea2278e 100644 --- a/crates/ui-egui/src/comments_tests.rs +++ b/crates/ui-egui/src/comments_tests.rs @@ -7,7 +7,7 @@ use egui::{Event, Key, Modifiers, Pos2, pos2, vec2}; use figcraft_engine::Session; use serde_json::{Value, json}; -use crate::comments::{cluster, insert_mention, mention_matches, mention_query}; +use crate::comments::{cluster, insert_mention, mention_matches, mention_query, start_draft}; use crate::present_tests::{Ui, id}; fn add(s: &mut Session, x: f64, y: f64, text: &str, author: &str) -> u64 { @@ -41,6 +41,35 @@ fn comments(u: &Ui) -> Value { u.app.inspect()["comments"].clone() } +#[test] +fn switching_from_comment_to_move_closes_the_unposted_composer() { + let mut u = Ui::new(Session::new()); + u.app.run("tool.set", json!({"tool": "comment"})); + start_draft(&mut u.app, 100.0, 80.0); + assert!(comments(&u)["draft"].is_array()); + + u.app.run("tool.set", json!({"tool": "move"})); + u.frame(vec![]); + assert!(comments(&u)["draft"].is_null()); +} + +#[test] +fn control_channel_tool_switch_closes_the_unposted_composer() { + let mut u = Ui::new(Session::new()); + u.app.run("tool.set", json!({"tool": "comment"})); + start_draft(&mut u.app, 100.0, 80.0); + assert!(comments(&u)["draft"].is_array()); + + let invalid = json!({"command": "tool.set", "params": {"tool": "not-a-tool"}}); + assert!(crate::control::handle(&mut u.app, &egui::Context::default(), "engine.execute", &invalid).is_err()); + assert!(comments(&u)["draft"].is_array()); + + crate::control::handle(&mut u.app, &egui::Context::default(), "engine.execute", &json!({"command": "tool.set", "params": {"tool": "move"}})) + .unwrap(); + u.frame(vec![]); + assert!(comments(&u)["draft"].is_null()); +} + #[test] fn mention_helpers() { // The `@query` before the cursor. diff --git a/crates/ui-egui/src/control.rs b/crates/ui-egui/src/control.rs index a4a8dd15..2d35609a 100644 --- a/crates/ui-egui/src/control.rs +++ b/crates/ui-egui/src/control.rs @@ -239,6 +239,7 @@ pub fn handle(app: &mut FigApp, ctx: &Context, method: &str, p: &Value) -> Resul let cmd = p.get("command").and_then(Value::as_str).ok_or("`command` required")?; let params = p.get("params").cloned().unwrap_or(json!({})); let r = app.session.execute(cmd, ¶ms).map_err(|e| e.to_string()); + app.clear_comment_draft_after_tool_set(cmd, r.is_ok()); // Programmatic calls never open dialogs. app.session.ui_requests.retain(|u| !u.kind.starts_with("dialog.")); app.handle_ui_requests(); diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 072aec62..d728dc27 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -831,9 +831,17 @@ impl FigApp { } } + /// Dismiss the composer after a successful switch away from the Comment tool. + pub(crate) fn clear_comment_draft_after_tool_set(&mut self, id: &str, succeeded: bool) { + if id == "tool.set" && succeeded && self.session.tool.tool != figcraft_engine::tools::ToolId::Comment { + self.ui.comments.draft = None; + } + } + /// Run a command, surfacing errors as a toast. Returns the result. pub fn run(&mut self, id: &str, params: Value) -> Option { let r = self.session.execute(id, ¶ms); + self.clear_comment_draft_after_tool_set(id, r.is_ok()); self.handle_ui_requests(); r.map_err(|e| self.failed(id, &e)).ok() }