Phase 9: Keyed widgets (9.1 + 9.2)
9.1: Add content_hash field to Element, computed during VDOM evaluation from type_name + properties + children content_hashes via DefaultHasher. 9.2: Assign stable iced::widget::Id to text_input and scrollable widgets so Iced preserves widget state (cursor position, scroll offset) across frames. Ids are cached in a thread_local HashMap to avoid leaks. 9.3 skipped: iced::Element is not Clone and contains Box<dyn Widget>, making element-level caching impractical without unsafe lifetime hacks.
This commit is contained in:
@@ -9,8 +9,25 @@ use iced::widget::{
|
||||
use iced::{Alignment, Background, Border, Length, Theme};
|
||||
use iced::font::Weight;
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
|
||||
thread_local! {
|
||||
static WIDGET_ID_CACHE: RefCell<HashMap<(u32, &'static str), iced::widget::Id>> = RefCell::new(HashMap::new());
|
||||
}
|
||||
|
||||
fn get_or_create_widget_id(key: u32, prefix: &'static str) -> iced::widget::Id {
|
||||
WIDGET_ID_CACHE.with(|cache| {
|
||||
cache.borrow_mut()
|
||||
.entry((key, prefix))
|
||||
.or_insert_with(|| {
|
||||
let s = Box::leak(format!("{prefix}:{key}").into_boxed_str());
|
||||
iced::widget::Id::new(s)
|
||||
})
|
||||
.clone()
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_var_binding(el: &Element, prop: &str) -> Option<String> {
|
||||
el.properties.iter()
|
||||
.find_map(|(k, v)| {
|
||||
@@ -378,7 +395,8 @@ fn apply_universal_box_model<'a>(
|
||||
}
|
||||
|
||||
if let Some(sid) = scrollable_id {
|
||||
s = s.on_scroll(move |viewport| Message::ScrollableScrolled(sid, viewport.absolute_offset().y));
|
||||
s = s.id(get_or_create_widget_id(sid as u32, "sc"))
|
||||
.on_scroll(move |viewport| Message::ScrollableScrolled(sid, viewport.absolute_offset().y));
|
||||
}
|
||||
|
||||
s.into()
|
||||
@@ -1167,6 +1185,7 @@ fn render_input<'a>(
|
||||
|
||||
let mut input = text_input(&placeholder, &value)
|
||||
.on_input(move |v| Message::InputChanged(var_name.clone(), v))
|
||||
.id(get_or_create_widget_id(el.element_id.0, "ti"))
|
||||
.padding(padding);
|
||||
|
||||
if let Some(w) = cs.width {
|
||||
|
||||
Reference in New Issue
Block a user