From 52ac7a25153e19c58828766befdd52ad4c7798d2 Mon Sep 17 00:00:00 2001 From: Hendrik Norkowski Date: Sun, 23 Apr 2023 12:37:12 +0200 Subject: [PATCH] feat(ui): unfocused block cursor: added color calculation POC --- helix-term/src/ui/editor.rs | 18 ++++++++-- helix-view/src/theme.rs | 67 +++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index fa7cfbff94831..5debef635afb5 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -414,6 +414,10 @@ impl EditorView { let base_cursor_scope = theme .find_scope_index_exact("ui.cursor") .unwrap_or(selection_scope); + let base_cursor_unfocused_scope = theme + .find_scope_index_exact("ui.cursor_unfocused") + .unwrap_or(base_cursor_scope); + let base_primary_cursor_scope = theme .find_scope_index("ui.cursor.primary") .unwrap_or(base_cursor_scope); @@ -427,6 +431,12 @@ impl EditorView { Mode::Normal => theme.find_scope_index_exact("ui.cursor.normal"), } .unwrap_or(base_cursor_scope); + let cursor_unfocused_scope = match mode { + Mode::Insert => theme.find_scope_index_exact("ui.cursor.insert.unfocused"), + Mode::Select => theme.find_scope_index_exact("ui.cursor.select.unfocused"), + Mode::Normal => theme.find_scope_index_exact("ui.cursor.normal.unfocused"), + } + .unwrap_or(base_cursor_unfocused_scope); let primary_cursor_scope = match mode { Mode::Insert => theme.find_scope_index_exact("ui.cursor.primary.insert"), @@ -445,11 +455,13 @@ impl EditorView { for (i, range) in selection.iter().enumerate() { let selection_is_primary = i == primary_idx; let (cursor_scope, selection_scope) = if selection_is_primary { - if is_terminal_focused { - (primary_cursor_scope, primary_selection_scope) - } else { + if !is_terminal_focused && cursor_is_block { (primary_cursor_unfocused_scope, primary_selection_scope) + } else { + (primary_cursor_scope, primary_selection_scope) } + } else if !is_terminal_focused && cursor_is_block { + (cursor_unfocused_scope, selection_scope) } else { (cursor_scope, selection_scope) }; diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index a8cc592602916..a8bb3c6d553b5 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -288,9 +288,76 @@ fn build_theme_values( highlights.push(style); } + let fallback_background_color = Color::Black; + let background_color = styles + .get("ui.background") + .map_or(fallback_background_color, |style| { + style.bg.unwrap_or(fallback_background_color) + }); + + let focused_cursor_keys = [ + "ui.cursor", + "ui.cursor.normal", + "ui.cursor.insert", + "ui.cursor.select", + "ui.cursor.primary", + "ui.cursor.primary.normal", + "ui.cursor.primary.insert", + "ui.cursor.primary.select", + ]; + + for focused_cursor_key in focused_cursor_keys { + if let Some(cursor_scope) = styles.get(focused_cursor_key) { + let unfocused_cursor_key = focused_cursor_key.to_owned() + ".unfocused"; + if styles.contains_key(&unfocused_cursor_key) { + continue; + } + + // DIM does not work - calculate dimmed color from fg / bg mix + + if let Some(dimmed_color) = cursor_scope.bg.and_then(|cursor_color| { + calculate_transparent_color(&background_color, &cursor_color, 100) + }) { + let cursor_unfocused_scope = cursor_scope.bg(dimmed_color); + styles.insert(unfocused_cursor_key.to_owned(), cursor_unfocused_scope); + scopes.push(unfocused_cursor_key.to_owned()); + highlights.push(cursor_unfocused_scope); + } + } + } + (styles, scopes, highlights) } +fn calculate_transparent_color( + background: &Color, + foreground: &Color, + opacity: u8, +) -> Option { + // TODO: Impl method for non RGB colors and remove Option from return type + let background = match background { + Color::Rgb(r, g, b) => (*r, *g, *b), + _ => return None, + }; + let foreground = match foreground { + Color::Rgb(r, g, b) => (*r, *g, *b), + _ => return None, + }; + + let opacity_normalized = f32::from(opacity) / 255.0; + Some(Color::Rgb( + ((1.0 - opacity_normalized) * f32::from(background.0) + + opacity_normalized * f32::from(foreground.0)) + .round() as u8, + ((1.0 - opacity_normalized) * f32::from(background.1) + + opacity_normalized * f32::from(foreground.1)) + .round() as u8, + ((1.0 - opacity_normalized) * f32::from(background.2) + + opacity_normalized * f32::from(foreground.2)) + .round() as u8, + )) +} + impl Theme { #[inline] pub fn highlight(&self, index: usize) -> Style {