diff --git a/CHANGELOG.md b/CHANGELOG.md index 425e31cfcb..7a4af253ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ You can find its changes [documented below](#060---2020-06-01). - TextBox supports vertical movement ([#1280] by [@cmyr]) - Widgets can specify a baseline, flex rows can align baselines ([#1295] by [@cmyr]) - `TextBox::with_text_color` and `TextBox::set_text_color` ([#1320] by [@cmyr]) +- `Checkbox::set_text` to update the label. ([#1346] by [@finnerale]) ### Changed @@ -74,6 +75,7 @@ You can find its changes [documented below](#060---2020-06-01). - `LensWrap` widget moved into widget module ([#1251] by [@cmyr]) - `Delegate::command` now returns `Handled`, not `bool` ([#1298] by [@jneem]) - `TextBox` selects all contents when tabbed to on macOS ([#1283] by [@cmyr]) +- All Image formats are now optional, reducing compile time and binary size by default ([#1340] by [@JAicewizard]) ### Deprecated @@ -511,6 +513,7 @@ Last release without a changelog :( [#1311]: https://github.com/linebender/druid/pull/1311 [#1320]: https://github.com/linebender/druid/pull/1320 [#1326]: https://github.com/linebender/druid/pull/1326 +[#1346]: https://github.com/linebender/druid/pull/1346 [Unreleased]: https://github.com/linebender/druid/compare/v0.6.0...master [0.6.0]: https://github.com/linebender/druid/compare/v0.5.0...v0.6.0 diff --git a/druid-shell/Cargo.toml b/druid-shell/Cargo.toml index cf33b1c0ef..62f2386f25 100644 --- a/druid-shell/Cargo.toml +++ b/druid-shell/Cargo.toml @@ -18,6 +18,23 @@ default = ["gtk"] gtk = ["gio", "gdk", "gdk-sys", "glib", "glib-sys", "gtk-sys", "gtk-rs", "gdk-pixbuf"] x11 = ["x11rb", "nix", "cairo-sys-rs"] +# passing on all the image features. AVIF is not supported because it does not +# support decoding, and that's all we use `Image` for. +image_png = ["piet-common/image_png"] +jpeg = ["piet-common/jpeg"] +jpeg_rayon = ["piet-common/jpeg_rayon"] +gif = ["piet-common/gif"] +bmp = ["piet-common/bmp"] +ico = ["piet-common/ico"] +tiff = ["piet-common/tiff"] +webp = ["piet-common/webp"] +pnm = ["piet-common/pnm"] +dds = ["piet-common/dds"] +tga = ["piet-common/tga"] +farbfeld = ["piet-common/farbfeld"] +dxt = ["piet-common/dxt"] +hdr = ["piet-common/hdr"] + [dependencies] # NOTE: When changing the piet or kurbo versions, ensure that # the kurbo version included in piet is compatible with the kurbo version specified here. @@ -33,7 +50,7 @@ anyhow = "1.0.32" keyboard-types = { version = "0.5.0", default_features = false } # Optional dependencies -image = { version = "0.23.10", optional = true } +image = { version = "0.23.10", optional = true, default_features = false } [target.'cfg(target_os="windows")'.dependencies] scopeguard = "1.1.0" diff --git a/druid/Cargo.toml b/druid/Cargo.toml index dbe2f93fbd..42734e0d54 100644 --- a/druid/Cargo.toml +++ b/druid/Cargo.toml @@ -26,6 +26,23 @@ image = ["druid-shell/image"] svg = ["usvg", "harfbuzz-sys"] x11 = ["druid-shell/x11"] +# passing on all the image features. AVIF is not supported because it does not +# support decoding, and that's all we use `Image` for. +png = ["druid-shell/image_png"] +jpeg = ["druid-shell/jpeg"] +jpeg_rayon = ["druid-shell/jpeg_rayon"] +gif = ["druid-shell/gif"] +bmp = ["druid-shell/bmp"] +ico = ["druid-shell/ico"] +tiff = ["druid-shell/tiff"] +webp = ["druid-shell/webp"] +pnm = ["druid-shell/pnm"] +dds = ["druid-shell/dds"] +tga = ["druid-shell/tga"] +farbfeld = ["druid-shell/farbfeld"] +dxt = ["druid-shell/dxt"] +hdr = ["druid-shell/hdr"] + [dependencies] druid-shell = { version = "0.6.0", default-features = false, path = "../druid-shell" } druid-derive = { version = "0.3.1", path = "../druid-derive" } diff --git a/druid/examples/anim.rs b/druid/examples/anim.rs index 313e9325b5..21b0c8f4ab 100644 --- a/druid/examples/anim.rs +++ b/druid/examples/anim.rs @@ -12,7 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! An example of an animating widget. +//! An example of an animating widget. It is just a widget that +//! requests an animation frame when it needs to, and draws the frame in the +//! `paint` method. +//! Once the animation is over it simply stops requesting animation frames. +//! Usually we would put the state in the `Data`, but for things like animation +//! we don't. This is because the animation state is not useful to know for the +//! rest of the app. If this is something the rest of your widgets should know +//! about, you could put it in the `data`. use std::f64::consts::PI; @@ -24,8 +31,8 @@ struct AnimWidget { t: f64, } -impl Widget for AnimWidget { - fn event(&mut self, ctx: &mut EventCtx, event: &Event, _data: &mut u32, _env: &Env) { +impl Widget<()> for AnimWidget { + fn event(&mut self, ctx: &mut EventCtx, event: &Event, _data: &mut (), _env: &Env) { match event { Event::MouseDown(_) => { self.t = 0.0; @@ -36,27 +43,32 @@ impl Widget for AnimWidget { self.t += (*interval as f64) * 1e-9; if self.t < 1.0 { ctx.request_anim_frame(); + } else { + // We might have t>1.0 at the end of the animation, + // we want to make sure the line points up at the + // end of the animation. + self.t = 0.0; } } _ => (), } } - fn lifecycle(&mut self, _ctx: &mut LifeCycleCtx, _event: &LifeCycle, _data: &u32, _env: &Env) {} + fn lifecycle(&mut self, _ctx: &mut LifeCycleCtx, _event: &LifeCycle, _data: &(), _env: &Env) {} - fn update(&mut self, _ctx: &mut UpdateCtx, _old_data: &u32, _data: &u32, _env: &Env) {} + fn update(&mut self, _ctx: &mut UpdateCtx, _old_data: &(), _data: &(), _env: &Env) {} fn layout( &mut self, _layout_ctx: &mut LayoutCtx, bc: &BoxConstraints, - _data: &u32, + _data: &(), _env: &Env, ) -> Size { bc.constrain((100.0, 100.0)) } - fn paint(&mut self, ctx: &mut PaintCtx, _data: &u32, _env: &Env) { + fn paint(&mut self, ctx: &mut PaintCtx, _data: &(), _env: &Env) { let t = self.t; let center = Point::new(50.0, 50.0); ctx.paint_with_z_index(1, move |ctx| { @@ -75,6 +87,6 @@ pub fn main() { ); AppLauncher::with_window(window) .use_simple_logger() - .launch(0) + .launch(()) .expect("launch failed"); } diff --git a/druid/examples/blocking_function.rs b/druid/examples/blocking_function.rs index cb7abcac5d..52f47a9b58 100644 --- a/druid/examples/blocking_function.rs +++ b/druid/examples/blocking_function.rs @@ -12,45 +12,73 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! An example of a blocking function running in another thread. +//! An example of a blocking function running in another thread. We give +//! the other thread some data and then we also pass some data back +//! to the main thread using commands. use std::{thread, time}; +use druid::widget::prelude::*; +use druid::widget::{Button, Either, Flex, Label, Spinner}; use druid::{ - AppDelegate, AppLauncher, Command, Data, DelegateCtx, Env, ExtEventSink, Lens, LocalizedString, - Selector, Widget, WidgetExt, WindowDesc, -}; - -use druid::{ - widget::{Button, Either, Flex, Label, Spinner}, - Handled, Target, + AppDelegate, AppLauncher, Command, Data, DelegateCtx, ExtEventSink, Handled, Lens, + LocalizedString, Selector, Target, WidgetExt, WindowDesc, }; const FINISH_SLOW_FUNCTION: Selector = Selector::new("finish_slow_function"); -struct Delegate {} - #[derive(Clone, Default, Data, Lens)] struct AppState { processing: bool, value: u32, } -// Pretend this is downloading a file, or doing heavy calculations... -fn slow_function(number: u32) -> u32 { - let a_while = time::Duration::from_millis(2000); - thread::sleep(a_while); - number + 1 +fn ui_builder() -> impl Widget { + let button = Button::new("Start slow increment") + .on_click(|ctx, data: &mut AppState, _env| { + data.processing = true; + // In order to make sure that the other thread can communicate with the main thread we + // have to pass an external handle to the second thread. + // Using this handle we can send commands back to the main thread. + wrapped_slow_function(ctx.get_external_handle(), data.value); + }) + .padding(5.0); + + let button_placeholder = Flex::column() + .with_child(Label::new(LocalizedString::new("Processing...")).padding(5.0)) + .with_child(Spinner::new()); + + // Hello-counter is defined in the built-in localisation file. This maps to "Current value is {count}" + // localised in english, french, or german. Every time the value is updated it shows the new value. + let text = LocalizedString::new("hello-counter") + .with_arg("count", |data: &AppState, _env| (data.value).into()); + let label = Label::new(text).padding(5.0).center(); + + let either = Either::new(|data, _env| data.processing, button_placeholder, button); + + Flex::column().with_child(label).with_child(either) } fn wrapped_slow_function(sink: ExtEventSink, number: u32) { thread::spawn(move || { let number = slow_function(number); + // Once the slow function is done we can use the event sink (the external handle). + // This sends the `FINISH_SLOW_FUNCTION` command to the main thread and attach + // the number as payload. sink.submit_command(FINISH_SLOW_FUNCTION, number, Target::Auto) .expect("command failed to submit"); }); } +// Pretend this is downloading a file, or doing heavy calculations... +fn slow_function(number: u32) -> u32 { + let a_while = time::Duration::from_millis(2000); + thread::sleep(a_while); + number + 1 +} + +struct Delegate; + impl AppDelegate for Delegate { fn command( &mut self, @@ -61,6 +89,7 @@ impl AppDelegate for Delegate { _env: &Env, ) -> Handled { if let Some(number) = cmd.get(FINISH_SLOW_FUNCTION) { + // If the command we received is `FINISH_SLOW_FUNCTION` handle the payload. data.processing = false; data.value = *number; Handled::Yes @@ -70,31 +99,10 @@ impl AppDelegate for Delegate { } } -fn ui_builder() -> impl Widget { - let button = Button::new("Start slow increment") - .on_click(|ctx, data: &mut AppState, _env| { - data.processing = true; - wrapped_slow_function(ctx.get_external_handle(), data.value); - }) - .padding(5.0); - let button_placeholder = Flex::column() - .with_child(Label::new(LocalizedString::new("Processing...")).padding(5.0)) - .with_child(Spinner::new()); - - let text = LocalizedString::new("hello-counter") - .with_arg("count", |data: &AppState, _env| (data.value).into()); - let label = Label::new(text).padding(5.0).center(); - - let either = Either::new(|data, _env| data.processing, button_placeholder, button); - - Flex::column().with_child(label).with_child(either) -} fn main() { let main_window = WindowDesc::new(ui_builder).title(LocalizedString::new("Blocking functions")); - let app = AppLauncher::with_window(main_window); - let delegate = Delegate {}; - app.delegate(delegate) - .use_simple_logger() + AppLauncher::with_window(main_window) + .delegate(Delegate {}) .launch(AppState::default()) .expect("launch failed"); } diff --git a/druid/examples/identity.rs b/druid/examples/identity.rs index d90cec06d8..1faa6b9976 100644 --- a/druid/examples/identity.rs +++ b/druid/examples/identity.rs @@ -33,11 +33,10 @@ use instant::Instant; use std::time::Duration; use druid::kurbo::RoundedRect; +use druid::widget::prelude::*; use druid::widget::{Button, CrossAxisAlignment, Flex, WidgetId}; use druid::{ - AppLauncher, BoxConstraints, Color, Data, Env, Event, EventCtx, LayoutCtx, LifeCycle, - LifeCycleCtx, LocalizedString, PaintCtx, Rect, RenderContext, Selector, Size, TimerToken, - UpdateCtx, Widget, WidgetExt, WindowDesc, + AppLauncher, Color, Data, LocalizedString, Rect, Selector, TimerToken, WidgetExt, WindowDesc, }; const CYCLE_DURATION: Duration = Duration::from_millis(100); @@ -59,6 +58,7 @@ pub fn main() { color: Color::BLACK, }; AppLauncher::with_window(window) + .use_simple_logger() .launch(data) .expect("launch failed"); } diff --git a/druid/src/widget/checkbox.rs b/druid/src/widget/checkbox.rs index 09a6e91b19..757547a73b 100644 --- a/druid/src/widget/checkbox.rs +++ b/druid/src/widget/checkbox.rs @@ -25,12 +25,17 @@ pub struct Checkbox { } impl Checkbox { - /// Create a new `Checkbox` with a label. - pub fn new(label: impl Into>) -> Checkbox { + /// Create a new `Checkbox` with a text label. + pub fn new(text: impl Into>) -> Checkbox { Checkbox { - child_label: Label::new(label), + child_label: Label::new(text), } } + + /// Update the text label. + pub fn set_text(&mut self, label: impl Into>) { + self.child_label.set_text(label); + } } impl Widget for Checkbox {