CursorIcon + disabled refactoring

Input can now accept focus while disabled, and all controls should do
the right thing with regard to cursor icons now.
This commit is contained in:
Jonathan Johnson 2023-11-22 12:06:29 -08:00
parent 00cb29d261
commit 3e651c2964
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
11 changed files with 208 additions and 60 deletions

25
examples/cursor-icon.rs Normal file
View file

@ -0,0 +1,25 @@
use gooey::value::Dynamic;
use gooey::widget::MakeWidget;
use gooey::widgets::input::InputValue;
use gooey::widgets::Custom;
use gooey::Run;
use kludgine::app::winit::window::CursorIcon;
fn main() -> gooey::Result {
Custom::new(
"Try hovering the mouse cursor around this window"
.and(
Dynamic::new(String::from("Input fields show the text selection cursor"))
.into_input(),
)
.into_rows()
.pad()
.centered(),
)
.on_hover(|_location, _context| Some(CursorIcon::Help))
.on_hit_test(|_location, _context| true)
.contain()
.centered()
.expand()
.run()
}

View file

@ -17,7 +17,7 @@ fn main() -> gooey::Result {
.and("Allow Custom Widget to Lose Focus".into_checkbox(allow_blur.clone())) .and("Allow Custom Widget to Lose Focus".into_checkbox(allow_blur.clone()))
.and( .and(
Custom::empty() Custom::empty()
.on_accept_focus(|_| true) .on_accept_focus(|context| context.enabled())
.on_redraw(|context| { .on_redraw(|context| {
context.fill(context.theme().secondary.color); context.fill(context.theme().secondary.color);
if context.focused() { if context.focused() {

View file

@ -1,6 +1,7 @@
use gooey::animation::{LinearInterpolate, PercentBetween}; use gooey::animation::{LinearInterpolate, PercentBetween};
use gooey::value::{Dynamic, ForEach}; use gooey::value::{Dynamic, ForEach};
use gooey::widget::MakeWidget; use gooey::widget::MakeWidget;
use gooey::widgets::checkbox::Checkable;
use gooey::widgets::input::InputValue; use gooey::widgets::input::InputValue;
use gooey::widgets::slider::Slidable; use gooey::widgets::slider::Slidable;
use gooey::Run; use gooey::Run;
@ -8,10 +9,14 @@ use kludgine::figures::units::Lp;
use kludgine::figures::Ranged; use kludgine::figures::Ranged;
fn main() -> gooey::Result { fn main() -> gooey::Result {
let enabled = Dynamic::new(true);
u8_slider() u8_slider()
.and(u8_range_slider()) .and(u8_range_slider())
.and(enum_slider()) .and(enum_slider())
.into_rows() .into_rows()
.with_enabled(enabled.clone())
.and(enabled.into_checkbox("Enabled"))
.into_rows()
.expand_horizontally() .expand_horizontally()
.contain() .contain()
.width(..Lp::points(800)) .width(..Lp::points(800))

View file

@ -8,6 +8,7 @@ use kempt::Set;
use kludgine::app::winit::event::{ use kludgine::app::winit::event::{
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase, DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
}; };
use kludgine::app::winit::window::CursorIcon;
use kludgine::figures::units::{Lp, Px, UPx}; use kludgine::figures::units::{Lp, Px, UPx};
use kludgine::figures::{IntoSigned, Point, Px2D, Rect, Round, ScreenScale, Size, Zero}; use kludgine::figures::{IntoSigned, Point, Px2D, Rect, Round, ScreenScale, Size, Zero};
use kludgine::shapes::{Shape, StrokeOptions}; use kludgine::shapes::{Shape, StrokeOptions};
@ -163,10 +164,17 @@ impl<'context, 'window> EventContext<'context, 'window> {
let mut context = self.for_other(&unhovered); let mut context = self.for_other(&unhovered);
unhovered.lock().as_widget().unhover(&mut context); unhovered.lock().as_widget().unhover(&mut context);
} }
for hover in changes.hovered {
let mut cursor = None;
for hover in changes.hovered.into_iter().rev() {
let mut context = self.for_other(&hover); let mut context = self.for_other(&hover);
hover.lock().as_widget().hover(location, &mut context); let widget_cursor = hover.lock().as_widget().hover(location, &mut context);
if cursor.is_none() {
cursor = widget_cursor;
}
} }
self.winit().set_cursor_icon(cursor.unwrap_or_default());
} }
pub(crate) fn clear_hover(&mut self) { pub(crate) fn clear_hover(&mut self) {
@ -177,6 +185,8 @@ impl<'context, 'window> EventContext<'context, 'window> {
let mut old_hover_context = self.for_other(&old_hover); let mut old_hover_context = self.for_other(&old_hover);
old_hover.lock().as_widget().unhover(&mut old_hover_context); old_hover.lock().as_widget().unhover(&mut old_hover_context);
} }
self.winit().set_cursor_icon(CursorIcon::Default);
} }
fn apply_pending_activation(&mut self) { fn apply_pending_activation(&mut self) {
@ -227,14 +237,10 @@ impl<'context, 'window> EventContext<'context, 'window> {
fn apply_pending_focus(&mut self) { fn apply_pending_focus(&mut self) {
let mut focus_changes = 0; let mut focus_changes = 0;
while focus_changes < Self::MAX_PENDING_CHANGE_CYCLES { while focus_changes < Self::MAX_PENDING_CHANGE_CYCLES {
let focus = match self let focus = self
.pending_state .pending_state
.focus .focus
.and_then(|w| self.current_node.tree.widget(w)) .and_then(|w| self.current_node.tree.widget(w));
{
Some(focus) => self.for_other(&focus).enabled().then_some(focus),
None => None,
};
if self.current_node.tree.focused_widget() == focus.as_ref().map(|w| w.node_id) { if self.current_node.tree.focused_widget() == focus.as_ref().map(|w| w.node_id) {
break; break;
} }
@ -242,8 +248,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
self.pending_state.focus = focus.and_then(|mut focus| loop { self.pending_state.focus = focus.and_then(|mut focus| loop {
let mut focus_context = self.for_other(&focus); let mut focus_context = self.for_other(&focus);
let accept_focus = focus_context.enabled() let accept_focus = focus.lock().as_widget().accept_focus(&mut focus_context);
&& focus.lock().as_widget().accept_focus(&mut focus_context);
drop(focus_context); drop(focus_context);
if accept_focus { if accept_focus {
@ -402,8 +407,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
} }
let mut child_context = self.for_other(&child); let mut child_context = self.for_other(&child);
let accept_focus = child_context.enabled() let accept_focus = child.lock().as_widget().accept_focus(&mut child_context);
&& child.lock().as_widget().accept_focus(&mut child_context);
drop(child_context); drop(child_context);
if accept_focus { if accept_focus {
return Some(child.id()); return Some(child.id());

View file

@ -129,6 +129,8 @@ define_components! {
WidgetBackground(Color, "widget_backgrond_color", Color::CLEAR_WHITE) WidgetBackground(Color, "widget_backgrond_color", Color::CLEAR_WHITE)
/// A [`Color`] to be used to accent a widget. /// A [`Color`] to be used to accent a widget.
WidgetAccentColor(Color, "widget_accent_color", .primary.color) WidgetAccentColor(Color, "widget_accent_color", .primary.color)
/// A [`Color`] to be used to accent a disabled widget.
DisabledWidgetAccentColor(Color, "disabled_widget_accent_color", .primary.color_dim)
/// A [`Color`] to be used as an outline color. /// A [`Color`] to be used as an outline color.
OutlineColor(Color, "outline_color", .surface.outline) OutlineColor(Color, "outline_color", .surface.outline)
/// A [`Color`] to be used as an outline color. /// A [`Color`] to be used as an outline color.

View file

@ -12,6 +12,7 @@ use alot::LotId;
use kludgine::app::winit::event::{ use kludgine::app::winit::event::{
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase, DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
}; };
use kludgine::app::winit::window::CursorIcon;
use kludgine::figures::units::{Px, UPx}; use kludgine::figures::units::{Px, UPx};
use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, Size}; use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, Size};
use kludgine::Color; use kludgine::Color;
@ -68,7 +69,13 @@ pub trait Widget: Send + UnwindSafe + Debug + 'static {
/// The widget is currently has a cursor hovering it at `location`. /// The widget is currently has a cursor hovering it at `location`.
#[allow(unused_variables)] #[allow(unused_variables)]
fn hover(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) {} fn hover(
&mut self,
location: Point<Px>,
context: &mut EventContext<'_, '_>,
) -> Option<CursorIcon> {
None
}
/// The widget is no longer being hovered. /// The widget is no longer being hovered.
#[allow(unused_variables)] #[allow(unused_variables)]
@ -333,7 +340,13 @@ pub trait WrapperWidget: Debug + Send + UnwindSafe + 'static {
/// The widget is currently has a cursor hovering it at `location`. /// The widget is currently has a cursor hovering it at `location`.
#[allow(unused_variables)] #[allow(unused_variables)]
fn hover(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) {} fn hover(
&mut self,
location: Point<Px>,
context: &mut EventContext<'_, '_>,
) -> Option<CursorIcon> {
None
}
/// The widget is no longer being hovered. /// The widget is no longer being hovered.
#[allow(unused_variables)] #[allow(unused_variables)]
@ -500,8 +513,12 @@ where
T::hit_test(self, location, context) T::hit_test(self, location, context)
} }
fn hover(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) { fn hover(
T::hover(self, location, context); &mut self,
location: Point<Px>,
context: &mut EventContext<'_, '_>,
) -> Option<CursorIcon> {
T::hover(self, location, context)
} }
fn unhover(&mut self, context: &mut EventContext<'_, '_>) { fn unhover(&mut self, context: &mut EventContext<'_, '_>) {

View file

@ -3,6 +3,7 @@ use std::panic::UnwindSafe;
use std::time::Duration; use std::time::Duration;
use kludgine::app::winit::event::{DeviceId, ElementState, KeyEvent, MouseButton}; use kludgine::app::winit::event::{DeviceId, ElementState, KeyEvent, MouseButton};
use kludgine::app::winit::window::CursorIcon;
use kludgine::figures::units::{Lp, Px, UPx}; use kludgine::figures::units::{Lp, Px, UPx};
use kludgine::figures::{IntoSigned, Point, Rect, ScreenScale, Size}; use kludgine::figures::{IntoSigned, Point, Rect, ScreenScale, Size};
use kludgine::shapes::{Shape, StrokeOptions}; use kludgine::shapes::{Shape, StrokeOptions};
@ -383,7 +384,7 @@ impl Widget for Button {
} }
fn accept_focus(&mut self, context: &mut EventContext<'_, '_>) -> bool { fn accept_focus(&mut self, context: &mut EventContext<'_, '_>) -> bool {
context.get(&AutoFocusableControls).is_all() context.enabled() && context.get(&AutoFocusableControls).is_all()
} }
fn mouse_down( fn mouse_down(
@ -492,8 +493,18 @@ impl Widget for Button {
self.update_colors(context, false); self.update_colors(context, false);
} }
fn hover(&mut self, _location: Point<Px>, context: &mut EventContext<'_, '_>) { fn hover(
&mut self,
_location: Point<Px>,
context: &mut EventContext<'_, '_>,
) -> Option<CursorIcon> {
self.update_colors(context, false); self.update_colors(context, false);
if context.enabled() {
Some(CursorIcon::Pointer)
} else {
Some(CursorIcon::NotAllowed)
}
} }
fn focus(&mut self, context: &mut EventContext<'_, '_>) { fn focus(&mut self, context: &mut EventContext<'_, '_>) {

View file

@ -4,6 +4,7 @@ use std::panic::UnwindSafe;
use kludgine::app::winit::event::{ use kludgine::app::winit::event::{
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase, DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
}; };
use kludgine::app::winit::window::CursorIcon;
use kludgine::figures::units::Px; use kludgine::figures::units::Px;
use kludgine::figures::{Point, Size}; use kludgine::figures::{Point, Size};
use kludgine::Color; use kludgine::Color;
@ -36,7 +37,7 @@ pub struct Custom {
adjust_child: Option<Box<dyn AdjustChildConstraintsFunc>>, adjust_child: Option<Box<dyn AdjustChildConstraintsFunc>>,
position_child: Option<Box<dyn PositionChildFunc>>, position_child: Option<Box<dyn PositionChildFunc>>,
hit_test: Option<Box<dyn OneParamEventFunc<Point<Px>, bool>>>, hit_test: Option<Box<dyn OneParamEventFunc<Point<Px>, bool>>>,
hover: Option<Box<dyn OneParamEventFunc<Point<Px>>>>, hover: Option<Box<dyn OneParamEventFunc<Point<Px>, Option<CursorIcon>>>>,
mouse_down: mouse_down:
Option<Box<dyn ThreeParamEventFunc<Point<Px>, DeviceId, MouseButton, EventHandling>>>, Option<Box<dyn ThreeParamEventFunc<Point<Px>, DeviceId, MouseButton, EventHandling>>>,
mouse_drag: Option<Box<dyn ThreeParamEventFunc<Point<Px>, DeviceId, MouseButton>>>, mouse_drag: Option<Box<dyn ThreeParamEventFunc<Point<Px>, DeviceId, MouseButton>>>,
@ -366,7 +367,10 @@ impl Custom {
Hover: Send Hover: Send
+ UnwindSafe + UnwindSafe
+ 'static + 'static
+ for<'context, 'window> FnMut(Point<Px>, &mut EventContext<'context, 'window>), + for<'context, 'window> FnMut(
Point<Px>,
&mut EventContext<'context, 'window>,
) -> Option<CursorIcon>,
{ {
self.hover = Some(Box::new(hover)); self.hover = Some(Box::new(hover));
self self
@ -563,10 +567,13 @@ impl WrapperWidget for Custom {
} }
} }
fn hover(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) { fn hover(
if let Some(hover) = &mut self.hover { &mut self,
hover.invoke(location, context); location: Point<Px>,
} context: &mut EventContext<'_, '_>,
) -> Option<CursorIcon> {
let hover = self.hover.as_mut()?;
hover.invoke(location, context)
} }
fn unhover(&mut self, context: &mut EventContext<'_, '_>) { fn unhover(&mut self, context: &mut EventContext<'_, '_>) {

View file

@ -12,7 +12,7 @@ use std::time::Duration;
use intentional::Cast; use intentional::Cast;
use kludgine::app::winit::event::{ElementState, Ime, KeyEvent}; use kludgine::app::winit::event::{ElementState, Ime, KeyEvent};
use kludgine::app::winit::keyboard::{Key, NamedKey}; use kludgine::app::winit::keyboard::{Key, NamedKey};
use kludgine::app::winit::window::ImePurpose; use kludgine::app::winit::window::{CursorIcon, ImePurpose};
use kludgine::figures::units::{Lp, Px, UPx}; use kludgine::figures::units::{Lp, Px, UPx};
use kludgine::figures::{ use kludgine::figures::{
FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size, FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size,
@ -163,7 +163,11 @@ where
}); });
} }
fn forward_delete(&mut self) { fn forward_delete(&mut self, context: &mut EventContext<'_, '_>) {
if !context.enabled() {
return;
}
let (cursor, selection) = self.selected_range(); let (cursor, selection) = self.selected_range();
if let Some(selection) = selection { if let Some(selection) = selection {
self.replace_range(cursor, selection, ""); self.replace_range(cursor, selection, "");
@ -193,7 +197,11 @@ where
}); });
} }
fn delete(&mut self) { fn delete(&mut self, context: &mut EventContext<'_, '_>) {
if !context.enabled() {
return;
}
let (cursor, selection) = self.selected_range(); let (cursor, selection) = self.selected_range();
if let Some(selection) = selection { if let Some(selection) = selection {
self.replace_range(cursor, selection, ""); self.replace_range(cursor, selection, "");
@ -395,7 +403,11 @@ where
}); });
} }
fn replace_selection(&mut self, new_text: &str) { fn replace_selection(&mut self, new_text: &str, context: &mut EventContext<'_, '_>) {
if !context.enabled() {
return;
}
let selected_range = self.selected_range(); let selected_range = self.selected_range();
match selected_range { match selected_range {
(start, Some(end)) => { (start, Some(end)) => {
@ -415,12 +427,16 @@ where
} }
fn paste_from_clipboard(&mut self, context: &mut EventContext<'_, '_>) -> bool { fn paste_from_clipboard(&mut self, context: &mut EventContext<'_, '_>) -> bool {
if !context.enabled() {
return false;
}
match context match context
.clipboard_guard() .clipboard_guard()
.map(|mut clipboard| clipboard.get_text()) .map(|mut clipboard| clipboard.get_text())
{ {
Some(Ok(text)) => { Some(Ok(text)) => {
self.replace_selection(&text); self.replace_selection(&text, context);
true true
} }
None | Some(Err(arboard::Error::ConversionFailure)) => false, None | Some(Err(arboard::Error::ConversionFailure)) => false,
@ -435,8 +451,8 @@ where
match (input.state, input.logical_key, input.text.as_deref()) { match (input.state, input.logical_key, input.text.as_deref()) {
(ElementState::Pressed, Key::Named(key @ (NamedKey::Backspace| NamedKey::Delete)), _) => { (ElementState::Pressed, Key::Named(key @ (NamedKey::Backspace| NamedKey::Delete)), _) => {
match key { match key {
NamedKey::Backspace => self.delete(), NamedKey::Backspace => self.delete(context),
NamedKey::Delete => self.forward_delete(), NamedKey::Delete => self.forward_delete(context),
_ => unreachable!("previously matched"), _ => unreachable!("previously matched"),
} }
@ -505,7 +521,7 @@ where
=> =>
{ {
if state.is_pressed() { if state.is_pressed() {
self.replace_selection(text); self.replace_selection(text, context);
} }
HANDLED HANDLED
} }
@ -914,6 +930,14 @@ where
HANDLED HANDLED
} }
fn hover(
&mut self,
_location: Point<Px>,
_context: &mut EventContext<'_, '_>,
) -> Option<CursorIcon> {
Some(CursorIcon::Text)
}
fn mouse_drag( fn mouse_drag(
&mut self, &mut self,
location: Point<Px>, location: Point<Px>,
@ -963,6 +987,7 @@ where
} else { } else {
ImePurpose::Normal ImePurpose::Normal
}); });
if let Some(selection) = cache.selection { if let Some(selection) = cache.selection {
let (start, end) = if selection < cache.cursor { let (start, end) = if selection < cache.cursor {
(selection, cache.cursor) (selection, cache.cursor)
@ -1098,7 +1123,7 @@ where
tracing::warn!("TODO: preview IME input {text}, cursor: {cursor:?}"); tracing::warn!("TODO: preview IME input {text}, cursor: {cursor:?}");
} }
Ime::Commit(text) => { Ime::Commit(text) => {
self.replace_selection(&text); self.replace_selection(&text, context);
context.set_needs_redraw(); context.set_needs_redraw();
} }
} }

View file

@ -3,6 +3,7 @@ use std::time::Duration;
use intentional::Cast; use intentional::Cast;
use kludgine::app::winit::event::{DeviceId, MouseScrollDelta, TouchPhase}; use kludgine::app::winit::event::{DeviceId, MouseScrollDelta, TouchPhase};
use kludgine::app::winit::window::CursorIcon;
use kludgine::figures::units::{Lp, Px, UPx}; use kludgine::figures::units::{Lp, Px, UPx};
use kludgine::figures::{ use kludgine::figures::{
FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size, FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size,
@ -107,8 +108,14 @@ impl Widget for Scroll {
true true
} }
fn hover(&mut self, _location: Point<Px>, context: &mut EventContext<'_, '_>) { fn hover(
&mut self,
_location: Point<Px>,
context: &mut EventContext<'_, '_>,
) -> Option<CursorIcon> {
self.show_scrollbars(context); self.show_scrollbars(context);
None
} }
fn unhover(&mut self, context: &mut EventContext<'_, '_>) { fn unhover(&mut self, context: &mut EventContext<'_, '_>) {

View file

@ -7,6 +7,7 @@ use std::panic::UnwindSafe;
use intentional::{Assert, Cast as _}; use intentional::{Assert, Cast as _};
use kludgine::app::winit::event::{DeviceId, MouseButton, MouseScrollDelta, TouchPhase}; use kludgine::app::winit::event::{DeviceId, MouseButton, MouseScrollDelta, TouchPhase};
use kludgine::app::winit::keyboard::{Key, NamedKey}; use kludgine::app::winit::keyboard::{Key, NamedKey};
use kludgine::app::winit::window::CursorIcon;
use kludgine::figures::units::{Lp, Px, UPx}; use kludgine::figures::units::{Lp, Px, UPx};
use kludgine::figures::{ use kludgine::figures::{
FloatConversion, IntoSigned, Point, Ranged, Rect, Round, ScreenScale, Size, FloatConversion, IntoSigned, Point, Ranged, Rect, Round, ScreenScale, Size,
@ -17,7 +18,8 @@ use kludgine::{Color, DrawableExt, Origin};
use crate::animation::{LinearInterpolate, PercentBetween, ZeroToOne}; use crate::animation::{LinearInterpolate, PercentBetween, ZeroToOne};
use crate::context::{EventContext, GraphicsContext, LayoutContext}; use crate::context::{EventContext, GraphicsContext, LayoutContext};
use crate::styles::components::{ use crate::styles::components::{
AutoFocusableControls, OpaqueWidgetColor, OutlineColor, WidgetAccentColor, AutoFocusableControls, DisabledWidgetAccentColor, OpaqueWidgetColor, OutlineColor,
WidgetAccentColor,
}; };
use crate::styles::{Dimension, HorizontalOrder, VerticalOrder, VisualOrder}; use crate::styles::{Dimension, HorizontalOrder, VerticalOrder, VisualOrder};
use crate::value::{Dynamic, IntoDynamic, IntoValue, Value}; use crate::value::{Dynamic, IntoDynamic, IntoValue, Value};
@ -420,9 +422,19 @@ where
T: SliderValue, T: SliderValue,
{ {
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) { fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
let track_color = context.get(&TrackColor); let (track_color, inactive_track_color, knob_color) = if context.enabled() {
let inactive_track_color = context.get(&InactiveTrackColor); (
let knob_color = context.get(&KnobColor); context.get(&TrackColor),
context.get(&InactiveTrackColor),
context.get(&KnobColor),
)
} else {
(
context.get(&DisabledTrackColor),
context.get(&DisabledInactiveTrackColor),
context.get(&DisabledKnobColor),
)
};
let knob_size = self.knob_size.into_signed(); let knob_size = self.knob_size.into_signed();
let mut track_size = context.get(&TrackSize).into_px(context.gfx.scale()); let mut track_size = context.get(&TrackSize).into_px(context.gfx.scale());
if knob_size > 0 { if knob_size > 0 {
@ -548,8 +560,29 @@ where
self.interactive self.interactive
} }
fn hover(
&mut self,
_location: Point<Px>,
context: &mut EventContext<'_, '_>,
) -> Option<CursorIcon> {
(self.interactive && self.knob_visible).then_some({
if context.enabled() {
if self.mouse_buttons_down > 0 {
CursorIcon::Grabbing
} else {
CursorIcon::Grab
}
} else {
CursorIcon::NotAllowed
}
})
}
fn accept_focus(&mut self, context: &mut EventContext<'_, '_>) -> bool { fn accept_focus(&mut self, context: &mut EventContext<'_, '_>) -> bool {
self.interactive && self.knob_visible && context.get(&AutoFocusableControls).is_all() context.enabled()
&& self.interactive
&& self.knob_visible
&& context.get(&AutoFocusableControls).is_all()
} }
fn focus(&mut self, context: &mut EventContext<'_, '_>) { fn focus(&mut self, context: &mut EventContext<'_, '_>) {
@ -606,13 +639,15 @@ where
return IGNORED; return IGNORED;
}; };
let previous_focus = match (self.previous_focus.take(), self.focused_knob.take()) { if context.enabled() {
(None | Some(_), Some(focus)) | (Some(focus), None) => Some(focus), let previous_focus = match (self.previous_focus.take(), self.focused_knob.take()) {
(None, None) => None, (None | Some(_), Some(focus)) | (Some(focus), None) => Some(focus),
}; (None, None) => None,
self.update_from_click(location, previous_focus); };
self.update_from_click(location, previous_focus);
context.focus();
}
self.mouse_buttons_down += 1; self.mouse_buttons_down += 1;
context.focus();
HANDLED HANDLED
} }
@ -621,9 +656,11 @@ where
location: Point<Px>, location: Point<Px>,
_device_id: DeviceId, _device_id: DeviceId,
_button: MouseButton, _button: MouseButton,
_context: &mut EventContext<'_, '_>, context: &mut EventContext<'_, '_>,
) { ) {
self.update_from_click(location, None); if context.enabled() {
self.update_from_click(location, None);
}
} }
fn mouse_up( fn mouse_up(
@ -666,24 +703,26 @@ where
_device_id: DeviceId, _device_id: DeviceId,
delta: MouseScrollDelta, delta: MouseScrollDelta,
_phase: TouchPhase, _phase: TouchPhase,
_context: &mut EventContext<'_, '_>, context: &mut EventContext<'_, '_>,
) -> EventHandling { ) -> EventHandling {
let true = self.interactive else { let true = self.interactive else {
return IGNORED; return IGNORED;
}; };
let factor: f32 = match delta { if context.enabled() {
MouseScrollDelta::LineDelta(_, y) => y, let factor: f32 = match delta {
MouseScrollDelta::PixelDelta(pt) => pt.y.cast(), MouseScrollDelta::LineDelta(_, y) => y,
}; MouseScrollDelta::PixelDelta(pt) => pt.y.cast(),
};
let (forwards, factor) = if factor.is_sign_negative() { let (forwards, factor) = if factor.is_sign_negative() {
(false, -factor) (false, -factor)
} else { } else {
(true, factor) (true, factor)
}; };
self.step(forwards, factor); self.step(forwards, factor);
}
// @ecton: Unlike scroll alreas cascasing, I feel like scrolling while // @ecton: Unlike scroll alreas cascasing, I feel like scrolling while
// using a mouse wheel as an input is annoying. // using a mouse wheel as an input is annoying.
@ -726,10 +765,16 @@ define_components! {
MinimumSliderSize(Dimension, "minimum_size", |context| context.get(&KnobSize) * 2) MinimumSliderSize(Dimension, "minimum_size", |context| context.get(&KnobSize) * 2)
/// The color of the draggable portion of the knob. /// The color of the draggable portion of the knob.
KnobColor(Color, "knob_color", @WidgetAccentColor) KnobColor(Color, "knob_color", @WidgetAccentColor)
/// The color of the draggable portion of the knob.
DisabledKnobColor(Color, "disabled_knob_color", @DisabledWidgetAccentColor)
/// The color of the track that the knob rests on. /// The color of the track that the knob rests on.
TrackColor(Color,"track_color", |context| context.get(&KnobColor)) TrackColor(Color,"track_color", |context| context.get(&KnobColor))
/// The color of the track that the knob rests on. /// The color of the track that the knob rests on when the widget is disabled.
DisabledTrackColor(Color,"track_color", |context| context.get(&DisabledKnobColor))
/// The color of the track that the knob rests.
InactiveTrackColor(Color, "inactive_track_color", |context| context.get(&OpaqueWidgetColor)) InactiveTrackColor(Color, "inactive_track_color", |context| context.get(&OpaqueWidgetColor))
/// The color of the track that the knob rests.
DisabledInactiveTrackColor(Color, "disabled_inactive_track_color", |context| context.get(&OpaqueWidgetColor))
} }
} }