Skip to content

Commit

Permalink
nuon: Remove Widget::children_tree & Widget::diff
Browse files Browse the repository at this point in the history
  • Loading branch information
PolyMeilex committed Dec 7, 2024
1 parent 21abef4 commit ed95d4a
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 71 deletions.
4 changes: 2 additions & 2 deletions neothesia/src/scene/playing_scene/top_bar/widget/looper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ impl<MSG> Widget<MSG> for Looper<MSG> {
tree: &Tree<Self::State>,
_ctx: &RenderCtx,
) {
let state = tree.state();
let state = tree.state.get();

let bg = &layout.children[0];

Expand Down Expand Up @@ -160,7 +160,7 @@ impl<MSG> Widget<MSG> for Looper<MSG> {
tree: &mut Tree<Self::State>,
ctx: &mut UpdateCtx<MSG>,
) {
let state = tree.state_mut();
let state = tree.state.get_mut();
let player = ctx.globals.get::<MidiPlayer>();

match event {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl<MSG: Clone> Widget<MSG> for ProgressBar<MSG> {
tree: &Tree<Self::State>,
ctx: &RenderCtx,
) {
let _state = tree.state();
let _state = tree.state.get();
let player = ctx.globals.get::<MidiPlayer>();

let progress_w = layout.w * player.percentage();
Expand Down Expand Up @@ -107,7 +107,7 @@ impl<MSG: Clone> Widget<MSG> for ProgressBar<MSG> {
tree: &mut Tree<Self::State>,
ctx: &mut UpdateCtx<MSG>,
) {
let state = tree.state_mut();
let state = tree.state.get_mut();

match event {
Event::CursorMoved { position } => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl<MSG: Clone> Widget<MSG> for SpeedPill<MSG> {

fn layout(&self, tree: &mut Tree<Self::State>, parent: &ParentLayout, ctx: &LayoutCtx) -> Node {
let minus = self.children[0].as_widget().layout(
tree.children[0].remap_mut(),
&mut tree.children[0],
&ParentLayout {
x: parent.x,
y: parent.y + 5.0,
Expand All @@ -87,7 +87,7 @@ impl<MSG: Clone> Widget<MSG> for SpeedPill<MSG> {
ctx,
);
let plus = self.children[1].as_widget().layout(
tree.children[1].remap_mut(),
&mut tree.children[1],
&ParentLayout {
x: parent.x + minus.w,
y: parent.y + 5.0,
Expand Down
40 changes: 9 additions & 31 deletions nuon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
collections::HashMap,
};

pub use tree::Tree;
pub use tree::{Tree, TreeState};
pub use widget::*;

pub use euclid;
Expand Down Expand Up @@ -100,12 +100,9 @@ pub struct ParentLayout {

pub trait WidgetAny<MSG> {
fn state_type_id(&self) -> TypeId;
fn state(&self) -> Box<dyn Any>;
fn state(&self) -> TreeState;

fn children(&self) -> &[Element<MSG>];
fn children_tree(&self) -> Vec<Tree>;

fn diff(&self, tree: &mut Tree);

fn layout(&self, tree: &mut Tree, avalilable: &ParentLayout, ctx: &LayoutCtx) -> Node;
fn render(&self, renderer: &mut dyn Renderer, layout: &Node, tree: &Tree, ctx: &RenderCtx);
Expand All @@ -117,28 +114,20 @@ impl<MSG, W: Widget<MSG>> WidgetAny<MSG> for W {
TypeId::of::<W::State>()
}

fn state(&self) -> Box<dyn Any> {
Widget::state(self)
fn state(&self) -> TreeState {
TreeState::new(Widget::state(self))
}

fn children(&self) -> &[Element<MSG>] {
Widget::children(self)
}

fn children_tree(&self) -> Vec<Tree> {
Widget::children_tree(self)
}

fn diff(&self, tree: &mut Tree) {
Widget::diff(self, tree)
}

fn layout(&self, tree: &mut Tree, parent: &ParentLayout, ctx: &LayoutCtx) -> Node {
Widget::layout(self, tree.remap_mut(), parent, ctx)
Widget::layout(self, tree.cast_mut(), parent, ctx)
}

fn render(&self, renderer: &mut dyn Renderer, layout: &Node, tree: &Tree, ctx: &RenderCtx) {
Widget::render(self, renderer, layout, tree.remap_ref(), ctx)
Widget::render(self, renderer, layout, tree.cast_ref(), ctx)
}

fn update(
Expand All @@ -148,32 +137,21 @@ impl<MSG, W: Widget<MSG>> WidgetAny<MSG> for W {
tree: &mut Tree,
ctx: &mut UpdateCtx<MSG>,
) {
Widget::update(self, event, layout, tree.remap_mut(), ctx)
Widget::update(self, event, layout, tree.cast_mut(), ctx)
}
}

pub trait Widget<MSG> {
type State: Any + Default;

fn state(&self) -> Box<dyn Any> {
Box::new(Self::State::default())
fn state(&self) -> Self::State {
Self::State::default()
}

fn children(&self) -> &[Element<MSG>] {
&[]
}

fn children_tree(&self) -> Vec<Tree> {
self.children()
.iter()
.map(|w| Tree::new(w.as_widget()))
.collect()
}

fn diff(&self, tree: &mut Tree) {
tree.diff_children(self.children());
}

fn layout(&self, tree: &mut Tree<Self::State>, parent: &ParentLayout, ctx: &LayoutCtx) -> Node {
widget::stack::stack_layout(self, tree, parent, ctx)
}
Expand Down
91 changes: 59 additions & 32 deletions nuon/src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,73 +8,104 @@ use crate::{Element, WidgetAny};
pub struct UnknownState;
struct NullTreeState;

pub struct Tree<T = UnknownState> {
pub state: Box<dyn Any>,
pub children: Vec<Tree>,
#[track_caller]
fn type_check_assert<NEW: Any>(state_type_id: TypeId) {
if TypeId::of::<NEW>() != TypeId::of::<UnknownState>() {
assert_eq!(TypeId::of::<NEW>(), state_type_id);
} else {
// Always allow cast to unknown
}
}

pub struct TreeState<T = UnknownState> {
state: Box<dyn Any>,
_ph: PhantomData<T>,
}

impl<T: 'static> Tree<T> {
pub fn remap<NEW: Any>(self) -> Tree<NEW> {
if TypeId::of::<NEW>() != TypeId::of::<UnknownState>() {
assert_eq!(TypeId::of::<NEW>(), self.state_type_id());
impl<T: Any> TreeState<T> {
pub(crate) fn new(state: impl Any) -> Self {
Self {
state: Box::new(state),
_ph: PhantomData,
}
}

// SAFTETY: T is only in phantom data
unsafe { std::mem::transmute(self) }
pub fn get(&self) -> &T {
self.state.downcast_ref::<T>().unwrap()
}

pub fn remap_ref<NEW: Any>(&self) -> &Tree<NEW> {
if TypeId::of::<NEW>() != TypeId::of::<UnknownState>() {
assert_eq!(TypeId::of::<NEW>(), self.state_type_id());
}
pub fn get_mut(&mut self) -> &mut T {
self.state.downcast_mut::<T>().unwrap()
}

fn state_type_id(&self) -> TypeId {
self.state.as_ref().type_id()
}

fn cast<NEW: Any>(self) -> TreeState<NEW> {
type_check_assert::<NEW>(self.state_type_id());
// SAFTETY: T is only in phantom data
unsafe { std::mem::transmute(self) }
}
}

pub fn remap_mut<NEW: Any>(&mut self) -> &mut Tree<NEW> {
if TypeId::of::<NEW>() != TypeId::of::<UnknownState>() {
assert_eq!(TypeId::of::<NEW>(), self.state_type_id());
}
pub struct Tree<T = UnknownState> {
pub state: TreeState<T>,
pub children: Vec<Tree>,
_ph: PhantomData<T>,
}

impl<T: 'static> Tree<T> {
#[expect(unused)]
pub(crate) fn cast<NEW: Any>(self) -> Tree<NEW> {
type_check_assert::<NEW>(self.state.state_type_id());
// SAFTETY: T is only in phantom data
unsafe { std::mem::transmute(self) }
}

pub fn state(&self) -> &T {
self.state.downcast_ref::<T>().unwrap()
pub(crate) fn cast_ref<NEW: Any>(&self) -> &Tree<NEW> {
type_check_assert::<NEW>(self.state.state_type_id());
// SAFTETY: T is only in phantom data
unsafe { std::mem::transmute(self) }
}

pub fn state_mut(&mut self) -> &mut T {
self.state.downcast_mut::<T>().unwrap()
pub(crate) fn cast_mut<NEW: Any>(&mut self) -> &mut Tree<NEW> {
type_check_assert::<NEW>(self.state.state_type_id());
// SAFTETY: T is only in phantom data
unsafe { std::mem::transmute(self) }
}

pub fn null() -> Self {
Self {
state: Box::new(NullTreeState),
state: TreeState::new(Box::new(NullTreeState)),
children: Vec::new(),
_ph: PhantomData,
}
}

pub fn new<MSG>(widget: &dyn WidgetAny<MSG>) -> Self {
let children = widget
.children()
.iter()
.map(|w| Tree::new(w.as_widget()))
.collect();

Self {
state: widget.state(),
children: widget.children_tree(),
state: widget.state().cast(),
children,
_ph: PhantomData,
}
}

pub fn diff<MSG>(&mut self, new: &dyn WidgetAny<MSG>) {
if self.state_type_id() == new.state_type_id() {
new.diff(self.remap_mut());
if self.state.state_type_id() == new.state_type_id() {
self.diff_children(new.children());
} else {
*self = Self::new(new);
}
}

pub fn diff_children<MSG>(&mut self, new_children: &[Element<MSG>]) {
fn diff_children<MSG>(&mut self, new_children: &[Element<MSG>]) {
if self.children.len() > new_children.len() {
self.children.truncate(new_children.len());
}
Expand All @@ -87,12 +118,8 @@ impl<T: 'static> Tree<T> {
self.children.extend(
new_children[self.children.len()..]
.iter()
.map(|widget| Self::new(widget.as_widget()).remap()),
.map(|widget| Tree::new(widget.as_widget())),
);
}
}

pub fn state_type_id(&self) -> TypeId {
self.state.as_ref().type_id()
}
}
4 changes: 2 additions & 2 deletions nuon/src/widget/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl<MSG: Clone> Widget<MSG> for Button<MSG> {
tree: &Tree<Self::State>,
_ctx: &RenderCtx,
) {
let state = tree.state();
let state = tree.state.get();

renderer.rounded_quad(
layout.x,
Expand Down Expand Up @@ -146,7 +146,7 @@ impl<MSG: Clone> Widget<MSG> for Button<MSG> {
tree: &mut Tree<Self::State>,
ctx: &mut UpdateCtx<MSG>,
) {
let state = tree.state_mut();
let state = tree.state.get_mut();

match event {
Event::CursorMoved { position } => {
Expand Down

0 comments on commit ed95d4a

Please sign in to comment.