Skip to content

Commit e171445

Browse files
Merge branch 'master' into ScrollComponent
2 parents 5f7c985 + 8cdb145 commit e171445

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2147
-704
lines changed

AUTHORS

+1
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ Kaur Kuut
1212
Leopold Luley
1313
Andrey Kabylin
1414
Garrett Risley
15+
Robert Wittams

CHANGELOG.md

+22-2
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,27 @@ You can find its changes [documented below](#060---2020-06-01).
99

1010
### Added
1111
- `OPEN_PANEL_CANCELLED` and `SAVE_PANEL_CANCELLED` commands. ([#1061] by @cmyr)
12-
1312
- Export `Image` and `ImageData` by default. ([#1011] by [@covercash2])
1413
- Re-export `druid_shell::Scalable` under `druid` namespace. ([#1075] by [@ForLoveOfCats])
1514
- `TextBox` now supports ctrl and shift hotkeys. ([#1076] by [@vkahl])
1615
- Added selection text color to textbox. ([#1093] by [@sysint64])
1716
- `ScrollComponent` for ease of adding consistent, customized, scrolling behavior to a widget. ([#1107] by [@ForLoveOfCats])
17+
- Selection text color to textbox. ([#1093] by [@sysint64])
18+
- `BoxConstraints::UNBOUNDED` constant. ([#1126] by [@danieldulaney])
19+
- Close requests from the shell can now be intercepted ([#1118] by [@jneem])
20+
- The Lens derive now supports an `ignore` attribute. ([#1133] by [@jneem])
21+
- `request_update` in `EventCtx`. ([#1128] by [@raphlinus])
22+
- `ExtEventSink`s can now be obtained from widget methods. ([#1152] by [@jneem])
23+
- 'Scope' widget to allow encapsulation of reactive state. ([#1151] by [@rjwittams])
1824

1925
### Changed
2026

2127
- `Scale::from_scale` to `Scale::new`, and `Scale` methods `scale_x` / `scale_y` to `x` / `y`. ([#1042] by [@xStrom])
2228
- Major rework of keyboard event handling. ([#1049] by [@raphlinus])
2329
- `Container::rounded` takes `KeyOrValue<f64>` instead of `f64`. ([#1054] by [@binomial0])
2430
- `List` handles its own scrolling on either the vertical or horizontal axis. ([#1107] by [@ForLoveOfCats])
31+
- `request_anim_frame` no longer invalidates the entire window. ([#1057] by [@jneem])
32+
- Use new Piet text api ([#1143] by [@cmyr])
2533

2634
### Deprecated
2735

@@ -47,7 +55,9 @@ You can find its changes [documented below](#060---2020-06-01).
4755
- `ViewSwitcher` now skips the update after switching widgets. ([#1113] by [@finnerale])
4856
- Key and KeyOrValue derive Clone ([#1119] by [@rjwittams])
4957
- Allow submit_command from the layout method in Widgets ([#1119] by [@rjwittams])
50-
- Allow derivation of lenses for generic types ([#1120]) by [@rjwittams])
58+
- Allow derivation of lenses for generic types ([#1120]) by [@rjwittams])
59+
- Switch widget: Toggle animation being window refresh rate dependent ([#1145] by [@ForLoveOfCats])
60+
- Multi-click on Windows, partial fix for #859 ([#1157] by [@raphlinus])
5161

5262
### Visual
5363

@@ -372,6 +382,7 @@ Last release without a changelog :(
372382
[#1049]: https://github.com/linebender/druid/pull/1049
373383
[#1050]: https://github.com/linebender/druid/pull/1050
374384
[#1054]: https://github.com/linebender/druid/pull/1054
385+
[#1057]: https://github.com/linebender/druid/pull/1057
375386
[#1058]: https://github.com/linebender/druid/pull/1058
376387
[#1061]: https://github.com/linebender/druid/pull/1061
377388
[#1062]: https://github.com/linebender/druid/pull/1062
@@ -385,8 +396,17 @@ Last release without a changelog :(
385396
[#1100]: https://github.com/linebender/druid/pull/1100
386397
[#1103]: https://github.com/linebender/druid/pull/1103
387398
[#1107]: https://github.com/linebender/druid/pull/1107
399+
[#1118]: https://github.com/linebender/druid/pull/1118
388400
[#1119]: https://github.com/linebender/druid/pull/1119
389401
[#1120]: https://github.com/linebender/druid/pull/1120
402+
[#1126]: https://github.com/linebender/druid/pull/1120
403+
[#1128]: https://github.com/linebender/druid/pull/1128
404+
[#1133]: https://github.com/linebender/druid/pull/1133
405+
[#1143]: https://github.com/linebender/druid/pull/1143
406+
[#1145]: https://github.com/linebender/druid/pull/1145
407+
[#1151]: https://github.com/linebender/druid/pull/1151
408+
[#1152]: https://github.com/linebender/druid/pull/1152
409+
[#1157]: https://github.com/linebender/druid/pull/1157
390410

391411
[Unreleased]: https://github.com/linebender/druid/compare/v0.6.0...master
392412
[0.6.0]: https://github.com/linebender/druid/compare/v0.5.0...v0.6.0

CONTRIBUTING.md

+36-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,40 @@ All submissions, including submissions by project members, require review. We
2020
use GitHub pull requests for this purpose. Consult [GitHub Help] for more
2121
information on using pull requests.
2222

23+
24+
## Before opening a PR
25+
26+
Testing a patch on github can take 15+ minutes, and you can save a lot of time by
27+
testing locally. We recommend using the following [git `pre-push` hook], by
28+
copying it to `druid/.git/hooks/pre-push`:
29+
30+
```sh
31+
#!/bin/sh
32+
33+
set -e
34+
35+
echo "cargo fmt"
36+
cargo fmt --all -- --check
37+
echo "cargo clippy druid-shell"
38+
cargo clippy --manifest-path=druid-shell/Cargo.toml --all-targets -- -D warnings
39+
echo "cargo clippy druid"
40+
cargo clippy --manifest-path=druid/Cargo.toml --all-targets --features=svg,image,im -- -D warnings
41+
echo "cargo clippy druid (wasm)"
42+
cargo clippy --manifest-path=druid/Cargo.toml --all-targets --features=image,im --target wasm32-unknown-unknown -- -D warnings
43+
echo "cargo clippy druid-derive"
44+
cargo clippy --manifest-path=druid-derive/Cargo.toml --all-targets -- -D warnings
45+
echo "cargo clippy book examples"
46+
cargo clippy --manifest-path=docs/book_examples/Cargo.toml --all-targets -- -D warnings
47+
echo "cargo test druid-shell"
48+
cargo test --manifest-path=druid-shell/Cargo.toml
49+
echo "cargo test druid"
50+
cargo test --manifest-path=druid/Cargo.toml --features=svg,image,im
51+
echo "cargo test druid-derive"
52+
cargo test --manifest-path=druid-derive/Cargo.toml
53+
echo "cargo test book examples"
54+
cargo test --manifest-path=docs/book_examples/Cargo.toml
55+
```
56+
2357
# How to maintain
2458

2559
## Preparing for a new release
@@ -134,4 +168,5 @@ plus how and if it makes sense to update to the newer version.
134168
[AUTHORS]: AUTHORS
135169
[changelog]: CHANGELOG.md
136170
[cargo-edit]: https://github.com/killercup/cargo-edit
137-
[semver]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
171+
[semver]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
172+
[git `pre-push` hook]: https://githooks.com

druid-derive/Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ rustdoc-args = ["--cfg", "docsrs"]
1515
default-target = "x86_64-pc-windows-msvc"
1616

1717
[dependencies]
18-
syn = "1.0.29"
19-
quote = "1.0.6"
20-
proc-macro2 = "1.0.17"
18+
syn = "1.0.38"
19+
quote = "1.0.7"
20+
proc-macro2 = "1.0.19"
2121

2222
[dev-dependencies]
2323
druid = { version = "0.6.0", path = "../druid" }

druid-derive/src/attr.rs

+94-24
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ const LENS_NAME_OVERRIDE_ATTR_PATH: &str = "name";
3030

3131
/// The fields for a struct or an enum variant.
3232
#[derive(Debug)]
33-
pub struct Fields {
33+
pub struct Fields<Attrs> {
3434
pub kind: FieldKind,
35-
fields: Vec<Field>,
35+
fields: Vec<Field<Attrs>>,
3636
}
3737

3838
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -60,18 +60,45 @@ impl FieldIdent {
6060
}
6161

6262
#[derive(Debug)]
63-
pub struct Field {
63+
pub struct Field<Attrs> {
6464
pub ident: FieldIdent,
6565
pub ty: syn::Type,
6666

67+
pub attrs: Attrs,
68+
}
69+
70+
#[derive(Debug)]
71+
pub struct DataAttrs {
6772
/// `true` if this field should be ignored.
6873
pub ignore: bool,
6974
pub same_fn: Option<ExprPath>,
75+
}
76+
77+
#[derive(Debug)]
78+
pub struct LensAttrs {
79+
/// `true` if this field should be ignored.
80+
pub ignore: bool,
7081
pub lens_name_override: Option<Ident>,
71-
//TODO: more attrs here
7282
}
7383

74-
impl Fields {
84+
impl Fields<DataAttrs> {
85+
pub fn parse_ast(fields: &syn::Fields) -> Result<Self, Error> {
86+
let kind = match fields {
87+
syn::Fields::Named(_) => FieldKind::Named,
88+
syn::Fields::Unnamed(_) | syn::Fields::Unit => FieldKind::Unnamed,
89+
};
90+
91+
let fields = fields
92+
.iter()
93+
.enumerate()
94+
.map(|(i, field)| Field::<DataAttrs>::parse_ast(field, i))
95+
.collect::<Result<Vec<_>, _>>()?;
96+
97+
Ok(Fields { kind, fields })
98+
}
99+
}
100+
101+
impl Fields<LensAttrs> {
75102
pub fn parse_ast(fields: &syn::Fields) -> Result<Self, Error> {
76103
let kind = match fields {
77104
syn::Fields::Named(_) => FieldKind::Named,
@@ -81,22 +108,24 @@ impl Fields {
81108
let fields = fields
82109
.iter()
83110
.enumerate()
84-
.map(|(i, field)| Field::parse_ast(field, i))
111+
.map(|(i, field)| Field::<LensAttrs>::parse_ast(field, i))
85112
.collect::<Result<Vec<_>, _>>()?;
86113

87114
Ok(Fields { kind, fields })
88115
}
116+
}
89117

118+
impl<Attrs> Fields<Attrs> {
90119
pub fn len(&self) -> usize {
91120
self.fields.len()
92121
}
93122

94-
pub fn iter(&self) -> impl Iterator<Item = &Field> {
123+
pub fn iter(&self) -> impl Iterator<Item = &Field<Attrs>> {
95124
self.fields.iter()
96125
}
97126
}
98127

99-
impl Field {
128+
impl Field<DataAttrs> {
100129
pub fn parse_ast(field: &syn::Field, index: usize) -> Result<Self, Error> {
101130
let ident = match field.ident.as_ref() {
102131
Some(ident) => FieldIdent::Named(ident.to_string().trim_start_matches("r#").to_owned()),
@@ -107,7 +136,6 @@ impl Field {
107136

108137
let mut ignore = false;
109138
let mut same_fn = None;
110-
let mut lens_name_override = None;
111139

112140
for attr in field.attrs.iter() {
113141
if attr.path.is_ident(BASE_DRUID_DEPRECATED_ATTR_PATH) {
@@ -152,11 +180,61 @@ impl Field {
152180
));
153181
}
154182
}
183+
}
184+
}
185+
Ok(Field {
186+
ident,
187+
ty,
188+
attrs: DataAttrs { ignore, same_fn },
189+
})
190+
}
191+
192+
/// The tokens to be used as the function for 'same'.
193+
pub fn same_fn_path_tokens(&self) -> TokenStream {
194+
match self.attrs.same_fn {
195+
Some(ref f) => quote!(#f),
196+
None => {
197+
let span = Span::call_site();
198+
quote_spanned!(span=> druid::Data::same)
199+
}
200+
}
201+
}
202+
}
203+
204+
impl Field<LensAttrs> {
205+
pub fn parse_ast(field: &syn::Field, index: usize) -> Result<Self, Error> {
206+
let ident = match field.ident.as_ref() {
207+
Some(ident) => FieldIdent::Named(ident.to_string().trim_start_matches("r#").to_owned()),
208+
None => FieldIdent::Unnamed(index),
209+
};
210+
211+
let ty = field.ty.clone();
212+
213+
let mut ignore = false;
214+
let mut lens_name_override = None;
215+
216+
for attr in field.attrs.iter() {
217+
if attr.path.is_ident(BASE_DRUID_DEPRECATED_ATTR_PATH) {
218+
panic!(
219+
"The 'druid' attribute has been replaced with separate \
220+
'lens' and 'data' attributes.",
221+
);
155222
} else if attr.path.is_ident(BASE_LENS_ATTR_PATH) {
156223
match attr.parse_meta()? {
157224
Meta::List(meta) => {
158225
for nested in meta.nested.iter() {
159226
match nested {
227+
NestedMeta::Meta(Meta::Path(path))
228+
if path.is_ident(IGNORE_ATTR_PATH) =>
229+
{
230+
if ignore {
231+
return Err(Error::new(
232+
nested.span(),
233+
"Duplicate attribute",
234+
));
235+
}
236+
ignore = true;
237+
}
160238
NestedMeta::Meta(Meta::NameValue(meta))
161239
if meta.path.is_ident(LENS_NAME_OVERRIDE_ATTR_PATH) =>
162240
{
@@ -174,7 +252,7 @@ impl Field {
174252
other => {
175253
return Err(Error::new(
176254
other.span(),
177-
"Expected attribute list (the form #[data(one, two)])",
255+
"Expected attribute list (the form #[lens(one, two)])",
178256
));
179257
}
180258
}
@@ -183,12 +261,15 @@ impl Field {
183261
Ok(Field {
184262
ident,
185263
ty,
186-
ignore,
187-
same_fn,
188-
lens_name_override,
264+
attrs: LensAttrs {
265+
ignore,
266+
lens_name_override,
267+
},
189268
})
190269
}
270+
}
191271

272+
impl<Attrs> Field<Attrs> {
192273
pub fn ident_tokens(&self) -> TokenTree {
193274
match self.ident {
194275
FieldIdent::Named(ref s) => Ident::new(&s, Span::call_site()).into(),
@@ -202,17 +283,6 @@ impl Field {
202283
FieldIdent::Unnamed(num) => num.to_string(),
203284
}
204285
}
205-
206-
/// The tokens to be used as the function for 'same'.
207-
pub fn same_fn_path_tokens(&self) -> TokenStream {
208-
match self.same_fn {
209-
Some(ref f) => quote!(#f),
210-
None => {
211-
let span = Span::call_site();
212-
quote_spanned!(span=> druid::Data::same)
213-
}
214-
}
215-
}
216286
}
217287

218288
fn parse_lit_into_expr_path(lit: &syn::Lit) -> Result<ExprPath, Error> {

druid-derive/src/data.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
//! The implementation for #[derive(Data)]
1616
17-
use crate::attr::{Field, FieldKind, Fields};
17+
use crate::attr::{DataAttrs, Field, FieldKind, Fields};
1818

1919
use quote::{quote, quote_spanned};
2020
use syn::{spanned::Spanned, Data, DataEnum, DataStruct};
@@ -40,14 +40,17 @@ fn derive_struct(
4040
let impl_generics = generics_bounds(&input.generics);
4141
let (_, ty_generics, where_clause) = &input.generics.split_for_impl();
4242

43-
let fields = Fields::parse_ast(&s.fields)?;
43+
let fields = Fields::<DataAttrs>::parse_ast(&s.fields)?;
4444

4545
let diff = if fields.len() > 0 {
4646
let same_fns = fields
4747
.iter()
48-
.filter(|f| !f.ignore)
48+
.filter(|f| !f.attrs.ignore)
4949
.map(Field::same_fn_path_tokens);
50-
let fields = fields.iter().filter(|f| !f.ignore).map(Field::ident_tokens);
50+
let fields = fields
51+
.iter()
52+
.filter(|f| !f.attrs.ignore)
53+
.map(Field::ident_tokens);
5154
quote!( #( #same_fns(&self.#fields, &other.#fields) )&&* )
5255
} else {
5356
quote!(true)
@@ -97,13 +100,13 @@ fn derive_enum(
97100
.variants
98101
.iter()
99102
.map(|variant| {
100-
let fields = Fields::parse_ast(&variant.fields)?;
103+
let fields = Fields::<DataAttrs>::parse_ast(&variant.fields)?;
101104
let variant = &variant.ident;
102105

103106
// the various inner `same()` calls, to the right of the match arm.
104107
let tests: Vec<_> = fields
105108
.iter()
106-
.filter(|field| !field.ignore)
109+
.filter(|field| !field.attrs.ignore)
107110
.map(|field| {
108111
let same_fn = field.same_fn_path_tokens();
109112
let var_left = ident_from_str(&format!("__self_{}", field.ident_string()));
@@ -145,7 +148,7 @@ fn derive_enum(
145148
.map(|field| ident_from_str(&format!("__other_{}", field.ident_string())))
146149
.collect();
147150

148-
if fields.iter().filter(|field| !field.ignore).count() > 0 {
151+
if fields.iter().count() > 0 {
149152
Ok(quote! {
150153
( #ident :: #variant( #(#vars_left),* ), #ident :: #variant( #(#vars_right),* )) => {
151154
#( #tests )&&*

0 commit comments

Comments
 (0)