use crate::grid::{GridCell, GridCellFlags};
use crate::input::{GridAttr, COLOUR_DEFAULT, COLOUR_TERMINAL};
use crate::style::{style_parse, Style, StyleCell};
use super::Screen;
impl Screen {
#[must_use]
pub fn has_selected_cells(&self) -> bool {
self.has_selected_cells
}
pub fn mark_selected_row_range(&mut self, row: u32, start_x: u32, end_x: u32) {
let line_width = self.grid.sx();
if row >= self.grid.sy() || line_width == 0 {
return;
}
let Some(line) = self.grid.visible_line_mut(row) else {
return;
};
let start_x = start_x.min(line_width.saturating_sub(1));
let end_x = end_x.min(line_width.saturating_sub(1));
if start_x > end_x {
return;
}
let start_x = line.owning_cell_x(start_x).unwrap_or(start_x);
let end_x = line.owning_cell_x(end_x).unwrap_or(end_x);
let mut touched = false;
let mut x = start_x;
while x <= end_x {
let owner_x = line.owning_cell_x(x).unwrap_or(x);
let width = line
.cell(owner_x)
.map(|cell| u32::from(cell.width().max(1)))
.unwrap_or(1);
for offset in 0..width {
let cell_x = owner_x.saturating_add(offset);
if let Some(cell) = line.cell_mut(cell_x) {
let mut flags = cell.flags();
flags.insert(GridCellFlags::SELECTED);
cell.set_flags(flags);
self.has_selected_cells = true;
touched = true;
}
}
x = owner_x.saturating_add(width.max(1));
}
if touched {
line.touch();
}
}
pub fn clear_selected_cells(&mut self) {
if !self.has_selected_cells {
return;
}
let width = self.grid.sx();
for row in 0..self.grid.sy() {
let Some(line) = self.grid.visible_line_mut(row) else {
continue;
};
let mut touched = false;
for x in 0..width {
let Some(cell) = line.cell_mut(x) else {
continue;
};
if !cell.flags().contains(GridCellFlags::SELECTED) {
continue;
}
let mut flags = cell.flags();
flags.remove(GridCellFlags::SELECTED);
cell.set_flags(flags);
touched = true;
}
if touched {
line.touch();
}
}
self.has_selected_cells = false;
}
pub fn overlay_style_on_selected(&mut self, style_input: &str) {
if style_input.is_empty() {
self.clear_selected_cells();
return;
}
let Some(style) = parse_cell_overlay_style(style_input) else {
return;
};
let width = self.grid.sx();
for row in 0..self.grid.sy() {
let Some(line) = self.grid.visible_line_mut(row) else {
continue;
};
let mut touched = false;
for x in 0..width {
let Some(cell) = line.cell_mut(x) else {
continue;
};
if !cell.flags().contains(GridCellFlags::SELECTED) || cell.is_padding() {
continue;
}
apply_cell_overlay_style(cell, &style);
touched = true;
}
if touched {
line.touch();
}
}
self.clear_selected_cells();
}
pub fn overlay_style_on_row_range(
&mut self,
row: u32,
start_x: u32,
end_x: u32,
style: &Style,
) {
if row >= self.grid.sy() || self.grid.sx() == 0 {
return;
}
let line_width = self.grid.sx();
let Some(line) = self.grid.visible_line_mut(row) else {
return;
};
let start_x = start_x.min(line_width.saturating_sub(1));
let end_x = end_x.min(line_width.saturating_sub(1));
if start_x > end_x {
return;
}
let start_x = line.owning_cell_x(start_x).unwrap_or(start_x);
let end_x = line.owning_cell_x(end_x).unwrap_or(end_x);
let mut touched = false;
let mut x = start_x;
while x <= end_x {
let owner_x = line.owning_cell_x(x).unwrap_or(x);
let width = line
.cell(owner_x)
.map(|cell| u32::from(cell.width().max(1)))
.unwrap_or(1);
if let Some(cell) = line.cell_mut(owner_x) {
if !cell.is_padding() {
apply_cell_overlay_style(cell, style);
touched = true;
}
}
let next = owner_x.saturating_add(width.max(1));
if next <= x {
break;
}
x = next;
}
if touched {
line.touch();
}
}
}
fn parse_cell_overlay_style(style_input: &str) -> Option<Style> {
let base = StyleCell::default();
let mut style = Style::with_cell(base);
style_parse(&mut style, &base, style_input).ok()?;
Some(style)
}
fn apply_cell_overlay_style(cell: &mut GridCell, style: &Style) {
let fg_set = !matches!(style.cell.fg, COLOUR_DEFAULT | COLOUR_TERMINAL);
let bg_set = !matches!(style.cell.bg, COLOUR_DEFAULT | COLOUR_TERMINAL);
let style_attr = style.cell.attr & !GridAttr::NOATTR;
let attr = if style.cell.attr & GridAttr::NOATTR != 0 || (fg_set && bg_set) {
style_attr | (cell.attr() & GridAttr::CHARSET)
} else {
style_attr | cell.attr()
};
cell.set_attr(attr);
if fg_set {
cell.set_fg(style.cell.fg);
}
if bg_set {
cell.set_bg(style.cell.bg);
}
cell.set_us(style.cell.us);
}