refactored editor into multiple files to make things more readable

macos-click-through
Keith Simmons 5 years ago
parent be7c9f5207
commit 8467ef18ab

@ -0,0 +1,81 @@
use std::collections::HashMap;
use skulpin::skia_safe::Color4f;
use super::style::{Style, Colors};
#[derive(Debug, Clone, PartialEq)]
pub enum CursorShape {
Block,
Horizontal,
Vertical
}
impl CursorShape {
pub fn from_type_name(name: &str) -> Option<CursorShape> {
match name {
"block" => Some(CursorShape::Block),
"horizontal" => Some(CursorShape::Horizontal),
"vertical" => Some(CursorShape::Vertical),
_ => None
}
}
}
#[derive(new, Debug, Clone, PartialEq)]
pub struct CursorMode {
#[new(default)]
pub shape: Option<CursorShape>,
#[new(default)]
pub style_id: Option<u64>
}
#[derive(Clone)]
pub struct Cursor {
pub position: (u64, u64),
pub shape: CursorShape,
pub style: Option<Style>,
pub enabled: bool,
pub mode_list: Vec<CursorMode>
}
impl Cursor {
pub fn new() -> Cursor {
Cursor {
position: (0, 0),
shape: CursorShape::Block,
style: Option::<Style>::default(),
enabled: true,
mode_list: Vec::new()
}
}
pub fn foreground(&self, default_colors: &Colors) -> Color4f {
if let Some(style) = &self.style {
style.colors.foreground.clone().unwrap_or(default_colors.background.clone().unwrap())
} else {
default_colors.background.clone().unwrap()
}
}
pub fn background(&self, default_colors: &Colors) -> Color4f {
if let Some(style) = &self.style {
style.colors.background.clone().unwrap_or(default_colors.foreground.clone().unwrap())
} else {
default_colors.foreground.clone().unwrap()
}
}
pub fn change_mode(&mut self, mode_index: u64, styles: &HashMap<u64, Style>) {
if let Some(CursorMode { shape, style_id }) = self.mode_list.get(mode_index as usize) {
if let Some(shape) = shape {
self.shape = shape.clone();
}
if let Some(style_id) = style_id {
self.style = styles
.get(style_id)
.map(|style_reference| style_reference.clone());
}
}
}
}

