Compare commits
2 Commits
06dd015092
...
remove_siz
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e4a7f8cf5 | |||
| 93291badc1 |
@@ -2,7 +2,7 @@ use crate::vec2;
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct Align {
|
pub struct Align {
|
||||||
pub x: Option<AxisAlign>,
|
pub x: Option<AxisAlign>,
|
||||||
pub y: Option<AxisAlign>,
|
pub y: Option<AxisAlign>,
|
||||||
@@ -24,13 +24,26 @@ impl Align {
|
|||||||
pub const TOP: CardinalAlign = CardinalAlign::TOP;
|
pub const TOP: CardinalAlign = CardinalAlign::TOP;
|
||||||
pub const V_CENTER: CardinalAlign = CardinalAlign::V_CENTER;
|
pub const V_CENTER: CardinalAlign = CardinalAlign::V_CENTER;
|
||||||
pub const BOT: CardinalAlign = CardinalAlign::BOT;
|
pub const BOT: CardinalAlign = CardinalAlign::BOT;
|
||||||
|
pub const NONE: Align = Align { x: None, y: None };
|
||||||
|
|
||||||
pub fn tuple(&self) -> (Option<AxisAlign>, Option<AxisAlign>) {
|
pub fn tuple(&self) -> (Option<AxisAlign>, Option<AxisAlign>) {
|
||||||
(self.x, self.y)
|
(self.x, self.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// naming is a bit inconsistent w option,
|
||||||
|
/// normally would return Self, but can't see
|
||||||
|
/// that being needed atm and would wanna do
|
||||||
|
/// a trait if so, so they can both be named .or
|
||||||
|
/// (because Self impls From<RegionAlign>)
|
||||||
|
pub fn or(&self, other: RegionAlign) -> RegionAlign {
|
||||||
|
RegionAlign {
|
||||||
|
x: self.x.unwrap_or(other.x),
|
||||||
|
y: self.y.unwrap_or(other.x),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum AxisAlign {
|
pub enum AxisAlign {
|
||||||
Neg,
|
Neg,
|
||||||
Center,
|
Center,
|
||||||
@@ -106,6 +119,7 @@ impl UiVec2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// aligns this as a size within a region
|
||||||
pub fn align(&self, align: RegionAlign) -> UiRegion {
|
pub fn align(&self, align: RegionAlign) -> UiRegion {
|
||||||
UiRegion {
|
UiRegion {
|
||||||
x: self.x.align(align.x),
|
x: self.x.align(align.x),
|
||||||
|
|||||||
@@ -140,12 +140,22 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, bytemuck::Pod, Default, bytemuck::Zeroable)]
|
#[derive(Debug, Copy, Clone, bytemuck::Pod, Default, bytemuck::Zeroable)]
|
||||||
pub struct UiScalar {
|
pub struct UiScalar {
|
||||||
pub rel: f32,
|
pub rel: f32,
|
||||||
pub abs: f32,
|
pub abs: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: unknown exactly what these should be
|
||||||
|
const REL_EPSILON: f32 = 0.00001;
|
||||||
|
const ABS_EPSILON: f32 = 0.1;
|
||||||
|
|
||||||
|
impl PartialEq for UiScalar {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
(self.rel - other.rel).abs() < REL_EPSILON && (self.abs - other.abs).abs() < ABS_EPSILON
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Eq for UiScalar {}
|
impl Eq for UiScalar {}
|
||||||
impl Hash for UiScalar {
|
impl Hash for UiScalar {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
use crate::{LayerId, MaskIdx, PrimitiveHandle, TextureHandle, UiRegion, WidgetId};
|
use crate::{Align, LayerId, MaskIdx, PrimitiveHandle, TextureHandle, UiRegion, WidgetId};
|
||||||
|
|
||||||
/// important non rendering data for retained drawing
|
/// important non rendering data for retained drawing
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ActiveData {
|
pub struct ActiveData {
|
||||||
pub id: WidgetId,
|
pub id: WidgetId,
|
||||||
pub region: UiRegion,
|
pub region: UiRegion,
|
||||||
|
pub region_used: UiRegion,
|
||||||
pub parent: Option<WidgetId>,
|
pub parent: Option<WidgetId>,
|
||||||
pub textures: Vec<TextureHandle>,
|
pub textures: Vec<TextureHandle>,
|
||||||
pub primitives: Vec<PrimitiveHandle>,
|
pub primitives: Vec<PrimitiveHandle>,
|
||||||
pub children: Vec<WidgetId>,
|
pub children: Vec<WidgetId>,
|
||||||
pub mask: MaskIdx,
|
pub mask: MaskIdx,
|
||||||
pub layer: LayerId,
|
pub layer: LayerId,
|
||||||
|
pub align: Align,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
use crate::{BothAxis, Len, UiVec2, WidgetId, util::HashMap};
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Cache {
|
|
||||||
pub size: BothAxis<HashMap<WidgetId, (UiVec2, Len)>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Cache {
|
|
||||||
pub fn remove(&mut self, id: WidgetId) {
|
|
||||||
self.size.x.remove(&id);
|
|
||||||
self.size.y.remove(&id);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.size.x.clear();
|
|
||||||
self.size.y.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ActiveData, Axis, EventsLike, Painter, SizeCtx, Ui, UiRegion, UiVec2, WidgetId,
|
ActiveData, Align, Axis, EventsLike, Painter, Ui, UiRegion, WidgetId,
|
||||||
render::MaskIdx,
|
render::MaskIdx,
|
||||||
util::{HashSet, forget_ref},
|
util::{HashSet, forget_ref},
|
||||||
};
|
};
|
||||||
@@ -31,51 +31,21 @@ impl<'a> DrawState<'a> {
|
|||||||
/// redraws a widget that's currently active (drawn)
|
/// redraws a widget that's currently active (drawn)
|
||||||
pub fn redraw(&mut self, id: WidgetId) {
|
pub fn redraw(&mut self, id: WidgetId) {
|
||||||
self.widgets.needs_redraw.remove(&id);
|
self.widgets.needs_redraw.remove(&id);
|
||||||
self.draw_started.remove(&id);
|
|
||||||
// check if parent depends on the desired size of this, if so then redraw it first
|
|
||||||
for axis in [Axis::X, Axis::Y] {
|
|
||||||
if let Some(&(outer, old)) = self.cache.size.axis_dyn(axis).get(&id)
|
|
||||||
&& let Some(current) = self.active.get(&id)
|
|
||||||
&& let Some(pid) = current.parent
|
|
||||||
{
|
|
||||||
self.cache.size.axis_dyn(axis).remove(&id);
|
|
||||||
let new = self.size_ctx(id, outer).len_axis(id, axis);
|
|
||||||
self.cache.size.axis_dyn(axis).insert(id, (outer, new));
|
|
||||||
if new != old {
|
|
||||||
self.redraw(pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.draw_started.contains(&id) {
|
let Some(active) = self.active.get(&id) else {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(active) = self.remove(id, false) else {
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
let ActiveData {
|
||||||
self.draw_inner(
|
|
||||||
active.layer,
|
|
||||||
id,
|
id,
|
||||||
active.region,
|
region,
|
||||||
active.parent,
|
parent,
|
||||||
active.mask,
|
mask,
|
||||||
Some(active.children),
|
layer,
|
||||||
);
|
align,
|
||||||
}
|
..
|
||||||
|
} = *active;
|
||||||
|
|
||||||
pub(super) fn size_ctx<'b>(&'b mut self, source: WidgetId, outer: UiVec2) -> SizeCtx<'b> {
|
self.draw_inner(layer, id, region, parent, mask, align);
|
||||||
SizeCtx {
|
|
||||||
source,
|
|
||||||
cache: &mut self.ui.cache,
|
|
||||||
text: &mut self.ui.text,
|
|
||||||
textures: &mut self.ui.textures,
|
|
||||||
widgets: &self.ui.widgets,
|
|
||||||
outer,
|
|
||||||
output_size: self.ui.output_size,
|
|
||||||
id: source,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redraw_all(&mut self) {
|
pub fn redraw_all(&mut self) {
|
||||||
@@ -83,13 +53,12 @@ impl<'a> DrawState<'a> {
|
|||||||
for (_, active) in self.ui.active.drain() {
|
for (_, active) in self.ui.active.drain() {
|
||||||
self.events.undraw(&active);
|
self.events.undraw(&active);
|
||||||
}
|
}
|
||||||
self.ui.cache.clear();
|
|
||||||
self.ui.free(self.events);
|
self.ui.free(self.events);
|
||||||
self.layers.clear();
|
self.layers.clear();
|
||||||
self.widgets.needs_redraw.clear();
|
self.widgets.needs_redraw.clear();
|
||||||
|
|
||||||
if let Some(id) = &self.ui.root {
|
if let Some(id) = &self.ui.root {
|
||||||
self.draw_inner(0, id.id(), UiRegion::FULL, None, MaskIdx::NONE, None);
|
self.draw_inner(0, id.id(), UiRegion::FULL, None, MaskIdx::NONE, Align::NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,22 +69,19 @@ impl<'a> DrawState<'a> {
|
|||||||
region: UiRegion,
|
region: UiRegion,
|
||||||
parent: Option<WidgetId>,
|
parent: Option<WidgetId>,
|
||||||
mask: MaskIdx,
|
mask: MaskIdx,
|
||||||
old_children: Option<Vec<WidgetId>>,
|
align: Align,
|
||||||
) {
|
) {
|
||||||
let mut old_children = old_children.unwrap_or_default();
|
let mut old_children = Vec::new();
|
||||||
if let Some(active) = self.ui.active.get_mut(&id)
|
if let Some(active) = self.ui.active.get_mut(&id) {
|
||||||
&& !self.ui.widgets.needs_redraw.contains(&id)
|
// check to see if we can skip drawing first, and just need to move
|
||||||
{
|
if !self.ui.widgets.needs_redraw.contains(&id) {
|
||||||
// check to see if we can skip drawing first
|
if active.region == region {
|
||||||
if active.region == region {
|
return;
|
||||||
return;
|
} else if active.region.size() == region.size() {
|
||||||
} else if active.region.size() == region.size() {
|
self.mov(id, active.region, region);
|
||||||
// TODO: epsilon?
|
return;
|
||||||
let from = active.region;
|
}
|
||||||
self.mov(id, from, region);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
// if not, then maintain resize and track old children to remove unneeded
|
|
||||||
let active = self.remove(id, false).unwrap();
|
let active = self.remove(id, false).unwrap();
|
||||||
old_children = active.children;
|
old_children = active.children;
|
||||||
}
|
}
|
||||||
@@ -126,6 +92,7 @@ impl<'a> DrawState<'a> {
|
|||||||
let mut painter = Painter {
|
let mut painter = Painter {
|
||||||
state: self,
|
state: self,
|
||||||
region,
|
region,
|
||||||
|
region_used: region,
|
||||||
mask,
|
mask,
|
||||||
layer,
|
layer,
|
||||||
id,
|
id,
|
||||||
@@ -134,11 +101,13 @@ impl<'a> DrawState<'a> {
|
|||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut widget = painter.state.widgets.get_dyn_dynamic(id);
|
let mut widget = painter.state.widgets.get_dyn(id);
|
||||||
widget.draw(&mut painter);
|
widget.draw(&mut painter);
|
||||||
drop(widget);
|
let walign = painter.state.widgets.data(id).unwrap().align;
|
||||||
|
let align = align.or(walign.into());
|
||||||
|
|
||||||
let Painter {
|
let Painter {
|
||||||
|
region_used,
|
||||||
state: _,
|
state: _,
|
||||||
region,
|
region,
|
||||||
mask,
|
mask,
|
||||||
@@ -149,28 +118,37 @@ impl<'a> DrawState<'a> {
|
|||||||
id,
|
id,
|
||||||
} = painter;
|
} = painter;
|
||||||
|
|
||||||
// add to active
|
|
||||||
let active = ActiveData {
|
|
||||||
id,
|
|
||||||
region,
|
|
||||||
parent,
|
|
||||||
textures,
|
|
||||||
primitives,
|
|
||||||
children,
|
|
||||||
mask,
|
|
||||||
layer,
|
|
||||||
};
|
|
||||||
|
|
||||||
// remove old children that weren't kept
|
// remove old children that weren't kept
|
||||||
for c in &old_children {
|
for c in &old_children {
|
||||||
if !active.children.contains(c) {
|
if !children.contains(c) {
|
||||||
self.remove_rec(*c);
|
self.remove_rec(*c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update modules
|
// add to active
|
||||||
self.events.draw(&active);
|
self.active.insert(
|
||||||
self.active.insert(id, active);
|
id,
|
||||||
|
ActiveData {
|
||||||
|
id,
|
||||||
|
region,
|
||||||
|
parent,
|
||||||
|
textures,
|
||||||
|
primitives,
|
||||||
|
children,
|
||||||
|
region_used,
|
||||||
|
mask,
|
||||||
|
layer,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: unsure if there's a better way, currently using epsilon
|
||||||
|
// in PartialEq impl for UiScalar
|
||||||
|
let target = region_used.size().align(align);
|
||||||
|
if region_used != target {
|
||||||
|
self.mov(id, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.events.draw(self.active.get(&id).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mov(&mut self, id: WidgetId, from: UiRegion, to: UiRegion) {
|
fn mov(&mut self, id: WidgetId, from: UiRegion, to: UiRegion) {
|
||||||
@@ -207,7 +185,6 @@ impl<'a> DrawState<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn remove_rec(&mut self, id: WidgetId) -> Option<ActiveData> {
|
fn remove_rec(&mut self, id: WidgetId) -> Option<ActiveData> {
|
||||||
self.cache.remove(id);
|
|
||||||
let inst = self.remove(id, true);
|
let inst = self.remove(id, true);
|
||||||
if let Some(inst) = &inst {
|
if let Some(inst) = &inst {
|
||||||
for c in &inst.children {
|
for c in &inst.children {
|
||||||
|
|||||||
@@ -11,16 +11,12 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
mod active;
|
mod active;
|
||||||
mod cache;
|
|
||||||
mod draw_state;
|
mod draw_state;
|
||||||
mod painter;
|
mod painter;
|
||||||
mod size;
|
|
||||||
mod state;
|
mod state;
|
||||||
|
|
||||||
pub use active::*;
|
pub use active::*;
|
||||||
use cache::*;
|
|
||||||
pub use painter::Painter;
|
pub use painter::Painter;
|
||||||
pub use size::*;
|
|
||||||
|
|
||||||
pub struct Ui {
|
pub struct Ui {
|
||||||
// TODO: edit visibilities
|
// TODO: edit visibilities
|
||||||
@@ -33,7 +29,6 @@ pub struct Ui {
|
|||||||
pub text: TextData,
|
pub text: TextData,
|
||||||
output_size: Vec2,
|
output_size: Vec2,
|
||||||
pub masks: TrackedArena<Mask, u32>,
|
pub masks: TrackedArena<Mask, u32>,
|
||||||
pub cache: Cache,
|
|
||||||
|
|
||||||
pub root: Option<WidgetHandle>,
|
pub root: Option<WidgetHandle>,
|
||||||
old_root: Option<WidgetId>,
|
old_root: Option<WidgetId>,
|
||||||
@@ -206,7 +201,6 @@ impl Default for Ui {
|
|||||||
masks: Default::default(),
|
masks: Default::default(),
|
||||||
text: Default::default(),
|
text: Default::default(),
|
||||||
textures: Default::default(),
|
textures: Default::default(),
|
||||||
cache: Default::default(),
|
|
||||||
output_size: Vec2::ZERO,
|
output_size: Vec2::ZERO,
|
||||||
root: None,
|
root: None,
|
||||||
old_root: None,
|
old_root: None,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
Axis, Len, RenderedText, Size, SizeCtx, TextAttrs, TextBuffer, TextData, TextureHandle,
|
RenderedText, TextAttrs, TextBuffer, TextData, TextureHandle, UiRegion, WidgetHandle, WidgetId,
|
||||||
UiRegion, Widget, WidgetHandle, WidgetId,
|
|
||||||
render::{Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst},
|
render::{Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst},
|
||||||
ui::draw_state::DrawState,
|
ui::draw_state::DrawState,
|
||||||
util::Vec2,
|
util::Vec2,
|
||||||
@@ -10,6 +9,7 @@ use crate::{
|
|||||||
pub struct Painter<'a, 'b> {
|
pub struct Painter<'a, 'b> {
|
||||||
pub(super) state: &'a mut DrawState<'b>,
|
pub(super) state: &'a mut DrawState<'b>,
|
||||||
|
|
||||||
|
pub region_used: UiRegion,
|
||||||
pub(super) region: UiRegion,
|
pub(super) region: UiRegion,
|
||||||
pub(super) mask: MaskIdx,
|
pub(super) mask: MaskIdx,
|
||||||
pub(super) textures: Vec<TextureHandle>,
|
pub(super) textures: Vec<TextureHandle>,
|
||||||
@@ -56,6 +56,10 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
self.widget_at(id, self.region);
|
self.widget_at(id, self.region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rest_hint(&self, id: &WidgetHandle) -> f32 {
|
||||||
|
self.state.widgets.data(id).unwrap().align
|
||||||
|
}
|
||||||
|
|
||||||
/// Draws a widget somewhere within this one.
|
/// Draws a widget somewhere within this one.
|
||||||
/// Useful for drawing child widgets in select areas.
|
/// Useful for drawing child widgets in select areas.
|
||||||
pub fn widget_within<W: ?Sized>(&mut self, id: &WidgetHandle<W>, region: UiRegion) {
|
pub fn widget_within<W: ?Sized>(&mut self, id: &WidgetHandle<W>, region: UiRegion) {
|
||||||
@@ -65,7 +69,7 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
fn widget_at<W: ?Sized>(&mut self, id: &WidgetHandle<W>, region: UiRegion) {
|
fn widget_at<W: ?Sized>(&mut self, id: &WidgetHandle<W>, region: UiRegion) {
|
||||||
self.children.push(id.id());
|
self.children.push(id.id());
|
||||||
self.state
|
self.state
|
||||||
.draw_inner(self.layer, id.id(), region, Some(self.id), self.mask, None);
|
.draw_inner(self.layer, id.id(), region, Some(self.id), self.mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn texture_within(&mut self, handle: &TextureHandle, region: UiRegion) {
|
pub fn texture_within(&mut self, handle: &TextureHandle, region: UiRegion) {
|
||||||
@@ -78,11 +82,6 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
self.primitive(handle.primitive());
|
self.primitive(handle.primitive());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn texture_at(&mut self, handle: &TextureHandle, region: UiRegion) {
|
|
||||||
self.textures.push(handle.clone());
|
|
||||||
self.primitive_at(handle.primitive(), region);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns (handle, offset from top left)
|
/// returns (handle, offset from top left)
|
||||||
pub fn render_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> RenderedText {
|
pub fn render_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> RenderedText {
|
||||||
self.state
|
self.state
|
||||||
@@ -95,17 +94,6 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
self.region
|
self.region
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size<W: ?Sized + Widget>(&mut self, id: &WidgetHandle<W>) -> Size {
|
|
||||||
self.size_ctx().size(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len_axis<W: ?Sized + Widget>(&mut self, id: &WidgetHandle<W>, axis: Axis) -> Len {
|
|
||||||
match axis {
|
|
||||||
Axis::X => self.size_ctx().width(id),
|
|
||||||
Axis::Y => self.size_ctx().height(id),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn output_size(&self) -> Vec2 {
|
pub fn output_size(&self) -> Vec2 {
|
||||||
self.state.output_size
|
self.state.output_size
|
||||||
}
|
}
|
||||||
@@ -133,8 +121,4 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
pub fn id(&self) -> &WidgetId {
|
pub fn id(&self) -> &WidgetId {
|
||||||
&self.id
|
&self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size_ctx(&mut self) -> SizeCtx<'_> {
|
|
||||||
self.state.size_ctx(self.id, self.region.size())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
Axis, AxisT, IdLike, Len, RenderedText, Size, TextAttrs, TextBuffer, TextData, Textures,
|
|
||||||
UiVec2, WidgetAxisFns, WidgetId, Widgets, XAxis, YAxis, ui::cache::Cache, util::Vec2,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct SizeCtx<'a> {
|
|
||||||
pub text: &'a mut TextData,
|
|
||||||
pub textures: &'a mut Textures,
|
|
||||||
pub(super) source: WidgetId,
|
|
||||||
pub(super) widgets: &'a Widgets,
|
|
||||||
pub(super) cache: &'a mut Cache,
|
|
||||||
/// TODO: should this be pub? rn used for sized
|
|
||||||
pub outer: UiVec2,
|
|
||||||
pub(super) output_size: Vec2,
|
|
||||||
pub(super) id: WidgetId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SizeCtx<'_> {
|
|
||||||
pub fn id(&self) -> &WidgetId {
|
|
||||||
&self.id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn source(&self) -> &WidgetId {
|
|
||||||
&self.source
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn len_inner<A: const AxisT>(&mut self, id: WidgetId) -> Len {
|
|
||||||
if let Some((_, len)) = self.cache.size.axis::<A>().get(&id) {
|
|
||||||
return *len;
|
|
||||||
}
|
|
||||||
let len = self
|
|
||||||
.widgets
|
|
||||||
.get_dyn_dynamic(id)
|
|
||||||
.desired_len::<A>(&mut SizeCtx {
|
|
||||||
text: self.text,
|
|
||||||
textures: self.textures,
|
|
||||||
source: self.source,
|
|
||||||
widgets: self.widgets,
|
|
||||||
cache: self.cache,
|
|
||||||
outer: self.outer,
|
|
||||||
output_size: self.output_size,
|
|
||||||
id,
|
|
||||||
});
|
|
||||||
self.cache.size.axis::<A>().insert(id, (self.outer, len));
|
|
||||||
len
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn width(&mut self, id: impl IdLike) -> Len {
|
|
||||||
self.len_inner::<XAxis>(id.id())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn height(&mut self, id: impl IdLike) -> Len {
|
|
||||||
self.len_inner::<YAxis>(id.id())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len_axis(&mut self, id: impl IdLike, axis: Axis) -> Len {
|
|
||||||
match axis {
|
|
||||||
Axis::X => self.width(id),
|
|
||||||
Axis::Y => self.height(id),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn size(&mut self, id: impl IdLike) -> Size {
|
|
||||||
let id = id.id();
|
|
||||||
Size {
|
|
||||||
x: self.width(id),
|
|
||||||
y: self.height(id),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn px_size(&mut self) -> Vec2 {
|
|
||||||
self.outer.to_abs(self.output_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn output_size(&mut self) -> Vec2 {
|
|
||||||
self.output_size
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw_text(&mut self, buffer: &mut TextBuffer, attrs: &TextAttrs) -> RenderedText {
|
|
||||||
self.text.draw(buffer, attrs, self.textures)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn label(&self, id: WidgetId) -> &String {
|
|
||||||
self.widgets.label(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
use crate::Widget;
|
use crate::{RegionAlign, Widget};
|
||||||
|
|
||||||
pub struct WidgetData {
|
pub struct WidgetData {
|
||||||
pub widget: Box<dyn Widget>,
|
pub widget: Box<dyn Widget>,
|
||||||
pub label: String,
|
pub label: String,
|
||||||
|
/// alignment used if this does not fill up container
|
||||||
|
/// and there is no enforced alignment from parent
|
||||||
|
pub align: RegionAlign,
|
||||||
|
pub rest_len: Option<f32>,
|
||||||
/// dynamic borrow checking
|
/// dynamic borrow checking
|
||||||
pub borrowed: bool,
|
pub borrowed: bool,
|
||||||
}
|
}
|
||||||
@@ -15,7 +19,9 @@ impl WidgetData {
|
|||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
widget: Box::new(widget),
|
widget: Box::new(widget),
|
||||||
|
align: RegionAlign::CENTER,
|
||||||
label,
|
label,
|
||||||
|
rest_len: None,
|
||||||
borrowed: false,
|
borrowed: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{Axis, AxisT, Len, Painter, SizeCtx};
|
use crate::Painter;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
mod data;
|
mod data;
|
||||||
@@ -15,31 +15,10 @@ pub use widgets::*;
|
|||||||
|
|
||||||
pub trait Widget: Any {
|
pub trait Widget: Any {
|
||||||
fn draw(&mut self, painter: &mut Painter);
|
fn draw(&mut self, painter: &mut Painter);
|
||||||
fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len;
|
|
||||||
fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait WidgetAxisFns {
|
|
||||||
fn desired_len<A: AxisT>(&mut self, ctx: &mut SizeCtx) -> Len;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: Widget + ?Sized> WidgetAxisFns for W {
|
|
||||||
fn desired_len<A: AxisT>(&mut self, ctx: &mut SizeCtx) -> Len {
|
|
||||||
match A::get() {
|
|
||||||
Axis::X => self.desired_width(ctx),
|
|
||||||
Axis::Y => self.desired_height(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for () {
|
impl Widget for () {
|
||||||
fn draw(&mut self, _: &mut Painter) {}
|
fn draw(&mut self, _: &mut Painter) {}
|
||||||
fn desired_width(&mut self, _: &mut SizeCtx) -> Len {
|
|
||||||
Len::ZERO
|
|
||||||
}
|
|
||||||
fn desired_height(&mut self, _: &mut SizeCtx) -> Len {
|
|
||||||
Len::ZERO
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl dyn Widget {
|
impl dyn Widget {
|
||||||
|
|||||||
@@ -26,18 +26,9 @@ impl Widgets {
|
|||||||
!self.needs_redraw.is_empty()
|
!self.needs_redraw.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_dyn(&self, id: WidgetId) -> Option<&dyn Widget> {
|
|
||||||
Some(self.vec.get(id)?.widget.as_ref())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_dyn_mut(&mut self, id: WidgetId) -> Option<&mut dyn Widget> {
|
|
||||||
self.needs_redraw.insert(id);
|
|
||||||
Some(self.vec.get_mut(id)?.widget.as_mut())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// get_dyn but dynamic borrow checking of widgets
|
/// get_dyn but dynamic borrow checking of widgets
|
||||||
/// lets you do recursive (tree) operations, like the painter does
|
/// lets you do recursive (tree) operations, like the painter does
|
||||||
pub(crate) fn get_dyn_dynamic<'a>(&self, id: WidgetId) -> WidgetWrapper<'a> {
|
pub(crate) fn get_dyn<'a>(&self, id: WidgetId) -> WidgetWrapper<'a> {
|
||||||
// SAFETY: must guarantee no other mutable references to this widget exist
|
// SAFETY: must guarantee no other mutable references to this widget exist
|
||||||
// done through the borrow variable
|
// done through the borrow variable
|
||||||
let data = unsafe { forget_mut(to_mut(self.vec.get(id).unwrap())) };
|
let data = unsafe { forget_mut(to_mut(self.vec.get(id).unwrap())) };
|
||||||
@@ -51,14 +42,26 @@ impl Widgets {
|
|||||||
where
|
where
|
||||||
I::Widget: Sized + Widget,
|
I::Widget: Sized + Widget,
|
||||||
{
|
{
|
||||||
self.get_dyn(id.id())?.as_any().downcast_ref()
|
self.vec
|
||||||
|
.get(id.id())?
|
||||||
|
.widget
|
||||||
|
.as_ref()
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mut<I: IdLike>(&mut self, id: &I) -> Option<&mut I::Widget>
|
pub fn get_mut<I: IdLike>(&mut self, id: &I) -> Option<&mut I::Widget>
|
||||||
where
|
where
|
||||||
I::Widget: Sized + Widget,
|
I::Widget: Sized + Widget,
|
||||||
{
|
{
|
||||||
self.get_dyn_mut(id.id())?.as_any_mut().downcast_mut()
|
let id = id.id();
|
||||||
|
self.needs_redraw.insert(id);
|
||||||
|
self.vec
|
||||||
|
.get_mut(id)?
|
||||||
|
.widget
|
||||||
|
.as_mut()
|
||||||
|
.as_any_mut()
|
||||||
|
.downcast_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_strong<W: Widget>(&mut self, widget: W) -> WidgetHandle<W> {
|
pub fn add_strong<W: Widget>(&mut self, widget: W) -> WidgetHandle<W> {
|
||||||
@@ -77,7 +80,9 @@ impl Widgets {
|
|||||||
if !self.waiting.remove(&rf.id()) {
|
if !self.waiting.remove(&rf.id()) {
|
||||||
let label = self.label(rf);
|
let label = self.label(rf);
|
||||||
let id = rf.id();
|
let id = rf.id();
|
||||||
panic!("widget '{label}' ({id:?}) was already added\ncannot add a widget twice; consider creating two")
|
panic!(
|
||||||
|
"widget '{label}' ({id:?}) was already added\ncannot add a widget twice; consider creating two"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
WidgetHandle::new(rf.id(), self.send.clone())
|
WidgetHandle::new(rf.id(), self.send.clone())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,12 @@ pub struct Span {
|
|||||||
|
|
||||||
impl Widget for Span {
|
impl Widget for Span {
|
||||||
fn draw(&mut self, painter: &mut Painter) {
|
fn draw(&mut self, painter: &mut Painter) {
|
||||||
let total = self.len_sum(&mut painter.size_ctx());
|
let total = self.len_sum();
|
||||||
let mut start = UiScalar::rel_min();
|
let mut start = UiScalar::rel_min();
|
||||||
for child in &self.children {
|
for child in &self.children {
|
||||||
let mut span = UiSpan::FULL;
|
let mut span = UiSpan::FULL;
|
||||||
span.start = start;
|
span.start = start;
|
||||||
|
painter.widget(id);
|
||||||
let len = painter.len_axis(child, self.dir.axis);
|
let len = painter.len_axis(child, self.dir.axis);
|
||||||
if len.rest > 0.0 {
|
if len.rest > 0.0 {
|
||||||
let offset = UiScalar::new(total.rel, total.abs);
|
let offset = UiScalar::new(total.rel, total.abs);
|
||||||
@@ -32,20 +33,6 @@ impl Widget for Span {
|
|||||||
start.abs += self.gap;
|
start.abs += self.gap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len {
|
|
||||||
match self.dir.axis {
|
|
||||||
Axis::X => self.desired_len(ctx),
|
|
||||||
Axis::Y => self.desired_ortho(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len {
|
|
||||||
match self.dir.axis {
|
|
||||||
Axis::X => self.desired_ortho(ctx),
|
|
||||||
Axis::Y => self.desired_len(ctx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Span {
|
impl Span {
|
||||||
@@ -70,22 +57,6 @@ impl Span {
|
|||||||
self.children.pop()
|
self.children.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn len_sum(&mut self, ctx: &mut SizeCtx) -> Len {
|
|
||||||
let gap = self.gap * self.children.len().saturating_sub(1) as f32;
|
|
||||||
self.children.iter().fold(Len::abs(gap), |mut s, id| {
|
|
||||||
// it's tempting to subtract the abs & rel from the ctx outer,
|
|
||||||
// but that would create inconsistent sizing if you put
|
|
||||||
// a rest first vs last & only speed up in one direction.
|
|
||||||
// I think this is only solvable by restricting how you can
|
|
||||||
// compute size, bc currently you need child to define parent's
|
|
||||||
// sectioning and you need parent's sectioning to define child.
|
|
||||||
// Fortunately, that doesn't matter in most cases
|
|
||||||
let len = ctx.len_axis(id, self.dir.axis);
|
|
||||||
s += len;
|
|
||||||
s
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn desired_len(&mut self, ctx: &mut SizeCtx) -> Len {
|
fn desired_len(&mut self, ctx: &mut SizeCtx) -> Len {
|
||||||
let len = self.len_sum(ctx);
|
let len = self.len_sum(ctx);
|
||||||
if len.rest == 0.0 && len.rel == 0.0 {
|
if len.rest == 0.0 && len.rel == 0.0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user