perf: keep heavy work off UI thread

This commit is contained in:
Hakan Seven committed 2026-07-25 18:49:18 +03:00
1 parent 12bf126646
commit deec48ad99
75 files changed
+11702 -518

No files matched your search

+27 -35
View File
@@ -1,7 +1,7 @@
//! Modal overlay shown while a CAD file is being loaded.
//!
//! Displays the file name, size, current phase, an indeterminate animated
//! progress bar, and a Cancel button.
//! Displays the file name, size, current phase, measured progress, and a
//! Cancel button.
use iced::time::Instant;
use iced::widget::{button, column, container, row, stack, text, Space};
@@ -10,20 +10,18 @@ use std::sync::atomic::Ordering;
use crate::app::{
Message, OpenProgress, OPEN_PHASE_CACHING, OPEN_PHASE_FINALIZING, OPEN_PHASE_PARSING,
OPEN_PHASE_READING,
OPEN_PHASE_READING, OPEN_PHASE_XREF,
};
const CARD_WIDTH: f32 = 420.0;
const BAR_TRACK_WIDTH: f32 = 380.0;
const BAR_TRACK_HEIGHT: f32 = 6.0;
const BAR_WINDOW_WIDTH: f32 = 100.0;
/// Period of one back-and-forth bounce, in milliseconds.
const BAR_PERIOD_MS: f32 = 1800.0;
fn phase_label(phase: u8) -> &'static str {
match phase {
OPEN_PHASE_READING => "Reading file…",
OPEN_PHASE_PARSING => "Parsing entities…",
OPEN_PHASE_XREF => "Loading references…",
OPEN_PHASE_CACHING => "Building scene caches…",
OPEN_PHASE_FINALIZING => "Finalizing…",
_ => "Working…",
@@ -46,29 +44,22 @@ fn format_size(bytes: u64) -> String {
}
}
/// Compute the left-offset of the moving highlight inside the track.
/// Bounces left↔right using a triangle wave so the user sees motion even when
/// the actual phase atomic stays put for a while.
fn bar_offset(elapsed_ms: f32) -> f32 {
let travel = (BAR_TRACK_WIDTH - BAR_WINDOW_WIDTH).max(0.0);
let cycle = (elapsed_ms / BAR_PERIOD_MS).fract();
let tri = if cycle < 0.5 {
cycle * 2.0
} else {
(1.0 - cycle) * 2.0
};
tri * travel
}
pub fn view<'a>(progress: &'a OpenProgress, _now: Instant) -> Element<'a, Message> {
let phase = progress.state.phase.load(Ordering::Acquire);
let basis_points = progress
.state
.basis_points
.load(Ordering::Relaxed)
.min(10000);
let fraction = basis_points as f32 / 10000.0;
let fill_width = BAR_TRACK_WIDTH * fraction;
let trailing = (BAR_TRACK_WIDTH - fill_width).max(0.0);
pub fn view<'a>(progress: &'a OpenProgress, now: Instant) -> Element<'a, Message> {
let phase = progress.phase.load(Ordering::Relaxed);
let elapsed_ms = now.saturating_duration_since(progress.started).as_millis() as f32;
// ── Animated indeterminate bar ────────────────────────────────────────
let offset = bar_offset(elapsed_ms);
let trailing = (BAR_TRACK_WIDTH - BAR_WINDOW_WIDTH - offset).max(0.0);
let bar_window: Element<'_, Message> = container(Space::new().width(Length::Fixed(BAR_WINDOW_WIDTH)).height(Length::Fixed(BAR_TRACK_HEIGHT)))
let bar_fill: Element<'_, Message> = container(
Space::new()
.width(Length::Fixed(fill_width))
.height(Length::Fixed(BAR_TRACK_HEIGHT)),
)
.style(|_: &Theme| container::Style {
background: Some(Background::Color(Color {
r: 0.30,
@@ -84,11 +75,8 @@ pub fn view<'a>(progress: &'a OpenProgress, now: Instant) -> Element<'a, Message
})
.into();
let bar_moving: Element<'_, Message> = row![
Space::new()
.width(Length::Fixed(offset))
.height(Length::Fixed(BAR_TRACK_HEIGHT)),
bar_window,
let bar_value: Element<'_, Message> = row![
bar_fill,
Space::new()
.width(Length::Fixed(trailing))
.height(Length::Fixed(BAR_TRACK_HEIGHT)),
@@ -111,7 +99,7 @@ pub fn view<'a>(progress: &'a OpenProgress, now: Instant) -> Element<'a, Message
},
..Default::default()
}),
bar_moving,
bar_value,
]
.width(Length::Fixed(BAR_TRACK_WIDTH))
.height(Length::Fixed(BAR_TRACK_HEIGHT)),
@@ -136,7 +124,11 @@ pub fn view<'a>(progress: &'a OpenProgress, now: Instant) -> Element<'a, Message
a: 1.0,
});
let phase_line = text(phase_label(phase))
let phase_line = text(format!(
"{} {:.1}%",
phase_label(phase),
basis_points as f32 / 100.0
))
.size(12)
.color(Color {
r: 0.70,