LR-BEHAV-BG-TASKS: one whole-percent rule for the bar text and its announced value

This commit is contained in:
Nathaniel Ledford
2026-10-22 13:46:24 -04:00
parent 0198375edf
commit 5626550640
4 changed files with 35 additions and 12 deletions
+3 -3
View File
@@ -142,12 +142,12 @@ pub fn detail_toggle(app: &mut LightcraftApp, ui: &mut egui::Ui, id: PhotoId, on
}
/// The bar under the Denoise slider while a photo's picture is made: at most 240 px wide, and
/// sweeping while the number of tiles is not known yet. The percentage is floored, as the bar's
/// accessible value is (and the SAM bar's text): 100 % only once done.
/// sweeping while the number of tiles is not known yet. The percentage is `progress::percent`, as the
/// bar's accessible value is: 100 % only once done.
pub(crate) fn detail_bar(ui: &mut egui::Ui, done: u64, total: u64) -> egui::Response {
let fraction = crate::progress::fraction_of(done, total);
let text = match fraction {
Some(f) => tr_format!("Making the denoised picture… {}%", (f * 100.0).floor() as u32),
Some(f) => tr_format!("Making the denoised picture… {}%", crate::progress::percent(f)),
None => tr("Starting…").to_string(),
};
crate::progress::Progress::new(fraction).label(text).width(ui.available_width().min(240.0)).widget("denoise:progress").show(ui)
+1 -1
View File
@@ -766,7 +766,7 @@ pub(crate) fn start_describe(app: &mut LightcraftApp, op: &str) {
pub(crate) fn sam_download_bar(ui: &mut egui::Ui, done: u64, total: u64, width: f32) -> egui::Response {
let fraction = crate::progress::fraction_of(done, total);
let label = match fraction {
Some(f) => format!("SAM 3: {} %", (f64::from(f) * 100.0).floor()),
Some(f) => format!("SAM 3: {} %", crate::progress::percent(f)),
None => "SAM 3".to_string(),
};
crate::progress::Progress::new(fraction).label(label).width(width).widget("maskSamProgress").show(ui)
+10 -1
View File
@@ -45,6 +45,15 @@ pub fn fraction_of(done: u64, total: u64) -> Option<f32> {
(total > 0).then(|| clamp_fraction(done as f32 / total as f32))
}
/// The whole percent a bar says for `fraction`: rounded down, so 100 comes only at exactly 1.0, but
/// with a little slack so a fraction that is exact in decimals (53 of 100, held as 0.52999997)
/// still says 53. A bar's text and its accessible value both come from here, so they agree.
pub fn percent(fraction: f32) -> u32 {
let f = clamp_fraction(fraction);
let whole = (f64::from(f) * 100.0 + 1e-3).floor() as u32;
if f < 1.0 { whole.min(99) } else { 100 }
}
/// A progress bar, built and then shown with [`Progress::show`].
#[derive(Clone, Debug)]
pub struct Progress {
@@ -103,7 +112,7 @@ impl Progress {
Some(l) => egui::WidgetInfo::labeled(egui::WidgetType::ProgressIndicator, ui.is_enabled(), l),
None => egui::WidgetInfo::new(egui::WidgetType::ProgressIndicator),
};
info.value = self.fraction.map(|f| f64::from(f * 100.0).floor());
info.value = self.fraction.map(|f| f64::from(percent(f)));
info
});
if let Some(w) = &self.widget {
+21 -7
View File
@@ -240,13 +240,27 @@ fn the_denoise_bars_keep_their_widths_in_a_wide_container() {
#[test]
fn the_denoise_bar_label_and_its_accessible_value_agree() {
// 3 of 7 is 42.86 %: the number drawn on the bar is the one announced
let (nodes, _, _) = frames(Vec::new(), |ui| {
crate::panels::denoise::detail_bar(ui, 3, 7);
});
let bar = nodes.iter().find(|n| n.role == "ProgressIndicator").unwrap_or_else(|| panic!("{nodes:?}"));
let shown: f64 = bar.label.rsplit(' ').next().unwrap().trim_end_matches('%').parse().unwrap();
assert_eq!(bar.value, Some(shown), "{bar:?}");
// the number drawn on the bar is the one announced, and exact decimals stay exact
for (done, total, says) in
[(3, 7, 42.0), (53, 100, 53.0), (59, 100, 59.0), (29, 100, 29.0), (99, 100, 99.0), (100, 100, 100.0), (999, 1000, 99.0)]
{
let (nodes, _, _) = frames(Vec::new(), |ui| {
crate::panels::denoise::detail_bar(ui, done, total);
});
let bar = nodes.iter().find(|n| n.role == "ProgressIndicator").unwrap_or_else(|| panic!("{nodes:?}"));
let shown: f64 = bar.label.rsplit(' ').next().unwrap().trim_end_matches('%').parse().unwrap();
assert_eq!((shown, bar.value), (says, Some(says)), "{done}/{total}: {bar:?}");
}
}
#[test]
fn the_sam_bar_text_and_its_accessible_value_agree() {
for (done, total, says) in [(53, 100, 53.0), (59, 100, 59.0), (29, 100, 29.0), (999, 1000, 99.0), (100, 100, 100.0)] {
let (nodes, _, _) = frames(Vec::new(), |ui| crate::panels::masking::sam_download_bar(ui, done, total, 200.0).rect.width());
let bar = nodes.iter().find(|n| n.role == "ProgressIndicator").unwrap_or_else(|| panic!("{nodes:?}"));
assert_eq!(bar.label, format!("SAM 3: {says} %"), "{done}/{total}");
assert_eq!(bar.value, Some(says), "{done}/{total}");
}
}
#[test]