[IMP] OneCAD rebrand: OneCAD wordmark + direct-to-workspace launch, no splash hold, no external links (docs/GitHub removed, local reports), all visible strings + locales OneCAD

This commit is contained in:
Z User committed 2026-10-18 17:43:10 +00:00
1 parent ac05e26934
commit a824c1eb75
33 files changed
+472 -461

No files matched your search

+1 -1
View File
@@ -40,7 +40,7 @@ pub fn initialize_params(version: &str) -> Value {
"auth": {"terminal": true},
"_meta": {"terminal-auth": true},
},
"clientInfo": {"name": "solidcraft", "title": "SolidCraft", "version": version},
"clientInfo": {"name": "onecad", "title": "OneCAD", "version": version},
})
}
+1 -1
View File
@@ -134,7 +134,7 @@ impl AcpBackend {
Incoming::ModeChanged(m) => out.push(Event::Modes { current: m, available: Vec::new() }),
Incoming::ModelChanged(m) => out.push(Event::Models { current: m, available: Vec::new() }),
Incoming::Unsupported { rpc, method } => {
self.proc.send(&acp::reply_error(rpc, acp::METHOD_NOT_FOUND, &format!("SolidCraft does not serve `{method}`")));
self.proc.send(&acp::reply_error(rpc, acp::METHOD_NOT_FOUND, &format!("OneCAD does not serve `{method}`")));
}
Incoming::Ignored => {}
}
+3 -3
View File
@@ -179,7 +179,7 @@ impl Worker {
/// One MCP request to the server; its `result`.
fn mcp_call(&mut self, method: &str, params: Value) -> Result<Value, String> {
let Some(m) = self.mcp.as_ref() else { return Err("no SolidCraft tools in this session".into()) };
let Some(m) = self.mcp.as_ref() else { return Err("no OneCAD tools in this session".into()) };
self.next += 1;
let id = self.next;
m.send(&json!({"jsonrpc": "2.0", "id": id, "method": method, "params": params}));
@@ -202,9 +202,9 @@ impl Worker {
}
return Ok(v.get("result").cloned().unwrap_or(Value::Null));
}
Ok(FromAgent::Exited(_)) => return Err("the SolidCraft tools stopped".into()),
Ok(FromAgent::Exited(_)) => return Err("the OneCAD tools stopped".into()),
Err(std::sync::mpsc::RecvTimeoutError::Timeout) if std::time::Instant::now() < deadline => {}
Err(_) => return Err("the SolidCraft tools did not answer".into()),
Err(_) => return Err("the OneCAD tools did not answer".into()),
}
}
}
+1 -1
View File
@@ -50,7 +50,7 @@ pub fn announce(app: &mut SolveApp, fresh: &[Summary]) {
}
app.crashes.open = true;
app.crashes.refresh();
app.set_status("SolidCraft closed unexpectedly or hit an internal error last time. A crash report was saved (Help > Crash Reports…).", true);
app.set_status("OneCAD closed unexpectedly or hit an internal error last time. A crash report was saved (Help > Crash Reports…).", true);
}
pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
+3 -3
View File
@@ -61,7 +61,7 @@ pub fn copy(app: &mut SolveApp) -> bool {
let Ok(out) = app.run("sketch.copy", json!({ "entities": entities })) else { return false };
let n = out.get("curves").and_then(Value::as_u64).unwrap_or(0) + out.get("points").and_then(Value::as_u64).unwrap_or(0);
let k = out.get("constraints").and_then(Value::as_u64).unwrap_or(0);
let text = format!("SolidCraft sketch geometry: {n} entities, {k} constraints and dimensions");
let text = format!("OneCAD sketch geometry: {n} entities, {k} constraints and dimensions");
app.set_status(format!("Copied {n} sketch entities with {k} constraints and dimensions"), false);
leave_text(text);
return true;
@@ -74,7 +74,7 @@ pub fn copy(app: &mut SolveApp) -> bool {
let Ok(out) = app.run("timeline.copy", json!({ "features": features })) else { return false };
let names: Vec<&str> = out.get("copied").and_then(Value::as_array).map(|a| a.iter().filter_map(Value::as_str).collect()).unwrap_or_default();
app.set_status(format!("Copied {}", names.join(", ")), false);
leave_text(format!("SolidCraft features: {}", names.join(", ")));
leave_text(format!("OneCAD features: {}", names.join(", ")));
true
}
@@ -92,7 +92,7 @@ pub fn cut(app: &mut SolveApp) -> bool {
let Ok(out) = app.run("sketch.cut", json!({ "entities": entities })) else { return false };
let n = out.get("curves").and_then(Value::as_u64).unwrap_or(0) + out.get("points").and_then(Value::as_u64).unwrap_or(0);
app.set_status(format!("Cut {n} sketch entities"), false);
leave_text(format!("SolidCraft sketch geometry: {n} entities"));
leave_text(format!("OneCAD sketch geometry: {n} entities"));
true
}
+1 -1
View File
@@ -89,7 +89,7 @@ fn copy_leaves_text_on_the_system_clipboard_so_paste_can_follow() {
_ => None,
}));
}
assert!(copied.iter().any(|t| t.starts_with("SolidCraft sketch geometry")), "{copied:?}");
assert!(copied.iter().any(|t| t.starts_with("OneCAD sketch geometry")), "{copied:?}");
}
#[test]
+3 -3
View File
@@ -354,7 +354,7 @@ fn start(app: &mut SolveApp) {
let picture = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| partial_picture(&partial.world, &stop))).ok().flatten();
if solidcraft_engine::geom::env::var_os("PROFILE_OPEN").is_some() {
eprintln!(
"SolidCraft partial picture: features={} bodies={} drawn={} ms={:.1}",
"OneCAD partial picture: features={} bodies={} drawn={} ms={:.1}",
partial.features,
partial.world.bodies.len(),
picture.is_some(),
@@ -380,7 +380,7 @@ fn start(app: &mut SolveApp) {
if let Some(picture) = picture.filter(|_| !progress.is_cancelled()) {
let _ = preview_tx.send(picture);
if solidcraft_engine::geom::env::var_os("PROFILE_OPEN").is_some() {
eprintln!("SolidCraft saved preview: ready_ms={:.3}", preview_began.elapsed().as_secs_f64() * 1000.0);
eprintln!("OneCAD saved preview: ready_ms={:.3}", preview_began.elapsed().as_secs_f64() * 1000.0);
}
}
}
@@ -736,7 +736,7 @@ fn compute(
let image = if thumbnail { crate::home::remember(&session) } else { None };
if profile {
eprintln!(
"SolidCraft open phases: geometry_ms={geometry_ms:.3} placement_ms={placement_ms:.3} tessellation_ms={tessellation_ms:.3} display_warmup_ms={view_ms:.3} thumbnail_ms={:.3} total_ms={:.3}",
"OneCAD open phases: geometry_ms={geometry_ms:.3} placement_ms={placement_ms:.3} tessellation_ms={tessellation_ms:.3} display_warmup_ms={view_ms:.3} thumbnail_ms={:.3} total_ms={:.3}",
thumbnail_began.elapsed().as_secs_f64() * 1000.0,
began.elapsed().as_secs_f64() * 1000.0
);
+14 -15
View File
@@ -1,6 +1,7 @@
//! The Help menu (the ? button on the application bar): Documentation (the online book), About
//! SolidCraft (version, commit, build date, licences, attributions, fonts), the keyboard shortcuts
//! (read only), and Report an Issue, which opens a local editable report draft.
//! The Help menu (the ? button on the application bar): About OneCAD (version, commit, build
//! date, licences, attributions, fonts) and the keyboard shortcuts (read only). OneBSpace
//! (OneCAD): upstream's Documentation link and GitHub issue reporting were removed —
//! everything stays inside the workspace.
use egui::{RichText, vec2};
@@ -10,15 +11,14 @@ use crate::theme::Tokens;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const COMMIT: &str = env!("SOLIDCRAFT_COMMIT");
pub const BUILD_DATE: &str = env!("SOLIDCRAFT_BUILD_DATE");
/// The user and developer guide (docs/book, published by .github/workflows/pages.yml).
pub const DOCS_URL: &str = "https://docs.solidcraft.io/";
// OneBSpace (OneCAD): upstream's docs.solidcraft.io DOCS_URL was removed.
const ATTRIBUTION: &str = include_str!("../../../ATTRIBUTION.md");
use solidcraft_engine::licences::{LICENSE_APACHE, LICENSE_MIT, NOTICE, THIRD_PARTY};
/// Fonts: what this build carries.
pub const FONTS: &str = "The interface uses egui's built-in fonts (Ubuntu Light and Hack, under the Ubuntu Font Licence and \
the MIT/Bitstream Vera licence; Noto Emoji and the emoji icon font, under the OFL and MIT). Sketch text uses Liberation Sans \
(SIL OFL 1.1). The Crafting Apps' optional font pack, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans \
CJK SC, Noto Sans Arabic; SIL OFL 1.1), is not bundled in SolidCraft builds.";
CJK SC, Noto Sans Arabic; SIL OFL 1.1), is not bundled in OneCAD builds.";
#[derive(Default)]
pub struct HelpState {
@@ -32,7 +32,7 @@ pub struct HelpState {
pub fn diagnostics(app: &SolveApp) -> String {
let renderer = if app.viewport.gpu.is_some() { "GPU" } else { "CPU" };
format!(
"SolidCraft {VERSION} ({COMMIT}, built {BUILD_DATE})\nOS: {} {}\nRenderer: {renderer}{}\nWindow: {}\nDesign: {} ({} features, {} bodies)",
"OneCAD {VERSION} ({COMMIT}, built {BUILD_DATE})\nOS: {} {}\nRenderer: {renderer}{}\nWindow: {}\nDesign: {} ({} features, {} bodies)",
std::env::consts::OS,
std::env::consts::ARCH,
app.help.gpu.as_ref().map(|g| format!(", {g}")).unwrap_or_default(),
@@ -43,11 +43,12 @@ pub fn diagnostics(app: &SolveApp) -> String {
)
}
/// Run a Help menu item: `docs`, `about`, `shortcuts`, `report`, `crashes`.
/// Run a Help menu item: `about`, `shortcuts`, `report`, `crashes`.
pub fn run(app: &mut SolveApp, ctx: &egui::Context, item: &str) {
app.help.menu = false;
match item {
"docs" => ctx.open_url(egui::OpenUrl::new_tab(DOCS_URL)),
// OneBSpace (OneCAD): upstream's `docs` item (docs.solidcraft.io) is gone. `report`
// stays: the app-bar bug button opens the LOCAL draft only (no GitHub anywhere).
"about" => app.help.about = true,
"shortcuts" => {
app.keymap.open = true;
@@ -71,10 +72,8 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context, anchor: egui::Pos2) {
crate::frame::area(egui::Id::new("sc_help_menu")).fixed_pos(anchor).constrain(true).order(egui::Order::Foreground).show(ctx, |ui| {
crate::context_menu::menu_frame(ui, |ui| {
for (id, label) in [
("docs", "Documentation"),
("about", "About SolidCraft"),
("about", "About OneCAD"),
("shortcuts", "Keyboard Shortcuts"),
("report", "Report an Issue…"),
("crashes", "Crash Reports…"),
] {
if crate::context_menu::list_row(ui, &crate::context_menu::Item::action(id, label, "")).is_some() {
@@ -103,14 +102,14 @@ fn about(app: &mut SolveApp, ctx: &egui::Context) {
}
let t = Tokens::get();
let mut open = true;
crate::frame::window(ctx, crate::i18n::tr_label("About SolidCraft"), crate::frame::Width::Normal)
crate::frame::window(ctx, crate::i18n::tr_label("About OneCAD"), crate::frame::Width::Normal)
.id(egui::Id::new("sc_about"))
.open(&mut open)
.default_size(vec2(440.0, 560.0))
.show(ctx, |ui| {
ui.label(RichText::new("SolidCraft").size(22.0).strong());
ui.label(RichText::new("OneCAD").size(22.0).strong());
ui.label(format!("Version {VERSION} · commit {COMMIT} · built {BUILD_DATE}"));
ui.label(RichText::new(crate::i18n::tr_label("Open-source parametric 3D CAD in Rust. Licensed MIT OR Apache-2.0.")).color(t.text_dim));
ui.label(RichText::new(crate::i18n::tr_label("Parametric 3D CAD of the One B OS workspace, in Rust. Licensed MIT OR Apache-2.0.")).color(t.text_dim));
ui.add_space(6.0);
ui.horizontal(|ui| {
if ui.button(crate::i18n::tr_label("Copy diagnostic information")).clicked() {
+4 -4
View File
@@ -356,7 +356,8 @@ pub fn show(app: &mut SolveApp, ui: &mut egui::Ui) {
egui::CentralPanel::default().frame(egui::Frame::NONE.fill(t.panel).inner_margin(egui::Margin::symmetric(36, 24))).show(ui, |ui| {
egui::ScrollArea::vertical().auto_shrink([false, false]).show(ui, |ui| {
ui.horizontal(|ui| {
ui.label(RichText::new("SolidCraft").size(26.0).strong().color(t.text));
// OneBSpace (OneCAD): our own name on the start page.
ui.label(RichText::new("OneCAD").size(26.0).strong().color(t.text));
ui.add_space(12.0);
ui.label(RichText::new(crate::i18n::tr_label("Start")).size(16.0).color(t.text_dim));
});
@@ -406,9 +407,8 @@ pub fn show(app: &mut SolveApp, ui: &mut egui::Ui) {
});
ui.add_space(24.0);
ui.horizontal_wrapped(|ui| {
ui.hyperlink_to(app.tr("home.documentation"), crate::help::DOCS_URL);
ui.hyperlink_to(app.tr("home.report_issue"), "https://github.com/tangency-labs/solidcraft/issues/new");
ui.hyperlink_to(app.tr("home.whats_new"), "https://github.com/bherbruck/solidcraft/releases/latest");
// OneBSpace (OneCAD): no outbound links here (upstream had Documentation,
// Report an Issue and What's New pointing at solidcraft.io / GitHub).
if ui.link(app.tr("ui.keyboard_shortcuts")).clicked() {
app.keymap.open = true;
app.keymap.read_only = true;
+23 -54
View File
@@ -298,8 +298,8 @@ pub fn crash_draft(report: &serde_json::Value) -> Draft {
let what = match report.get("kind").and_then(serde_json::Value::as_str) {
Some("command_panic") => "An internal error stopped a command (the design was left unchanged)",
Some("kernel_panic_recovered") => "The geometry kernel hit an internal error (caught; the operation failed)",
Some("unclean_exit") => "SolidCraft closed unexpectedly (abort, stack overflow, a crash in a graphics driver or the process was killed)",
_ => "SolidCraft hit an internal error",
Some("unclean_exit") => "OneCAD closed unexpectedly (abort, stack overflow, a crash in a graphics driver or the process was killed)",
_ => "OneCAD hit an internal error",
};
let command = report.get("command").and_then(|c| c.get("command")).and_then(serde_json::Value::as_str);
let frames: Vec<&str> =
@@ -336,7 +336,7 @@ pub fn crash_draft(report: &serde_json::Value) -> Draft {
},
s("id"),
block(&format!(
"SolidCraft {} ({}, built {})\nOS: {} {}\n{}",
"OneCAD {} ({}, built {})\nOS: {} {}\n{}",
field(app, "version"),
field(app, "commit"),
field(app, "built"),
@@ -379,6 +379,8 @@ fn encode(value: &str) -> String {
}
/// Long drafts stay local and can be copied into the browser editor; never discard them.
/// OneBSpace (OneCAD): no longer called by the UI (reports stay local); kept for tests.
#[cfg_attr(not(test), allow(dead_code))]
pub fn draft_url(title: &str, body: &str) -> (String, bool) {
let title = limited(title, 160);
let base = format!("{ISSUE_URL}?title={}", encode(&title));
@@ -492,7 +494,7 @@ pub(crate) fn receive(app: &mut SolveApp, token: u64, image: Arc<ColorImage>) {
draft.note = "Screenshot dimensions are unsupported. The text draft is still available.".into();
} else {
draft.image = Some(image);
draft.note = "Screenshot captured locally. Review it before attaching it on GitHub.".into();
draft.note = "Screenshot captured locally. Review it before sharing it.".into();
}
}
}
@@ -519,7 +521,7 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
// Only the editable report and evidence scroll. Keep the submission guide
// and actions visible even when a screenshot or long report needs more room.
egui::ScrollArea::vertical().id_salt("issue-report-review").max_height((screen.height() - 260.0).clamp(80.0, 520.0)).show(ui, |ui| {
ui.label(crate::i18n::tr_label("Review the report and screenshot before opening GitHub."));
ui.label(crate::i18n::tr_label("Review the report and screenshot before copying it out of the workspace."));
// TextEdit rounds its allocation to physical pixels. Leaving one pixel of
// room prevents that rounding from increasing the window width every frame
// at fractional display/UI scales (for example 140%).
@@ -560,7 +562,7 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
&& let Some(image) = draft.image.as_ref()
{
ctx.copy_image((**image).clone());
draft.note = "Paste the image into the GitHub draft, or save the PNG if image copying is unavailable.".into();
draft.note = "Paste the image into your own tracker, or save the PNG if image copying is unavailable.".into();
}
if ui.add_enabled(draft.image.is_some() && app.services.pick_save.is_some(), egui::Button::new("Save screenshot…")).clicked()
&& let Some(image) = draft.image.clone()
@@ -570,7 +572,7 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
let result = crate::control::save_screenshot(&image, Some(&path));
if let Some(draft) = app.issue_report.draft.as_mut() {
draft.note = if result.get("ok").and_then(serde_json::Value::as_bool) == Some(true) {
"Screenshot saved. Attach the PNG in the GitHub draft.".into()
"Screenshot saved. Attach the PNG wherever you share the report.".into()
} else {
format!("Could not save screenshot: {}", debug(&result.get("error"), 1000))
};
@@ -584,43 +586,13 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
}
});
ui.separator();
ui.label(RichText::new(crate::i18n::tr_label("Send your report on GitHub")).strong());
let (url, copy_needed) = draft_url(&draft.title, &draft.body);
ui.add(
egui::Label::new(crate::i18n::tr_label(if copy_needed {
"1. Open GitHub draft below, then paste the report copied to your clipboard."
} else {
"1. Open GitHub draft below. Your title and report will be filled in."
}))
.wrap(),
);
ui.add(egui::Label::new(crate::i18n::tr_label("2. Attach your screenshot: copy and paste it, or save and upload the PNG.")).wrap());
ui.add(egui::Label::new(crate::i18n::tr_label("3. Click Submit new issue on GitHub to send your report.")).wrap());
// OneBSpace (OneCAD): the report never leaves the workspace — no GitHub, no
// external site. Copy the text (and the screenshot above) into your own tracker.
ui.label(RichText::new(crate::i18n::tr_label("Your report stays in the workspace")).strong());
ui.horizontal_wrapped(|ui| {
let t = crate::theme::Tokens::get();
if crate::frame::add_outlined(
ui,
egui::Button::new(RichText::new(crate::i18n::tr_label("Open GitHub draft")).strong().color(t.text))
.fill(t.accent_soft)
.stroke(egui::Stroke::new(1.0, t.accent)),
1.0,
)
.clicked()
{
if copy_needed {
ctx.copy_text(draft.body.clone());
}
ctx.open_url(egui::OpenUrl::new_tab(url));
draft.note = if copy_needed {
"Report copied. Paste into the GitHub draft, attach the screenshot, then click Submit new issue on GitHub."
} else {
"Review the GitHub draft and attach the screenshot. GitHub's Submit new issue button publishes it."
}
.into();
}
if ui.button(crate::i18n::tr_label("Copy report")).clicked() {
ctx.copy_text(draft.body.clone());
draft.note = "Report copied. Paste it into the GitHub draft if needed.".into();
ctx.copy_text(format!("{}\n\n{}", draft.title, draft.body));
draft.note = "Report copied to the clipboard — paste it into your own issue tracker.".into();
}
close = ui.button(crate::i18n::tr_label("Close draft")).clicked();
});
@@ -764,7 +736,7 @@ mod tests {
}
#[test]
fn issue_report_long_draft_open_click_copies_the_full_reviewed_text() {
fn issue_report_copy_click_copies_the_full_reviewed_text() {
let mut h = crate::scenario::Harness::new();
h.app.home.open = false;
let mut draft = draft_for(&h.app, None, None);
@@ -772,9 +744,8 @@ mod tests {
let reviewed = draft.body.clone();
h.app.issue_report.draft = Some(draft);
h.frames(4);
assert!(h.widget("1. Open GitHub draft below, then paste the report copied to your clipboard.").is_some());
assert!(h.widget("3. Click Submit new issue on GitHub to send your report.").is_some());
let [x, y] = h.widget("Open GitHub draft").unwrap();
assert!(h.widget("Your report stays in the workspace").is_some());
let [x, y] = h.widget("Copy report").unwrap();
assert_eq!(h.call("ui.move", json!({"x":x,"y":y}))["ok"], true);
let (request, _reply) = crate::control::ControlRequest::new("ui.click", json!({"x":x,"y":y}));
assert!(matches!(crate::control::handle(&mut h.app, &h.ctx, &request), crate::control::Outcome::Done(value) if value["ok"] == true));
@@ -783,13 +754,11 @@ mod tests {
h.frame();
commands.extend(h.output.commands.clone());
}
assert!(commands.iter().any(|c| matches!(c, egui::OutputCommand::CopyText(text) if text == &reviewed)), "commands: {commands:?}");
assert!(
commands.iter().any(|c| matches!(c, egui::OutputCommand::OpenUrl(url) if url.url.starts_with(ISSUE_URL) && !url.url.contains("&body=")))
);
assert!(commands.iter().any(|c| matches!(c, egui::OutputCommand::CopyText(text) if text.contains(&reviewed))), "commands: {commands:?}");
assert_eq!(h.app.issue_report.draft.as_ref().unwrap().body, reviewed);
assert!(h.app.issue_report.draft.as_ref().unwrap().note.starts_with("Report copied. Paste into the GitHub draft"));
assert!(h.app.issue_report.draft.as_ref().unwrap().note.contains("Submit new issue"));
assert!(h.app.issue_report.draft.as_ref().unwrap().note.contains("clipboard"));
// OneBSpace (OneCAD): nothing here opens an external site any more.
assert!(!commands.iter().any(|c| matches!(c, egui::OutputCommand::OpenUrl(_))));
}
#[test]
@@ -801,7 +770,7 @@ mod tests {
h.app.home.open = false;
h.call("ui.resize", json!({"width":size[0],"height":size[1]}));
let mut draft = draft_for(&h.app, None, None);
draft.note = "Screenshot captured locally. Review it before attaching it on GitHub.".into();
draft.note = "Screenshot captured locally. Review it before sharing it.".into();
draft.image = Some(Arc::new(ColorImage::new([1600, 1000], vec![egui::Color32::GREEN; 1_600_000])));
h.app.issue_report.draft = Some(draft);
h.frames(20);
@@ -812,7 +781,7 @@ mod tests {
assert!((idle.width() - settled.width()).abs() < 1.0, "size={size:?}: {settled:?} grew to {idle:?}");
assert!(idle.width() <= 790.0, "report must retain its width limit: {idle:?}");
assert!(h.ctx.content_rect().contains_rect(idle), "size={size:?} scale={scale}: window must fit: {idle:?}");
for label in ["Copy screenshot", "Save screenshot…", "Open GitHub draft", "Copy report", "Close draft"] {
for label in ["Copy screenshot", "Save screenshot…", "Copy report", "Close draft"] {
let [x, y] = h.widget(label).unwrap();
assert!(idle.contains(egui::pos2(x as f32, y as f32)), "{label} must stay visible: {idle:?}, {x}, {y}");
}
+2 -2
View File
@@ -138,7 +138,7 @@ fn sketch_tool_for(app: &SolveApp, key: &str) -> Option<&'static str> {
pub fn bind(app: &mut SolveApp, id: &str, key: &str, replace: bool) -> Result<(), String> {
let spec = solidcraft_engine::find_command(id).ok_or_else(|| format!("no command `{id}`"))?;
if RESERVED.contains(&key) {
return Err(format!("{key} is used by SolidCraft itself"));
return Err(format!("{key} is used by OneCAD itself"));
}
if !key.is_empty() {
let others: Vec<&'static str> = commands_for(app, key).into_iter().filter(|o| *o != id).collect();
@@ -287,7 +287,7 @@ pub fn page(app: &mut SolveApp, ui: &mut egui::Ui) {
Some((_, "reset_all")) => reset(app, None),
Some((_, "export")) => {
let text = crate::toolbar_custom::export(app).to_string();
app.pick_save("SolidCraft shortcuts.json", &["json"], move |app, path| {
app.pick_save("OneCAD shortcuts.json", &["json"], move |app, path| {
if let Some(path) = path {
app.keymap.message = std::fs::write(&path, text).err().map(|e| format!("export: {e}"));
}
+1 -1
View File
@@ -63,7 +63,7 @@ pub fn show(app: &mut SolveApp, ctx: &egui::Context) {
.min_width(420.0)
.anchor(egui::Align2::CENTER_CENTER, egui::vec2(0.0, 0.0))
.show(ctx, |ui| {
ui.label(crate::i18n::tr_label("SolidCraft closed before these designs were saved. Their last autosave can be opened."));
ui.label(crate::i18n::tr_label("OneCAD closed before these designs were saved. Their last autosave can be opened."));
ui.add_space(6.0);
for e in app.recoverable.iter().take(20) {
ui.label(RichText::new(&e.name).strong());
+5 -11
View File
@@ -295,16 +295,10 @@ pub fn app_bar(app: &mut SolveApp, ui: &mut egui::Ui) {
let left = r.left() + if app.integrated_titlebar { crate::titlebar::TRAFFIC_LIGHTS } else { 0.0 };
// Keep the current header controls and product name when merging the new mark.
let compact_actions = r.right() - left < 640.0;
// Brand mark: the SolidCraft logo, drawn in code from the SVG's own coordinates
// (viewBox 357 x 412). Same 20 px height and centre as the old block.
{
let c = pos2(left + 20.0, r.center().y);
crate::icons::glyphs::brand_mark(ui.painter(), c);
}
if !compact_actions {
ui.painter().text(pos2(left + 36.0, r.center().y), Align2::LEFT_CENTER, "SolidCraft", FontId::proportional(14.0), t.app_bar_text);
}
let mut x = left + if compact_actions { 60.0 } else { 128.0 };
// OneBSpace (OneCAD): the wordmark replaces the upstream mark; the name shows in the
// compact layout too (a narrow bar loses the menus, not the app's own name).
ui.painter().text(pos2(left + 20.0, r.center().y), Align2::LEFT_CENTER, "OneCAD", FontId::proportional(14.0), t.app_bar_text);
let mut x = left + if compact_actions { 82.0 } else { 92.0 };
// While a file loads the design waits: no menus or commands from the bar.
let idle = !app.file_load.busy();
// The File menu: a text button (New, Open, Save, Save As, Export…). Its handle keeps the
@@ -412,7 +406,7 @@ pub fn app_bar(app: &mut SolveApp, ui: &mut egui::Ui) {
if report_label {
ui.painter().text(pos2(report.left() + REPORT_TEXT_X, report.center().y), Align2::LEFT_CENTER, report_text, report_font, t.app_bar_text);
}
if response.on_hover_text(crate::i18n::tr_label("Report a bug — review a screenshot and open a GitHub draft")).clicked() {
if response.on_hover_text(crate::i18n::tr_label("Report a bug — capture a screenshot and diagnostics to copy")).clicked() {
crate::help::run(app, &ui.ctx().clone(), "report");
}
// Preferences, at the top right like Fusion's profile menu (also Ctrl+,).
+1 -1
View File
@@ -203,7 +203,7 @@ pub fn export(app: &SolveApp) -> Value {
pub fn import(app: &mut SolveApp, v: &Value) -> Result<(), String> {
// "solvecraft-shortcuts/1": files exported before the rename (compatibility shim).
if !matches!(v.get("format").and_then(Value::as_str), Some("solidcraft-shortcuts/1" | "solvecraft-shortcuts/1")) {
return Err("not a SolidCraft shortcuts file".into());
return Err("not a OneCAD shortcuts file".into());
}
if let Some(s) = v.get("shortcuts") {
app.keymap.load(s);