@ -1,65 +1,13 @@
use std::collections::HashMap;
use skulpin::skia_safe::colors;
use skulpin::skia_safe::{colors, Color4f};
mod cursor;
mod style;
pub use cursor::{Cursor, CursorShape, CursorMode};
pub use style::{Colors, Style};
use crate::events::{GridLineCell, RedrawEvent};
#[derive(new, PartialEq, Debug, Clone)]
pub struct Colors {
pub foreground: Option<Color4f>,
pub background: Option<Color4f>,
pub special: Option<Color4f>
}
#[derive(new, Debug, Clone, PartialEq)]
pub struct Style {
pub colors: Colors,
#[new(default)]
pub reverse: bool,
#[new(default)]
pub italic: bool,
#[new(default)]
pub bold: bool,
#[new(default)]
pub strikethrough: bool,
#[new(default)]
pub underline: bool,
#[new(default)]
pub undercurl: bool,
#[new(default)]
pub blend: u8
}
impl Style {
pub fn foreground(&self, default_colors: &Colors) -> Color4f {
if self.reverse {
self.colors.background.clone().unwrap_or(default_colors.background.clone().unwrap())
} else {
self.colors.foreground.clone().unwrap_or(default_colors.foreground.clone().unwrap())
}
}
pub fn background(&self, default_colors: &Colors) -> Color4f {
if self.reverse {
self.colors.foreground.clone().unwrap_or(default_colors.foreground.clone().unwrap())
} else {
self.colors.background.clone().unwrap_or(default_colors.background.clone().unwrap())
}
}
pub fn special(&self, default_colors: &Colors) -> Color4f {
self.colors.special.clone().unwrap_or(default_colors.special.clone().unwrap())
}
}
#[derive(new, Debug, Clone, PartialEq)]
pub struct ModeInfo {
#[new(default)]
pub cursor_type: Option<CursorType>,
#[new(default)]
pub cursor_style_id: Option<u64>
}
pub type GridCell = Option<(char, Style)>;
#[derive(new, Debug, Clone)]
@ -69,35 +17,13 @@ pub struct DrawCommand {
pub style: Style
}
#[derive(Debug, Clone, PartialEq)]
pub enum CursorType {
Block,
Horizontal,
Vertical
}
impl CursorType {
pub fn from_type_name(name: &str) -> Option<CursorType> {
match name {
"block" => Some(CursorType::Block),
"horizontal" => Some(CursorType::Horizontal),
"vertical" => Some(CursorType::Vertical),
_ => None
}
}
}
pub struct Editor {
pub grid: Vec<Vec<GridCell>>,
pub title: String,
pub cursor_pos: (u64, u64),
pub cursor_type: CursorType,
pub cursor_style: Option<Style>,
pub cursor_enabled: bool,
pub size: (u64, u64),
pub cursor: Cursor,
pub default_colors: Colors,
pub defined_styles: HashMap<u64, Style>,
pub mode_list: Vec<ModeInfo>,
pub previous_style: Option<Style>
}
@ -106,33 +32,31 @@ impl Editor {
let mut editor = Editor {
grid: Vec::new(),
title: "".to_string(),
cursor_pos: (0, 0),
cursor_type: CursorType::Block,
cursor_style: None,
cursor_enabled: true,
cursor: Cursor::new(),
size: (width, height),
default_colors: Colors::new(Some(colors::WHITE), Some(colors::BLACK), Some(colors::GREY)),
defined_styles: HashMap::new(),
mode_list: Vec::new(),
previous_style: None
};
editor.clear();
editor
}
pub fn cursor_foreground(&self) -> Color4f {
if let Some(cursor_style) = &self.cursor_style {
cursor_style.colors.foreground.clone().unwrap_or(self.default_colors.background.clone().unwrap())
} else {
self.default_colors.background.clone().unwrap()
}
}
pub fn cursor_background(&self) -> Color4f {
if let Some(cursor_style) = &self.cursor_style {
cursor_style.colors.background.clone().unwrap_or(self.default_colors.foreground.clone().unwrap())
} else {
self.default_colors.foreground.clone().unwrap()
pub fn handle_redraw_event(&mut self, event: RedrawEvent) {
match event {
RedrawEvent::SetTitle { title } => self.title = title,
RedrawEvent::ModeInfoSet { cursor_modes } => self.cursor.mode_list = cursor_modes,
RedrawEvent::ModeChange { mode_index } => self.cursor.change_mode(mode_index, &self.defined_styles),
RedrawEvent::BusyStart => self.cursor.enabled = false,
RedrawEvent::BusyStop => self.cursor.enabled = true,
RedrawEvent::Resize { width, height, .. } => self.resize((width, height)),
RedrawEvent::DefaultColorsSet { colors } => self.default_colors = colors,
RedrawEvent::HighlightAttributesDefine { id, style } => { self.defined_styles.insert(id, style); },
RedrawEvent::GridLine { row, column_start, cells, .. } => self.draw_grid_line(row, column_start, cells),
RedrawEvent::Clear { .. } => self.clear(),
RedrawEvent::CursorGoto { row, column, .. } => self.cursor.position = (row, column),
RedrawEvent::Scroll { top, bottom, left, right, rows, columns, .. } => self.scroll_region(top, bottom, left, right, rows, columns)
}
}
@ -181,61 +105,6 @@ impl Editor {
}).flatten().collect()
}
pub fn handle_redraw_event(&mut self, event: RedrawEvent) {
match event {
RedrawEvent::SetTitle { title } => self.set_title(title),
RedrawEvent::ModeInfoSet { mode_list } => self.set_mode_list(mode_list),
RedrawEvent::ModeChange { mode_index } => self.change_mode(mode_index),
RedrawEvent::BusyStart => self.set_cursor_enabled(false),
RedrawEvent::BusyStop => self.set_cursor_enabled(true),
RedrawEvent::Resize { width, height, .. } => self.resize(width, height),
RedrawEvent::DefaultColorsSet { foreground, background, special } => self.set_default_colors(foreground, background, special),
RedrawEvent::HighlightAttributesDefine { id, style } => self.define_style(id, style),
RedrawEvent::GridLine { row, column_start, cells, .. } => self.draw_grid_line(row, column_start, cells),
RedrawEvent::Clear { .. } => self.clear(),
RedrawEvent::CursorGoto { row, column, .. } => self.jump_cursor_to(row, column),
RedrawEvent::Scroll { top, bottom, left, right, rows, columns, .. } => self.scroll_region(top, bottom, left, right, rows, columns)
}
}
pub fn set_title(&mut self, title: String) {
self.title = title;
}
pub fn set_mode_list(&mut self, mode_list: Vec<ModeInfo>) {
self.mode_list = mode_list;
}
pub fn change_mode(&mut self, mode_index: u64) {
if let Some(ModeInfo { cursor_type, cursor_style_id }) = self.mode_list.get(mode_index as usize) {
if let Some(cursor_type) = cursor_type {
self.cursor_type = cursor_type.clone();
}
if let Some(cursor_style_id) = cursor_style_id {
self.cursor_style = self.defined_styles
.get(cursor_style_id)
.map(|style_reference| style_reference.clone());
}
}
}
pub fn set_cursor_enabled(&mut self, cursor_enabled: bool) {
self.cursor_enabled = cursor_enabled;
}
pub fn resize(&mut self, new_width: u64, new_height: u64) {
self.size = (new_width, new_height);
}
fn set_default_colors(&mut self, foreground: Color4f, background: Color4f, special: Color4f) {
self.default_colors = Colors::new(Some(foreground), Some(background), Some(special));
}
fn define_style(&mut self, id: u64, style: Style) {
self.defined_styles.insert(id, style);
}
fn draw_grid_line_cell(&mut self, row_index: u64, column_pos: &mut u64, cell: GridLineCell) {
let style = match (cell.highlight_id, self.previous_style.clone()) {
(Some(0), _) => Style::new(self.default_colors.clone()),
@ -272,15 +141,16 @@ impl Editor {
}
}
fn resize(&mut self, new_size: (u64, u64)) {
self.size = new_size;
self.clear();
}
fn clear(&mut self) {
let (width, height) = self.size;
self.grid = vec![vec![None; width as usize]; height as usize];
}
fn jump_cursor_to(&mut self, row: u64, col: u64) {
self.cursor_pos = (row, col);
}
fn scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64, rows: i64, cols: i64) {
let (top, bot) = if rows > 0 {
(top as i64 + rows, bot as i64)

@ -0,0 +1,49 @@
use skulpin::skia_safe::Color4f;
#[derive(new, PartialEq, Debug, Clone)]
pub struct Colors {
pub foreground: Option<Color4f>,
pub background: Option<Color4f>,
pub special: Option<Color4f>
}
#[derive(new, Debug, Clone, PartialEq)]
pub struct Style {
pub colors: Colors,
#[new(default)]
pub reverse: bool,
#[new(default)]
pub italic: bool,
#[new(default)]
pub bold: bool,
#[new(default)]
pub strikethrough: bool,
#[new(default)]
pub underline: bool,
#[new(default)]
pub undercurl: bool,
#[new(default)]
pub blend: u8
}
impl Style {
pub fn foreground(&self, default_colors: &Colors) -> Color4f {
if self.reverse {
self.colors.background.clone().unwrap_or(default_colors.background.clone().unwrap())
} else {
self.colors.foreground.clone().unwrap_or(default_colors.foreground.clone().unwrap())
}
}
pub fn background(&self, default_colors: &Colors) -> Color4f {
if self.reverse {
self.colors.foreground.clone().unwrap_or(default_colors.foreground.clone().unwrap())
} else {
self.colors.background.clone().unwrap_or(default_colors.background.clone().unwrap())
}
}
pub fn special(&self, default_colors: &Colors) -> Color4f {
self.colors.special.clone().unwrap_or(default_colors.special.clone().unwrap())
}
}

@ -4,7 +4,7 @@ use std::fmt;
use rmpv::Value;
use skulpin::skia_safe::Color4f;
use crate::editor::{Colors, Style, ModeInfo, CursorType};
use crate::editor::{Colors, Style, CursorMode, CursorShape};
#[derive(Debug, Clone)]
pub enum EventParseError {
@ -46,12 +46,12 @@ pub struct GridLineCell {
#[derive(Debug)]
pub enum RedrawEvent {
SetTitle { title: String },
ModeInfoSet { mode_list: Vec<ModeInfo> },
ModeInfoSet { cursor_modes: Vec<CursorMode> },
ModeChange { mode_index: u64 },
BusyStart,
BusyStop,
Resize { grid: u64, width: u64, height: u64 },
DefaultColorsSet { foreground: Color4f, background: Color4f, special: Color4f },
DefaultColorsSet { colors: Colors },
HighlightAttributesDefine { id: u64, style: Style },
GridLine { grid: u64, row: u64, column_start: u64, cells: Vec<GridLineCell> },
Clear { grid: u64 },
@ -125,26 +125,26 @@ fn parse_set_title(set_title_arguments: Vec<Value>) -> Result<RedrawEvent> {
fn parse_mode_info_set(mode_info_set_arguments: Vec<Value>) -> Result<RedrawEvent> {
if let [_cursor_style_enabled, mode_info] = mode_info_set_arguments.as_slice() {
let mode_info_values = parse_array(&mode_info)?;
let mut mode_list = Vec::new();
let mut cursor_modes = Vec::new();
for mode_info_value in mode_info_values {
let info_map = parse_map(&mode_info_value)?;
let mut mode_info = ModeInfo::new();
let mut mode_info = CursorMode::new();
for (name, value) in info_map {
let name = parse_string(&name)?;
match name.as_ref() {
"cursor_shape" => {
mode_info.cursor_type = CursorType::from_type_name(&parse_string(&value)?);
mode_info.shape = CursorShape::from_type_name(&parse_string(&value)?);
},
"attr_id" => {
mode_info.cursor_style_id = Some(parse_u64(&value)?);
mode_info.style_id = Some(parse_u64(&value)?);
},
_ => {}
}
}
mode_list.push(mode_info);
cursor_modes.push(mode_info);
}
Ok(RedrawEvent::ModeInfoSet {
mode_list
cursor_modes
})
} else {
Err(EventParseError::InvalidEventFormat)
@ -176,9 +176,11 @@ fn parse_default_colors(default_colors_arguments: Vec<Value>) -> Result<RedrawEv
foreground, background, special, _term_foreground, _term_background
] = default_colors_arguments.as_slice() {
Ok(RedrawEvent::DefaultColorsSet {
foreground: unpack_color(parse_u64(&foreground)?),
background: unpack_color(parse_u64(&background)?),
special: unpack_color(parse_u64(special)?),
colors: Colors {
foreground: Some(unpack_color(parse_u64(&foreground)?)),
background: Some(unpack_color(parse_u64(&background)?)),
special: Some(unpack_color(parse_u64(special)?)),
}
})
} else {
Err(EventParseError::InvalidEventFormat)

@ -1,4 +1,4 @@
// #![windows_subsystem = "windows"]
#![windows_subsystem = "windows"]
mod editor;
mod events;

@ -3,12 +3,11 @@ use skulpin::skia_safe::{Canvas, Paint, Rect, Typeface, Font, FontStyle, colors}
mod caching_shaper;
mod fps_tracker;
mod font_measurer;
use caching_shaper::CachingShaper;
use fps_tracker::FpsTracker;
use crate::editor::{Editor, CursorType, Style, Colors};
use crate::editor::{Editor, CursorShape, Style, Colors};
const FONT_NAME: &str = "Delugia Nerd Font";
const FONT_SIZE: f32 = 14.0;
@ -90,17 +89,13 @@ impl Renderer {
}
pub fn draw(&mut self, canvas: &mut Canvas) {
let (draw_commands, default_colors, (width, height), cursor_grid_pos, cursor_type, cursor_foreground, cursor_background, cursor_enabled) = {
let (draw_commands, default_colors, (width, height), cursor) = {
let editor = self.editor.lock().unwrap();
(
editor.build_draw_commands().clone(),
editor.default_colors.clone(),
editor.size.clone(),
editor.cursor_pos.clone(),
editor.cursor_type.clone(),
editor.cursor_foreground(),
editor.cursor_background(),
editor.cursor_enabled
editor.cursor.clone()
)
};
@ -116,7 +111,7 @@ impl Renderer {
self.fps_tracker.record_frame();
self.draw_text(canvas, &self.fps_tracker.fps.to_string(), (width - 2, height - 1), &Style::new(default_colors.clone()), &default_colors, false);
let (cursor_grid_x, cursor_grid_y) = cursor_grid_pos;
let (cursor_grid_x, cursor_grid_y) = cursor.position;
let target_cursor_x = cursor_grid_x as f32 * self.font_width;
let target_cursor_y = cursor_grid_y as f32 * self.font_height;
let (previous_cursor_x, previous_cursor_y) = self.cursor_pos;
@ -125,21 +120,21 @@ impl Renderer {
let cursor_y = (target_cursor_y - previous_cursor_y) * 0.5 + previous_cursor_y;
self.cursor_pos = (cursor_x, cursor_y);
if cursor_enabled {
let cursor_width = match cursor_type {
CursorType::Vertical => self.font_width / 8.0,
CursorType::Horizontal | CursorType::Block => self.font_width
if cursor.enabled {
let cursor_width = match cursor.shape {
CursorShape::Vertical => self.font_width / 8.0,
CursorShape::Horizontal | CursorShape::Block => self.font_width
};
let cursor_height = match cursor_type {
CursorType::Horizontal => self.font_width / 8.0,
CursorType::Vertical | CursorType::Block => self.font_height
let cursor_height = match cursor.shape {
CursorShape::Horizontal => self.font_width / 8.0,
CursorShape::Vertical | CursorShape::Block => self.font_height
};
let cursor = Rect::new(cursor_x, cursor_y, cursor_x + cursor_width, cursor_y + cursor_height);
self.paint.set_color(cursor_background.to_color());
canvas.draw_rect(cursor, &self.paint);
let cursor_region = Rect::new(cursor_x, cursor_y, cursor_x + cursor_width, cursor_y + cursor_height);
self.paint.set_color(cursor.background(&default_colors).to_color());
canvas.draw_rect(cursor_region, &self.paint);
if let CursorType::Block = cursor_type {
self.paint.set_color(cursor_foreground.to_color());
if let CursorShape::Block = cursor.shape {
self.paint.set_color(cursor.foreground(&default_colors).to_color());
let editor = self.editor.lock().unwrap();
let character = editor.grid[cursor_grid_y as usize][cursor_grid_x as usize].clone()
.map(|(character, _)| character)

Loading…
Cancel
Save