Skip to content

Commit fa3da15

Browse files
authored
Merge pull request #18 from kas-gui/work
Update to v0.14
2 parents 015c08d + a7223d6 commit fa3da15

20 files changed

+689
-783
lines changed

Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
[package]
2-
name = "KAS-tutorials"
2+
name = "kas-tutorials"
33
version = "0.1.0"
44
authors = ["Diggory Hardy <[email protected]>"]
5-
edition = "2018"
5+
edition = "2021"
66
resolver = "2"
77
publish = false
88

99
[dependencies]
1010
env_logger = "0.10"
11-
kas = "0.13.0"
11+
kas = "0.14.2"
12+
kas-wgpu = "0.14.1"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KAS Tutorials
1+
Kas Tutorials
22
==========
33

44
Read here: <https://kas-gui.github.io/tutorials/>

book.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
authors = ["Diggory Hardy"]
33
multilingual = false
44
src = "src"
5-
title = "KAS tutorials"
5+
title = "Kas Tutorials"

examples/calculator.rs

Lines changed: 73 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,69 @@
1+
use kas::event::NamedKey;
2+
use kas::prelude::*;
3+
use kas::widgets::{AccessLabel, Adapt, Button, EditBox};
14
use std::num::ParseFloatError;
25
use std::str::FromStr;
36

4-
use kas::event::{Command, VirtualKeyCode as VK};
5-
use kas::prelude::*;
6-
use kas::widgets::{EditBox, TextButton};
7+
type Key = kas::event::Key<kas::event::SmolStr>;
78

8-
#[derive(Clone, Debug)]
9-
enum Key {
10-
Clear,
11-
DelBack,
12-
Divide,
13-
Multiply,
14-
Subtract,
15-
Add,
16-
Equals,
17-
Char(char),
9+
fn key_button(label: &str) -> Button<AccessLabel> {
10+
let string = AccessString::from(label);
11+
let key = string.key().unwrap().clone();
12+
Button::label_msg(string, key)
1813
}
19-
20-
impl_scope! {
21-
// Buttons get keyboard bindings through the "&" item (e.g. "&1"
22-
// binds both main and numpad 1 key) and via `with_keys`.
23-
#[widget{
24-
layout = grid: {
25-
0, 0: TextButton::new_msg("&clear", Key::Clear).with_keys(&[VK::Delete]);
26-
1, 0: TextButton::new_msg("&÷", Key::Divide).with_keys(&[VK::Slash]);
27-
2, 0: TextButton::new_msg("&×", Key::Multiply).with_keys(&[VK::Asterisk]);
28-
3, 0: TextButton::new_msg("&−", Key::Subtract);
29-
0, 1: TextButton::new_msg("&7", Key::Char('7'));
30-
1, 1: TextButton::new_msg("&8", Key::Char('8'));
31-
2, 1: TextButton::new_msg("&9", Key::Char('9'));
32-
3, 1..3: TextButton::new_msg("&+", Key::Add);
33-
0, 2: TextButton::new_msg("&4", Key::Char('4'));
34-
1, 2: TextButton::new_msg("&5", Key::Char('5'));
35-
2, 2: TextButton::new_msg("&6", Key::Char('6'));
36-
0, 3: TextButton::new_msg("&1", Key::Char('1'));
37-
1, 3: TextButton::new_msg("&2", Key::Char('2'));
38-
2, 3: TextButton::new_msg("&3", Key::Char('3'));
39-
3, 3..5: TextButton::new_msg("&=", Key::Equals)
40-
.with_keys(&[VK::Return, VK::NumpadEnter]);
41-
0..2, 4: TextButton::new_msg("&0", Key::Char('0'));
42-
2, 4: TextButton::new_msg("&.", Key::Char('.'));
43-
};
44-
}]
45-
#[derive(Debug, Default)]
46-
struct Buttons(widget_core!());
14+
fn key_button_with(label: &str, key: Key) -> Button<AccessLabel> {
15+
Button::label_msg(label, key.clone()).with_access_key(key)
4716
}
4817

