From c536e6247be982f59c85ef2889ad687281c5fc0f Mon Sep 17 00:00:00 2001 From: vcoppe Date: Sun, 4 Oct 2026 17:29:57 +0200 Subject: [PATCH] progress --- .../engine/src/engine/command/pattern/mod.rs | 2 + .../engine/command/pattern/update_waypoint.rs | 30 +++++++++++ .../src/engine/command/tools/edit_waypoint.rs | 51 ++++++++----------- .../src/engine/command/tools/move_waypoint.rs | 35 +++---------- gpx-rs/engine/src/engine/engine.rs | 11 +--- gpx-rs/wasm/src/lib.rs | 30 +++++++---- .../toolbar/tools/waypoint/Waypoint.svelte | 6 +-- website/src/lib/engine.ts | 6 ++- 8 files changed, 89 insertions(+), 82 deletions(-) create mode 100644 gpx-rs/engine/src/engine/command/pattern/update_waypoint.rs diff --git a/gpx-rs/engine/src/engine/command/pattern/mod.rs b/gpx-rs/engine/src/engine/command/pattern/mod.rs index 7ac5a61aa..7855021e9 100644 --- a/gpx-rs/engine/src/engine/command/pattern/mod.rs +++ b/gpx-rs/engine/src/engine/command/pattern/mod.rs @@ -3,9 +3,11 @@ mod edit_waypoint_chunks; mod insert_waypoints; mod produce; mod update_selected; +mod update_waypoint; pub use copy::*; pub use edit_waypoint_chunks::*; pub use insert_waypoints::*; pub use produce::*; pub use update_selected::*; +pub use update_waypoint::*; diff --git a/gpx-rs/engine/src/engine/command/pattern/update_waypoint.rs b/gpx-rs/engine/src/engine/command/pattern/update_waypoint.rs new file mode 100644 index 000000000..69cfe5881 --- /dev/null +++ b/gpx-rs/engine/src/engine/command/pattern/update_waypoint.rs @@ -0,0 +1,30 @@ +use std::rc::Rc; + +use crate::{CommandError, FileId, State, Waypoint, WaypointId, edit_waypoint_chunks}; + +/// Changes one waypoint of a file with `f`, whatever is selected. Nothing to do if the file or +/// the waypoint does not exist. +pub fn update_waypoint( + state: &mut State, + file_id: FileId, + waypoint_id: WaypointId, + f: impl Fn(&mut Waypoint), +) -> Result<(), CommandError> { + let file = state.files.get(&file_id).ok_or(CommandError::NothingToDo)?; + let mut file = (**file).clone(); + let changed = edit_waypoint_chunks( + &mut file, + |wpt| wpt.id == waypoint_id, + |wpts| { + wpts.iter_mut() + .filter(|wpt| wpt.id == waypoint_id) + .for_each(&f); + true + }, + ); + if !changed { + return Err(CommandError::NothingToDo); + } + state.files.insert(file_id, Rc::new(file)); + Ok(()) +} diff --git a/gpx-rs/engine/src/engine/command/tools/edit_waypoint.rs b/gpx-rs/engine/src/engine/command/tools/edit_waypoint.rs index 3a4c501b7..a051d48cf 100644 --- a/gpx-rs/engine/src/engine/command/tools/edit_waypoint.rs +++ b/gpx-rs/engine/src/engine/command/tools/edit_waypoint.rs @@ -1,11 +1,12 @@ -use crate::{ - Apply, CommandError, Edit, Editor, State, Waypoint, set_waypoint_fields, update_selected, -}; +use crate::{Apply, CommandError, FileId, State, WaypointId, set_waypoint_fields, update_waypoint}; -/// Changes the selected waypoints (what the form of the waypoint tool does): their name, -/// description, icon, link, position and elevation. The strings that are empty remove the field. +/// Changes a waypoint of a file, whatever is selected (what the form of the waypoint tool does): +/// its name, description, icon, link, position and elevation. The strings that are empty remove +/// the field. #[derive(Debug)] pub struct EditWaypoint<'a> { + pub file_id: FileId, + pub waypoint_id: WaypointId, pub lng: f64, pub lat: f64, pub ele: f64, @@ -16,38 +17,32 @@ pub struct EditWaypoint<'a> { } impl Apply for EditWaypoint<'_> { - fn apply(mut self, state: &mut State) -> Result<(), CommandError> { - update_selected(state, &mut self); - Ok(()) - } -} - -impl Editor for EditWaypoint<'_> { - fn waypoint(&mut self, waypoint: &mut Waypoint) -> Edit { - set_waypoint_fields( - waypoint, - (self.lng, self.lat, self.ele), - self.name, - self.desc, - self.icon, - self.link, - ); - Edit::Changed + fn apply(self, state: &mut State) -> Result<(), CommandError> { + update_waypoint(state, self.file_id, self.waypoint_id, |wpt| { + set_waypoint_fields( + wpt, + (self.lng, self.lat, self.ele), + self.name, + self.desc, + self.icon, + self.link, + ) + }) } } #[cfg(test)] mod tests { - use std::{collections::HashSet, rc::Rc}; + use std::rc::Rc; use crate::{ - File, Link, Selection, WaypointChunk, engine::command::fixture::Fixture, waypoint_ids, + File, Link, Waypoint, WaypointChunk, engine::command::fixture::Fixture, waypoint_ids, }; use super::*; #[test] - fn test_edit_the_selected_waypoint() { + fn test_edit_the_given_waypoint() { let mut fx = Fixture::default(); let mut file = File::default(); file.wpt.push(Rc::new(WaypointChunk { @@ -73,12 +68,10 @@ mod tests { let id = file.id; let ids: Vec<_> = waypoint_ids(&file).collect(); fx.files.insert(id, Rc::new(file)); - fx.selection = Selection::Waypoint { - file_id: id, - wpt_ids: HashSet::from([ids[0]]), - }; EditWaypoint { + file_id: id, + waypoint_id: ids[0], lng: 4.5, lat: 50.5, ele: 12.0, diff --git a/gpx-rs/engine/src/engine/command/tools/move_waypoint.rs b/gpx-rs/engine/src/engine/command/tools/move_waypoint.rs index 07ca2c52a..13063309f 100644 --- a/gpx-rs/engine/src/engine/command/tools/move_waypoint.rs +++ b/gpx-rs/engine/src/engine/command/tools/move_waypoint.rs @@ -1,6 +1,4 @@ -use std::rc::Rc; - -use crate::{Apply, CommandError, FileId, LngLat, State, WaypointId, edit_waypoint_chunks}; +use crate::{Apply, CommandError, FileId, LngLat, State, WaypointId, update_waypoint}; /// Moves a waypoint of a file, whatever is selected (what a drag does): only its position and /// elevation change. @@ -15,30 +13,13 @@ pub struct MoveWaypoint { impl Apply for MoveWaypoint { fn apply(self, state: &mut State) -> Result<(), CommandError> { - let file = state - .files - .get(&self.file_id) - .ok_or(CommandError::NothingToDo)?; - let mut file = (**file).clone(); - let changed = edit_waypoint_chunks( - &mut file, - |wpt| wpt.id == self.waypoint_id, - |wpts| { - for wpt in wpts.iter_mut().filter(|wpt| wpt.id == self.waypoint_id) { - wpt.coordinates = LngLat { - lng: self.lng, - lat: self.lat, - }; - wpt.ele = self.ele; - } - true - }, - ); - if !changed { - return Err(CommandError::NothingToDo); - } - state.files.insert(self.file_id, Rc::new(file)); - Ok(()) + update_waypoint(state, self.file_id, self.waypoint_id, |wpt| { + wpt.coordinates = LngLat { + lng: self.lng, + lat: self.lat, + }; + wpt.ele = self.ele; + }) } } diff --git a/gpx-rs/engine/src/engine/engine.rs b/gpx-rs/engine/src/engine/engine.rs index 8284dd063..713d54f32 100644 --- a/gpx-rs/engine/src/engine/engine.rs +++ b/gpx-rs/engine/src/engine/engine.rs @@ -1188,18 +1188,11 @@ mod tests { // the coordinates buffer follows assert_eq!(engine.waypoint_coordinates(&file), &[5.0, 51.0]); - // editing applies to the selected waypoints - select_elements( - &mut engine, - Selection::Waypoint { - file_id: file, - wpt_ids: [id].into(), - }, - SelectMode::Replace, - ); assert!(edit( &mut engine, Command::EditWaypoint(EditWaypoint { + file_id: file, + waypoint_id: id, lng: 6.0, lat: 52.0, ele: 30.0, diff --git a/gpx-rs/wasm/src/lib.rs b/gpx-rs/wasm/src/lib.rs index d3f55012a..9eeba0e6e 100644 --- a/gpx-rs/wasm/src/lib.rs +++ b/gpx-rs/wasm/src/lib.rs @@ -317,10 +317,13 @@ fn parse_waypoint_id(id: &str) -> Option { uuid::Uuid::parse_str(id).ok().map(engine::WaypointId) } -/// Changes the selected waypoints: their name, description, icon, link, position and elevation. -/// The strings that are empty remove the field. +/// Changes a waypoint of a file, whatever is selected: its name, description, icon, link, position +/// and elevation. The strings that are empty remove the field. #[wasm_bindgen] +#[allow(clippy::too_many_arguments)] pub fn update_waypoint( + file_id: &str, + waypoint_id: &str, lng: f64, lat: f64, ele: f64, @@ -329,15 +332,20 @@ pub fn update_waypoint( icon: &str, link: &str, ) -> bool { - edit(Command::EditWaypoint(engine::EditWaypoint { - lng, - lat, - ele, - name, - desc, - icon, - link, - })) + match (parse_file_id(file_id), parse_waypoint_id(waypoint_id)) { + (Some(file_id), Some(waypoint_id)) => edit(Command::EditWaypoint(engine::EditWaypoint { + file_id, + waypoint_id, + lng, + lat, + ele, + name, + desc, + icon, + link, + })), + _ => false, + } } #[wasm_bindgen] diff --git a/website/src/lib/components/toolbar/tools/waypoint/Waypoint.svelte b/website/src/lib/components/toolbar/tools/waypoint/Waypoint.svelte index 5002553d0..a6720b1be 100644 --- a/website/src/lib/components/toolbar/tools/waypoint/Waypoint.svelte +++ b/website/src/lib/components/toolbar/tools/waypoint/Waypoint.svelte @@ -99,12 +99,10 @@ link, }; if (target) { - // the engine changes the selected waypoint - await engine.selectWaypoints(target.fileId, [target.id]); - await engine.updateWaypoint(waypoint); + engine.updateWaypoint(target.fileId, target.id, waypoint); } else { // it goes in the selected files - await engine.newWaypoint(waypoint); + engine.newWaypoint(waypoint); } reset(); diff --git a/website/src/lib/engine.ts b/website/src/lib/engine.ts index 3bfe819cd..bd8a5234b 100644 --- a/website/src/lib/engine.ts +++ b/website/src/lib/engine.ts @@ -449,10 +449,12 @@ class Engine { ); } - /** Changes the selected waypoints. Empty strings remove the field. */ - updateWaypoint(waypoint: NewWaypoint) { + /** Changes a waypoint, selected or not. Empty strings remove the field. */ + updateWaypoint(fileId: string, waypointId: string, waypoint: NewWaypoint) { return this.run((w) => w.update_waypoint( + fileId, + waypointId, waypoint.lng, waypoint.lat, waypoint.ele,