Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_tui/src/lib_tui/draw/outline.rs

6.4 KiB, 7 runs

created by r1870400018:1177, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use crate::lib_tui::{
2 cfg::line::LineType,
3 render::{
4 Drawable,
5 Drawer,
6 Renderer,
7 Sink,
8 When,
9 },
10 style::Style,
11 window::WindowMode,
12};
13
14use oxedyne_fe2o3_core::prelude::*;
15use oxedyne_fe2o3_geom::{
16 dim::Coord,
17 rect::{
18 AbsRect,
19 RectSide,
20 RectSideIter,
21 },
22};
23
24
25/// Outline state for an individual window.
26#[derive(Clone, Copy, Debug, Default)]
27pub enum BorderManagementMode {
28 #[default]
29 Adjust,
30 Selection,
31}
32
33/// Outline state for an individual window.
34#[derive(Clone, Debug)]
35pub struct OutlineState {
36 pub line: RectSide,
37 pub iter: RectSideIter,
38 pub mode: Option<BorderManagementMode>,
39}
40
41impl Default for OutlineState {
42 fn default() -> Self {
43 let line = RectSide::Bottom;
44 let mut iter = RectSideIter::new(line);
45 iter.next();
46 Self {
47 line,
48 iter,
49 mode: None,
50 }
51 }
52}
53
54#[derive(Clone, Debug)]
55pub struct OutlineConfig {
56 pub style: Style,
57 pub typ: LineType,
58}
59
60impl Default for OutlineConfig {
61 fn default() -> Self {
62 Self {
63 style: Style::default(),
64 typ: LineType::SingleSharp,
65 }
66 }
67}
68
69#[derive(Clone, Debug, Default)]
70pub struct OutlineConfigs {
71 pub normal: OutlineConfig,
72 pub focus: OutlineConfig,
73 pub interact: OutlineConfig,
74 pub mgmt_mode: OutlineConfig,
75 pub mgmt_tint: OutlineConfig,
76 pub mgmt_focus: OutlineConfig,
77}
78
79impl OutlineConfigs {
80 pub fn get(
81 &self,
82 focus: bool,
83 mode: WindowMode,
84 state: &OutlineState,
85 )
86 -> &OutlineConfig
87 {
88 if focus {
89 match mode {
90 WindowMode::WindowManagement => match state.mode {
91 Some(_) => &self.mgmt_tint,
92 _ => &self.mgmt_mode,
93 }
94 WindowMode::Interaction => &self.interact,
95 _ => &self.focus,
96 }
97 } else {
98 &self.normal
99 }
100 }
101}
102
103#[derive(Clone, Debug)]
104pub struct Outline<'a> {
105 pub view: AbsRect,
106 pub cfgs: &'a OutlineConfigs,
107 pub state: &'a OutlineState,
108 pub focus: bool,
109 pub wmode: WindowMode,
110}
111
112impl<'a> Drawable for Outline<'a> {
113 fn render<S: Sink, R: Renderer<S>>(
114 &mut self,
115 drawer: &mut Drawer<S, R>,
116 when: When,
117 )
118 -> Outcome<()>
119 {
120 let (x, y, w, h) = self.view.tup();
121 let mut cfg = self.cfgs.get(self.focus, self.wmode, self.state).clone();
122 let parts = drawer.lib.line[cfg.typ].clone();
123
124 res!(cfg.style.render(drawer, When::Later));
125 for j in 0..h.as_index() {
126 res!(drawer.rend.set_cursor(Coord::new((x, y + j)), When::Later));
127 if j == 0 {
128 let top_border = fmt!("{}{}{}",
129 parts.top_left,
130 parts.horiz().repeat((w - 2).as_index()),
131 parts.top_right,
132 );
133 res!(drawer.rend.print(&top_border, When::Later));
134 } else if j == (h - 1).as_index() {
135 let bottom_border = fmt!("{}{}{}",
136 parts.bot_left,
137 parts.horiz().repeat((w - 2).as_index()),
138 parts.bot_right,
139 );
140 res!(drawer.rend.print(&bottom_border, When::Later));
141 } else {
142 res!(drawer.rend.print(&parts.vert(), When::Later));
143 res!(drawer.rend.set_cursor(Coord::new((x + w - 1, y + j)), When::Later));
144 res!(drawer.rend.print(&parts.vert(), When::Later));
145 }
146 }
147
148 match self.state.mode {
149 Some(_) => {
150 let mut cfg = self.cfgs.mgmt_focus.clone();
151 let parts = drawer.lib.line[cfg.typ].clone();
152 res!(cfg.style.render(drawer, When::Later));
153 match self.state.line {
154 RectSide::Top => {
155 res!(drawer.rend.set_cursor(Coord::new((x, y)), When::Later));
156 let top_border = fmt!("{}{}{}",
157 parts.top_left,
158 parts.horiz().repeat((w - 2).as_index()),
159 parts.top_right,
160 );
161 res!(drawer.rend.print(&top_border, When::Later));
162 }
163 RectSide::Right => {
164 res!(drawer.rend.set_cursor(Coord::new((x + w - 1, y)), When::Later));
165 res!(drawer.rend.print(&parts.top_right.to_string(), When::Later));
166 for j in 1..(h - 1).as_index() {
167 res!(drawer.rend.set_cursor(Coord::new((x + w - 1, y + j)), When::Later));
168 res!(drawer.rend.print(&parts.vert(), When::Later));
169 }
170 res!(drawer.rend.set_cursor(Coord::new((x + w - 1, y + h - 1)), When::Later));
171 res!(drawer.rend.print(&parts.bot_right.to_string(), When::Later));
172 }
173 RectSide::Bottom => {
174 res!(drawer.rend.set_cursor(Coord::new((x, y + h - 1)), When::Later));
175 let bottom_border = fmt!("{}{}{}",
176 parts.bot_left,
177 parts.horiz().repeat((w - 2).as_index()),
178 parts.bot_right,
179 );
180 res!(drawer.rend.print(&bottom_border, When::Later));
181 }
182 RectSide::Left => {
183 res!(drawer.rend.set_cursor(Coord::new((x, y)), When::Later));
184 res!(drawer.rend.print(&parts.top_left.to_string(), When::Later));
185 for j in 1..(h - 1).as_index() {
186 res!(drawer.rend.set_cursor(Coord::new((x, y + j)), When::Later));
187 res!(drawer.rend.print(&parts.vert(), When::Later));
188 }
189 res!(drawer.rend.set_cursor(Coord::new((x, y + h - 1)), When::Later));
190 res!(drawer.rend.print(&parts.bot_left.to_string(), When::Later));
191 }
192 }
193 }
194 _ => {}
195 }
196
197 res!(drawer.rend.reset_style(When::Later));
198
199 if when == When::Now {
200 res!(drawer.rend.flush());
201 }
202 Ok(())
203 }
204}