Skip to content

Commit

Permalink
poc random layout
Browse files Browse the repository at this point in the history
  • Loading branch information
blitzarx1 committed Oct 1, 2024
1 parent 46c6b0d commit 8d8af7a
Show file tree
Hide file tree
Showing 14 changed files with 48 additions and 66 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ keywords = ["egui", "ui", "graph", "node-graph"]
categories = ["gui", "visualization"]

[dependencies]
egui = { version = "0.29", default-features = false }
egui = { version = "0.29", default-features = false, features = [
"persistence",
] }
rand = "0.8"
petgraph = { version = "0.6", default-features = false, features = [
"stable_graph",
"matrix_graph",
] }
serde = { version = "1.0", features = ["derive"] }

crossbeam = { version = "0.8", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = { version = "1.0", optional = true }

[features]
egui_persistence = ["dep:serde"]
events = ["dep:serde", "dep:serde_json", "dep:crossbeam"]
serde = ["dep:serde", "egui/serde", "petgraph/serde", "petgraph/serde-1"]
events = ["dep:crossbeam"]

[workspace]
members = ["examples/*"]
Expand Down
8 changes: 0 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,6 @@ Can be enabled with `events` feature. Events describe a change made in graph whe

Combining this feature with custom node draw function allows to implement custom node behavior and drawing according to the events happening.

## Egui crates features support
### Persistence
To use egui `persistence` feature you need to enable `egui_persistence` feature of this crate. For example:
```toml
egui_graphs = { version = "0.22", features = ["egui_persistence"]}
egui = {version="0.29", features = ["persistence"]}
```

## Examples
### Basic setup example
The source code of the following steps can be found in the [basic example](https://github.com/blitzarx1/egui_graphs/blob/master/examples/basic/src/main.rs).
Expand Down
4 changes: 2 additions & 2 deletions examples/animated_nodes/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl<N: Clone + IsClockwise> From<NodeProps<N>> for NodeShapeAnimated {
fn from(node_props: NodeProps<N>) -> Self {
Self {
label: node_props.label,
loc: node_props.location.unwrap_or_default(),
loc: node_props.location,
dragged: node_props.dragged,
clockwise: node_props.payload.get_is_clockwise(),

Expand Down Expand Up @@ -145,7 +145,7 @@ impl<N: Clone + IsClockwise, E: Clone, Ty: EdgeType, Ix: IndexType> DisplayNode<

fn update(&mut self, state: &NodeProps<N>) {
self.label = state.label.clone();
self.loc = state.location.unwrap();
self.loc = state.location;
self.dragged = state.dragged;
self.clockwise = state.payload.get_is_clockwise();
}
Expand Down
4 changes: 2 additions & 2 deletions examples/flex_nodes/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ impl<N: Clone> From<NodeProps<N>> for NodeShapeFlex {
fn from(node_props: NodeProps<N>) -> Self {
Self {
label: node_props.label,
loc: node_props.location.unwrap_or_default(),
loc: node_props.location,

size_x: 0.,
size_y: 0.,
Expand Down Expand Up @@ -67,7 +67,7 @@ impl<N: Clone, E: Clone, Ty: EdgeType, Ix: IndexType> DisplayNode<N, E, Ty, Ix>

fn update(&mut self, state: &NodeProps<N>) {
self.label = state.label.clone();
self.loc = state.location.unwrap();
self.loc = state.location;
}
}

Expand Down
2 changes: 1 addition & 1 deletion examples/rainbow_edges/src/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl<N: Clone, E: Clone, Ty: EdgeType, Ix: IndexType, D: DisplayNode<N, E, Ty, I
ctx: &DrawContext,
) -> Vec<egui::Shape> {
let mut res = vec![];
let (start, end) = (start.location().unwrap(), end.location().unwrap());
let (start, end) = (start.location(), end.location());
let (x_dist, y_dist) = (end.x - start.x, end.y - start.y);
let (dx, dy) = (x_dist / COLORS.len() as f32, y_dist / COLORS.len() as f32);
let d_vec = Vec2::new(dx, dy);
Expand Down
18 changes: 6 additions & 12 deletions src/draw/displays_default/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use crate::{draw::DrawContext, elements::EdgeProps, DisplayEdge, DisplayNode, No

use super::edge_shape_builder::{EdgeShapeBuilder, TipProps};

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug)]
pub struct DefaultEdgeShape {
pub order: usize,
Expand Down Expand Up @@ -53,8 +52,8 @@ impl<N: Clone, E: Clone, Ty: EdgeType, Ix: IndexType, D: DisplayNode<N, E, Ty, I
return self.is_inside_loop(start, pos);
}

let pos_start = start.location().unwrap();
let pos_end = end.location().unwrap();
let pos_start = start.location();
let pos_end = end.location();

if self.order == 0 {
return self.is_inside_line(pos_start, pos_end, pos);
Expand Down Expand Up @@ -86,7 +85,7 @@ impl<N: Clone, E: Clone, Ty: EdgeType, Ix: IndexType, D: DisplayNode<N, E, Ty, I
// draw loop
let size = node_size(start, Vec2::new(-1., 0.));
let mut line_looped_shapes = EdgeShapeBuilder::new(stroke)
.looped(start.location().unwrap(), size, self.loop_size, self.order)
.looped(start.location(), size, self.loop_size, self.order)
.with_scaler(ctx.meta)
.build();
let line_looped_shape = line_looped_shapes.clone().pop().unwrap();
Expand Down Expand Up @@ -119,7 +118,7 @@ impl<N: Clone, E: Clone, Ty: EdgeType, Ix: IndexType, D: DisplayNode<N, E, Ty, I
return res;
}

let dir = (end.location().unwrap() - start.location().unwrap()).normalized();
let dir = (end.location() - start.location()).normalized();
let start_connector_point = start.display().closest_boundary_point(dir);
let end_connector_point = end.display().closest_boundary_point(-dir);

Expand Down Expand Up @@ -233,12 +232,7 @@ impl DefaultEdgeShape {
let node_size = node_size(node, Vec2::new(-1., 0.));

let shape = EdgeShapeBuilder::new(Stroke::new(self.width, Color32::default()))
.looped(
node.location().unwrap(),
node_size,
self.loop_size,
self.order,
)
.looped(node.location(), node_size, self.loop_size, self.order)
.build();

match shape.first() {
Expand All @@ -264,7 +258,7 @@ impl DefaultEdgeShape {
node_end: &Node<N, E, Ty, Ix, D>,
pos: Pos2,
) -> bool {
let dir = (node_end.location().unwrap() - node_start.location().unwrap()).normalized();
let dir = (node_end.location() - node_start.location()).normalized();
let start = node_start.display().closest_boundary_point(dir);
let end = node_end.display().closest_boundary_point(-dir);

Expand Down
5 changes: 2 additions & 3 deletions src/draw/displays_default/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::{draw::drawer::DrawContext, DisplayNode, NodeProps};
/// This is the default node shape which is used to display nodes in the graph.
///
/// You can use this implementation as an example for implementing your own custom node shapes.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Debug)]
pub struct DefaultNodeShape {
pub pos: Pos2,
Expand All @@ -26,7 +25,7 @@ pub struct DefaultNodeShape {
impl<N: Clone> From<NodeProps<N>> for DefaultNodeShape {
fn from(node_props: NodeProps<N>) -> Self {
DefaultNodeShape {
pos: node_props.location.unwrap_or_default(), // can be null if not set on creation explicitly
pos: node_props.location, // can be null if not set on creation explicitly
selected: node_props.selected,
dragged: node_props.dragged,
label_text: node_props.label.to_string(),
Expand Down Expand Up @@ -95,7 +94,7 @@ impl<N: Clone, E: Clone, Ty: EdgeType, Ix: IndexType> DisplayNode<N, E, Ty, Ix>
}

fn update(&mut self, state: &NodeProps<N>) {
self.pos = state.location.unwrap(); // should be set by the layout before rendering
self.pos = state.location; // should be set by the layout before rendering
self.selected = state.selected;
self.dragged = state.dragged;
self.label_text = state.label.to_string();
Expand Down
8 changes: 4 additions & 4 deletions src/elements/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{DefaultNodeShape, DisplayNode};
#[derive(Clone, Debug)]
pub struct NodeProps<N: Clone> {
pub payload: N,
pub location: Option<Pos2>,
pub location: Pos2,
pub label: String,
pub selected: bool,
pub dragged: bool,
Expand Down Expand Up @@ -82,7 +82,7 @@ where
pub fn new(payload: N) -> Self {
let props = NodeProps {
payload,
location: Option::default(),
location: Pos2::default(),
label: String::default(),
selected: bool::default(),
dragged: bool::default(),
Expand Down Expand Up @@ -132,12 +132,12 @@ where
&mut self.props.payload
}

pub fn location(&self) -> Option<Pos2> {
pub fn location(&self) -> Pos2 {
self.props.location
}

pub fn set_location(&mut self, loc: Pos2) {
self.props.location = Some(loc);
self.props.location = loc;
}

pub fn selected(&self) -> bool {
Expand Down
13 changes: 7 additions & 6 deletions src/graph_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,32 +79,33 @@ where
L: Layout,
{
fn ui(self, ui: &mut Ui) -> Response {
let (resp, p) = ui.allocate_painter(ui.available_size(), Sense::click_and_drag());

let mut meta = Metadata::get(ui);
self.sync_state(&mut meta);

L::default().next(self.g);

let (resp, p) = ui.allocate_painter(ui.available_size(), Sense::click_and_drag());

self.handle_fit_to_screen(&resp, &mut meta);
self.handle_navigation(ui, &resp, &mut meta);

self.handle_node_drag(&resp, &mut meta);
self.handle_click(&resp, &mut meta);

let is_directed = self.g.is_directed();
Drawer::<N, E, Ty, Ix, Nd, Ed, L>::new(
self.g,
&DrawContext {
ctx: ui.ctx(),
painter: &p,
meta: &meta,
is_directed,
is_directed: self.g.is_directed(),
style: &self.settings_style,
},
)
.draw();

meta.first_frame = false;
meta.store_into_ui(ui);

ui.ctx().request_repaint();

resp
Expand Down Expand Up @@ -523,7 +524,7 @@ where

fn move_node(&mut self, idx: NodeIndex<Ix>, delta: Vec2) {
let n = self.g.node_mut(idx).unwrap();
let new_loc = n.location().unwrap() + delta;
let new_loc = n.location() + delta;
n.set_location(new_loc);

#[cfg(feature = "events")]
Expand Down
4 changes: 3 additions & 1 deletion src/layouts/layout.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use egui::util::id_type_map::SerializableAny;
use petgraph::{stable_graph::IndexType, EdgeType};

use crate::{DisplayEdge, DisplayNode, Graph};

pub trait Layout: Default {
/// This function is called on every frame. It should update the graph layout aka nodes locations.
/// Called on every frame. It should update the graph layout aka nodes locations.
// TODO: maybe should have signature next(prev: impl Serializable, g), where prev is prev state?:w
fn next<
N: Clone,
E: Clone,
Expand Down
2 changes: 1 addition & 1 deletion src/layouts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ mod layout;
mod random;

pub use default::Default;
pub use hierarchical::Hierarchical;
pub use layout::Layout;
pub use random::Random;
pub use hierarchical::Hierarchical;
10 changes: 3 additions & 7 deletions src/layouts/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::Graph;

use super::Layout;

const DEFAULT_SPAWN_SIZE: f32 = 250.;
const SPAWN_SIZE: f32 = 250.;

/// Randomly places nodes on the canvas. Does not override existing locations. Applies once.
#[derive(Default)]
Expand All @@ -33,13 +33,9 @@ impl Layout for Random {

let mut rng = rand::thread_rng();
for node in g.g.node_weights_mut() {
if node.location().is_some() {
continue;
};

node.set_location(Pos2::new(
rng.gen_range(0. ..DEFAULT_SPAWN_SIZE),
rng.gen_range(0. ..DEFAULT_SPAWN_SIZE),
rng.gen_range(0. ..SPAWN_SIZE),
rng.gen_range(0. ..SPAWN_SIZE),
));
}

Expand Down
22 changes: 10 additions & 12 deletions src/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use egui::{Id, Pos2, Rect, Vec2};
use petgraph::{stable_graph::IndexType, EdgeType};
use serde::{Deserialize, Serialize};

use crate::{DisplayNode, Node};

#[cfg_attr(
feature = "egui_persistence",
derive(serde::Serialize, serde::Deserialize)
)]
#[derive(Clone, Debug)]
const KEY: &str = "egui_graphs_metadata";

#[derive(Clone, Debug, Serialize, Deserialize)]
struct Bounds {
min: Vec2,
max: Vec2,
Expand All @@ -33,7 +32,7 @@ impl Bounds {
&mut self,
n: &Node<N, E, Ty, Ix, D>,
) {
let loc = n.location().unwrap();
let loc = n.location();
if loc.x < self.min.x {
self.min.x = loc.x;
};
Expand All @@ -49,11 +48,7 @@ impl Bounds {
}
}

#[cfg_attr(
feature = "egui_persistence",
derive(serde::Serialize, serde::Deserialize)
)]
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Metadata {
/// Whether the frame is the first one
pub first_frame: bool,
Expand Down Expand Up @@ -82,7 +77,10 @@ impl Default for Metadata {

impl Metadata {
pub fn get(ui: &egui::Ui) -> Self {
ui.data_mut(|data| data.get_persisted::<Metadata>(Id::NULL).unwrap_or_default())
ui.data_mut(|data| {
data.get_persisted::<Metadata>(Id::new(KEY))
.unwrap_or_default()
})
}

pub fn store_into_ui(self, ui: &mut egui::Ui) {
Expand Down

0 comments on commit 8d8af7a

Please sign in to comment.