Skip to content

feat: add slider widget with horizontal and vertical support #853

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Cupnfish
Copy link
Contributor

  • Implement Slider widget with customizable colors, step size, and radii
  • Add horizontal and vertical axis support with proper coordinate handling
  • Include hover effects and accessibility features
  • Add comprehensive tests for interaction and rendering
  • Integrate slider into widget gallery example with direction switching
  • Add documentation and example usage
  • Fix edge cases for min/max values and step adjustments

There is still an issue where my tests are not outputting images for some reason. Can anyone help me with this?

- Implement Slider widget with customizable colors, step size, and radii
- Add horizontal and vertical axis support with proper coordinate handling
- Include hover effects and accessibility features
- Add comprehensive tests for interaction and rendering
- Integrate slider into widget gallery example with direction switching
- Add documentation and example usage
- Fix edge cases for min/max values and step adjustments
@Cupnfish Cupnfish marked this pull request as ready for review January 27, 2025 11:00
@Cupnfish
Copy link
Contributor Author

#819


#[must_use]
/// Set the callback for editing state changes.
pub fn on_editing_changed(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping to see some use case for this.
Also "editing state changes" is extremely vague terminology.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've not reviewed this code

Copy link
Contributor

@waywardmonkeys waywardmonkeys left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All that I have time for right now…

- Move slider-related constants from Slider impl to theme module
- Change color fields from Color to Brush type for better flexibility
- Rename color-related methods to thumb_color for clarity
- Remove macro-based property handling in favor of explicit updates
@DJMcNab DJMcNab requested a review from PoignardAzur March 17, 2025 09:04
Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to approve the Xilem side. I would still like some documentation for why you'd set on_editing_changed, but I won't block on it.

@PoignardAzur can you please review the Masonry/widget code?

Copy link
Contributor

@PoignardAzur PoignardAzur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code calculating the slider values and the tests checking that code are pretty intense, and I didn't inspect them in detail. I think it may be possible to write a simpler version of that code, but I won't block on that.

The Widget code itself seems mostly fine and idiomatic. I'm fine with merging it once the problems I've pointed out are fixed.

Comment on lines +1 to +2
// Copyright 2023 the Xilem Authors and the Druid Authors
// SPDX-License-Identifier: Apache-2.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Copyright 2023 the Xilem Authors and the Druid Authors
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0

Comment on lines +8 to +23
use vello::{
kurbo::{Affine, Point, Rect, RoundedRect, RoundedRectRadii, Shape as _, Size},
peniko::{Brush, Color},
Scene,
};

use crate::{
core::{
AccessCtx, AccessEvent, Action, BoxConstraints, EventCtx, LayoutCtx, PaintCtx,
PointerButton, PointerEvent, QueryCtx, RegisterCtx, TextEvent, Update, UpdateCtx, Widget,
WidgetId, WidgetMut,
},
theme,
};

use super::Axis;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: I'd rather this code follow the import conventions of other files. That is: no nested group imports, and no super:: imports.

Comment on lines +204 to +221
pub fn set_value(this: &mut WidgetMut<'_, Self>, value: f64) {
this.widget.value = value.clamp(this.widget.min, this.widget.max);
this.ctx.request_paint_only();
}

/// Sets the slider's minimum value.
pub fn set_min(this: &mut WidgetMut<'_, Self>, min: f64) {
this.widget.min = min;
this.widget.value = this.widget.value.clamp(this.widget.min, this.widget.max);
this.ctx.request_paint_only();
}

/// Sets the slider's maximum value.
pub fn set_max(this: &mut WidgetMut<'_, Self>, max: f64) {
this.widget.max = max;
this.widget.value = this.widget.value.clamp(this.widget.min, this.widget.max);
this.ctx.request_paint_only();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three setters affect the accessibility node, and should therefore call request_render(). Not sure about the others.

Comment on lines +299 to +300
self.is_dragging = true;
self.editing = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any difference between is_dragging and is_editing? They seem to be updated in tandem.


fn accessibility(&mut self, _ctx: &mut AccessCtx, node: &mut Node) {
node.set_value(self.value.to_string());
node.add_action(accesskit::Action::SetValue);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This action needs to be processed in on_access_event.

Comment on lines +443 to +451
if ctx.is_disabled() {
CursorIcon::Wait
} else if self.is_dragging {
CursorIcon::Grabbing
} else if self.is_hovered {
CursorIcon::Grab
} else {
CursorIcon::Default
}
Copy link
Contributor

@PoignardAzur PoignardAzur Mar 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC disabled widgets don't affect the cursor.

Also, if your get_cursor methods can return different values based on status, you should call request_cursor_icon_change when the status changes. (Otherwise, you may have cases where the icon doesn't change until the mouse moves.)

EDIT: Though honestly, we already trigger a pointer pass in most relevant cases, and we could generalize it to all pointer events. So I guess it's fine if you ignore this.

Comment on lines +485 to +492
#[test]
fn vertical_slider() {
let [slider_id] = widget_ids();
let slider = Slider::new(Axis::Vertical, 0.0, 100.0, 75.0).with_id(slider_id);

let mut harness = TestHarness::create_with_size(slider, Size::new(40.0, 200.0));
assert_render_snapshot!(harness, "vertical_slider");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's great that you added lots of screenshot tests, but the screenshots haven't been added to source control.

@DJMcNab DJMcNab mentioned this pull request Jun 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants