diff --git a/Cargo.lock b/Cargo.lock index 1159481f5..fd4345fb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1191,13 +1191,14 @@ dependencies = [ [[package]] name = "craft-update" version = "0.1.0" -source = "git+https://github.com/storytold/craft-libs?rev=92d392cff132eaf53e13afff77f38b5c11b73aa0#92d392cff132eaf53e13afff77f38b5c11b73aa0" +source = "git+https://github.com/storytold/craft-libs?rev=1065653e75854e9c17e1ff563acdd344c1b185f0#1065653e75854e9c17e1ff563acdd344c1b185f0" dependencies = [ "chrono", "dunce", "egui", "flate2", "getrandom 0.3.4", + "image", "log", "plist", "semver", diff --git a/Cargo.toml b/Cargo.toml index 1d4d7c530..220f29403 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,8 @@ eframe = { version = "0.37", default-features = false } egui-wgpu = "0.37" # Monotonic time on native and web (performance.now on wasm). web-time = "1.1" -craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0", features = ["egui"] } +# craft-update with storytold/craft-libs#434: the update prompt shows the app's icon, accent and developer. +craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "1065653e75854e9c17e1ff563acdd344c1b185f0", features = ["egui"] } rfd = "0.17" arboard = { version = "3.6", default-features = false } diff --git a/apps/cadcraft/src/main.rs b/apps/cadcraft/src/main.rs index 19546d6ce..4d7bdc39b 100644 --- a/apps/cadcraft/src/main.rs +++ b/apps/cadcraft/src/main.rs @@ -218,7 +218,7 @@ fn main() -> eframe::Result { let logger = logging::install(); // The update helper relaunches this binary after a self-update; it runs and exits here. #[cfg(not(target_arch = "wasm32"))] - if let Some(done) = craft_update::self_update::finish(&craft_update::suite::CADCRAFT, &std::env::args_os().skip(1).collect::>()) { + if let Some(done) = craft_update::self_update::finish(&cadcraft_ui_egui::UPDATE_APP, &std::env::args_os().skip(1).collect::>()) { if let Err(e) = done { eprintln!("CADCraft update helper failed: {e}"); std::process::exit(1); diff --git a/crates/constraints/src/auto.rs b/crates/constraints/src/auto.rs index fe7764205..211be6b93 100644 --- a/crates/constraints/src/auto.rs +++ b/crates/constraints/src/auto.rs @@ -52,15 +52,11 @@ fn collect(d: &Drawing, handles: &[Handle]) -> Geo { g.curves.push((GeomRef::whole(h), ga.center, a.radius)); } } - EntityKind::Circle(c) => { - if c.center.is_finite() && c.radius.is_finite() { - g.curves.push((GeomRef::whole(h), c.center.xy(), c.radius)); - } + EntityKind::Circle(c) if c.center.is_finite() && c.radius.is_finite() => { + g.curves.push((GeomRef::whole(h), c.center.xy(), c.radius)); } - EntityKind::Point(p) => { - if p.p.is_finite() { - g.points.push((GeomRef::whole(h), p.p.xy())); - } + EntityKind::Point(p) if p.p.is_finite() => { + g.points.push((GeomRef::whole(h), p.p.xy())); } EntityKind::LwPolyline(p) => { let n = p.vertices.len(); diff --git a/crates/engine/src/audit.rs b/crates/engine/src/audit.rs index f78de7efe..c055bff25 100644 --- a/crates/engine/src/audit.rs +++ b/crates/engine/src/audit.rs @@ -460,17 +460,13 @@ fn references(d: &mut Drawing, out: &mut Vec) { m.style = "Standard".into(); } } - EntityKind::Table(t) => { - if !has_name(&d.table_styles, &t.style, |s| &s.name) { - note("table style", &t.style); - t.style = "Standard".into(); - } + EntityKind::Table(t) if !has_name(&d.table_styles, &t.style, |s| &s.name) => { + note("table style", &t.style); + t.style = "Standard".into(); } - EntityKind::Leader(l) => { - if !ok_dim(d, &l.style) { - note("dimension style", &l.style); - l.style = "Standard".into(); - } + EntityKind::Leader(l) if !ok_dim(d, &l.style) => { + note("dimension style", &l.style); + l.style = "Standard".into(); } EntityKind::Dimension(dim) => { if !ok_dim(d, &dim.style) { diff --git a/crates/engine/src/cmd/inquiry.rs b/crates/engine/src/cmd/inquiry.rs index c7f59a0cf..0fa342e23 100644 --- a/crates/engine/src/cmd/inquiry.rs +++ b/crates/engine/src/cmd/inquiry.rs @@ -840,11 +840,9 @@ impl Interactive for DistM { let model = model_points(&self.sources); s.echo(format!("Distance = {}", fmt_d(s, path_len(model.as_deref().unwrap_or(pts), &self.bulges)))); } - Input::Keyword(k) if k == "Undo" => { - if pts.len() > 1 { - self.arcs.undo(pts, &mut self.bulges); - self.sources.pop(); - } + Input::Keyword(k) if k == "Undo" && pts.len() > 1 => { + self.arcs.undo(pts, &mut self.bulges); + self.sources.pop(); } Input::Keyword(k) if k == "Length" => self.length = true, Input::Keyword(k) if k == "Total" => return self.total(s, false), @@ -852,10 +850,8 @@ impl Interactive for DistM { self.arcs.close(pts, &mut self.bulges)?; return self.total(s, true); } - Input::Keyword(k) => { - if !self.arcs.keyword(&k, pts) { - s.echo(format!("{k}: not available yet")); - } + Input::Keyword(k) if !self.arcs.keyword(&k, pts) => { + s.echo(format!("{k}: not available yet")); } Input::Enter => return self.total(s, false), _ => {} diff --git a/crates/engine/src/mtext_edit.rs b/crates/engine/src/mtext_edit.rs index 30da0b897..97ecede6f 100644 --- a/crates/engine/src/mtext_edit.rs +++ b/crates/engine/src/mtext_edit.rs @@ -136,11 +136,9 @@ impl Formatted { i += 2; match code { None => {} - Some('P') => { - if f.paras.len() < MAX_PARAS { - f.push_char('\n', &cur); - f.paras.push(props.clone()); - } + Some('P') if f.paras.len() < MAX_PARAS => { + f.push_char('\n', &cur); + f.paras.push(props.clone()); } Some(c @ ('\\' | '{' | '}')) => f.push_char(c, &cur), Some('L') => cur.underline = true, diff --git a/crates/geom/src/nurbs.rs b/crates/geom/src/nurbs.rs index 5268203b1..104ba8d3c 100644 --- a/crates/geom/src/nurbs.rs +++ b/crates/geom/src/nurbs.rs @@ -487,7 +487,7 @@ impl Spline { /// Arc length between parameters `a` and `b` (adaptive Gauss–Legendre over each knot span). pub fn length_between(&self, a: f64, b: f64) -> f64 { - if !self.is_valid() || !(a.is_finite() && b.is_finite()) { + if !(self.is_valid() && a.is_finite() && b.is_finite()) { return 0.0; } let (lo, hi) = self.domain(); diff --git a/crates/io/src/dxf_raw.rs b/crates/io/src/dxf_raw.rs index 0154b01d3..9b755f80f 100644 --- a/crates/io/src/dxf_raw.rs +++ b/crates/io/src/dxf_raw.rs @@ -135,10 +135,8 @@ fn head(tags: &[Tag]) -> Head { h.has_reactors |= group.as_deref() == Some("ACAD_REACTORS"); } (_, Some("ACAD_REACTORS")) => h.reactors.push(norm(&t.str())), - (_, Some("ACAD_XDICTIONARY")) => { - if h.xdict.is_none() { - h.xdict = Some(norm(&t.str())); - } + (_, Some("ACAD_XDICTIONARY")) if h.xdict.is_none() => { + h.xdict = Some(norm(&t.str())); } (_, Some(_)) => {} (5 | 105, None) if h.handle.is_none() => h.handle = Some(norm(&t.str())), diff --git a/crates/io/src/dxf_read/document.rs b/crates/io/src/dxf_read/document.rs index 02ea0f532..d732f4450 100644 --- a/crates/io/src/dxf_read/document.rs +++ b/crates/io/src/dxf_read/document.rs @@ -35,13 +35,11 @@ pub(super) fn parse_entities( extra = more; kindent = Some((c, k)); } - "INSERT" => { - if t.i(66) == Some(1) { - let ins_layer = kindent.as_ref().map(|(c, _)| c.layer.clone()).unwrap_or_default(); - let attribs = insert_attribs(recs, &mut i, &ins_layer); - if let Some((_, EntityKind::Insert(ins))) = kindent.as_mut() { - ins.attribs = attribs; - } + "INSERT" if t.i(66) == Some(1) => { + let ins_layer = kindent.as_ref().map(|(c, _)| c.layer.clone()).unwrap_or_default(); + let attribs = insert_attribs(recs, &mut i, &ins_layer); + if let Some((_, EntityKind::Insert(ins))) = kindent.as_mut() { + ins.attribs = attribs; } } // A VERTEX or ATTRIB with no POLYLINE or INSERT before it; a stray SEQEND holds nothing. diff --git a/crates/render/src/text.rs b/crates/render/src/text.rs index 1f80d7af4..8e692facd 100644 --- a/crates/render/src/text.rs +++ b/crates/render/src/text.rs @@ -77,7 +77,7 @@ pub(super) fn mesh(g: &TextGlyph, xf: Mat3, pixel: f64) -> Arc { let contours = ttf::glyph_contours(&g.face, g.gid); let points = contours.iter().map(Vec::len).try_fold(0usize, usize::checked_add); // Font data is untrusted; don't hand unbounded or invalid paths to the tessellator. - if !points.is_some_and(|n| n <= MAX_POINTS) || contours.iter().flatten().any(|p| !p.is_finite() || p.x.abs().max(p.y.abs()) > 1.0e6) { + if points.is_none_or(|n| n > MAX_POINTS) || contours.iter().flatten().any(|p| !p.is_finite() || p.x.abs().max(p.y.abs()) > 1.0e6) { return Arc::new(Mesh { contours: Arc::default(), triangles: Vec::new() }); } let contours = match detail { diff --git a/crates/ui-egui/src/cmdline.rs b/crates/ui-egui/src/cmdline.rs index d78561551..9d8bd9821 100644 --- a/crates/ui-egui/src/cmdline.rs +++ b/crates/ui-egui/src/cmdline.rs @@ -379,13 +379,11 @@ pub fn keyboard(app: &mut CadApp, ctx: &egui::Context) { app.cmd.buffer.pop(); } } - Key::ArrowUp if !modifiers.any() => { - if !app.cmd.history.is_empty() { - let n = app.cmd.history.len(); - let pos = app.cmd.history_pos.map(|p| p.saturating_sub(1)).unwrap_or(n - 1); - app.cmd.history_pos = Some(pos); - app.cmd.buffer = app.cmd.history.get(pos).cloned().unwrap_or_default(); - } + Key::ArrowUp if !modifiers.any() && !app.cmd.history.is_empty() => { + let n = app.cmd.history.len(); + let pos = app.cmd.history_pos.map(|p| p.saturating_sub(1)).unwrap_or(n - 1); + app.cmd.history_pos = Some(pos); + app.cmd.buffer = app.cmd.history.get(pos).cloned().unwrap_or_default(); } Key::ArrowDown if !modifiers.any() => { if !options_key(app, 1) diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 22e325cbe..311dd4cbf 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -8,6 +8,15 @@ #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] #![forbid(unsafe_code)] +/// CADCraft as craft-update knows it, with its 128 px icon and accent colour: the update +/// prompt shows both, and an AppImage's menu entry gets the icon. +#[cfg(not(target_arch = "wasm32"))] +pub const UPDATE_APP: craft_update::app::App = craft_update::app::App { + icon_png: Some(include_bytes!("../../../assets/app-icon/hicolor/128x128/apps/ai.storyteller.cadcraft.png")), + accent: Some([0x3e, 0xa6, 0xe8]), + ..craft_update::suite::CADCRAFT +}; + pub mod aliasdlg; pub mod animation; pub mod autosave; diff --git a/crates/ui-egui/src/updates_ui.rs b/crates/ui-egui/src/updates_ui.rs index 1bd05c6f8..ffc625767 100644 --- a/crates/ui-egui/src/updates_ui.rs +++ b/crates/ui-egui/src/updates_ui.rs @@ -2,7 +2,6 @@ //! Updates… (desktop only; the web build is always the latest). The flow itself is //! `craft_update::updater::Updater`. -use craft_update::suite::CADCRAFT; use craft_update::updater::{Action, Status, Updater}; use crate::CadApp; @@ -21,7 +20,7 @@ pub struct Runtime { impl Default for Runtime { fn default() -> Self { - Self { updater: Updater::new(&CADCRAFT, VERSION), enabled: false, check_requested: false } + Self { updater: Updater::new(&crate::UPDATE_APP, VERSION), enabled: false, check_requested: false } } } diff --git a/xtask/src/layers.rs b/xtask/src/layers.rs index aab245784..c23825d11 100644 --- a/xtask/src/layers.rs +++ b/xtask/src/layers.rs @@ -167,10 +167,8 @@ pub fn check(crates: &[Crate]) -> Vec { match classify(&d.name) { // Unregistered deps are reported on their own entry. None => {} - Some(Class::Testkit) => { - if d.kind != DepKind::Dev { - out.push(Violation::TestkitAsNormalDep { krate: c.name.clone() }); - } + Some(Class::Testkit) if d.kind != DepKind::Dev => { + out.push(Violation::TestkitAsNormalDep { krate: c.name.clone() }); } Some(dc) => { let to = dc.layer().unwrap_or(u8::MAX);