1use std;
4use std::sync::{LazyLock, Mutex};
5use {log, easycurses, pancurses, nsys};
6
7use crate::{Application, Interface, Tree};
8use crate::math::Vector2;
9use crate::geometry::integer::Aabb2;
10use crate::geometry::intersect::integer as intersect;
11use crate::interface::{view, View};
12use crate::widget;
13use crate::tree::NodeId;
14use super::{Graphics, Presentation};
15
16pub static INIT_COLORS : LazyLock <Mutex <Option <[[u8; 3]; 8]>>> =
17 LazyLock::new (|| Mutex::new (None));
18
19#[derive(Debug)]
21pub struct Curses {
22 inner : nsys::curses::Curses,
23 release_buttons : Vec <view::input::Button>
27}
28
29pub fn border_acs_lines() -> view::Border {
30 #[expect(trivial_numeric_casts)]
31 view::Border {
32 top: pancurses::ACS_HLINE() as u32,
33 bottom: pancurses::ACS_HLINE() as u32,
34 left: pancurses::ACS_VLINE() as u32,
35 right: pancurses::ACS_VLINE() as u32,
36 top_left: pancurses::ACS_ULCORNER() as u32,
37 top_right: pancurses::ACS_URCORNER() as u32,
38 bottom_left: pancurses::ACS_LLCORNER() as u32,
39 bottom_right: pancurses::ACS_LRCORNER() as u32,
40 thickness_top: 1,
41 thickness_bottom: 1,
42 thickness_left: 1,
43 thickness_right: 1
44 }
45}
46
47impl Curses {
48 #[inline]
49 pub const fn inner (&self) -> &nsys::curses::Curses {
50 &self.inner
51 }
52 #[inline]
53 pub const fn inner_mut (&mut self) -> &mut nsys::curses::Curses {
54 &mut self.inner
55 }
56 #[inline]
57 pub fn dimensions (&self) -> view::dimensions::Tile {
58 let (rows, columns) = self.inner.dimensions_rc();
59 debug_assert!(rows > 0);
60 debug_assert!(columns > 0);
61 Vector2::new (rows as u32, columns as u32).into()
62 }
63}
64
65impl Default for Curses {
66 fn default() -> Self {
67 let mut inner = {
68 let init_colors = INIT_COLORS.lock().unwrap();
69 nsys::curses::Curses::new (init_colors.as_ref())
70 };
71 inner.un_get_input (pancurses::Input::KeyResize);
73 Curses { inner, release_buttons: Vec::new() }
74 }
75}
76
77impl Graphics for Curses { }
78impl Presentation for Curses {
79 fn with_root (_root : View, _id : NodeId) -> Self {
80 Self::default()
81 }
82
83 fn make_interface <A : Application> () -> Interface <A, Self> {
85 use widget::BuildElement;
86 let screen = widget::frame::screen::TileBuilder::<A>::new().build_element();
89 let mut interface = Interface::<A, Self>::with_root (screen);
90 let dimensions = interface.presentation.dimensions();
91 let mut actions = vec![];
92 widget::frame::screen::resize (
93 &view::input::System::Resized {
94 width: dimensions.columns(),
95 height: dimensions.rows()
96 },
97 interface.elements(),
98 interface.root_id(),
99 &mut actions
100 );
101 let _ = interface.actions (actions);
102 interface
103 }
104
105 fn get_input (&mut self, input_buffer : &mut Vec <view::Input>) {
106 use view::{input, Input};
107 log::trace!("get input...");
108 input_buffer.extend (self.release_buttons.drain (..)
109 .map (|button|{
110 let input = Input::Button (button, input::button::State::Released);
111 log::debug!("input: {input:?}");
112 input
113 }));
114 if let Some (pancurses_input) = self.inner.getch_nowait() {
115 log::trace!("pancurses input: {pancurses_input:?}");
116 let input = match pancurses_input.into() {
117 Input::System (input::System::Resized { width: 0, height: 0 }) => {
119 let (width, height) = {
121 let (rows, columns) = self.inner.dimensions_rc();
122 debug_assert!(rows >= 0);
123 debug_assert!(columns >= 0);
124 (columns as u32, rows as u32)
128 };
129 input::System::Resized { width, height }.into()
130 }
131 Input::Button (button, pressed) => {
132 debug_assert_eq!(pressed, input::button::State::Pressed);
133 self.release_buttons.push (button);
135 Input::Button (button, pressed)
136 }
137 Input::Text (input::Text::Char (ch)) => {
138 let button = {
140 let (keycode, modifiers) = char_to_keycode (ch);
141 input::Button { variant: keycode.into(), modifiers }
142 };
143 let input = Input::Text (input::Text::Char (ch));
144 log::debug!("input: {input:?}");
145 input_buffer.push (input);
146 self.release_buttons.push (button);
148 (button, input::button::State::Pressed).into()
149 }
150 input => input
151 };
152 log::debug!("input: {input:?}");
153 input_buffer.push (input);
154 }
155 log::trace!("...get input");
156 }
157
158 fn display_view <V : AsRef <View>> (&mut self,
159 view_tree : &Tree <V>,
160 _display_values : std::vec::Drain <(NodeId, view::Display)>
161 ) {
162 use std::collections::VecDeque;
163 use pancurses::chtype;
164 use nsys::curses::{color_pair_attr, pancurses_ok, pancurses_warn_ok};
165 use view::component::{canvas, Body, Canvas, Image, Kind};
166 log::trace!("display view...");
167 let (attrs, colors) = self.inner.win().attrget();
169 let bkgd = self.inner.win().getbkgd();
170 log::trace!(" window: attributes: {attrs:064b}");
171 log::trace!(" window: color pair: {colors}");
172 log::trace!(" window: background: {bkgd:064b}");
173 let screen_id = view_tree.root_node_id().unwrap();
175 let screen = view_tree.get (screen_id).unwrap().data().as_ref();
176 let screen_canvas = Canvas::try_ref (&screen.component).unwrap();
177 let (clear, bg_color) = {
180 let color = match screen_canvas.clear_color {
181 canvas::ClearColor::Appearance =>
182 screen.appearance.style.as_ref().map(|style| style.bg),
183 canvas::ClearColor::Fixed (clear_color) => clear_color
184 };
185 ( color.is_some(),
186 color.map_or (0x00, |color| {
188 let bg = convert_color (color).unwrap();
189 color_pair_attr (easycurses::Color::White, bg)
190 })
191 )
192 };
193 self.inner.win().bkgdset (' ' as chtype | bg_color);
194 if clear {
195 pancurses_ok!(self.inner.win().erase());
196 }
197 let style = screen.appearance.style.clone().unwrap_or_default();
199 #[expect(trivial_numeric_casts)]
201 if let Some (border) = screen_canvas.border.as_ref() {
202 let rc_min = (0,0);
203 let rc_max = (
204 screen_canvas.coordinates.dimensions().vec().numcast().unwrap()
205 - Vector2::new (1,1)
206 ).into_tuple();
207 let color = color_pair_attr (
208 convert_color (style.fg).unwrap(),
209 convert_color (style.bg).unwrap());
210 pancurses_warn_ok!(self.inner.draw_border (
211 border.left as chtype | color,
212 border.right as chtype | color,
213 border.top as chtype | color,
214 border.bottom as chtype | color,
215 border.top_left as chtype | color,
216 border.top_right as chtype | color,
217 border.bottom_left as chtype | color,
218 border.bottom_right as chtype | color,
219 rc_min, rc_max,
220 border.thickness_top as u32,
221 border.thickness_bottom as u32,
222 border.thickness_left as u32,
223 border.thickness_right as u32
224 ));
225 }
226 let screen_aabb = screen_canvas.coordinates.into();
228 let mut canvases = VecDeque::new();
229 for child_id in view_tree.children_ids (screen_id).unwrap() {
230 let child = view_tree.get (child_id).unwrap().data().as_ref();
231 let style = child.appearance.style.as_ref().unwrap_or (&style);
232 if let Some (child_canvas) = Canvas::try_ref (&child.component) &&
233 let Some ((canvas, body_aabb)) =
234 canvas_and_body_aabb (child_canvas, &screen_aabb)
235 {
236 canvases.push_back ((child_id, canvas, style, body_aabb));
237 }
238 }
239 while canvases.len() > 0 {
240 let (node_id, canvas, style, body_aabb) = canvases.pop_front().unwrap();
241 let node = view_tree.get (node_id).unwrap();
242 let mut text = None;
243 let mut image = None;
244 for child_id in node.children().iter().rev() {
245 let child = view_tree.get (child_id).unwrap().data().as_ref();
246 let style = child.appearance.style.as_ref().unwrap_or (style);
247 if let Some (child_canvas) = Canvas::try_ref (&child.component) &&
248 let Some ((canvas, body_aabb)) =
249 canvas_and_body_aabb (child_canvas, &screen_aabb)
250 {
251 canvases.push_front ((child_id, canvas, style, body_aabb));
252 } else if let Some (child_text) = Body::try_ref (&child.component) {
253 debug_assert!(text.is_none());
254 let skip = body_aabb.min().0.x as usize;
257 let take = body_aabb.max().0.x as usize - skip;
258 let start = body_aabb.min().0.y as usize;
259 let end = body_aabb.max().0.y as usize;
260 text = Some ((
261 child_text.0.lines().skip (skip).take (take).map (
262 move |line| &line[start.min (line.len())..end.min (line.len())]),
263 child.appearance.style.clone()
264 ));
265 } else if let Some (child_image) = Image::try_ref (&child.component) {
266 debug_assert!(image.is_none());
267 match child_image {
268 Image::Raw64 (pixmap) => {
269 let skip = body_aabb.min().0.x as usize;
270 let take = body_aabb.max().0.x as usize - skip;
271 let start = body_aabb.min().0.y as usize;
272 let end = body_aabb.max().0.y as usize;
273 image = Some (pixmap.rows().skip (skip).take (take).map (
274 move |row| &row[start.min (row.len())..end.min (row.len())]
275 ));
276 }
277 Image::Raw8(_) | Image::Raw16(_) | Image::Raw32(_) |
278 Image::Texture(_) => {
279 image = None;
281 }
282 }
283 }
284 }
285 self.draw_canvas (&canvas, style, text, image, true);
286 }
287 log::trace!("...display view");
290
291 fn canvas_and_body_aabb (child_canvas : &Canvas, screen_aabb : &Aabb2 <i32>)
292 -> Option <(Canvas, Aabb2 <i32>)>
293 {
294 let child_aabb = child_canvas.coordinates.into();
295 intersect::continuous_aabb2_aabb2 (screen_aabb, &child_aabb).map (
296 |intersection| {
297 let coordinates = view::Coordinates::tile_from_aabb (intersection);
298 let mut canvas = Canvas {
299 coordinates, .. child_canvas.clone()
300 };
301 let (body_width, body_height) = child_canvas.body_wh();
302 let (mut body_min_row, mut body_min_col) = (0, 0);
303 let (mut body_max_row, mut body_max_col) =
304 (body_height as i32, body_width as i32);
305 if let Some (border) = canvas.border.as_mut() {
306 let outside_top = screen_aabb.min().0.x - child_aabb.min().0.x;
307 if outside_top > 0 {
308 body_min_row = (outside_top as u32)
309 .saturating_sub (border.thickness_top as u32) as i32;
310 border.thickness_top = border.thickness_top
311 .saturating_sub (outside_top as u16);
312 }
313 let outside_bottom = child_aabb.max().0.x - screen_aabb.max().0.x;
314 if outside_bottom > 0 {
315 body_max_row -= (outside_bottom as u32)
316 .saturating_sub (border.thickness_bottom as u32) as i32;
317 border.thickness_bottom = border.thickness_bottom
318 .saturating_sub (outside_bottom as u16);
319 }
320 let outside_left = screen_aabb.min().0.y - child_aabb.min().0.y;
321 if outside_left > 0 {
322 body_min_col = (outside_left as u32)
323 .saturating_sub (border.thickness_left as u32) as i32;
324 border.thickness_left = border.thickness_left
325 .saturating_sub (outside_left as u16);
326 }
327 let outside_right = child_aabb.max().0.y - screen_aabb.max().0.y;
328 if outside_right > 0 {
329 body_max_col -= (outside_right as u32)
330 .saturating_sub (border.thickness_right as u32) as i32;
331 border.thickness_right = border.thickness_right
332 .saturating_sub (outside_right as u16);
333 }
334 }
335 ( canvas,
336 Aabb2::with_minmax (
337 [body_min_row, body_min_col].into(),
338 [body_max_row, body_max_col].into()
339 )
340 )
341 }
342 )
343 }
344 }
345}
346
347impl Curses {
348 fn draw_canvas <'a> (&mut self,
350 canvas : &view::component::Canvas,
351 style : &view::Style,
352 text : Option <(impl Iterator <Item=&'a str>, Option <view::Style>)>,
353 image : Option <impl Iterator <Item=&'a [u64]>>,
354 _debug : bool
355 ) {
356 use std::convert::TryInto;
357 use nsys::curses::{chtype_color_pair, color_pair_attr, pancurses_ok,
358 pancurses_warn_ok};
359 use pancurses::chtype;
360 use crate::interface::view::component::canvas;
361 log::trace!("draw_canvas...");
362 let curses = &mut self.inner;
363 let (position, dimensions)
364 : (view::position::Tile, view::dimensions::Tile)
365 = canvas.coordinates.try_into().unwrap();
366 let (rc_min, rc_max) = {
367 let (row, col) = (position.row(), position.column());
368 let (rows, cols) = (dimensions.rows() as i32, dimensions.columns() as i32);
369 ( (row, col),
370 (row + rows-1, col + cols-1) )
371 };
372 let clear_color = match canvas.clear_color {
374 canvas::ClearColor::Appearance => Some (style.bg),
375 canvas::ClearColor::Fixed (color) => color
376 };
377 clear_color.map (|color|{
378 let border = ' ' as chtype;
379 let bgcolor = convert_color (color).unwrap();
380 let fill_color = color_pair_attr (easycurses::Color::White, bgcolor);
381 let fill = ' ' as chtype | fill_color;
382 curses.draw_rect (border, fill, rc_min, rc_max, 0,0); });
384 let color = color_pair_attr (
385 convert_color (style.fg).unwrap(),
386 convert_color (style.bg).unwrap());
387 let color_pair = chtype_color_pair (color);
388 pancurses_ok!(curses.win().color_set (color_pair));
389 curses.win().bkgdset (b' ' as chtype | color);
390 #[expect(trivial_numeric_casts)]
392 let (border_thickness_top, border_thickness_left) =
393 canvas.border.as_ref().map (|border|{
394 pancurses_warn_ok!(curses.draw_border (
395 border.left as chtype | color,
396 border.right as chtype | color,
397 border.top as chtype | color,
398 border.bottom as chtype | color,
399 border.top_left as chtype | color,
400 border.top_right as chtype | color,
401 border.bottom_left as chtype | color,
402 border.bottom_right as chtype | color,
403 rc_min, rc_max,
404 border.thickness_top as u32,
405 border.thickness_bottom as u32,
406 border.thickness_left as u32,
407 border.thickness_right as u32
408 ));
409 ( border.thickness_top as i32,
410 border.thickness_left as i32 )
411 }).unwrap_or_default();
412 text.map (|(text, style)|{
414 style.map (|style|{
415 let color = color_pair_attr (
416 convert_color (style.fg).unwrap(),
417 convert_color (style.bg).unwrap());
418 let color_pair = chtype_color_pair (color);
419 pancurses_ok!(curses.win().color_set (color_pair));
420 curses.win().bkgdset (b' ' as chtype | color);
421 });
422 for (i, line) in text.enumerate() {
423 let printable = line.trim_start_matches ('\0');
424 let skip = line.len() - printable.len();
425 let row = rc_min.0 + border_thickness_top + i as i32;
426 let col = rc_min.1 + border_thickness_left + skip as i32;
427 if line.len() > 0 {
428 let _ = curses.win().mvaddstr (row, col, printable);
429 }
430 }
431 });
432 image.map (|image|{
434 for (i, line) in image.enumerate() {
435 let row = rc_min.0 + border_thickness_top + i as i32;
436 let col = rc_min.1 + border_thickness_left;
437 for (j, ch) in line.iter().enumerate() {
438 if *ch != 0x0 {
439 let _ = curses.win().mvaddch (row, col+j as i32, *ch as chtype);
440 }
441 }
442 }
443 });
444 log::trace!("...draw_canvas");
445 }
446}
447
448impl From <pancurses::Input> for view::Input {
449
450 fn from (input : pancurses::Input) -> Self {
456 use pancurses::Input::*;
457 use view::input::{self, button::Keycode, Modifiers};
458 const ALT : Modifiers = Modifiers::ALT;
459 const CTRL : Modifiers = Modifiers::CTRL;
460 const SHIFT : Modifiers = Modifiers::SHIFT;
461 const EMPTY : Modifiers = Modifiers::empty();
462 let unhandled = |input| {
463 log::warn!("curses unhandled input: {input:?}");
464 (Keycode::NonConvert, EMPTY)
465 };
466 #[expect(clippy::match_same_arms)]
467 let (keycode, modifiers) = match input {
468 Character (ch) => match ch {
469 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' |
470 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' |
471 'y' | 'z' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '0' |
472 '-' | '=' | '`' | '[' | ']' | '\\'| ';' | '\''| ',' | '.' | '/' | 'A' |
473 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' |
474 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' |
475 'Z' | '!' | '@' | '#' | '$' | '%' | '^' | '&' | '*' | '(' | ')' | '_' |
476 '+' | '~' | '{' | '}' | '|' | ':' | '"' | '<' | '>' | '?' | ' ' | '\n'|
477 '\t' => return input::Text::Char (ch).into(),
478 special => {
479 let unhandled = |ch| {
480 log::warn!("curses unhandled special character: {ch:?}");
481 (Keycode::NonConvert, EMPTY)
482 };
483 let keyname = pancurses::keyname (special as i32).unwrap_or_else (||{
484 log::error!("pancurses keyname failed for special char {special:?}");
485 unreachable!()
486 });
487 log::trace!("keyname: {keyname:?}");
488 match keyname.as_str() {
489 "^A" => (Keycode::A, CTRL),
490 "^B" => (Keycode::B, CTRL),
491 "^C" => (Keycode::C, CTRL),
492 "^D" => (Keycode::D, CTRL),
493 "^E" => (Keycode::E, CTRL),
494 "^F" => (Keycode::F, CTRL),
495 "^G" => (Keycode::G, CTRL),
496 "^H" => (Keycode::Backspace, EMPTY),
498 "^I" => (Keycode::I, CTRL),
499 "^J" => (Keycode::J, CTRL),
500 "^K" => (Keycode::K, CTRL),
501 "^L" => (Keycode::L, CTRL),
502 "^M" => (Keycode::M, CTRL),
503 "^N" => (Keycode::N, CTRL),
504 "^O" => (Keycode::O, CTRL),
505 "^P" => (Keycode::P, CTRL),
506 "^Q" => (Keycode::Q, CTRL),
507 "^R" => (Keycode::R, CTRL),
508 "^S" => (Keycode::S, CTRL),
509 "^T" => (Keycode::T, CTRL),
510 "^U" => (Keycode::U, CTRL),
511 "^V" => (Keycode::V, CTRL),
512 "^W" => (Keycode::W, CTRL),
513 "^X" => (Keycode::X, CTRL),
514 "^Y" => (Keycode::Y, CTRL),
515 "^Z" => (Keycode::Z, CTRL),
516 "^_" => (Keycode::Minus, SHIFT | CTRL),
517 "^?" => (Keycode::Backspace, EMPTY),
518 "^[" => (Keycode::Escape, EMPTY), "^@" => (Keycode::Key2, CTRL),
521 "KEY_PAUSE" => (Keycode::Pause, EMPTY),
523 "KEY_SCROLLLOCK" => (Keycode::ScrollLock, EMPTY),
524 "KEY_SDOWN" => (Keycode::Down, SHIFT),
525 "KEY_SUP" => (Keycode::Up, SHIFT),
526 "KEY_B2" => (Keycode::Numpad5, SHIFT),
527 "SHF_PADENTER" => (Keycode::NumpadEnter, SHIFT),
528 "SHF_PADMINUS" => (Keycode::NumpadSubtract, SHIFT),
529 "SHF_PADPLUS" => (Keycode::NumpadAdd, SHIFT),
530 "SHF_PADSLASH" => (Keycode::NumpadDivide, SHIFT),
531 "SHF_PADSTAR" => (Keycode::NumpadMultiply, SHIFT),
532 "KEY_F(25)" => (Keycode::F1, CTRL),
533 "KEY_F(26)" => (Keycode::F2, CTRL),
534 "KEY_F(27)" => (Keycode::F3, CTRL),
535 "KEY_F(28)" => (Keycode::F4, CTRL),
536 "KEY_F(29)" => (Keycode::F5, CTRL),
537 "KEY_F(30)" => (Keycode::F6, CTRL),
538 "KEY_F(31)" => (Keycode::F7, CTRL),
539 "KEY_F(32)" => (Keycode::F8, CTRL),
540 "KEY_F(33)" => (Keycode::F9, CTRL),
541 "KEY_F(34)" => (Keycode::F10, CTRL),
542 "KEY_F(35)" => (Keycode::F11, CTRL),
543 "KEY_F(36)" => (Keycode::F12, CTRL),
544 "KEY_F(37)" => (Keycode::F1, ALT),
545 "KEY_F(38)" => (Keycode::F2, ALT),
546 "KEY_F(39)" => (Keycode::F3, ALT),
547 "KEY_F(40)" => (Keycode::F4, ALT),
548 "KEY_F(41)" => (Keycode::F5, ALT),
549 "KEY_F(42)" => (Keycode::F6, ALT),
550 "KEY_F(43)" => (Keycode::F7, ALT),
551 "KEY_F(44)" => (Keycode::F8, ALT),
552 "KEY_F(45)" => (Keycode::F9, ALT),
553 "KEY_F(46)" => (Keycode::F10, ALT),
554 "KEY_F(47)" => (Keycode::F11, ALT),
555 "KEY_F(48)" => (Keycode::F12, ALT),
556 "CTL_0" => (Keycode::Key0, CTRL),
557 "CTL_1" => (Keycode::Key1, CTRL),
558 "CTL_2" => (Keycode::Key2, CTRL),
559 "CTL_3" => (Keycode::Key3, CTRL),
560 "CTL_4" => (Keycode::Key4, CTRL),
561 "CTL_5" => (Keycode::Key5, CTRL),
562 "CTL_6" => (Keycode::Key6, CTRL),
563 "CTL_7" => (Keycode::Key7, CTRL),
564 "CTL_8" => (Keycode::Key8, CTRL),
565 "CTL_9" => (Keycode::Key9, CTRL),
566 "CTL_DOWN" => (Keycode::Down, CTRL),
567 "CTL_LEFT" => (Keycode::Left, CTRL),
568 "CTL_RIGHT" => (Keycode::Right, CTRL),
569 "CTL_UP" => (Keycode::Up, CTRL),
570 "CTL_PAD0" => (Keycode::Numpad0, CTRL),
571 "CTL_PAD1" => (Keycode::Numpad1, CTRL),
572 "CTL_PAD2" => (Keycode::Numpad2, CTRL),
573 "CTL_PAD3" => (Keycode::Numpad3, CTRL),
574 "CTL_PAD4" => (Keycode::Numpad4, CTRL),
575 "CTL_PAD5" => (Keycode::Numpad5, CTRL),
576 "CTL_PAD6" => (Keycode::Numpad6, CTRL),
577 "CTL_PAD7" => (Keycode::Numpad7, CTRL),
578 "CTL_PAD8" => (Keycode::Numpad8, CTRL),
579 "CTL_PAD9" => (Keycode::Numpad9, CTRL),
580 "CTL_PADENTER" => (Keycode::NumpadEnter, CTRL),
581 "CTL_PADMINUS" => (Keycode::NumpadSubtract, CTRL),
582 "CTL_PADPLUS" => (Keycode::NumpadAdd, CTRL),
583 "CTL_PADSLASH" => (Keycode::NumpadDivide, CTRL),
584 "CTL_PADSTOP" => (Keycode::NumpadDecimal, CTRL),
585 "CTL_PADSTAR" => (Keycode::NumpadMultiply, CTRL),
586 "CTL_BQUOTE" => (Keycode::Grave, CTRL),
587 "CTL_DEL" => (Keycode::Delete, CTRL),
588 "CTL_END" => (Keycode::End, CTRL),
589 "CTL_FLASH" => (Keycode::Slash, CTRL),
590 "CTL_HOME" => (Keycode::Home, CTRL),
591 "CTL_INS" => (Keycode::Insert, CTRL),
592 "CTL_PAUSE" => (Keycode::Pause, CTRL),
593 "CTL_PGDN" => (Keycode::PageDown, CTRL),
594 "CTL_PGUP" => (Keycode::PageUp, CTRL),
595 "CTL_SEMICOLON" => (Keycode::Semicolon, CTRL),
596 "CTL_STOP" => (Keycode::Period, CTRL),
597 "CTL_TAB" => (Keycode::Tab, CTRL),
598 "ALT_0" => (Keycode::Key0, ALT),
599 "ALT_1" => (Keycode::Key1, ALT),
600 "ALT_2" => (Keycode::Key2, ALT),
601 "ALT_3" => (Keycode::Key3, ALT),
602 "ALT_4" => (Keycode::Key4, ALT),
603 "ALT_5" => (Keycode::Key5, ALT),
604 "ALT_6" => (Keycode::Key6, ALT),
605 "ALT_7" => (Keycode::Key7, ALT),
606 "ALT_8" => (Keycode::Key8, ALT),
607 "ALT_9" => (Keycode::Key9, ALT),
608 "ALT_A" => (Keycode::A, ALT),
609 "ALT_B" => (Keycode::B, ALT),
610 "ALT_C" => (Keycode::C, ALT),
611 "ALT_D" => (Keycode::D, ALT),
612 "ALT_E" => (Keycode::E, ALT),
613 "ALT_F" => (Keycode::F, ALT),
614 "ALT_G" => (Keycode::G, ALT),
615 "ALT_H" => (Keycode::H, ALT),
616 "ALT_I" => (Keycode::I, ALT),
617 "ALT_J" => (Keycode::J, ALT),
618 "ALT_K" => (Keycode::K, ALT),
619 "ALT_L" => (Keycode::L, ALT),
620 "ALT_M" => (Keycode::M, ALT),
621 "ALT_N" => (Keycode::N, ALT),
622 "ALT_O" => (Keycode::O, ALT),
623 "ALT_P" => (Keycode::P, ALT),
624 "ALT_Q" => (Keycode::Q, ALT),
625 "ALT_R" => (Keycode::R, ALT),
626 "ALT_S" => (Keycode::S, ALT),
627 "ALT_T" => (Keycode::T, ALT),
628 "ALT_U" => (Keycode::U, ALT),
629 "ALT_V" => (Keycode::V, ALT),
630 "ALT_W" => (Keycode::W, ALT),
631 "ALT_X" => (Keycode::X, ALT),
632 "ALT_Y" => (Keycode::Y, ALT),
633 "ALT_Z" => (Keycode::Z, ALT),
634 "ALT_BKSP" => (Keycode::Backspace, ALT),
635 "ALT_BQUOTE" => (Keycode::Grave, ALT),
636 "ALT_BSLASH" => (Keycode::Backslash, ALT),
637 "^\\" => (Keycode::LBracket, ALT),
638 "ALT_COMMA" => (Keycode::Comma, ALT),
639 "ALT_DEL" => (Keycode::Delete, ALT),
640 "ALT_END" => (Keycode::End, ALT),
641 "ALT_ENTER" => (Keycode::Enter, ALT),
642 "ALT_EQUALS" => (Keycode::Equal, ALT),
643 "ALT_HOME" => (Keycode::Home, ALT),
644 "ALT_INS" => (Keycode::Insert, ALT),
645 "ALT_FQUOTE" => (Keycode::Quote, ALT),
646 "ALT_FSLASH" => (Keycode::Slash, ALT),
647 "ALT_MINUS" => (Keycode::Minus, ALT),
648 "ALT_PGDN" => (Keycode::PageDown, ALT),
649 "ALT_PGUP" => (Keycode::PageUp, ALT),
650 "ALT_RBRACKET" => (Keycode::RBracket, ALT),
651 "ALT_SCROLLLOCK" => (Keycode::ScrollLock, ALT),
652 "ALT_SEMICOLON" => (Keycode::Semicolon, ALT),
653 "ALT_STOP" => (Keycode::Period, ALT),
654 "ALT_PADENTER" => (Keycode::NumpadEnter, ALT),
655 "ALT_PADMINUS" => (Keycode::NumpadSubtract, ALT),
656 "ALT_PADSLASH" => (Keycode::NumpadDivide, ALT),
657 "ALT_PADSTAR" => (Keycode::NumpadMultiply, ALT),
658 "ALT_PADSTOP" => (Keycode::NumpadDecimal, ALT),
659 ch => unhandled (ch)
660 }
661 }
662 },
663 Unknown(_) => unhandled (input),
664 KeyCodeYes => unhandled (input),
665
666 KeyBreak => (Keycode::Pause, EMPTY),
667 KeyDown => (Keycode::Down, EMPTY),
668 KeyUp => (Keycode::Up, EMPTY),
669 KeyLeft => (Keycode::Left, EMPTY),
670 KeyRight => (Keycode::Right, EMPTY),
671 KeyHome => (Keycode::Home, EMPTY),
672 KeyBackspace => (Keycode::Backspace, EMPTY),
673 KeyF0 => unhandled (input),
674 KeyF1 => (Keycode::F1, EMPTY),
675 KeyF2 => (Keycode::F2, EMPTY),
676 KeyF3 => (Keycode::F3, EMPTY),
677 KeyF4 => (Keycode::F4, EMPTY),
678 KeyF5 => (Keycode::F5, EMPTY),
679 KeyF6 => (Keycode::F6, EMPTY),
680 KeyF7 => (Keycode::F7, EMPTY),
681 KeyF8 => (Keycode::F8, EMPTY),
682 KeyF9 => (Keycode::F9, EMPTY),
683 KeyF10 => (Keycode::F10, EMPTY),
684 KeyF11 => (Keycode::F11, EMPTY),
685 KeyF12 => (Keycode::F12, EMPTY),
686 KeyF13 => (Keycode::F13, EMPTY),
687 KeyF14 => (Keycode::F14, EMPTY),
688 KeyF15 => (Keycode::F15, EMPTY),
689
690 KeyDL => unhandled (input),
691 KeyIL => unhandled (input),
692 KeyDC => (Keycode::Delete, EMPTY),
693 KeyIC => (Keycode::Insert, EMPTY),
694 KeyEIC => unhandled (input),
695 KeyClear => unhandled (input),
696 KeyEOS => unhandled (input),
697 KeyEOL => unhandled (input),
698 KeySF => (Keycode::Down, SHIFT),
699 KeySR => (Keycode::Up, SHIFT),
700 KeyNPage => (Keycode::PageDown, EMPTY),
701 KeyPPage => (Keycode::PageUp, EMPTY),
702 KeySTab => unhandled (input), KeyCTab => unhandled (input),
704 KeyCATab => unhandled (input),
705 KeyEnter => (Keycode::Enter, EMPTY),
706 KeySReset => unhandled (input),
707 KeyReset => unhandled (input),
708 KeyPrint => unhandled (input),
709 KeyLL => unhandled (input),
710 KeyAbort => unhandled (input),
711 KeySHelp => unhandled (input),
712 KeyLHelp => unhandled (input),
713 KeyBTab => (Keycode::Tab, SHIFT),
714 KeyBeg => unhandled (input),
715 KeyCancel => unhandled (input),
716 KeyClose => unhandled (input),
717 KeyCommand => unhandled (input),
718 KeyCopy => (Keycode::Copy, EMPTY),
719 KeyCreate => unhandled (input),
720 KeyEnd => (Keycode::End, EMPTY),
721 KeyExit => unhandled (input),
722 KeyFind => unhandled (input),
723 KeyHelp => unhandled (input),
724 KeyMark => unhandled (input),
725 KeyMessage => unhandled (input),
726 KeyMove => unhandled (input),
727 KeyNext => unhandled (input),
728 KeyOpen => unhandled (input),
729 KeyOptions => unhandled (input),
730 KeyPrevious => unhandled (input),
731 KeyRedo => unhandled (input),
732 KeyReference => unhandled (input),
733 KeyRefresh => unhandled (input),
734 KeyReplace => unhandled (input),
735 KeyRestart => unhandled (input),
736 KeyResume => unhandled (input),
737 KeySave => unhandled (input),
738 KeySBeg => unhandled (input),
739 KeySCancel => unhandled (input),
740 KeySCommand => unhandled (input),
741 KeySCopy => unhandled (input),
742 KeySCreate => unhandled (input),
743 KeySDC => (Keycode::Delete, SHIFT),
744 KeySDL => unhandled (input),
745 KeySelect => unhandled (input),
746 KeySEnd => (Keycode::End, SHIFT),
747 KeySEOL => unhandled (input),
748 KeySExit => unhandled (input),
749 KeySFind => unhandled (input),
750 KeySHome => (Keycode::Home, SHIFT),
751 KeySIC => (Keycode::Insert, SHIFT),
752
753 KeySLeft | KeySMessage => (Keycode::Left, SHIFT),
755 KeySMove => unhandled (input),
756 KeySNext => (Keycode::PageDown, SHIFT),
757 KeySOptions => unhandled (input),
758 KeySPrevious => (Keycode::PageUp, SHIFT),
759 KeySPrint => unhandled (input),
760 KeySRedo => unhandled (input),
761 KeySReplace => unhandled (input),
762 KeySRight | KeySResume => (Keycode::Right, SHIFT),
764 KeySSave => unhandled (input),
765 KeySSuspend => unhandled (input),
766 KeySUndo => unhandled (input),
767 KeySuspend => unhandled (input),
768 KeyUndo => unhandled (input),
769
770 KeyResize => return input::System::Resized { width: 0, height: 0 }.into(),
775 KeyEvent => unhandled (input),
776 KeyMouse => unhandled (input),
777
778 KeyA1 => unhandled (input),
779 KeyA3 => unhandled (input),
780 KeyB2 => unhandled (input),
781 KeyC1 => unhandled (input),
782 KeyC3 => unhandled (input)
783 };
784 ( input::Button {
785 variant: keycode.into(),
786 modifiers
787 },
788 input::button::State::Pressed
789 ).into()
790 }
791}
792
793fn char_to_keycode (ch : char)
797 -> (view::input::button::Keycode, view::input::Modifiers)
798{
799 use view::input::Modifiers;
800 use view::input::button::Keycode;
801 const EMPTY : Modifiers = Modifiers::empty();
802 const SHIFT : Modifiers = Modifiers::SHIFT;
803 match ch {
804 'a' => (Keycode::A, EMPTY),
805 'b' => (Keycode::B, EMPTY),
806 'c' => (Keycode::C, EMPTY),
807 'd' => (Keycode::D, EMPTY),
808 'e' => (Keycode::E, EMPTY),
809 'f' => (Keycode::F, EMPTY),
810 'g' => (Keycode::G, EMPTY),
811 'h' => (Keycode::H, EMPTY),
812 'i' => (Keycode::I, EMPTY),
813 'j' => (Keycode::J, EMPTY),
814 'k' => (Keycode::K, EMPTY),
815 'l' => (Keycode::L, EMPTY),
816 'm' => (Keycode::M, EMPTY),
817 'n' => (Keycode::N, EMPTY),
818 'o' => (Keycode::O, EMPTY),
819 'p' => (Keycode::P, EMPTY),
820 'q' => (Keycode::Q, EMPTY),
821 'r' => (Keycode::R, EMPTY),
822 's' => (Keycode::S, EMPTY),
823 't' => (Keycode::T, EMPTY),
824 'u' => (Keycode::U, EMPTY),
825 'v' => (Keycode::V, EMPTY),
826 'w' => (Keycode::W, EMPTY),
827 'x' => (Keycode::X, EMPTY),
828 'y' => (Keycode::Y, EMPTY),
829 'z' => (Keycode::Z, EMPTY),
830 '1' => (Keycode::Key1, EMPTY),
831 '2' => (Keycode::Key2, EMPTY),
832 '3' => (Keycode::Key3, EMPTY),
833 '4' => (Keycode::Key4, EMPTY),
834 '5' => (Keycode::Key5, EMPTY),
835 '6' => (Keycode::Key6, EMPTY),
836 '7' => (Keycode::Key7, EMPTY),
837 '8' => (Keycode::Key8, EMPTY),
838 '9' => (Keycode::Key9, EMPTY),
839 '0' => (Keycode::Key0, EMPTY),
840 '-' => (Keycode::Minus, EMPTY),
841 '=' => (Keycode::Equal, EMPTY),
842 '`' => (Keycode::Grave, EMPTY),
843 '[' => (Keycode::LBracket, EMPTY),
844 ']' => (Keycode::RBracket, EMPTY),
845 '\\' => (Keycode::Backslash, EMPTY),
846 ';' => (Keycode::Semicolon, EMPTY),
847 '\'' => (Keycode::Quote, EMPTY),
848 ',' => (Keycode::Comma, EMPTY),
849 '.' => (Keycode::Period, EMPTY),
850 '/' => (Keycode::Slash, EMPTY),
851 'A' => (Keycode::A, SHIFT),
852 'B' => (Keycode::B, SHIFT),
853 'C' => (Keycode::C, SHIFT),
854 'D' => (Keycode::D, SHIFT),
855 'E' => (Keycode::E, SHIFT),
856 'F' => (Keycode::F, SHIFT),
857 'G' => (Keycode::G, SHIFT),
858 'H' => (Keycode::H, SHIFT),
859 'I' => (Keycode::I, SHIFT),
860 'J' => (Keycode::J, SHIFT),
861 'K' => (Keycode::K, SHIFT),
862 'L' => (Keycode::L, SHIFT),
863 'M' => (Keycode::M, SHIFT),
864 'N' => (Keycode::N, SHIFT),
865 'O' => (Keycode::O, SHIFT),
866 'P' => (Keycode::P, SHIFT),
867 'Q' => (Keycode::Q, SHIFT),
868 'R' => (Keycode::R, SHIFT),
869 'S' => (Keycode::S, SHIFT),
870 'T' => (Keycode::T, SHIFT),
871 'U' => (Keycode::U, SHIFT),
872 'V' => (Keycode::V, SHIFT),
873 'W' => (Keycode::W, SHIFT),
874 'X' => (Keycode::X, SHIFT),
875 'Y' => (Keycode::Y, SHIFT),
876 'Z' => (Keycode::Z, SHIFT),
877 '!' => (Keycode::Key1, SHIFT),
878 '@' => (Keycode::Key2, SHIFT),
879 '#' => (Keycode::Key3, SHIFT),
880 '$' => (Keycode::Key4, SHIFT),
881 '%' => (Keycode::Key5, SHIFT),
882 '^' => (Keycode::Key6, SHIFT),
883 '&' => (Keycode::Key7, SHIFT),
884 '*' => (Keycode::Key8, SHIFT),
885 '(' => (Keycode::Key9, SHIFT),
886 ')' => (Keycode::Key0, SHIFT),
887 '_' => (Keycode::Minus, SHIFT),
888 '+' => (Keycode::Equal, SHIFT),
889 '~' => (Keycode::Grave, SHIFT),
890 '{' => (Keycode::LBracket, SHIFT),
891 '}' => (Keycode::RBracket, SHIFT),
892 '|' => (Keycode::Backslash, SHIFT),
893 ':' => (Keycode::Semicolon, SHIFT),
894 '"' => (Keycode::Quote, SHIFT),
895 '<' => (Keycode::Comma, SHIFT),
896 '>' => (Keycode::Period, SHIFT),
897 '?' => (Keycode::Slash, SHIFT),
898 ' ' => (Keycode::Space, EMPTY),
899 '\n' => (Keycode::Enter, EMPTY),
900 '\t' => (Keycode::Tab, EMPTY),
901 _ => unreachable!()
902 }
903}
904
905const fn convert_color (color : view::Color)
906 -> Result <easycurses::Color, view::Color>
907{
908 use view::color::*;
909 let color = match color {
910 Color::Named (named) => match named {
911 Named::Monochrome (Monochrome::White) => easycurses::Color::White,
912 Named::Monochrome (Monochrome::Grey) => return Err (color),
913 Named::Monochrome (Monochrome::Black) => easycurses::Color::Black,
914 Named::Hue (hue) => match hue {
915 Hue::Primary (Primary::Red) => easycurses::Color::Red,
916 Hue::Primary (Primary::Green) => easycurses::Color::Green,
917 Hue::Primary (Primary::Blue) => easycurses::Color::Blue,
918 Hue::Secondary (Secondary::Cyan) => easycurses::Color::Cyan,
919 Hue::Secondary (Secondary::Yellow) => easycurses::Color::Yellow,
920 Hue::Secondary (Secondary::Magenta) => easycurses::Color::Magenta,
921 _ => return Err (color)
922 }
923 },
924 Color::Raw (_) => return Err (color)
925 };
926 Ok (color)
927}