mirror of https://github.com/sgoudham/neovide.git
part way to multi grid rendering
parent
655339bbf8
commit
4ef6adcfef
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,224 @@
|
|||||||
|
use std::collections::{HashSet, HashMap};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use log::trace;
|
||||||
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
|
use crate::bridge::{GridLineCell, WindowAnchor};
|
||||||
|
use super::grid::CharacterGrid;
|
||||||
|
use super::style::Style;
|
||||||
|
|
||||||
|
#[derive(new, Debug, Clone)]
|
||||||
|
pub struct DrawCommand {
|
||||||
|
pub text: String,
|
||||||
|
pub cell_width: u64,
|
||||||
|
pub grid_position: (u64, u64),
|
||||||
|
pub style: Option<Arc<Style>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Window {
|
||||||
|
pub id: u64,
|
||||||
|
pub grid_id: u64,
|
||||||
|
pub grid: CharacterGrid,
|
||||||
|
pub hidden: bool,
|
||||||
|
pub anchor_grid_id: Option<u64>,
|
||||||
|
pub anchor_type: WindowAnchor,
|
||||||
|
pub anchor_row: u64,
|
||||||
|
pub anchor_column: u64,
|
||||||
|
pub children: HashSet<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Window {
|
||||||
|
pub fn new(id: u64, grid_id: u64, width: u64, height: u64, anchor_grid_id: Option<u64>, anchor_type: WindowAnchor, anchor_row: u64, anchor_column: u64) -> Window {
|
||||||
|
Window {
|
||||||
|
id, grid_id, anchor_grid_id, anchor_type, anchor_row, anchor_column,
|
||||||
|
grid: CharacterGrid::new((width, height)),
|
||||||
|
hidden: false,
|
||||||
|
children: HashSet::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resize(&mut self, width: u64, height: u64) {
|
||||||
|
self.grid.resize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_grid_line_cell(&mut self, row_index: u64, column_pos: &mut u64, cell: GridLineCell, defined_styles: &HashMap<u64, Arc<Style>>, previous_style: &mut Option<Arc<Style>>) {
|
||||||
|
let style = match cell.highlight_id {
|
||||||
|
Some(0) => None,
|
||||||
|
Some(style_id) => defined_styles.get(&style_id).cloned(),
|
||||||
|
None => previous_style.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut text = cell.text;
|
||||||
|
|
||||||
|
if let Some(times) = cell.repeat {
|
||||||
|
text = text.repeat(times as usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if text.is_empty() {
|
||||||
|
if let Some(cell) = self.grid.get_cell_mut(*column_pos, row_index) {
|
||||||
|
*cell = Some(("".to_string(), style.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.grid.set_dirty_cell(*column_pos, row_index);
|
||||||
|
*column_pos += 1;
|
||||||
|
} else {
|
||||||
|
for (i, character) in text.graphemes(true).enumerate() {
|
||||||
|
if let Some(cell) = self.grid.get_cell_mut(i as u64 + *column_pos, row_index) {
|
||||||
|
*cell = Some((character.to_string(), style.clone()));
|
||||||
|
self.grid.set_dirty_cell(*column_pos, row_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*column_pos += text.graphemes(true).count() as u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
*previous_style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_grid_line(&mut self, row: u64, column_start: u64, cells: Vec<GridLineCell>, defined_styles: &HashMap<u64, Arc<Style>>, previous_style: &mut Option<Arc<Style>>) {
|
||||||
|
if row < self.grid.height {
|
||||||
|
let mut column_pos = column_start;
|
||||||
|
for cell in cells {
|
||||||
|
self.draw_grid_line_cell(row, &mut column_pos, cell, defined_styles, previous_style);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Draw command out of bounds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64, rows: i64, cols: i64) {
|
||||||
|
let y_iter: Box<dyn Iterator<Item = i64>> = if rows > 0 {
|
||||||
|
Box::new((top as i64 + rows)..bot as i64)
|
||||||
|
} else {
|
||||||
|
Box::new((top as i64..(bot as i64 + rows)).rev())
|
||||||
|
};
|
||||||
|
|
||||||
|
for y in y_iter {
|
||||||
|
let dest_y = y - rows;
|
||||||
|
if dest_y >= 0 && dest_y < self.grid.height as i64 {
|
||||||
|
let x_iter: Box<dyn Iterator<Item = i64>> = if cols > 0 {
|
||||||
|
Box::new((left as i64 + cols)..right as i64)
|
||||||
|
} else {
|
||||||
|
Box::new((left as i64..(right as i64 + cols)).rev())
|
||||||
|
};
|
||||||
|
|
||||||
|
for x in x_iter {
|
||||||
|
let dest_x = x - cols;
|
||||||
|
let cell_data = self.grid.get_cell(x as u64, y as u64).cloned();
|
||||||
|
|
||||||
|
if let Some(cell_data) = cell_data {
|
||||||
|
if let Some(dest_cell) =
|
||||||
|
self.grid.get_cell_mut(dest_x as u64, dest_y as u64)
|
||||||
|
{
|
||||||
|
*dest_cell = cell_data;
|
||||||
|
self.grid.set_dirty_cell(dest_x as u64, dest_y as u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace!("Region scrolled");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_draw_commands(&mut self) -> (Vec<DrawCommand>, bool) {
|
||||||
|
let mut draw_commands = Vec::new();
|
||||||
|
|
||||||
|
for (row_index, row) in self.grid.rows().enumerate() {
|
||||||
|
let mut command = None;
|
||||||
|
|
||||||
|
fn add_command(commands_list: &mut Vec<DrawCommand>, command: Option<DrawCommand>) {
|
||||||
|
if let Some(command) = command {
|
||||||
|
commands_list.push(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn command_matches(command: &Option<DrawCommand>, style: &Option<Arc<Style>>) -> bool {
|
||||||
|
match command {
|
||||||
|
Some(command) => &command.style == style,
|
||||||
|
None => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_character(
|
||||||
|
command: &mut Option<DrawCommand>,
|
||||||
|
character: &str,
|
||||||
|
row_index: u64,
|
||||||
|
col_index: u64,
|
||||||
|
style: Option<Arc<Style>>,
|
||||||
|
) {
|
||||||
|
match command {
|
||||||
|
Some(command) => {
|
||||||
|
command.text.push_str(character);
|
||||||
|
command.cell_width += 1;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
command.replace(DrawCommand::new(
|
||||||
|
character.to_string(),
|
||||||
|
1,
|
||||||
|
(col_index, row_index),
|
||||||
|
style,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (col_index, cell) in row.iter().enumerate() {
|
||||||
|
if let Some((character, style)) = cell {
|
||||||
|
if character.is_empty() {
|
||||||
|
add_character(
|
||||||
|
&mut command,
|
||||||
|
&" ",
|
||||||
|
row_index as u64,
|
||||||
|
col_index as u64,
|
||||||
|
style.clone(),
|
||||||
|
);
|
||||||
|
add_command(&mut draw_commands, command);
|
||||||
|
command = None;
|
||||||
|
} else {
|
||||||
|
if !command_matches(&command, &style) {
|
||||||
|
add_command(&mut draw_commands, command);
|
||||||
|
command = None;
|
||||||
|
}
|
||||||
|
add_character(
|
||||||
|
&mut command,
|
||||||
|
&character,
|
||||||
|
row_index as u64,
|
||||||
|
col_index as u64,
|
||||||
|
style.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !command_matches(&command, &None) {
|
||||||
|
add_command(&mut draw_commands, command);
|
||||||
|
command = None;
|
||||||
|
}
|
||||||
|
add_character(&mut command, " ", row_index as u64, col_index as u64, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_command(&mut draw_commands, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
let should_clear = self.grid.should_clear;
|
||||||
|
let draw_commands = draw_commands
|
||||||
|
.into_iter()
|
||||||
|
.filter(|command| {
|
||||||
|
let (x, y) = command.grid_position;
|
||||||
|
let min = (x as i64 - 1).max(0) as u64;
|
||||||
|
let max = (x + command.cell_width + 1).min(self.grid.width);
|
||||||
|
|
||||||
|
for char_index in min..max {
|
||||||
|
if self.grid.is_dirty_cell(char_index, y) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
.collect::<Vec<DrawCommand>>();
|
||||||
|
|
||||||
|
self.grid.set_dirty_all(false);
|
||||||
|
self.grid.should_clear = false;
|
||||||
|
|
||||||
|
trace!("Draw commands sent");
|
||||||
|
(draw_commands, should_clear)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue