ui: correctly turn on/off terminal attributes in draw_horizontal_segment()
`Attr` (terminal attributes such as bold, underline, etc) were not being printed properly: their bitmap representation was printed instead of the correct ANSI codes to turn them on/off. This worked so far because the attributes and {fore,back}ground color was reset in every character print. draw_horizontal_segment() now keeps state of current_{fg,bg,attr} to keep from resetting in each column draw.async
parent
77d9cef6fc
commit
3c7328d901
|
@ -491,39 +491,32 @@ impl State {
|
||||||
cursor::Goto(x_start as u16 + 1, (y + 1) as u16)
|
cursor::Goto(x_start as u16 + 1, (y + 1) as u16)
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let mut current_fg = Color::Default;
|
||||||
|
let mut current_bg = Color::Default;
|
||||||
|
let mut current_attrs = Attr::Default;
|
||||||
|
let Self {
|
||||||
|
ref grid,
|
||||||
|
ref mut stdout,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
let stdout = stdout.as_mut().unwrap();
|
||||||
|
write!(stdout, "\x1B[m").unwrap();
|
||||||
for x in x_start..=x_end {
|
for x in x_start..=x_end {
|
||||||
let c = self.grid[(x, y)];
|
let c = &grid[(x, y)];
|
||||||
if c.bg() != Color::Default {
|
if c.attrs() != current_attrs {
|
||||||
c.bg().write_bg(self.stdout()).unwrap();
|
c.attrs().write(current_attrs, stdout).unwrap();
|
||||||
|
current_attrs = c.attrs();
|
||||||
}
|
}
|
||||||
if c.fg() != Color::Default {
|
if c.bg() != current_bg {
|
||||||
c.fg().write_fg(self.stdout()).unwrap();
|
c.bg().write_bg(stdout).unwrap();
|
||||||
|
current_bg = c.bg();
|
||||||
}
|
}
|
||||||
if c.attrs() != Attr::Default {
|
if c.fg() != current_fg {
|
||||||
write!(self.stdout(), "\x1B[{}m", c.attrs() as u8).unwrap();
|
c.fg().write_fg(stdout).unwrap();
|
||||||
|
current_fg = c.fg();
|
||||||
}
|
}
|
||||||
if !c.empty() {
|
if !c.empty() {
|
||||||
write!(self.stdout(), "{}", c.ch()).unwrap();
|
write!(stdout, "{}", c.ch()).unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
if c.bg() != Color::Default {
|
|
||||||
write!(
|
|
||||||
self.stdout(),
|
|
||||||
"{}",
|
|
||||||
termion::color::Bg(termion::color::Reset)
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
if c.fg() != Color::Default {
|
|
||||||
write!(
|
|
||||||
self.stdout(),
|
|
||||||
"{}",
|
|
||||||
termion::color::Fg(termion::color::Reset)
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
if c.attrs() != Attr::Default {
|
|
||||||
write!(self.stdout(), "\x1B[{}m", Attr::Default as u8).unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -601,20 +601,23 @@ impl Cell {
|
||||||
self.empty
|
self.empty
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_empty(&mut self, new_val: bool) {
|
pub fn set_empty(&mut self, new_val: bool) -> &mut Cell {
|
||||||
self.empty = new_val;
|
self.empty = new_val;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets `keep_fg` field. If true, the foreground color will not be altered if attempted so
|
/// Sets `keep_fg` field. If true, the foreground color will not be altered if attempted so
|
||||||
/// until the character content of the cell is changed.
|
/// until the character content of the cell is changed.
|
||||||
pub fn set_keep_fg(&mut self, new_val: bool) {
|
pub fn set_keep_fg(&mut self, new_val: bool) -> &mut Cell {
|
||||||
self.keep_fg = new_val;
|
self.keep_fg = new_val;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets `keep_bg` field. If true, the background color will not be altered if attempted so
|
/// Sets `keep_bg` field. If true, the background color will not be altered if attempted so
|
||||||
/// until the character content of the cell is changed.
|
/// until the character content of the cell is changed.
|
||||||
pub fn set_keep_bg(&mut self, new_val: bool) {
|
pub fn set_keep_bg(&mut self, new_val: bool) -> &mut Cell {
|
||||||
self.keep_bg = new_val;
|
self.keep_bg = new_val;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,6 +714,7 @@ impl Color {
|
||||||
pub fn write_fg(self, stdout: &mut crate::StateStdout) -> std::io::Result<()> {
|
pub fn write_fg(self, stdout: &mut crate::StateStdout) -> std::io::Result<()> {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
match self {
|
match self {
|
||||||
|
Color::Default => write!(stdout, "{}", termion::color::Fg(termion::color::Reset)),
|
||||||
Color::Rgb(r, g, b) => write!(stdout, "{}", termion::color::Fg(TermionRgb(r, g, b))),
|
Color::Rgb(r, g, b) => write!(stdout, "{}", termion::color::Fg(TermionRgb(r, g, b))),
|
||||||
_ => write!(stdout, "{}", termion::color::Fg(self.as_termion())),
|
_ => write!(stdout, "{}", termion::color::Fg(self.as_termion())),
|
||||||
}
|
}
|
||||||
|
@ -719,6 +723,7 @@ impl Color {
|
||||||
pub fn write_bg(self, stdout: &mut crate::StateStdout) -> std::io::Result<()> {
|
pub fn write_bg(self, stdout: &mut crate::StateStdout) -> std::io::Result<()> {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
match self {
|
match self {
|
||||||
|
Color::Default => write!(stdout, "{}", termion::color::Bg(termion::color::Reset)),
|
||||||
Color::Rgb(r, g, b) => write!(stdout, "{}", termion::color::Bg(TermionRgb(r, g, b))),
|
Color::Rgb(r, g, b) => write!(stdout, "{}", termion::color::Bg(TermionRgb(r, g, b))),
|
||||||
_ => write!(stdout, "{}", termion::color::Bg(self.as_termion())),
|
_ => write!(stdout, "{}", termion::color::Bg(self.as_termion())),
|
||||||
}
|
}
|
||||||
|
@ -1001,6 +1006,7 @@ impl Color {
|
||||||
"Yellow4" => 100,
|
"Yellow4" => 100,
|
||||||
"Yellow5" => 106,
|
"Yellow5" => 106,
|
||||||
"Yellow6" => 148,
|
"Yellow6" => 148,
|
||||||
|
"Default" => return Ok(Color::Default),
|
||||||
s if s.starts_with("#")
|
s if s.starts_with("#")
|
||||||
&& s.len() == 7
|
&& s.len() == 7
|
||||||
&& s[1..].as_bytes().iter().all(|&b| {
|
&& s[1..].as_bytes().iter().all(|&b| {
|
||||||
|
@ -1388,6 +1394,14 @@ pub enum Attr {
|
||||||
BoldReverseUnderline = 0b111,
|
BoldReverseUnderline = 0b111,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl core::ops::BitAnd for Attr {
|
||||||
|
type Output = bool;
|
||||||
|
|
||||||
|
fn bitand(self, rhs: Self) -> Self::Output {
|
||||||
|
self as u8 & rhs as u8 > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Attr {
|
impl Default for Attr {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Attr::Default
|
Attr::Default
|
||||||
|
@ -1442,6 +1456,24 @@ impl Attr {
|
||||||
_ => Err(de::Error::custom("invalid attr value")),
|
_ => Err(de::Error::custom("invalid attr value")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn write(self, prev: Attr, stdout: &mut crate::StateStdout) -> std::io::Result<()> {
|
||||||
|
use std::io::Write;
|
||||||
|
match (self & Attr::Bold, prev & Attr::Bold) {
|
||||||
|
(true, true) | (false, false) => Ok(()),
|
||||||
|
(false, true) => write!(stdout, "\x1B[22m"),
|
||||||
|
(true, false) => write!(stdout, "\x1B[1m"),
|
||||||
|
}
|
||||||
|
.and_then(|_| match (self & Attr::Underline, prev & Attr::Underline) {
|
||||||
|
(true, true) | (false, false) => Ok(()),
|
||||||
|
(false, true) => write!(stdout, "\x1B[24m"),
|
||||||
|
(true, false) => write!(stdout, "\x1B[4m"),
|
||||||
|
})
|
||||||
|
.and_then(|_| match (self & Attr::Reverse, prev & Attr::Reverse) {
|
||||||
|
(true, true) | (false, false) => Ok(()),
|
||||||
|
(false, true) => write!(stdout, "\x1B[27m"),
|
||||||
|
(true, false) => write!(stdout, "\x1B[7m"),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_area_with_break(
|
pub fn copy_area_with_break(
|
||||||
|
@ -1542,26 +1574,27 @@ pub fn copy_area(grid_dest: &mut CellBuffer, grid_src: &CellBuffer, dest: Area,
|
||||||
|
|
||||||
/// Change foreground and background colors in an `Area`
|
/// Change foreground and background colors in an `Area`
|
||||||
pub fn change_colors(grid: &mut CellBuffer, area: Area, fg_color: Color, bg_color: Color) {
|
pub fn change_colors(grid: &mut CellBuffer, area: Area, fg_color: Color, bg_color: Color) {
|
||||||
let bounds = grid.size();
|
if cfg!(feature = "debug-tracing") {
|
||||||
let upper_left = upper_left!(area);
|
let bounds = grid.size();
|
||||||
let bottom_right = bottom_right!(area);
|
let upper_left = upper_left!(area);
|
||||||
let (x, y) = upper_left;
|
let bottom_right = bottom_right!(area);
|
||||||
if y > (get_y(bottom_right))
|
let (x, y) = upper_left;
|
||||||
|| x > get_x(bottom_right)
|
if y > (get_y(bottom_right))
|
||||||
|| y >= get_y(bounds)
|
|| x > get_x(bottom_right)
|
||||||
|| x >= get_x(bounds)
|
|| y >= get_y(bounds)
|
||||||
{
|
|| x >= get_x(bounds)
|
||||||
debug!("BUG: Invalid area in change_colors:\n area: {:?}", area);
|
{
|
||||||
return;
|
debug!("BUG: Invalid area in change_colors:\n area: {:?}", area);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if !is_valid_area!(area) {
|
||||||
|
debug!("BUG: Invalid area in change_colors:\n area: {:?}", area);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !is_valid_area!(area) {
|
for row in grid.bounds_iter(area) {
|
||||||
debug!("BUG: Invalid area in change_colors:\n area: {:?}", area);
|
for c in row {
|
||||||
return;
|
grid[c].set_fg(fg_color).set_bg(bg_color);
|
||||||
}
|
|
||||||
for y in get_y(upper_left!(area))..=get_y(bottom_right!(area)) {
|
|
||||||
for x in get_x(upper_left!(area))..=get_x(bottom_right!(area)) {
|
|
||||||
grid[(x, y)].set_fg(fg_color);
|
|
||||||
grid[(x, y)].set_bg(bg_color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1648,9 +1681,10 @@ pub fn write_string_to_grid(
|
||||||
} else {
|
} else {
|
||||||
grid[(x, y)].set_ch(c);
|
grid[(x, y)].set_ch(c);
|
||||||
}
|
}
|
||||||
grid[(x, y)].set_attrs(attrs);
|
grid[(x, y)]
|
||||||
grid[(x, y)].set_fg(fg_color);
|
.set_fg(fg_color)
|
||||||
grid[(x, y)].set_bg(bg_color);
|
.set_bg(bg_color)
|
||||||
|
.set_attrs(attrs);
|
||||||
|
|
||||||
match wcwidth(u32::from(c)) {
|
match wcwidth(u32::from(c)) {
|
||||||
Some(0) | None => {
|
Some(0) | None => {
|
||||||
|
@ -1663,10 +1697,11 @@ pub fn write_string_to_grid(
|
||||||
x += 1;
|
x += 1;
|
||||||
inspect_bounds!(grid, area, x, y, line_break);
|
inspect_bounds!(grid, area, x, y, line_break);
|
||||||
grid[(x, y)] = Cell::default();
|
grid[(x, y)] = Cell::default();
|
||||||
grid[(x, y)].set_attrs(attrs);
|
grid[(x, y)]
|
||||||
grid[(x, y)].set_fg(fg_color);
|
.set_fg(fg_color)
|
||||||
grid[(x, y)].set_bg(bg_color);
|
.set_bg(bg_color)
|
||||||
grid[(x, y)].empty = true;
|
.set_attrs(attrs)
|
||||||
|
.set_empty(true);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue