requestty_ui/backend/
mod.rs1#[cfg(all(not(feature = "crossterm"), feature = "termion"))]
4use std::os::fd::AsFd;
5use std::{fmt::Display, io};
6
7#[cfg(feature = "crossterm")]
9#[cfg_attr(docsrs, doc(cfg(feature = "crossterm")))]
10pub fn get_backend<W: io::Write>(buf: W) -> impl Backend {
11 CrosstermBackend::new(buf)
12}
13
14#[cfg(all(not(feature = "crossterm"), feature = "termion"))]
16#[cfg_attr(docsrs, doc(cfg(feature = "termion")))]
17pub fn get_backend<W>(buf: W) -> impl Backend
18where
19 W: io::Write + AsFd,
20{
21 TermionBackend::new(buf)
22}
23
24mod test_backend;
25pub use test_backend::TestBackend;
26
27#[cfg(feature = "termion")]
28mod termion;
29
30#[cfg(feature = "termion")]
31pub use self::termion::{TermionBackend, TermionDisplayBackend};
32
33#[cfg(feature = "crossterm")]
34mod crossterm;
35
36#[cfg(feature = "crossterm")]
37pub use self::crossterm::CrosstermBackend;
38
39use crate::style::{Attributes, Color, Styled};
40
41#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Default)]
43#[allow(missing_docs)]
44pub struct Size {
45 pub width: u16,
46 pub height: u16,
47}
48
49impl Size {
50 pub fn area(self) -> u16 {
52 self.width * self.height
53 }
54}
55
56impl From<(u16, u16)> for Size {
57 fn from((width, height): (u16, u16)) -> Self {
58 Size { width, height }
59 }
60}
61
62#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
64pub enum ClearType {
65 All,
67 FromCursorDown,
69 FromCursorUp,
71 CurrentLine,
73 UntilNewLine,
75}
76
77#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
79pub enum MoveDirection {
80 Up(u16),
82 Down(u16),
84 Left(u16),
86 Right(u16),
88 NextLine(u16),
90 PrevLine(u16),
92 Column(u16),
94}
95
96pub trait DisplayBackend: io::Write {
98 fn set_attributes(&mut self, attributes: Attributes) -> io::Result<()>;
100 fn set_fg(&mut self, color: Color) -> io::Result<()>;
102 fn set_bg(&mut self, color: Color) -> io::Result<()>;
104 fn write_styled(&mut self, styled: &Styled<dyn Display + '_>) -> io::Result<()> {
110 styled.write(self)
111 }
112}
113
114pub trait Backend: DisplayBackend {
116 fn enable_raw_mode(&mut self) -> io::Result<()>;
118 fn disable_raw_mode(&mut self) -> io::Result<()>;
120 fn hide_cursor(&mut self) -> io::Result<()>;
122 fn show_cursor(&mut self) -> io::Result<()>;
124
125 fn get_cursor_pos(&mut self) -> io::Result<(u16, u16)>;
127 fn move_cursor_to(&mut self, x: u16, y: u16) -> io::Result<()>;
129 fn move_cursor(&mut self, direction: MoveDirection) -> io::Result<()> {
131 default_move_cursor(self, direction)
132 }
133 fn scroll(&mut self, dist: i16) -> io::Result<()>;
138
139 fn clear(&mut self, clear_type: ClearType) -> io::Result<()>;
141 fn size(&self) -> io::Result<Size>;
143}
144
145fn default_move_cursor<B: Backend + ?Sized>(
146 backend: &mut B,
147 direction: MoveDirection,
148) -> io::Result<()> {
149 let (mut x, mut y) = backend.get_cursor_pos()?;
150
151 match direction {
152 MoveDirection::Up(dy) => y = y.saturating_sub(dy),
153 MoveDirection::Down(dy) => y = y.saturating_add(dy),
154 MoveDirection::Left(dx) => x = x.saturating_sub(dx),
155 MoveDirection::Right(dx) => x = x.saturating_add(dx),
156 MoveDirection::NextLine(dy) => {
157 x = 0;
158 y = y.saturating_add(dy);
159 }
160 MoveDirection::Column(new_x) => x = new_x,
161 MoveDirection::PrevLine(dy) => {
162 x = 0;
163 y = y.saturating_sub(dy);
164 }
165 }
166
167 backend.move_cursor_to(x, y)
168}
169
170impl<B: DisplayBackend> DisplayBackend for &mut B {
171 fn set_attributes(&mut self, attributes: Attributes) -> io::Result<()> {
172 (**self).set_attributes(attributes)
173 }
174 fn set_fg(&mut self, color: Color) -> io::Result<()> {
175 (**self).set_fg(color)
176 }
177 fn set_bg(&mut self, color: Color) -> io::Result<()> {
178 (**self).set_bg(color)
179 }
180 fn write_styled(&mut self, styled: &Styled<dyn Display + '_>) -> io::Result<()> {
181 (**self).write_styled(styled)
182 }
183}
184
185impl<B: Backend> Backend for &mut B {
186 fn enable_raw_mode(&mut self) -> io::Result<()> {
187 (**self).enable_raw_mode()
188 }
189 fn disable_raw_mode(&mut self) -> io::Result<()> {
190 (**self).disable_raw_mode()
191 }
192 fn hide_cursor(&mut self) -> io::Result<()> {
193 (**self).hide_cursor()
194 }
195 fn show_cursor(&mut self) -> io::Result<()> {
196 (**self).show_cursor()
197 }
198 fn get_cursor_pos(&mut self) -> io::Result<(u16, u16)> {
199 (**self).get_cursor_pos()
200 }
201 fn move_cursor_to(&mut self, x: u16, y: u16) -> io::Result<()> {
202 (**self).move_cursor_to(x, y)
203 }
204 fn move_cursor(&mut self, direction: MoveDirection) -> io::Result<()> {
205 (**self).move_cursor(direction)
206 }
207 fn scroll(&mut self, dist: i16) -> io::Result<()> {
208 (**self).scroll(dist)
209 }
210 fn clear(&mut self, clear_type: ClearType) -> io::Result<()> {
211 (**self).clear(clear_type)
212 }
213 fn size(&self) -> io::Result<Size> {
214 (**self).size()
215 }
216}