use std::marker::PhantomData;
use crate::core::{
AppendVec, ElementSplice, MessageContext, MessageResult, Mut, SuperElement, View, ViewElement,
ViewMarker, ViewSequence,
};
use crate::{Pod, ViewCtx};
use masonry::core::{FromDynWidget, Widget, WidgetMut};
use masonry::widgets;
pub fn indexed_stack<State, Action, Seq: IndexedStackSequence<State, Action>>(
sequence: Seq,
) -> IndexedStack<Seq, State, Action> {
IndexedStack {
sequence,
active_child: 0,
phantom: PhantomData,
}
}
#[must_use = "View values do nothing unless provided to Xilem."]
pub struct IndexedStack<Seq, State, Action = ()> {
sequence: Seq,
active_child: usize,
phantom: PhantomData<fn() -> (State, Action)>,
}
impl<Seq, State, Action> IndexedStack<Seq, State, Action> {
#[track_caller]
pub fn active(mut self, active: usize) -> Self {
self.active_child = active;
self
}
}
mod hidden {
use super::IndexedStackElement;
use crate::core::AppendVec;
#[doc(hidden)]
#[expect(
unnameable_types,
reason = "Implementation detail, public because of trait visibility rules"
)]
pub struct IndexedStackState<SeqState> {
pub(crate) seq_state: SeqState,
pub(crate) scratch: AppendVec<IndexedStackElement>,
}
}
use hidden::IndexedStackState;
impl<Seq, State, Action> ViewMarker for IndexedStack<Seq, State, Action> {}
impl<State, Action, Seq> View<State, Action, ViewCtx> for IndexedStack<Seq, State, Action>
where
State: 'static,
Action: 'static,
Seq: IndexedStackSequence<State, Action>,
{
type Element = Pod<widgets::IndexedStack>;
type ViewState = IndexedStackState<Seq::SeqState>;
fn build(&self, ctx: &mut ViewCtx, app_state: &mut State) -> (Self::Element, Self::ViewState) {
let mut elements = AppendVec::default();
let mut widget = widgets::IndexedStack::new();
let seq_state = self.sequence.seq_build(ctx, &mut elements, app_state);
for element in elements.drain() {
widget = widget.with_child(element.child.new_widget);
}
widget = widget.with_active_child(self.active_child);
let pod = ctx.create_pod(widget);
(
pod,
IndexedStackState {
seq_state,
scratch: elements,
},
)
}
fn rebuild(
&self,
prev: &Self,
IndexedStackState { seq_state, scratch }: &mut Self::ViewState,
ctx: &mut ViewCtx,
mut element: Mut<'_, Self::Element>,
app_state: &mut State,
) {
{
let mut splice = IndexedStackSplice::new(element.reborrow_mut(), scratch);
self.sequence
.seq_rebuild(&prev.sequence, seq_state, ctx, &mut splice, app_state);
debug_assert!(scratch.is_empty());
}
if self.active_child != element.widget.active_child_index() {
widgets::IndexedStack::set_active_child(&mut element, self.active_child);
}
}
fn teardown(
&self,
IndexedStackState { seq_state, scratch }: &mut Self::ViewState,
ctx: &mut ViewCtx,
element: Mut<'_, Self::Element>,
) {
let mut splice = IndexedStackSplice::new(element, scratch);
self.sequence.seq_teardown(seq_state, ctx, &mut splice);
debug_assert!(scratch.is_empty());
}
fn message(
&self,
IndexedStackState { seq_state, scratch }: &mut Self::ViewState,
message: &mut MessageContext,
element: Mut<'_, Self::Element>,
app_state: &mut State,
) -> MessageResult<Action> {
let mut splice = IndexedStackSplice::new(element, scratch);
let result = self
.sequence
.seq_message(seq_state, message, &mut splice, app_state);
debug_assert!(scratch.is_empty());
result
}
}
impl ViewElement for IndexedStackElement {
type Mut<'w> = IndexedStackElementMut<'w>;
}
impl SuperElement<Self, ViewCtx> for IndexedStackElement {
fn upcast(_ctx: &mut ViewCtx, child: Self) -> Self {
child
}
fn with_downcast_val<R>(
mut this: Mut<'_, Self>,
f: impl FnOnce(Mut<'_, Self>) -> R,
) -> (Self::Mut<'_>, R) {
let r = {
let parent = this.parent.reborrow_mut();
let reborrow = IndexedStackElementMut {
idx: this.idx,
parent,
};
f(reborrow)
};
(this, r)
}
}
impl<W: Widget + FromDynWidget + ?Sized> SuperElement<Pod<W>, ViewCtx> for IndexedStackElement {
fn upcast(_: &mut ViewCtx, child: Pod<W>) -> Self {
Self {
child: child.erased(),
}
}
fn with_downcast_val<R>(
mut this: Mut<'_, Self>,
f: impl FnOnce(Mut<'_, Pod<W>>) -> R,
) -> (Mut<'_, Self>, R) {
let ret = {
let mut child = widgets::IndexedStack::child_mut(&mut this.parent, this.idx);
let downcast = child.downcast();
f(downcast)
};
(this, ret)
}
}
impl ElementSplice<IndexedStackElement> for IndexedStackSplice<'_, '_> {
fn with_scratch<R>(&mut self, f: impl FnOnce(&mut AppendVec<IndexedStackElement>) -> R) -> R {
let ret = f(self.scratch);
for element in self.scratch.drain() {
widgets::IndexedStack::insert_child(
&mut self.element,
self.idx,
element.child.new_widget,
);
self.idx += 1;
}
ret
}
fn insert(&mut self, element: IndexedStackElement) {
widgets::IndexedStack::insert_child(&mut self.element, self.idx, element.child.new_widget);
self.idx += 1;
}
fn mutate<R>(&mut self, f: impl FnOnce(Mut<'_, IndexedStackElement>) -> R) -> R {
let child = IndexedStackElementMut {
parent: self.element.reborrow_mut(),
idx: self.idx,
};
let ret = f(child);
self.idx += 1;
ret
}
fn skip(&mut self, n: usize) {
self.idx += n;
}
fn index(&self) -> usize {
self.idx
}
fn delete<R>(&mut self, f: impl FnOnce(Mut<'_, IndexedStackElement>) -> R) -> R {
let ret = {
let child = IndexedStackElementMut {
parent: self.element.reborrow_mut(),
idx: self.idx,
};
f(child)
};
widgets::IndexedStack::remove_child(&mut self.element, self.idx);
ret
}
}
pub trait IndexedStackSequence<State, Action = ()>:
ViewSequence<State, Action, ViewCtx, IndexedStackElement>
{
}
impl<Seq, State, Action> IndexedStackSequence<State, Action> for Seq where
Seq: ViewSequence<State, Action, ViewCtx, IndexedStackElement>
{
}
pub struct IndexedStackElement {
child: Pod<dyn Widget>,
}
pub struct IndexedStackElementMut<'w> {
parent: WidgetMut<'w, widgets::IndexedStack>,
idx: usize,
}
struct IndexedStackSplice<'w, 's> {
idx: usize,
element: WidgetMut<'w, widgets::IndexedStack>,
scratch: &'s mut AppendVec<IndexedStackElement>,
}
impl<'w, 's> IndexedStackSplice<'w, 's> {
fn new(
element: WidgetMut<'w, widgets::IndexedStack>,
scratch: &'s mut AppendVec<IndexedStackElement>,
) -> Self {
Self {
idx: 0,
element,
scratch,
}
}
}