dash-frontend: clock, wgui: refactoring, non-panicking casts

This commit is contained in:
Aleksander
2025-09-16 20:09:13 +02:00
parent 129785daa7
commit 0fdc0e3828
20 changed files with 287 additions and 165 deletions

View File

@@ -5,7 +5,7 @@ use crate::{
animation::{Animation, AnimationEasing},
components::{Component, ComponentBase, ComponentTrait, InitData},
drawing::{self, Color},
event::{EventAlterables, EventListenerCollection, EventListenerKind, ListenerHandleVec},
event::{CallbackDataCommon, EventAlterables, EventListenerCollection, EventListenerKind, ListenerHandleVec},
i18n::Translation,
layout::{Layout, LayoutState, WidgetID},
renderer_vk::text::{FontWeight, TextStyle},
@@ -46,6 +46,16 @@ pub struct ButtonClickEvent<'a> {
pub state: &'a LayoutState,
pub alterables: &'a mut EventAlterables,
}
impl ButtonClickEvent<'_> {
pub const fn as_common(&mut self) -> CallbackDataCommon {
CallbackDataCommon {
alterables: self.alterables,
state: self.state,
}
}
}
pub type ButtonClickCallback = Box<dyn Fn(ButtonClickEvent) -> anyhow::Result<()>>;
struct State {
@@ -61,7 +71,6 @@ struct Data {
initial_hover_border_color: drawing::Color,
id_label: WidgetID, // Label
id_rect: WidgetID, // Rectangle
node_label: taffy::NodeId,
}
pub struct ComponentButton {
@@ -79,15 +88,12 @@ impl ComponentTrait for ComponentButton {
}
impl ComponentButton {
pub fn set_text(&self, state: &LayoutState, alterables: &mut EventAlterables, text: Translation) {
let globals = state.globals.clone();
pub fn set_text(&self, common: &mut CallbackDataCommon, text: Translation) {
let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(self.data.id_label) else {
return;
};
state.widgets.call(self.data.id_label, |label: &mut WidgetLabel| {
label.set_text(&mut globals.i18n(), text);
});
alterables.mark_redraw();
alterables.mark_dirty(self.data.node_label);
label.set_text(common, text);
}
pub fn on_click(&self, func: ButtonClickCallback) {
@@ -115,7 +121,7 @@ fn anim_hover_in(data: Rc<Data>, state: Rc<RefCell<State>>, widget_id: WidgetID)
2,
AnimationEasing::OutQuad,
Box::new(move |common, anim_data| {
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>();
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
anim_hover(rect, &data, anim_data.pos, state.borrow().down);
common.alterables.mark_redraw();
}),
@@ -128,7 +134,7 @@ fn anim_hover_out(data: Rc<Data>, state: Rc<RefCell<State>>, widget_id: WidgetID
8,
AnimationEasing::OutQuad,
Box::new(move |common, anim_data| {
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>();
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
anim_hover(rect, &data, 1.0 - anim_data.pos, state.borrow().down);
common.alterables.mark_redraw();
}),
@@ -190,7 +196,7 @@ fn register_event_mouse_press<U1, U2>(
Box::new(move |common, event_data, _, _| {
let mut state = state.borrow_mut();
let rect = event_data.obj.get_as_mut::<WidgetRectangle>();
let rect = event_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
anim_hover(rect, &data, 1.0, true);
if state.hovered {
@@ -216,7 +222,7 @@ fn register_event_mouse_release<U1, U2>(
data.id_rect,
EventListenerKind::MouseRelease,
Box::new(move |common, event_data, _, _| {
let rect = event_data.obj.get_as_mut::<WidgetRectangle>();
let rect = event_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
anim_hover(rect, &data, 1.0, false);
let mut state = state.borrow_mut();
@@ -272,7 +278,7 @@ pub fn construct<U1, U2>(
let light_text = (params.color.r + params.color.g + params.color.b) < 1.5;
let (id_label, node_label) = layout.add_child(
let (id_label, _node_label) = layout.add_child(
id_rect,
WidgetLabel::create(
&mut globals.get(),
@@ -295,7 +301,6 @@ pub fn construct<U1, U2>(
let data = Rc::new(Data {
id_label,
id_rect,
node_label,
initial_color: params.color,
initial_border_color: params.border_color,
initial_hover_color: params.hover_color,

View File

@@ -8,7 +8,7 @@ use crate::{
animation::{Animation, AnimationEasing},
components::{Component, ComponentBase, ComponentTrait, InitData},
drawing::Color,
event::{EventAlterables, EventListenerCollection, EventListenerKind, ListenerHandleVec},
event::{CallbackDataCommon, EventAlterables, EventListenerCollection, EventListenerKind, ListenerHandleVec},
i18n::Translation,
layout::{self, Layout, LayoutState, WidgetID},
renderer_vk::text::{FontWeight, TextStyle},
@@ -42,6 +42,16 @@ pub struct CheckboxToggleEvent<'a> {
pub alterables: &'a mut EventAlterables,
pub checked: bool,
}
impl CheckboxToggleEvent<'_> {
pub const fn as_common(&mut self) -> CallbackDataCommon {
CallbackDataCommon {
alterables: self.alterables,
state: self.state,
}
}
}
pub type CheckboxToggleCallback = Box<dyn Fn(CheckboxToggleEvent) -> anyhow::Result<()>>;
struct State {
@@ -51,14 +61,13 @@ struct State {
on_toggle: Option<CheckboxToggleCallback>,
}
#[allow(clippy::struct_field_names)]
struct Data {
id_container: WidgetID, // Rectangle, transparent if not hovered
//id_outer_box: WidgetID, // Rectangle, parent of container
id_inner_box: WidgetID, // Rectangle, parent of outer_box
id_label: WidgetID, // Label, parent of container
node_label: taffy::NodeId,
}
pub struct ComponentCheckbox {
@@ -85,15 +94,12 @@ fn set_box_checked(widgets: &layout::WidgetMap, data: &Data, checked: bool) {
}
impl ComponentCheckbox {
pub fn set_text(&self, state: &LayoutState, alterables: &mut EventAlterables, text: Translation) {
let globals = state.globals.clone();
pub fn set_text(&self, state: &LayoutState, common: &mut CallbackDataCommon, text: Translation) {
let Some(mut label) = state.widgets.get_as::<WidgetLabel>(self.data.id_label) else {
return;
};
state.widgets.call(self.data.id_label, |label: &mut WidgetLabel| {
label.set_text(&mut globals.i18n(), text);
});
alterables.mark_redraw();
alterables.mark_dirty(self.data.node_label);
label.set_text(common, text);
}
pub fn set_checked(&self, state: &LayoutState, alterables: &mut EventAlterables, checked: bool) {
@@ -123,7 +129,7 @@ fn anim_hover_in(state: Rc<RefCell<State>>, widget_id: WidgetID) -> Animation {
5,
AnimationEasing::OutQuad,
Box::new(move |common, anim_data| {
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>();
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
anim_hover(rect, anim_data.pos, state.borrow().down);
common.alterables.mark_redraw();
}),
@@ -136,7 +142,7 @@ fn anim_hover_out(state: Rc<RefCell<State>>, widget_id: WidgetID) -> Animation {
8,
AnimationEasing::OutQuad,
Box::new(move |common, anim_data| {
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>();
let rect = anim_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
anim_hover(rect, 1.0 - anim_data.pos, state.borrow().down);
common.alterables.mark_redraw();
}),
@@ -198,7 +204,7 @@ fn register_event_mouse_press<U1, U2>(
Box::new(move |common, event_data, _, _| {
let mut state = state.borrow_mut();
let rect = event_data.obj.get_as_mut::<WidgetRectangle>();
let rect = event_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
anim_hover(rect, 1.0, true);
if state.hovered {
@@ -224,7 +230,7 @@ fn register_event_mouse_release<U1, U2>(
data.id_container,
EventListenerKind::MouseRelease,
Box::new(move |common, event_data, _, _| {
let rect = event_data.obj.get_as_mut::<WidgetRectangle>();
let rect = event_data.obj.get_as_mut::<WidgetRectangle>().unwrap();
anim_hover(rect, 1.0, false);
let mut state = state.borrow_mut();
@@ -327,7 +333,7 @@ pub fn construct<U1, U2>(
},
)?;
let (id_label, node_label) = layout.add_child(
let (id_label, _node_label) = layout.add_child(
id_container,
WidgetLabel::create(
&mut globals.get(),
@@ -346,7 +352,6 @@ pub fn construct<U1, U2>(
id_container,
id_inner_box,
id_label,
node_label,
});
let state = Rc::new(RefCell::new(State {

View File

@@ -2,7 +2,7 @@ use std::rc::Rc;
use crate::{
any::AnyTrait,
event::{self, EventAlterables},
event::{self, CallbackDataCommon, EventAlterables},
layout::LayoutState,
};
@@ -15,6 +15,15 @@ pub struct InitData<'a> {
pub alterables: &'a mut EventAlterables,
}
impl InitData<'_> {
const fn as_common(&mut self) -> CallbackDataCommon {
CallbackDataCommon {
alterables: self.alterables,
state: self.state,
}
}
}
// common component data
#[derive(Default)]
pub struct ComponentBase {
@@ -32,7 +41,6 @@ pub struct Component(pub Rc<dyn ComponentTrait>);
pub type ComponentWeak = std::rc::Weak<dyn ComponentTrait>;
impl Component {
pub fn weak(&self) -> ComponentWeak {
Rc::downgrade(&self.0)
}

View File

@@ -7,9 +7,9 @@ use crate::{
animation::{Animation, AnimationEasing},
components::{Component, ComponentBase, ComponentTrait, InitData},
drawing::{self},
event::{self, CallbackDataCommon, EventAlterables, EventListenerCollection, EventListenerKind, ListenerHandleVec},
i18n::{I18n, Translation},
layout::{Layout, LayoutState, WidgetID},
event::{self, CallbackDataCommon, EventListenerCollection, EventListenerKind, ListenerHandleVec},
i18n::Translation,
layout::{Layout, WidgetID},
renderer_vk::{
text::{FontWeight, HorizontalAlign, TextStyle},
util,
@@ -69,7 +69,7 @@ impl ComponentTrait for ComponentSlider {
fn init(&self, init_data: &mut InitData) {
let mut state = self.state.borrow_mut();
let value = state.values.value;
state.set_value(init_data.state, &self.data, init_data.alterables, value);
state.set_value(&mut init_data.as_common(), &self.data, value);
}
fn base(&mut self) -> &mut ComponentBase {
@@ -125,25 +125,26 @@ impl State {
let target_value = self.values.get_from_normalized(norm);
let val = target_value;
self.set_value(common.state, data, common.alterables, val);
self.set_value(common, data, val);
}
fn update_text(i18n: &mut I18n, text: &mut WidgetLabel, value: f32) {
fn update_text(common: &mut CallbackDataCommon, text: &mut WidgetLabel, value: f32) {
// round displayed value, should be sufficient for now
text.set_text(i18n, Translation::from_raw_text(&format!("{}", value.round())));
text.set_text(common, Translation::from_raw_text(&format!("{}", value.round())));
}
fn set_value(&mut self, state: &LayoutState, data: &Data, alterables: &mut EventAlterables, value: f32) {
fn set_value(&mut self, common: &mut CallbackDataCommon, data: &Data, value: f32) {
//common.call_on_widget(data.slider_handle_id, |_div: &mut Div| {});
self.values.value = value;
let mut style = state.tree.style(data.slider_handle_node).unwrap().clone();
conf_handle_style(&self.values, data.slider_body_node, &mut style, &state.tree);
alterables.mark_dirty(data.slider_handle_node);
alterables.mark_redraw();
alterables.set_style(data.slider_handle_node, style);
state.widgets.call(data.slider_text_id, |label: &mut WidgetLabel| {
Self::update_text(&mut state.globals.i18n(), label, value);
});
let mut style = common.state.tree.style(data.slider_handle_node).unwrap().clone();
conf_handle_style(&self.values, data.slider_body_node, &mut style, &common.state.tree);
common.alterables.mark_dirty(data.slider_handle_node);
common.alterables.mark_redraw();
common.alterables.set_style(data.slider_handle_node, style);
if let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(data.slider_text_id) {
Self::update_text(common, &mut label, value);
}
}
}
@@ -173,7 +174,7 @@ fn on_enter_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID) {
20,
AnimationEasing::OutBack,
Box::new(move |common, data| {
let rect = data.obj.get_as_mut::<WidgetRectangle>();
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
data.data.transform = get_anim_transform(data.pos, data.widget_size);
anim_rect(rect, data.pos);
common.alterables.mark_redraw();
@@ -187,7 +188,7 @@ fn on_leave_anim(common: &mut event::CallbackDataCommon, handle_id: WidgetID) {
10,
AnimationEasing::OutQuad,
Box::new(move |common, data| {
let rect = data.obj.get_as_mut::<WidgetRectangle>();
let rect = data.obj.get_as_mut::<WidgetRectangle>().unwrap();
data.data.transform = get_anim_transform(1.0 - data.pos, data.widget_size);
anim_rect(rect, 1.0 - data.pos);
common.alterables.mark_redraw();

View File

@@ -80,7 +80,6 @@ impl Event {
&& pos.y < transform.pos.y + transform.dim.y
}
pub fn test_mouse_within_transform(&self, transform: &Transform) -> bool {
match self {
Self::MouseDown(evt) => Self::test_transform_pos(transform, evt.pos),
@@ -130,10 +129,17 @@ pub struct CallbackDataCommon<'a> {
}
impl CallbackDataCommon<'_> {
pub fn i18n(&self) -> RefMut<I18n> {
self.state.globals.i18n()
}
// helper function
pub fn mark_widget_dirty(&mut self, id: WidgetID) {
if let Some(node_id) = self.state.nodes.get(id) {
self.alterables.mark_dirty(*node_id);
}
self.alterables.mark_redraw();
}
}
pub struct CallbackData<'a> {
@@ -153,7 +159,7 @@ pub enum CallbackMetadata {
impl CallbackMetadata {
// helper function
pub const fn get_mouse_pos_absolute(&self) -> Option<Vec2> {
match *self {
Self::MouseButton(b) => Some(b.pos),
@@ -162,7 +168,6 @@ impl CallbackMetadata {
}
}
pub fn get_mouse_pos_relative(&self, transform_stack: &TransformStack) -> Option<Vec2> {
let mouse_pos_abs = self.get_mouse_pos_absolute()?;
Some(mouse_pos_abs - transform_stack.get_pos())
@@ -209,18 +214,11 @@ pub struct EventListener<U1, U2> {
}
impl<U1, U2> EventListener<U1, U2> {
pub fn callback_for_kind(
&self,
kind: EventListenerKind,
) -> Option<
&impl Fn(&mut CallbackDataCommon, &mut CallbackData, &mut U1, &mut U2) -> anyhow::Result<()>,
> {
if self.kind == kind {
Some(&self.callback)
} else {
None
}
) -> Option<&impl Fn(&mut CallbackDataCommon, &mut CallbackData, &mut U1, &mut U2) -> anyhow::Result<()>> {
if self.kind == kind { Some(&self.callback) } else { None }
}
}
@@ -311,7 +309,6 @@ impl<U1, U2> EventListenerCollection<U1, U2> {
log::debug!("EventListenerCollection: cleaned-up {count} expired events");
}
pub fn get(&self, widget_id: WidgetID) -> Option<&EventListenerVec<U1, U2>> {
self.map.get(widget_id)
}

View File

@@ -29,10 +29,8 @@ impl Widget {
Self(Rc::new(RefCell::new(widget_state)))
}
// panics on failure
// TODO: panic-less alternative
pub fn get_as_mut<T: 'static>(&self) -> RefMut<T> {
RefMut::map(self.0.borrow_mut(), |w| w.obj.get_as_mut::<T>())
pub fn get_as_mut<T: 'static>(&self) -> Option<RefMut<T>> {
RefMut::filter_map(self.0.borrow_mut(), |w| w.obj.get_as_mut::<T>()).ok()
}
pub fn state(&self) -> RefMut<WidgetState> {
@@ -54,7 +52,7 @@ impl WidgetMap {
}
pub fn get_as<T: 'static>(&self, handle: WidgetID) -> Option<RefMut<T>> {
Some(self.0.get(handle)?.get_as_mut::<T>())
self.0.get(handle)?.get_as_mut::<T>()
}
pub fn get(&self, handle: WidgetID) -> Option<&Widget> {
@@ -62,16 +60,20 @@ impl WidgetMap {
}
pub fn insert(&mut self, obj: Widget) -> WidgetID {
self.0.insert(obj)
self
.0
.try_insert_with_key::<_, ()>(|widget_id| {
obj.state().obj.set_id(widget_id);
Ok(obj)
})
.unwrap()
}
pub fn remove_single(&mut self, handle: WidgetID) {
self.0.remove(handle);
}
// cast to specific widget type, does nothing if widget ID is expired
// panics in case if the widget type is wrong
// TODO: panic-less alternative
// cast to specific widget type, does nothing if widget ID is expired or the type is wrong
pub fn call<WIDGET, FUNC>(&self, widget_id: WidgetID, func: FUNC)
where
WIDGET: WidgetObj,
@@ -82,7 +84,9 @@ impl WidgetMap {
return;
};
func(&mut widget.get_as_mut::<WIDGET>());
if let Some(mut casted) = widget.get_as_mut::<WIDGET>() {
func(&mut casted);
}
}
}
@@ -151,7 +155,7 @@ impl Layout {
) -> anyhow::Result<(WidgetID, taffy::NodeId)> {
let parent_node = *self.state.nodes.get(parent_widget_id).unwrap();
self.needs_redraw = true;
self.mark_redraw();
add_child_internal(
&mut self.state.tree,
@@ -181,7 +185,7 @@ impl Layout {
self.collect_children_ids_recursive(widget_id, &mut ids);
if !ids.is_empty() {
self.needs_redraw = true;
self.mark_redraw();
}
for (widget_id, node_id) in ids {
@@ -191,6 +195,10 @@ impl Layout {
}
}
pub const fn mark_redraw(&mut self) {
self.needs_redraw = true;
}
fn process_pending_components(&mut self) -> anyhow::Result<()> {
let mut alterables = EventAlterables::default();
@@ -365,7 +373,7 @@ impl Layout {
return Ok(());
}
self.needs_redraw = true;
self.mark_redraw();
log::debug!("re-computing layout, size {}x{}", size.x, size.y);
self.prev_size = size;
@@ -429,13 +437,13 @@ impl Layout {
Ok(())
}
fn process_alterables(&mut self, alterables: EventAlterables) -> anyhow::Result<()> {
pub fn process_alterables(&mut self, alterables: EventAlterables) -> anyhow::Result<()> {
for node in alterables.dirty_nodes {
self.state.tree.mark_dirty(node)?;
}
if alterables.needs_redraw {
self.needs_redraw = true;
self.mark_redraw();
}
if alterables.trigger_haptics {
@@ -443,7 +451,7 @@ impl Layout {
}
if !alterables.animations.is_empty() {
self.needs_redraw = true;
self.mark_redraw();
for anim in alterables.animations {
self.animations.add(anim);
}

View File

@@ -709,7 +709,7 @@ impl CustomAttribInfo<'_> {
}
pub fn get_widget_as<T: 'static>(&self) -> Option<RefMut<T>> {
Some(self.widgets.get(self.widget_id)?.get_as_mut::<T>())
self.widgets.get(self.widget_id)?.get_as_mut::<T>()
}
}

View File

@@ -1,10 +1,16 @@
use slotmap::Key;
use crate::layout::WidgetID;
use super::{WidgetObj, WidgetState};
pub struct WidgetDiv {}
pub struct WidgetDiv {
id: WidgetID,
}
impl WidgetDiv {
pub fn create() -> WidgetState {
WidgetState::new(Box::new(Self {}))
WidgetState::new(Box::new(Self { id: WidgetID::null() }))
}
}
@@ -12,4 +18,12 @@ impl WidgetObj for WidgetDiv {
fn draw(&mut self, _state: &mut super::DrawState, _params: &super::DrawParams) {
// no-op
}
fn get_id(&self) -> WidgetID {
self.id
}
fn set_id(&mut self, id: WidgetID) {
self.id = id;
}
}

View File

@@ -1,12 +1,15 @@
use std::{cell::RefCell, rc::Rc};
use cosmic_text::{Attrs, Buffer, Metrics, Shaping, Wrap};
use slotmap::Key;
use taffy::AvailableSpace;
use crate::{
drawing::{self, Boundary},
event::CallbackDataCommon,
globals::Globals,
i18n::{I18n, Translation},
layout::WidgetID,
renderer_vk::text::{FONT_SYSTEM, TextStyle},
};
@@ -19,6 +22,8 @@ pub struct WidgetLabelParams {
}
pub struct WidgetLabel {
id: WidgetID,
params: WidgetLabelParams,
buffer: Rc<RefCell<Buffer>>,
last_boundary: Boundary,
@@ -52,12 +57,15 @@ impl WidgetLabel {
params,
buffer: Rc::new(RefCell::new(buffer)),
last_boundary: Boundary::default(),
id: WidgetID::null(),
}))
}
pub fn set_text(&mut self, i18n: &mut I18n, translation: Translation) {
// set text without layout/re-render update.
// Not recommended unless the widget wasn't rendered yet (first init).
pub fn set_text_simple(&mut self, i18n: &mut I18n, translation: Translation) -> bool {
if self.params.content == translation {
return;
return false;
}
self.params.content = translation;
@@ -72,6 +80,15 @@ impl WidgetLabel {
Shaping::Advanced,
self.params.style.align.map(Into::into),
);
true
}
// set text and check if it needs to be re-rendered/re-layouted
pub fn set_text(&mut self, common: &mut CallbackDataCommon, translation: Translation) {
if self.set_text_simple(&mut common.i18n(), translation) {
common.mark_widget_dirty(self.id);
}
}
}
@@ -118,4 +135,12 @@ impl WidgetObj for WidgetLabel {
let height = total_lines as f32 * buffer.metrics().line_height;
taffy::Size { width, height }
}
fn get_id(&self) -> WidgetID {
self.id
}
fn set_id(&mut self, id: WidgetID) {
self.id = id;
}
}

View File

@@ -111,6 +111,10 @@ pub struct DrawParams<'a> {
}
pub trait WidgetObj: AnyTrait {
// every widget stores their of id for convenience reasons
fn get_id(&self) -> WidgetID;
fn set_id(&mut self, id: WidgetID); // always set at insertion
fn draw(&mut self, state: &mut DrawState, params: &DrawParams);
fn measure(
&mut self,
@@ -173,18 +177,14 @@ pub fn get_scrollbar_info(l: &taffy::Layout) -> Option<ScrollbarInfo> {
}
impl dyn WidgetObj {
// panics on failure
// TODO: panic-less alternative
pub fn get_as<T: 'static>(&self) -> &T {
pub fn get_as<T: 'static>(&self) -> Option<&T> {
let any = self.as_any();
any.downcast_ref::<T>().unwrap()
any.downcast_ref::<T>()
}
// panics on failure
// TODO: panic-less alternative
pub fn get_as_mut<T: 'static>(&mut self) -> &mut T {
pub fn get_as_mut<T: 'static>(&mut self) -> Option<&mut T> {
let any = self.as_any_mut();
any.downcast_mut::<T>().unwrap()
any.downcast_mut::<T>()
}
}

View File

@@ -1,5 +1,8 @@
use slotmap::Key;
use crate::{
drawing::{self, GradientMode},
layout::WidgetID,
widget::util::WLength,
};
@@ -19,11 +22,15 @@ pub struct WidgetRectangleParams {
pub struct WidgetRectangle {
pub params: WidgetRectangleParams,
id: WidgetID,
}
impl WidgetRectangle {
pub fn create(params: WidgetRectangleParams) -> WidgetState {
WidgetState::new(Box::new(Self { params }))
WidgetState::new(Box::new(Self {
params,
id: WidgetID::null(),
}))
}
}
@@ -33,9 +40,7 @@ impl WidgetObj for WidgetRectangle {
let round_units = match self.params.round {
WLength::Units(units) => units as u8,
WLength::Percent(percent) => {
(f32::min(boundary.size.x, boundary.size.y) * percent / 2.0) as u8
}
WLength::Percent(percent) => (f32::min(boundary.size.x, boundary.size.y) * percent / 2.0) as u8,
};
state.primitives.push(drawing::RenderPrimitive {
@@ -52,4 +57,12 @@ impl WidgetObj for WidgetRectangle {
}),
});
}
fn get_id(&self) -> WidgetID {
self.id
}
fn set_id(&mut self, id: WidgetID) {
self.id = id;
}
}

View File

@@ -1,9 +1,11 @@
use std::{cell::RefCell, rc::Rc};
use cosmic_text::{Attrs, Buffer, Color, Shaping, Weight};
use slotmap::Key;
use crate::{
drawing::{self},
layout::WidgetID,
renderer_vk::text::{
DEFAULT_METRICS, FONT_SYSTEM,
custom_glyph::{CustomGlyph, CustomGlyphData},
@@ -21,11 +23,15 @@ pub struct WidgetSpriteParams {
#[derive(Debug, Default)]
pub struct WidgetSprite {
params: WidgetSpriteParams,
id: WidgetID,
}
impl WidgetSprite {
pub fn create(params: WidgetSpriteParams) -> WidgetState {
WidgetState::new(Box::new(Self { params }))
WidgetState::new(Box::new(Self {
params,
id: WidgetID::null(),
}))
}
}
@@ -62,9 +68,7 @@ impl WidgetObj for WidgetSprite {
{
let mut font_system = FONT_SYSTEM.lock();
let mut buffer = buffer.borrow_with(&mut font_system);
let attrs = Attrs::new()
.color(Color::rgb(255, 0, 255))
.weight(Weight::BOLD);
let attrs = Attrs::new().color(Color::rgb(255, 0, 255)).weight(Weight::BOLD);
// set text last in order to avoid expensive re-shaping
buffer.set_text("Error", &attrs, Shaping::Basic);
@@ -85,4 +89,12 @@ impl WidgetObj for WidgetSprite {
) -> taffy::Size<f32> {
taffy::Size::ZERO
}
fn get_id(&self) -> WidgetID {
self.id
}
fn set_id(&mut self, id: WidgetID) {
self.id = id;
}
}