text shadow + battery display poc
This commit is contained in:
@@ -100,6 +100,16 @@ _Text size in pixel units_
|
|||||||
|
|
||||||
`weight`: "normal" | "bold"
|
`weight`: "normal" | "bold"
|
||||||
|
|
||||||
|
`shadow`: #112233 | #112233CC (default: None)
|
||||||
|
|
||||||
|
`shadow_x`: **float** (default: 1.5)
|
||||||
|
|
||||||
|
_Horizontal offset of the shadow from the original text. Positive is right._
|
||||||
|
|
||||||
|
`shadow_y`: **float** (default: 1.5)
|
||||||
|
|
||||||
|
_Vertical offset of the shadow from the original text. Positive is down._
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## rectangle widget
|
## rectangle widget
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use taffy::TraversePartialTree;
|
|||||||
use crate::{
|
use crate::{
|
||||||
drawing,
|
drawing,
|
||||||
layout::Widget,
|
layout::Widget,
|
||||||
renderer_vk::text::custom_glyph::CustomGlyph,
|
renderer_vk::text::{custom_glyph::CustomGlyph, TextShadow},
|
||||||
stack::{self, ScissorStack, TransformStack},
|
stack::{self, ScissorStack, TransformStack},
|
||||||
widget::{self},
|
widget::{self},
|
||||||
};
|
};
|
||||||
@@ -135,7 +135,7 @@ pub struct PrimitiveExtent {
|
|||||||
|
|
||||||
pub enum RenderPrimitive {
|
pub enum RenderPrimitive {
|
||||||
Rectangle(PrimitiveExtent, Rectangle),
|
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
|
Sprite(PrimitiveExtent, Option<CustomGlyph>), //option because we want as_slice
|
||||||
ScissorEnable(Boundary),
|
ScissorEnable(Boundary),
|
||||||
ScissorDisable,
|
ScissorDisable,
|
||||||
|
|||||||
@@ -78,6 +78,25 @@ pub fn parse_text_style(attribs: &[AttribPair]) -> TextStyle {
|
|||||||
print_invalid_attrib(key, value);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,20 @@ use std::{cell::RefCell, rc::Rc, sync::Arc};
|
|||||||
|
|
||||||
use cosmic_text::Buffer;
|
use cosmic_text::Buffer;
|
||||||
use glam::{Mat4, Vec2, Vec3};
|
use glam::{Mat4, Vec2, Vec3};
|
||||||
use slotmap::{SlotMap, new_key_type};
|
use slotmap::{new_key_type, SlotMap};
|
||||||
use vulkano::pipeline::graphics::viewport;
|
use vulkano::pipeline::graphics::viewport;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
drawing::{self},
|
drawing::{self},
|
||||||
gfx::{WGfx, cmd::GfxCommandBuffer},
|
gfx::{cmd::GfxCommandBuffer, WGfx},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
rect::{RectPipeline, RectRenderer},
|
rect::{RectPipeline, RectRenderer},
|
||||||
text::{
|
text::{
|
||||||
DEFAULT_METRICS, FONT_SYSTEM, SWASH_CACHE, TextArea, TextBounds,
|
|
||||||
text_atlas::{TextAtlas, TextPipeline},
|
text_atlas::{TextAtlas, TextPipeline},
|
||||||
text_renderer::TextRenderer,
|
text_renderer::TextRenderer,
|
||||||
|
TextArea, TextBounds, DEFAULT_METRICS, FONT_SYSTEM, SWASH_CACHE,
|
||||||
},
|
},
|
||||||
viewport::Viewport,
|
viewport::Viewport,
|
||||||
};
|
};
|
||||||
@@ -248,7 +248,20 @@ impl Context {
|
|||||||
.rect_renderer
|
.rect_renderer
|
||||||
.add_rect(extent.boundary, *rectangle, &extent.transform);
|
.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 {
|
pass.text_areas.push(TextArea {
|
||||||
buffer: text.clone(),
|
buffer: text.clone(),
|
||||||
left: extent.boundary.pos.x * self.pixel_scale,
|
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
|
bounds: TextBounds::default(), //FIXME: just using boundary coords here doesn't work
|
||||||
scale: self.pixel_scale,
|
scale: self.pixel_scale,
|
||||||
default_color: cosmic_text::Color::rgb(0, 0, 0),
|
default_color: cosmic_text::Color::rgb(0, 0, 0),
|
||||||
|
override_color: None,
|
||||||
custom_glyphs: &[],
|
custom_glyphs: &[],
|
||||||
transform: extent.transform,
|
transform: extent.transform,
|
||||||
});
|
});
|
||||||
@@ -269,6 +283,7 @@ impl Context {
|
|||||||
scale: self.pixel_scale,
|
scale: self.pixel_scale,
|
||||||
custom_glyphs: sprites.as_slice(),
|
custom_glyphs: sprites.as_slice(),
|
||||||
default_color: cosmic_text::Color::rgb(255, 0, 255),
|
default_color: cosmic_text::Color::rgb(255, 0, 255),
|
||||||
|
override_color: None,
|
||||||
transform: extent.transform,
|
transform: extent.transform,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,23 @@ const DEFAULT_LINE_HEIGHT_RATIO: f32 = 1.43;
|
|||||||
pub(crate) const DEFAULT_METRICS: Metrics =
|
pub(crate) const DEFAULT_METRICS: Metrics =
|
||||||
Metrics::new(DEFAULT_FONT_SIZE, DEFAULT_FONT_SIZE * DEFAULT_LINE_HEIGHT_RATIO);
|
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)]
|
#[derive(Default, Clone)]
|
||||||
pub struct TextStyle {
|
pub struct TextStyle {
|
||||||
pub size: Option<f32>,
|
pub size: Option<f32>,
|
||||||
@@ -34,6 +51,7 @@ pub struct TextStyle {
|
|||||||
pub weight: Option<FontWeight>,
|
pub weight: Option<FontWeight>,
|
||||||
pub align: Option<HorizontalAlign>,
|
pub align: Option<HorizontalAlign>,
|
||||||
pub wrap: bool,
|
pub wrap: bool,
|
||||||
|
pub shadow: Option<TextShadow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&TextStyle> for Attrs<'_> {
|
impl From<&TextStyle> for Attrs<'_> {
|
||||||
@@ -60,7 +78,11 @@ impl From<&TextStyle> for Metrics {
|
|||||||
|
|
||||||
impl From<&TextStyle> for Wrap {
|
impl From<&TextStyle> for Wrap {
|
||||||
fn from(value: &TextStyle) -> Self {
|
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,
|
pub bounds: TextBounds,
|
||||||
/// The default color of the text area.
|
/// The default color of the text area.
|
||||||
pub default_color: Color,
|
pub default_color: Color,
|
||||||
|
/// Override text color. Used for shadow.
|
||||||
|
pub override_color: Option<Color>,
|
||||||
/// Additional custom glyphs to render.
|
/// Additional custom glyphs to render.
|
||||||
pub custom_glyphs: &'a [CustomGlyph],
|
pub custom_glyphs: &'a [CustomGlyph],
|
||||||
/// Text transformation
|
/// Text transformation
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ContentType, FontSystem, GlyphDetails, GpuCacheStatus, SwashCache, TextArea,
|
|
||||||
custom_glyph::{CustomGlyphCacheKey, RasterizeCustomGlyphRequest, RasterizedCustomGlyph},
|
custom_glyph::{CustomGlyphCacheKey, RasterizeCustomGlyphRequest, RasterizedCustomGlyph},
|
||||||
text_atlas::{GlyphVertex, TextAtlas, TextPipeline},
|
text_atlas::{GlyphVertex, TextAtlas, TextPipeline},
|
||||||
|
ContentType, FontSystem, GlyphDetails, GpuCacheStatus, SwashCache, TextArea,
|
||||||
};
|
};
|
||||||
use cosmic_text::{Color, SubpixelBin, SwashContent};
|
use cosmic_text::{Color, SubpixelBin, SwashContent};
|
||||||
use glam::{Mat4, Vec2, Vec3};
|
use glam::{Mat4, Vec2, Vec3};
|
||||||
@@ -96,7 +96,10 @@ impl TextRenderer {
|
|||||||
y_bin,
|
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(
|
if let Some(glyph_to_render) = prepare_glyph(
|
||||||
&mut PrepareGlyphParams {
|
&mut PrepareGlyphParams {
|
||||||
@@ -168,10 +171,10 @@ impl TextRenderer {
|
|||||||
for glyph in run.glyphs {
|
for glyph in run.glyphs {
|
||||||
let physical_glyph = glyph.physical((text_area.left, text_area.top), text_area.scale);
|
let physical_glyph = glyph.physical((text_area.left, text_area.top), text_area.scale);
|
||||||
|
|
||||||
let color = match glyph.color_opt {
|
let color = text_area
|
||||||
Some(some) => some,
|
.override_color
|
||||||
None => text_area.default_color,
|
.or(glyph.color_opt)
|
||||||
};
|
.unwrap_or(text_area.default_color);
|
||||||
|
|
||||||
if let Some(glyph_to_render) = prepare_glyph(
|
if let Some(glyph_to_render) = prepare_glyph(
|
||||||
&mut PrepareGlyphParams {
|
&mut PrepareGlyphParams {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::{
|
|||||||
globals::Globals,
|
globals::Globals,
|
||||||
i18n::{I18n, Translation},
|
i18n::{I18n, Translation},
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
renderer_vk::text::{FONT_SYSTEM, TextStyle},
|
renderer_vk::text::{TextStyle, FONT_SYSTEM},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{WidgetObj, WidgetState};
|
use super::{WidgetObj, WidgetState};
|
||||||
@@ -124,6 +124,7 @@ impl WidgetObj for WidgetLabel {
|
|||||||
transform: state.transform_stack.get().transform,
|
transform: state.transform_stack.get().transform,
|
||||||
},
|
},
|
||||||
self.buffer.clone(),
|
self.buffer.clone(),
|
||||||
|
self.params.style.shadow.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use crate::{
|
|||||||
drawing::{self, PrimitiveExtent},
|
drawing::{self, PrimitiveExtent},
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
renderer_vk::text::{
|
renderer_vk::text::{
|
||||||
DEFAULT_METRICS, FONT_SYSTEM,
|
|
||||||
custom_glyph::{CustomGlyph, CustomGlyphData},
|
custom_glyph::{CustomGlyph, CustomGlyphData},
|
||||||
|
DEFAULT_METRICS, FONT_SYSTEM,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,6 +81,7 @@ impl WidgetObj for WidgetSprite {
|
|||||||
transform: state.transform_stack.get().transform,
|
transform: state.transform_stack.get().transform,
|
||||||
},
|
},
|
||||||
Rc::new(RefCell::new(buffer)),
|
Rc::new(RefCell::new(buffer)),
|
||||||
|
None,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,13 +20,16 @@
|
|||||||
|
|
||||||
<template name="Device">
|
<template name="Device">
|
||||||
<sprite color="~device_color" width="${size}" height="${size}" src="${src}" />
|
<sprite color="~device_color" width="${size}" height="${size}" src="${src}" />
|
||||||
|
<div position="absolute" margin_top="10" margin_left="9">
|
||||||
|
<label _source="battery" _device="${device}" size="18" shadow="#000000" weight="bold" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template name="Set">
|
<template name="Set">
|
||||||
<Button macro="button_style" _press="::OverlayToggle ${handle}">
|
<Button macro="button_style" _press="::OverlayToggle ${handle}">
|
||||||
<sprite width="40" height="40" color="~set_color" src="watch/set2.svg" />
|
<sprite width="40" height="40" color="~set_color" src="watch/set2.svg" />
|
||||||
<div position="absolute" margin_top="11">
|
<div position="absolute" margin_top="9">
|
||||||
<label text="${display}" size="24" color="#000000" weight="bold" />
|
<label text="${display}" size="24" color="#00050F" weight="bold" />
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
</template>
|
</template>
|
||||||
@@ -35,12 +38,12 @@
|
|||||||
<div width="400" height="200">
|
<div width="400" height="200">
|
||||||
<rectangle width="100%" height="100%" padding="4" box_sizing="content_box" flex_wrap="wrap" flex_direction="column" gap="4" color="~bg_color">
|
<rectangle width="100%" height="100%" padding="4" box_sizing="content_box" flex_wrap="wrap" flex_direction="column" gap="4" color="~bg_color">
|
||||||
<div width="100%" flex_direction="row">
|
<div width="100%" flex_direction="row">
|
||||||
<Device src="watch/hmd.svg" size="40" />
|
<Device src="watch/hmd.svg" size="40" device="0" />
|
||||||
<Device src="watch/controller_l.svg" size="36" />
|
<Device src="watch/controller_l.svg" size="36" device="1" />
|
||||||
<Device src="watch/controller_r.svg" size="36" />
|
<Device src="watch/controller_r.svg" size="36" device="2" />
|
||||||
<Device src="watch/track3.svg" size="40" />
|
<Device src="watch/track3.svg" size="40" device="3" />
|
||||||
<Device src="watch/track3.svg" size="40" />
|
<Device src="watch/track3.svg" size="40" device="4" />
|
||||||
<Device src="watch/track3.svg" size="40" />
|
<Device src="watch/track3.svg" size="40" device="5" />
|
||||||
</div>
|
</div>
|
||||||
<div flex_direction="row">
|
<div flex_direction="row">
|
||||||
<div flex_direction="column" padding="4">
|
<div flex_direction="column" padding="4">
|
||||||
@@ -74,4 +77,4 @@
|
|||||||
</rectangle>
|
</rectangle>
|
||||||
</div>
|
</div>
|
||||||
</elements>
|
</elements>
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
@@ -376,16 +376,13 @@ fn battery_on_tick(
|
|||||||
app: &AppState,
|
app: &AppState,
|
||||||
) {
|
) {
|
||||||
let device = app.input_state.devices.get(state.device);
|
let device = app.input_state.devices.get(state.device);
|
||||||
|
|
||||||
let tags = ["", "H", "L", "R", "T"];
|
|
||||||
|
|
||||||
let label = data.obj.get_as_mut::<WidgetLabel>().unwrap();
|
let label = data.obj.get_as_mut::<WidgetLabel>().unwrap();
|
||||||
|
|
||||||
if let Some(device) = device
|
if let Some(device) = device
|
||||||
&& let Some(soc) = device.soc
|
&& let Some(soc) = device.soc
|
||||||
{
|
{
|
||||||
let soc = (soc * 100.).min(99.) as u32;
|
let soc = (soc * 100.).min(99.) as u32;
|
||||||
let text = format!("{}{}", tags[device.role as usize], soc);
|
let text = soc.to_string();
|
||||||
let color = if device.charging {
|
let color = if device.charging {
|
||||||
state.charging_color
|
state.charging_color
|
||||||
} else if soc < state.low_threshold {
|
} else if soc < state.low_threshold {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::{collections::HashMap, rc::Rc};
|
use std::{collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use glam::{Mat4, Vec2, Vec3, vec2, vec3a};
|
use glam::{vec2, vec3a, Mat4, Vec2, Vec3};
|
||||||
use wgui::{
|
use wgui::{
|
||||||
animation::{Animation, AnimationEasing},
|
animation::{Animation, AnimationEasing},
|
||||||
drawing::Color,
|
drawing::Color,
|
||||||
@@ -20,13 +20,13 @@ use crate::{
|
|||||||
backend::overlay::{OverlayData, OverlayState, Positioning},
|
backend::overlay::{OverlayData, OverlayState, Positioning},
|
||||||
gui::panel::GuiPanel,
|
gui::panel::GuiPanel,
|
||||||
state::AppState,
|
state::AppState,
|
||||||
subsystem::hid::{ALT, CTRL, META, SHIFT, SUPER, XkbKeymap},
|
subsystem::hid::{XkbKeymap, ALT, CTRL, META, SHIFT, SUPER},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
KEYBOARD_NAME, KeyButtonData, KeyState, KeyboardBackend, KeyboardState, handle_press,
|
handle_press, handle_release,
|
||||||
handle_release,
|
|
||||||
layout::{self, AltModifier, KeyCapType},
|
layout::{self, AltModifier, KeyCapType},
|
||||||
|
KeyButtonData, KeyState, KeyboardBackend, KeyboardState, KEYBOARD_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
const BACKGROUND_PADDING: f32 = 4.;
|
const BACKGROUND_PADDING: f32 = 4.;
|
||||||
|
|||||||
Reference in New Issue
Block a user