1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
//! Define the backend trait for actual terminal interaction. //! //! Cursive doesn't print anything by itself: it delegates this job to a //! backend library, which handles all actual input and output. //! //! This module defines the [`Backend`] trait, to be implemented by actual //! types, usually using third-party libraries. //! //! [`Backend`]: trait.Backend.html use crate::event::Event; use crate::theme; use crate::Vec2; use unicode_width::UnicodeWidthStr; /// Trait defining the required methods to be a backend. /// /// A backend is the interface between the abstract view tree and the actual /// input/output, like a terminal. /// /// It usually delegates the work to a terminal-handling library like ncurses /// or termion, or it can entirely simulate a terminal and show it as a /// graphical window (`BearLibTerminal`). /// /// When creating a new cursive tree with [`Cursive::new()`][1], you will need to /// provide a backend initializer - usually their `init()` function. /// /// Backends are responsible for handling input and converting it to [`Event`]. /// Input must be non-blocking, it will be polled regularly. /// /// [1]: ../struct.Cursive.html#method.new /// [`Event`]: ../event/enum.Event.html pub trait Backend { /// Polls the backend for any input. /// /// Should return immediately: /// * `None` if no event is currently available. /// * `Some(event)` for each event to process. fn poll_event(&mut self) -> Option<Event>; /// Refresh the screen. /// /// This will be called each frame after drawing has been done. /// /// A backend could, for example, buffer any print command, and apply /// everything when refresh() is called. fn refresh(&mut self); /// Should return `true` if this backend supports colors. fn has_colors(&self) -> bool; /// Returns the screen size. fn screen_size(&self) -> Vec2; /// Main method used for printing fn print_at(&self, pos: Vec2, text: &str); /// Efficient method to print repetitions of the same text. /// /// Usually used to draw horizontal lines/borders. /// /// It is a small optimization to avoid moving the cursor after each step. fn print_at_rep(&self, pos: Vec2, repetitions: usize, text: &str) { if repetitions > 0 { self.print_at(pos, text); let width = text.width(); let mut pos = pos; let mut dupes_left = repetitions - 1; while dupes_left > 0 { pos = pos.saturating_add((width, 0)); self.print_at(pos, text); dupes_left -= 1; } } } /// Clears the screen with the given color. fn clear(&self, color: theme::Color); /// Starts using a new color. /// /// This should return the previously active color. /// /// Any call to `print_at` from now on should use the given color. fn set_color(&self, colors: theme::ColorPair) -> theme::ColorPair; /// Enables the given effect. /// /// Any call to `print_at` from now on should use the given effect. fn set_effect(&self, effect: theme::Effect); /// Disables the given effect. fn unset_effect(&self, effect: theme::Effect); /// Returns a name to identify the backend. /// /// Mostly used for debugging. fn name(&self) -> &str { "unknown" } } /// Dummy backend that does nothing and immediately exits. /// /// Mostly used for testing. pub struct Dummy; impl Dummy { /// Creates a new dummy backend. pub fn init() -> Box<dyn Backend> where Self: Sized, { Box::new(Dummy) } } impl Backend for Dummy { fn name(&self) -> &str { "dummy" } fn refresh(&mut self) {} fn has_colors(&self) -> bool { false } fn screen_size(&self) -> Vec2 { (1, 1).into() } fn poll_event(&mut self) -> Option<Event> { Some(Event::Exit) } fn print_at(&self, _: Vec2, _: &str) {} fn print_at_rep(&self, _pos: Vec2, _repetitions: usize, _text: &str) {} fn clear(&self, _: theme::Color) {} // This sets the Colours and returns the previous colours // to allow you to set them back when you're done. fn set_color(&self, colors: theme::ColorPair) -> theme::ColorPair { // TODO: actually save a stack of colors? colors } fn set_effect(&self, _: theme::Effect) {} fn unset_effect(&self, _: theme::Effect) {} }