[IMP] OneBSpace rebrand of OpenCADStudio -> OneCAD Draft (wordmark, about, crash banner, 23 locales; strip SW/manifest; air-gap: update check, donations, discussions, external help links)

This commit is contained in:
Z User committed 2026-10-18 21:25:27 +00:00
1 parent c9e763006e
commit 193f2ae9ab
57 files changed
+760 -1091

No files matched your search

+1 -1
View File
@@ -114,7 +114,7 @@ fn route(path: &str, format: Option<usize>) -> Result<Route, String> {
.find(|f| f.extensions.iter().any(|e| e.eq_ignore_ascii_case(&ext)));
Err(match named.and_then(|f| unsupported_reason(f.support).map(|r| (f, r))) {
Some((f, reason)) => format!("{}: {reason}", f.name),
None => crate::t!("OpenCAD Studio has no importer for this format.").into_owned(),
None => crate::t!("OneCAD Draft has no importer for this format.") /* OneBSpace (OneCAD Draft): rebranded */.into_owned(),
})
}
+13 -55
View File
@@ -69,33 +69,15 @@ fn ensure_draw_order_table(doc: &mut codec::CadDocument, block: codec::Handle) -
impl OpenCADStudio {
pub(crate) fn dispatch_view(&mut self, cmd: &str, i: usize) -> Option<Task<Message>> {
match cmd {
"DONATE" => {
self.command_line
.push_info(crate::t!("Opening Patreon page...").as_ref());
return Some(crate::sys::open_url(
"https://patreon.com/HakanSeven12",
self.main_window,
));
}
// OneBSpace (OneCAD Draft): donations disabled — air-gapped build.
"DONATE" => Some(Task::none()),
"WEBVERSION" => {
self.command_line
.push_info(crate::t!("Opening OCS Web...").as_ref());
return Some(crate::sys::open_url(
"https://hakanseven12.github.io/OpenCADStudio/",
self.main_window,
));
}
// OneBSpace (OneCAD Draft): the upstream web-app link is gone.
"WEBVERSION" => Some(Task::none()),
"HELP" => {
self.command_line.push_info(
crate::t!("Opening OCS Discussions for help and questions...").as_ref(),
);
return Some(crate::sys::open_url(
"https://github.com/HakanSeven12/OpenCADStudio/discussions",
self.main_window,
));
}
// OneBSpace (OneCAD Draft): external help/discussions link removed —
// air-gapped build. Use the in-app help instead.
"HELP" => Some(Task::none()),
// ── DWGPROPS — print round-trip-only HeaderVariables ─────────
// No UI dialog for these yet; the command surfaces them so
@@ -317,28 +299,9 @@ impl OpenCADStudio {
}
}
"REPORT" => {
// Pre-fill the GitHub issue body with version + platform so
// reports arrive with the basics already filled in. The rule
// is `***`: text typed right above a `---` line turns into a
// Markdown heading.
let body = format!(
"<!-- Describe the issue and the steps to reproduce it. -->\n\n\n\
***\n- Open CAD Studio: v{}\n- Revision: {} ({}, {})\n- Platform: {}\n",
env!("OCS_FULL_VERSION"),
env!("OCS_GIT_REV"),
env!("OCS_COMMIT_DATE"),
env!("OCS_BUILD_PROFILE"),
crate::sys::platform_info(),
);
let url = format!(
"https://github.com/HakanSeven12/OpenCADStudio/issues/new?body={}",
crate::sys::percent_encode(&body)
);
self.command_line
.push_info(crate::t!("Opening feedback page...").as_ref());
return Some(crate::sys::open_url(&url, self.main_window));
}
// OneBSpace (OneCAD Draft): the upstream GitHub issue tracker is
// unreachable from an air-gapped build; feedback is a no-op.
"REPORT" => Some(Task::none()),
"ABOUT" => {
return Some(Task::done(Message::AboutOpen));
@@ -348,14 +311,9 @@ impl OpenCADStudio {
return Some(Task::done(Message::PluginManagerOpen));
}
"CHANGELOG" => {
self.command_line
.push_info(crate::t!("Opening release notes...").as_ref());
return Some(crate::sys::open_url(
"https://github.com/HakanSeven12/OpenCADStudio/releases",
self.main_window,
));
}
// OneBSpace (OneCAD Draft): upstream release notes are unreachable
// from an air-gapped build.
"CHANGELOG" => Some(Task::none()),
// ── ALIASEDIT — command-alias editor ───────────────────────────
// Opens the command-alias table editor (ocad.pgp). Keyboard
+18 -44
View File
@@ -5469,54 +5469,26 @@ impl OpenCADStudio {
)
};
s.queue_startup_prompts();
// Fetch the Patreon supporters list once at boot for the Start page.
#[cfg(not(target_arch = "wasm32"))]
let patrons_fetch = Task::perform(
async { crate::patreon::fetch_patrons() },
Message::PatronsFetched,
);
#[cfg(target_arch = "wasm32")]
// OneBSpace (OneCAD Draft): Patreon supporters fetch disabled — air-gapped
// build. The Start page supporters rail renders from the local list only.
let patrons_fetch = Task::none();
// Tutorial videos: show the on-disk cache instantly, refresh from the
// live playlist in the background. Nothing ships in the binary. The
// fetch runs on its own OS thread — its several sequential HTTP
// requests would otherwise sit on the async executor and hold up the
// rest of the boot tasks (the Start page waited on it).
// OneBSpace (OneCAD Draft): tutorial videos show the local on-disk
// cache only — no playlist refresh, no thumbnail downloads (air-gapped).
#[cfg(not(target_arch = "wasm32"))]
let videos_fetch = {
s.set_videos(crate::videos::load_cached());
s.videos_loading = true;
let (tx, rx) = iced::futures::channel::oneshot::channel();
std::thread::spawn(move || {
let _ = tx.send(crate::videos::fetch_playlist());
});
Task::perform(
async move {
rx.await
.unwrap_or_else(|_| Err("video fetch thread died".into()))
},
Message::VideosFetched,
)
s.videos_loading = false;
Task::none()
};
#[cfg(target_arch = "wasm32")]
let videos_fetch = Task::none();
// GitHub Discussions: seed from the last successful fetch, then refresh
// the public feed and pinned section on a background thread.
// OneBSpace (OneCAD Draft): GitHub Discussions refresh disabled —
// air-gapped build. The Start page lists the bundled discussions.json.
#[cfg(not(target_arch = "wasm32"))]
let discussions_fetch = {
s.discussions = crate::discussions::load_cached();
s.discussions_loading = true;
let (tx, rx) = iced::futures::channel::oneshot::channel();
std::thread::spawn(move || {
let _ = tx.send(crate::discussions::fetch_discussions());
});
Task::perform(
async move {
rx.await
.unwrap_or_else(|_| Err("discussion fetch thread died".into()))
},
Message::DiscussionsFetched,
)
s.discussions_loading = false;
Task::none()
};
#[cfg(target_arch = "wasm32")]
let discussions_fetch = Task::none();
@@ -5565,9 +5537,11 @@ impl OpenCADStudio {
Task::done(Message::PollWebFonts),
Task::done(Message::ApplyWebFont(primary_font)),
]);
// Web can't reach the Patreon API directly (CORS); fetch the CI-built
// supporters.json served on the same origin instead.
let patrons = Task::perform(crate::patreon::fetch_patrons_web(), Message::PatronsFetched);
// OneBSpace (OneCAD Draft): Patreon supporters fetch disabled — air-gapped
// build (no Patreon API, no supporters.json).
let patrons = Task::none();
// Videos/discussions read the LOCAL same-origin videos.json /
// discussions.json shipped next to the app; no remote endpoints.
s.videos_loading = true;
let videos = Task::perform(crate::videos::fetch_playlist_web(), Message::VideosFetched);
s.discussions_loading = true;
@@ -5662,13 +5636,13 @@ pub fn run() -> iced::Result {
let dot = if tab.dirty { "● " } else { "" };
let name = tab.tab_display_name();
format!(
"{}Open CAD Studio {} - {}",
"{}OneCAD Draft {} - {}", // OneBSpace (OneCAD Draft): rebranded wordmark
dot,
env!("OCS_APP_VERSION"),
name
)
} else {
concat!("Open CAD Studio ", env!("OCS_APP_VERSION")).to_string()
concat!("OneCAD Draft ", env!("OCS_APP_VERSION")).to_string() // OneBSpace (OneCAD Draft): rebranded wordmark
}
})
.theme(|state: &OpenCADStudio, _| state.active_theme.clone())
@@ -5714,7 +5688,7 @@ pub fn run_web() -> iced::Result {
)
.subscription(OpenCADStudio::subscription)
.title(|_state: &OpenCADStudio| {
concat!("Open CAD Studio ", env!("OCS_APP_VERSION")).to_string()
concat!("OneCAD Draft ", env!("OCS_APP_VERSION")).to_string() // OneBSpace (OneCAD Draft): rebranded wordmark
})
.theme(|state: &OpenCADStudio| state.active_theme.clone())
.backend(iced::Backend::Hardware(iced::backend::Api::OpenGL))
+25 -48
View File
@@ -8,16 +8,8 @@ impl OpenCADStudio {
self.pending_startup_modals
.push_back(ModalKind::AssocPrompt);
}
// Automation sessions (#1349): once control traffic has arrived (or a
// web host opted in at boot) while control is enabled, the donation
// prompt is suppressed — a modal would block every automated
// operation until a client closed it by hand.
if self.donation_prompt_version != env!("OCS_APP_VERSION")
&& !(self.control.enabled && self.control.automation_seen)
{
self.pending_startup_modals
.push_back(ModalKind::DonationPrompt);
}
// OneBSpace (OneCAD Draft): the donation prompt was removed —
// air-gapped build, no fundraising UI at startup.
self.show_next_startup_modal();
}
@@ -200,47 +192,32 @@ mod tests {
}
#[test]
fn donation_prompt_persists_once_per_version() {
fn donation_prompt_is_no_longer_queued() {
// OneBSpace (OneCAD Draft): the donation prompt was removed; startup
// must never queue it, regardless of the stored prompt version.
let mut app = OpenCADStudio::new_for_test();
// Older settings have no donation version; headless construction never prompts.
app.apply_config(serde_json::from_str::<AppConfig>("{}").unwrap());
assert!(app.active_modal.is_none());
assert!(app.pending_startup_modals.is_empty());
app.default_assoc_prompted = true;
app.queue_startup_prompts();
assert_eq!(app.active_modal, Some(ModalKind::DonationPrompt));
assert!(app.donation_prompt_version.is_empty());
let _ = app.update(Message::ModalContentResized(iced::Size::new(540.0, 280.0)));
let saved = serde_json::to_string(&app.current_config()).unwrap();
let _ = app.update(Message::CloseModal);
assert!(app.active_modal.is_none());
assert!(app.pending_startup_modals.is_empty());
let mut restarted = OpenCADStudio::new_for_test();
restarted.apply_config(serde_json::from_str(&saved).unwrap());
restarted.queue_startup_prompts();
assert_eq!(restarted.donation_prompt_version, env!("OCS_APP_VERSION"));
assert!(restarted.active_modal.is_none());
restarted.donation_prompt_version = "previous-release".to_string();
restarted.queue_startup_prompts();
assert_eq!(restarted.active_modal, Some(ModalKind::DonationPrompt));
let _ = restarted.update(Message::CommandEscape);
assert!(restarted.active_modal.is_none());
assert_eq!(restarted.donation_prompt_version, env!("OCS_APP_VERSION"));
let _ = restarted.update(Message::Noop);
assert!(restarted.active_modal.is_none());
app.donation_prompt_version = "previous-release".to_string();
app.queue_startup_prompts();
assert!(app.active_modal.is_none());
assert!(app.pending_startup_modals.is_empty());
}
#[test]
fn automation_sessions_skip_the_donation_prompt() {
fn automation_sessions_drop_queued_startup_prompts() {
// OneBSpace (OneCAD Draft): startup no longer queues the donation
// prompt; seed one manually to exercise the automation drop guard.
// First control contact drops a still-queued donation prompt and
// stops later queueing while control stays enabled (#1349).
let mut app = OpenCADStudio::new_for_test();
app.default_assoc_prompted = true;
app.queue_startup_prompts();
assert_eq!(app.active_modal, Some(ModalKind::DonationPrompt));
let _ = app.update(Message::CloseModal);
app.donation_prompt_version = "previous-release".to_string();
app.pending_startup_modals
.push_back(ModalKind::DonationPrompt);
@@ -248,6 +225,12 @@ mod tests {
assert!(app.pending_startup_modals.is_empty());
app.queue_startup_prompts();
assert_ne!(app.active_modal, Some(ModalKind::DonationPrompt));
app.pending_startup_modals
.push_back(ModalKind::DonationPrompt);
let _ = app.control_request(serde_json::json!({"op":"state"}));
assert!(app.pending_startup_modals.is_empty());
app.queue_startup_prompts();
assert_ne!(app.active_modal, Some(ModalKind::DonationPrompt));
// A still-queued (not yet shown) prompt is dropped on first contact.
let mut queued = OpenCADStudio::new_for_test();
@@ -261,11 +244,12 @@ mod tests {
assert_ne!(queued.active_modal, Some(ModalKind::DonationPrompt));
// A prompt already on screen is left for its reader; clients close
// it themselves, and a session with no control traffic still prompts.
// it themselves. OneBSpace (OneCAD Draft): with no control traffic a
// session never sees the donation prompt anymore.
let mut human = OpenCADStudio::new_for_test();
human.default_assoc_prompted = true;
human.queue_startup_prompts();
assert_eq!(human.active_modal, Some(ModalKind::DonationPrompt));
assert_ne!(human.active_modal, Some(ModalKind::DonationPrompt));
}
#[test]
@@ -282,16 +266,9 @@ mod tests {
)));
assert_eq!(app.active_modal, Some(ModalKind::AssocPrompt));
let _ = app.update(Message::AssocPromptNo);
assert_eq!(app.active_modal, Some(ModalKind::DonationPrompt));
// A file-recovery dialog may interrupt startup before the first frame.
app.active_modal = Some(ModalKind::Recovery);
let _ = app.update(Message::CloseModal);
assert_eq!(app.active_modal, Some(ModalKind::DonationPrompt));
assert!(app.donation_prompt_version.is_empty());
let _ = app.update(Message::ModalContentResized(iced::Size::new(540.0, 280.0)));
assert_eq!(app.donation_prompt_version, env!("OCS_APP_VERSION"));
let _ = app.update(Message::CloseModal);
// OneBSpace (OneCAD Draft): the donation prompt is gone; the update
// notice queued by the (manually delivered) check result still waits
// its turn behind the association prompt.
assert_eq!(app.active_modal, Some(ModalKind::UpdateNotice));
let _ = app.update(Message::UpdateNoticeClose);
assert!(app.active_modal.is_none());
+1 -1
View File
@@ -3649,7 +3649,7 @@ impl OpenCADStudio {
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| outcome.path.display().to_string());
self.command_line.push_error_once(
crate::tf!("Save stopped: \"{file_name}\" changed outside Open CAD Studio.")
crate::tf!("Save stopped: \"{file_name}\" changed outside OneCAD Draft.")
.as_ref(),
);
self.pending_external_change = Some(crate::app::PendingExternalChange {
+3 -2
View File
@@ -11003,9 +11003,10 @@ impl OpenCADStudio {
Task::none()
}
Message::DonationPromptDonate => {
// OneBSpace (OneCAD Draft): donations disabled — air-gapped
// build; the prompt is never queued, the button is inert.
self.close_active_modal();
self.dispatch_view("DONATE", self.active_tab)
.unwrap_or_else(Task::none)
Task::none()
}
Message::UpdateNoticeClose => {
self.close_active_modal();
+20 -206
View File
@@ -3669,7 +3669,7 @@ fn start_page_content<'a>(
action_width_out: std::sync::Arc<std::sync::atomic::AtomicU32>,
active: super::StartSection,
) -> Element<'a, Message> {
let headline = text("Open CAD Studio").size(40).style(start_primary_style);
let headline = text("OneCAD Draft").size(40).style(start_primary_style); // OneBSpace (OneCAD Draft): rebranded wordmark
// Plain outlined button (Open / New / Help / Contribute).
let outline_btn = |label: String, msg: Message| {
@@ -3695,23 +3695,8 @@ fn start_page_content<'a>(
})
};
// Donate — the prominent call-to-action, using the theme's danger role.
let donate_btn = {
button(
row![
crate::ui::icons::themed_danger_text(crate::ui::icons::HEART, 14.0),
text(crate::tr!("start", "donate")).size(14),
]
.spacing(5)
.align_y(iced::Center),
)
.on_press(Message::RibbonToolClick {
tool_id: "DONATE".to_string(),
event: crate::modules::ModuleEvent::Command("DONATE".to_string()),
})
.padding([10, 22])
.style(|theme: &Theme, status| start_action_shape(button::danger(theme, status)))
};
// OneBSpace (OneCAD Draft): the donation call-to-action was removed —
// air-gapped build, no external fundraising links.
let primary_row = WrapFlow::new(vec![
outline_btn(crate::tr!("start", "new-drawing"), Message::TabNew).into(),
@@ -3725,7 +3710,6 @@ fn start_page_content<'a>(
)
.into(),
outline_btn(crate::tr!("start", "open-file"), Message::OpenFile).into(),
donate_btn.into(),
])
.spacing_x(12.0)
.row_h(48.0)
@@ -3745,90 +3729,15 @@ fn start_page_content<'a>(
];
secondary_items
.push(outline_btn(crate::tr!("action", "plugins"), Message::PluginManagerOpen).into());
// The web build is already in the browser, so only the desktop offers a
// link to the web version.
#[cfg(not(target_arch = "wasm32"))]
{
// Filled with the active theme's primary colour.
secondary_items.push(
button(text(crate::t!("OCS Web")).size(14))
.on_press(Message::RibbonToolClick {
tool_id: "WEBVERSION".to_string(),
event: crate::modules::ModuleEvent::Command("WEBVERSION".to_string()),
})
.padding([10, 22])
.style(|theme: &Theme, status| start_action_shape(button::primary(theme, status)))
.into(),
);
}
#[cfg(target_arch = "wasm32")]
secondary_items.push(
button(text(crate::t!("OCS Desktop")).size(14))
.on_press(Message::OpenUrl(
"https://github.com/HakanSeven12/OpenCADStudio/releases/latest".to_string(),
))
.padding([10, 22])
.style(|theme: &Theme, status| start_action_shape(button::primary(theme, status)))
.into(),
);
// OneBSpace (OneCAD Draft): the "OCS Web" / "OCS Desktop" cross-promotion
// buttons were removed — no external download or website links.
let secondary_row = WrapFlow::new(secondary_items)
.spacing_x(12.0)
.row_h(44.0)
.report_natural_width(action_width_out.clone());
let reddit_btn = button(
row![
iced::widget::svg(iced::widget::svg::Handle::from_memory(include_bytes!(
"../../../assets/icons/reddit.svg"
)))
.width(20)
.height(20),
text("r/OpenCADStudio").size(14),
]
.spacing(7)
.align_y(iced::Center),
)
.on_press(Message::OpenUrl(
"https://www.reddit.com/r/OpenCADStudio/".to_string(),
))
.padding([10, 22])
.style(|theme: &Theme, status| {
let palette = theme.palette();
let pair = match status {
button::Status::Hovered => palette.background.strong,
_ => palette.background.weak,
};
start_action_shape(button::Style {
background: Some(Background::Color(pair.color)),
text_color: pair.text,
border: Border {
color: Color::from_rgb8(255, 69, 0),
width: 1.0,
..Default::default()
},
..Default::default()
})
});
let sponsors = column![
text(crate::tr!("start", "sponsors")).size(15),
mouse_area(
container(
iced::widget::svg(iced::widget::svg::Handle::from_memory(include_bytes!(
"../../../assets/sponsors/openaec-logo-dark-on-light.svg"
)))
.width(Fill)
.height(iced::Length::Fixed(120.0))
.content_fit(iced::ContentFit::Contain),
)
.width(Fill.max(300.0)),
)
.interaction(iced::mouse::Interaction::Pointer)
.on_press(Message::OpenUrl("https://open-aec.com/".to_string())),
]
.spacing(10)
.align_x(iced::alignment::Horizontal::Center)
.width(Fill);
// OneBSpace (OneCAD Draft): the community Reddit link and the Open-AEC
// sponsor block were removed — no external links in the Start page.
let content = column![
Space::new().height(iced::Length::Fixed(28.0)),
@@ -3837,10 +3746,6 @@ fn start_page_content<'a>(
container(primary_row).center_x(Fill),
Space::new().height(iced::Length::Fixed(10.0)),
container(secondary_row).center_x(Fill),
Space::new().height(iced::Length::Fixed(10.0)),
container(reddit_btn).center_x(Fill),
Space::new().height(iced::Length::Fixed(20.0)),
sponsors,
Space::new().height(iced::Length::Fixed(52.0)),
]
.spacing(0)
@@ -3908,8 +3813,9 @@ fn start_page_content<'a>(
);
let welcome = container(content).width(Fill).height(Fill);
// Tutorial-videos rail: the official playlist, fetched at boot (cached on
// disk) — thumbnail card + title per video, click opens the browser.
// Tutorial-videos rail: local listing only (cached on disk / bundled
// videos.json) — thumbnail card + title per video; OneBSpace (OneCAD
// Draft): no click-through, cards are informational (air-gapped build).
let videos_panel: Element<'a, Message> = {
// Derive the 16:9 cover box from the actual shared list width so the
// whole thumbnail remains visible when that width changes.
@@ -3946,11 +3852,9 @@ fn start_page_content<'a>(
);
}
card = card.push(text(v.title.clone()).size(12).style(start_muted_style));
list = list.push(
mouse_area(card)
.interaction(iced::mouse::Interaction::Pointer)
.on_press(Message::OpenUrl(crate::videos::watch_url(&v.id))),
);
// OneBSpace (OneCAD Draft): cards are informational only — no
// click-through to YouTube (air-gapped build).
list = list.push(card);
}
if videos.is_empty() {
let note = if videos_loading {
@@ -3960,32 +3864,7 @@ fn start_page_content<'a>(
};
list = list.push(text(note).size(12).style(start_muted_style));
}
let playlist_btn = mouse_area(
container(text(crate::tr!("start", "open-playlist")).size(12))
.padding([6, 10])
.width(Fill)
.center_x(Fill)
.style(|theme: &Theme| {
let pair = theme.palette().danger.base;
container::Style {
background: Some(Background::Color(pair.color)),
border: Border {
color: Color::TRANSPARENT,
width: 0.0,
radius: 6.0.into(),
},
text_color: Some(pair.text),
..Default::default()
}
}),
)
.interaction(iced::mouse::Interaction::Pointer)
.on_press(Message::OpenUrl(crate::videos::PLAYLIST_URL.to_string()));
container(column![
iced::widget::scrollable(list).height(Fill),
Space::new().height(iced::Length::Fixed(12.0)),
playlist_btn,
])
container(column![iced::widget::scrollable(list).height(Fill)])
.width(match start_layout {
StartLayout::AllPanels => iced::Length::Fixed(panel_w),
StartLayout::WithoutVideos
@@ -4055,11 +3934,7 @@ fn start_page_content<'a>(
..Default::default()
}
});
list = list.push(
mouse_area(card)
.interaction(iced::mouse::Interaction::Pointer)
.on_press(Message::OpenUrl(discussion.url.clone())),
);
list = list.push(card);
}
if discussions.is_empty() {
let note = if discussions_loading {
@@ -4069,34 +3944,7 @@ fn start_page_content<'a>(
};
list = list.push(text(note).size(12).style(start_muted_style));
}
let open_btn = mouse_area(
container(text(crate::tr!("start", "open-discussions")).size(12))
.padding([6, 10])
.width(Fill)
.center_x(Fill)
.style(|theme: &Theme| {
let pair = theme.palette().primary.base;
container::Style {
background: Some(Background::Color(pair.color)),
border: Border {
color: Color::TRANSPARENT,
width: 0.0,
radius: 6.0.into(),
},
text_color: Some(pair.text),
..Default::default()
}
}),
)
.interaction(iced::mouse::Interaction::Pointer)
.on_press(Message::OpenUrl(
crate::discussions::DISCUSSIONS_URL.to_string(),
));
container(column![
iced::widget::scrollable(list).height(Fill),
Space::new().height(iced::Length::Fixed(12.0)),
open_btn,
])
container(column![iced::widget::scrollable(list).height(Fill)])
.width(match start_layout {
StartLayout::AllPanels | StartLayout::WithoutVideos => iced::Length::Fixed(panel_w),
StartLayout::WithoutVideosAndDiscussions
@@ -4120,9 +3968,9 @@ fn start_page_content<'a>(
.into()
};
// Right rail: Patreon supporters, fetched at boot. When the list is empty
// (no token configured / offline) only the "Support on Patreon" button
// shows, so the rail always invites support.
// OneBSpace (OneCAD Draft): right rail shows the local supporters list
// only — the Patreon fetch and the "Support on Patreon" button were
// removed (air-gapped build, no external links).
let supporters: Element<'a, Message> = {
let mut list = column![
text(crate::tr!("start", "supporters")).size(15),
@@ -4146,41 +3994,7 @@ fn start_page_content<'a>(
.spacing(6),
);
}
let support_btn = mouse_area(
container(
iced::widget::row![
crate::ui::icons::themed_danger_text(crate::ui::icons::HEART, 13.0),
text(crate::tr!("start", "support-on-patreon")).size(12),
]
.spacing(6)
.align_y(iced::Center),
)
.padding([6, 10])
.width(Fill)
.center_x(Fill)
.style(|theme: &Theme| {
let pair = theme.palette().danger.base;
container::Style {
background: Some(Background::Color(pair.color)),
border: Border {
color: Color::TRANSPARENT,
width: 0.0,
radius: 6.0.into(),
},
text_color: Some(pair.text),
..Default::default()
}
}),
)
.interaction(iced::mouse::Interaction::Pointer)
.on_press(Message::OpenUrl(
"https://patreon.com/HakanSeven12".to_string(),
));
container(column![
iced::widget::scrollable(list).height(Fill),
Space::new().height(iced::Length::Fixed(12.0)),
support_btn,
])
container(column![iced::widget::scrollable(list).height(Fill)])
.width(match start_layout {
StartLayout::AllPanels
| StartLayout::WithoutVideos
+2 -2
View File
@@ -2589,10 +2589,10 @@ fn donation_dialog_window(sizing: crate::ui::modal::ModalSizing) -> Element<'sta
fn default_assoc_dialog_window(sizing: crate::ui::modal::ModalSizing) -> Element<'static, Message> {
container(
column![
text(t!("Make Open CAD Studio your default CAD app?"))
text(t!("Make OneCAD Draft your default CAD app?")) /* OneBSpace (OneCAD Draft): rebranded */
.size(15),
iced::widget::Space::new().height(10),
text(t!("Open .dwg and .dxf drawings in Open CAD Studio by default. You can change this later in your system settings."))
text(t!("Open .dwg and .dxf drawings in OneCAD Draft by default. You can change this later in your system settings.")) /* OneBSpace (OneCAD Draft): rebranded */
.size(12)
.style(dialog_muted_text_style),
iced::widget::Space::new().height(22),
+1 -1
View File
@@ -28,7 +28,7 @@ use clap::Parser;
"\nprofile: ", env!("OCS_BUILD_PROFILE"),
"\nfeatures: ", env!("OCS_BUILD_FEATURES"),
),
about = crate::t!("Open CAD Studio — 2D/3D CAD editor").into_owned(),
about = crate::t!("OneCAD Draft — 2D/3D CAD editor") /* OneBSpace (OneCAD Draft): rebranded */.into_owned(),
long_about = None,
)]
pub struct Cli {
+2 -2
View File
@@ -348,7 +348,7 @@ impl Commands {
fn new(actions: &[Action]) -> Self {
let mut strings = vec![
CString::new("Default").unwrap(),
CString::new("Open CAD Studio").unwrap(),
CString::new("OneCAD Draft").unwrap(), // OneBSpace (OneCAD Draft): rebranded
CString::new("").unwrap(),
];
let mut nodes = vec![Node {
@@ -493,7 +493,7 @@ impl Connection {
let result = unsafe {
(api.create)(
&mut handle,
c"Open CAD Studio".as_ptr(),
c"OneCAD Draft".as_ptr(), // OneBSpace (OneCAD Draft): rebranded
accessors.as_ptr(),
accessors.len(),
&options,
+1 -1
View File
@@ -248,7 +248,7 @@ mod windows_impl {
.spawn()
.ok()?;
Some(
"Opened Settings → Default apps — choose Open CAD Studio for .dwg / .dxf there."
"Opened Settings → Default apps — choose OneCAD Draft for .dwg / .dxf there." // OneBSpace (OneCAD Draft): rebranded
.to_string(),
)
}
+12
View File
@@ -138,8 +138,18 @@ pub fn local_font_file(name: &str) -> Option<PathBuf> {
}
/// List the community folder through the GitHub contents API.
/// OneBSpace (OneCAD Draft): the upstream community font repository is
/// disabled — air-gapped build; the GitHub fetch is kept below for reference
/// but never runs. Custom (user-configured) font folders still work.
#[cfg(not(target_arch = "wasm32"))]
fn fetch_repo_fonts() -> Result<Vec<RepoFont>, String> {
let _ = REPO_API_URL;
Err("the built-in font repository is disabled in this air-gapped build; configure a custom font folder instead".to_string())
}
#[cfg(not(target_arch = "wasm32"))]
#[allow(dead_code)]
fn fetch_repo_fonts_github() -> Result<Vec<RepoFont>, String> {
let agent = crate::network::agent(std::time::Duration::from_secs(15));
let mut response = agent
.get(REPO_API_URL)
@@ -159,7 +169,9 @@ fn fetch_repo_fonts() -> Result<Vec<RepoFont>, String> {
/// Parse the GitHub contents-API response:
/// `[{"name":"romans.shx","download_url":"https://…"}, …]`.
/// OneBSpace (OneCAD Draft): only used by the disabled GitHub fetch + tests.
#[cfg(not(target_arch = "wasm32"))]
#[allow(dead_code)]
fn parse_contents(body: &str) -> Result<Vec<RepoFont>, String> {
let value: serde_json::Value =
serde_json::from_str(body).map_err(|e| format!("Unexpected font listing: {e}"))?;
+3 -3
View File
@@ -211,7 +211,7 @@ pub fn build_step(meshes: &[&MeshModel]) -> Option<String> {
let msb_id = alloc();
writeln!(
data,
"#{} = MANIFOLD_SOLID_BREP('OpenCADStudio_Solid',#{});",
"#{} = MANIFOLD_SOLID_BREP('OneCAD_Draft_Solid',#{});",
msb_id, shell_id
)
.ok();
@@ -229,7 +229,7 @@ pub fn build_step(meshes: &[&MeshModel]) -> Option<String> {
writeln!(data, "#{} = GEOMETRIC_REPRESENTATION_CONTEXT(3);", gc_id).ok();
writeln!(
data,
"#{sr_id} = SHAPE_REPRESENTATION('OpenCADStudio_Shape',(#{}),#{gc_id});",
"#{sr_id} = SHAPE_REPRESENTATION('OneCAD_Draft_Shape',(#{}),#{gc_id});",
msb_id
)
.ok();
@@ -239,7 +239,7 @@ pub fn build_step(meshes: &[&MeshModel]) -> Option<String> {
let file = format!(
"ISO-10303-21;\n\
HEADER;\n\
FILE_DESCRIPTION(('Open CAD Studio STEP export'),'2;1');\n\
FILE_DESCRIPTION(('OneCAD Draft STEP export'),'2;1');\n\
FILE_NAME('{ts}','','',(''),'',' ',' ');\n\
FILE_SCHEMA(('CONFIG_CONTROL_DESIGN'));\n\
ENDSEC;\n\
+13 -5
View File
@@ -1,12 +1,17 @@
// Check for a newer published native release.
/// Check for a newer published native release.
/// OneBSpace (OneCAD Draft): update check disabled — air-gapped build. The
/// upstream GitHub-releases probe below is kept for reference but never runs;
/// no network call is ever made from this module.
#[cfg(not(target_arch = "wasm32"))]
#[allow(dead_code)]
const RELEASES_API: &str =
"https://api.github.com/repos/HakanSeven12/OpenCADStudio/releases/latest";
pub const RELEASES_PAGE: &str = "https://github.com/HakanSeven12/OpenCADStudio/releases/latest";
/// Give release assets time to propagate before offering an update.
#[cfg(not(target_arch = "wasm32"))]
#[allow(dead_code)]
const MIN_RELEASE_AGE_SECS: u64 = 60 * 60;
/// What `check_for_update` reports when a newer release exists.
@@ -21,14 +26,14 @@ pub struct UpdateInfo {
#[cfg(not(target_arch = "wasm32"))]
pub async fn check_for_update() -> Option<UpdateInfo> {
std::thread::spawn(fetch_latest_if_outdated)
.join()
.ok()
.flatten()
// OneBSpace (OneCAD Draft): update check disabled — air-gapped build.
// Earliest return: no thread is spawned, no HTTP request is made.
None
}
/// On wasm there is no background thread or blocking HTTP client; the web build
/// skips the self-update check (the page is always served fresh).
/// OneBSpace (OneCAD Draft): disabled on every platform — air-gapped build.
#[cfg(target_arch = "wasm32")]
#[allow(dead_code)]
pub async fn check_for_update() -> Option<UpdateInfo> {
@@ -36,6 +41,7 @@ pub async fn check_for_update() -> Option<UpdateInfo> {
}
#[cfg(not(target_arch = "wasm32"))]
#[allow(dead_code)]
fn fetch_latest_if_outdated() -> Option<UpdateInfo> {
let agent = crate::network::agent(std::time::Duration::from_secs(5));
let body = agent
@@ -110,6 +116,7 @@ fn fetch_latest_if_outdated() -> Option<UpdateInfo> {
/// Only handles the fixed `YYYY-MM-DDTHH:MM:SSZ` format the GitHub API
/// emits; returns `None` for anything else.
#[cfg(not(target_arch = "wasm32"))]
#[allow(dead_code)]
fn parse_iso8601_utc(s: &str) -> Option<u64> {
let b = s.as_bytes();
if b.len() != 20
@@ -155,6 +162,7 @@ fn parse_iso8601_utc(s: &str) -> Option<u64> {
}
#[cfg(not(target_arch = "wasm32"))]
#[allow(dead_code)]
fn is_newer(latest: &str, installed: &str) -> bool {
let parse = |version: &str| {
let version = version.trim_start_matches('v');
+12 -12
View File
@@ -71,7 +71,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Download available" => Some(("modal", "missing-fonts-download-available")),
"Skip" => Some(("modal", "missing-fonts-skip")),
"Missing fonts" => Some(("modal", "missing-fonts-title")),
"This drawing uses fonts that are not installed on this machine. OpenCADStudio can download any redistributable fonts that exist in the selected repository; unavailable fonts will keep using a substitute." => Some(("modal", "missing-fonts-description")),
"This drawing uses fonts that are not installed on this machine. OneCAD Draft can download any redistributable fonts that exist in the selected repository; unavailable fonts will keep using a substitute." => Some(("modal", "missing-fonts-description")),
"Font source — leave empty for the community repository, or point at any folder (e.g. your company's font server):" => Some(("modal", "missing-fonts-source")),
"https://server/fonts or a GitHub raw folder" => Some(("modal", "missing-fonts-source-placeholder")),
"Coincident" => Some(("common", "parametric-coincident")),
@@ -89,7 +89,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"No sketch open" => Some(("ui", "window-no-sketch-open")),
"Bodies ({})" => Some(("ui", "window-bodies")),
"No solids yet" => Some(("ui", "window-no-solids-yet")),
"Saved immediately. Changes take effect the next time Open CAD Studio starts." => Some(("ui", "window-saved-immediately-changes-take-effect-the-next-t")),
"Saved immediately. Changes take effect the next time OneCAD Draft starts." => Some(("ui", "window-saved-immediately-changes-take-effect-the-next-t")),
"This session" => Some(("ui", "window-this-session")),
"Driver" => Some(("ui", "window-driver")),
"Backend" => Some(("ui", "window-backend")),
@@ -109,7 +109,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Connection details" => Some(("ui", "window-connection-details")),
"{:.1}% a notch" => Some(("ui", "window-1-a-notch")),
"The slider covers the system variable's {} to {}; the field takes up to {} for a faster wheel." => Some(("ui", "window-the-slider-covers-the-system-variable-s-to-the-f")),
"Bundled with Open CAD Studio" => Some(("ui", "window-bundled-with-open-cad-studio")),
"Bundled with OneCAD Draft" => Some(("ui", "window-bundled-with-open-cad-studio")), /* OneBSpace (OneCAD Draft): literal rebranded, ftl key unchanged */
"How the Reference Manager works on web" => Some(("ui", "window-how-the-reference-manager-works-on-web")),
"This panel lists the drawing's references read-only: status, type, size, date and saved path, plus the Details pane. Select rows to inspect them; List and Tree switch the presentation." => Some(("ui", "window-this-panel-lists-the-drawing-s-references-read-o")),
"Attach, Refresh and Change Path stay disabled here: the web build has no filesystem access and no native file pickers, so references can be neither added, reloaded nor repathed — and previews stay unavailable. Nested references are read-only on every platform, and relative paths need the drawing saved first." => Some(("ui", "window-attach-refresh-and-change-path-stay-disabled-her")),
@@ -608,7 +608,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"<none>" => Some(("plot", "none")),
"<previous>" => Some(("plot", "previous")),
"= {v}" => Some(("inquiry", "v")),
"A newer Open CAD Studio version is published on GitHub." => Some(("ui", "a-newer-open-cad-studio-version-is-published-o")),
"A newer OneCAD Draft version is published on GitHub." => Some(("ui", "a-newer-open-cad-studio-version-is-published-o")),
"AC Version" => Some(("properties", "ac-version")),
"ACI Color Index" => Some(("styles", "aci-color-index")),
"ACI:" => Some(("styles", "aci")),
@@ -2204,7 +2204,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Major axis vector Z" => Some(("properties", "major-axis-vector-z")),
"Major radius" => Some(("properties", "major-radius")),
"Make Current" => Some(("layers", "make-current")),
"Make Open CAD Studio your default CAD app?" => Some(("modal", "make-open-cad-studio-your-default-cad-app")),
"Make OneCAD Draft your default CAD app?" => Some(("modal", "make-open-cad-studio-your-default-cad-app")), /* OneBSpace (OneCAD Draft): literal rebranded, ftl key unchanged */
"Manage" => Some(("common", "manage")),
"Manage..." => Some(("ui", "manage-menu-period-title-case")),
"Manage…" => Some(("ui", "manage-picker-title-case")),
@@ -2414,8 +2414,8 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Opacity" => Some(("properties", "opacity")),
"Opacity Map" => Some(("properties", "opacity-map")),
"Open" => Some(("common", "open")),
"Open .dwg and .dxf drawings in Open CAD Studio by default. You can change this later in your system settings." => Some(("modal", "open-dwg-and-dxf-drawings-in-open-cad-studio-b")),
"Open CAD Studio could not trust the certificate presented for the plugin registry. Check your system certificate and proxy settings, then retry." => Some(("plugins", "open-cad-studio-could-not-trust-the-certificat")),
"Open .dwg and .dxf drawings in OneCAD Draft by default. You can change this later in your system settings." => Some(("modal", "open-dwg-and-dxf-drawings-in-open-cad-studio-b")), /* OneBSpace (OneCAD Draft): literal rebranded, ftl key unchanged */
"OneCAD Draft could not trust the certificate presented for the plugin registry. Check your system certificate and proxy settings, then retry." => Some(("plugins", "open-cad-studio-could-not-trust-the-certificat")),
"Open CAD Studio plugins are native packages and cannot run inside a browser. Download the desktop app to browse, install, and use plugins." => Some(("plugins", "open-cad-studio-plugins-are-native-packages-an")),
"Open CAD Studio ready." => Some(("file", "open-cad-studio-ready")),
"Open DWG/DXF: not yet implemented." => Some(("common", "open-dwg-dxf-not-yet-implemented")),
@@ -3024,7 +3024,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Save failed: {error}" => Some(("file", "save-failed-error")),
"Save failed: {e}" => Some(("file", "save-failed-e")),
"Save in source version" => Some(("common", "save-in-source-version")),
"Save stopped: \"{file_name}\" changed outside Open CAD Studio." => Some(("file", "save-stopped-file-name-changed-outside-open-ca")),
"Save stopped: \"{file_name}\" changed outside OneCAD Draft." => Some(("file", "save-stopped-file-name-changed-outside-open-ca")),
"Save the drawing before copying its file path." => Some(("common", "save-the-drawing-before-copying-its-file-path")),
"Save the drawing before opening its file location." => Some(("common", "save-the-drawing-before-opening-its-file-locat")),
"Save to PDF file…" => Some(("plot", "save-to-pdf-file")),
@@ -3477,7 +3477,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Unavailable" => Some(("plugins", "unavailable")),
"Supported" => Some(("dgn-import", "supported")),
"By extension" => Some(("dgn-import", "by-extension")),
"OpenCAD Studio has no importer for this format." => Some(("dgn-import", "no-importer")),
"OneCAD Draft has no importer for this format." => Some(("dgn-import", "no-importer")), /* OneBSpace (OneCAD Draft): literal rebranded, ftl key unchanged */
"Recent:" => Some(("dgn-import", "recent")),
"2D / Underlay" => Some(("dgn-import", "group-2d")),
"3D Model" => Some(("dgn-import", "group-3d")),
@@ -4510,7 +4510,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Include matching objects" => Some(("common", "include-matching-objects")),
"Exclude matching objects" => Some(("common", "exclude-matching-objects")),
"Append result to current selection" => Some(("common", "append-result-to-current-selection")),
"Open CAD Studio — 2D/3D CAD editor" => Some(("common", "open-cad-studio-2d-3d-cad-editor")),
"OneCAD Draft — 2D/3D CAD editor" => Some(("common", "open-cad-studio-2d-3d-cad-editor")), /* OneBSpace (OneCAD Draft): literal rebranded, ftl key unchanged */
"CAD files to open at startup (.dwg / .dxf)." => Some(("common", "cad-files-to-open-at-startup-dwg-dxf")),
"Start with a new empty drawing." => Some(("common", "start-with-a-new-empty-drawing")),
"Start a new editor process." => Some(("common", "start-a-new-editor-process")),
@@ -4987,7 +4987,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Base minor radius" => Some(("common", "base-minor-radius")),
"Top major radius" => Some(("common", "top-major-radius")),
"Top minor radius" => Some(("common", "top-minor-radius")),
"OpenCADStudio renderer error — copy this into a bug report:" => Some(("common", "opencadstudio-renderer-error-copy-this-into-a-bug-report")),
"OneCAD Draft renderer error — copy this into a bug report:" => Some(("common", "opencadstudio-renderer-error-copy-this-into-a-bug-report")), // OneBSpace (OneCAD Draft): literal rebranded, ftl key unchanged,
"Dismiss" => Some(("common", "dismiss")),
"?" => Some(("common", "value-8a8de8")),
"Select Color..." => Some(("common", "select-color-8dddf1")),
@@ -5070,7 +5070,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
"Translate from" => Some(("common", "translate-from")),
"Translate to" => Some(("common", "translate-to")),
"%{n} mapping(s)" => Some(("common", "mapping-s")),
"Open .dwg and .dxf files with Open CAD Studio" => Some(("common", "open-dwg-and-dxf-files-with-open-cad-studio")),
"Open .dwg and .dxf files with OneCAD Draft" => Some(("common", "open-dwg-and-dxf-files-with-open-cad-studio")), /* OneBSpace (OneCAD Draft): literal rebranded, ftl key unchanged */
"Also installs the application and file-type icons the desktop shows." => Some(("common", "also-installs-the-application-and-file-type-icons-the-desktop-shows")),
"Model Space Appearance" => Some(("common", "model-space-appearance")),
"Restore Defaults" => Some(("common", "restore-defaults")),
+1 -1
View File
@@ -944,7 +944,7 @@ fn sessions(launch_if_none: bool) -> Result<Vec<Value>, String> {
if claimed {
release_startup_lock(&directory);
}
return Err(format!("OpenCADStudio exited while starting ({status})"));
return Err(format!("OneCAD Draft exited while starting ({status})" /* OneBSpace (OneCAD Draft): rebranded */));
}
}
thread::sleep(Duration::from_millis(200));
+3 -3
View File
@@ -21,9 +21,9 @@ const USD_RATES_URL: &str = "https://api.frankfurter.dev/v2/rates?base=USD";
/// To add a supporter, add a `("Display name", usd_cents)` line below. The
/// amount is in **USD cents**: a $25 donation is `2500`; convert other
/// currencies to USD before adding them.
const MANUAL_SUPPORTERS: &[(&str, i64)] = &[
("Stefano", 10_500), // $105
];
/// OneBSpace (OneCAD Draft): the upstream hand-maintained supporter list was
/// cleared; the fetch functions are never called in the air-gapped build.
const MANUAL_SUPPORTERS: &[(&str, i64)] = &[];
/// Append the hand-maintained [`MANUAL_SUPPORTERS`] to `patrons` and sort the
/// combined list by amount (highest first, then alphabetically). Both the
+9
View File
@@ -20,7 +20,16 @@ pub(crate) const REGISTRY_URL: &str =
"https://raw.githubusercontent.com/HakanSeven12/OpenCADStudio/main/plugins/registry.json";
/// Fetch the curated plugin registry (`plugins/registry.json`).
/// OneBSpace (OneCAD Draft): the curated upstream marketplace registry is
/// disabled — air-gapped build; the GitHub fetch is kept below for reference
/// but never runs. Locally installed / user-added repositories still work.
pub fn fetch_registry() -> Result<Vec<RegistryEntry>, String> {
let _ = REGISTRY_URL;
Ok(Vec::new())
}
#[allow(dead_code)]
fn fetch_registry_github() -> Result<Vec<RegistryEntry>, String> {
let body = download_string(REGISTRY_URL)?;
let json: serde_json::Value = serde_json::from_str(&body).map_err(|e| e.to_string())?;
let arr = json.as_array().ok_or("registry is not a JSON array")?;
+3 -3
View File
@@ -1122,7 +1122,7 @@ pub mod crash_log {
// boundaries still place the fault.
let backtrace = std::backtrace::Backtrace::force_capture();
[
format!("Open CAD Studio {} crash report", env!("OCS_APP_VERSION")),
format!("OneCAD Draft {} crash report", env!("OCS_APP_VERSION")), // OneBSpace (OneCAD Draft): rebranded wordmark
format!("when: {when} (unix seconds)"),
format!("os: {} {}", std::env::consts::OS, std::env::consts::ARCH),
format!("gpu backend: {backend}"),
@@ -1198,7 +1198,7 @@ pub mod crash_log {
#[test]
fn a_report_names_the_message_and_the_line() {
let text = super::report_from("a deliberate test panic", "src/sys.rs:1:2", 42);
assert!(text.starts_with("Open CAD Studio "), "{text}");
assert!(text.starts_with("OneCAD Draft "), "{text}");
assert!(text.contains("panic: a deliberate test panic"), "{text}");
assert!(text.contains("at: src/sys.rs:1:2"), "{text}");
assert!(text.contains("when: 42 (unix seconds)"), "{text}");
@@ -1347,7 +1347,7 @@ pub mod web_diag {
for (id, label) in [
(
"ocs-err-title",
crate::t!("OpenCADStudio renderer error — copy this into a bug report:"),
crate::t!("OneCAD Draft renderer error — copy this into a bug report:"), // OneBSpace (OneCAD Draft): rebranded
),
("ocs-err-copy", crate::t!("Copy")),
("ocs-err-dismiss", crate::t!("Dismiss")),
+2 -2
View File
@@ -111,7 +111,7 @@ pub(crate) fn report() -> String {
let sys = system_info();
#[allow(unused_mut)]
let mut out = format!(
"Open CAD Studio v{}\nRevision: {}\nCommit date: {}\nProfile: {}\nFeatures: {}\n\n\
"OneCAD Draft v{}\nRevision: {}\nCommit date: {}\nProfile: {}\nFeatures: {}\n\n\
[System]\nOS: {} ({} {})\nCPU: {}\nLogical processors: {}\nRAM: {} total, {} available\n",
env!("OCS_FULL_VERSION"),
env!("OCS_GIT_REV"),
@@ -195,7 +195,7 @@ pub fn view_window(sizing: crate::ui::modal::ModalSizing) -> Element<'static, Me
row![
logo,
column![
text("Open CAD Studio").size(28).style(primary_style),
text("OneCAD Draft").size(28).style(primary_style), // OneBSpace (OneCAD Draft): rebranded wordmark
text(t!("CAD application for Architecture & Engineering"))
.size(11)
.style(muted_style),
+1 -1
View File
@@ -238,7 +238,7 @@ fn badge<'a>(support: Support) -> Element<'a, Message> {
pub fn unsupported_reason(support: Support) -> Option<std::borrow::Cow<'static, str>> {
match support {
Support::Yes | Support::ByExtension => None,
Support::No => Some(t!("OpenCAD Studio has no importer for this format.")),
Support::No => Some(t!("OneCAD Draft has no importer for this format.")) /* OneBSpace (OneCAD Draft): rebranded */,
}
}
+1 -1
View File
@@ -59,7 +59,7 @@ pub fn view_window<'a>(
column![
text(crate::t!("Missing fonts")).size(20),
text(crate::t!(
"This drawing uses fonts that are not installed on this machine. OpenCADStudio can download any redistributable fonts that exist in the selected repository; unavailable fonts will keep using a substitute."
"This drawing uses fonts that are not installed on this machine. OneCAD Draft can download any redistributable fonts that exist in the selected repository; unavailable fonts will keep using a substitute."
))
.size(11)
.style(muted_style),
+1 -1
View File
@@ -456,7 +456,7 @@ pub fn view_window<'a>(
iced::widget::checkbox(file_assoc_enabled)
.on_toggle(Message::FileAssocChanged)
.size(15),
text(crate::t!("Open .dwg and .dxf files with Open CAD Studio")).size(12),
text(crate::t!("Open .dwg and .dxf files with OneCAD Draft")) /* OneBSpace (OneCAD Draft): rebranded */.size(12),
]
.spacing(8)
.align_y(iced::Center),
+1 -1
View File
@@ -39,7 +39,7 @@ pub(crate) fn view(prefs: GraphicsPrefs, active: ActiveGpu) -> Element<'static,
text(crate::t!("Graphics")).size(15),
Space::new().height(6),
text(crate::t!(
"Saved immediately. Changes take effect the next time Open CAD Studio starts."
"Saved immediately. Changes take effect the next time OneCAD Draft starts."
))
.size(11)
.width(Fill),
+1 -1
View File
@@ -124,7 +124,7 @@ pub(crate) fn view(
let detail = match status {
Status::Unavailable(reason) => reason,
Status::Unsupported => "This version supports SpaceMouse through 3DxWare on Windows. Other platforms do not yet have a device adapter.".into(),
Status::Disconnected => "3DxWare is running. Connect a SpaceMouse; Open CAD Studio reconnects automatically.".into(),
Status::Disconnected => "3DxWare is running. Connect a SpaceMouse; OneCAD Draft reconnects automatically.".into(),
_ => "Uses the installed 3DxWare driver. Navigation pauses while a dialog is open. Your selected navigation mode is saved across drawings and sessions.".into(),
};
content = content.push(text(crate::t!(&detail).into_owned()).size(11).width(Fill));
+7 -16
View File
@@ -38,10 +38,8 @@ pub struct MarketView<'a> {
pub status: &'a str,
}
/// Latest desktop builds, used by the browser-only plugin notice.
#[cfg(target_arch = "wasm32")]
pub const DESKTOP_DOWNLOAD_URL: &str =
"https://github.com/HakanSeven12/OpenCADStudio/releases/latest";
// OneBSpace (OneCAD Draft): the upstream desktop-download link was removed —
// the browser-only plugin notice no longer links anywhere external.
// Register the command names for autocomplete. On the web they open a desktop
// download notice instead of the native marketplace.
@@ -308,7 +306,7 @@ fn external_card<'a>(
}
if p.bundled {
actions = actions.push(
text(t!("Bundled with Open CAD Studio"))
text(t!("Bundled with OneCAD Draft")) /* OneBSpace (OneCAD Draft): rebranded */
.size(11)
.style(muted_style),
);
@@ -477,7 +475,7 @@ fn registry_error_message(error: &str) -> (Cow<'static, str>, Cow<'static, str>)
(
t!("Unable to verify the server certificate"),
t!(
"Open CAD Studio could not trust the certificate presented for the plugin registry. Check your system certificate and proxy settings, then retry."
"OneCAD Draft could not trust the certificate presented for the plugin registry. Check your system certificate and proxy settings, then retry."
),
)
} else if error.contains("timed out") || error.contains("timeout") {
@@ -915,14 +913,8 @@ pub fn view_window<'a>(
/// Browser replacement for the native Plugin Manager.
#[cfg(target_arch = "wasm32")]
pub fn view_web_notice<'a>() -> Element<'a, Message> {
let download = button(text(t!("Download desktop app")).size(13))
.on_press(Message::OpenUrl(DESKTOP_DOWNLOAD_URL.to_string()))
.padding([9, 18])
.style(|theme: &Theme, status| {
let mut style = button::primary(theme, status);
style.text_color = iced::Color::WHITE;
style
});
// OneBSpace (OneCAD Draft): the "Download desktop app" button was removed —
// no external download links in the air-gapped embedded build.
let icon = container(crate::ui::icons::themed_primary(
crate::ui::icons::GEAR,
@@ -946,14 +938,13 @@ pub fn view_web_notice<'a>() -> Element<'a, Message> {
.width(Length::Fit)
.align_x(iced::alignment::Horizontal::Center),
text(t!(
"Open CAD Studio plugins are native packages and cannot run inside a browser. Download the desktop app to browse, install, and use plugins."
"OneCAD Draft plugins are native packages and cannot run inside a browser. Use the desktop build to browse, install, and use plugins." // OneBSpace (OneCAD Draft): rebranded, no external download link
))
.size(13)
.width(Length::Fit)
.align_x(iced::alignment::Horizontal::Center)
.style(muted_style),
Space::new().height(4),
download,
]
.spacing(10)
.align_x(iced::alignment::Horizontal::Center)
+1 -1
View File
@@ -136,7 +136,7 @@ pub fn view_window<'a>(
.size(20)
.style(primary_style),
text(t!(
"A newer Open CAD Studio version is published on GitHub."
"A newer OneCAD Draft version is published on GitHub."
))
.size(11)
.style(muted_style),
+4 -27
View File
@@ -6,13 +6,11 @@
use crate::app::Message;
use crate::ui::style::common::muted_style;
use crate::ui::style::form::dialog_button;
use iced::widget::{column, container, row, text, Space};
use iced::{Background, Element, Fill, Length, Theme};
/// GitHub issues page linked from the help window, so web users can report
/// missing or broken behavior where it will be seen.
pub const XREF_ISSUES_URL: &str = "https://github.com/HakanSeven12/OpenCADStudio/issues";
// OneBSpace (OneCAD Draft): the GitHub issues link was removed — air-gapped
// build keeps help text only, with no external links.
pub fn view_window(sizing: crate::ui::modal::ModalSizing) -> Element<'static, Message> {
// Fixed window width: paragraphs wrap against this instead of the
@@ -34,21 +32,10 @@ pub fn view_window(sizing: crate::ui::modal::ModalSizing) -> Element<'static, Me
)
.into_owned(),
);
let report_hint = para(
crate::t!(
"Hit something broken or missing? Report it on the GitHub issues page so it can be fixed."
)
.into_owned(),
);
let report_button = dialog_button(
crate::t!("Report an issue"),
Message::OpenUrl(XREF_ISSUES_URL.to_string()),
true,
);
let close_button = dialog_button(crate::t!("Close"), Message::CloseModal, false);
let close_button = crate::ui::style::form::dialog_button(crate::t!("Close"), Message::CloseModal, false);
let action_row: Element<'static, Message> =
row![Space::new().width(Fill), report_button, close_button,]
row![Space::new().width(Fill), close_button,]
.spacing(8)
.align_y(iced::Center)
.into();
@@ -61,7 +48,6 @@ pub fn view_window(sizing: crate::ui::modal::ModalSizing) -> Element<'static, Me
intro,
list,
limits,
report_hint,
Space::new().height(4),
action_row,
]
@@ -78,12 +64,3 @@ pub fn view_window(sizing: crate::ui::modal::ModalSizing) -> Element<'static, Me
})
.into()
}
#[cfg(test)]
mod tests {
#[test]
fn issues_url_points_at_github_issues() {
assert!(super::XREF_ISSUES_URL.starts_with("https://github.com/"));
assert!(super::XREF_ISSUES_URL.contains("/issues"));
}
}
+3 -9
View File
@@ -212,16 +212,10 @@ pub async fn fetch_playlist_web() -> Result<Vec<VideoEntry>, String> {
#[cfg(target_arch = "wasm32")]
async fn fetch_thumbnail_web(id: String) -> Result<Vec<u8>, String> {
// OneBSpace (OneCAD Draft): only the LOCAL same-origin thumbnail cache is
// read; the YouTube image-CDN fallback was removed — air-gapped build.
let local = format!("video_thumbs/{id}.jpg");
match fetch_thumbnail_url(&local).await {
Ok(bytes) => Ok(bytes),
Err(_) => {
// Local development uses the checked-in JSON snapshot without
// binary thumbnails. YouTube's image CDN explicitly permits CORS,
// so it is a safe fallback; deployed Pages builds use local files.
fetch_thumbnail_url(&format!("https://i.ytimg.com/vi/{id}/mqdefault.jpg")).await
}
}
fetch_thumbnail_url(&local).await
}
#[cfg(target_arch = "wasm32")]