use super::core::EditorState;
use indicatrix_cut_core::{Edit, EditError, MaterialSelection, OptimizeOutcome, PreformSpec};
use std::sync::atomic::Ordering as AtomicOrdering;
impl EditorState {
pub(in crate::gui::editor) fn apply(&mut self, edit: Edit) -> Result<(), EditError> {
let Self {
design, history, ..
} = self;
let outcome = history.apply(design, edit);
if outcome.is_ok() {
self.generation.fetch_add(1, AtomicOrdering::Relaxed);
self.prune_multi_selected();
}
outcome
}
pub(in crate::gui::editor) fn apply_coalescing(
&mut self,
edit: Edit,
key: u64,
) -> Result<(), EditError> {
let Self {
design, history, ..
} = self;
let outcome = history.apply_coalescing(design, edit, key, std::time::Instant::now());
if outcome.is_ok() {
self.generation.fetch_add(1, AtomicOrdering::Relaxed);
self.prune_multi_selected();
}
outcome
}
pub(in crate::gui::editor) fn undo(&mut self) -> Result<bool, EditError> {
let Self {
design, history, ..
} = self;
let undone = history.undo(design)?;
if undone {
self.generation.fetch_add(1, AtomicOrdering::Relaxed);
self.prune_multi_selected();
}
Ok(undone)
}
pub(in crate::gui::editor) fn redo(&mut self) -> Result<bool, EditError> {
let Self {
design, history, ..
} = self;
let redone = history.redo(design)?;
if redone {
self.generation.fetch_add(1, AtomicOrdering::Relaxed);
self.prune_multi_selected();
}
Ok(redone)
}
fn prune_multi_selected(&mut self) {
let tier_count = self.design.tiers.len();
self.multi_selected.retain(|&index| index < tier_count);
}
pub(in crate::gui::editor) fn apply_optimize_outcome(
&mut self,
outcome: &OptimizeOutcome,
) -> Result<usize, EditError> {
let Self {
design, history, ..
} = self;
let result = indicatrix_cut_core::apply_optimize_outcome(history, design, outcome);
match &result {
Ok(0) => {}
Ok(_) | Err(_) => {
self.generation.fetch_add(1, AtomicOrdering::Relaxed);
}
}
result
}
#[must_use]
pub(in crate::gui::editor) fn is_dirty(&self) -> bool {
self.generation.load(AtomicOrdering::Relaxed) != self.saved_generation
}
pub(in crate::gui::editor) fn record_scratch_push(&self) -> ScratchDelta {
let design = &self.design;
let mut cache = self.last_pushed_scratch.borrow_mut();
let meta_now = (
design.meta.headers.clone(),
design.meta.footnotes.clone(),
design.meta.gear_reference_angle,
);
let delta = ScratchDelta {
material: cache.material.as_ref() != Some(&design.material),
gear: cache.gear_teeth != Some(design.meta.gear_teeth),
symmetry: cache.symmetry != Some((design.meta.symmetry_order, design.meta.mirror)),
preform: cache.preform != Some(design.preform),
girdle: cache.girdle_diameter_mm
!= GirdleDiameterPush::Observed(design.girdle_diameter_mm),
meta: cache.meta.as_ref() != Some(&meta_now),
};
*cache = PushedScratch {
material: Some(design.material.clone()),
gear_teeth: Some(design.meta.gear_teeth),
symmetry: Some((design.meta.symmetry_order, design.meta.mirror)),
preform: Some(design.preform),
girdle_diameter_mm: GirdleDiameterPush::Observed(design.girdle_diameter_mm),
meta: Some(meta_now),
};
delta
}
}
#[derive(Default)]
pub(in crate::gui::editor) struct PushedScratch {
pub(super) material: Option<MaterialSelection>,
pub(super) gear_teeth: Option<i32>,
pub(super) symmetry: Option<(u32, bool)>,
pub(super) preform: Option<PreformSpec>,
pub(super) girdle_diameter_mm: GirdleDiameterPush,
pub(super) meta: Option<(Vec<String>, Vec<String>, f64)>,
}
#[derive(Clone, Copy, Default, PartialEq)]
pub(super) enum GirdleDiameterPush {
#[default]
Unobserved,
Observed(Option<f64>),
}
pub(in crate::gui::editor) struct ScratchDelta {
pub(in crate::gui::editor) material: bool,
pub(in crate::gui::editor) gear: bool,
pub(in crate::gui::editor) symmetry: bool,
pub(in crate::gui::editor) preform: bool,
pub(in crate::gui::editor) girdle: bool,
pub(in crate::gui::editor) meta: bool,
}
#[must_use]
pub(in crate::gui::editor) const fn result_is_stale(
result_generation: Option<u64>,
current_generation: u64,
) -> bool {
match result_generation {
Some(g) => g != current_generation,
None => false,
}
}
pub(in crate::gui::editor) fn angle_nudge_coalesce_key(targets: &[usize]) -> u64 {
use std::hash::{Hash, Hasher};
let mut sorted = targets.to_vec();
sorted.sort_unstable();
sorted.dedup();
let mut hasher = std::collections::hash_map::DefaultHasher::new();
sorted.len().hash(&mut hasher);
for value in &sorted {
value.hash(&mut hasher);
}
hasher.finish()
}