Skip to main content

wi_core/
lib.rs

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
80// TODO: drop references for types that are Copy
81pub 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}