node-based graph editor
git clone https://git.lucas.co/cce-graph.git
refactor: hold widgets in Owned boxes (cce-ui Owned<W>)
The UiContext registry keeps raw pointers to registered widgets, and a
widget that moved while registered (its Vec reallocating, its struct
returned by value) left one pointing at the old address. Each widget
field is now an Owned<Adapted<..>> — a heap box whose allocation, not the
widget, carries the liveness token the registry watches — so the
registered address never moves and is dropped from the registry when the
box is freed. Field access is unchanged through Deref; construction
sites wrap in Owned::new.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/main.rs | 27 ++++++++++++++-------------
src/vault.rs | 5 +++--
2 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index 2709917..8a9d2b6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
use wayland_client::QueueHandle;
+use cce_ui::widget::Owned;
use cce_ui::engine::{Application, EngineState, LogicalPosition, LogicalSize, WindowSettings};
mod linkgraph;
mod vault;
@@ -52,12 +53,12 @@ struct LoadedImage {
}
struct GraphApp {
- menu_bar: Adapted<MenuBar>,
- dropdown_file: Adapted<Dropdown>,
- dropdown_edit: Adapted<Dropdown>,
- dropdown_view: Adapted<Dropdown>,
+ menu_bar: Owned<Adapted<MenuBar>>,
+ dropdown_file: Owned<Adapted<Dropdown>>,
+ dropdown_edit: Owned<Adapted<Dropdown>>,
+ dropdown_view: Owned<Adapted<Dropdown>>,
- graph: Adapted<Graph>,
+ graph: Owned<Adapted<Graph>>,
needs_rebuild: bool,
width: u32,
height: u32,
@@ -81,7 +82,7 @@ struct GraphApp {
panel_drag_ox: f32,
panel_drag_oy: f32,
show_control_panel: bool,
- control_panel_label: cce_ui::widget::Adapted<cce_ui::widget::Label>,
+ control_panel_label: Owned<cce_ui::widget::Adapted<cce_ui::widget::Label>>,
}
fn get_default_project_path() -> std::path::PathBuf {
@@ -864,11 +865,11 @@ impl Application for GraphApp {
let mut app = Self {
- menu_bar,
- dropdown_file,
- dropdown_edit,
- dropdown_view,
- graph,
+ menu_bar: Owned::new(menu_bar),
+ dropdown_file: Owned::new(dropdown_file),
+ dropdown_edit: Owned::new(dropdown_edit),
+ dropdown_view: Owned::new(dropdown_view),
+ graph: Owned::new(graph),
needs_rebuild: true,
width: 1024,
height: 768,
@@ -890,7 +891,7 @@ impl Application for GraphApp {
panel_drag_ox: 0.0,
panel_drag_oy: 0.0,
show_control_panel,
- control_panel_label,
+ control_panel_label: Owned::new(control_panel_label),
};
@@ -1557,7 +1558,7 @@ impl Application for GraphApp {
// A press on a port can complete a wire drawn
// with the mouse; write it into the node.
if let Some((to, from, port)) =
- GraphController::take_pending_connection_to_port(&mut *self.graph)
+ GraphController::take_pending_connection_to_port(&mut **self.graph)
{
let mut nodes = self.graph.get_nodes();
if wiring::connect(&mut nodes, &to, &from, port) {
diff --git a/src/vault.rs b/src/vault.rs
index bbefd2c..f695440 100644
--- a/src/vault.rs
+++ b/src/vault.rs
@@ -18,6 +18,7 @@ use std::path::PathBuf;
use std::sync::OnceLock;
use std::time::{Duration, Instant};
+use cce_ui::widget::Owned;
use cce_ui::engine::{Application, CursorIcon, EngineState, LogicalPosition, LogicalSize, WindowSettings};
use cce_ui::scene::layout::Rect;
use cce_ui::scene::paint::{Cap, DisplayList, PaintCtx};
@@ -173,7 +174,7 @@ pub struct VaultApp {
center: Option<String>,
next_poll: Instant,
- filter_input: Adapted<TextBox>,
+ filter_input: Owned<Adapted<TextBox>>,
filter_seen: String,
/// World point at the middle of the graph area, and px per world unit.
@@ -561,7 +562,7 @@ impl Application for VaultApp {
depth: 1,
center: None,
next_poll: Instant::now(),
- filter_input: TextBox::new(String::new()).with_placeholder("Filter: words, #tag, path:"),
+ filter_input: Owned::new(TextBox::new(String::new()).with_placeholder("Filter: words, #tag, path:")),
filter_seen: String::new(),
cam: (0.0, 0.0),
zoom: 1.0,