Skip to content

Commit b4be717

Browse files
authored
Merge pull request #29 from kas-gui/push-rvxupnyqrsql
Update tutorials for kas 0.17
2 parents 8886948 + efc5a47 commit b4be717

17 files changed

Lines changed: 245 additions & 182 deletions

.github/workflows/test.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ jobs:
2323
override: true
2424
components: rustfmt
2525
- name: Install dependencies
26-
run: sudo apt-get install -y libxkbcommon-dev libxcb-shape0-dev libxcb-xfixes0-dev
26+
run: |
27+
sudo apt-get update
28+
sudo apt-get install -y libfontconfig1-dev
2729
- name: Test examples
2830
run: |
2931
cargo fmt -- --check

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ publish = false
88

99
[dependencies]
1010
env_logger = "0.11"
11-
kas = "0.16"
12-
kas-wgpu = "0.16"
11+
kas = { version = "0.17.0", features = ["view"] }
12+
kas-wgpu = "0.17.1"

book.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
[book]
22
authors = ["Diggory Hardy"]
3-
multilingual = false
4-
src = "src"
53
title = "Kas Tutorials"

examples/calculator.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ use std::str::FromStr;
33

44
use kas::event::NamedKey;
55
use kas::prelude::*;
6-
use kas::widgets::{AccessLabel, Adapt, Button, EditBox, column, grid};
6+
use kas::theme::FrameStyle;
7+
use kas::widgets::{AccessLabel, Adapt, Button, EditBox, Frame, column, grid};
78

89
type Key = kas::event::Key<kas::event::SmolStr>;
910

