sizing actually working correctly now
This commit is contained in:
@@ -7,11 +7,11 @@ pub struct Aligned {
|
|||||||
|
|
||||||
impl Widget for Aligned {
|
impl Widget for Aligned {
|
||||||
fn draw(&mut self, painter: &mut Painter) {
|
fn draw(&mut self, painter: &mut Painter) {
|
||||||
let region = UiRegion::from_size_align(painter.size(&self.inner), self.align);
|
let region = UiRegion::from_ui_size_align(painter.size(&self.inner), self.align);
|
||||||
painter.widget_within(&self.inner, region);
|
painter.widget_within(&self.inner, region);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_size(&mut self, ctx: &mut SizeCtx) -> Vec2 {
|
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||||
ctx.size(&self.inner)
|
ctx.size(&self.inner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ impl Widget for Image {
|
|||||||
painter.texture(&self.handle);
|
painter.texture(&self.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_size(&mut self, _: &mut SizeCtx) -> Vec2 {
|
fn desired_size(&mut self, _: &mut SizeCtx) -> UiVec2 {
|
||||||
self.handle.size()
|
UiVec2::abs(self.handle.size())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
mod align;
|
mod align;
|
||||||
mod frame;
|
|
||||||
mod image;
|
mod image;
|
||||||
|
mod pad;
|
||||||
mod rect;
|
mod rect;
|
||||||
mod sense;
|
mod sense;
|
||||||
mod sized;
|
mod sized;
|
||||||
@@ -11,8 +11,8 @@ mod text_edit;
|
|||||||
mod trait_fns;
|
mod trait_fns;
|
||||||
|
|
||||||
pub use align::*;
|
pub use align::*;
|
||||||
pub use frame::*;
|
|
||||||
pub use image::*;
|
pub use image::*;
|
||||||
|
pub use pad::*;
|
||||||
pub use rect::*;
|
pub use rect::*;
|
||||||
pub use sense::*;
|
pub use sense::*;
|
||||||
pub use sized::*;
|
pub use sized::*;
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ impl Widget for Padded {
|
|||||||
painter.widget_within(&self.inner, self.padding.region());
|
painter.widget_within(&self.inner, self.padding.region());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_size(&mut self, ctx: &mut SizeCtx) -> Vec2 {
|
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||||
let mut size = ctx.size(&self.inner);
|
let mut size = ctx.size(&self.inner);
|
||||||
size.x += self.padding.left + self.padding.right;
|
size.abs.x += self.padding.left + self.padding.right;
|
||||||
size.y += self.padding.top + self.padding.bottom;
|
size.abs.y += self.padding.top + self.padding.bottom;
|
||||||
size
|
size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,10 +36,10 @@ impl Padding {
|
|||||||
}
|
}
|
||||||
pub fn region(&self) -> UiRegion {
|
pub fn region(&self) -> UiRegion {
|
||||||
let mut region = UiRegion::full();
|
let mut region = UiRegion::full();
|
||||||
region.top_left.offset.x += self.left;
|
region.top_left.abs.x += self.left;
|
||||||
region.top_left.offset.y += self.top;
|
region.top_left.abs.y += self.top;
|
||||||
region.bot_right.offset.x -= self.right;
|
region.bot_right.abs.x -= self.right;
|
||||||
region.bot_right.offset.y -= self.bottom;
|
region.bot_right.abs.y -= self.bottom;
|
||||||
region
|
region
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ impl Widget for Sized {
|
|||||||
painter.widget(&self.inner);
|
painter.widget(&self.inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_size(&mut self, _: &mut SizeCtx) -> Vec2 {
|
fn desired_size(&mut self, _: &mut SizeCtx) -> UiVec2 {
|
||||||
self.size
|
UiVec2::abs(self.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,34 +8,30 @@ 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.setup(&mut painter.size_ctx());
|
let total = self.setup(&mut painter.size_ctx());
|
||||||
let mut start = UIScalar::min();
|
let mut start = UiScalar::rel_min();
|
||||||
for (child, length) in &self.children {
|
for (child, length) in &self.children {
|
||||||
let mut child_region = UiRegion::full();
|
let mut child_region = UiRegion::full();
|
||||||
let mut axis = child_region.axis_mut(self.dir.axis);
|
let mut axis = child_region.axis_mut(self.dir.axis);
|
||||||
axis.top_left.set(start);
|
axis.top_left.set(start);
|
||||||
match *length {
|
match *length {
|
||||||
SpanLen::Fixed(offset) => {
|
SpanLen::Fixed(offset) => {
|
||||||
start.offset += offset;
|
start.abs += offset;
|
||||||
*axis.bot_right.offset = start.offset;
|
|
||||||
*axis.bot_right.anchor = *axis.top_left.anchor;
|
|
||||||
}
|
}
|
||||||
SpanLen::Ratio(ratio) => {
|
SpanLen::Ratio(ratio) => {
|
||||||
let offset = UIScalar::new(total.relative, total.fixed);
|
let offset = UiScalar::new(total.rel, total.abs);
|
||||||
let rel_end = UIScalar::from_anchor(ratio / total.ratio);
|
let rel_end = UiScalar::from_anchor(ratio / total.ratio);
|
||||||
start = rel_end.within(start, (UIScalar::max() + start) - offset);
|
start = rel_end.within(start, (UiScalar::rel_max() + start) - offset);
|
||||||
axis.bot_right.set(start);
|
|
||||||
}
|
}
|
||||||
SpanLen::Relative(rel) => {
|
SpanLen::Relative(rel) => {
|
||||||
start.anchor += rel;
|
start.rel += rel;
|
||||||
axis.bot_right.set(start);
|
|
||||||
}
|
}
|
||||||
SpanLen::Sized(size) => {
|
SpanLen::Sized(size) => {
|
||||||
let offset = size.axis(self.dir.axis);
|
let size_axis = size.axis(self.dir.axis);
|
||||||
start.offset += offset;
|
start.abs += size_axis.abs;
|
||||||
*axis.bot_right.offset = start.offset;
|
start.rel += size_axis.rel;
|
||||||
*axis.bot_right.anchor = *axis.top_left.anchor;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
axis.bot_right.set(start);
|
||||||
if self.dir.sign == Sign::Neg {
|
if self.dir.sign == Sign::Neg {
|
||||||
child_region.flip();
|
child_region.flip();
|
||||||
}
|
}
|
||||||
@@ -43,24 +39,28 @@ impl Widget for Span {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_size(&mut self, ctx: &mut SizeCtx) -> Vec2 {
|
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||||
let total = self.setup(ctx);
|
let total = self.setup(ctx);
|
||||||
let axis = self.dir.axis;
|
let axis = self.dir.axis;
|
||||||
let dir_len = if total.ratio != 0.0 {
|
let dir_len = if total.ratio != 0.0 {
|
||||||
ctx.size.axis(axis)
|
UiScalar::rel_max()
|
||||||
} else {
|
} else {
|
||||||
total.fixed + total.relative * ctx.size.axis(axis)
|
UiScalar::new(total.rel, total.abs)
|
||||||
};
|
};
|
||||||
Vec2::from_axis(axis, dir_len, total.max_sized)
|
let mut max_ortho = UiScalar::default();
|
||||||
|
for (child, _) in &self.children {
|
||||||
|
let size = ctx.size(child);
|
||||||
|
max_ortho = max_ortho.max(size.axis(!self.dir.axis));
|
||||||
|
}
|
||||||
|
UiVec2::from_axis(axis, dir_len, max_ortho)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SpanLenSums {
|
pub struct SpanLenSums {
|
||||||
pub fixed: f32,
|
pub abs: f32,
|
||||||
pub ratio: f32,
|
pub ratio: f32,
|
||||||
pub relative: f32,
|
pub rel: f32,
|
||||||
pub max_sized: f32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Span {
|
impl Span {
|
||||||
@@ -76,15 +76,15 @@ impl Span {
|
|||||||
.iter_mut()
|
.iter_mut()
|
||||||
.fold(SpanLenSums::default(), |mut s, (id, l)| {
|
.fold(SpanLenSums::default(), |mut s, (id, l)| {
|
||||||
match l {
|
match l {
|
||||||
SpanLen::Fixed(v) => s.fixed += *v,
|
SpanLen::Fixed(v) => s.abs += *v,
|
||||||
SpanLen::Ratio(v) => s.ratio += *v,
|
SpanLen::Ratio(v) => s.ratio += *v,
|
||||||
SpanLen::Relative(v) => s.relative += *v,
|
SpanLen::Relative(v) => s.rel += *v,
|
||||||
SpanLen::Sized(v) => {
|
SpanLen::Sized(v) => {
|
||||||
let size = ctx.size(id);
|
let size = ctx.size(id);
|
||||||
let len = size.axis(self.dir.axis);
|
let len = size.axis(self.dir.axis);
|
||||||
s.max_sized = s.max_sized.max(size.axis(!self.dir.axis));
|
|
||||||
*v = size;
|
*v = size;
|
||||||
s.fixed += len;
|
s.abs += len.abs;
|
||||||
|
s.rel += len.rel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
@@ -105,7 +105,7 @@ pub enum SpanLen {
|
|||||||
/// size determined by the child widget itself
|
/// size determined by the child widget itself
|
||||||
/// the value is not used externally, I just don't wanna make a duplicate enum
|
/// the value is not used externally, I just don't wanna make a duplicate enum
|
||||||
/// there are util functions instead so
|
/// there are util functions instead so
|
||||||
Sized(Vec2),
|
Sized(UiVec2),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fixed<N: UiNum>(x: N) -> SpanLen {
|
pub fn fixed<N: UiNum>(x: N) -> SpanLen {
|
||||||
@@ -121,7 +121,7 @@ pub fn relative<N: UiNum>(x: N) -> SpanLen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn sized() -> SpanLen {
|
pub fn sized() -> SpanLen {
|
||||||
SpanLen::Sized(Vec2::ZERO)
|
SpanLen::Sized(UiVec2::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: UiNum> From<N> for SpanLen {
|
impl<N: UiNum> From<N> for SpanLen {
|
||||||
|
|||||||
@@ -66,15 +66,15 @@ impl Widget for Text {
|
|||||||
let dims = handle.size();
|
let dims = handle.size();
|
||||||
self.size = offset.size(&handle);
|
self.size = offset.size(&handle);
|
||||||
let mut region = self.region();
|
let mut region = self.region();
|
||||||
region.top_left.offset += offset.top_left;
|
region.top_left.abs += offset.top_left;
|
||||||
region.bot_right.offset = region.top_left.offset + dims;
|
region.bot_right.abs = region.top_left.abs + dims;
|
||||||
painter.texture_within(&handle, region);
|
painter.texture_within(&handle, region);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_size(&mut self, ctx: &mut SizeCtx) -> Vec2 {
|
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||||
self.update_buf(&mut ctx.text.font_system);
|
self.update_buf(&mut ctx.text.font_system);
|
||||||
let (handle, offset) = ctx.draw_text(&mut self.buf, &self.attrs);
|
let (handle, offset) = ctx.draw_text(&mut self.buf, &self.attrs);
|
||||||
offset.size(&handle)
|
UiVec2::abs(offset.size(&handle))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,16 +24,17 @@ impl TextEdit {
|
|||||||
impl Widget for TextEdit {
|
impl Widget for TextEdit {
|
||||||
fn draw(&mut self, painter: &mut Painter) {
|
fn draw(&mut self, painter: &mut Painter) {
|
||||||
let font_system = &mut painter.text_data().font_system;
|
let font_system = &mut painter.text_data().font_system;
|
||||||
self.buf.shape_until_scroll(font_system, false);
|
|
||||||
self.attrs.apply(font_system, &mut self.buf);
|
self.attrs.apply(font_system, &mut self.buf);
|
||||||
|
self.buf.shape_until_scroll(font_system, false);
|
||||||
let (handle, tex_offset) = painter.render_text(&mut self.buf, &self.attrs);
|
let (handle, tex_offset) = painter.render_text(&mut self.buf, &self.attrs);
|
||||||
let dims = handle.size();
|
let dims = handle.size();
|
||||||
self.size = tex_offset.size(&handle);
|
self.size = tex_offset.size(&handle);
|
||||||
let region = self.region();
|
let region = self.region();
|
||||||
let mut tex_region = region;
|
let mut tex_region = region;
|
||||||
tex_region.top_left.offset += tex_offset.top_left;
|
tex_region.top_left.abs += tex_offset.top_left;
|
||||||
tex_region.bot_right.offset = tex_region.top_left.offset + dims;
|
tex_region.bot_right.abs = tex_region.top_left.abs + dims;
|
||||||
painter.texture_within(&handle, tex_region);
|
painter.texture_within(&handle, tex_region);
|
||||||
|
|
||||||
if let Some(cursor) = &self.cursor
|
if let Some(cursor) = &self.cursor
|
||||||
&& let Some(pos) = cursor_pos(cursor, &self.buf)
|
&& let Some(pos) = cursor_pos(cursor, &self.buf)
|
||||||
{
|
{
|
||||||
@@ -45,12 +46,15 @@ impl Widget for TextEdit {
|
|||||||
.shifted(offset)
|
.shifted(offset)
|
||||||
.within(®ion),
|
.within(®ion),
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
// keep number of primitives constant so shifting isn't needed
|
||||||
|
painter.primitive(RectPrimitive::color(Color::NONE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_size(&mut self, ctx: &mut SizeCtx) -> Vec2 {
|
fn desired_size(&mut self, ctx: &mut SizeCtx) -> UiVec2 {
|
||||||
let (handle, offset) = ctx.draw_text(&mut self.buf, &self.attrs);
|
let (handle, offset) = ctx.draw_text(&mut self.buf, &self.attrs);
|
||||||
offset.size(&handle)
|
UiVec2::abs(offset.size(&handle))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +109,10 @@ impl TextEditBuilder {
|
|||||||
self.attrs.line_height = height;
|
self.attrs.line_height = height;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
pub fn text_align(mut self, align: Align) -> Self {
|
||||||
|
self.align = align;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextEditCtx<'a> {
|
pub struct TextEditCtx<'a> {
|
||||||
@@ -113,6 +121,21 @@ pub struct TextEditCtx<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TextEditCtx<'a> {
|
impl<'a> TextEditCtx<'a> {
|
||||||
|
pub fn take(&mut self) -> String {
|
||||||
|
let text = self
|
||||||
|
.text
|
||||||
|
.buf
|
||||||
|
.lines
|
||||||
|
.drain(..)
|
||||||
|
.map(|l| l.into_text())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
self.text
|
||||||
|
.buf
|
||||||
|
.set_text(self.font_system, "", &Attrs::new(), Shaping::Advanced);
|
||||||
|
text
|
||||||
|
}
|
||||||
|
|
||||||
pub fn motion(&mut self, motion: Motion) {
|
pub fn motion(&mut self, motion: Motion) {
|
||||||
if let Some(cursor) = self.text.cursor
|
if let Some(cursor) = self.text.cursor
|
||||||
&& let Some((cursor, _)) =
|
&& let Some((cursor, _)) =
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ impl<T: ColorNum> Color<T> {
|
|||||||
pub const PURPLE: Self = Self::rgb(T::MID, T::MIN, T::MAX);
|
pub const PURPLE: Self = Self::rgb(T::MID, T::MIN, T::MAX);
|
||||||
pub const MAGENTA: Self = Self::rgb(T::MAX, T::MIN, T::MAX);
|
pub const MAGENTA: Self = Self::rgb(T::MAX, T::MIN, T::MAX);
|
||||||
|
|
||||||
|
pub const NONE: Self = Self::new(T::MIN, T::MIN, T::MIN, T::MIN);
|
||||||
|
|
||||||
pub const fn new(r: T, g: T, b: T, a: T) -> Self {
|
pub const fn new(r: T, g: T, b: T, a: T) -> Self {
|
||||||
Self { r, g, b, a }
|
Self { r, g, b, a }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ use std::ops::Range;
|
|||||||
use crate::{
|
use crate::{
|
||||||
layout::{
|
layout::{
|
||||||
Active, TextAttrs, TextBuffer, TextData, TextOffset, TextureHandle, Textures, UiRegion,
|
Active, TextAttrs, TextBuffer, TextData, TextOffset, TextureHandle, Textures, UiRegion,
|
||||||
Vec2, WidgetId, Widgets,
|
UiVec2, Vec2, WidgetId, Widgets,
|
||||||
},
|
},
|
||||||
render::{Primitive, PrimitiveHandle, Primitives},
|
render::{Primitive, PrimitiveHandle, Primitives},
|
||||||
util::{HashSet, Id},
|
util::{HashMap, HashSet, Id},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Painter<'a, 'c> {
|
pub struct Painter<'a, 'c> {
|
||||||
@@ -15,7 +15,7 @@ pub struct Painter<'a, 'c> {
|
|||||||
textures: Vec<TextureHandle>,
|
textures: Vec<TextureHandle>,
|
||||||
primitives: Vec<PrimitiveHandle>,
|
primitives: Vec<PrimitiveHandle>,
|
||||||
children: Vec<Id>,
|
children: Vec<Id>,
|
||||||
sized_children: HashSet<Id>,
|
sized_children: HashMap<Id, UiVec2>,
|
||||||
id: Id,
|
id: Id,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ pub struct WidgetInstance {
|
|||||||
pub textures: Vec<TextureHandle>,
|
pub textures: Vec<TextureHandle>,
|
||||||
pub primitives: Vec<PrimitiveHandle>,
|
pub primitives: Vec<PrimitiveHandle>,
|
||||||
pub children: Vec<Id>,
|
pub children: Vec<Id>,
|
||||||
pub resize: Option<Id>,
|
pub resize: Option<(Id, UiVec2)>,
|
||||||
pub span: Range<usize>,
|
pub span: Range<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ impl<'a> PainterCtx<'a> {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(rid) = &active.resize {
|
if let Some((rid, size)) = &active.resize {
|
||||||
self.redraw(&rid.duplicate());
|
self.redraw(&rid.duplicate());
|
||||||
if self.drawing.contains(id) {
|
if self.drawing.contains(id) {
|
||||||
return;
|
return;
|
||||||
@@ -76,15 +76,20 @@ impl<'a> PainterCtx<'a> {
|
|||||||
let Some(active) = self.remove(id) else {
|
let Some(active) = self.remove(id) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let parent = active.parent();
|
||||||
|
drop(active.textures);
|
||||||
|
self.textures.free();
|
||||||
|
|
||||||
self.primitives.set_pos(active.span.start);
|
self.primitives.set_pos(active.span.start);
|
||||||
self.draw_inner(id, active.region, active.parent(), Some(active.children));
|
self.draw_inner(id, active.region, parent, Some(active.children));
|
||||||
self.active.widgets.get_mut(id).unwrap().resize = active.resize;
|
self.active.widgets.get_mut(id).unwrap().resize = active.resize;
|
||||||
|
|
||||||
let delta = self.primitives.apply(active.span.clone());
|
let delta = self.primitives.apply(active.span.clone());
|
||||||
if delta != 0
|
if delta != 0
|
||||||
&& let Some(parent) = active.parent
|
&& let Some(parent) = active.parent
|
||||||
{
|
{
|
||||||
self.shift_parent(parent, active.span.start, delta);
|
self.shift_parent(id, parent, active.span.start, delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,12 +118,12 @@ impl<'a> PainterCtx<'a> {
|
|||||||
}
|
}
|
||||||
let mut old_children = old_children.unwrap_or_default();
|
let mut old_children = old_children.unwrap_or_default();
|
||||||
let mut resize = None;
|
let mut resize = None;
|
||||||
if let Some(active) = self.active.widgets.get(id) {
|
if let Some(active) = self.active.widgets.get_mut(id) {
|
||||||
if active.parent != parent {
|
if active.parent != parent {
|
||||||
panic!("Cannot draw the same widget twice (2)");
|
panic!("Cannot draw the same widget twice (2)");
|
||||||
}
|
}
|
||||||
if active.region == region {
|
if active.region == region {
|
||||||
self.primitives.skip(&active.span);
|
self.primitives.skip(&mut active.span);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO:
|
// TODO:
|
||||||
@@ -126,6 +131,8 @@ impl<'a> PainterCtx<'a> {
|
|||||||
let active = self.remove(id).unwrap();
|
let active = self.remove(id).unwrap();
|
||||||
old_children = active.children;
|
old_children = active.children;
|
||||||
resize = active.resize;
|
resize = active.resize;
|
||||||
|
drop(active.textures);
|
||||||
|
self.textures.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut painter = Painter {
|
let mut painter = Painter {
|
||||||
@@ -135,7 +142,7 @@ impl<'a> PainterCtx<'a> {
|
|||||||
primitives: Vec::new(),
|
primitives: Vec::new(),
|
||||||
ctx: self,
|
ctx: self,
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
sized_children: HashSet::new(),
|
sized_children: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// draw widgets
|
// draw widgets
|
||||||
@@ -156,9 +163,9 @@ impl<'a> PainterCtx<'a> {
|
|||||||
children: painter.children,
|
children: painter.children,
|
||||||
resize,
|
resize,
|
||||||
};
|
};
|
||||||
for cid in sized_children {
|
for (cid, size) in sized_children {
|
||||||
if let Some(w) = self.active.widgets.get_mut(&cid) {
|
if let Some(w) = self.active.widgets.get_mut(&cid) {
|
||||||
w.resize = Some(id.duplicate())
|
w.resize = Some((id.duplicate(), size))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for c in &old_children {
|
for c in &old_children {
|
||||||
@@ -193,28 +200,31 @@ impl<'a> PainterCtx<'a> {
|
|||||||
/// shifts the primitive spans for all widgets above this one in the tree
|
/// shifts the primitive spans for all widgets above this one in the tree
|
||||||
/// also goes into children of them and modifies those that come after this one
|
/// also goes into children of them and modifies those that come after this one
|
||||||
/// should be done after applying primitives to ensure active spans are correct
|
/// should be done after applying primitives to ensure active spans are correct
|
||||||
fn shift_parent(&mut self, parent: Id, start: usize, delta: isize) {
|
fn shift_parent(&mut self, original: &Id, parent: Id, start: usize, delta: isize) {
|
||||||
let instance = self.active.widgets.get_mut(&parent).unwrap();
|
let instance = self.active.widgets.get_mut(&parent).unwrap();
|
||||||
let end = &mut instance.span.end;
|
let end = &mut instance.span.end;
|
||||||
*end = end.strict_add_signed(delta);
|
*end = end.strict_add_signed(delta);
|
||||||
let parent = instance.parent();
|
let parent_parent = instance.parent();
|
||||||
for child in instance
|
for child in instance
|
||||||
.children
|
.children
|
||||||
.iter()
|
.iter()
|
||||||
|
// skip original
|
||||||
|
.skip_while(|id| *id != original)
|
||||||
|
.skip(1)
|
||||||
.map(|id| id.duplicate())
|
.map(|id| id.duplicate())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
{
|
{
|
||||||
self.shift_child(&child, start, delta);
|
self.shift_child(&child, start, delta);
|
||||||
}
|
}
|
||||||
if let Some(parent) = parent {
|
if let Some(parent_parent) = parent_parent {
|
||||||
self.shift_parent(parent, start, delta);
|
self.shift_parent(&parent, parent_parent, start, delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shift_child(&mut self, child: &Id, start: usize, delta: isize) {
|
fn shift_child(&mut self, child: &Id, start: usize, delta: isize) {
|
||||||
let instance = self.active.widgets.get_mut(child).unwrap();
|
let instance = self.active.widgets.get_mut(child).unwrap();
|
||||||
// = also prevents the original id from getting shifted
|
// = also prevents the original id from getting shifted
|
||||||
if instance.span.start <= start {
|
if instance.span.start < start {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
instance.span.start = instance.span.start.strict_add_signed(delta);
|
instance.span.start = instance.span.start.strict_add_signed(delta);
|
||||||
@@ -232,11 +242,11 @@ impl<'a> PainterCtx<'a> {
|
|||||||
|
|
||||||
impl<'a, 'c> Painter<'a, 'c> {
|
impl<'a, 'c> Painter<'a, 'c> {
|
||||||
fn primitive_at<P: Primitive>(&mut self, primitive: P, region: UiRegion) {
|
fn primitive_at<P: Primitive>(&mut self, primitive: P, region: UiRegion) {
|
||||||
self.primitives.push(
|
let h = self
|
||||||
self.ctx
|
.ctx
|
||||||
.primitives
|
.primitives
|
||||||
.write(self.id.duplicate(), primitive, region),
|
.write(self.id.duplicate(), primitive, region);
|
||||||
);
|
self.primitives.push(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a primitive to be rendered
|
/// Writes a primitive to be rendered
|
||||||
@@ -293,17 +303,12 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
self.region
|
self.region
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size<W>(&mut self, id: &WidgetId<W>) -> Vec2 {
|
pub fn size<W>(&mut self, id: &WidgetId<W>) -> UiVec2 {
|
||||||
self.sized_children.insert(id.id.duplicate());
|
self.size_ctx().size(id)
|
||||||
self.ctx
|
|
||||||
.widgets
|
|
||||||
.get_dyn_dynamic(&id.id)
|
|
||||||
.get_size(&mut self.size_ctx())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size_ctx(&mut self) -> SizeCtx<'_> {
|
pub fn size_ctx(&mut self) -> SizeCtx<'_> {
|
||||||
SizeCtx {
|
SizeCtx {
|
||||||
size: self.region.in_size(self.ctx.screen_size),
|
|
||||||
text: self.ctx.text,
|
text: self.ctx.text,
|
||||||
textures: self.ctx.textures,
|
textures: self.ctx.textures,
|
||||||
widgets: self.ctx.widgets,
|
widgets: self.ctx.widgets,
|
||||||
@@ -317,17 +322,21 @@ impl<'a, 'c> Painter<'a, 'c> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SizeCtx<'a> {
|
pub struct SizeCtx<'a> {
|
||||||
pub size: Vec2,
|
|
||||||
pub text: &'a mut TextData,
|
pub text: &'a mut TextData,
|
||||||
pub textures: &'a mut Textures,
|
pub textures: &'a mut Textures,
|
||||||
widgets: &'a Widgets,
|
widgets: &'a Widgets,
|
||||||
checked: &'a mut HashSet<Id>,
|
checked: &'a mut HashMap<Id, UiVec2>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SizeCtx<'_> {
|
impl SizeCtx<'_> {
|
||||||
pub fn size<W>(&mut self, id: &WidgetId<W>) -> Vec2 {
|
pub fn size<W>(&mut self, id: &WidgetId<W>) -> UiVec2 {
|
||||||
self.checked.insert(id.id.duplicate());
|
// TODO: determine if this is useful
|
||||||
self.widgets.get_dyn_dynamic(&id.id).get_size(self)
|
// if let Some(size) = self.checked.get(&id.id) {
|
||||||
|
// return Some(*size);
|
||||||
|
// }
|
||||||
|
let size = self.widgets.get_dyn_dynamic(&id.id).desired_size(self);
|
||||||
|
self.checked.insert(id.id.duplicate(), size);
|
||||||
|
size
|
||||||
}
|
}
|
||||||
pub fn draw_text(
|
pub fn draw_text(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ use crate::{
|
|||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, bytemuck::Pod, bytemuck::Zeroable, Default)]
|
#[derive(Debug, Copy, Clone, PartialEq, bytemuck::Pod, bytemuck::Zeroable, Default)]
|
||||||
pub struct UiPos {
|
pub struct UiVec2 {
|
||||||
pub anchor: Vec2,
|
pub rel: Vec2,
|
||||||
pub offset: Vec2,
|
pub abs: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiPos {
|
impl UiVec2 {
|
||||||
/// expands this position into a sized region centered at self
|
/// expands this position into a sized region centered at self
|
||||||
pub fn expand(&self, size: impl Into<Vec2>) -> UiRegion {
|
pub fn expand(&self, size: impl Into<Vec2>) -> UiRegion {
|
||||||
let size = size.into();
|
let size = size.into();
|
||||||
@@ -21,21 +21,29 @@ impl UiPos {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const fn anchor(anchor: Vec2) -> Self {
|
pub const fn anchor(anchor: Vec2) -> Self {
|
||||||
Self {
|
Self::rel(anchor)
|
||||||
anchor,
|
|
||||||
offset: Vec2::ZERO,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn offset(offset: Vec2) -> Self {
|
pub const fn offset(offset: Vec2) -> Self {
|
||||||
|
Self::abs(offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn abs(abs: Vec2) -> Self {
|
||||||
Self {
|
Self {
|
||||||
anchor: Vec2::ZERO,
|
rel: Vec2::ZERO,
|
||||||
offset,
|
abs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn rel(rel: Vec2) -> Self {
|
||||||
|
Self {
|
||||||
|
rel,
|
||||||
|
abs: Vec2::ZERO,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn shift(&mut self, offset: impl const Into<Vec2>) {
|
pub const fn shift(&mut self, offset: impl const Into<Vec2>) {
|
||||||
self.offset += offset.into();
|
self.abs += offset.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn shifted(mut self, offset: Vec2) -> Self {
|
pub const fn shifted(mut self, offset: Vec2) -> Self {
|
||||||
@@ -43,33 +51,44 @@ impl UiPos {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn within(&self, region: &UiRegion) -> UiPos {
|
pub const fn within(&self, region: &UiRegion) -> UiVec2 {
|
||||||
let anchor = self
|
let anchor = self.rel.lerp(region.top_left.rel, region.bot_right.rel);
|
||||||
.anchor
|
let offset = self.abs + self.rel.lerp(region.top_left.abs, region.bot_right.abs);
|
||||||
.lerp(region.top_left.anchor, region.bot_right.anchor);
|
UiVec2 {
|
||||||
let offset = self.offset
|
rel: anchor,
|
||||||
+ self
|
abs: offset,
|
||||||
.anchor
|
}
|
||||||
.lerp(region.top_left.offset, region.bot_right.offset);
|
|
||||||
UiPos { anchor, offset }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn axis_mut(&mut self, axis: Axis) -> UIScalarView<'_> {
|
pub fn axis_mut(&mut self, axis: Axis) -> UiScalarView<'_> {
|
||||||
match axis {
|
match axis {
|
||||||
Axis::X => UIScalarView {
|
Axis::X => UiScalarView {
|
||||||
anchor: &mut self.anchor.x,
|
anchor: &mut self.rel.x,
|
||||||
offset: &mut self.offset.x,
|
offset: &mut self.abs.x,
|
||||||
},
|
},
|
||||||
Axis::Y => UIScalarView {
|
Axis::Y => UiScalarView {
|
||||||
anchor: &mut self.anchor.y,
|
anchor: &mut self.rel.y,
|
||||||
offset: &mut self.offset.y,
|
offset: &mut self.abs.y,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn axis(&self, axis: Axis) -> UiScalar {
|
||||||
|
match axis {
|
||||||
|
Axis::X => UiScalar {
|
||||||
|
rel: self.rel.x,
|
||||||
|
abs: self.abs.x,
|
||||||
|
},
|
||||||
|
Axis::Y => UiScalar {
|
||||||
|
rel: self.rel.y,
|
||||||
|
abs: self.abs.y,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flip(&mut self) {
|
pub fn flip(&mut self) {
|
||||||
self.anchor = 1.0 - self.anchor;
|
self.rel = 1.0 - self.rel;
|
||||||
self.offset = -self.offset;
|
self.abs = -self.abs;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flipped(mut self) -> Self {
|
pub fn flipped(mut self) -> Self {
|
||||||
@@ -78,64 +97,92 @@ impl UiPos {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_size(&self, size: Vec2) -> Vec2 {
|
pub fn to_size(&self, size: Vec2) -> Vec2 {
|
||||||
self.anchor * size + self.offset
|
self.rel * size + self.abs
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn max_size() -> Self {
|
||||||
|
Self::rel(Vec2::ONE)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn from_axis(axis: Axis, aligned: UiScalar, ortho: UiScalar) -> Self {
|
||||||
|
Self {
|
||||||
|
rel: Vec2::from_axis(axis, aligned.rel, ortho.rel),
|
||||||
|
abs: Vec2::from_axis(axis, aligned.abs, ortho.abs),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const From<Align> for UiPos {
|
impl const From<Align> for UiVec2 {
|
||||||
fn from(align: Align) -> Self {
|
fn from(align: Align) -> Self {
|
||||||
Self::anchor(align.anchor())
|
Self::anchor(align.anchor())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Align {
|
impl Align {
|
||||||
pub fn pos(self) -> UiPos {
|
pub fn pos(self) -> UiVec2 {
|
||||||
UiPos::from(self)
|
UiVec2::from(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct UIScalar {
|
pub struct UiScalar {
|
||||||
pub anchor: f32,
|
pub rel: f32,
|
||||||
pub offset: f32,
|
pub abs: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_op!(UIScalar Add add; anchor offset);
|
impl_op!(UiScalar Add add; rel abs);
|
||||||
impl_op!(UIScalar Sub sub; anchor offset);
|
impl_op!(UiScalar Sub sub; rel abs);
|
||||||
|
|
||||||
impl UIScalar {
|
impl UiScalar {
|
||||||
pub fn new(anchor: f32, offset: f32) -> Self {
|
pub fn new(rel: f32, abs: f32) -> Self {
|
||||||
Self { anchor, offset }
|
Self { rel, abs }
|
||||||
}
|
}
|
||||||
pub fn min() -> Self {
|
pub fn rel_min() -> Self {
|
||||||
Self::new(0.0, 0.0)
|
Self::new(0.0, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max() -> Self {
|
pub fn rel_max() -> Self {
|
||||||
Self::new(1.0, 0.0)
|
Self::new(1.0, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn max(&self, other: Self) -> Self {
|
||||||
|
Self {
|
||||||
|
rel: self.rel.max(other.rel),
|
||||||
|
abs: self.abs.max(other.abs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn min(&self, other: Self) -> Self {
|
||||||
|
Self {
|
||||||
|
rel: self.rel.min(other.rel),
|
||||||
|
abs: self.abs.min(other.abs),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_anchor(anchor: f32) -> Self {
|
pub fn from_anchor(anchor: f32) -> Self {
|
||||||
Self::new(anchor, 0.0)
|
Self::new(anchor, 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset(mut self, amt: f32) -> Self {
|
pub fn offset(mut self, amt: f32) -> Self {
|
||||||
self.offset += amt;
|
self.abs += amt;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn within(&self, start: UIScalar, end: UIScalar) -> Self {
|
pub fn within(&self, start: UiScalar, end: UiScalar) -> Self {
|
||||||
let anchor = self.anchor.lerp(start.anchor, end.anchor);
|
let anchor = self.rel.lerp(start.rel, end.rel);
|
||||||
let offset = self.offset + self.anchor.lerp(start.offset, end.offset);
|
let offset = self.abs + self.rel.lerp(start.abs, end.abs);
|
||||||
Self { anchor, offset }
|
Self {
|
||||||
|
rel: anchor,
|
||||||
|
abs: offset,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Debug, Copy, Clone, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
pub struct UiRegion {
|
pub struct UiRegion {
|
||||||
pub top_left: UiPos,
|
pub top_left: UiVec2,
|
||||||
pub bot_right: UiPos,
|
pub bot_right: UiVec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UiRegion {
|
impl UiRegion {
|
||||||
@@ -147,8 +194,8 @@ impl UiRegion {
|
|||||||
}
|
}
|
||||||
pub fn anchor(anchor: Vec2) -> Self {
|
pub fn anchor(anchor: Vec2) -> Self {
|
||||||
Self {
|
Self {
|
||||||
top_left: UiPos::anchor(anchor),
|
top_left: UiVec2::anchor(anchor),
|
||||||
bot_right: UiPos::anchor(anchor),
|
bot_right: UiVec2::anchor(anchor),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn within(&self, parent: &Self) -> Self {
|
pub fn within(&self, parent: &Self) -> Self {
|
||||||
@@ -183,12 +230,12 @@ impl UiRegion {
|
|||||||
|
|
||||||
pub fn to_screen(&self, size: Vec2) -> ScreenRegion {
|
pub fn to_screen(&self, size: Vec2) -> ScreenRegion {
|
||||||
ScreenRegion {
|
ScreenRegion {
|
||||||
top_left: self.top_left.anchor * size + self.top_left.offset,
|
top_left: self.top_left.rel * size + self.top_left.abs,
|
||||||
bot_right: self.bot_right.anchor * size + self.bot_right.offset,
|
bot_right: self.bot_right.rel * size + self.bot_right.abs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn center(&self) -> UiPos {
|
pub fn center(&self) -> UiVec2 {
|
||||||
Align::Center.pos().within(self)
|
Align::Center.pos().within(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,10 +248,23 @@ impl UiRegion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_size_align(size: Vec2, align: Align) -> Self {
|
pub fn from_size_align(size: Vec2, align: Align) -> Self {
|
||||||
let mut top_left = UiPos::from(align);
|
let mut top_left = UiVec2::from(align);
|
||||||
top_left.offset -= size * align.anchor();
|
top_left.abs -= size * align.anchor();
|
||||||
let mut bot_right = UiPos::from(align);
|
let mut bot_right = UiVec2::from(align);
|
||||||
bot_right.offset += size * (Vec2::ONE - align.anchor());
|
bot_right.abs += size * (Vec2::ONE - align.anchor());
|
||||||
|
Self {
|
||||||
|
top_left,
|
||||||
|
bot_right,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_ui_size_align(size: UiVec2, align: Align) -> Self {
|
||||||
|
let mut top_left = UiVec2::from(align);
|
||||||
|
top_left.abs -= size.abs * align.anchor();
|
||||||
|
top_left.rel -= size.rel * align.anchor();
|
||||||
|
let mut bot_right = UiVec2::from(align);
|
||||||
|
bot_right.abs += size.abs * (Vec2::ONE - align.anchor());
|
||||||
|
bot_right.rel += size.rel * (Vec2::ONE - align.anchor());
|
||||||
Self {
|
Self {
|
||||||
top_left,
|
top_left,
|
||||||
bot_right,
|
bot_right,
|
||||||
@@ -227,24 +287,24 @@ impl ScreenRegion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct UIRegionAxisView<'a> {
|
pub struct UIRegionAxisView<'a> {
|
||||||
pub top_left: UIScalarView<'a>,
|
pub top_left: UiScalarView<'a>,
|
||||||
pub bot_right: UIScalarView<'a>,
|
pub bot_right: UiScalarView<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UIScalarView<'a> {
|
pub struct UiScalarView<'a> {
|
||||||
pub anchor: &'a mut f32,
|
pub anchor: &'a mut f32,
|
||||||
pub offset: &'a mut f32,
|
pub offset: &'a mut f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIScalarView<'_> {
|
impl UiScalarView<'_> {
|
||||||
pub fn set(&mut self, scalar: UIScalar) {
|
pub fn set(&mut self, scalar: UiScalar) {
|
||||||
*self.anchor = scalar.anchor;
|
*self.anchor = scalar.rel;
|
||||||
*self.offset = scalar.offset;
|
*self.offset = scalar.abs;
|
||||||
}
|
}
|
||||||
pub fn get(self) -> UIScalar {
|
pub fn get(self) -> UiScalar {
|
||||||
UIScalar {
|
UiScalar {
|
||||||
anchor: *self.anchor,
|
rel: *self.anchor,
|
||||||
offset: *self.offset,
|
abs: *self.offset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ pub trait UiCtx {
|
|||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO: this takes ui.sensor_map and then puts it back
|
||||||
|
/// it extends so you can add to it, but you can't actually index sensors with it
|
||||||
|
/// should something be done about this?
|
||||||
pub fn run_sensors<Ctx: UiCtx>(ctx: &mut Ctx, cursor: &CursorState, window_size: Vec2) {
|
pub fn run_sensors<Ctx: UiCtx>(ctx: &mut Ctx, cursor: &CursorState, window_size: Vec2) {
|
||||||
let active = std::mem::take(&mut ctx.ui().active.sensors);
|
let active = std::mem::take(&mut ctx.ui().active.sensors);
|
||||||
let mut map = std::mem::take(&mut ctx.ui().sensor_map);
|
let mut map = std::mem::take(&mut ctx.ui().sensor_map);
|
||||||
@@ -128,8 +131,11 @@ pub fn run_sensors<Ctx: UiCtx>(ctx: &mut Ctx, cursor: &CursorState, window_size:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.ui().sensor_map = map;
|
let ui = ctx.ui();
|
||||||
ctx.ui().active.sensors = active;
|
std::mem::swap(&mut ui.sensor_map, &mut map);
|
||||||
|
ui.sensor_map.extend(map);
|
||||||
|
assert!(ui.active.sensors.is_empty());
|
||||||
|
ui.active.sensors = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn should_run(senses: &Senses, cursor: &CursorButtons, hover: ActivationState) -> bool {
|
pub fn should_run(senses: &Senses, cursor: &CursorButtons, hover: ActivationState) -> bool {
|
||||||
|
|||||||
@@ -66,6 +66,10 @@ impl<Ctx> Ui<Ctx> {
|
|||||||
self.widgets.data_mut(&id.id).unwrap().label = label;
|
self.widgets.data_mut(&id.id).unwrap().label = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn label<W>(&self, id: &WidgetId<W>) -> &String {
|
||||||
|
&self.widgets.data(&id.id).unwrap().label
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_widget<W: Widget>(&mut self, w: W) -> WidgetId<W> {
|
pub fn add_widget<W: Widget>(&mut self, w: W) -> WidgetId<W> {
|
||||||
self.push(w)
|
self.push(w)
|
||||||
}
|
}
|
||||||
@@ -281,6 +285,10 @@ impl Widgets {
|
|||||||
self.map.get(id)
|
self.map.get(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn label(&self, id: &Id) -> &String {
|
||||||
|
&self.data(id).unwrap().label
|
||||||
|
}
|
||||||
|
|
||||||
pub fn data_mut(&mut self, id: &Id) -> Option<&mut WidgetData> {
|
pub fn data_mut(&mut self, id: &Id) -> Option<&mut WidgetData> {
|
||||||
self.map.get_mut(id)
|
self.map.get_mut(id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use crate::layout::{Painter, SizeCtx, StaticWidgetId, Ui, Vec2, WidgetId, WidgetIdFn};
|
use crate::layout::{Painter, SizeCtx, StaticWidgetId, Ui, UiVec2, WidgetId, WidgetIdFn};
|
||||||
|
|
||||||
use std::{any::Any, marker::PhantomData};
|
use std::{any::Any, marker::PhantomData};
|
||||||
|
|
||||||
pub trait Widget: Any {
|
pub trait Widget: Any {
|
||||||
fn draw(&mut self, painter: &mut Painter);
|
fn draw(&mut self, painter: &mut Painter);
|
||||||
fn get_size(&mut self, ctx: &mut SizeCtx) -> Vec2 {
|
fn desired_size(&mut self, _: &mut SizeCtx) -> UiVec2 {
|
||||||
ctx.size
|
UiVec2::max_size()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ impl Primitives {
|
|||||||
self.run.len() != 0
|
self.run.len() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip(&mut self, range: &Range<usize>) {
|
pub fn skip(&mut self, range: &mut Range<usize>) {
|
||||||
if self.running() {
|
if self.running() {
|
||||||
self.run.data.extend(&self.instances.data[range.clone()]);
|
self.run.data.extend(&self.instances.data[range.clone()]);
|
||||||
self.run.assoc.extend(
|
self.run.assoc.extend(
|
||||||
@@ -137,7 +137,9 @@ impl Primitives {
|
|||||||
.map(|i| i.duplicate()),
|
.map(|i| i.duplicate()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
range.start = self.pos;
|
||||||
self.pos += range.len();
|
self.pos += range.len();
|
||||||
|
range.end = self.pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clear(&mut self) {
|
pub(crate) fn clear(&mut self) {
|
||||||
@@ -184,6 +186,7 @@ impl Primitives {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct PrimitiveHandle {
|
pub struct PrimitiveHandle {
|
||||||
idx: usize,
|
idx: usize,
|
||||||
binding: u32,
|
binding: u32,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ pub struct Client {
|
|||||||
input: Input,
|
input: Input,
|
||||||
ui: Ui<Client>,
|
ui: Ui<Client>,
|
||||||
info: WidgetId<Text>,
|
info: WidgetId<Text>,
|
||||||
selected: Option<WidgetId<TextEdit>>,
|
focus: Option<WidgetId<TextEdit>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
@@ -38,7 +38,7 @@ impl Client {
|
|||||||
rrect.color(Color::ORANGE),
|
rrect.color(Color::ORANGE),
|
||||||
rrect.color(Color::LIME).pad(10.0),
|
rrect.color(Color::LIME).pad(10.0),
|
||||||
)
|
)
|
||||||
.span(Dir::RIGHT, [1, 1]),
|
.span(Dir::RIGHT, ratio(1)),
|
||||||
rrect.color(Color::YELLOW),
|
rrect.color(Color::YELLOW),
|
||||||
)
|
)
|
||||||
.span(Dir::RIGHT, [2, 2, 1])
|
.span(Dir::RIGHT, [2, 2, 1])
|
||||||
@@ -110,6 +110,7 @@ impl Client {
|
|||||||
btext(":gamer mode").family(Family::Monospace),
|
btext(":gamer mode").family(Family::Monospace),
|
||||||
rect(Color::CYAN).size(10).center(),
|
rect(Color::CYAN).size(10).center(),
|
||||||
rect(Color::RED).size(100).center(),
|
rect(Color::RED).size(100).center(),
|
||||||
|
rect(Color::PURPLE).size(50).align(Align::Top),
|
||||||
)
|
)
|
||||||
.span(Dir::RIGHT, sized())
|
.span(Dir::RIGHT, sized())
|
||||||
.center(),
|
.center(),
|
||||||
@@ -119,14 +120,34 @@ impl Client {
|
|||||||
.add_static(&mut ui);
|
.add_static(&mut ui);
|
||||||
|
|
||||||
let texts = Span::empty(Dir::DOWN).add(&mut ui);
|
let texts = Span::empty(Dir::DOWN).add(&mut ui);
|
||||||
let text_edit_scroll = (
|
let add_text = text_edit("add")
|
||||||
texts,
|
.text_align(Align::Left)
|
||||||
text_edit("add")
|
|
||||||
.font_size(30)
|
.font_size(30)
|
||||||
.id_on(Sense::click(), |id, client: &mut Client, ctx| {
|
.id_on(Sense::click(), |id, client: &mut Client, ctx| {
|
||||||
client.ui.text(id).select(ctx.cursor, ctx.size);
|
client.ui.text(id).select(ctx.cursor, ctx.size);
|
||||||
client.selected = Some(id.clone());
|
client.focus = Some(id.clone());
|
||||||
})
|
})
|
||||||
|
.add(&mut ui);
|
||||||
|
let text_edit_scroll = (
|
||||||
|
(Rect::new(Color::SKY), texts.clone()).stack(),
|
||||||
|
(
|
||||||
|
add_text.clone(),
|
||||||
|
Rect::new(Color::GREEN)
|
||||||
|
.on(Sense::click(), move |client: &mut Client, _| {
|
||||||
|
let content = client.ui.text(&add_text).take();
|
||||||
|
let text = text_edit(content)
|
||||||
|
.font_size(30)
|
||||||
|
.id_on(Sense::click(), |id, client: &mut Client, ctx| {
|
||||||
|
client.ui.text(id).select(ctx.cursor, ctx.size);
|
||||||
|
client.focus = Some(id.clone());
|
||||||
|
})
|
||||||
|
.pad(10)
|
||||||
|
.add(&mut client.ui);
|
||||||
|
client.ui[&texts].children.push((text.any(), sized()));
|
||||||
|
})
|
||||||
|
.size(40),
|
||||||
|
)
|
||||||
|
.span(Dir::RIGHT, [ratio(1), sized()])
|
||||||
.pad(30),
|
.pad(30),
|
||||||
)
|
)
|
||||||
.span(Dir::DOWN, [ratio(1), sized()])
|
.span(Dir::DOWN, [ratio(1), sized()])
|
||||||
@@ -161,24 +182,15 @@ impl Client {
|
|||||||
.span(Dir::RIGHT, ratio(1));
|
.span(Dir::RIGHT, ratio(1));
|
||||||
|
|
||||||
let info = text("").add(&mut ui);
|
let info = text("").add(&mut ui);
|
||||||
let info_sect = info.clone().pad(10).align(Align::BotLeft);
|
// let info_sect = info.clone().pad(10).align(Align::BotLeft);
|
||||||
ui.set_root(
|
ui.set_root((tabs, main).span(Dir::DOWN, [fixed(40), ratio(1)]));
|
||||||
(
|
|
||||||
tabs.label("tabs"),
|
|
||||||
(main, info_sect.label("info sect"))
|
|
||||||
.stack()
|
|
||||||
.label("main stack"),
|
|
||||||
)
|
|
||||||
.span(Dir::DOWN, [fixed(40), ratio(1)])
|
|
||||||
.label("root"),
|
|
||||||
);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
renderer,
|
renderer,
|
||||||
input: Input::default(),
|
input: Input::default(),
|
||||||
ui,
|
ui,
|
||||||
info,
|
info,
|
||||||
selected: None,
|
focus: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +198,12 @@ impl Client {
|
|||||||
self.input.event(&event);
|
self.input.event(&event);
|
||||||
let cursor_state = self.cursor_state().clone();
|
let cursor_state = self.cursor_state().clone();
|
||||||
let window_size = self.window_size();
|
let window_size = self.window_size();
|
||||||
|
if let Some(focus) = &self.focus
|
||||||
|
&& cursor_state.buttons.left.is_start()
|
||||||
|
{
|
||||||
|
self.ui.text(focus).deselect();
|
||||||
|
self.focus = None;
|
||||||
|
}
|
||||||
run_sensors(self, &cursor_state, window_size);
|
run_sensors(self, &cursor_state, window_size);
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
@@ -199,24 +217,24 @@ impl Client {
|
|||||||
self.renderer.resize(&size)
|
self.renderer.resize(&size)
|
||||||
}
|
}
|
||||||
WindowEvent::KeyboardInput { event, .. } => {
|
WindowEvent::KeyboardInput { event, .. } => {
|
||||||
if let Some(sel) = &self.selected
|
if let Some(sel) = &self.focus
|
||||||
&& event.state.is_pressed()
|
&& event.state.is_pressed()
|
||||||
&& self.ui.text(sel).apply_event(&event).unfocus()
|
&& self.ui.text(sel).apply_event(&event).unfocus()
|
||||||
{
|
{
|
||||||
self.selected = None;
|
self.focus = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
let new = format!(
|
// let new = format!(
|
||||||
"widgets: {}\nactive:{}\nviews: {}",
|
// "widgets: {}\nactive:{}\nviews: {}",
|
||||||
self.ui.num_widgets(),
|
// self.ui.num_widgets(),
|
||||||
self.ui.active_widgets(),
|
// self.ui.active_widgets(),
|
||||||
self.renderer.ui.view_count()
|
// self.renderer.ui.view_count()
|
||||||
);
|
// );
|
||||||
if new != self.ui[&self.info].content {
|
// if new != self.ui[&self.info].content {
|
||||||
self.ui[&self.info].content = new;
|
// self.ui[&self.info].content = new;
|
||||||
}
|
// }
|
||||||
if self.ui.needs_redraw() {
|
if self.ui.needs_redraw() {
|
||||||
self.renderer.window().request_redraw();
|
self.renderer.window().request_redraw();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,3 +54,13 @@ impl CopyId {
|
|||||||
Id(self.0)
|
Id(self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait IdUtil {
|
||||||
|
fn duplicate(&self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdUtil for Option<Id> {
|
||||||
|
fn duplicate(&self) -> Self {
|
||||||
|
self.as_ref().map(|i| i.duplicate())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user