How to initialize a state of a complex lazy component, directly after components constructor call? #1951
-
I am trying to build a flexible List / Table with a lazy component at the moment. However I do not understand how I can setup the ListState directly after instantiation of the List. Here is the commented List Code: pub struct List <'a, RBuilder: RowBuilder<DATA>, MsgFactory: MessageFactory<MSG>, DATA, MSG> where
[(); <RBuilder as ListHeaderBuilder>::MAX_HEADS]:
{
rb: PhantomData<RBuilder>,
mf: PhantomData<MsgFactory>,
msg: PhantomData<MSG>,
max_rows_viewport: usize,
data_ref: &'a Vec<DATA>
}
impl <'a, RBuilder: RowBuilder<DATA>, MsgFactory: MessageFactory<MSG>, DATA, MSG> List<'a, RBuilder, MsgFactory, DATA, MSG> where
[(); <RBuilder as ListHeaderBuilder>::MAX_HEADS]:
{
/* Create a new list to visualize some data vector
At the moment trying to solve the case, where the list is const (no add / edit operations)
*/
pub fn new (data: &'a Vec<DATA>, max_rows_viewport: usize) -> List<'a, RBuilder, MsgFactory, DATA, MSG> {
let mut list: List::<'a, RBuilder, MsgFactory, DATA, MSG> =
List::<'a, RBuilder, MsgFactory, DATA, MSG>{
rb: PhantomData::<RBuilder>{},
mf: PhantomData::<MsgFactory>{},
msg: PhantomData::<MSG>{},
max_rows_viewport: max_rows_viewport,
data_ref: &data
};
let mut_list: &mut list;
//How can I add a new ListState to the state tree here,
//so that when component.view(&self, state: &Self::State) -> Element<'_,Event, Renderer>
//is called the first time, the ListState already reflects the data vector????
}
fn vp_to_data_idx(&self, vp_idx: &usize, state: &ListState) -> Option<usize> {
let data_len: usize = self.data_ref.len();
if data_len> 0 && 0 <= *vp_idx && *vp_idx < self.max_rows_viewport {
let data_idx: usize = state.start_row_viewport+ vp_idx;
if 0<=data_idx && data_idx < data_len {
Some(data_idx)
}
else{
None
}
}
else{
None
}
}
} and here is the commented ListState Code: #[derive(Default)]
pub struct ListState{
inited: bool,
start_row_viewport: usize,
row_selection_states: Vec<SelectionState>,
last_event: Option<Event>
}
impl ListState{
/* Here is my problem, how can I modify the row selection
state vector before the first draw call???
(The row selection state vector holds UNSELECTED / SELECTED / ACTIVATED
for every data entry).
*/
fn new() -> ListState{
ListState{
inited: false,
start_row_viewport: 0,
row_selection_states: Vec::<SelectionState>::new(),
last_event:None
}
}
fn init(&mut self, data_ref: & Vec<DATA>) {
if !self.inited {
self.row_selection_states.resize(data_ref.len(), SelectionState::UNSELECTED);
}
self.inited=true;
}
} Another question where I already encountered a problem in a previous implementation attempt is the type parameter RBuilder of trait RowBuilder. Basically it contains one method create_row taking a DATA instance and producing a |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 16 replies
-
Use three backticks and the |
Beta Was this translation helpful? Give feedback.
-
I think my question is related to the discussion Related discussion. After reading again through the source code of TextInput widget, I understood, that the data to be visualized in a widget should be passed in as constructor argument, while the state of a widget contains the information to parametrize the algorithms inside the draw() and on_event() methods! However what is, if the state depends on data passed in like in my List/Table example, where the state needs to contain a vec representing the selection state for each data element in the data vec? In this case the assumption, that the state impl always is of type default is problematic (I cannot pass in the size of the data vec to the table state). Another example is filtering in a table parametrized by DATA (the data type) and configurable with regards to its column filters. Obviously filtering influences the way, how the table is drawn and which rows can throw selection events, therefore the predicates parametrizing the filter algorithm should also be part of the widget state, not part of the widget. Well, now one can argument that a freshly initialized table widget should never filter nor sort the input data list, but is this realistic? In case of a file open dialog, on start one would generally like to filter by the file extension, but in some special case probably by a "modified date older than" criteria. If you want the table widget to be really that customizable, I do not see any other way than wrapping all the possible state information together with the data vector in some kind of "listmodel wrapper " that is passed in on widget creation, thereby really exposing the Lists / Tables state to the outer world. If you do not like the idea of having a special state initialization method inside the widget trait, would a special INIT_STATE_EVENT that can be received by the normal on_event() method after default state initialization be more elm-like? |
Beta Was this translation helpful? Give feedback.
-
Are you trying to build a reusable widget that can be used by other Iced users, like |
Beta Was this translation helpful? Give feedback.
-
Oh, sorry, I didn't know we were talking about a particular I don't think "component" has a clear definition in Iced, so you're right, I should state what I mean. I usually use it to describe a collection of Iced widgets that together form a cohesive part of my app. Perhaps all the state required to draw these widgets is held in its own particular unit (like your
I'm no expert here, so take me lightly, but I think your two concepts ("data" and "information") are even just one thing in Iced: state. When you draw your widgets on each
Widgets actually have their own internal/private state that is managed separately from your app's state, like a |
Beta Was this translation helpful? Give feedback.
-
Okay, seems to work now, closing... |
Beta Was this translation helpful? Give feedback.
If I'm understanding correctly, you want to create a component which manages some internal state, but also expose the ability for its creator to customize that state in the initial
view
call that produces the component.That's definitely possible, but Iced will, by way of the type system, force you to address potential awkward behaviors that could come about from doing it.
Let's say the state is type
T
: you can do what you want by setting theState
associated type on the component trait toSomeNewType(Option<T>)
. The requirement forT
to implement default can be avoided by implementing theDefault
trait manually for "SomeNewType." Then, store&T
on whatever struct it is you are implementing