1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2019 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Demos basic list widget and list manipulations.
#[cfg(not(feature = "im"))]
pub fn main() {
eprintln!("This examples requires the \"im\" feature to be enabled:");
eprintln!("cargo run --example list --features im");
}
#[cfg(feature = "im")]
pub fn main() {
example::main()
}
#[cfg(feature = "im")]
mod example {
use druid::im::{vector, Vector};
use druid::lens::{self, LensExt};
use druid::widget::{Button, CrossAxisAlignment, Flex, Label, List, Scroll};
use druid::{
AppLauncher, Color, Data, Lens, LocalizedString, UnitPoint, Widget, WidgetExt, WindowDesc,
};
#[derive(Clone, Data, Lens)]
struct AppData {
left: Vector<u32>,
right: Vector<u32>,
}
pub fn main() {
let main_window = WindowDesc::new(ui_builder)
.title(LocalizedString::new("list-demo-window-title").with_placeholder("List Demo"));
// Set our initial data
let data = AppData {
left: vector![1, 2],
right: vector![1, 2, 3],
};
AppLauncher::with_window(main_window)
.use_simple_logger()
.launch(data)
.expect("launch failed");
}
fn ui_builder() -> impl Widget<AppData> {
let mut root = Flex::column();
// Build a button to add children to both lists
root.add_child(
Button::new("Add")
.on_click(|_, data: &mut AppData, _| {
// Add child to left list
let value = data.left.len() + 1;
data.left.push_back(value as u32);
// Add child to right list
let value = data.right.len() + 1;
data.right.push_back(value as u32);
})
.fix_height(30.0)
.expand_width(),
);
let mut lists = Flex::row().cross_axis_alignment(CrossAxisAlignment::Start);
// Build a simple list
lists.add_flex_child(
Scroll::new(List::new(|| {
Label::new(|item: &u32, _env: &_| format!("List item #{}", item))
.align_vertical(UnitPoint::LEFT)
.padding(10.0)
.expand()
.height(50.0)
.background(Color::rgb(0.5, 0.5, 0.5))
}))
.vertical()
.lens(AppData::left),
1.0,
);
// Build a list with shared data
lists.add_flex_child(
Scroll::new(List::new(|| {
Flex::row()
.with_child(
Label::new(|(_, item): &(Vector<u32>, u32), _env: &_| {
format!("List item #{}", item)
})
.align_vertical(UnitPoint::LEFT),
)
.with_flex_spacer(1.0)
.with_child(
Button::new("Delete")
.on_click(|_ctx, (shared, item): &mut (Vector<u32>, u32), _env| {
// We have access to both child's data and shared data.
// Remove element from right list.
shared.retain(|v| v != item);
})
.fix_size(80.0, 20.0)
.align_vertical(UnitPoint::CENTER),
)
.padding(10.0)
.background(Color::rgb(0.5, 0.0, 0.5))
.fix_height(50.0)
}))
.vertical()
.lens(lens::Id.map(
// Expose shared data with children data
|d: &AppData| (d.right.clone(), d.right.clone()),
|d: &mut AppData, x: (Vector<u32>, Vector<u32>)| {
// If shared data was changed reflect the changes in our AppData
d.right = x.0
},
)),
1.0,
);
root.add_flex_child(lists, 1.0);
// Mark the widget as needing its layout rects painted
root.debug_paint_layout()
}
}