The first small part of stage 9 (v1.1). <Space>= then m, c or g (the user's pick: leader menus), or :tidy map|chart|grid, lays out the cursor's branch while its top node stays put: a mind map puts each node in the middle of its children (the user's pick), an org chart puts them side by side below, and a grid makes a block of cards beside the node (the user's pick), a card's own branch going along as a mind map. Every node of the branch gets a place, folded away or not (the user's pick), as one undo step, and the message says when the branch now covers nodes outside it. The lines follow the layouts: a parent whose children are all below it sends its branches down to a shared bend, and a new child of it goes beside the last one; a grid card behind another isn't joined by a line, which would look like it joins the two cards. In visual mode, <Space>a then h, l, k, j or c lines the selection up on the box around it, each node bringing its branch along, and : opens the command line on the selection: :align and :tidy take it, and so do :color, :border, :style, :tag and :fold, as one undo step. The layouts are pure functions in view::canvas::arrange, applied as one EditOp::Reposition. Layout and Side moved from the parser to the model so keys can name them. Co-Authored-By: Claude Opus 5.5 <[email protected]>
101 lines
3.6 KiB
Rust
101 lines
3.6 KiB
Rust
//! The data: documents, nodes, links and how they look. No UI and no files
|
|
//! here, just the rules.
|
|
//!
|
|
//! - A [`Document`] owns a tree of [`Node`]s under one root, loose nodes
|
|
//! beside it, and cross-[`Link`]s, and keeps its rules (one root, no
|
|
//! cycles, links between nodes that exist).
|
|
//! - Every change goes through [`Document::edit`], which returns a
|
|
//! [`Change`] that [`History`] can undo and redo.
|
|
//! - Text from outside ([`Title`], [`Tag`]…) is checked once, when it's
|
|
//! turned into these types.
|
|
//! - [`Visible`] works out which nodes folding leaves on show.
|
|
|
|
mod clip;
|
|
mod document;
|
|
mod edit;
|
|
mod fold;
|
|
mod geometry;
|
|
mod history;
|
|
mod ids;
|
|
mod link;
|
|
mod look;
|
|
mod node;
|
|
mod op;
|
|
mod portal;
|
|
mod text;
|
|
|
|
pub use clip::{Clip, ClipNode};
|
|
pub use document::{Document, NodeRecord, Place, StructureError};
|
|
pub use edit::{Change, Edit, EditError, Spot};
|
|
pub use fold::Visible;
|
|
pub use geometry::{CanvasOffset, CanvasPos, CanvasRect, CanvasSize, Direction, Layout, Side};
|
|
pub use history::{Group, History, StateId};
|
|
pub use ids::{DocUid, NodeId};
|
|
pub use link::{LineRef, Link, LinkKey};
|
|
pub use look::{Arrows, Border, LineColor, LineLook, NodeLook, Stroke};
|
|
pub use node::{Content, Fold, Idea, Node};
|
|
pub use op::{Applied, EditOp, Inbox};
|
|
pub use portal::{Backlink, EmptyPath, LinkPath, Portal};
|
|
pub use text::{Body, ColorName, Label, StyleName, Tag, Tags, TextError, Title};
|
|
|
|
/// Small documents and helpers shared by the tests.
|
|
#[cfg(test)]
|
|
pub(crate) mod test_support {
|
|
use super::*;
|
|
|
|
pub fn title(text: &str) -> Title {
|
|
Title::parse(text).expect("a valid title")
|
|
}
|
|
|
|
pub fn idea(text: &str) -> Node {
|
|
Node::idea(title(text), CanvasPos::default())
|
|
}
|
|
|
|
/// The ids in [`garden`].
|
|
pub struct Garden {
|
|
pub root: NodeId,
|
|
pub soil: NodeId,
|
|
pub beds: NodeId,
|
|
pub cedar: NodeId,
|
|
pub watering: NodeId,
|
|
pub compost: NodeId,
|
|
}
|
|
|
|
/// The document from the design mockup:
|
|
///
|
|
/// ```text
|
|
/// Garden plans ─┬─ Soil
|
|
/// ├─ Raised beds ── Cedar
|
|
/// └─ Watering
|
|
/// ask about compost (loose)
|
|
/// ```
|
|
pub fn garden() -> (Document, Garden) {
|
|
let mut doc = Document::with_uid(title("Garden plans"), DocUid::parse("7f3c9a1e52b04d18").unwrap());
|
|
let root = doc.root();
|
|
let at = |text: &str, x: i32, y: i32| Node::idea(title(text), CanvasPos::new(x, y));
|
|
let (ids, _) = doc
|
|
.edit(|e| {
|
|
e.update(root, |node| node.pos = CanvasPos::new(0, 4))?;
|
|
let soil = e.add(at("Soil", 22, 0), Spot::LastChildOf(root))?;
|
|
let beds = e.add(at("Raised beds", 22, 4), Spot::LastChildOf(root))?;
|
|
let cedar = e.add(at("Cedar", 40, 4), Spot::LastChildOf(beds))?;
|
|
let watering = e.add(at("Watering", 22, 8), Spot::LastChildOf(root))?;
|
|
let compost = e.add(at("ask about compost", 0, 14), Spot::Loose)?;
|
|
Ok(Garden { root, soil, beds, cedar, watering, compost })
|
|
})
|
|
.expect("the garden builds");
|
|
(doc, ids)
|
|
}
|
|
|
|
/// Adds a portal to a "Kitchen" document under `parent`.
|
|
pub fn portal(doc: &mut Document, parent: NodeId) -> NodeId {
|
|
let portal = Portal {
|
|
path: LinkPath::parse("kitchen.cum").expect("a path"),
|
|
uid: DocUid::parse("c01d5e7aa0f3b912").expect("a uid"),
|
|
title: title("Kitchen"),
|
|
};
|
|
let node = Node::portal(portal, CanvasPos::new(22, 12));
|
|
doc.edit(|e| e.add(node, Spot::LastChildOf(parent))).expect("the portal goes in").0
|
|
}
|
|
}
|