Add text color to TextBox, fix resizing
This commit is contained in:
parent
091b9d2840
commit
bd327e4a21
1 changed files with 99 additions and 84 deletions
|
|
@ -17,12 +17,14 @@ use cosmic_text::{
|
||||||
TextBuffer,
|
TextBuffer,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
cmp,
|
||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Appearance {
|
pub struct Appearance {
|
||||||
background_color: Option<Color>,
|
background_color: Option<Color>,
|
||||||
|
text_color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait StyleSheet {
|
pub trait StyleSheet {
|
||||||
|
|
@ -34,9 +36,11 @@ impl StyleSheet for Theme {
|
||||||
match self {
|
match self {
|
||||||
Theme::Dark => Appearance {
|
Theme::Dark => Appearance {
|
||||||
background_color: Some(Color::from_rgb8(0x34, 0x34, 0x34)),
|
background_color: Some(Color::from_rgb8(0x34, 0x34, 0x34)),
|
||||||
|
text_color: Color::from_rgb8(0xFF, 0xFF, 0xFF),
|
||||||
},
|
},
|
||||||
Theme::Light => Appearance {
|
Theme::Light => Appearance {
|
||||||
background_color: Some(Color::from_rgb8(0xFC, 0xFC, 0xFC)),
|
background_color: Some(Color::from_rgb8(0xFC, 0xFC, 0xFC)),
|
||||||
|
text_color: Color::from_rgb8(0x00, 0x00, 0x00),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +120,9 @@ where
|
||||||
) {
|
) {
|
||||||
let state = tree.state.downcast_ref::<State>();
|
let state = tree.state.downcast_ref::<State>();
|
||||||
|
|
||||||
if let Some(background_color) = theme.appearance().background_color {
|
let appearance = theme.appearance();
|
||||||
|
|
||||||
|
if let Some(background_color) = appearance.background_color {
|
||||||
renderer.fill_quad(
|
renderer.fill_quad(
|
||||||
renderer::Quad {
|
renderer::Quad {
|
||||||
bounds: layout.bounds(),
|
bounds: layout.bounds(),
|
||||||
|
|
@ -128,7 +134,93 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((w, h, pixels)) = &state.pixels_opt {
|
let text_color = cosmic_text::Color::rgba(
|
||||||
|
cmp::max(0, cmp::min(255, (appearance.text_color.r * 255.0) as i32)) as u8,
|
||||||
|
cmp::max(0, cmp::min(255, (appearance.text_color.g * 255.0) as i32)) as u8,
|
||||||
|
cmp::max(0, cmp::min(255, (appearance.text_color.b * 255.0) as i32)) as u8,
|
||||||
|
cmp::max(0, cmp::min(255, (appearance.text_color.a * 255.0) as i32)) as u8,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut pixels_opt = state.pixels_opt.lock().unwrap();
|
||||||
|
|
||||||
|
let mut buffer = self.buffer.lock().unwrap();
|
||||||
|
|
||||||
|
let layout_w = layout.bounds().width as i32;
|
||||||
|
let layout_h = layout.bounds().height as i32;
|
||||||
|
buffer.set_size(layout_w, layout_h);
|
||||||
|
|
||||||
|
if buffer.cursor_moved {
|
||||||
|
buffer.shape_until_cursor();
|
||||||
|
buffer.cursor_moved = false;
|
||||||
|
} else {
|
||||||
|
buffer.shape_until_scroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: redraw on color change
|
||||||
|
if buffer.redraw || pixels_opt.is_none() {
|
||||||
|
// Redraw buffer to image
|
||||||
|
|
||||||
|
let instant = Instant::now();
|
||||||
|
|
||||||
|
let mut pixels = vec![0; layout_w as usize * layout_h as usize * 4];
|
||||||
|
|
||||||
|
buffer.draw(&mut self.cache.lock().unwrap(), text_color, |start_x, start_y, w, h, color| {
|
||||||
|
let alpha = (color.0 >> 24) & 0xFF;
|
||||||
|
if alpha == 0 {
|
||||||
|
// Do not draw if alpha is zero
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for y in start_y..start_y + h as i32{
|
||||||
|
if y < 0 || y >= layout_h {
|
||||||
|
// Skip if y out of bounds
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset_y = y as usize * layout_w as usize * 4;
|
||||||
|
for x in start_x..start_x + w as i32 {
|
||||||
|
if x < 0 || x >= layout_w {
|
||||||
|
// Skip if x out of bounds
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset = offset_y + x as usize * 4;
|
||||||
|
|
||||||
|
let mut current =
|
||||||
|
pixels[offset] as u32 |
|
||||||
|
(pixels[offset + 1] as u32) << 8 |
|
||||||
|
(pixels[offset + 2] as u32) << 16 |
|
||||||
|
(pixels[offset + 3] as u32) << 24;
|
||||||
|
|
||||||
|
if alpha >= 255 || current == 0 {
|
||||||
|
// Alpha is 100% or current is null, replace with no blending
|
||||||
|
current = color.0;
|
||||||
|
} else {
|
||||||
|
// Alpha blend with current value
|
||||||
|
let n_alpha = 255 - alpha;
|
||||||
|
let rb = ((n_alpha * (current & 0x00FF00FF)) + (alpha * (color.0 & 0x00FF00FF))) >> 8;
|
||||||
|
let ag = (n_alpha * ((current & 0xFF00FF00) >> 8))
|
||||||
|
+ (alpha * (0x01000000 | ((color.0 & 0x0000FF00) >> 8)));
|
||||||
|
current = (rb & 0x00FF00FF) | (ag & 0xFF00FF00);
|
||||||
|
}
|
||||||
|
|
||||||
|
pixels[offset] = current as u8;
|
||||||
|
pixels[offset + 1] = (current >> 8) as u8;
|
||||||
|
pixels[offset + 2] = (current >> 16) as u8;
|
||||||
|
pixels[offset + 3] = (current >> 24) as u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
*pixels_opt = Some((layout_w as u32, layout_h as u32, pixels));
|
||||||
|
|
||||||
|
buffer.redraw = false;
|
||||||
|
|
||||||
|
let duration = instant.elapsed();
|
||||||
|
log::debug!("redraw: {:?}", duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((w, h, pixels)) = &*pixels_opt {
|
||||||
let handle = image::Handle::from_pixels(*w, *h, pixels.clone());
|
let handle = image::Handle::from_pixels(*w, *h, pixels.clone());
|
||||||
image::Renderer::draw(renderer, handle, layout.bounds());
|
image::Renderer::draw(renderer, handle, layout.bounds());
|
||||||
}
|
}
|
||||||
|
|
@ -147,10 +239,6 @@ where
|
||||||
let state = tree.state.downcast_mut::<State>();
|
let state = tree.state.downcast_mut::<State>();
|
||||||
let mut buffer = self.buffer.lock().unwrap();
|
let mut buffer = self.buffer.lock().unwrap();
|
||||||
|
|
||||||
let layout_w = layout.bounds().width as i32;
|
|
||||||
let layout_h = layout.bounds().height as i32;
|
|
||||||
buffer.set_size(layout_w, layout_h);
|
|
||||||
|
|
||||||
let mut status = Status::Ignored;
|
let mut status = Status::Ignored;
|
||||||
match event {
|
match event {
|
||||||
Event::Keyboard(KeyEvent::KeyPressed { key_code, modifiers }) => match key_code {
|
Event::Keyboard(KeyEvent::KeyPressed { key_code, modifiers }) => match key_code {
|
||||||
|
|
@ -239,81 +327,6 @@ where
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
if buffer.cursor_moved {
|
|
||||||
buffer.shape_until_cursor();
|
|
||||||
buffer.cursor_moved = false;
|
|
||||||
} else {
|
|
||||||
buffer.shape_until_scroll();
|
|
||||||
}
|
|
||||||
|
|
||||||
if layout_w < 0 || layout_h < 0 {
|
|
||||||
// Invalid size, clear pixels
|
|
||||||
state.pixels_opt = None;
|
|
||||||
} else if buffer.redraw || state.pixels_opt.is_none() {
|
|
||||||
// Redraw buffer to image
|
|
||||||
|
|
||||||
let instant = Instant::now();
|
|
||||||
|
|
||||||
let mut pixels = vec![0; layout_w as usize * layout_h as usize * 4];
|
|
||||||
|
|
||||||
//TODO: load from theme somehow
|
|
||||||
let text_color = cosmic_text::Color::rgb(0xFF, 0xFF, 0xFF);
|
|
||||||
buffer.draw(&mut self.cache.lock().unwrap(), text_color, |start_x, start_y, w, h, color| {
|
|
||||||
let alpha = (color.0 >> 24) & 0xFF;
|
|
||||||
if alpha == 0 {
|
|
||||||
// Do not draw if alpha is zero
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for y in start_y..start_y + h as i32{
|
|
||||||
if y < 0 || y >= layout_h {
|
|
||||||
// Skip if y out of bounds
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let offset_y = y as usize * layout_w as usize * 4;
|
|
||||||
for x in start_x..start_x + w as i32 {
|
|
||||||
if x < 0 || x >= layout_w {
|
|
||||||
// Skip if x out of bounds
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let offset = offset_y + x as usize * 4;
|
|
||||||
|
|
||||||
let mut current =
|
|
||||||
pixels[offset] as u32 |
|
|
||||||
(pixels[offset + 1] as u32) << 8 |
|
|
||||||
(pixels[offset + 2] as u32) << 16 |
|
|
||||||
(pixels[offset + 3] as u32) << 24;
|
|
||||||
|
|
||||||
if alpha >= 255 || current == 0 {
|
|
||||||
// Alpha is 100% or current is null, replace with no blending
|
|
||||||
current = color.0;
|
|
||||||
} else {
|
|
||||||
// Alpha blend with current value
|
|
||||||
let n_alpha = 255 - alpha;
|
|
||||||
let rb = ((n_alpha * (current & 0x00FF00FF)) + (alpha * (color.0 & 0x00FF00FF))) >> 8;
|
|
||||||
let ag = (n_alpha * ((current & 0xFF00FF00) >> 8))
|
|
||||||
+ (alpha * (0x01000000 | ((color.0 & 0x0000FF00) >> 8)));
|
|
||||||
current = (rb & 0x00FF00FF) | (ag & 0xFF00FF00);
|
|
||||||
}
|
|
||||||
|
|
||||||
pixels[offset] = current as u8;
|
|
||||||
pixels[offset + 1] = (current >> 8) as u8;
|
|
||||||
pixels[offset + 2] = (current >> 16) as u8;
|
|
||||||
pixels[offset + 3] = (current >> 24) as u8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
state.pixels_opt = Some((layout_w as u32, layout_h as u32, pixels));
|
|
||||||
|
|
||||||
buffer.redraw = false;
|
|
||||||
|
|
||||||
let duration = instant.elapsed();
|
|
||||||
log::debug!("redraw: {:?}", duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
status
|
status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -328,15 +341,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
is_dragging: bool,
|
is_dragging: bool,
|
||||||
pixels_opt: Option<(u32, u32, Vec<u8>)>,
|
pixels_opt: Mutex<Option<(u32, u32, Vec<u8>)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
/// Creates a new [`State`].
|
/// Creates a new [`State`].
|
||||||
pub fn new() -> State {
|
pub fn new() -> State {
|
||||||
State::default()
|
State {
|
||||||
|
is_dragging: false,
|
||||||
|
pixels_opt: Mutex::new(None),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue