You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

775 lines
21KB

  1. /*
  2. * meli - ui crate.
  3. *
  4. * Copyright 2017-2018 Manos Pitsidianakis
  5. *
  6. * This file is part of meli.
  7. *
  8. * meli is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * meli is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with meli. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. /*!
  22. Define a (x, y) point in the terminal display as a holder of a character, foreground/background
  23. colors and attributes.
  24. */
  25. use super::position::*;
  26. use std::convert::From;
  27. use std::fmt;
  28. use std::ops::{Deref, DerefMut, Index, IndexMut};
  29. use termion::color::AnsiValue;
  30. /// Types and implementations taken from rustty for convenience.
  31. pub trait CellAccessor: HasSize {
  32. fn cellvec(&self) -> &Vec<Cell>;
  33. fn cellvec_mut(&mut self) -> &mut Vec<Cell>;
  34. /// Clears `self`, using the given `Cell` as a blank.
  35. fn clear(&mut self, blank: Cell) {
  36. for cell in self.cellvec_mut().iter_mut() {
  37. *cell = blank;
  38. }
  39. }
  40. fn pos_to_index(&self, x: usize, y: usize) -> Option<usize> {
  41. let (cols, rows) = self.size();
  42. if x < cols && y < rows {
  43. Some((cols * y) + x)
  44. } else {
  45. None
  46. }
  47. }
  48. /// Returns a reference to the `Cell` at the given coordinates, or `None` if the index is out of
  49. /// bounds.
  50. ///
  51. /// # Examples
  52. ///
  53. /// ```norun
  54. /// use rustty::{Terminal, CellAccessor};
  55. ///
  56. /// let mut term = Terminal::new().unwrap();
  57. ///
  58. /// let a_cell = term.get(5, 5);
  59. /// ```
  60. fn get(&self, x: usize, y: usize) -> Option<&Cell> {
  61. match self.pos_to_index(x, y) {
  62. Some(i) => self.cellvec().get(i),
  63. None => None,
  64. }
  65. }
  66. /// Returns a mutable reference to the `Cell` at the given coordinates, or `None` if the index
  67. /// is out of bounds.
  68. ///
  69. /// # Examples
  70. ///
  71. /// ```norun
  72. /// use rustty::{Terminal, CellAccessor};
  73. ///
  74. /// let mut term = Terminal::new().unwrap();
  75. ///
  76. /// let a_mut_cell = term.get_mut(5, 5);
  77. /// ```
  78. fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut Cell> {
  79. match self.pos_to_index(x, y) {
  80. Some(i) => self.cellvec_mut().get_mut(i),
  81. None => None,
  82. }
  83. }
  84. }
  85. /// An array of `Cell`s that represents a terminal display.
  86. ///
  87. /// A `CellBuffer` is a two-dimensional array of `Cell`s, each pair of indices correspond to a
  88. /// single point on the underlying terminal.
  89. ///
  90. /// The first index, `Cellbuffer[y]`, corresponds to a row, and thus the y-axis. The second
  91. /// index, `Cellbuffer[y][x]`, corresponds to a column within a row and thus the x-axis.
  92. #[derive(Clone, PartialEq, Eq)]
  93. pub struct CellBuffer {
  94. cols: usize,
  95. rows: usize,
  96. buf: Vec<Cell>,
  97. }
  98. impl fmt::Debug for CellBuffer {
  99. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  100. write!(
  101. f,
  102. "CellBuffer {{ cols: {}, rows: {}, buf: {} cells",
  103. self.cols,
  104. self.rows,
  105. self.buf.len()
  106. )
  107. }
  108. }
  109. impl CellBuffer {
  110. pub fn area(&self) -> Area {
  111. (
  112. (0, 0),
  113. (self.cols.saturating_sub(1), self.rows.saturating_sub(1)),
  114. )
  115. }
  116. pub fn set_cols(&mut self, new_cols: usize) {
  117. self.cols = new_cols;
  118. }
  119. /// Constructs a new `CellBuffer` with the given number of columns and rows, using the given
  120. /// `cell` as a blank.
  121. pub fn new(cols: usize, rows: usize, cell: Cell) -> CellBuffer {
  122. CellBuffer {
  123. cols,
  124. rows,
  125. buf: vec![cell; cols * rows],
  126. }
  127. }
  128. /// Resizes `CellBuffer` to the given number of rows and columns, using the given `Cell` as
  129. /// a blank.
  130. pub fn resize(&mut self, newcols: usize, newrows: usize, blank: Cell) {
  131. let newlen = newcols * newrows;
  132. if self.buf.len() == newlen {
  133. return;
  134. }
  135. let mut newbuf: Vec<Cell> = Vec::with_capacity(newlen);
  136. for y in 0..newrows {
  137. for x in 0..newcols {
  138. let cell = self.get(x, y).unwrap_or(&blank);
  139. newbuf.push(*cell);
  140. }
  141. }
  142. self.buf = newbuf;
  143. self.cols = newcols;
  144. self.rows = newrows;
  145. }
  146. pub fn split_newlines(self) -> Self {
  147. let lines: Vec<&[Cell]> = self.split(|cell| cell.ch() == '\n').collect();
  148. let height = lines.len();
  149. let width = lines.iter().map(|l| l.len()).max().unwrap_or(0) + 1;
  150. let mut content = CellBuffer::new(width, height, Cell::with_char(' '));
  151. {
  152. let mut x;
  153. let c_slice: &mut [Cell] = &mut content;
  154. for (y, l) in lines.iter().enumerate() {
  155. let y_r = y * width;
  156. x = l.len() + y_r;
  157. c_slice[y_r..x].copy_from_slice(l);
  158. c_slice[x].set_ch('\n');
  159. }
  160. }
  161. content
  162. }
  163. pub fn is_empty(&self) -> bool {
  164. self.buf.is_empty()
  165. }
  166. pub fn empty(&mut self) {
  167. self.buf.clear();
  168. self.cols = 0;
  169. self.rows = 0;
  170. }
  171. }
  172. impl HasSize for CellBuffer {
  173. fn size(&self) -> Size {
  174. (self.cols, self.rows)
  175. }
  176. }
  177. impl CellAccessor for CellBuffer {
  178. fn cellvec(&self) -> &Vec<Cell> {
  179. &self.buf
  180. }
  181. fn cellvec_mut(&mut self) -> &mut Vec<Cell> {
  182. &mut self.buf
  183. }
  184. }
  185. impl Deref for CellBuffer {
  186. type Target = [Cell];
  187. fn deref(&self) -> &[Cell] {
  188. &self.buf
  189. }
  190. }
  191. impl DerefMut for CellBuffer {
  192. fn deref_mut(&mut self) -> &mut [Cell] {
  193. &mut self.buf
  194. }
  195. }
  196. impl Index<Pos> for CellBuffer {
  197. type Output = Cell;
  198. fn index(&self, index: Pos) -> &Cell {
  199. let (x, y) = index;
  200. self.get(x, y).expect("index out of bounds")
  201. }
  202. }
  203. impl IndexMut<Pos> for CellBuffer {
  204. fn index_mut(&mut self, index: Pos) -> &mut Cell {
  205. let (x, y) = index;
  206. self.get_mut(x, y).expect("index out of bounds")
  207. }
  208. }
  209. impl Default for CellBuffer {
  210. /// Constructs a new `CellBuffer` with a size of `(0, 0)`, using the default `Cell` as a blank.
  211. fn default() -> CellBuffer {
  212. CellBuffer::new(0, 0, Cell::default())
  213. }
  214. }
  215. impl<'a> From<&'a str> for CellBuffer {
  216. fn from(s: &'a str) -> Self {
  217. let lines: Vec<&str> = s.lines().map(|l| l.trim_right()).collect();
  218. let len = s.len() + lines.len();
  219. let mut buf = CellBuffer::new(len, 1, Cell::default());
  220. let mut x = 0;
  221. for l in &lines {
  222. for (idx, c) in l.chars().enumerate() {
  223. buf[(x + idx, 0)].set_ch(c);
  224. }
  225. x += l.chars().count();
  226. buf[(x, 0)].set_ch('\n');
  227. x += 1;
  228. }
  229. buf
  230. }
  231. }
  232. impl fmt::Display for CellBuffer {
  233. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  234. '_y: for y in 0..self.rows {
  235. for x in 0..self.cols {
  236. let c: &char = &self[(x, y)].ch();
  237. write!(f, "{}", *c).unwrap();
  238. if *c == '\n' {
  239. continue '_y;
  240. }
  241. }
  242. }
  243. Ok(())
  244. }
  245. }
  246. /// A single point on a terminal display.
  247. ///
  248. /// A `Cell` contains a character and style.
  249. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  250. pub struct Cell {
  251. ch: char,
  252. fg: Color,
  253. bg: Color,
  254. attrs: Attr,
  255. }
  256. impl Cell {
  257. /// Creates a new `Cell` with the given `char`, `Color`s and `Attr`.
  258. ///
  259. /// # Examples
  260. ///
  261. /// ```norun
  262. /// use rustty::{Cell, Color, Attr};
  263. ///
  264. /// let cell = Cell::new('x', Color::Default, Color::Green, Attr::Default);
  265. /// assert_eq!(cell.ch(), 'x');
  266. /// assert_eq!(cell.fg(), Color::Default);
  267. /// assert_eq!(cell.bg(), Color::Green);
  268. /// assert_eq!(cell.attrs(), Attr::Default);
  269. /// ```
  270. pub fn new(ch: char, fg: Color, bg: Color, attrs: Attr) -> Cell {
  271. Cell { ch, fg, bg, attrs }
  272. }
  273. /// Creates a new `Cell` with the given `char` and default style.
  274. ///
  275. /// # Examples
  276. ///
  277. /// ```norun
  278. /// use rustty::{Cell, Color, Attr};
  279. ///
  280. /// let mut cell = Cell::with_char('x');
  281. /// assert_eq!(cell.ch(), 'x');
  282. /// assert_eq!(cell.fg(), Color::Default);
  283. /// assert_eq!(cell.bg(), Color::Default);
  284. /// assert_eq!(cell.attrs(), Attr::Default);
  285. /// ```
  286. pub fn with_char(ch: char) -> Cell {
  287. Cell::new(ch, Color::Default, Color::Default, Attr::Default)
  288. }
  289. /// Creates a new `Cell` with the given style and a blank `char`.
  290. ///
  291. /// # Examples
  292. ///
  293. /// ```norun
  294. /// use rustty::{Cell, Color, Attr};
  295. ///
  296. /// let mut cell = Cell::with_style(Color::Default, Color::Red, Attr::Bold);
  297. /// assert_eq!(cell.fg(), Color::Default);
  298. /// assert_eq!(cell.bg(), Color::Red);
  299. /// assert_eq!(cell.attrs(), Attr::Bold);
  300. /// assert_eq!(cell.ch(), ' ');
  301. /// ```
  302. pub fn with_style(fg: Color, bg: Color, attr: Attr) -> Cell {
  303. Cell::new(' ', fg, bg, attr)
  304. }
  305. /// Returns the `Cell`'s character.
  306. ///
  307. /// # Examples
  308. ///
  309. /// ```norun
  310. /// use rustty::Cell;
  311. ///
  312. /// let mut cell = Cell::with_char('x');
  313. /// assert_eq!(cell.ch(), 'x');
  314. /// ```
  315. pub fn ch(&self) -> char {
  316. self.ch
  317. }
  318. /// Sets the `Cell`'s character to the given `char`
  319. ///
  320. /// # Examples
  321. ///
  322. /// ```norun
  323. /// use rustty::Cell;
  324. ///
  325. /// let mut cell = Cell::with_char('x');
  326. /// assert_eq!(cell.ch(), 'x');
  327. ///
  328. /// cell.set_ch('y');
  329. /// assert_eq!(cell.ch(), 'y');
  330. /// ```
  331. pub fn set_ch(&mut self, newch: char) -> &mut Cell {
  332. self.ch = newch;
  333. self
  334. }
  335. /// Returns the `Cell`'s foreground `Color`.
  336. ///
  337. /// # Examples
  338. ///
  339. /// ```norun
  340. /// use rustty::{Cell, Color, Attr};
  341. ///
  342. /// let mut cell = Cell::with_style(Color::Blue, Color::Default, Attr::Default);
  343. /// assert_eq!(cell.fg(), Color::Blue);
  344. /// ```
  345. pub fn fg(&self) -> Color {
  346. self.fg
  347. }
  348. /// Sets the `Cell`'s foreground `Color` to the given `Color`.
  349. ///
  350. /// # Examples
  351. ///
  352. /// ```norun
  353. /// use rustty::{Cell, Color, Attr};
  354. ///
  355. /// let mut cell = Cell::default();
  356. /// assert_eq!(cell.fg(), Color::Default);
  357. ///
  358. /// cell.set_fg(Color::White);
  359. /// assert_eq!(cell.fg(), Color::White);
  360. /// ```
  361. pub fn set_fg(&mut self, newfg: Color) -> &mut Cell {
  362. self.fg = newfg;
  363. self
  364. }
  365. /// Returns the `Cell`'s background `Color`.
  366. ///
  367. /// # Examples
  368. ///
  369. /// ```norun
  370. /// use rustty::{Cell, Color, Attr};
  371. ///
  372. /// let mut cell = Cell::with_style(Color::Default, Color::Green, Attr::Default);
  373. /// assert_eq!(cell.bg(), Color::Green);
  374. /// ```
  375. pub fn bg(&self) -> Color {
  376. self.bg
  377. }
  378. /// Sets the `Cell`'s background `Color` to the given `Color`.
  379. ///
  380. /// # Examples
  381. ///
  382. /// ```norun
  383. /// use rustty::{Cell, Color, Attr};
  384. ///
  385. /// let mut cell = Cell::default();
  386. /// assert_eq!(cell.bg(), Color::Default);
  387. ///
  388. /// cell.set_bg(Color::Black);
  389. /// assert_eq!(cell.bg(), Color::Black);
  390. /// ```
  391. pub fn set_bg(&mut self, newbg: Color) -> &mut Cell {
  392. self.bg = newbg;
  393. self
  394. }
  395. pub fn attrs(&self) -> Attr {
  396. self.attrs
  397. }
  398. pub fn set_attrs(&mut self, newattrs: Attr) -> &mut Cell {
  399. self.attrs = newattrs;
  400. self
  401. }
  402. }
  403. impl Default for Cell {
  404. /// Constructs a new `Cell` with a blank `char` and default `Color`s.
  405. ///
  406. /// # Examples
  407. ///
  408. /// ```norun
  409. /// use rustty::{Cell, Color};
  410. ///
  411. /// let mut cell = Cell::default();
  412. /// assert_eq!(cell.ch(), ' ');
  413. /// assert_eq!(cell.fg(), Color::Default);
  414. /// assert_eq!(cell.bg(), Color::Default);
  415. /// ```
  416. fn default() -> Cell {
  417. Cell::new(' ', Color::Default, Color::Default, Attr::Default)
  418. }
  419. }
  420. /// The color of a `Cell`.
  421. ///
  422. /// `Color::Default` represents the default color of the underlying terminal.
  423. ///
  424. /// The eight basic colors may be used directly and correspond to 0x00..0x07 in the 8-bit (256)
  425. /// color range; in addition, the eight basic colors coupled with `Attr::Bold` correspond to
  426. /// 0x08..0x0f in the 8-bit color range.
  427. ///
  428. /// `Color::Byte(..)` may be used to specify a color in the 8-bit range.
  429. ///
  430. /// # Examples
  431. ///
  432. /// ```norun
  433. /// use rustty::Color;
  434. ///
  435. /// // The default color.
  436. /// let default = Color::Default;
  437. ///
  438. /// // A basic color.
  439. /// let red = Color::Red;
  440. ///
  441. /// // An 8-bit color.
  442. /// let fancy = Color::Byte(0x01);
  443. ///
  444. /// // Basic colors are also 8-bit colors (but not vice-versa).
  445. /// assert_eq!(red.as_byte(), fancy.as_byte())
  446. /// ```
  447. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  448. pub enum Color {
  449. Black,
  450. Red,
  451. Green,
  452. Yellow,
  453. Blue,
  454. Magenta,
  455. Cyan,
  456. White,
  457. Byte(u8),
  458. Default,
  459. }
  460. impl Color {
  461. /// Returns the `u8` representation of the `Color`.
  462. pub fn as_byte(self) -> u8 {
  463. match self {
  464. Color::Black => 0x00,
  465. Color::Red => 0x01,
  466. Color::Green => 0x02,
  467. Color::Yellow => 0x03,
  468. Color::Blue => 0x04,
  469. Color::Magenta => 0x05,
  470. Color::Cyan => 0x06,
  471. Color::White => 0x07,
  472. Color::Byte(b) => b,
  473. Color::Default => 0x00,
  474. }
  475. }
  476. pub fn as_termion(self) -> AnsiValue {
  477. match self {
  478. b @ Color::Black
  479. | b @ Color::Red
  480. | b @ Color::Green
  481. | b @ Color::Yellow
  482. | b @ Color::Blue
  483. | b @ Color::Magenta
  484. | b @ Color::Cyan
  485. | b @ Color::White
  486. | b @ Color::Default => AnsiValue(b.as_byte()),
  487. Color::Byte(b) => AnsiValue(b as u8),
  488. }
  489. }
  490. }
  491. /// The attributes of a `Cell`.
  492. ///
  493. /// `Attr` enumerates all combinations of attributes a given style may have.
  494. ///
  495. /// `Attr::Default` represents no attribute.
  496. ///
  497. /// # Examples
  498. ///
  499. /// ```norun
  500. /// use rustty::Attr;
  501. ///
  502. /// // Default attribute.
  503. /// let def = Attr::Default;
  504. ///
  505. /// // Base attribute.
  506. /// let base = Attr::Bold;
  507. ///
  508. /// // Combination.
  509. /// let comb = Attr::UnderlineReverse;
  510. /// ```
  511. #[derive(Debug, Copy, Clone, PartialEq, Eq)]
  512. pub enum Attr {
  513. Default = 0b000,
  514. Bold = 0b001,
  515. Underline = 0b010,
  516. BoldUnderline = 0b011,
  517. Reverse = 0b100,
  518. BoldReverse = 0b101,
  519. UnderlineReverse = 0b110,
  520. BoldReverseUnderline = 0b111,
  521. }
  522. // TODO: word break.
  523. pub fn copy_area_with_break(
  524. grid_dest: &mut CellBuffer,
  525. grid_src: &CellBuffer,
  526. dest: Area,
  527. src: Area,
  528. ) -> Pos {
  529. if !is_valid_area!(dest) || !is_valid_area!(src) {
  530. debug!(
  531. "BUG: Invalid areas in copy_area:\n src: {:?}\n dest: {:?}",
  532. src, dest
  533. );
  534. return upper_left!(dest);
  535. }
  536. if grid_src.is_empty() || grid_dest.is_empty() {
  537. return upper_left!(dest);
  538. }
  539. let mut ret = bottom_right!(dest);
  540. let mut src_x = get_x(upper_left!(src));
  541. let mut src_y = get_y(upper_left!(src));
  542. 'y_: for y in get_y(upper_left!(dest))..=get_y(bottom_right!(dest)) {
  543. 'x_: for x in get_x(upper_left!(dest))..=get_x(bottom_right!(dest)) {
  544. if grid_src[(src_x, src_y)].ch() == '\n' {
  545. src_y += 1;
  546. src_x = 0;
  547. if src_y >= get_y(bottom_right!(src)) {
  548. ret.1 = y;
  549. break 'y_;
  550. }
  551. continue 'y_;
  552. }
  553. grid_dest[(x, y)] = grid_src[(src_x, src_y)];
  554. src_x += 1;
  555. if src_x >= get_x(bottom_right!(src)) {
  556. src_y += 1;
  557. src_x = 0;
  558. if src_y >= get_y(bottom_right!(src)) {
  559. //clear_area(grid_dest, ((get_x(upper_left!(dest)), y), bottom_right!(dest)));
  560. ret.1 = y;
  561. break 'y_;
  562. }
  563. break 'x_;
  564. }
  565. }
  566. }
  567. ret
  568. }
  569. /// Copy a source `Area` to a destination.
  570. pub fn copy_area(grid_dest: &mut CellBuffer, grid_src: &CellBuffer, dest: Area, src: Area) -> Pos {
  571. if !is_valid_area!(dest) || !is_valid_area!(src) {
  572. debug!(
  573. "BUG: Invalid areas in copy_area:\n src: {:?}\n dest: {:?}",
  574. src, dest
  575. );
  576. return upper_left!(dest);
  577. }
  578. if grid_src.is_empty() || grid_dest.is_empty() {
  579. return upper_left!(dest);
  580. }
  581. let mut ret = bottom_right!(dest);
  582. let mut src_x = get_x(upper_left!(src));
  583. let mut src_y = get_y(upper_left!(src));
  584. let (cols, rows) = grid_src.size();
  585. if src_x >= cols || src_y >= rows {
  586. debug!("BUG: src area outside of grid_src in copy_area",);
  587. return upper_left!(dest);
  588. }
  589. for y in get_y(upper_left!(dest))..=get_y(bottom_right!(dest)) {
  590. 'for_x: for x in get_x(upper_left!(dest))..=get_x(bottom_right!(dest)) {
  591. grid_dest[(x, y)] = grid_src[(src_x, src_y)];
  592. if src_x >= get_x(bottom_right!(src)) {
  593. break 'for_x;
  594. }
  595. src_x += 1;
  596. }
  597. src_x = get_x(upper_left!(src));
  598. src_y += 1;
  599. if src_y > get_y(bottom_right!(src)) {
  600. clear_area(
  601. grid_dest,
  602. ((get_x(upper_left!(dest)), y + 1), bottom_right!(dest)),
  603. );
  604. ret.1 = y;
  605. break;
  606. }
  607. }
  608. ret
  609. }
  610. /// Change foreground and background colors in an `Area`
  611. pub fn change_colors(grid: &mut CellBuffer, area: Area, fg_color: Color, bg_color: Color) {
  612. let bounds = grid.size();
  613. let upper_left = upper_left!(area);
  614. let bottom_right = bottom_right!(area);
  615. let (x, y) = upper_left;
  616. if y > (get_y(bottom_right))
  617. || x > get_x(bottom_right)
  618. || y >= get_y(bounds)
  619. || x >= get_x(bounds)
  620. {
  621. debug!("BUG: Invalid area in change_colors:\n area: {:?}", area);
  622. return;
  623. }
  624. if !is_valid_area!(area) {
  625. debug!("BUG: Invalid area in change_colors:\n area: {:?}", area);
  626. return;
  627. }
  628. for y in get_y(upper_left!(area))..=get_y(bottom_right!(area)) {
  629. for x in get_x(upper_left!(area))..=get_x(bottom_right!(area)) {
  630. grid[(x, y)].set_fg(fg_color);
  631. grid[(x, y)].set_bg(bg_color);
  632. }
  633. }
  634. }
  635. macro_rules! inspect_bounds {
  636. ($grid:ident, $area:ident, $x: ident, $y: ident, $line_break:ident) => {
  637. let bounds = $grid.size();
  638. let (upper_left, bottom_right) = $area;
  639. if $x == (get_x(bottom_right)) + 1 || $x > get_x(bounds) {
  640. $x = get_x(upper_left);
  641. $y += 1;
  642. if $y > (get_y(bottom_right)) || $y > get_y(bounds) {
  643. return ($x, $y - 1);
  644. }
  645. if !$line_break {
  646. break;
  647. }
  648. }
  649. };
  650. }
  651. /// Write an `&str` to a `CellBuffer` in a specified `Area` with the passed colors.
  652. pub fn write_string_to_grid(
  653. s: &str,
  654. grid: &mut CellBuffer,
  655. fg_color: Color,
  656. bg_color: Color,
  657. area: Area,
  658. line_break: bool,
  659. ) -> Pos {
  660. let bounds = grid.size();
  661. let upper_left = upper_left!(area);
  662. let bottom_right = bottom_right!(area);
  663. let (mut x, mut y) = upper_left;
  664. if y == get_y(bounds) || x == get_x(bounds) {
  665. return (x, y);
  666. }
  667. if y > (get_y(bottom_right))
  668. || x > get_x(bottom_right)
  669. || y > get_y(bounds)
  670. || x > get_x(bounds)
  671. {
  672. debug!(" Invalid area with string {} and area {:?}", s, area);
  673. return (x, y);
  674. }
  675. for c in s.chars() {
  676. if c == '\r' {
  677. continue;
  678. }
  679. if c == '\t' {
  680. grid[(x, y)].set_ch(' ');
  681. grid[(x, y)].set_fg(fg_color);
  682. grid[(x, y)].set_bg(bg_color);
  683. x += 1;
  684. inspect_bounds!(grid, area, x, y, line_break);
  685. grid[(x, y)].set_ch(' ');
  686. grid[(x, y)].set_fg(fg_color);
  687. grid[(x, y)].set_bg(bg_color);
  688. } else {
  689. grid[(x, y)].set_ch(c);
  690. grid[(x, y)].set_fg(fg_color);
  691. grid[(x, y)].set_bg(bg_color);
  692. }
  693. x += 1;
  694. inspect_bounds!(grid, area, x, y, line_break);
  695. }
  696. (x, y)
  697. }
  698. /// Completely clear an `Area` with an empty char and the terminal's default colors.
  699. pub fn clear_area(grid: &mut CellBuffer, area: Area) {
  700. if !is_valid_area!(area) {
  701. return;
  702. }
  703. let upper_left = upper_left!(area);
  704. let bottom_right = bottom_right!(area);
  705. for y in get_y(upper_left)..=get_y(bottom_right) {
  706. for x in get_x(upper_left)..=get_x(bottom_right) {
  707. grid[(x, y)].set_ch(' ');
  708. grid[(x, y)].set_bg(Color::Default);
  709. grid[(x, y)].set_fg(Color::Default);
  710. }
  711. }
  712. }