pub mod align;
pub mod assets;
pub mod color;
pub mod context_menu;
pub mod fill;
pub mod inspect;
pub mod layers;
pub mod machine;
pub mod modifiers;
pub mod path;
pub mod stroke;
use glam::DVec2;
use renamite_animation::Frame;
use renamite_model::{CompId, Document, NodeId};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Selection {
pub nodes: Vec<NodeId>,
pub comp: Option<CompId>,
}
impl Selection {
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn contains(&self, id: NodeId) -> bool {
self.nodes.contains(&id)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct ViewTransform {
pub scale: f64,
pub offset: DVec2,
}
impl ViewTransform {
pub fn identity() -> Self {
Self {
scale: 1.0,
offset: DVec2::ZERO,
}
}
pub fn screen_to_world(&self, p: DVec2) -> DVec2 {
(p - self.offset) / self.scale
}
pub fn world_to_screen(&self, p: DVec2) -> DVec2 {
p * self.scale + self.offset
}
pub fn world_tolerance(&self, px: f64) -> f64 {
px / self.scale
}
pub fn zoom_at(&mut self, screen_pos: DVec2, factor: f64, min: f64, max: f64) {
let world = self.screen_to_world(screen_pos);
self.scale = (self.scale * factor).clamp(min, max);
self.offset = screen_pos - world * self.scale;
}
pub fn pan_by(&mut self, delta: DVec2) {
self.offset += delta;
}
pub fn fit(&mut self, surface: DVec2, artboard: DVec2) {
fit_view(self, surface, artboard);
}
}
pub fn fit_view(view: &mut ViewTransform, surface: DVec2, artboard: DVec2) {
if surface.x <= 1.0 || surface.y <= 1.0 || artboard.x <= 0.0 || artboard.y <= 0.0 {
return;
}
let margin = 56.0;
let available = (surface - DVec2::splat(margin * 2.0)).max(DVec2::splat(1.0));
let scale = (available.x / artboard.x)
.min(available.y / artboard.y)
.clamp(0.05, 32.0);
view.scale = scale;
view.offset = (surface - artboard * scale) * 0.5;
}
pub fn fit_exact_view(view: &mut ViewTransform, surface: DVec2, artboard: DVec2) {
if surface.x <= 1.0 || surface.y <= 1.0 || artboard.x <= 0.0 || artboard.y <= 0.0 {
return;
}
let scale = (surface.x / artboard.x)
.min(surface.y / artboard.y)
.clamp(0.05, 64.0);
view.scale = scale;
view.offset = (surface - artboard * scale) * 0.5;
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct FitState {
surface: DVec2,
artboard: DVec2,
pub pending: bool,
}
impl FitState {
pub fn new() -> Self {
Self {
surface: DVec2::ZERO,
artboard: DVec2::ZERO,
pending: true,
}
}
pub fn with_surface(surface: DVec2) -> Self {
Self {
surface,
artboard: DVec2::ZERO,
pending: false,
}
}
pub fn ensure(
&mut self,
view: &mut ViewTransform,
surface: DVec2,
artboard: DVec2,
refit_on_resize: bool,
) -> bool {
let resized = (surface - self.surface).abs().max_element() > 0.5;
let art_changed = (artboard - self.artboard).abs().max_element() > 0.5;
let first_layout = self.surface == DVec2::ZERO && surface != DVec2::ZERO;
self.surface = surface;
if self.pending || first_layout || art_changed || (refit_on_resize && resized) {
view.fit(surface, artboard);
self.artboard = artboard;
self.pending = false;
true
} else {
false
}
}
pub fn request(&mut self) {
self.pending = true;
}
pub fn surface_size(&self) -> DVec2 {
self.surface
}
pub fn zoom_centered(&self, view: &mut ViewTransform, factor: f64) {
if self.surface == DVec2::ZERO {
return;
}
self.zoom_at(view, self.surface * 0.5, factor);
}
pub fn zoom_at(&self, view: &mut ViewTransform, screen_pos: DVec2, factor: f64) {
if self.surface == DVec2::ZERO {
return;
}
view.zoom_at(screen_pos, factor, 0.05, 64.0);
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Modifiers {
pub shift: bool,
pub alt: bool,
pub ctrl: bool,
}
impl Modifiers {
pub fn none() -> Self {
Self {
shift: false,
alt: false,
ctrl: false,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct SnapConfig {
pub grid: Option<f64>,
pub anchor: bool,
pub guide: bool,
}
pub struct ToolContext<'a> {
pub doc: &'a Document,
pub scene: &'a renamite_model::Scene,
pub comp: CompId,
pub selection: &'a Selection,
pub playhead: Frame,
pub record: bool,
pub view: ViewTransform,
pub snap: SnapConfig,
pub modifiers: Modifiers,
pub current_paint: &'a renamite_model::StylePaint,
}