text shadow + battery display poc

This commit is contained in:
galister
2025-09-29 17:43:16 +09:00
parent a78ae55bdc
commit 90bdf99e32
11 changed files with 105 additions and 32 deletions

View File

@@ -7,7 +7,7 @@ use taffy::TraversePartialTree;
use crate::{
drawing,
layout::Widget,
renderer_vk::text::custom_glyph::CustomGlyph,
renderer_vk::text::{custom_glyph::CustomGlyph, TextShadow},
stack::{self, ScissorStack, TransformStack},
widget::{self},
};
@@ -135,7 +135,7 @@ pub struct PrimitiveExtent {
pub enum RenderPrimitive {
Rectangle(PrimitiveExtent, Rectangle),
Text(PrimitiveExtent, Rc<RefCell<Buffer>>),
Text(PrimitiveExtent, Rc<RefCell<Buffer>>, Option<TextShadow>),
Sprite(PrimitiveExtent, Option<CustomGlyph>), //option because we want as_slice
ScissorEnable(Boundary),
ScissorDisable,

View File

@@ -78,6 +78,25 @@ pub fn parse_text_style(attribs: &[AttribPair]) -> TextStyle {
print_invalid_attrib(key, value);
}
}
"shadow" => {
if let Some(color) = parse_color_hex(value) {
style.shadow.get_or_insert_default().color = color;
}
}
"shadow_x" => {
if let Ok(x) = value.parse::<f32>() {
style.shadow.get_or_insert_default().x = x;
} else {
print_invalid_attrib(key, value);
}
}
"shadow_y" => {
if let Ok(y) = value.parse::<f32>() {
style.shadow.get_or_insert_default().y = y;
} else {
print_invalid_attrib(key, value);
}
}
_ => {}
}
}

View File

