From 6ac1a8d685769c38f53214b00d8a672c6be3fbf3 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Sun, 14 Sep 2025 10:18:42 +0100 Subject: [PATCH] Update examples/data-list-view.rs as in tutorial --- examples/data-list-view.rs | 112 ++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 65 deletions(-) diff --git a/examples/data-list-view.rs b/examples/data-list-view.rs index b96528f9f..e50da6c23 100644 --- a/examples/data-list-view.rs +++ b/examples/data-list-view.rs @@ -16,9 +16,6 @@ use kas::widgets::{column, *}; use kas_view::{DataGenerator, DataLen, GeneratorChanges, GeneratorClerk}; use std::collections::HashMap; -#[derive(Debug)] -struct SelectEntry(usize); - #[derive(Clone, Debug)] enum Control { SetRowLimit(bool), @@ -26,31 +23,29 @@ enum Control { DecrLen, IncrLen, Reverse, - Select(usize, String), + Select(usize), Update(usize, String), } #[derive(Debug)] -struct Data { +struct MyData { row_limit: bool, len: usize, last_change: GeneratorChanges, - last_string: usize, + last_key: usize, active: usize, dir: Direction, - active_string: String, strings: HashMap, } -impl Data { +impl MyData { fn new(row_limit: bool, len: usize) -> Self { - Data { + MyData { row_limit, len, last_change: GeneratorChanges::None, - last_string: len, + last_key: len, active: 0, dir: Direction::Down, - active_string: String::from("Entry 1"), strings: HashMap::new(), } } @@ -75,18 +70,14 @@ impl Data { self.dir = self.dir.reversed(); return; } - Control::Select(index, text) => { + Control::Select(index) => { self.last_change = GeneratorChanges::Any; self.active = index; - self.active_string = text; return; } Control::Update(index, text) => { self.last_change = GeneratorChanges::Range(index..index + 1); - self.last_string = self.last_string.max(index); - if index == self.active { - self.active_string = text.clone(); - } + self.last_key = self.last_key.max(index); self.strings.insert(index, text); return; } @@ -95,30 +86,29 @@ impl Data { self.len = len; if self.active >= len && len > 0 { self.active = len - 1; - self.active_string = self.get_string(self.active); } } } -type Item = (usize, String); // (active index, entry's text) +type MyItem = (usize, String); // (active index, entry's text) #[derive(Debug)] struct ListEntryGuard(usize); impl EditGuard for ListEntryGuard { - type Data = Item; + type Data = MyItem; - fn update(edit: &mut EditField, cx: &mut ConfigCx, data: &Item) { + fn update(edit: &mut EditField, cx: &mut ConfigCx, data: &MyItem) { if !edit.has_edit_focus() { edit.set_string(cx, data.1.to_string()); } } - fn activate(edit: &mut EditField, cx: &mut EventCx, _: &Item) -> IsUsed { - cx.push(SelectEntry(edit.guard.0)); + fn activate(edit: &mut EditField, cx: &mut EventCx, _: &MyItem) -> IsUsed { + cx.push(Control::Select(edit.guard.0)); Used } - fn edit(edit: &mut EditField, cx: &mut EventCx, _: &Item) { + fn edit(edit: &mut EditField, cx: &mut EventCx, _: &MyItem) { cx.push(Control::Update(edit.guard.0, edit.clone_string())); } } @@ -136,33 +126,48 @@ mod ListEntry { #[widget(&())] label: Label, #[widget] - radio: RadioButton, + radio: RadioButton, #[widget] edit: EditBox, } impl Events for Self { - type Data = Item; + type Data = MyItem; + } +} - fn handle_messages(&mut self, cx: &mut EventCx, data: &Item) { - if let Some(SelectEntry(n)) = cx.try_pop() { - if data.0 != n { - cx.push(Control::Select(n, self.edit.clone_string())); - } - } +struct ListEntryDriver; +impl Driver for ListEntryDriver { + type Widget = ListEntry; + + fn make(&mut self, key: &usize) -> Self::Widget { + let n = *key; + ListEntry { + core: Default::default(), + label: Label::new(format!("Entry number {}", n + 1)), + radio: RadioButton::new_msg( + "display this entry", + move |_, data: &MyItem| data.0 == n, + move || Control::Select(n), + ), + edit: EditBox::new(ListEntryGuard(n)), } } + + fn navigable(_: &Self::Widget) -> bool { + false + } } #[derive(Default)] struct Generator; impl DataGenerator for Generator { - type Data = Data; + type Data = MyData; type Key = usize; - type Item = Item; + type Item = MyItem; fn update(&mut self, data: &Self::Data) -> GeneratorChanges { - // We assume that `Data::handle` has only been called once since this + // We assume that `MyData::handle` has only been called once since this // method was last called. data.last_change.clone() } @@ -171,7 +176,7 @@ impl DataGenerator for Generator { if data.row_limit { DataLen::Known(data.len) } else { - DataLen::LBound((data.active.max(data.last_string) + 1).max(lbound)) + DataLen::LBound((data.active.max(data.last_key) + 1).max(lbound)) } } @@ -184,29 +189,6 @@ impl DataGenerator for Generator { } } -struct MyDriver; -impl Driver for MyDriver { - type Widget = ListEntry; - - fn make(&mut self, key: &usize) -> Self::Widget { - let n = *key; - ListEntry { - core: Default::default(), - label: Label::new(format!("Entry number {}", n + 1)), - radio: RadioButton::new_msg( - "display this entry", - move |_, data: &Item| data.0 == n, - move || SelectEntry(n), - ), - edit: EditBox::new(ListEntryGuard(n)), - } - } - - fn navigable(_: &Self::Widget) -> bool { - false - } -} - fn main() -> kas::runner::Result<()> { env_logger::init(); @@ -223,21 +205,21 @@ fn main() -> kas::runner::Result<()> { .map_any(), ]; - let data = Data::new(false, 5); + let data = MyData::new(false, 5); let clerk = GeneratorClerk::new(Generator::default()); - let list = ListView::new(clerk, MyDriver).on_update(|cx, list, data: &Data| { + let list = ListView::new(clerk, ListEntryDriver).on_update(|cx, list, data: &MyData| { list.set_direction(cx, data.dir); }); let tree = column![ "Demonstration of dynamic widget creation / deletion", - CheckButton::new("Explicit row limit:", |_, data: &Data| data.row_limit) + CheckButton::new("Explicit row limit:", |_, data: &MyData| data.row_limit) .with_msg(Control::SetRowLimit), controls - .map(|data: &Data| &data.len) - .on_update(|cx, _, data: &Data| cx.set_disabled(!data.row_limit)), + .map(|data: &MyData| &data.len) + .on_update(|cx, _, data: &MyData| cx.set_disabled(!data.row_limit)), "Contents of selected entry:", - Text::new(|_, data: &Data| data.active_string.clone()), + Text::new(|_, data: &MyData| data.get_string(data.active)), Separator::new(), ScrollBars::new(list).with_fixed_bars(false, true), ];