[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:
1 parent
ac05e26934
commit
a824c1eb75
33 files changed
+472
-461
No files matched your search
@@ -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},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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 => {}
|
||||
}
|
||||
|
||||
@@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
|
||||
@@ -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}"));
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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+,).
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user