hsb colors, themes, settings

This commit is contained in:
Anton-4 2021-02-23 19:43:50 +01:00
parent 005e548757
commit f8944468a4
14 changed files with 265 additions and 77 deletions

81
Cargo.lock generated
View File

@ -2009,6 +2009,30 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "palette"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a05c0334468e62a4dfbda34b29110aa7d70d58c7fdb2c9857b5874dd9827cc59"
dependencies = [
"approx 0.3.2",
"num-traits",
"palette_derive",
"phf",
"phf_codegen",
]
[[package]]
name = "palette_derive"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b4b5f600e60dd3a147fb57b4547033d382d1979eb087af310e91cb45a63b1f4"
dependencies = [
"proc-macro2 1.0.24",
"quote 1.0.8",
"syn 1.0.60",
]
[[package]]
name = "parking_lot"
version = "0.10.2"
@ -2120,6 +2144,44 @@ dependencies = [
"indexmap",
]
[[package]]
name = "phf"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
dependencies = [
"phf_shared",
]
[[package]]
name = "phf_codegen"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
dependencies = [
"phf_generator",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
dependencies = [
"phf_shared",
"rand 0.7.3",
]
[[package]]
name = "phf_shared"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
dependencies = [
"siphasher",
]
[[package]]
name = "pin-project-lite"
version = "0.1.11"
@ -2331,7 +2393,7 @@ dependencies = [
"rand_isaac",
"rand_jitter",
"rand_os",
"rand_pcg",
"rand_pcg 0.1.2",
"rand_xorshift",
"winapi 0.3.9",
]
@ -2347,6 +2409,7 @@ dependencies = [
"rand_chacha 0.2.2",
"rand_core 0.5.1",
"rand_hc 0.2.0",
"rand_pcg 0.2.1",
]
[[package]]
@ -2495,6 +2558,15 @@ dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_pcg"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
@ -2794,6 +2866,7 @@ dependencies = [
"log",
"maplit",
"page_size",
"palette",
"pest",
"pest_derive",
"pretty_assertions",
@ -3340,6 +3413,12 @@ dependencies = [
"libc",
]
[[package]]
name = "siphasher"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7"
[[package]]
name = "sized-chunks"
version = "0.5.3"

View File

@ -70,6 +70,7 @@ pest_derive = "2.1"
ropey = "1.2.0"
copypasta = "0.7.1"
indoc = "0.3.3"
palette = "0.5"
[dependencies.bytemuck]
version = "1.4"

View File

@ -1,8 +1,41 @@
use crate::graphics::colors as gr_colors;
use crate::graphics::colors::ColorTup;
use crate::ui::colors as ui_colors;
pub const BG_COL: ColorTup = (0.17, 0.17, 0.19, 1.0);
pub const EQUALS_SYNTAX_COL: ColorTup = (0.043, 0.0196, 0.102, 1.0);
pub const STRING_SYNTAX_COL: ColorTup = ui_colors::LIGHT_BRAND_COL;
pub const CODE_COL: ColorTup = gr_colors::WHITE;
use crate::graphics::colors as gr_colors;
use gr_colors::{RgbaTup, from_hsb};
use crate::ui::colors as ui_colors;
use ui_colors::UITheme;
pub struct SyntaxHighlightTheme {
pub code: RgbaTup,
// operators are "=+-:>..."
pub operator: RgbaTup,
pub string: RgbaTup,
}
impl Default for SyntaxHighlightTheme {
fn default() -> Self {
let ui_theme = UITheme::default();
Self {
code: gr_colors::WHITE,
operator: from_hsb(257, 81, 10),
string: ui_theme.light_brand,
}
}
}
pub struct EdTheme {
pub background: RgbaTup,
pub syntax_high_theme: SyntaxHighlightTheme,
pub ui_theme: UITheme,
}
impl Default for EdTheme {
fn default() -> Self {
Self {
background: from_hsb(240, 10, 19),
syntax_high_theme: SyntaxHighlightTheme::default(),
ui_theme: UITheme::default(),
}
}
}

View File

@ -1,17 +1,24 @@
use super::keyboard_input;
use crate::editor::colors::BG_COL;
use crate::editor::colors::CODE_COL;
use crate::editor::ed_error::{print_err, print_ui_err};
use crate::editor::mvc::{app_model::AppModel, app_update, ed_model, ed_model::EdModel, ed_view};
use crate::graphics::colors::to_wgpu_color;
use crate::graphics::primitives::text::{
build_glyph_brush, example_code_glyph_rect, queue_code_text_draw, queue_text_draw, Text,
use crate::editor::{
ed_error::{print_err, print_ui_err},
colors::EdTheme,
mvc::{app_model::AppModel, app_update, ed_model, ed_model::EdModel, ed_view},
settings::Settings,
};
use crate::graphics::{
colors::to_wgpu_color,
primitives::text::{
build_glyph_brush, example_code_glyph_rect, queue_code_text_draw, queue_text_draw, Text,
},
lowlevel::buffer::create_rect_buffers, lowlevel::ortho::update_ortho_buffer,
lowlevel::pipelines, style::CODE_FONT_SIZE, style::CODE_TXT_XY,
lowlevel::pipelines, style::CODE_TXT_XY,
};
use crate::ui::{
text::lines::Lines,
text::text_pos::TextPos,
ui_error::UIResult,
colors::UITheme
};
use crate::ui::{colors::TXT_COL, text::lines::Lines, text::text_pos::TextPos, ui_error::UIResult};
//use crate::resources::strings::NOTHING_OPENED;
use super::util::slice_get;
use crate::lang::{pool::Pool, scope::Scope};
@ -149,6 +156,9 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
let mut rects_arena = Bump::new();
let mut ast_arena = Bump::new();
let settings = Settings::default();
let ed_theme = EdTheme::default();
// Render loop
window.request_redraw();
@ -251,7 +261,8 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
&size,
&ed_model.text.all_lines(&arena),
ed_model.text.caret_w_select.caret_pos,
CODE_TXT_XY.into(),
&ed_theme,
&settings,
&mut glyph_brush,
);
} else {
@ -294,6 +305,7 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
&expr2,
&size,
CODE_TXT_XY.into(),
&settings,
&mut glyph_brush,
);
}
@ -307,11 +319,12 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
&frame.view,
&gpu_device,
&rect_resources,
&ed_theme,
) {
Ok(()) => (),
Err(e) => {
print_ui_err(&e);
begin_render_pass(&mut encoder, &frame.view);
begin_render_pass(&mut encoder, &frame.view, &ed_theme);
}
}
@ -353,13 +366,14 @@ fn draw_all_rects(
texture_view: &TextureView,
gpu_device: &wgpu::Device,
rect_resources: &RectResources,
ed_theme: &EdTheme,
) -> UIResult<()> {
if let Some(ed_model) = ed_model_opt {
let all_rects = ed_view::create_ed_rects(ed_model, arena)?;
let all_rects = ed_view::create_ed_rects(ed_model, &ed_theme.ui_theme, arena)?;
let rect_buffers = create_rect_buffers(gpu_device, encoder, &all_rects);
let mut render_pass = begin_render_pass(encoder, texture_view);
let mut render_pass = begin_render_pass(encoder, texture_view, ed_theme);
render_pass.set_pipeline(&rect_resources.pipeline);
render_pass.set_bind_group(0, &rect_resources.ortho.bind_group, &[]);
@ -368,7 +382,7 @@ fn draw_all_rects(
render_pass.draw_indexed(0..rect_buffers.num_rects, 0, 0..1);
} else {
// need to begin render pass to clear screen
begin_render_pass(encoder, texture_view);
begin_render_pass(encoder, texture_view, ed_theme);
}
Ok(())
@ -377,8 +391,9 @@ fn draw_all_rects(
fn begin_render_pass<'a>(
encoder: &'a mut CommandEncoder,
texture_view: &'a TextureView,
ed_theme: &EdTheme
) -> RenderPass<'a> {
let bg_color = to_wgpu_color(BG_COL);
let bg_color = to_wgpu_color(ed_theme.background);
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
@ -398,17 +413,18 @@ fn queue_editor_text(
size: &PhysicalSize<u32>,
editor_lines: &str,
caret_pos: TextPos,
code_coords: Vector2<f32>,
ed_theme: &EdTheme,
settings: &Settings,
glyph_brush: &mut GlyphBrush<()>,
) {
let area_bounds = (size.width as f32, size.height as f32).into();
let code_text = Text {
position: code_coords,
position: CODE_TXT_XY.into(),
area_bounds,
color: CODE_COL.into(),
color: ed_theme.syntax_high_theme.code,
text: editor_lines,
size: CODE_FONT_SIZE,
size: settings.code_font_size,
..Default::default()
};
@ -418,7 +434,7 @@ fn queue_editor_text(
let caret_pos_label = Text {
position: ((size.width as f32) - 150.0, (size.height as f32) - 40.0).into(),
area_bounds,
color: TXT_COL.into(),
color: ed_theme.ui_theme.text,
text,
size: 25.0,
..Default::default()
@ -433,6 +449,8 @@ fn _queue_no_file_text(
size: &PhysicalSize<u32>,
text: &str,
text_coords: Vector2<f32>,
ui_theme: &UITheme,
settings: &Settings,
glyph_brush: &mut GlyphBrush<()>,
) {
let area_bounds = (size.width as f32, size.height as f32).into();
@ -440,9 +458,9 @@ fn _queue_no_file_text(
let code_text = Text {
position: text_coords,
area_bounds,
color: CODE_COL.into(),
color: ui_theme.text,
text,
size: CODE_FONT_SIZE,
size: settings.code_font_size,
..Default::default()
};

View File

@ -1,4 +1,5 @@
mod colors;
pub mod colors; // TODO remove pub once we have ast based syntax highlighting
mod settings;
mod ed_error;
mod keyboard_input;
pub mod main;

View File

@ -1,16 +1,18 @@
use super::ed_model::EdModel;
use crate::graphics::primitives::rect::Rect;
use crate::ui::colors::CARET_COL;
use crate::ui::text::{selection::create_selection_rects, text_pos::TextPos};
use crate::ui::ui_error::MissingGlyphDims;
use crate::ui::ui_error::UIResult;
use crate::ui::{
colors::UITheme,
text::{selection::create_selection_rects, text_pos::TextPos},
ui_error::{MissingGlyphDims, UIResult},
};
use bumpalo::collections::Vec as BumpVec;
use bumpalo::Bump;
use snafu::ensure;
//TODO add editor text here as well
pub fn create_ed_rects<'a>(ed_model: &EdModel, arena: &'a Bump) -> UIResult<BumpVec<'a, Rect>> {
pub fn create_ed_rects<'a>(ed_model: &EdModel, ui_theme:&UITheme, arena: &'a Bump) -> UIResult<BumpVec<'a, Rect>> {
ensure!(ed_model.glyph_dim_rect_opt.is_some(), MissingGlyphDims {});
let glyph_rect = ed_model.glyph_dim_rect_opt.unwrap();
@ -21,18 +23,18 @@ pub fn create_ed_rects<'a>(ed_model: &EdModel, arena: &'a Bump) -> UIResult<Bump
if let Some(selection) = selection_opt {
let mut selection_rects =
create_selection_rects(selection, &ed_model.text, &glyph_rect, &arena)?;
create_selection_rects(selection, &ed_model.text, &glyph_rect, ui_theme, &arena)?;
all_rects.append(&mut selection_rects);
}
let caret_pos = ed_model.text.caret_w_select.caret_pos;
all_rects.push(make_caret_rect(caret_pos, &glyph_rect));
all_rects.push(make_caret_rect(caret_pos, &glyph_rect, ui_theme));
Ok(all_rects)
}
fn make_caret_rect(caret_pos: TextPos, glyph_dim_rect: &Rect) -> Rect {
fn make_caret_rect(caret_pos: TextPos, glyph_dim_rect: &Rect, ui_theme: &UITheme) -> Rect {
let caret_y =
glyph_dim_rect.top_left_coords.y + (caret_pos.line as f32) * glyph_dim_rect.height;
@ -43,6 +45,6 @@ fn make_caret_rect(caret_pos: TextPos, glyph_dim_rect: &Rect) -> Rect {
top_left_coords: (caret_x, caret_y).into(),
height: glyph_dim_rect.height,
width: 2.0,
color: CARET_COL,
color: ui_theme.caret,
}
}

View File

@ -6,12 +6,12 @@ use wgpu_glyph::GlyphBrush;
use winit::dpi::PhysicalSize;
use crate::{
editor::colors::CODE_COL,
graphics::{
primitives::text::{queue_code_text_draw, Text},
style::CODE_FONT_SIZE,
colors,
},
lang::{ast::Expr2, expr::Env},
editor::settings::Settings,
};
fn pool_str_len<'a>(env: &Env<'a>, pool_str: &PoolStr) -> usize {
@ -155,6 +155,7 @@ pub fn render_expr2<'a>(
expr2: &Expr2,
size: &PhysicalSize<u32>,
position: Vector2<f32>,
settings: &Settings,
glyph_brush: &mut GlyphBrush<()>,
) {
let area_bounds = (size.width as f32, size.height as f32).into();
@ -166,9 +167,9 @@ pub fn render_expr2<'a>(
let code_text = Text {
position,
area_bounds,
color: CODE_COL.into(),
color: colors::WHITE,
text: &expr_str,
size: CODE_FONT_SIZE,
size: settings.code_font_size,
..Default::default()
};

View File

@ -0,0 +1,14 @@
pub struct Settings {
pub code_font_size: f32,
}
impl Default for Settings {
fn default() -> Self {
Self {
code_font_size: 30.0,
}
}
}

View File

@ -1,13 +1,15 @@
use crate::editor::colors as ed_colors;
use ed_colors::SyntaxHighlightTheme;
use crate::graphics::colors as gr_colors;
use crate::graphics::primitives;
use gr_colors::ColorTup;
use gr_colors::RgbaTup;
//TODO optimize memory allocation
//TODO this is a demo function, the AST should be used for highlighting, see #904.
pub fn highlight_code(
code_text: &primitives::text::Text,
all_text_tups: &mut Vec<(String, ColorTup)>,
all_text_tups: &mut Vec<(String, RgbaTup)>,
syntax_theme: &SyntaxHighlightTheme,
) {
let split_code = split_inclusive(&code_text.text);
@ -16,11 +18,11 @@ pub fn highlight_code(
for token_seq in split_code {
let new_word_color = if token_seq.contains(&'\"'.to_string()) {
ed_colors::STRING_SYNTAX_COL
syntax_theme.string
} else if token_seq.contains(&'='.to_string()) {
ed_colors::EQUALS_SYNTAX_COL
syntax_theme.operator
} else {
gr_colors::WHITE
syntax_theme.code
};
if new_word_color != active_color {

View File

@ -1,7 +1,10 @@
pub type ColorTup = (f32, f32, f32, f32);
pub const WHITE: ColorTup = (1.0, 1.0, 1.0, 1.0);
pub fn to_wgpu_color((r, g, b, a): ColorTup) -> wgpu::Color {
use palette::{Hsv, LinSrgb};
pub type RgbaTup = (f32, f32, f32, f32);
pub const WHITE: RgbaTup = (1.0, 1.0, 1.0, 1.0);
pub fn to_wgpu_color((r, g, b, a): RgbaTup) -> wgpu::Color {
wgpu::Color {
r: r as f64,
g: g as f64,
@ -10,6 +13,22 @@ pub fn to_wgpu_color((r, g, b, a): ColorTup) -> wgpu::Color {
}
}
pub fn to_slice((r, g, b, a): ColorTup) -> [f32; 4] {
pub fn to_slice((r, g, b, a): RgbaTup) -> [f32; 4] {
[r, g, b, a]
}
pub fn from_hsb(hue: usize, saturation: usize, brightness: usize) -> RgbaTup {
from_hsba(hue, saturation, brightness, 1.0)
}
pub fn from_hsba(hue: usize, saturation: usize, brightness: usize, alpha: f32) -> RgbaTup {
let rgb = LinSrgb::from(
Hsv::new(
hue as f32,
(saturation as f32)/100.0,
(brightness as f32)/100.0
)
);
(rgb.red, rgb.green, rgb.blue, alpha)
}

View File

@ -4,8 +4,8 @@
use super::rect::Rect;
use crate::editor::syntax_highlight;
use crate::graphics::colors;
use crate::graphics::colors::ColorTup;
use crate::graphics::style::{CODE_FONT_SIZE, CODE_TXT_XY};
use crate::graphics::colors::RgbaTup;
use crate::graphics::style::{DEFAULT_FONT_SIZE, CODE_TXT_XY};
use ab_glyph::{FontArc, Glyph, InvalidFont};
use cgmath::{Vector2, Vector4};
use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section};
@ -14,7 +14,7 @@ use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section
pub struct Text<'a> {
pub position: Vector2<f32>,
pub area_bounds: Vector2<f32>,
pub color: Vector4<f32>,
pub color: RgbaTup,
pub text: &'a str,
pub size: f32,
pub visible: bool,
@ -26,9 +26,9 @@ impl<'a> Default for Text<'a> {
Self {
position: (0.0, 0.0).into(),
area_bounds: (std::f32::INFINITY, std::f32::INFINITY).into(),
color: (1.0, 1.0, 1.0, 1.0).into(),
color: colors::WHITE,
text: "",
size: CODE_FONT_SIZE,
size: DEFAULT_FONT_SIZE,
visible: true,
centered: false,
}
@ -40,9 +40,9 @@ pub fn example_code_glyph_rect(glyph_brush: &mut GlyphBrush<()>) -> Rect {
let code_text = Text {
position: CODE_TXT_XY.into(),
area_bounds: (std::f32::INFINITY, std::f32::INFINITY).into(),
color: (1.0, 1.0, 1.0, 1.0).into(),
color: colors::WHITE,
text: "a",
size: CODE_FONT_SIZE,
size: DEFAULT_FONT_SIZE,
..Default::default()
};
@ -79,7 +79,7 @@ fn section_from_text<'a>(
}
.add_text(
wgpu_glyph::Text::new(&text.text)
.with_color(text.color)
.with_color(Vector4::from(text.color))
.with_scale(text.size),
)
}
@ -98,13 +98,13 @@ fn section_from_glyph_text(
}
}
fn colored_text_to_glyph_text(text_tups: &[(String, ColorTup)]) -> Vec<wgpu_glyph::Text> {
fn colored_text_to_glyph_text(text_tups: &[(String, RgbaTup)]) -> Vec<wgpu_glyph::Text> {
text_tups
.iter()
.map(|(word_string, color_tup)| {
wgpu_glyph::Text::new(&word_string)
.with_color(colors::to_slice(*color_tup))
.with_scale(CODE_FONT_SIZE)
.with_scale(DEFAULT_FONT_SIZE)
})
.collect()
}
@ -117,11 +117,14 @@ pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) {
glyph_brush.queue(section.clone());
}
// TODO move this out of graphics folder and make syntax_theme an argument
pub fn queue_code_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) {
let layout = layout_from_text(text);
let mut all_text_tups: Vec<(String, ColorTup)> = Vec::new();
syntax_highlight::highlight_code(text, &mut all_text_tups);
let mut all_text_tups: Vec<(String, RgbaTup)> = Vec::new();
let syntax_theme = crate::editor::colors::SyntaxHighlightTheme::default();
syntax_highlight::highlight_code(text, &mut all_text_tups, &syntax_theme);
let glyph_text_vec = colored_text_to_glyph_text(&all_text_tups);
let section = section_from_glyph_text(

View File

@ -1,2 +1,2 @@
pub const CODE_FONT_SIZE: f32 = 30.0;
pub const DEFAULT_FONT_SIZE: f32 = 30.0;
pub const CODE_TXT_XY: (f32, f32) = (30.0, 30.0);

View File

@ -1,8 +1,22 @@
use crate::graphics::colors as gr_colors;
use gr_colors::ColorTup;
use gr_colors::{RgbaTup, from_hsb};
pub const LIGHT_BRAND_COL: ColorTup = (0.506, 0.337, 0.902, 1.0);
//pub const DARK_BRAND_COL: ColorTup = (0.380, 0.169, 0.871, 1.0);
pub const TXT_COL: ColorTup = (1.0, 1.0, 1.0, 1.0);
pub const CARET_COL: ColorTup = gr_colors::WHITE;
pub const SELECT_COL: ColorTup = (0.45, 0.61, 1.0, 1.0);
pub struct UITheme {
pub light_brand: RgbaTup,
pub dark_brand: RgbaTup,
pub text: RgbaTup,
pub caret: RgbaTup,
pub select_highlight: RgbaTup,
}
impl Default for UITheme {
fn default() -> Self {
Self {
light_brand: from_hsb(258, 62, 90),
dark_brand: from_hsb(258, 81, 87),
text: gr_colors::WHITE,
caret: gr_colors::WHITE,
select_highlight: from_hsb(240, 55, 100),
}
}
}

View File

@ -1,6 +1,6 @@
use super::lines::Lines;
use super::text_pos::TextPos;
use crate::ui::colors;
use crate::ui::colors::UITheme;
use crate::ui::ui_error::{InvalidSelection, UIResult};
use bumpalo::collections::Vec as BumpVec;
use snafu::ensure;
@ -64,6 +64,7 @@ pub fn create_selection_rects<'a>(
valid_sel: Selection,
lines: &dyn Lines,
glyph_dim_rect: &Rect,
theme: &UITheme,
arena: &'a Bump,
) -> UIResult<BumpVec<'a, Rect>> {
let Selection { start_pos, end_pos } = valid_sel;
@ -83,7 +84,7 @@ pub fn create_selection_rects<'a>(
top_left_coords: (sel_rect_x, start_y).into(),
width,
height,
color: colors::SELECT_COL,
color: theme.select_highlight,
});
Ok(all_rects)
@ -99,7 +100,7 @@ pub fn create_selection_rects<'a>(
top_left_coords: (sel_rect_x, start_y).into(),
width,
height,
color: colors::SELECT_COL,
color: theme.select_highlight,
});
//middle lines
@ -117,7 +118,7 @@ pub fn create_selection_rects<'a>(
top_left_coords: (line_start_x, sel_rect_y).into(),
width,
height,
color: colors::SELECT_COL,
color: theme.select_highlight,
});
}
@ -132,7 +133,7 @@ pub fn create_selection_rects<'a>(
top_left_coords: (line_start_x, sel_rect_y).into(),
width,
height,
color: colors::SELECT_COL,
color: theme.select_highlight,
});
}