feat: canvas alpha
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use glam::{Vec2, Vec3, Vec4};
|
use glam::{Vec2, Vec4};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
command_buffer::CommandBufferUsage,
|
command_buffer::CommandBufferUsage,
|
||||||
format::Format,
|
format::Format,
|
||||||
@@ -19,6 +19,8 @@ use crate::{
|
|||||||
state::AppState,
|
state::AppState,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use self::modular::GuiColor;
|
||||||
|
|
||||||
pub mod font;
|
pub mod font;
|
||||||
pub mod modular;
|
pub mod modular;
|
||||||
|
|
||||||
@@ -32,14 +34,33 @@ struct Rect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parses a color from a HTML hex string
|
// Parses a color from a HTML hex string
|
||||||
pub fn color_parse(html_hex: &str) -> anyhow::Result<Vec3> {
|
pub fn color_parse(html_hex: &str) -> anyhow::Result<GuiColor> {
|
||||||
if html_hex.len() == 7 {
|
if html_hex.len() == 7 {
|
||||||
if let (Ok(r), Ok(g), Ok(b)) = (
|
if let (Ok(r), Ok(g), Ok(b)) = (
|
||||||
u8::from_str_radix(&html_hex[1..3], 16),
|
u8::from_str_radix(&html_hex[1..3], 16),
|
||||||
u8::from_str_radix(&html_hex[3..5], 16),
|
u8::from_str_radix(&html_hex[3..5], 16),
|
||||||
u8::from_str_radix(&html_hex[5..7], 16),
|
u8::from_str_radix(&html_hex[5..7], 16),
|
||||||
) {
|
) {
|
||||||
return Ok(Vec3::new(r as f32 / 255., g as f32 / 255., b as f32 / 255.));
|
return Ok(Vec4::new(
|
||||||
|
r as f32 / 255.,
|
||||||
|
g as f32 / 255.,
|
||||||
|
b as f32 / 255.,
|
||||||
|
1.,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if html_hex.len() == 9 {
|
||||||
|
if let (Ok(r), Ok(g), Ok(b), Ok(a)) = (
|
||||||
|
u8::from_str_radix(&html_hex[1..3], 16),
|
||||||
|
u8::from_str_radix(&html_hex[3..5], 16),
|
||||||
|
u8::from_str_radix(&html_hex[5..7], 16),
|
||||||
|
u8::from_str_radix(&html_hex[7..9], 16),
|
||||||
|
) {
|
||||||
|
return Ok(Vec4::new(
|
||||||
|
r as f32 / 255.,
|
||||||
|
g as f32 / 255.,
|
||||||
|
b as f32 / 255.,
|
||||||
|
a as f32 / 255.,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bail!(
|
bail!(
|
||||||
@@ -51,8 +72,8 @@ pub fn color_parse(html_hex: &str) -> anyhow::Result<Vec3> {
|
|||||||
pub struct CanvasBuilder<D, S> {
|
pub struct CanvasBuilder<D, S> {
|
||||||
canvas: Canvas<D, S>,
|
canvas: Canvas<D, S>,
|
||||||
|
|
||||||
pub fg_color: Vec3,
|
pub fg_color: GuiColor,
|
||||||
pub bg_color: Vec3,
|
pub bg_color: GuiColor,
|
||||||
pub font_size: isize,
|
pub font_size: isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,8 +87,8 @@ impl<D, S> CanvasBuilder<D, S> {
|
|||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
canvas: Canvas::new(width, height, graphics, format, data)?,
|
canvas: Canvas::new(width, height, graphics, format, data)?,
|
||||||
bg_color: Vec3::ZERO,
|
bg_color: Vec4::ZERO,
|
||||||
fg_color: Vec3::ONE,
|
fg_color: Vec4::ONE,
|
||||||
font_size: 16,
|
font_size: 16,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -522,8 +543,8 @@ impl<D, S> OverlayBackend for Canvas<D, S> {
|
|||||||
pub struct Control<D, S> {
|
pub struct Control<D, S> {
|
||||||
pub state: Option<S>,
|
pub state: Option<S>,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
fg_color: Vec3,
|
fg_color: GuiColor,
|
||||||
bg_color: Vec3,
|
bg_color: GuiColor,
|
||||||
text: Arc<str>,
|
text: Arc<str>,
|
||||||
size: isize,
|
size: isize,
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
@@ -554,8 +575,8 @@ impl<D, S> Control<D, S> {
|
|||||||
w: 0.,
|
w: 0.,
|
||||||
h: 0.,
|
h: 0.,
|
||||||
},
|
},
|
||||||
fg_color: Vec3::ONE,
|
fg_color: Vec4::ONE,
|
||||||
bg_color: Vec3::ZERO,
|
bg_color: Vec4::ZERO,
|
||||||
text: Arc::from(""),
|
text: Arc::from(""),
|
||||||
dirty: true,
|
dirty: true,
|
||||||
size: 24,
|
size: 24,
|
||||||
@@ -581,7 +602,7 @@ impl<D, S> Control<D, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_fg_color(&mut self, color: Vec3) {
|
pub fn set_fg_color(&mut self, color: GuiColor) {
|
||||||
if self.fg_color == color {
|
if self.fg_color == color {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -604,10 +625,9 @@ impl<D, S> Control<D, S> {
|
|||||||
self.rect.w,
|
self.rect.w,
|
||||||
self.rect.h,
|
self.rect.h,
|
||||||
)?;
|
)?;
|
||||||
let set0 = canvas.pipeline_bg_color.uniform_buffer(
|
let set0 = canvas
|
||||||
0,
|
.pipeline_bg_color
|
||||||
vec![self.bg_color.x, self.bg_color.y, self.bg_color.z, 1.],
|
.uniform_buffer(0, self.bg_color.to_array().to_vec())?;
|
||||||
)?;
|
|
||||||
canvas.pipeline_bg_color.create_pass(
|
canvas.pipeline_bg_color.create_pass(
|
||||||
[canvas.width as _, canvas.height as _],
|
[canvas.width as _, canvas.height as _],
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
@@ -624,7 +644,7 @@ impl<D, S> Control<D, S> {
|
|||||||
canvas: &CanvasData<D>,
|
canvas: &CanvasData<D>,
|
||||||
_: &mut AppState,
|
_: &mut AppState,
|
||||||
cmd_buffer: &mut WlxCommandBuffer,
|
cmd_buffer: &mut WlxCommandBuffer,
|
||||||
color: Vec4,
|
color: GuiColor,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let vertex_buffer = canvas.graphics.upload_verts(
|
let vertex_buffer = canvas.graphics.upload_verts(
|
||||||
canvas.width as _,
|
canvas.width as _,
|
||||||
@@ -676,10 +696,9 @@ impl<D, S> Control<D, S> {
|
|||||||
ImageView::new_default(tex)?,
|
ImageView::new_default(tex)?,
|
||||||
Filter::Linear,
|
Filter::Linear,
|
||||||
)?;
|
)?;
|
||||||
let set1 = canvas.pipeline_fg_glyph.uniform_buffer(
|
let set1 = canvas
|
||||||
1,
|
.pipeline_fg_glyph
|
||||||
vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.],
|
.uniform_buffer(1, self.fg_color.to_array().to_vec())?;
|
||||||
)?;
|
|
||||||
let pass = canvas.pipeline_fg_glyph.create_pass(
|
let pass = canvas.pipeline_fg_glyph.create_pass(
|
||||||
[canvas.width as _, canvas.height as _],
|
[canvas.width as _, canvas.height as _],
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
@@ -725,10 +744,9 @@ impl<D, S> Control<D, S> {
|
|||||||
ImageView::new_default(tex)?,
|
ImageView::new_default(tex)?,
|
||||||
Filter::Linear,
|
Filter::Linear,
|
||||||
)?;
|
)?;
|
||||||
let set1 = canvas.pipeline_fg_glyph.uniform_buffer(
|
let set1 = canvas
|
||||||
1,
|
.pipeline_fg_glyph
|
||||||
vec![self.fg_color.x, self.fg_color.y, self.fg_color.z, 1.],
|
.uniform_buffer(1, self.fg_color.to_array().to_vec())?;
|
||||||
)?;
|
|
||||||
let pass = canvas.pipeline_fg_glyph.create_pass(
|
let pass = canvas.pipeline_fg_glyph.create_pass(
|
||||||
[canvas.width as _, canvas.height as _],
|
[canvas.width as _, canvas.height as _],
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use chrono_tz::Tz;
|
use chrono_tz::Tz;
|
||||||
use glam::Vec3;
|
use glam::Vec4;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
io::Read,
|
io::Read,
|
||||||
@@ -13,7 +13,7 @@ use crate::{gui::modular::FALLBACK_COLOR, state::AppState};
|
|||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use super::{color_parse_or_default, ExecArgs, ModularControl, ModularData};
|
use super::{color_parse_or_default, ExecArgs, GuiColor, ModularControl, ModularData};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(tag = "source")]
|
#[serde(tag = "source")]
|
||||||
@@ -45,9 +45,9 @@ pub enum LabelData {
|
|||||||
Battery {
|
Battery {
|
||||||
device: usize,
|
device: usize,
|
||||||
low_threshold: f32,
|
low_threshold: f32,
|
||||||
normal_color: Vec3,
|
normal_color: GuiColor,
|
||||||
low_color: Vec3,
|
low_color: GuiColor,
|
||||||
charging_color: Vec3,
|
charging_color: GuiColor,
|
||||||
},
|
},
|
||||||
Clock {
|
Clock {
|
||||||
format: Arc<str>,
|
format: Arc<str>,
|
||||||
@@ -86,7 +86,7 @@ pub fn modular_label_init(label: &mut ModularControl, content: &LabelContent) {
|
|||||||
let tz: Option<Tz> = timezone.as_ref().map(|tz| {
|
let tz: Option<Tz> = timezone.as_ref().map(|tz| {
|
||||||
tz.parse().unwrap_or_else(|_| {
|
tz.parse().unwrap_or_else(|_| {
|
||||||
log::error!("Failed to parse timezone '{}'", &tz);
|
log::error!("Failed to parse timezone '{}'", &tz);
|
||||||
label.set_fg_color(FALLBACK_COLOR);
|
label.set_fg_color(*FALLBACK_COLOR);
|
||||||
Tz::UTC
|
Tz::UTC
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -153,7 +153,7 @@ pub(super) fn label_update(control: &mut ModularControl, _: &mut (), app: &mut A
|
|||||||
};
|
};
|
||||||
(text, color)
|
(text, color)
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| ("".into(), Vec3::ZERO));
|
.unwrap_or_else(|| ("".into(), Vec4::ZERO));
|
||||||
|
|
||||||
control.set_text(&text);
|
control.set_text(&text);
|
||||||
control.set_fg_color(color);
|
control.set_fg_color(color);
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ pub mod label;
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use glam::Vec3;
|
use glam::Vec4;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{backend::common::OverlaySelector, state::AppState};
|
use crate::{backend::common::OverlaySelector, state::AppState};
|
||||||
@@ -19,11 +20,9 @@ use super::{color_parse, Canvas, CanvasBuilder, Control};
|
|||||||
type ModularControl = Control<(), ModularData>;
|
type ModularControl = Control<(), ModularData>;
|
||||||
type ExecArgs = Vec<Arc<str>>;
|
type ExecArgs = Vec<Arc<str>>;
|
||||||
|
|
||||||
const FALLBACK_COLOR: Vec3 = Vec3 {
|
pub type GuiColor = Vec4;
|
||||||
x: 1.,
|
|
||||||
y: 0.,
|
static FALLBACK_COLOR: Lazy<GuiColor> = Lazy::new(|| Vec4::new(1., 0., 1., 1.));
|
||||||
z: 1.,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct ModularUiConfig {
|
pub struct ModularUiConfig {
|
||||||
@@ -130,7 +129,7 @@ pub fn modular_canvas(
|
|||||||
rect: [x, y, w, h],
|
rect: [x, y, w, h],
|
||||||
bg_color,
|
bg_color,
|
||||||
} => {
|
} => {
|
||||||
canvas.bg_color = color_parse(bg_color).unwrap_or(FALLBACK_COLOR);
|
canvas.bg_color = color_parse(bg_color).unwrap_or(*FALLBACK_COLOR);
|
||||||
canvas.panel(*x, *y, *w, *h);
|
canvas.panel(*x, *y, *w, *h);
|
||||||
}
|
}
|
||||||
ModularElement::Label {
|
ModularElement::Label {
|
||||||
@@ -140,7 +139,7 @@ pub fn modular_canvas(
|
|||||||
data,
|
data,
|
||||||
} => {
|
} => {
|
||||||
canvas.font_size = *font_size;
|
canvas.font_size = *font_size;
|
||||||
canvas.fg_color = color_parse(fg_color).unwrap_or(FALLBACK_COLOR);
|
canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR);
|
||||||
let label = canvas.label(*x, *y, *w, *h, empty_str.clone());
|
let label = canvas.label(*x, *y, *w, *h, empty_str.clone());
|
||||||
modular_label_init(label, data);
|
modular_label_init(label, data);
|
||||||
}
|
}
|
||||||
@@ -152,8 +151,8 @@ pub fn modular_canvas(
|
|||||||
text,
|
text,
|
||||||
data,
|
data,
|
||||||
} => {
|
} => {
|
||||||
canvas.bg_color = color_parse(bg_color).unwrap_or(FALLBACK_COLOR);
|
canvas.bg_color = color_parse(bg_color).unwrap_or(*FALLBACK_COLOR);
|
||||||
canvas.fg_color = color_parse(fg_color).unwrap_or(FALLBACK_COLOR);
|
canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR);
|
||||||
canvas.font_size = *font_size;
|
canvas.font_size = *font_size;
|
||||||
let button = canvas.button(*x, *y, *w, *h, text.clone());
|
let button = canvas.button(*x, *y, *w, *h, text.clone());
|
||||||
modular_button_init(button, data);
|
modular_button_init(button, data);
|
||||||
@@ -177,7 +176,7 @@ pub fn modular_canvas(
|
|||||||
ListLayout::Vertical => (*w, *h / num_buttons),
|
ListLayout::Vertical => (*w, *h / num_buttons),
|
||||||
};
|
};
|
||||||
|
|
||||||
let fg_color = color_parse(fg_color).unwrap_or(FALLBACK_COLOR);
|
let fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR);
|
||||||
canvas.font_size = *font_size;
|
canvas.font_size = *font_size;
|
||||||
canvas.fg_color = fg_color;
|
canvas.fg_color = fg_color;
|
||||||
|
|
||||||
@@ -225,8 +224,8 @@ pub fn modular_canvas(
|
|||||||
ListLayout::Vertical => (*w, *h / num_buttons),
|
ListLayout::Vertical => (*w, *h / num_buttons),
|
||||||
};
|
};
|
||||||
|
|
||||||
canvas.bg_color = color_parse(bg_color).unwrap_or(FALLBACK_COLOR);
|
canvas.bg_color = color_parse(bg_color).unwrap_or(*FALLBACK_COLOR);
|
||||||
canvas.fg_color = color_parse(fg_color).unwrap_or(FALLBACK_COLOR);
|
canvas.fg_color = color_parse(fg_color).unwrap_or(*FALLBACK_COLOR);
|
||||||
canvas.font_size = *font_size;
|
canvas.font_size = *font_size;
|
||||||
|
|
||||||
for screen in state.screens.iter() {
|
for screen in state.screens.iter() {
|
||||||
@@ -326,9 +325,9 @@ pub fn modular_canvas(
|
|||||||
Ok(canvas.build())
|
Ok(canvas.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn color_parse_or_default(color: &str) -> Vec3 {
|
pub fn color_parse_or_default(color: &str) -> GuiColor {
|
||||||
color_parse(color).unwrap_or_else(|e| {
|
color_parse(color).unwrap_or_else(|e| {
|
||||||
log::error!("Failed to parse color '{}': {}", color, e);
|
log::error!("Failed to parse color '{}': {}", color, e);
|
||||||
FALLBACK_COLOR
|
*FALLBACK_COLOR
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user