Skip to content

Commit 8886948

Browse files
authored
Merge pull request #28 from kas-gui/push-vqornvyrkusn
Add data-list-view
2 parents 85f3757 + 3204a3d commit 8886948

5 files changed

Lines changed: 460 additions & 26 deletions

File tree

examples/data-list-view.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
use kas::prelude::*;
2+
use kas::view::{DataGenerator, DataLen, GeneratorChanges, GeneratorClerk};
3+
use kas::view::{Driver, ListView};
4+
use kas::widgets::{column, *};
5+
use std::collections::HashMap;
6+
7+
#[derive(Clone, Debug)]
8+
enum Control {
9+
Select(usize),
10+
Update(usize, String),
11+
}
12+
13+
#[derive(Debug)]
14+
struct MyData {
15+
last_change: GeneratorChanges<usize>,
16+
last_key: usize,
17+
active: usize,
18+
strings: HashMap<usize, String>,
19+
}
20+
impl MyData {
21+
fn new() -> Self {
22+
MyData {
23+
last_change: GeneratorChanges::None,
24+
last_key: 0,
25+
active: 0,
26+
strings: HashMap::new(),
27+
}
28+
}
29+
fn get_string(&self, index: usize) -> String {
30+
self.strings
31+
.get(&index)
32+
.cloned()
33+
.unwrap_or_else(|| format!("Entry #{}", index + 1))
34+
}
35+
fn handle(&mut self, control: Control) {
36+
match control {
37+
Control::Select(index) => {
38+
self.last_change = GeneratorChanges::Any;
39+
self.active = index;
40+
}
41+
Control::Update(index, text) => {
42+
self.last_change = GeneratorChanges::Range(index..index + 1);
43+
self.last_key = self.last_key.max(index);
44+
self.strings.insert(index, text);
45+
}
46+
};
47+
}
48+
}
49+
50+
type MyItem = (usize, String); // (active index, entry's text)
51+
52+
#[derive(Debug)]
53+
struct ListEntryGuard(usize);
54+
impl EditGuard for ListEntryGuard {
55+
type Data = MyItem;
56+
57+
fn update(edit: &mut EditField<Self>, cx: &mut ConfigCx, data: &MyItem) {
58+
if !edit.has_edit_focus() {
59+
edit.set_string(cx, data.1.to_string());
60+
}
61+
}
62+
63+
fn activate(edit: &mut EditField<Self>, cx: &mut EventCx, _: &MyItem) -> IsUsed {
64+
cx.push(Control::Select(edit.guard.0));
65+
Used
66+
}
67+
68+
fn edit(edit: &mut EditField<Self>, cx: &mut EventCx, _: &MyItem) {
69+
cx.push(Control::Update(edit.guard.0, edit.clone_string()));
70+
}
71+
}
72+
73+
#[impl_self]
74+
mod ListEntry {
75+
// The list entry
76+
#[widget]
77+
#[layout(column! [
78+
row! [self.label, self.radio],
79+
self.edit,
80+
])]
81+
struct ListEntry {
82+
core: widget_core!(),
83+
#[widget(&())]
84+
label: Label<String>,
85+
#[widget]
86+
radio: RadioButton<MyItem>,
87+
#[widget]
88+
edit: EditBox<ListEntryGuard>,
89+
}
90+
91+
impl Events for Self {
92+
type Data = MyItem;
93+
}
94+
}
95+
96+
struct ListEntryDriver;
97+
impl Driver<usize, MyItem> for ListEntryDriver {
98+
type Widget = ListEntry;
99+
100+
fn make(&mut self, key: &usize) -> Self::Widget {
101+
let n = *key;
102+
ListEntry {
103+
core: Default::default(),
104+
label: Label::new(format!("Entry number {}", n + 1)),
105+
radio: RadioButton::new_msg(
106+
"display this entry",
107+
move |_, data: &MyItem| data.0 == n,
108+
move || Control::Select(n),
109+
),
110+
edit: EditBox::new(ListEntryGuard(n)).with_width_em(18.0, 30.0),
111+
}
112+
}
113+
114+
fn navigable(_: &Self::Widget) -> bool {
115+
false
116+
}
117+
}
118+
119+
#[derive(Default)]
120+
struct Generator;
121+
impl DataGenerator<usize> for Generator {
122+
type Data = MyData;
123+
type Key = usize;
124+
type Item = MyItem;
125+
126+
fn update(&mut self, data: &Self::Data) -> GeneratorChanges<usize> {
127+
// We assume that `MyData::handle` has only been called once since this
128+
// method was last called.
129+
data.last_change.clone()
130+
}
131+
132+
fn len(&self, data: &Self::Data, lbound: usize) -> DataLen<usize> {
133+
DataLen::LBound((data.active.max(data.last_key) + 1).max(lbound))
134+
}
135+
136+
fn key(&self, _: &Self::Data, index: usize) -> Option<Self::Key> {
137+
Some(index)
138+
}
139+
140+
fn generate(&self, data: &Self::Data, key: &usize) -> Self::Item {
141+
(data.active, data.get_string(*key))
142+
}
143+
}
144+
145+
fn main() -> kas::runner::Result<()> {
146+
env_logger::init();
147+
148+
let clerk = GeneratorClerk::new(Generator::default());
149+
let list = ListView::down(clerk, ListEntryDriver);
150+
let tree = column![
151+
"Contents of selected entry:",
152+
Text::new(|_, data: &MyData| data.get_string(data.active)),
153+
Separator::new(),
154+
ScrollBars::new(list).with_fixed_bars(false, true),
155+
];
156+
157+
let ui = tree
158+
.with_state(MyData::new())
159+
.on_message(|_, data, control| data.handle(control));
160+
161+
let window = Window::new(ui, "Data list view");
162+
163+
kas::runner::Runner::new(())?.with(window).run()
164+
}

src/SUMMARY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
- [Configuration](config.md)
88
- [Calculator: make_widget and grid](calculator.md)
99
- [Custom widgets](custom-widget.md)
10-
- [Data models](data-models.md)
10+
- [Data list view](data-list-view.md)

0 commit comments

Comments
 (0)