implement vertical slider orientation (#875)
This commit is contained in:
parent
0bad1d0c99
commit
491739b580
2 changed files with 172 additions and 69 deletions
|
@ -32,7 +32,13 @@ struct SliderSpec {
|
||||||
largest_finite: f64,
|
largest_finite: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Control a number by a horizontal slider.
|
/// Specifies the orientation of a [`Slider`].
|
||||||
|
pub enum SliderOrientation {
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Control a number with a slider.
|
||||||
///
|
///
|
||||||
/// The slider range defines the values you get when pulling the slider to the far edges.
|
/// The slider range defines the values you get when pulling the slider to the far edges.
|
||||||
/// By default, the slider can still show values outside this range,
|
/// By default, the slider can still show values outside this range,
|
||||||
|
@ -41,7 +47,7 @@ struct SliderSpec {
|
||||||
///
|
///
|
||||||
/// The range can include any numbers, and go from low-to-high or from high-to-low.
|
/// The range can include any numbers, and go from low-to-high or from high-to-low.
|
||||||
///
|
///
|
||||||
/// The slider consists of three parts: a horizontal slider, a value display, and an optional text.
|
/// The slider consists of three parts: a slider, a value display, and an optional text.
|
||||||
/// The user can click the value display to edit its value. It can be turned off with `.show_value(false)`.
|
/// The user can click the value display to edit its value. It can be turned off with `.show_value(false)`.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -60,6 +66,7 @@ pub struct Slider<'a> {
|
||||||
clamp_to_range: bool,
|
clamp_to_range: bool,
|
||||||
smart_aim: bool,
|
smart_aim: bool,
|
||||||
show_value: bool,
|
show_value: bool,
|
||||||
|
orientation: SliderOrientation,
|
||||||
prefix: String,
|
prefix: String,
|
||||||
suffix: String,
|
suffix: String,
|
||||||
text: String,
|
text: String,
|
||||||
|
@ -69,6 +76,7 @@ pub struct Slider<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Slider<'a> {
|
impl<'a> Slider<'a> {
|
||||||
|
/// Creates a new horizontal slider.
|
||||||
pub fn new<Num: emath::Numeric>(value: &'a mut Num, range: RangeInclusive<Num>) -> Self {
|
pub fn new<Num: emath::Numeric>(value: &'a mut Num, range: RangeInclusive<Num>) -> Self {
|
||||||
let range_f64 = range.start().to_f64()..=range.end().to_f64();
|
let range_f64 = range.start().to_f64()..=range.end().to_f64();
|
||||||
let slf = Self::from_get_set(range_f64, move |v: Option<f64>| {
|
let slf = Self::from_get_set(range_f64, move |v: Option<f64>| {
|
||||||
|
@ -100,6 +108,7 @@ impl<'a> Slider<'a> {
|
||||||
clamp_to_range: true,
|
clamp_to_range: true,
|
||||||
smart_aim: true,
|
smart_aim: true,
|
||||||
show_value: true,
|
show_value: true,
|
||||||
|
orientation: SliderOrientation::Horizontal,
|
||||||
prefix: Default::default(),
|
prefix: Default::default(),
|
||||||
suffix: Default::default(),
|
suffix: Default::default(),
|
||||||
text: Default::default(),
|
text: Default::default(),
|
||||||
|
@ -109,7 +118,7 @@ impl<'a> Slider<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Control wether or not the slider shows the current value.
|
/// Control whether or not the slider shows the current value.
|
||||||
/// Default: `true`.
|
/// Default: `true`.
|
||||||
pub fn show_value(mut self, show_value: bool) -> Self {
|
pub fn show_value(mut self, show_value: bool) -> Self {
|
||||||
self.show_value = show_value;
|
self.show_value = show_value;
|
||||||
|
@ -139,6 +148,18 @@ impl<'a> Slider<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Vertical or horizontal slider? The default is horizontal.
|
||||||
|
pub fn orientation(mut self, orientation: SliderOrientation) -> Self {
|
||||||
|
self.orientation = orientation;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make this a vertical slider.
|
||||||
|
pub fn vertical(mut self) -> Self {
|
||||||
|
self.orientation = SliderOrientation::Vertical;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Make this a logarithmic slider.
|
/// Make this a logarithmic slider.
|
||||||
/// This is great for when the slider spans a huge range,
|
/// This is great for when the slider spans a huge range,
|
||||||
/// e.g. from one to a million.
|
/// e.g. from one to a million.
|
||||||
|
@ -249,49 +270,43 @@ impl<'a> Slider<'a> {
|
||||||
self.range.clone()
|
self.range.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For instance, `x` is the mouse position and `x_range` is the physical location of the slider on the screen.
|
/// For instance, `position` is the mouse position and `position_range` is the physical location of the slider on the screen.
|
||||||
fn value_from_x(&self, x: f32, x_range: RangeInclusive<f32>) -> f64 {
|
fn value_from_position(&self, position: f32, position_range: RangeInclusive<f32>) -> f64 {
|
||||||
let normalized = remap_clamp(x, x_range, 0.0..=1.0) as f64;
|
let normalized = remap_clamp(position, position_range, 0.0..=1.0) as f64;
|
||||||
value_from_normalized(normalized, self.range(), &self.spec)
|
value_from_normalized(normalized, self.range(), &self.spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn x_from_value(&self, value: f64, x_range: RangeInclusive<f32>) -> f32 {
|
fn position_from_value(&self, value: f64, position_range: RangeInclusive<f32>) -> f32 {
|
||||||
let normalized = normalized_from_value(value, self.range(), &self.spec);
|
let normalized = normalized_from_value(value, self.range(), &self.spec);
|
||||||
lerp(x_range, normalized as f32)
|
lerp(position_range, normalized as f32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_radius(rect: &Rect) -> f32 {
|
|
||||||
rect.height() / 2.5
|
|
||||||
}
|
|
||||||
|
|
||||||
fn x_range(rect: &Rect) -> RangeInclusive<f32> {
|
|
||||||
let handle_radius = handle_radius(rect);
|
|
||||||
(rect.left() + handle_radius)..=(rect.right() - handle_radius)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Slider<'a> {
|
impl<'a> Slider<'a> {
|
||||||
/// Just the slider, no text
|
/// Just the slider, no text
|
||||||
#[allow(clippy::unused_self)]
|
fn allocate_slider_space(&self, ui: &mut Ui, perpendicular: f32) -> Response {
|
||||||
fn allocate_slider_space(&self, ui: &mut Ui, height: f32) -> Response {
|
let desired_size = match self.orientation {
|
||||||
let desired_size = vec2(ui.spacing().slider_width, height);
|
SliderOrientation::Horizontal => vec2(ui.spacing().slider_width, perpendicular),
|
||||||
|
SliderOrientation::Vertical => vec2(perpendicular, ui.spacing().slider_width),
|
||||||
|
};
|
||||||
ui.allocate_response(desired_size, Sense::click_and_drag())
|
ui.allocate_response(desired_size, Sense::click_and_drag())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Just the slider, no text
|
/// Just the slider, no text
|
||||||
fn slider_ui(&mut self, ui: &mut Ui, response: &Response) {
|
fn slider_ui(&mut self, ui: &mut Ui, response: &Response) {
|
||||||
let rect = &response.rect;
|
let rect = &response.rect;
|
||||||
let x_range = x_range(rect);
|
let position_range = self.position_range(rect);
|
||||||
|
|
||||||
if let Some(pointer_pos) = response.interact_pointer_pos() {
|
if let Some(pointer_position_2d) = response.interact_pointer_pos() {
|
||||||
|
let position = self.pointer_position(pointer_position_2d);
|
||||||
let new_value = if self.smart_aim {
|
let new_value = if self.smart_aim {
|
||||||
let aim_radius = ui.input().aim_radius();
|
let aim_radius = ui.input().aim_radius();
|
||||||
emath::smart_aim::best_in_range_f64(
|
emath::smart_aim::best_in_range_f64(
|
||||||
self.value_from_x(pointer_pos.x - aim_radius, x_range.clone()),
|
self.value_from_position(position - aim_radius, position_range.clone()),
|
||||||
self.value_from_x(pointer_pos.x + aim_radius, x_range.clone()),
|
self.value_from_position(position + aim_radius, position_range.clone()),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.value_from_x(pointer_pos.x, x_range.clone())
|
self.value_from_position(position, position_range.clone())
|
||||||
};
|
};
|
||||||
self.set_value(new_value);
|
self.set_value(new_value);
|
||||||
}
|
}
|
||||||
|
@ -300,21 +315,22 @@ impl<'a> Slider<'a> {
|
||||||
response.widget_info(|| WidgetInfo::slider(value, &self.text));
|
response.widget_info(|| WidgetInfo::slider(value, &self.text));
|
||||||
|
|
||||||
if response.has_focus() {
|
if response.has_focus() {
|
||||||
let kb_step = ui.input().num_presses(Key::ArrowRight) as f32
|
let increment = ui.input().num_presses(self.key_increment());
|
||||||
- ui.input().num_presses(Key::ArrowLeft) as f32;
|
let decrement = ui.input().num_presses(self.key_decrement());
|
||||||
|
let kb_step = increment as f32 - decrement as f32;
|
||||||
|
|
||||||
if kb_step != 0.0 {
|
if kb_step != 0.0 {
|
||||||
let prev_value = self.get_value();
|
let prev_value = self.get_value();
|
||||||
let prev_x = self.x_from_value(prev_value, x_range.clone());
|
let prev_position = self.position_from_value(prev_value, position_range.clone());
|
||||||
let new_x = prev_x + kb_step;
|
let new_position = prev_position + kb_step;
|
||||||
let new_value = if self.smart_aim {
|
let new_value = if self.smart_aim {
|
||||||
let aim_radius = ui.input().aim_radius();
|
let aim_radius = ui.input().aim_radius();
|
||||||
emath::smart_aim::best_in_range_f64(
|
emath::smart_aim::best_in_range_f64(
|
||||||
self.value_from_x(new_x - aim_radius, x_range.clone()),
|
self.value_from_position(new_position - aim_radius, position_range.clone()),
|
||||||
self.value_from_x(new_x + aim_radius, x_range.clone()),
|
self.value_from_position(new_position + aim_radius, position_range.clone()),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.value_from_x(new_x, x_range.clone())
|
self.value_from_position(new_position, position_range.clone())
|
||||||
};
|
};
|
||||||
self.set_value(new_value);
|
self.set_value(new_value);
|
||||||
}
|
}
|
||||||
|
@ -324,15 +340,10 @@ impl<'a> Slider<'a> {
|
||||||
if ui.is_rect_visible(response.rect) {
|
if ui.is_rect_visible(response.rect) {
|
||||||
let value = self.get_value();
|
let value = self.get_value();
|
||||||
|
|
||||||
let rail_radius = ui
|
let rail_radius = ui.painter().round_to_pixel(self.rail_radius_limit(rect));
|
||||||
.painter()
|
let rail_rect = self.rail_rect(rect, rail_radius);
|
||||||
.round_to_pixel((rect.height() / 4.0).at_least(2.0));
|
|
||||||
|
|
||||||
let rail_rect = Rect::from_min_max(
|
let position_1d = self.position_from_value(value, position_range);
|
||||||
pos2(rect.left(), rect.center().y - rail_radius),
|
|
||||||
pos2(rect.right(), rect.center().y + rail_radius),
|
|
||||||
);
|
|
||||||
let marker_center_x = self.x_from_value(value, x_range);
|
|
||||||
|
|
||||||
let visuals = ui.style().interact(response);
|
let visuals = ui.style().interact(response);
|
||||||
ui.painter().add(epaint::RectShape {
|
ui.painter().add(epaint::RectShape {
|
||||||
|
@ -346,15 +357,85 @@ impl<'a> Slider<'a> {
|
||||||
// stroke: ui.visuals().widgets.inactive.bg_stroke,
|
// stroke: ui.visuals().widgets.inactive.bg_stroke,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let center = self.marker_center(position_1d, &rail_rect);
|
||||||
|
|
||||||
ui.painter().add(epaint::CircleShape {
|
ui.painter().add(epaint::CircleShape {
|
||||||
center: pos2(marker_center_x, rail_rect.center().y),
|
center,
|
||||||
radius: handle_radius(rect) + visuals.expansion,
|
radius: self.handle_radius(rect) + visuals.expansion,
|
||||||
fill: visuals.bg_fill,
|
fill: visuals.bg_fill,
|
||||||
stroke: visuals.fg_stroke,
|
stroke: visuals.fg_stroke,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn marker_center(&self, position_1d: f32, rail_rect: &Rect) -> Pos2 {
|
||||||
|
match self.orientation {
|
||||||
|
SliderOrientation::Horizontal => pos2(position_1d, rail_rect.center().y),
|
||||||
|
SliderOrientation::Vertical => pos2(rail_rect.center().x, position_1d),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pointer_position(&self, pointer_position_2d: Pos2) -> f32 {
|
||||||
|
match self.orientation {
|
||||||
|
SliderOrientation::Horizontal => pointer_position_2d.x,
|
||||||
|
SliderOrientation::Vertical => pointer_position_2d.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn position_range(&self, rect: &Rect) -> RangeInclusive<f32> {
|
||||||
|
let handle_radius = self.handle_radius(rect);
|
||||||
|
match self.orientation {
|
||||||
|
SliderOrientation::Horizontal => {
|
||||||
|
(rect.left() + handle_radius)..=(rect.right() - handle_radius)
|
||||||
|
}
|
||||||
|
SliderOrientation::Vertical => {
|
||||||
|
(rect.bottom() - handle_radius)..=(rect.top() + handle_radius)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_increment(&self) -> Key {
|
||||||
|
match self.orientation {
|
||||||
|
SliderOrientation::Horizontal => Key::ArrowRight,
|
||||||
|
SliderOrientation::Vertical => Key::ArrowUp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_decrement(&self) -> Key {
|
||||||
|
match self.orientation {
|
||||||
|
SliderOrientation::Horizontal => Key::ArrowLeft,
|
||||||
|
SliderOrientation::Vertical => Key::ArrowDown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rail_rect(&self, rect: &Rect, radius: f32) -> Rect {
|
||||||
|
match self.orientation {
|
||||||
|
SliderOrientation::Horizontal => Rect::from_min_max(
|
||||||
|
pos2(rect.left(), rect.center().y - radius),
|
||||||
|
pos2(rect.right(), rect.center().y + radius),
|
||||||
|
),
|
||||||
|
SliderOrientation::Vertical => Rect::from_min_max(
|
||||||
|
pos2(rect.center().x - radius, rect.top()),
|
||||||
|
pos2(rect.center().x + radius, rect.bottom()),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_radius(&self, rect: &Rect) -> f32 {
|
||||||
|
let limit = match self.orientation {
|
||||||
|
SliderOrientation::Horizontal => rect.height(),
|
||||||
|
SliderOrientation::Vertical => rect.width(),
|
||||||
|
};
|
||||||
|
limit / 2.5
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rail_radius_limit(&self, rect: &Rect) -> f32 {
|
||||||
|
match self.orientation {
|
||||||
|
SliderOrientation::Horizontal => (rect.height() / 4.0).at_least(2.0),
|
||||||
|
SliderOrientation::Vertical => (rect.width() / 4.0).at_least(2.0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn label_ui(&mut self, ui: &mut Ui) {
|
fn label_ui(&mut self, ui: &mut Ui) {
|
||||||
if !self.text.is_empty() {
|
if !self.text.is_empty() {
|
||||||
let text_color = self.text_color.unwrap_or_else(|| ui.visuals().text_color());
|
let text_color = self.text_color.unwrap_or_else(|| ui.visuals().text_color());
|
||||||
|
@ -363,11 +444,11 @@ impl<'a> Slider<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn value_ui(&mut self, ui: &mut Ui, x_range: RangeInclusive<f32>) {
|
fn value_ui(&mut self, ui: &mut Ui, position_range: RangeInclusive<f32>) {
|
||||||
let mut value = self.get_value();
|
let mut value = self.get_value();
|
||||||
ui.add(
|
ui.add(
|
||||||
DragValue::new(&mut value)
|
DragValue::new(&mut value)
|
||||||
.speed(self.current_gradient(&x_range))
|
.speed(self.current_gradient(&position_range))
|
||||||
.clamp_range(self.clamp_range())
|
.clamp_range(self.clamp_range())
|
||||||
.min_decimals(self.min_decimals)
|
.min_decimals(self.min_decimals)
|
||||||
.max_decimals_opt(self.max_decimals)
|
.max_decimals_opt(self.max_decimals)
|
||||||
|
@ -380,41 +461,46 @@ impl<'a> Slider<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// delta(value) / delta(points)
|
/// delta(value) / delta(points)
|
||||||
fn current_gradient(&mut self, x_range: &RangeInclusive<f32>) -> f64 {
|
fn current_gradient(&mut self, position_range: &RangeInclusive<f32>) -> f64 {
|
||||||
// TODO: handle clamping
|
// TODO: handle clamping
|
||||||
let value = self.get_value();
|
let value = self.get_value();
|
||||||
let value_from_x = |x: f32| self.value_from_x(x, x_range.clone());
|
let value_from_pos =
|
||||||
let x_from_value = |value: f64| self.x_from_value(value, x_range.clone());
|
|position: f32| self.value_from_position(position, position_range.clone());
|
||||||
let left_value = value_from_x(x_from_value(value) - 0.5);
|
let pos_from_value = |value: f64| self.position_from_value(value, position_range.clone());
|
||||||
let right_value = value_from_x(x_from_value(value) + 0.5);
|
let left_value = value_from_pos(pos_from_value(value) - 0.5);
|
||||||
|
let right_value = value_from_pos(pos_from_value(value) + 0.5);
|
||||||
right_value - left_value
|
right_value - left_value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_contents(&mut self, ui: &mut Ui) -> Response {
|
||||||
|
let text_style = TextStyle::Button;
|
||||||
|
let perpendicular = ui
|
||||||
|
.fonts()
|
||||||
|
.row_height(text_style)
|
||||||
|
.at_least(ui.spacing().interact_size.y);
|
||||||
|
let slider_response = self.allocate_slider_space(ui, perpendicular);
|
||||||
|
self.slider_ui(ui, &slider_response);
|
||||||
|
|
||||||
|
if self.show_value {
|
||||||
|
let position_range = self.position_range(&slider_response.rect);
|
||||||
|
self.value_ui(ui, position_range);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.text.is_empty() {
|
||||||
|
self.label_ui(ui);
|
||||||
|
}
|
||||||
|
slider_response
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Widget for Slider<'a> {
|
impl<'a> Widget for Slider<'a> {
|
||||||
fn ui(mut self, ui: &mut Ui) -> Response {
|
fn ui(mut self, ui: &mut Ui) -> Response {
|
||||||
let text_style = TextStyle::Button;
|
|
||||||
let height = ui
|
|
||||||
.fonts()
|
|
||||||
.row_height(text_style)
|
|
||||||
.at_least(ui.spacing().interact_size.y);
|
|
||||||
|
|
||||||
let old_value = self.get_value();
|
let old_value = self.get_value();
|
||||||
|
|
||||||
let inner_response = ui.horizontal(|ui| {
|
let inner_response = match self.orientation {
|
||||||
let slider_response = self.allocate_slider_space(ui, height);
|
SliderOrientation::Horizontal => ui.horizontal(|ui| self.add_contents(ui)),
|
||||||
self.slider_ui(ui, &slider_response);
|
SliderOrientation::Vertical => ui.vertical(|ui| self.add_contents(ui)),
|
||||||
|
};
|
||||||
if self.show_value {
|
|
||||||
let x_range = x_range(&slider_response.rect);
|
|
||||||
self.value_ui(ui, x_range);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.text.is_empty() {
|
|
||||||
self.label_ui(ui);
|
|
||||||
}
|
|
||||||
slider_response
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut response = inner_response.inner | inner_response.response;
|
let mut response = inner_response.inner | inner_response.response;
|
||||||
response.changed = self.get_value() != old_value;
|
response.changed = self.get_value() != old_value;
|
||||||
|
|
|
@ -12,6 +12,7 @@ pub struct Sliders {
|
||||||
pub clamp_to_range: bool,
|
pub clamp_to_range: bool,
|
||||||
pub smart_aim: bool,
|
pub smart_aim: bool,
|
||||||
pub integer: bool,
|
pub integer: bool,
|
||||||
|
pub vertical: bool,
|
||||||
pub value: f64,
|
pub value: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ impl Default for Sliders {
|
||||||
clamp_to_range: false,
|
clamp_to_range: false,
|
||||||
smart_aim: true,
|
smart_aim: true,
|
||||||
integer: false,
|
integer: false,
|
||||||
|
vertical: false,
|
||||||
value: 10.0,
|
value: 10.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,6 +56,7 @@ impl super::View for Sliders {
|
||||||
clamp_to_range,
|
clamp_to_range,
|
||||||
smart_aim,
|
smart_aim,
|
||||||
integer,
|
integer,
|
||||||
|
vertical,
|
||||||
value,
|
value,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
|
@ -70,6 +73,12 @@ impl super::View for Sliders {
|
||||||
*min = min.clamp(type_min, type_max);
|
*min = min.clamp(type_min, type_max);
|
||||||
*max = max.clamp(type_min, type_max);
|
*max = max.clamp(type_min, type_max);
|
||||||
|
|
||||||
|
let orientation = if *vertical {
|
||||||
|
SliderOrientation::Vertical
|
||||||
|
} else {
|
||||||
|
SliderOrientation::Horizontal
|
||||||
|
};
|
||||||
|
|
||||||
if *integer {
|
if *integer {
|
||||||
let mut value_i32 = *value as i32;
|
let mut value_i32 = *value as i32;
|
||||||
ui.add(
|
ui.add(
|
||||||
|
@ -77,6 +86,7 @@ impl super::View for Sliders {
|
||||||
.logarithmic(*logarithmic)
|
.logarithmic(*logarithmic)
|
||||||
.clamp_to_range(*clamp_to_range)
|
.clamp_to_range(*clamp_to_range)
|
||||||
.smart_aim(*smart_aim)
|
.smart_aim(*smart_aim)
|
||||||
|
.orientation(orientation)
|
||||||
.text("i32 demo slider"),
|
.text("i32 demo slider"),
|
||||||
);
|
);
|
||||||
*value = value_i32 as f64;
|
*value = value_i32 as f64;
|
||||||
|
@ -86,6 +96,7 @@ impl super::View for Sliders {
|
||||||
.logarithmic(*logarithmic)
|
.logarithmic(*logarithmic)
|
||||||
.clamp_to_range(*clamp_to_range)
|
.clamp_to_range(*clamp_to_range)
|
||||||
.smart_aim(*smart_aim)
|
.smart_aim(*smart_aim)
|
||||||
|
.orientation(orientation)
|
||||||
.text("f64 demo slider"),
|
.text("f64 demo slider"),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -100,6 +111,7 @@ impl super::View for Sliders {
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
ui.label("Slider range:");
|
ui.label("Slider range:");
|
||||||
ui.add(
|
ui.add(
|
||||||
Slider::new(min, type_min..=type_max)
|
Slider::new(min, type_min..=type_max)
|
||||||
|
@ -121,6 +133,11 @@ impl super::View for Sliders {
|
||||||
ui.radio_value(integer, true, "i32");
|
ui.radio_value(integer, true, "i32");
|
||||||
ui.radio_value(integer, false, "f64");
|
ui.radio_value(integer, false, "f64");
|
||||||
});
|
});
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Slider orientation:");
|
||||||
|
ui.radio_value(vertical, false, "Horizontal");
|
||||||
|
ui.radio_value(vertical, true, "Vertical");
|
||||||
|
});
|
||||||
ui.label("(f32, usize etc are also possible)");
|
ui.label("(f32, usize etc are also possible)");
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue