Skip to content

Commit 5fb3e8f

Browse files
authored
Merge pull request #680 from kas-gui/push-zokuxsyrwxrs
Infer editor colors from the highlighter
2 parents a7b5c8a + 01dfa55 commit 5fb3e8f

File tree

12 files changed

+230
-38
lines changed

12 files changed

+230
-38
lines changed

crates/kas-core/src/draw/draw.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ impl<'a, DS: DrawSharedImpl> DrawIface<'a, DS> {
137137
col: Rgba,
138138
) {
139139
let tokens = [(0, format::Colors {
140-
color: format::Color::from_rgba(col),
140+
foreground: format::Color::from_rgba(col),
141141
..Default::default()
142142
})];
143143
self.text(pos, bounding_box, text, theme, &tokens);

crates/kas-core/src/text/format.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ pub struct Color(NonZeroU32);
2222

2323
impl Default for Color {
2424
/// Use a theme-defined color (automatic)
25-
///
26-
/// For backgrounds, this uses the text-selection color.
2725
fn default() -> Self {
2826
let color = Rgba8Srgb::rgba(1, 0, 0, 0);
2927
Color(NonZeroU32::new(u32::from_ne_bytes(color.0)).unwrap())
@@ -89,15 +87,17 @@ impl Color {
8987
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
9088
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9189
pub struct Colors {
92-
pub color: Color,
90+
/// The default text color
91+
pub foreground: Color,
92+
/// The text background (highlight) color
9393
pub background: Option<Color>,
9494
}
9595

9696
impl Colors {
9797
/// Resolve the background color, if any
9898
pub fn resolve_background_color(self, theme: &ColorsLinear) -> Option<Rgba> {
9999
self.background
100-
.map(|bg| bg.as_rgba().unwrap_or(theme.text_sel_bg))
100+
.map(|bg| bg.as_rgba().unwrap_or(theme.edit_bg))
101101
}
102102
}
103103

crates/kas-core/src/text/raster.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ impl State {
575575
}
576576
};
577577

578-
let col = token.color.resolve_color(theme, None);
578+
let col = token.foreground.resolve_color(theme, None);
579579
queue.push_sprite(pass, glyph.position.into(), bb, col, sprite);
580580
};
581581

crates/kas-core/src/theme/draw.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ impl<'a> DrawCx<'a> {
320320
pub fn text_with_color<T: FormattableText>(&mut self, rect: Rect, text: &Text<T>, color: Rgba) {
321321
if let Ok(display) = text.display() {
322322
let tokens = [(0, format::Colors {
323-
color: format::Color::from_rgba(color),
323+
foreground: format::Color::from_rgba(color),
324324
..Default::default()
325325
})];
326326
self.text_with_colors(rect.pos, rect, display, &tokens);
@@ -399,9 +399,10 @@ impl<'a> DrawCx<'a> {
399399
rect: Rect,
400400
text: &Text<T>,
401401
byte: usize,
402+
color: Option<format::Color>,
402403
) {
403404
if let Ok(text) = text.display() {
404-
self.h.text_cursor(&self.id, pos, rect, text, byte);
405+
self.h.text_cursor(&self.id, pos, rect, text, byte, color);
405406
}
406407
}
407408

@@ -589,7 +590,15 @@ pub trait ThemeDraw {
589590
/// Draw an edit marker at the given `byte` index on this `text`
590591
///
591592
/// The `text` should be prepared before calling this method.
592-
fn text_cursor(&mut self, id: &Id, pos: Coord, rect: Rect, text: &TextDisplay, byte: usize);
593+
fn text_cursor(
594+
&mut self,
595+
id: &Id,
596+
pos: Coord,
597+
rect: Rect,
598+
text: &TextDisplay,
599+
byte: usize,
600+
color: Option<format::Color>,
601+
);
593602

594603
/// Draw UI element: check box
595604
///

crates/kas-core/src/theme/simple_theme.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,15 @@ impl<'a, DS: DrawSharedImpl> ThemeDraw for DrawHandle<'a, DS> {
378378
.decorate_text(pos.cast(), bb, text, self.cols, decorations);
379379
}
380380

381-
fn text_cursor(&mut self, id: &Id, pos: Coord, rect: Rect, text: &TextDisplay, byte: usize) {
381+
fn text_cursor(
382+
&mut self,
383+
id: &Id,
384+
pos: Coord,
385+
rect: Rect,
386+
text: &TextDisplay,
387+
byte: usize,
388+
color: Option<format::Color>,
389+
) {
382390
if self.ev.window_has_focus() && !self.w.anim.text_cursor(self.draw.draw, id, byte) {
383391
return;
384392
}
@@ -388,7 +396,10 @@ impl<'a, DS: DrawSharedImpl> ThemeDraw for DrawHandle<'a, DS> {
388396
let bb = Quad::conv(rect);
389397
let l_half = (0.5 * width).floor();
390398

391-
let mut col = self.cols.nav_focus;
399+
let mut col = color
400+
.and_then(|c| c.as_rgba())
401+
.unwrap_or(self.cols.nav_focus);
402+
392403
for cursor in text.text_glyph_pos(byte).rev() {
393404
let mut p1 = pos + Vec2::from(cursor.pos);
394405
let mut p2 = p1;

crates/kas-macros/src/extends.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,9 @@ impl Methods {
109109
rect: Rect,
110110
text: &TextDisplay,
111111
byte: usize,
112+
color: Option<::kas::text::format::Color>,
112113
) {
113-
(#base).text_cursor(id, pos, rect, text, byte);
114+
(#base).text_cursor(id, pos, rect, text, byte, color);
114115
}
115116

116117
fn check_box(&mut self, id: &Id, rect: Rect, checked: bool, last_change: Option<Instant>) {

crates/kas-widgets/src/edit/edit_box.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use kas::event::Scroll;
1212
use kas::event::components::ScrollComponent;
1313
use kas::messages::{ReplaceSelectedText, SetValueText};
1414
use kas::prelude::*;
15-
use kas::theme::{Background, FrameStyle, TextClass};
15+
use kas::theme::{FrameStyle, TextClass};
1616
use std::fmt::{Debug, Display};
1717
use std::str::FromStr;
1818

@@ -110,11 +110,7 @@ mod EditBox {
110110
fn draw(&self, mut draw: DrawCx) {
111111
let mut draw_inner = draw.re();
112112
draw_inner.set_id(self.inner.id());
113-
let bg = if self.inner.has_error() {
114-
Background::Error
115-
} else {
116-
Background::Default
117-
};
113+
let bg = self.inner.background_color();
118114
draw_inner.frame(self.rect(), FrameStyle::EditBox, bg);
119115

120116
self.inner

crates/kas-widgets/src/edit/edit_field.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::edit::highlight::{Highlighter, Plain};
1010
use kas::event::CursorIcon;
1111
use kas::messages::{ReplaceSelectedText, SetValueText};
1212
use kas::prelude::*;
13-
use kas::theme::TextClass;
13+
use kas::theme::{Background, TextClass};
1414
use std::fmt::{Debug, Display};
1515
use std::ops::DerefMut;
1616
use std::str::FromStr;
@@ -255,10 +255,17 @@ mod EditField {
255255
}
256256

257257
/// Set a new highlighter of the same type
258+
#[inline]
258259
pub fn set_highlighter(&mut self, highlighter: H) {
259260
self.editor.set_highlighter(highlighter);
260261
}
261262

263+
/// Get the background color
264+
#[inline]
265+
pub fn background_color(&self) -> Background {
266+
self.editor.background_color()
267+
}
268+
262269
/// Call the [`EditGuard`]'s `activate` method
263270
#[inline]
264271
pub fn call_guard_activate(&mut self, cx: &mut EventCx, data: &G::Data) {

crates/kas-widgets/src/edit/editor.rs

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55

66
//! Text editor component
77
8-
use super::highlight::{self, Highlighter};
8+
use super::highlight::{self, Highlighter, SchemeColors};
99
use super::*;
1010
use kas::event::components::{TextInput, TextInputAction};
1111
use kas::event::{ElementState, FocusSource, Ime, ImePurpose, ImeSurroundingText, Scroll};
1212
use kas::geom::Vec2;
1313
use kas::prelude::*;
1414
use kas::text::format::FormattableText;
1515
use kas::text::{CursorRange, NotReady, SelectionHelper, format};
16-
use kas::theme::{Text, TextClass};
16+
use kas::theme::{Background, Text, TextClass};
1717
use kas::util::UndoStack;
1818
use std::borrow::Cow;
1919
use unicode_segmentation::{GraphemeCursor, UnicodeSegmentation};
@@ -31,6 +31,7 @@ pub struct EditorComponent<H: Highlighter> {
3131
id: Id,
3232
editable: bool,
3333
text: Text<highlight::Text<H>>,
34+
colors: SchemeColors,
3435
selection: SelectionHelper,
3536
edit_x_coord: Option<f32>,
3637
last_edit: Option<EditOp>,
@@ -94,6 +95,7 @@ impl<H: Default + Highlighter> Default for Component<H> {
9495
id: Id::default(),
9596
editable: true,
9697
text: Text::new(Default::default(), TextClass::Editor, false),
98+
colors: SchemeColors::default(),
9799
selection: Default::default(),
98100
edit_x_coord: None,
99101
last_edit: Some(EditOp::Initial),
@@ -134,6 +136,7 @@ impl<H: Highlighter> Component<H> {
134136
id: self.0.id,
135137
editable: self.0.editable,
136138
text: Text::new(text, class, wrap),
139+
colors: self.0.colors,
137140
selection: self.0.selection,
138141
edit_x_coord: self.0.edit_x_coord,
139142
last_edit: self.0.last_edit,
@@ -151,6 +154,17 @@ impl<H: Highlighter> Component<H> {
151154
self.text.text_mut().set_highlighter(highlighter);
152155
}
153156

157+
/// Get the background color
158+
pub fn background_color(&self) -> Background {
159+
if self.error_state {
160+
Background::Error
161+
} else if let Some(c) = self.colors.background.as_rgba() {
162+
Background::Rgb(c.as_rgb())
163+
} else {
164+
Background::Default
165+
}
166+
}
167+
154168
/// Access text
155169
#[inline]
156170
pub fn text(&self) -> &Text<impl FormattableText> {
@@ -183,6 +197,8 @@ impl<H: Highlighter> Component<H> {
183197
#[inline]
184198
pub fn configure(&mut self, cx: &mut ConfigCx, id: Id) {
185199
self.id = id;
200+
self.text.text_mut().configure(cx);
201+
self.0.colors = self.text.text().scheme_colors();
186202
self.text.configure(&mut cx.size_cx());
187203
}
188204

@@ -205,17 +221,33 @@ impl<H: Highlighter> Component<H> {
205221
let range: Range<u32> = self.selection.range().cast();
206222

207223
let color_tokens = self.text.color_tokens();
208-
let mut buf = [(0, format::Colors::default()); 3];
224+
let default_colors = format::Colors {
225+
foreground: self.colors.foreground,
226+
background: None,
227+
};
228+
let mut buf = [(0, default_colors); 3];
209229
let mut vec = vec![];
210230
let tokens = if range.is_empty() {
211-
color_tokens
231+
if color_tokens.is_empty() {
232+
&buf[..1]
233+
} else {
234+
color_tokens
235+
}
212236
} else if color_tokens.is_empty() {
213237
buf[1].0 = range.start;
214-
buf[1].1.background = Some(format::Color::default());
238+
buf[1].1.foreground = self.colors.selection_foreground;
239+
buf[1].1.background = Some(self.colors.selection_background);
215240
buf[2].0 = range.end;
216241
let r0 = if range.start > 0 { 0 } else { 1 };
217242
&buf[r0..]
218243
} else {
244+
let set_selection_colors = |colors: &mut format::Colors| {
245+
if colors.foreground == self.colors.foreground {
246+
colors.foreground = self.colors.selection_foreground;
247+
}
248+
colors.background = Some(self.colors.selection_background);
249+
};
250+
219251
vec.reserve(color_tokens.len() + 2);
220252
let mut i = 0;
221253
let mut change_index = range.start;
@@ -224,12 +256,12 @@ impl<H: Highlighter> Component<H> {
224256
let (start, mut colors) = color_tokens[i];
225257
if start < change_index {
226258
if in_selection {
227-
colors.background = Some(format::Color::default());
259+
set_selection_colors(&mut colors);
228260
}
229261
} else if start == change_index {
230262
in_selection = change_index == range.start;
231263
if in_selection {
232-
colors.background = Some(format::Color::default());
264+
set_selection_colors(&mut colors);
233265
change_index = range.end;
234266
} else {
235267
change_index = u32::MAX;
@@ -244,7 +276,7 @@ impl<H: Highlighter> Component<H> {
244276
in_selection = change_index == range.start;
245277
if in_selection {
246278
change_index = range.end;
247-
colors.background = Some(Default::default());
279+
set_selection_colors(&mut colors);
248280
} else {
249281
change_index = u32::MAX;
250282
};
@@ -254,15 +286,19 @@ impl<H: Highlighter> Component<H> {
254286
vec.push((start, colors));
255287
i += 1;
256288
}
289+
let last_colors = if i > 0 {
290+
color_tokens[i - 1].1
291+
} else {
292+
Default::default()
293+
};
257294
if change_index == range.start {
258-
vec.push((range.start, format::Colors {
259-
color: Default::default(),
260-
background: Some(Default::default()),
261-
}));
295+
let mut colors = last_colors;
296+
set_selection_colors(&mut colors);
297+
vec.push((range.start, colors));
262298
change_index = range.end;
263299
}
264300
if change_index == range.end {
265-
vec.push((range.end, format::Colors::default()));
301+
vec.push((range.end, last_colors));
266302
}
267303
&vec
268304
};
@@ -282,7 +318,13 @@ impl<H: Highlighter> Component<H> {
282318
}
283319

284320
if self.editable && draw.ev_state().has_input_focus(self.id_ref()) == Some(true) {
285-
draw.text_cursor(pos, rect, &self.text, self.selection.edit_index());
321+
draw.text_cursor(
322+
pos,
323+
rect,
324+
&self.text,
325+
self.selection.edit_index(),
326+
Some(self.colors.cursor),
327+
);
286328
}
287329
}
288330

0 commit comments

Comments
 (0)