use crate::{
MainWindow, RetargetModel,
gui::editor::retarget::search::{DEFAULT_EFFORT_INDEX, DEFAULT_RANGE_INDEX, SearchSettings},
};
use slint::ComponentHandle;
const CROWN_FRACTION_EPSILON: f32 = 1e-4;
#[derive(Debug, Clone, Copy, PartialEq)]
pub(super) struct HiddenRetargetSettings {
pub crown_fraction: f32,
pub scale_crown_by_ratio: bool,
pub crown_follows_pavilion: bool,
pub objective_index: i32,
pub range_index: i32,
pub effort_index: i32,
pub keep_look: bool,
pub girdle_allowance: bool,
}
impl HiddenRetargetSettings {
#[must_use]
pub(super) fn defaults() -> Self {
Self {
crown_fraction: 0.0,
scale_crown_by_ratio: false,
crown_follows_pavilion: true,
objective_index: i32::try_from(SearchSettings::default().preset.index()).unwrap_or(0),
range_index: i32::try_from(DEFAULT_RANGE_INDEX).unwrap_or(0),
effort_index: i32::try_from(DEFAULT_EFFORT_INDEX).unwrap_or(0),
keep_look: SearchSettings::default().keep_look,
girdle_allowance: SearchSettings::default().girdle.is_some(),
}
}
#[must_use]
pub(super) fn in_use(&self) -> bool {
let default = Self::defaults();
self.crown_fraction.abs() > CROWN_FRACTION_EPSILON
|| self.scale_crown_by_ratio != default.scale_crown_by_ratio
|| self.crown_follows_pavilion != default.crown_follows_pavilion
|| self.objective_index != default.objective_index
|| self.range_index != default.range_index
|| self.effort_index != default.effort_index
|| self.keep_look != default.keep_look
|| self.girdle_allowance != default.girdle_allowance
}
}
pub(super) fn setup_advanced_in_use_callback(ui: &MainWindow) {
ui.global::<RetargetModel>().on_advanced_in_use(
|crown_fraction,
scale_crown_by_ratio,
objective_index,
range_index,
effort_index,
crown_follows_pavilion,
keep_look,
girdle_allowance| {
HiddenRetargetSettings {
crown_fraction,
scale_crown_by_ratio,
crown_follows_pavilion,
objective_index,
range_index,
effort_index,
keep_look,
girdle_allowance,
}
.in_use()
},
);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::gui::editor::retarget::search::{EFFORT_CHOICES, RANGE_CHOICES_DEG};
fn default() -> HiddenRetargetSettings {
HiddenRetargetSettings::defaults()
}
#[test]
fn the_opening_values_are_not_advanced() {
assert!(!default().in_use());
}
#[test]
fn every_hidden_setting_off_its_default_counts_as_in_use() {
let changed = [
HiddenRetargetSettings {
crown_fraction: 0.25,
..default()
},
HiddenRetargetSettings {
scale_crown_by_ratio: true,
..default()
},
HiddenRetargetSettings {
crown_follows_pavilion: false,
..default()
},
HiddenRetargetSettings {
objective_index: default().objective_index + 1,
..default()
},
HiddenRetargetSettings {
range_index: default().range_index + 1,
..default()
},
HiddenRetargetSettings {
effort_index: default().effort_index + 1,
..default()
},
HiddenRetargetSettings {
keep_look: false,
..default()
},
HiddenRetargetSettings {
girdle_allowance: false,
..default()
},
];
for settings in changed {
assert!(settings.in_use(), "{settings:?}");
}
}
#[test]
fn a_crown_fraction_of_zero_within_rounding_is_not_in_use() {
let settings = HiddenRetargetSettings {
crown_fraction: 1e-6,
..default()
};
assert!(!settings.in_use());
}
#[test]
fn the_default_indices_name_the_default_search_settings() {
let settings = SearchSettings::default();
let range = usize::try_from(default().range_index)
.ok()
.and_then(|index| RANGE_CHOICES_DEG.get(index));
assert_eq!(range, Some(&settings.range_deg));
let effort = usize::try_from(default().effort_index)
.ok()
.and_then(|index| EFFORT_CHOICES.get(index));
assert_eq!(effort, Some(&settings.evaluations));
assert_eq!(default().objective_index, 0);
}
}