@@ -2,20 +2,20 @@ use std::{cell::RefCell, rc::Rc, sync::Arc};
use cosmic_text::Buffer;
use glam::{Mat4, Vec2, Vec3};
use slotmap::{SlotMap, new_key_type};
use slotmap::{new_key_type, SlotMap};
use vulkano::pipeline::graphics::viewport;
use crate::{
drawing::{self},
gfx::{WGfx, cmd::GfxCommandBuffer},
gfx::{cmd::GfxCommandBuffer, WGfx},
};
use super::{
rect::{RectPipeline, RectRenderer},
text::{
DEFAULT_METRICS, FONT_SYSTEM, SWASH_CACHE, TextArea, TextBounds,
text_atlas::{TextAtlas, TextPipeline},
text_renderer::TextRenderer,
TextArea, TextBounds, DEFAULT_METRICS, FONT_SYSTEM, SWASH_CACHE,
},
viewport::Viewport,
};
@@ -248,7 +248,20 @@ impl Context {
.rect_renderer
.add_rect(extent.boundary, *rectangle, &extent.transform);
}
drawing::RenderPrimitive::Text(extent, text) => {
drawing::RenderPrimitive::Text(extent, text, shadow) => {
if let Some(shadow) = shadow {
pass.text_areas.push(TextArea {
buffer: text.clone(),
left: (extent.boundary.pos.x + shadow.x) * self.pixel_scale,
top: (extent.boundary.pos.y + shadow.y) * self.pixel_scale,
bounds: TextBounds::default(), //FIXME: just using boundary coords here doesn't work
scale: self.pixel_scale,
default_color: cosmic_text::Color::rgb(0, 0, 0),
override_color: Some(shadow.color.into()),
custom_glyphs: &[],
transform: extent.transform,
});
}
pass.text_areas.push(TextArea {
buffer: text.clone(),
left: extent.boundary.pos.x * self.pixel_scale,
@@ -256,6 +269,7 @@ impl Context {
bounds: TextBounds::default(), //FIXME: just using boundary coords here doesn't work
scale: self.pixel_scale,
default_color: cosmic_text::Color::rgb(0, 0, 0),
override_color: None,
custom_glyphs: &[],
transform: extent.transform,
});
@@ -269,6 +283,7 @@ impl Context {
scale: self.pixel_scale,
custom_glyphs: sprites.as_slice(),
default_color: cosmic_text::Color::rgb(255, 0, 255),
override_color: None,
transform: extent.transform,
});
}

View File

@@ -25,6 +25,23 @@ const DEFAULT_LINE_HEIGHT_RATIO: f32 = 1.43;
pub(crate) const DEFAULT_METRICS: Metrics =
Metrics::new(DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE * DEFAULT_LINE_HEIGHT_RATIO);
#[derive(Clone)]
pub struct TextShadow {
pub y: f32,
pub x: f32,
pub color: drawing::Color,
}
impl Default for TextShadow {
fn default() -> Self {
Self {
y: 1.5,
x: 1.5,
color: drawing::Color::default(),
}
}
}
#[derive(Default, Clone)]
pub struct TextStyle {
pub size: Option<f32>,
@@ -34,6 +51,7 @@ pub struct TextStyle {
pub weight: Option<FontWeight>,
pub align: Option<HorizontalAlign>,
pub wrap: bool,
pub shadow: Option<TextShadow>,
}
impl From<&TextStyle> for Attrs<'_> {
@@ -60,7 +78,11 @@ impl From<&TextStyle> for Metrics {
impl From<&TextStyle> for Wrap {
fn from(value: &TextStyle) -> Self {
if value.wrap { Self::WordOrGlyph } else { Self::None }
if value.wrap {
Self::WordOrGlyph
} else {
Self::None
}
}
}
@@ -199,6 +221,8 @@ pub struct TextArea<'a> {
pub bounds: TextBounds,
/// The default color of the text area.
pub default_color: Color,
/// Override text color. Used for shadow.
pub override_color: Option<Color>,
/// Additional custom glyphs to render.
pub custom_glyphs: &'a [CustomGlyph],
/// Text transformation

View File

@@ -4,9 +4,9 @@ use crate::{
};
use super::{
ContentType, FontSystem, GlyphDetails, GpuCacheStatus, SwashCache, TextArea,
custom_glyph::{CustomGlyphCacheKey, RasterizeCustomGlyphRequest, RasterizedCustomGlyph},
text_atlas::{GlyphVertex, TextAtlas, TextPipeline},
ContentType, FontSystem, GlyphDetails, GpuCacheStatus, SwashCache, TextArea,
};
use cosmic_text::{Color, SubpixelBin, SwashContent};
use glam::{Mat4, Vec2, Vec3};
@@ -96,7 +96,10 @@ impl TextRenderer {
y_bin,
});
let color = glyph.color.unwrap_or(text_area.default_color);
let color = text_area
.override_color
.or(glyph.color)
.unwrap_or(text_area.default_color);
if let Some(glyph_to_render) = prepare_glyph(
&mut PrepareGlyphParams {
@@ -168,10 +171,10 @@ impl TextRenderer {
for glyph in run.glyphs {
let physical_glyph = glyph.physical((text_area.left, text_area.top), text_area.scale);
let color = match glyph.color_opt {
Some(some) => some,
None => text_area.default_color,
};
let color = text_area
.override_color
.or(glyph.color_opt)
.unwrap_or(text_area.default_color);
if let Some(glyph_to_render) = prepare_glyph(
&mut PrepareGlyphParams {

View File

@@ -10,7 +10,7 @@ use crate::{
globals::Globals,
i18n::{I18n, Translation},
layout::WidgetID,
renderer_vk::text::{FONT_SYSTEM, TextStyle},
renderer_vk::text::{TextStyle, FONT_SYSTEM},
};
use super::{WidgetObj, WidgetState};
@@ -124,6 +124,7 @@ impl WidgetObj for WidgetLabel {
transform: state.transform_stack.get().transform,
},
self.buffer.clone(),
self.params.style.shadow.clone(),
));
}

View File

@@ -7,8 +7,8 @@ use crate::{
drawing::{self, PrimitiveExtent},
layout::WidgetID,
renderer_vk::text::{
DEFAULT_METRICS, FONT_SYSTEM,
custom_glyph::{CustomGlyph, CustomGlyphData},
DEFAULT_METRICS, FONT_SYSTEM,
},
};
@@ -81,6 +81,7 @@ impl WidgetObj for WidgetSprite {
transform: state.transform_stack.get().transform,
},
Rc::new(RefCell::new(buffer)),
None,
));
}
}