Files
cumulus/src/model/geometry.rs
T
skkeyeandClaude Opus 5.5 69aa7eee58 Add the data model and the document file format
The model holds the rules: a document is a tree under one root, with
loose nodes beside it and cross-links between any two nodes. Every change
runs as a transaction that rolls back on error and returns an undo step
(the old and new values of whatever it touched), so undo and redo need no
code of their own per command. Text from outside (titles, tags, names) is
checked once, when it becomes a typed value. Folding (Open, Auto, Closed,
plus focus) is one function that every view will share.

storage::document_file reads and writes `.cum` files in RON, with
multi-line bodies kept readable, `\n` line endings on every OS, and errors
that name the node they're about. The tests cover the tree rules, 500
random edits undone and redone step by step, folding, and the file format
(the example from DESIGN.md is written back character for character).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 00:54:49 -04:00

67 lines
1.6 KiB
Rust

//! Places on the canvas.
//!
//! The canvas is a grid of terminal cells (at Normal zoom) with no edges, so
//! coordinates can be negative. `x` grows to the right and `y` downward, as in
//! the terminal.
use std::ops::{Add, AddAssign, Neg, Sub};
/// A point on the canvas.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct CanvasPos {
pub x: i32,
pub y: i32,
}
impl CanvasPos {
/// The point at `x`, `y`.
pub const fn new(x: i32, y: i32) -> CanvasPos {
CanvasPos { x, y }
}
}
/// A movement on the canvas: `dx` cells to the right, `dy` cells down.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct CanvasOffset {
pub dx: i32,
pub dy: i32,
}
impl CanvasOffset {
/// A movement of `dx` cells to the right and `dy` cells down.
pub const fn new(dx: i32, dy: i32) -> CanvasOffset {
CanvasOffset { dx, dy }
}
}
impl Add<CanvasOffset> for CanvasPos {
type Output = CanvasPos;
fn add(self, offset: CanvasOffset) -> CanvasPos {
CanvasPos::new(self.x + offset.dx, self.y + offset.dy)
}
}
impl AddAssign<CanvasOffset> for CanvasPos {
fn add_assign(&mut self, offset: CanvasOffset) {
*self = *self + offset;
}
}
impl Sub for CanvasPos {
type Output = CanvasOffset;
/// The movement that goes from `other` to `self`.
fn sub(self, other: CanvasPos) -> CanvasOffset {
CanvasOffset::new(self.x - other.x, self.y - other.y)
}
}
impl Neg for CanvasOffset {
type Output = CanvasOffset;
fn neg(self) -> CanvasOffset {
CanvasOffset::new(-self.dx, -self.dy)
}
}