Skip to content

Commit

Permalink
Implement disabled for druid controls (#1717)
Browse files Browse the repository at this point in the history
* - added LifeCycle::DisabledChanged and InternalLifeCycle::RouteDisabledChanged
 - implemented the disabled state in WidgetPod
 - changed call to focus_change from event to post event processing
 - implemented disabled handling in window.rs and core.rs

* created tests for disable

* fixed tests

* fixed tests

* updated core.rs and event.rs

* fixed focus-chain bug:
 - the focus chain was cleared, if the widget was disabled

* fix disabled update

* update tests

* fixed code (all tests succeed)

* refactored core.rs and tests/mod.rs

* updated tests

* fixed focus-chain bug

* make clippy happy
(i hope)

* make clippy happy #2

* Apply suggestions from code review

Update Documentation

Co-authored-by: Colin Rofls <colin@cmyr.net>

* Update druid/src/contexts.rs

Update documentation

Co-authored-by: Colin Rofls <colin@cmyr.net>

* refactor DisabledChanged

* refactor DisabledChanged

* fixed error, revered change of focus_chain

* refactored tests

* reordered lifecycle events

* reverted changes to the focus_chain

* implemented new focus-chain using LifeCycle::BuildFocusChain

* update tests

* fixed problems

* updated texts

* clippy fix

* fixed documentation

* Update druid/src/event.rs

Co-authored-by: Colin Rofls <colin@cmyr.net>

* fixed documentation

* made logic simpler

* refactored post_event_processing

* updated CHANGELOG.md

* fixed docs

* make clippy happy

* implemented DisabledIf

* reformat

* updated CHANGELOG.md

* fix issue

* updated example

Signed-off-by: xarvic <xarvix@web.de>

* added License, updated documentation

Signed-off-by: xarvic <xarvix@web.de>

* reformat

Signed-off-by: xarvic <xarvix@web.de>

* reformat

Signed-off-by: xarvic <xarvix@web.de>

* implement disabled state for button

Signed-off-by: xarvic <xarvix@web.de>

* updated visuals of controls when disabled

Signed-off-by: xarvic <xarvix@web.de>

* reformat

Signed-off-by: xarvic <xarvix@web.de>

* run clippy

Signed-off-by: xarvic <xarvix@web.de>

* run cargo fmt

Signed-off-by: xarvic <xarvix@web.de>

* Update CHANGELOG.md

* implemented disabled-text-color

Signed-off-by: xarvic <xarvix@web.de>

* changed background

Signed-off-by: xarvic <xarvix@web.de>

* reformat

Signed-off-by: xarvic <xarvix@web.de>

* Changed label.

Signed-off-by: xarvic <xarvix@web.de>

* added deprecation note

Signed-off-by: xarvic <xarvix@web.de>

Co-authored-by: xarvic <xarvix@web.de>
Co-authored-by: Colin Rofls <colin@cmyr.net>
  • Loading branch information
3 people committed May 3, 2021
1 parent 20f05cc commit 99a8d66
Show file tree
Hide file tree
Showing 20 changed files with 375 additions and 209 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ You can find its changes [documented below](#070---2021-01-01).
- Flex values that are less than 0.0 will default to 0.0 and warn in release. It will panic in debug mode. ([#1691] by [@arthmis])
- Lens implemented for tuples of Lenses of length 2-8, Tuple2 removed ([#1654] by [@Maan2003])
- Window size and positioning code is now in display points ([#1713] by [@jneem])
- Update look and feel of controls when disabled ([#1717] by [@xarvic])

### Deprecated

Expand Down Expand Up @@ -699,6 +700,7 @@ Last release without a changelog :(
[#1702]: https://github.com/linebender/druid/pull/1702
[#1713]: https://github.com/linebender/druid/pull/1713
[#1715]: https://github.com/linebender/druid/pull/1715
[#1717]: https://github.com/linebender/druid/pull/1717
[#1722]: https://github.com/linebender/druid/pull/1722
[#1724]: https://github.com/linebender/druid/pull/1724
[#1730]: https://github.com/linebender/druid/pull/1730
Expand Down
2 changes: 1 addition & 1 deletion docs/book_examples/src/env_md.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn make_labels() {
// ANCHOR: env_scope
fn scoped_label() {
let my_label = Label::<()>::new("Warning!").env_scope(|env, _| {
env.set(druid::theme::LABEL_COLOR, Color::BLACK);
env.set(druid::theme::TEXT_COLOR, Color::BLACK);
env.set(druid::theme::TEXT_SIZE_NORMAL, 18.0);
});
}
Expand Down
69 changes: 33 additions & 36 deletions druid/examples/disabled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,53 +42,50 @@ fn main_widget() -> impl Widget<AppData> {
Flex::column()
.with_child(named_child("text:", TextBox::new().lens(AppData::text)))
.with_default_spacer()
.with_child(named_child(
"text (disabled):",
TextBox::new()
.lens(AppData::text)
.with_child(
named_child("text (disabled):", TextBox::new().lens(AppData::text))
.disabled_if(|data, _| data.disabled),
))
)
.with_default_spacer()
.with_child(named_child("text:", TextBox::new().lens(AppData::text)))
.with_default_spacer()
.with_child(named_child(
"text (disabled):",
TextBox::new()
.lens(AppData::text)
.with_child(
named_child("text (disabled):", TextBox::new().lens(AppData::text))
.disabled_if(|data, _| data.disabled),
))
)
.with_default_spacer()
.with_default_spacer()
.with_child(named_child(
"value (disabled):",
Slider::new()
.with_range(0.0, 10.0)
.lens(AppData::value)
.disabled_if(|data, _| data.disabled),
))
.with_child(
named_child(
"value (disabled):",
Slider::new().with_range(0.0, 10.0).lens(AppData::value),
)
.disabled_if(|data, _| data.disabled),
)
.with_default_spacer()
.with_child(named_child(
"value (disabled):",
Stepper::new()
.with_range(0.0, 10.0)
.with_step(0.5)
.lens(AppData::value)
.disabled_if(|data, _| data.disabled),
))
.with_child(
named_child(
"value (disabled):",
Stepper::new()
.with_range(0.0, 10.0)
.with_step(0.5)
.lens(AppData::value),
)
.disabled_if(|data, _| data.disabled),
)
.with_default_spacer()
.with_child(named_child(
"option (disabled):",
Checkbox::new("option")
.lens(AppData::option)
.disabled_if(|data, _| data.disabled),
))
.with_child(
named_child(
"option (disabled):",
Checkbox::new("option").lens(AppData::option),
)
.disabled_if(|data, _| data.disabled),
)
.with_default_spacer()
.with_child(named_child(
"option (disabled):",
Switch::new()
.lens(AppData::option)
.with_child(
named_child("option (disabled):", Switch::new().lens(AppData::option))
.disabled_if(|data, _| data.disabled),
))
)
.with_default_spacer()
.with_child(
Flex::row()
Expand Down
2 changes: 1 addition & 1 deletion druid/examples/event_viewer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ pub fn main() {
.log_to_console()
.configure_env(|env, _| {
env.set(theme::UI_FONT, FontDescriptor::default().with_size(12.0));
env.set(theme::LABEL_COLOR, TEXT_COLOR);
env.set(theme::TEXT_COLOR, TEXT_COLOR);
env.set(theme::WIDGET_PADDING_HORIZONTAL, 2.0);
env.set(theme::WIDGET_PADDING_VERTICAL, 2.0);
})
Expand Down
2 changes: 1 addition & 1 deletion druid/examples/sub_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ impl<W: Widget<bool>> Controller<bool, W> for CancelClose {

fn build_root_widget() -> impl Widget<HelloState> {
let label = EnvScope::new(
|env, _t| env.set(theme::LABEL_COLOR, env.get(theme::PRIMARY_LIGHT)),
|env, _t| env.set(theme::TEXT_COLOR, env.get(theme::PRIMARY_LIGHT)),
ControllerHost::new(
Label::new(|data: &HelloState, _env: &Env| {
format!("Hello {}! {} ", data.name, data.sub.my_stuff)
Expand Down
45 changes: 30 additions & 15 deletions druid/src/text/input_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ impl<T: TextStorage + EditableText> Widget<T> for TextComponent<T> {
)]
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) {
match event {
Event::MouseDown(mouse) if self.can_write() => {
Event::MouseDown(mouse) if self.can_write() && !ctx.is_disabled() => {
ctx.set_active(true);
// ensure data is up to date before a click
let needs_rebuild = self
Expand All @@ -295,23 +295,26 @@ impl<T: TextStorage + EditableText> Widget<T> for TextComponent<T> {
ctx.request_paint();
}
Event::MouseMove(mouse) if self.can_write() => {
ctx.set_cursor(&Cursor::IBeam);
if ctx.is_active() {
let pre_sel = self.borrow().selection();
self.borrow_mut().do_drag(mouse.pos);
if self.borrow().selection() != pre_sel {
self.borrow_mut()
.update_pending_invalidation(ImeInvalidation::SelectionChanged);
ctx.request_update();
ctx.request_paint();
if !ctx.is_disabled() {
ctx.set_cursor(&Cursor::IBeam);
if ctx.is_active() {
let pre_sel = self.borrow().selection();
self.borrow_mut().do_drag(mouse.pos);
if self.borrow().selection() != pre_sel {
self.borrow_mut()
.update_pending_invalidation(ImeInvalidation::SelectionChanged);
ctx.request_update();
ctx.request_paint();
}
}
} else {
ctx.set_disabled(false);
ctx.clear_cursor();
}
}
Event::MouseUp(_) => {
if ctx.is_active() {
ctx.set_active(false);
ctx.request_paint();
}
Event::MouseUp(_) if ctx.is_active() => {
ctx.set_active(false);
ctx.request_paint();
}
Event::ImeStateChange => {
assert!(
Expand Down Expand Up @@ -380,6 +383,18 @@ impl<T: TextStorage + EditableText> Widget<T> for TextComponent<T> {
}
}
}
LifeCycle::DisabledChanged(disabled) => {
if self.can_write() {
let color = if *disabled {
env.get(theme::DISABLED_TEXT_COLOR)
} else {
env.get(theme::TEXT_COLOR)
};

self.borrow_mut().layout.set_text_color(color);
}
ctx.request_layout();
}
_ => (),
}
}
Expand Down
2 changes: 1 addition & 1 deletion druid/src/text/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl<T> TextLayout<T> {
TextLayout {
text: None,
font: crate::theme::UI_FONT.into(),
text_color: crate::theme::LABEL_COLOR.into(),
text_color: crate::theme::TEXT_COLOR.into(),
text_size_override: None,
layout: None,
wrap_width: f64::INFINITY,
Expand Down
21 changes: 19 additions & 2 deletions druid/src/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ use crate::{Env, FontDescriptor, FontFamily, FontStyle, FontWeight, Insets, Key}
pub const WINDOW_BACKGROUND_COLOR: Key<Color> =
Key::new("org.linebender.druid.theme.window_background_color");

pub const LABEL_COLOR: Key<Color> = Key::new("org.linebender.druid.theme.label_color");
#[deprecated(since = "0.8.0", note = "renamed to TEXT_COLOR")]
pub const LABEL_COLOR: Key<Color> = TEXT_COLOR;
pub const TEXT_COLOR: Key<Color> = Key::new("org.linebender.druid.theme.label_color");
pub const DISABLED_TEXT_COLOR: Key<Color> =
Key::new("org.linebender.druid.theme.disabled_label_color");
pub const PLACEHOLDER_COLOR: Key<Color> = Key::new("org.linebender.druid.theme.placeholder_color");

pub const PRIMARY_LIGHT: Key<Color> = Key::new("org.linebender.druid.theme.primary_light");
Expand All @@ -34,8 +38,16 @@ pub const BACKGROUND_LIGHT: Key<Color> = Key::new("org.linebender.druid.theme.ba
pub const BACKGROUND_DARK: Key<Color> = Key::new("org.linebender.druid.theme.background_dark");
pub const FOREGROUND_LIGHT: Key<Color> = Key::new("org.linebender.druid.theme.foreground_light");
pub const FOREGROUND_DARK: Key<Color> = Key::new("org.linebender.druid.theme.foreground_dark");
pub const DISABLED_FOREGROUND_LIGHT: Key<Color> =
Key::new("org.linebender.druid.theme.disabled_foreground_light");
pub const DISABLED_FOREGROUND_DARK: Key<Color> =
Key::new("org.linebender.druid.theme.disabled_foreground_dark");
pub const BUTTON_DARK: Key<Color> = Key::new("org.linebender.druid.theme.button_dark");
pub const BUTTON_LIGHT: Key<Color> = Key::new("org.linebender.druid.theme.button_light");
pub const DISABLED_BUTTON_DARK: Key<Color> =
Key::new("org.linebender.druid.theme.disabled_button_dark");
pub const DISABLED_BUTTON_LIGHT: Key<Color> =
Key::new("org.linebender.druid.theme.disabled_button_light");
pub const BUTTON_BORDER_RADIUS: Key<f64> = Key::new("org.linebender.druid.theme.button_radius");
pub const BUTTON_BORDER_WIDTH: Key<f64> =
Key::new("org.linebender.druid.theme.button_border_width");
Expand Down Expand Up @@ -107,7 +119,8 @@ pub const SCROLLBAR_MIN_SIZE: Key<f64> = Key::new("org.linebender.theme.scrollba
/// An initial theme.
pub(crate) fn add_to_env(env: Env) -> Env {
env.adding(WINDOW_BACKGROUND_COLOR, Color::rgb8(0x29, 0x29, 0x29))
.adding(LABEL_COLOR, Color::rgb8(0xf0, 0xf0, 0xea))
.adding(TEXT_COLOR, Color::rgb8(0xf0, 0xf0, 0xea))
.adding(DISABLED_TEXT_COLOR, Color::rgb8(0xa0, 0xa0, 0x9a))
.adding(PLACEHOLDER_COLOR, Color::rgb8(0x80, 0x80, 0x80))
.adding(PRIMARY_LIGHT, Color::rgb8(0x5c, 0xc4, 0xff))
.adding(PRIMARY_DARK, Color::rgb8(0x00, 0x8d, 0xdd))
Expand All @@ -116,8 +129,12 @@ pub(crate) fn add_to_env(env: Env) -> Env {
.adding(BACKGROUND_DARK, Color::rgb8(0x31, 0x31, 0x31))
.adding(FOREGROUND_LIGHT, Color::rgb8(0xf9, 0xf9, 0xf9))
.adding(FOREGROUND_DARK, Color::rgb8(0xbf, 0xbf, 0xbf))
.adding(DISABLED_FOREGROUND_LIGHT, Color::rgb8(0x89, 0x89, 0x89))
.adding(DISABLED_FOREGROUND_DARK, Color::rgb8(0x6f, 0x6f, 0x6f))
.adding(BUTTON_DARK, Color::BLACK)
.adding(BUTTON_LIGHT, Color::rgb8(0x21, 0x21, 0x21))
.adding(DISABLED_BUTTON_DARK, Color::grey8(0x28))
.adding(DISABLED_BUTTON_LIGHT, Color::grey8(0x38))
.adding(BUTTON_BORDER_RADIUS, 4.)
.adding(BUTTON_BORDER_WIDTH, 2.)
.adding(BORDER_DARK, Color::rgb8(0x3a, 0x3a, 0x3a))
Expand Down
29 changes: 20 additions & 9 deletions druid/src/widget/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,24 +115,26 @@ impl<T: Data> Widget<T> for Button<T> {
fn event(&mut self, ctx: &mut EventCtx, event: &Event, _data: &mut T, _env: &Env) {
match event {
Event::MouseDown(_) => {
ctx.set_active(true);
ctx.request_paint();
trace!("Button {:?} pressed", ctx.widget_id());
if !ctx.is_disabled() {
ctx.set_active(true);
ctx.request_paint();
trace!("Button {:?} pressed", ctx.widget_id());
}
}
Event::MouseUp(_) => {
if ctx.is_active() {
ctx.set_active(false);
if ctx.is_active() && !ctx.is_disabled() {
ctx.request_paint();
trace!("Button {:?} released", ctx.widget_id());
}
ctx.set_active(false);
}
_ => (),
}
}

#[instrument(name = "Button", level = "trace", skip(self, ctx, event, data, env))]
fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env) {
if let LifeCycle::HotChanged(_) = event {
if let LifeCycle::HotChanged(_) | LifeCycle::DisabledChanged(_) = event {
ctx.request_paint();
}
self.label.lifecycle(ctx, event, data, env)
Expand Down Expand Up @@ -165,7 +167,7 @@ impl<T: Data> Widget<T> for Button<T> {

#[instrument(name = "Button", level = "trace", skip(self, ctx, data, env))]
fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) {
let is_active = ctx.is_active();
let is_active = ctx.is_active() && !ctx.is_disabled();
let is_hot = ctx.is_hot();
let size = ctx.size();
let stroke_width = env.get(theme::BUTTON_BORDER_WIDTH);
Expand All @@ -175,7 +177,16 @@ impl<T: Data> Widget<T> for Button<T> {
.inset(-stroke_width / 2.0)
.to_rounded_rect(env.get(theme::BUTTON_BORDER_RADIUS));

let bg_gradient = if is_active {
let bg_gradient = if ctx.is_disabled() {
LinearGradient::new(
UnitPoint::TOP,
UnitPoint::BOTTOM,
(
env.get(theme::DISABLED_BUTTON_LIGHT),
env.get(theme::DISABLED_BUTTON_DARK),
),
)
} else if is_active {
LinearGradient::new(
UnitPoint::TOP,
UnitPoint::BOTTOM,
Expand All @@ -189,7 +200,7 @@ impl<T: Data> Widget<T> for Button<T> {
)
};

let border_color = if is_hot {
let border_color = if is_hot && !ctx.is_disabled() {
env.get(theme::BORDER_LIGHT)
} else {
env.get(theme::BORDER_DARK)
Expand Down
24 changes: 16 additions & 8 deletions druid/src/widget/checkbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ impl Widget<bool> for Checkbox {
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut bool, _env: &Env) {
match event {
Event::MouseDown(_) => {
ctx.set_active(true);
ctx.request_paint();
trace!("Checkbox {:?} pressed", ctx.widget_id());
if !ctx.is_disabled() {
ctx.set_active(true);
ctx.request_paint();
trace!("Checkbox {:?} pressed", ctx.widget_id());
}
}
Event::MouseUp(_) => {
if ctx.is_active() {
ctx.set_active(false);
if ctx.is_active() && !ctx.is_disabled() {
if ctx.is_hot() {
if *data {
*data = false;
Expand All @@ -62,6 +63,7 @@ impl Widget<bool> for Checkbox {
}
ctx.request_paint();
}
ctx.set_active(false);
}
_ => (),
}
Expand All @@ -70,7 +72,7 @@ impl Widget<bool> for Checkbox {
#[instrument(name = "CheckBox", level = "trace", skip(self, ctx, event, data, env))]
fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &bool, env: &Env) {
self.child_label.lifecycle(ctx, event, data, env);
if let LifeCycle::HotChanged(_) = event {
if let LifeCycle::HotChanged(_) | LifeCycle::DisabledChanged(_) = event {
ctx.request_paint();
}
}
Expand Down Expand Up @@ -126,7 +128,7 @@ impl Widget<bool> for Checkbox {

ctx.fill(rect, &background_gradient);

let border_color = if ctx.is_hot() {
let border_color = if ctx.is_hot() && !ctx.is_disabled() {
env.get(theme::BORDER_LIGHT)
} else {
env.get(theme::BORDER_DARK)
Expand All @@ -145,7 +147,13 @@ impl Widget<bool> for Checkbox {
.line_cap(LineCap::Round)
.line_join(LineJoin::Round);

ctx.stroke_styled(path, &env.get(theme::LABEL_COLOR), 2., &style);
let brush = if ctx.is_disabled() {
env.get(theme::DISABLED_TEXT_COLOR)
} else {
env.get(theme::TEXT_COLOR)
};

ctx.stroke_styled(path, &brush, 2., &style);
}

// Paint the text label
Expand Down
Loading

0 comments on commit 99a8d66

Please sign in to comment.