Canvas · Graphs and boards: node graph, flow chart, mind map, whiteboard

NodeGraph joins Nodes by wires between typed Ports: a title drags a
node, a drag out of an output lands on an input of the same kind, an
input takes one wire, and a press on a wired input lifts its wire.
Links join shapes on the plane and follow them, straight or at right
angles, with an arrow and words; the Connector tool draws them and the
Note tool drops a sticky note. A double press with Select writes on a
shape. FlowChart draws Steps as ellipses, boxes and diamonds with their
words. MindMap lays topics out from a root, half to each side, and asks
the owner to add, remove and rename by key. Whiteboard keeps its own
tool, view and selection over a board it hands back after each change.
Painting moves to canvas::paint; a press on the tool layer goes through
canvas::press, and the layer focuses itself and asks to delete.
This commit is contained in:
ZacharyZhang-NY committed 2026-09-27 08:22:54 -04:00
1 parent ec1988cd6f
commit 4498ff09dc
28 files changed
+3068 -240

No files matched your search

+18 -2
View File
@@ -28,14 +28,17 @@ fn icon(tool: Tool) -> IconName {
Tool::Pen => IconName::PenTool,
Tool::Text => IconName::Type,
Tool::Brush => IconName::Brush,
Tool::Note => IconName::StickyNote,
Tool::Connector => IconName::Spline,
}
}
/// The canvas's tools in a row, one picked, each named in a tip.
/// The canvas's tools in a row, one picked, each named in a tip. It offers every tool unless given fewer.
#[derive(IntoElement)]
pub struct ToolPalette {
id: ElementId,
tool: Tool,
tools: Vec<Tool>,
on_change: Option<OnTool>,
}
@@ -44,10 +47,17 @@ impl ToolPalette {
Self {
id: id.into(),
tool,
tools: Tool::ALL.to_vec(),
on_change: None,
}
}
/// The tools it offers, in order; the picked one among them.
pub fn tools(mut self, tools: impl IntoIterator<Item = Tool>) -> Self {
self.tools = tools.into_iter().collect();
self
}
pub fn on_change(mut self, handler: impl Fn(Tool, &mut Window, &mut App) + 'static) -> Self {
self.on_change = Some(Rc::new(handler));
self
@@ -56,8 +66,14 @@ impl ToolPalette {
impl RenderOnce for ToolPalette {
fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
assert!(
self.tools.contains(&self.tool),
"tool palette {:?}: {} is not offered",
self.id,
self.tool.words()
);
let on_change = self.on_change;
Tool::ALL
self.tools
.into_iter()
.fold(ToggleGroup::new(self.id), |group, tool| {
group.item(