1011
fn key_button(label: &str) -> Button<AccessLabel> {
1112
let string = AccessString::from(label);
12-
let key = string.key().unwrap().clone();
13+
let key = string.key().unwrap().0.clone();
1314
Button::label_msg(string, key)
1415
}
1516
fn key_button_with(label: &str, key: Key) -> Button<AccessLabel> {
@@ -21,9 +22,9 @@ fn calc_ui() -> Window<()> {
2122
let display = EditBox::string(|calc: &Calculator| calc.display())
2223
.with_multi_line(true)
2324
.with_lines(3.0, 3.0)
24-
.with_width_em(5.0, 10.0);
25+
.with_width_em(5.0, 10.0)
26+
.with_margin_style(kas::theme::MarginStyle::None);
2527

26-
// We use map_any to avoid passing input data (not wanted by buttons):
2728
let buttons = grid! {
2829
// Key bindings: C, Del
2930
(0, 0) => Button::label_msg("&clear", Key::Named(NamedKey::Clear))
@@ -37,18 +38,19 @@ fn calc_ui() -> Window<()> {
3738
(0, 1) => key_button("&7"),
3839
(1, 1) => key_button("&8"),
3940
(2, 1) => key_button("&9"),
40-
(3, 1..3) => key_button("&+"),
41+
(3, 1..=2) => key_button("&+"),
4142
(0, 2) => key_button("&4"),
4243
(1, 2) => key_button("&5"),
4344
(2, 2) => key_button("&6"),
4445
(0, 3) => key_button("&1"),
4546
(1, 3) => key_button("&2"),
4647
(2, 3) => key_button("&3"),
47-
(3, 3..5) => key_button_with("&=", NamedKey::Enter.into()),
48-
(0..2, 4) => key_button("&0"),
48+
(3, 3..=4) => key_button_with("&=", NamedKey::Enter.into()),
49+
(0..=1, 4) => key_button("&0"),
4950
(2, 4) => key_button("&."),
50-
}
51-
.map_any();
51+
};
52+
// We use map_any to avoid passing input data (not wanted by buttons):
53+
let buttons = Frame::new(buttons).with_style(FrameStyle::None).map_any();
5254

5355
let ui = Adapt::new(column![display, buttons], Calculator::new())
5456
.on_message(|_, calc, key| calc.handle(key));

examples/counter.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
use kas::prelude::*;
2-
use kas::widgets::{Button, column, format_value, row};
2+
use kas::widgets::{Button, column, format_label, row};
33

44
#[derive(Clone, Debug)]
55
struct Increment(i32);
66

77
fn counter() -> impl Widget<Data = ()> {
8-
let buttons = row![
9-
Button::label_msg("−", Increment(-1)),
10-
Button::label_msg("+", Increment(1)),
11-
];
128
let tree = column![
13-
format_value!("{}").align(AlignHints::CENTER),
14-
buttons.map_any(),
9+
format_label!("{}").align(AlignHints::CENTER),
10+
row![
11+
Button::label_msg("−", Increment(-1)),
12+
Button::label_msg("+", Increment(1)),
13+
]
14+
.map_any(),
1515
];
1616

1717
tree.with_state(0)

examples/custom-widget.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use kas::prelude::*;
2-
use kas::widgets::{AccessLabel, Button, Row, Text, format_value};
2+
use kas::widgets::{AccessLabel, Button, Row, Text, format_label};
33

44
#[derive(Clone, Debug)]
55
struct Increment(i32);
@@ -23,7 +23,7 @@ mod Counter {
2323
fn new(count: i32) -> Self {
2424
Counter {
2525
core: Default::default(),
26-
display: format_value!("{}"),
26+
display: format_label!("{}"),
2727
buttons: Row::new([
2828
Button::label_msg("-", Increment(-1)),
2929
Button::label_msg("+", Increment(1)),

examples/data-list-view.rs

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use kas::prelude::*;
2-
use kas::view::{DataGenerator, DataLen, GeneratorChanges, GeneratorClerk};
2+
use kas::view::clerk::{Clerk, GeneratorChanges, IndexedGenerator, Len};
33
use kas::view::{Driver, ListView};
4-
use kas::widgets::{column, *};
4+
use kas::widgets::edit::{EditBox, EditGuard, Editor};
5+
use kas::widgets::{Label, RadioButton, ScrollRegion, Separator, Text, column};
56
use std::collections::HashMap;
67

78
#[derive(Clone, Debug)]
@@ -43,7 +44,7 @@ impl MyData {
4344
self.last_key = self.last_key.max(index);
4445
self.strings.insert(index, text);
4546
}
46-
};
47+
}
4748
}
4849
}
4950

@@ -54,19 +55,17 @@ struct ListEntryGuard(usize);
5455
impl EditGuard for ListEntryGuard {
5556
type Data = MyItem;
5657

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-
}
58+
fn update(&mut self, edit: &mut Editor, cx: &mut ConfigCx, data: &MyItem) {
59+
edit.set_string(cx, data.1.to_string());
6160
}
6261

63-
fn activate(edit: &mut EditField<Self>, cx: &mut EventCx, _: &MyItem) -> IsUsed {
64-
cx.push(Control::Select(edit.guard.0));
62+
fn activate(&mut self, _: &mut Editor, cx: &mut EventCx, _: &MyItem) -> IsUsed {
63+
cx.push(Control::Select(self.0));
6564
Used
6665
}
6766

68-
fn edit(edit: &mut EditField<Self>, cx: &mut EventCx, _: &MyItem) {
69-
cx.push(Control::Update(edit.guard.0, edit.clone_string()));
67+
fn edit(&mut self, edit: &mut Editor, cx: &mut EventCx, _: &MyItem) {
68+
cx.push(Control::Update(self.0, edit.clone_string()));
7069
}
7170
}
7271

@@ -95,6 +94,8 @@ mod ListEntry {
9594

9695
struct ListEntryDriver;
9796
impl Driver<usize, MyItem> for ListEntryDriver {
97+
const TAB_NAVIGABLE: bool = true;
98+
9899
type Widget = ListEntry;
99100

100101
fn make(&mut self, key: &usize) -> Self::Widget {
@@ -107,7 +108,7 @@ impl Driver<usize, MyItem> for ListEntryDriver {
107108
move |_, data: &MyItem| data.0 == n,
108109
move || Control::Select(n),
109110
),
110-
edit: EditBox::new(ListEntryGuard(n)).with_width_em(18.0, 30.0),
111+
edit: EditBox::new(ListEntryGuard(n)),
111112
}
112113
}
113114

@@ -118,40 +119,36 @@ impl Driver<usize, MyItem> for ListEntryDriver {
118119

119120
#[derive(Default)]
120121
struct Generator;
121-
impl DataGenerator<usize> for Generator {
122+
impl Clerk<usize> for Generator {
122123
type Data = MyData;
123-
type Key = usize;
124124
type Item = MyItem;
125125

126+
fn len(&self, data: &Self::Data, lbound: usize) -> Len<usize> {
127+
Len::LBound((data.active.max(data.last_key) + 1).max(lbound))
128+
}
129+
}
130+
impl IndexedGenerator<usize> for Generator {
126131
fn update(&mut self, data: &Self::Data) -> GeneratorChanges<usize> {
127132
// We assume that `MyData::handle` has only been called once since this
128133
// method was last called.
129134
data.last_change.clone()
130135
}
131136

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))
137+
fn generate(&self, data: &Self::Data, index: usize) -> Self::Item {
138+
(data.active, data.get_string(index))
142139
}
143140
}
144141

145142
fn main() -> kas::runner::Result<()> {
146143
env_logger::init();
147144

148-
let clerk = GeneratorClerk::new(Generator::default());
145+
let clerk = Generator::default();
149146
let list = ListView::down(clerk, ListEntryDriver);
150147
let tree = column![
151148
"Contents of selected entry:",
152-
Text::new(|_, data: &MyData| data.get_string(data.active)),
149+
Text::new_gen(|_, data: &MyData| data.get_string(data.active)),
153150
Separator::new(),
154-
ScrollBars::new(list).with_fixed_bars(false, true),
151+
ScrollRegion::new_viewport(list).with_fixed_bars(false, true),
155152
];
156153

157154
let ui = tree

examples/sync-counter.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use kas::widgets::{AdaptWidget, Button, Label, Slider, column, format_data, row};
1+
use kas::widgets::{AdaptWidget, Button, Label, Slider, column, format_label, row};
22
use kas::window::Window;
33

44
#[derive(Clone, Debug)]
@@ -7,7 +7,7 @@ struct Increment(i32);
77
#[derive(Clone, Copy, Debug)]
88
struct Count(i32);
99
impl kas::runner::AppData for Count {
10-
fn handle_messages(&mut self, messages: &mut kas::runner::MessageStack) {
10+
fn handle_message(&mut self, messages: &mut impl kas::runner::ReadMessage) {
1111
if let Some(Increment(add)) = messages.try_pop() {
1212
self.0 += add;
1313
}
@@ -24,8 +24,8 @@ fn counter(title: &str) -> Window<Count> {
2424

2525
let slider = Slider::right(1..=10, |_, data: &Data| data.1).with_msg(SetValue);
2626
let ui = column![
27-
format_data!(data: &Data, "Count: {}", data.0.0),
28-
row![slider, format_data!(data: &Data, "{}", data.1)],
27+
format_label!(data: &Data, "Count: {}", data.0.0),
28+
row![slider, format_label!(data: &Data, "{}", data.1)],
2929
row![
3030
Button::new(Label::new_any("Sub")).with(|cx, data: &Data| cx.push(Increment(-data.1))),
3131
Button::new(Label::new_any("Add")).with(|cx, data: &Data| cx.push(Increment(data.1))),
@@ -34,7 +34,7 @@ fn counter(title: &str) -> Window<Count> {
3434

3535
let ui = ui
3636
.with_state(initial)
37-
.on_update(|_, state, count| state.0 = *count)
37+
.on_update(|_, _, state, count| state.0 = *count)
3838
.on_message(|_, state, SetValue(v)| state.1 = v);
3939
Window::new(ui, title).escapable()
4040
}

src/calculator.md

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@
55
![Calculator](screenshots/calculator.png)
66

77
```rust
8-
# extern crate kas;
98
use std::num::ParseFloatError;
109
use std::str::FromStr;
1110

1211
use kas::event::NamedKey;
1312
use kas::prelude::*;
14-
use kas::widgets::{AccessLabel, Adapt, Button, EditBox, column, grid};
13+
use kas::theme::FrameStyle;
14+
use kas::widgets::{AccessLabel, Adapt, Button, EditBox, Frame, column, grid};
1515

1616
type Key = kas::event::Key<kas::event::SmolStr>;
1717

1818
fn key_button(label: &str) -> Button<AccessLabel> {
1919
let string = AccessString::from(label);
20-
let key = string.key().unwrap().clone();
20+
let key = string.key().unwrap().0.clone();
2121
Button::label_msg(string, key)
2222
}
2323
fn key_button_with(label: &str, key: Key) -> Button<AccessLabel> {
@@ -29,7 +29,8 @@ fn calc_ui() -> Window<()> {
2929
let display = EditBox::string(|calc: &Calculator| calc.display())
3030
.with_multi_line(true)
3131
.with_lines(3.0, 3.0)
32-
.with_width_em(5.0, 10.0);
32+
.with_width_em(5.0, 10.0)
33+
.with_margin_style(kas::theme::MarginStyle::None);
3334

3435
let buttons = grid! {
3536
// Key bindings: C, Del
@@ -44,18 +45,19 @@ fn calc_ui() -> Window<()> {
4445
(0, 1) => key_button("&7"),
4546
(1, 1) => key_button("&8"),
4647
(2, 1) => key_button("&9"),
47-
(3, 1..3) => key_button("&+"),
48+
(3, 1..=2) => key_button("&+"),
4849
(0, 2) => key_button("&4"),
4950
(1, 2) => key_button("&5"),
5051
(2, 2) => key_button("&6"),
5152
(0, 3) => key_button("&1"),
5253
(1, 3) => key_button("&2"),
5354
(2, 3) => key_button("&3"),
54-
(3, 3..5) => key_button_with("&=", NamedKey::Enter.into()),
55-
(0..2, 4) => key_button("&0"),
55+
(3, 3..=4) => key_button_with("&=", NamedKey::Enter.into()),
56+
(0..=1, 4) => key_button("&0"),
5657
(2, 4) => key_button("&."),
57-
}
58-
.map_any();
58+
};
59+
// We use map_any to avoid passing input data (not wanted by buttons):
60+
let buttons = Frame::new(buttons).with_style(FrameStyle::None).map_any();
5961

6062
let ui = Adapt::new(column![display, buttons], Calculator::new())
6163
.on_message(|_, calc, key| calc.handle(key));
@@ -123,7 +125,6 @@ To make the calculator keyboard-accessible, we'll use *access keys* (see more on
123125

124126
To make constructing buttons easier, we define some helper functions. (These facilitate defining the button *message* more than they do the *access keys*.)
125127
```rust
126-
# extern crate kas;
127128
# use kas::text::AccessString;
128129
# use kas::widgets::{AccessLabel, Button};
129130
# type Key = kas::event::Key<kas::event::SmolStr>;
@@ -141,7 +142,6 @@ fn key_button_with(label: &str, key: Key) -> Button<AccessLabel> {
141142

142143
Normally, access keys are only active while holding <kbd>Alt</kbd>. To avoid this requirement we call [`with_alt_bypass`]. Further, we disable <kbd>Tab</kbd> key navigation with [`without_nav_focus`] and ensure that the window can be closed with the <kbd>Esc</kbd> key.
143144
```rust
144-
# extern crate kas;
145145
# use kas::{Widget, widgets::{Label, Adapt}, window::Window};
146146
# #[derive(Debug)]
147147
# struct Calculator;
@@ -163,10 +163,10 @@ Normally, access keys are only active while holding <kbd>Alt</kbd>. To avoid thi
163163

164164
We already saw column and row layouts. This time, we'll use [`grid!`] for layout.
165165
```rust
166-
# extern crate kas;
167166
# use kas::event::NamedKey;
168167
# use kas::prelude::*;
169-
# use kas::widgets::{AccessLabel, Button, grid};
168+
# use kas::widgets::{AccessLabel, Button, Frame, grid};
169+
# use kas::theme::FrameStyle;
170170
# type Key = kas::event::Key<kas::event::SmolStr>;
171171
# fn key_button(label: &str) -> Button<AccessLabel> {
172172
# let string = AccessString::from(label);
@@ -190,18 +190,19 @@ We already saw column and row layouts. This time, we'll use [`grid!`] for layout
190190
(0, 1) => key_button("&7"),
191191
(1, 1) => key_button("&8"),
192192
(2, 1) => key_button("&9"),
193-
(3, 1..3) => key_button("&+"),
193+
(3, 1..=2) => key_button("&+"),
194194
(0, 2) => key_button("&4"),
195195
(1, 2) => key_button("&5"),
196196
(2, 2) => key_button("&6"),
197197
(0, 3) => key_button("&1"),
198198
(1, 3) => key_button("&2"),
199199
(2, 3) => key_button("&3"),
200-
(3, 3..5) => key_button_with("&=", NamedKey::Enter.into()),
201-
(0..2, 4) => key_button("&0"),
200+
(3, 3..=4) => key_button_with("&=", NamedKey::Enter.into()),
201+
(0..=1, 4) => key_button("&0"),
202202
(2, 4) => key_button("&."),
203-
}
204-
.map_any();
203+
};
204+
// We use map_any to avoid passing input data (not wanted by buttons):
205+
let buttons = Frame::new(buttons).with_style(FrameStyle::None).map_any();
205206
# buttons
206207
# }
207208
```

0 commit comments

Comments
 (0)