1use std::{
2 fmt,
3 num::{NonZeroIsize, NonZeroU32},
4};
5
6use crate::bindings::Mode;
7pub use crate::{
8 actions::Action,
9 bindings::ModeKind,
10 cursor::{euclidean_cell, Cursor, EdgeCursor, WCursor, WEdgeCursor},
11 status::Status,
12};
13
14pub extern crate shibari;
15
16mod actions;
17mod bindings;
18mod cursor;
19mod keyboard;
20pub mod modifiers;
21mod operators;
22mod status;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25pub enum Side {
26 In,
27 Out,
28}
29
30impl Side {
31 #[inline]
32 #[must_use]
33 pub fn flip(self) -> Self {
34 match self {
35 Self::In => Self::Out,
36 Self::Out => Self::In,
37 }
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42pub struct Port<N, P>(pub N, pub P);
43
44pub type WPort<W> = Port<<W as GraphWidget>::NodeId, <W as GraphWidget>::PortId>;
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47pub struct SidedPort<N, P>(pub Side, pub Port<N, P>);
48
49pub type WSidedPort<W> = SidedPort<<W as GraphWidget>::NodeId, <W as GraphWidget>::PortId>;
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
52pub enum Step {
53 Left,
54 Down,
55 Up,
56 Right,
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
60pub enum AlignCell {
61 Overwrite,
62 KeepRow,
63 KeepCol,
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub enum CursorUpdate {
68 Move,
69 CenterInView,
70}
71
72pub trait GraphWidgetCell<W: GraphWidget + ?Sized> {
73 fn of_cursor(widget: &W, cursor: &WCursor<W>) -> Self;
74
75 fn position(&self, widget: &W) -> W::Point;
76
77 fn align_to_cursor(&mut self, widget: &W, cursor: &WCursor<W>, align: AlignCell);
78}
79
80pub trait GraphWidget {
82 type NodeId: Copy + Eq;
83 type PortId: Copy + Eq;
84
85 type Cell: GraphWidgetCell<Self>;
86 type Point: Copy;
87
88 type Context<'a>;
89
90 fn default_cursor(&self) -> WCursor<Self>;
91
92 fn nearest_node_where<F: Fn(&Self::NodeId) -> bool>(
93 &self,
94 cell: &Self::Cell,
95 pred: F,
96 ) -> Option<Self::NodeId>;
97
98 fn nearest_node(&self, cell: &Self::Cell) -> Option<Self::NodeId> {
99 self.nearest_node_where(cell, |_| true)
100 }
101
102 fn nearest_port(
103 &self,
104 node: &Self::NodeId,
105 side: Side,
106 cell: &Self::Cell,
107 ) -> Option<Self::PortId>;
108
109 fn step_port_by(
110 &self,
111 port: &WSidedPort<Self>,
112 count: isize,
113 ) -> Option<(NonZeroIsize, Self::PortId)>;
114
115 fn nearest_edge_where<F: Fn(&WEdgeCursor<Self>) -> bool>(
116 &self,
117 port: &WSidedPort<Self>,
118 cell: &Self::Cell,
119 pred: F,
120 ) -> Option<WEdgeCursor<Self>>;
121
122 #[inline]
123 fn nearest_edge(
124 &self,
125 port: &WSidedPort<Self>,
126 cell: &Self::Cell,
127 ) -> Option<WEdgeCursor<Self>> {
128 self.nearest_edge_where(port, cell, |_| true)
129 }
130
131 fn step_edge_by(
132 &self,
133 edge: &WEdgeCursor<Self>,
134 count: isize,
135 ) -> Option<(NonZeroIsize, WPort<Self>)>;
136
137 fn step_point_by(&self, point: &Self::Point, step: Step, count: usize) -> Self::Point;
138
139 fn update_cursor(
140 &mut self,
141 update: CursorUpdate,
142 cursor: &WCursor<Self>,
143 ctx: &mut Self::Context<'_>,
144 );
145
146 fn update_status(&mut self, status: Status, ctx: &mut Self::Context<'_>);
147
148 fn delete_node(&mut self, node: &Self::NodeId) -> bool;
149
150 fn delete_edge(&mut self, from: &WPort<Self>, to: &WPort<Self>) -> bool;
151}
152
153#[must_use]
154pub struct GraphWidgetDriver<W: GraphWidget + ?Sized> {
155 cursor: Option<WCursor<W>>,
156 cell: W::Cell,
157 debug: bool,
158
159 count: Option<NonZeroU32>,
160 mode: Mode,
161 last_action: Option<Action>,
162}
163
164impl<W: GraphWidget + ?Sized> fmt::Debug for GraphWidgetDriver<W>
165where
166 W::NodeId: fmt::Debug,
167 W::PortId: fmt::Debug,
168 W::Cell: fmt::Debug,
169 W::Point: fmt::Debug,
170{
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 let Self {
173 cursor,
174 cell,
175 debug,
176 count,
177 mode,
178 last_action,
179 } = self;
180 f.debug_struct("GraphWidgetDriver")
181 .field("cursor", cursor)
182 .field("cell", cell)
183 .field("debug", debug)
184 .field("count", count)
185 .field("mode", mode)
186 .field("last_action", last_action)
187 .finish()
188 }
189}
190
191impl<W: GraphWidget + ?Sized> GraphWidgetDriver<W> {
192 pub fn new(widget: &W) -> Self {
193 let cursor = widget.default_cursor();
194 let me = Self {
195 cell: W::Cell::of_cursor(widget, &cursor),
196 cursor: Some(cursor),
197 debug: false,
198 count: None,
199 mode: Mode::default(),
200 last_action: None,
201 };
202
203 debug_assert_eq!(me.status(), Status::default());
204
205 me
206 }
207
208 #[inline]
209 pub fn cursor(&self) -> &WCursor<W> { self.cursor.as_ref().unwrap_or_else(|| unreachable!()) }
210
211 #[inline]
212 pub fn cursor_cell(&self) -> &W::Cell { &self.cell }
213
214 #[inline]
215 pub fn view_debug(&self) -> bool { self.debug }
216}