list/
list.rs

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