made painter actually how I wanted it (draw now takes in an owned painter)

This commit is contained in:
2025-08-23 15:20:25 -04:00
parent 6fbdf9fbc8
commit 2ffb09bef0
10 changed files with 60 additions and 50 deletions

View File

@@ -6,9 +6,8 @@ pub struct Regioned {
} }
impl<Ctx: 'static> Widget<Ctx> for Regioned { impl<Ctx: 'static> Widget<Ctx> for Regioned {
fn draw(&self, painter: &mut Painter<Ctx>) { fn draw(&self, mut painter: Painter<Ctx>) {
painter.region.select(&self.region); painter.draw_within(&self.inner, self.region);
painter.draw_inner(&self.inner);
} }
} }

View File

@@ -1,13 +1,13 @@
use image::DynamicImage; use image::DynamicImage;
use crate::{Color, TextureHandle, Widget, WidgetFnRet, render::RectPrimitive}; use crate::{Color, Painter, TextureHandle, Widget, WidgetFnRet, render::RectPrimitive};
pub struct Image { pub struct Image {
handle: Option<TextureHandle>, handle: Option<TextureHandle>,
} }
impl<Ctx> Widget<Ctx> for Image { impl<Ctx> Widget<Ctx> for Image {
fn draw(&self, painter: &mut crate::Painter<Ctx>) { fn draw(&self, mut painter: Painter<Ctx>) {
if let Some(handle) = &self.handle { if let Some(handle) = &self.handle {
painter.draw_texture(handle); painter.draw_texture(handle);
} else { } else {

View File

@@ -28,7 +28,7 @@ impl Rect {
} }
impl<Ctx> Widget<Ctx> for Rect { impl<Ctx> Widget<Ctx> for Rect {
fn draw(&self, painter: &mut Painter<Ctx>) { fn draw(&self, mut painter: Painter<Ctx>) {
painter.write(RectPrimitive { painter.write(RectPrimitive {
color: self.color, color: self.color,
radius: self.radius, radius: self.radius,

View File

@@ -6,7 +6,7 @@ pub struct Span {
} }
impl<Ctx: 'static> Widget<Ctx> for Span { impl<Ctx: 'static> Widget<Ctx> for Span {
fn draw(&self, painter: &mut Painter<Ctx>) { fn draw(&self, mut painter: Painter<Ctx>) {
let total = self.sums(); let total = self.sums();
let mut start = UIScalar::min(); let mut start = UIScalar::min();
for (child, length) in &self.children { for (child, length) in &self.children {

View File

@@ -1,11 +1,11 @@
use crate::{Widget, WidgetId}; use crate::{Painter, Widget, WidgetId};
pub struct Stack { pub struct Stack {
pub children: Vec<WidgetId>, pub children: Vec<WidgetId>,
} }
impl<Ctx> Widget<Ctx> for Stack { impl<Ctx> Widget<Ctx> for Stack {
fn draw(&self, painter: &mut crate::Painter<Ctx>) { fn draw(&self, mut painter: Painter<Ctx>) {
for child in &self.children { for child in &self.children {
painter.draw(child); painter.draw(child);
} }

View File

@@ -6,17 +6,18 @@ use crate::{
pub struct Painter<'a, Ctx: 'static> { pub struct Painter<'a, Ctx: 'static> {
nodes: &'a Widgets<Ctx>, nodes: &'a Widgets<Ctx>,
ctx: &'a mut Ctx, ctx: &'a mut Ctx,
sensors_map: &'a mut SensorMap<Ctx>, sensors_map: &'a SensorMap<Ctx>,
active_sensors: &'a mut ActiveSensors, active_sensors: &'a mut ActiveSensors,
primitives: Primitives, primitives: &'a mut Primitives,
pub region: UiRegion, region: UiRegion,
} }
impl<'a, Ctx> Painter<'a, Ctx> { impl<'a, Ctx> Painter<'a, Ctx> {
pub fn new( pub fn new(
nodes: &'a Widgets<Ctx>, nodes: &'a Widgets<Ctx>,
primitives: &'a mut Primitives,
ctx: &'a mut Ctx, ctx: &'a mut Ctx,
sensors_map: &'a mut SensorMap<Ctx>, sensors_map: &'a SensorMap<Ctx>,
active_sensors: &'a mut ActiveSensors, active_sensors: &'a mut ActiveSensors,
) -> Self { ) -> Self {
Self { Self {
@@ -24,59 +25,56 @@ impl<'a, Ctx> Painter<'a, Ctx> {
ctx, ctx,
active_sensors, active_sensors,
sensors_map, sensors_map,
primitives: Primitives::default(), primitives,
region: UiRegion::full(), region: UiRegion::full(),
} }
} }
/// Writes a primitive to be rendered
pub fn write<P: Primitive>(&mut self, data: P) { pub fn write<P: Primitive>(&mut self, data: P) {
self.primitives.write(data, self.region); self.primitives.write(data, self.region);
} }
/// Draws a widget but does NOT maintain the region. /// Draws a widget within this widget's region.
/// Useful if you only have a single widget to draw.
pub fn draw_inner<W>(&mut self, id: &WidgetId<W>)
where
Ctx: 'static,
{
if self.sensors_map.get(&id.id).is_some() {
self.active_sensors.push((self.region, id.id.duplicate()));
}
self.nodes.get_dyn(id).draw(self);
}
/// Draws a widget and maintains the original region.
/// Useful if you need to draw multiple overlapping child widgets.
pub fn draw<W>(&mut self, id: &WidgetId<W>) pub fn draw<W>(&mut self, id: &WidgetId<W>)
where where
Ctx: 'static, Ctx: 'static,
{ {
let old = self.region; self.draw_at(id, self.region);
self.draw_inner(id);
self.region = old;
} }
/// Draws a widget within an inner region and maintains the original region. /// Draws a widget somewhere within this one.
/// Useful if you need to draw multiple child widgets in select areas within the original /// Useful for drawing child widgets in select areas.
/// region. pub fn draw_within<W>(&mut self, id: &WidgetId<W>, region: UiRegion)
pub fn draw_within(&mut self, id: &WidgetId, region: UiRegion)
where where
Ctx: 'static, Ctx: 'static,
{ {
let old = self.region; self.draw_at(id, region.within(&self.region));
self.region.select(&region); }
self.draw_inner(id);
self.region = old; /// Draws a widget in an arbitrary region.
pub fn draw_at<W>(&mut self, id: &WidgetId<W>, region: UiRegion)
where
Ctx: 'static,
{
if self.sensors_map.get(&id.id).is_some() {
self.active_sensors.push((region, id.id.duplicate()));
}
self.nodes.get_dyn(id).draw(Painter {
nodes: self.nodes,
ctx: self.ctx,
sensors_map: self.sensors_map,
active_sensors: self.active_sensors,
primitives: self.primitives,
region,
});
} }
pub fn draw_texture(&mut self, handle: &TextureHandle) { pub fn draw_texture(&mut self, handle: &TextureHandle) {
self.write(handle.inner); self.write(handle.inner);
} }
pub fn finish(self) -> Primitives { pub fn ctx(&mut self) -> &mut Ctx {
self.primitives
}
pub fn ctx_mut(&mut self) -> &mut Ctx {
self.ctx self.ctx
} }
} }

View File

@@ -93,16 +93,17 @@ impl<Ctx> Ui<Ctx> {
Ctx: 'static, Ctx: 'static,
{ {
self.active_sensors.clear(); self.active_sensors.clear();
self.primitives.clear();
let mut painter = Painter::new( let mut painter = Painter::new(
&self.widgets, &self.widgets,
&mut self.primitives,
ctx, ctx,
&mut self.sensor_map, &self.sensor_map,
&mut self.active_sensors, &mut self.active_sensors,
); );
if let Some(base) = &self.base { if let Some(base) = &self.base {
painter.draw_inner(base); painter.draw(base);
} }
self.primitives = painter.finish();
} }
pub fn update(&mut self, ctx: &mut Ctx) pub fn update(&mut self, ctx: &mut Ctx)

View File

@@ -2,7 +2,7 @@ use crate::{Painter, Ui, WidgetId, WidgetIdFnRet};
use std::{any::Any, marker::PhantomData}; use std::{any::Any, marker::PhantomData};
pub trait Widget<Ctx>: Any { pub trait Widget<Ctx>: Any {
fn draw(&self, painter: &mut Painter<Ctx>); fn draw(&self, painter: Painter<Ctx>);
} }
pub struct WidgetTag; pub struct WidgetTag;

View File

@@ -61,6 +61,12 @@ macro_rules! primitives {
} }
} }
impl PrimitiveData {
pub fn clear(&mut self) {
$(self.$name.clear();)*
}
}
$( $(
unsafe impl bytemuck::Pod for $ty {} unsafe impl bytemuck::Pod for $ty {}
unsafe impl bytemuck::Zeroable for $ty {} unsafe impl bytemuck::Zeroable for $ty {}
@@ -87,6 +93,12 @@ impl Primitives {
}); });
vec.push(data); vec.push(data);
} }
pub(crate) fn clear(&mut self) {
self.updated = true;
self.instances.clear();
self.data.clear();
}
} }
primitives!( primitives!(

View File

@@ -89,10 +89,10 @@ impl Client {
ctx.ui[id].color = color.add_rgb(-0.2); ctx.ui[id].color = color.add_rgb(-0.2);
}) })
.edit_on(Sense::HoverStart, move |r, _| { .edit_on(Sense::HoverStart, move |r, _| {
r.color = color.add_rgb(0.1); r.color = color.add_rgb(0.4);
}) })
.edit_on(Sense::PressEnd, move |r, _| { .edit_on(Sense::PressEnd, move |r, _| {
r.color = color.add_rgb(0.1); r.color = color.add_rgb(0.4);
}) })
.edit_on(Sense::HoverEnd, move |r, _| { .edit_on(Sense::HoverEnd, move |r, _| {
r.color = color; r.color = color;