use super::super::{BackgroundInstance, Cell, CellRenderer};
use super::powerline;
use par_term_config::{color_u8x4_rgb_to_f32, color_u8x4_rgb_to_f32_a};
pub(super) struct RowBackgroundParams<'a> {
pub row_cells: &'a [Cell],
pub row: usize,
pub cursor_pos: Option<(usize, usize)>,
pub cursor_opacity: f32,
pub content_x: f32,
pub content_y: f32,
pub opacity_multiplier: f32,
pub fill_default_bg_cells: bool,
pub skip_solid_background: bool,
}
struct CursorCellBgParams {
col: usize,
row: usize,
content_x: f32,
content_y: f32,
bg_color: [f32; 4],
cursor_opacity: f32,
render_hollow_here: bool,
opacity_multiplier: f32,
bg_index: usize,
}
impl CellRenderer {
pub(super) fn emit_row_backgrounds(
&mut self,
p: RowBackgroundParams<'_>,
mut bg_index: usize,
) -> usize {
let RowBackgroundParams {
row_cells,
row,
cursor_pos,
cursor_opacity,
content_x,
content_y,
opacity_multiplier,
fill_default_bg_cells,
skip_solid_background,
} = p;
let mut col = 0;
while col < row_cells.len() {
let cell = &row_cells[col];
let bg_f = color_u8x4_rgb_to_f32(cell.bg_color);
let is_default_bg = (bg_f[0] - self.background_color[0]).abs() < 0.001
&& (bg_f[1] - self.background_color[1]).abs() < 0.001
&& (bg_f[2] - self.background_color[2]).abs() < 0.001;
let cursor_at_cell = cursor_pos.is_some_and(|(cx, cy)| cx == col && cy == row)
&& !self.cursor.hidden_for_shader;
let render_hollow_here = cursor_at_cell
&& !self.is_focused
&& self.cursor.unfocused_style == par_term_config::UnfocusedCursorStyle::Hollow;
let has_cursor = (cursor_at_cell && cursor_opacity > 0.0) || render_hollow_here;
let is_half_block = {
let mut chars = cell.grapheme.chars();
matches!(chars.next(), Some('\u{2580}' | '\u{2584}')) && chars.next().is_none()
};
if is_half_block || (is_default_bg && !has_cursor && !fill_default_bg_cells) {
col += 1;
continue;
}
let bg_alpha = if self.transparency_affects_only_default_background && !is_default_bg {
1.0
} else {
self.window_opacity
};
let pane_alpha = bg_alpha * opacity_multiplier;
let bg_color = color_u8x4_rgb_to_f32_a(cell.bg_color, pane_alpha);
if has_cursor {
let emitted = self.emit_cursor_cell_bg(CursorCellBgParams {
col,
row,
content_x,
content_y,
bg_color,
cursor_opacity,
render_hollow_here,
opacity_multiplier,
bg_index,
});
if emitted {
bg_index += 1;
}
col += 1;
continue;
}
let start_col = col;
let run_color = cell.bg_color;
col += 1;
while col < row_cells.len() {
let next_cell = &row_cells[col];
let next_cursor_at_cell = cursor_pos.is_some_and(|(cx, cy)| cx == col && cy == row)
&& !self.cursor.hidden_for_shader;
let next_hollow = next_cursor_at_cell
&& !self.is_focused
&& self.cursor.unfocused_style == par_term_config::UnfocusedCursorStyle::Hollow;
let next_has_cursor = (next_cursor_at_cell && cursor_opacity > 0.0) || next_hollow;
let next_is_half_block = {
let mut chars = next_cell.grapheme.chars();
matches!(chars.next(), Some('\u{2580}' | '\u{2584}')) && chars.next().is_none()
};
if next_cell.bg_color != run_color || next_has_cursor || next_is_half_block {
break;
}
col += 1;
}
let run_length = col - start_col;
let x0 = (content_x + start_col as f32 * self.grid.cell_width).round();
let x1 = (content_x + (start_col + run_length) as f32 * self.grid.cell_width).round();
let y0 = (content_y + row as f32 * self.grid.cell_height).round();
let y1 = (content_y + (row + 1) as f32 * self.grid.cell_height).round();
let (x0, x1) = powerline::extend_powerline_fringes(powerline::PowerlineFringeParams {
row_cells,
start_col,
col,
x0,
x1,
skip_solid_background,
is_default_bg,
background_color: self.background_color,
});
if bg_index < self.buffers.max_bg_instances {
self.bg_instances[bg_index] = BackgroundInstance {
position: [
x0 / self.config.width as f32 * 2.0 - 1.0,
1.0 - (y0 / self.config.height as f32 * 2.0),
],
size: [
(x1 - x0) / self.config.width as f32 * 2.0,
(y1 - y0) / self.config.height as f32 * 2.0,
],
color: bg_color,
};
bg_index += 1;
}
}
bg_index
}
fn emit_cursor_cell_bg(&mut self, p: CursorCellBgParams) -> bool {
let CursorCellBgParams {
col,
row,
content_x,
content_y,
mut bg_color,
cursor_opacity,
render_hollow_here,
opacity_multiplier,
bg_index,
} = p;
use par_term_emu_core_rust::cursor::CursorStyle;
match self.cursor.style {
CursorStyle::SteadyBlock | CursorStyle::BlinkingBlock if !render_hollow_here => {
for (bg, &cursor) in bg_color.iter_mut().take(3).zip(&self.cursor.color) {
*bg = *bg * (1.0 - cursor_opacity) + cursor * cursor_opacity;
}
bg_color[3] = bg_color[3].max(cursor_opacity * opacity_multiplier);
}
_ => {}
}
let x0 = (content_x + col as f32 * self.grid.cell_width).round();
let x1 = (content_x + (col + 1) as f32 * self.grid.cell_width).round();
let y0 = (content_y + row as f32 * self.grid.cell_height).round();
let y1 = (content_y + (row + 1) as f32 * self.grid.cell_height).round();
if bg_index < self.buffers.max_bg_instances {
self.bg_instances[bg_index] = BackgroundInstance {
position: [
x0 / self.config.width as f32 * 2.0 - 1.0,
1.0 - (y0 / self.config.height as f32 * 2.0),
],
size: [
(x1 - x0) / self.config.width as f32 * 2.0,
(y1 - y0) / self.config.height as f32 * 2.0,
],
color: bg_color,
};
true
} else {
false
}
}
}