use super::crop::ItemMapping;
use super::{Editor, Selection};
use crate::geometry::Point;
use crate::model::{ItemId, SmearKind, Step, Stroke};
use crate::panic_free::Clamped;
pub const DEFAULT_STRENGTH: f64 = 0.5;
#[derive(Clone, Copy, Debug, PartialEq)]
pub(super) struct SmearSettings {
pub(super) kind: SmearKind,
pub(super) size: Option<f64>,
pub(super) strength: f64,
}
impl Default for SmearSettings {
fn default() -> Self {
Self {
kind: SmearKind::default(),
size: None,
strength: DEFAULT_STRENGTH,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SmearTool {
pub item: ItemId,
pub kind: SmearKind,
pub size: f64,
pub strength: f64,
}
impl Editor {
pub(super) fn start_smear(&mut self, item: ItemId) -> bool {
if self.project.state().item(item).is_none() {
return false;
}
self.crop = None;
self.smear = Some(item);
self.selection = Selection::Item(item);
true
}
pub fn smear_tool(&self) -> Option<SmearTool> {
let id = self.smear?;
let item = self.project.state().item(id)?;
let default = (f64::from(item.width.min(item.height)) * 0.05)
.max(1.0)
.round();
Some(SmearTool {
item: id,
kind: self.smear_settings.kind,
size: self.smear_settings.size.unwrap_or(default),
strength: self.smear_settings.strength,
})
}
pub fn set_smear_kind(&mut self, kind: SmearKind) {
self.smear_settings.kind = kind;
}
pub fn set_smear_size(&mut self, size: f64) {
if size.is_finite() && size >= 1.0 {
self.smear_settings.size = Some(size);
}
}
pub fn set_smear_strength(&mut self, strength: f64) {
if strength.is_finite() {
self.smear_settings.strength = strength.clamped(0.01, 1.0);
}
}
pub(super) fn stroke_from(&self, points: &[Point]) -> Option<(ItemId, Stroke)> {
let tool = self.smear_tool()?;
let item = *self.project.state().item(tool.item)?;
let mapping = ItemMapping::new(item);
let scale = (f64::from(item.width) / f64::from(item.crop.width)
+ f64::from(item.height) / f64::from(item.crop.height))
/ 2.0;
let points = points
.iter()
.map(|&p| {
let s = mapping.canvas_to_source(p);
[(s.x * 100.0).round() / 100.0, (s.y * 100.0).round() / 100.0]
})
.collect();
Some((
tool.item,
Stroke {
kind: tool.kind,
size: tool.size / scale,
strength: tool.strength,
points,
},
))
}
pub(super) fn finish_stroke(&mut self, points: &[Point]) -> bool {
match self.stroke_from(points) {
Some((item, stroke)) => self.record(Step::Smear { item, stroke }),
None => false,
}
}
}