49-
impl_scope! {
50-
#[impl_default]
51-
#[widget{
52-
layout = column: [
53-
self.display,
54-
Buttons::default(),
55-
];
56-
}]
57-
#[derive(Debug)]
58-
struct CalcUI {
59-
core: widget_core!(),
60-
#[widget] display: EditBox = EditBox::new("0")
61-
.with_editable(false)
62-
.with_multi_line(true)
63-
.with_lines(3, 3)
64-
.with_width_em(5.0, 10.0),
65-
calc: Calculator = Calculator::new(),
66-
}
67-
impl Widget for Self {
68-
fn configure(&mut self, mgr: &mut ConfigMgr) {
69-
mgr.disable_nav_focus(true);
70-
71-
// Enable key bindings without Alt held:
72-
mgr.enable_alt_bypass(self.id_ref(), true);
73-
74-
mgr.register_nav_fallback(self.id());
75-
}
76-
77-
fn handle_event(&mut self, mgr: &mut EventMgr, event: Event) -> Response {
78-
match event {
79-
Event::Command(Command::DelBack) => {
80-
if self.calc.handle(Key::DelBack) {
81-
*mgr |= self.display.set_string(self.calc.display());
82-
}
83-
Response::Used
84-
}
85-
_ => Response::Unused,
86-
}
87-
}
88-
89-
fn handle_message(&mut self, mgr: &mut EventMgr) {
90-
if let Some(msg) = mgr.try_pop::<Key>() {
91-
if self.calc.handle(msg) {
92-
*mgr |= self.display.set_string(self.calc.display());
93-
}
94-
}
95-
}
96-
}
97-
impl Window for Self {
98-
fn title(&self) -> &str { "Calculator" }
18+
fn calc_ui() -> impl Widget<Data = ()> {
19+
// We could use kas::widget::Text, but EditBox looks better.
20+
let display = EditBox::string(|calc: &Calculator| calc.display())
21+
.with_multi_line(true)
22+
.with_lines(3, 3)
23+
.with_width_em(5.0, 10.0);
24+
25+
// We use map_any to avoid passing input data (not wanted by buttons):
26+
let buttons = kas::grid! {
27+
// Key bindings: C, Del
28+
(0, 0) => Button::label_msg("&clear", Key::Named(NamedKey::Clear))
29+
.with_access_key(NamedKey::Delete.into()),
30+
// Widget is hidden but has key binding.
31+
// TODO(opt): exclude from layout & drawing.
32+
(0, 0) => key_button_with("", NamedKey::Backspace.into()),
33+
(1, 0) => key_button_with("&÷", Key::Character("/".into())),
34+
(2, 0) => key_button_with("&×", Key::Character("*".into())),
35+
(3, 0) => key_button_with("&−", Key::Character("-".into())),
36+
(0, 1) => key_button("&7"),
37+
(1, 1) => key_button("&8"),
38+
(2, 1) => key_button("&9"),
39+
(3, 1..3) => key_button("&+"),
40+
(0, 2) => key_button("&4"),
41+
(1, 2) => key_button("&5"),
42+
(2, 2) => key_button("&6"),
43+
(0, 3) => key_button("&1"),
44+
(1, 3) => key_button("&2"),
45+
(2, 3) => key_button("&3"),
46+
(3, 3..5) => key_button_with("&=", NamedKey::Enter.into()),
47+
(0..2, 4) => key_button("&0"),
48+
(2, 4) => key_button("&."),
9949
}
50+
.map_any();
51+
52+
Adapt::new(kas::column![display, buttons], Calculator::new())
53+
.on_message(|_, calc, key| calc.handle(key))
54+
.on_configure(|cx, _| {
55+
cx.disable_nav_focus(true);
56+
cx.enable_alt_bypass(true);
57+
})
10058
}
10159

102-
fn main() -> kas::shell::Result<()> {
60+
fn main() -> kas::app::Result<()> {
10361
env_logger::init();
10462

105-
let theme = kas::theme::SimpleTheme::new().with_font_size(16.0);
106-
kas::shell::DefaultShell::new(theme)?
107-
.with(CalcUI::default())?
63+
let theme = kas_wgpu::ShadedTheme::new().with_font_size(16.0);
64+
kas::app::Default::with_theme(theme)
65+
.build(())?
66+
.with(Window::new(calc_ui(), "Calculator"))
10867
.run()
10968
}
11069

@@ -136,7 +95,7 @@ impl Calculator {
13695
fn state_str(&self) -> String {
13796
match &self.state {
13897
Ok(x) => x.to_string(),
139-
Err(e) => format!("{}", e),
98+
Err(e) => format!("{e}"),
14099
}
141100
}
142101

@@ -151,32 +110,35 @@ impl Calculator {
151110
format!("{}\n{}\n{}", self.state_str(), op, &self.line_buf)
152111
}
153112

154-
// return true if display changes
155-
fn handle(&mut self, key: Key) -> bool {
113+
fn handle(&mut self, key: Key) {
156114
match key {
157-
Key::Clear => {
115+
Key::Named(NamedKey::Clear) | Key::Named(NamedKey::Delete) => {
158116
self.state = Ok(0.0);
159117
self.op = Op::None;
160118
self.line_buf.clear();
161-
true
162119
}
163-
Key::DelBack => self.line_buf.pop().is_some(),
164-
Key::Divide => self.do_op(Op::Divide),
165-
Key::Multiply => self.do_op(Op::Multiply),
166-
Key::Subtract => self.do_op(Op::Subtract),
167-
Key::Add => self.do_op(Op::Add),
168-
Key::Equals => self.do_op(Op::None),
169-
Key::Char(c) => {
170-
self.line_buf.push(c);
171-
true
120+
Key::Named(NamedKey::Backspace) => {
121+
self.line_buf.pop();
122+
}
123+
Key::Character(s) if s == "/" => self.do_op(Op::Divide),
124+
Key::Character(s) if s == "*" => self.do_op(Op::Multiply),
125+
Key::Character(s) if s == "-" => self.do_op(Op::Subtract),
126+
Key::Character(s) if s == "+" => self.do_op(Op::Add),
127+
Key::Named(NamedKey::Enter) => self.do_op(Op::None),
128+
Key::Character(s) if s.len() == 1 => {
129+
let c = s.chars().next().unwrap();
130+
if ('0'..='9').contains(&c) || c == '.' {
131+
self.line_buf.push(c);
132+
}
172133
}
134+
_ => (),
173135
}
174136
}
175137

176-
fn do_op(&mut self, next_op: Op) -> bool {
138+
fn do_op(&mut self, next_op: Op) {
177139
if self.line_buf.is_empty() {
178140
self.op = next_op;
179-
return true;
141+
return;
180142
}
181143

182144
let line = f64::from_str(&self.line_buf);
@@ -200,6 +162,5 @@ impl Calculator {
200162
}
201163

202164
self.op = next_op;
203-
true
204165
}
205166
}

examples/counter.rs

Lines changed: 17 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,28 @@
11
use kas::prelude::*;
2-
use kas::widgets::{Label, TextButton};
2+
use kas::widgets::{format_value, Adapt, Button};
33

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

7-
impl_scope! {
8-
#[widget{
9-
layout = column: [
10-
align(center): self.display,
11-
row: [
12-
TextButton::new_msg("−", Increment(-1)),
13-
TextButton::new_msg("+", Increment(1)),
14-
],
15-
];
16-
}]
17-
#[derive(Debug)]
18-
struct Counter {
19-
core: widget_core!(),
20-
#[widget] display: Label<String>,
21-
count: i32,
22-
}
23-
24-
impl Self {
25-
fn new(count: i32) -> Self {
26-
Counter {
27-
core: Default::default(),
28-
display: Label::from(count.to_string()),
29-
count,
30-
}
31-
}
32-
}
33-
34-
impl Widget for Self {
35-
fn handle_message(&mut self, mgr: &mut EventMgr) {
36-
if let Some(Increment(incr)) = mgr.try_pop() {
37-
self.count += incr;
38-
*mgr |= self.display.set_string(self.count.to_string());
39-
}
40-
}
41-
}
42-
43-
impl Window for Self {
44-
fn title(&self) -> &str { "Counter" }
45-
}
7+
fn counter() -> impl Widget<Data = ()> {
8+
let tree = kas::column![
9+
align!(center, format_value!("{}")),
10+
kas::row![
11+
Button::label_msg("−", Increment(-1)),
12+
Button::label_msg("+", Increment(1)),
13+
]
14+
.map_any(),
15+
];
16+
17+
Adapt::new(tree, 0).on_message(|_, count, Increment(add)| *count += add)
4618
}
4719

48-
fn main() -> kas::shell::Result<()> {
20+
fn main() -> kas::app::Result<()> {
4921
env_logger::init();
5022

5123
let theme = kas::theme::SimpleTheme::new().with_font_size(24.0);
52-
53-
let counter = Counter::new(0);
54-
kas::shell::DefaultShell::new(theme)?.with(counter)?.run()
24+
kas::app::Default::with_theme(theme)
25+
.build(())?
26+
.with(Window::new(counter(), "Counter"))
27+
.run()
5528
}

examples/hello.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use kas::widgets::dialog::MessageBox;
22

3-
fn main() -> Result<(), Box<dyn std::error::Error>> {
3+
fn main() -> kas::app::Result<()> {
44
env_logger::init();
55

6-
let window = MessageBox::new("Message", "Hello world");
6+
let window = MessageBox::new("Message").into_window("Hello world");
77

8-
let theme = kas::theme::FlatTheme::new();
9-
kas::shell::DefaultShell::new(theme)?.with(window)?.run()
8+
kas::app::Default::new(())?.with(window).run()
109
}

0 commit comments

Comments
 (0)