Add the range slider design to the NumberInput widget (#839)

* Add range slider to NumberInput

* Cleanup

* Fix event ordering causing bug in Firefox

* Polish the code

* Switch number input modes to range in relevant places
This commit is contained in:
Keavon Chambers
2022-11-05 22:57:19 -07:00
parent 18507b78ac
commit 782f528279
9 changed files with 435 additions and 120 deletions

View File

@@ -99,12 +99,13 @@ impl PropertyHolder for NewDocumentDialogMessageHandler {
direction: SeparatorDirection::Horizontal,
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: Some(self.dimensions.x as f64),
label: "W".into(),
unit: " px".into(),
disabled: self.infinite,
is_integer: true,
value: Some(self.dimensions.x as f64),
min: Some(0.),
is_integer: true,
disabled: self.infinite,
min_width: 100,
on_update: WidgetCallback::new(|number_input: &NumberInput| NewDocumentDialogMessage::DimensionsX(number_input.value.unwrap()).into()),
..NumberInput::default()
})),
@@ -113,12 +114,13 @@ impl PropertyHolder for NewDocumentDialogMessageHandler {
direction: SeparatorDirection::Horizontal,
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: Some(self.dimensions.y as f64),
label: "H".into(),
unit: " px".into(),
disabled: self.infinite,
is_integer: true,
value: Some(self.dimensions.y as f64),
min: Some(0.),
is_integer: true,
disabled: self.infinite,
min_width: 100,
on_update: WidgetCallback::new(|number_input: &NumberInput| NewDocumentDialogMessage::DimensionsY(number_input.value.unwrap()).into()),
..NumberInput::default()
})),

View File

@@ -153,8 +153,18 @@ pub struct InvisibleStandinInput {
#[derive(Clone, Serialize, Deserialize, Derivative)]
#[derivative(Debug, PartialEq, Default)]
pub struct NumberInput {
// Label
pub label: String,
pub tooltip: String,
#[serde(skip)]
pub tooltip_shortcut: Option<ActionKeys>,
// Disabled
pub disabled: bool,
// Value
pub value: Option<f64>,
pub min: Option<f64>,
@@ -164,6 +174,7 @@ pub struct NumberInput {
#[serde(rename = "isInteger")]
pub is_integer: bool,
// Number presentation
#[serde(rename = "displayDecimalPlaces")]
#[derivative(Default(value = "3"))]
pub display_decimal_places: u32,
@@ -174,23 +185,25 @@ pub struct NumberInput {
#[derivative(Default(value = "true"))]
pub unit_is_hidden_when_editing: bool,
// Mode behavior
pub mode: NumberInputMode,
#[serde(rename = "incrementBehavior")]
pub increment_behavior: NumberInputIncrementBehavior,
#[serde(rename = "incrementFactor")]
#[derivative(Default(value = "1."))]
pub increment_factor: f64,
pub step: f64,
pub disabled: bool,
#[serde(rename = "rangeMin")]
pub range_min: Option<f64>,
#[serde(rename = "rangeMax")]
pub range_max: Option<f64>,
// Styling
#[serde(rename = "minWidth")]
pub min_width: u32,
pub tooltip: String,
#[serde(skip)]
pub tooltip_shortcut: Option<ActionKeys>,
// Callbacks
#[serde(skip)]
#[derivative(Debug = "ignore", PartialEq = "ignore")]
@@ -213,6 +226,13 @@ pub enum NumberInputIncrementBehavior {
Callback,
}
#[derive(Clone, Serialize, Deserialize, Debug, Default, PartialEq, Eq)]
pub enum NumberInputMode {
#[default]
Increment,
Range,
}
#[derive(Clone, Default, Derivative, Serialize, Deserialize)]
#[derivative(Debug, PartialEq)]
pub struct OptionalInput {

View File

@@ -8,7 +8,9 @@ use crate::messages::input_mapper::utility_types::macros::action_keys;
use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, Widget, WidgetCallback, WidgetHolder, WidgetLayout};
use crate::messages::layout::utility_types::misc::LayoutTarget;
use crate::messages::layout::utility_types::widgets::button_widgets::{IconButton, PopoverButton};
use crate::messages::layout::utility_types::widgets::input_widgets::{DropdownEntryData, DropdownInput, NumberInput, NumberInputIncrementBehavior, OptionalInput, RadioEntryData, RadioInput};
use crate::messages::layout::utility_types::widgets::input_widgets::{
DropdownEntryData, DropdownInput, NumberInput, NumberInputIncrementBehavior, NumberInputMode, OptionalInput, RadioEntryData, RadioInput,
};
use crate::messages::layout::utility_types::widgets::label_widgets::{Separator, SeparatorDirection, SeparatorType};
use crate::messages::portfolio::document::properties_panel::utility_types::PropertiesPanelMessageHandlerData;
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
@@ -1684,7 +1686,7 @@ impl DocumentMessageHandler {
WidgetHolder::new(Widget::NumberInput(NumberInput {
unit: "°".into(),
value: Some(rotation_value),
increment_factor: 15.,
step: 15.,
on_update: WidgetCallback::new(|number_input: &NumberInput| {
NavigationMessage::SetCanvasRotation {
angle_radians: number_input.value.unwrap() * (std::f64::consts::PI / 180.),
@@ -1834,6 +1836,7 @@ impl DocumentMessageHandler {
value: opacity.map(|opacity| opacity * 100.),
min: Some(0.),
max: Some(100.),
mode: NumberInputMode::Range,
on_update: WidgetCallback::new(|number_input: &NumberInput| {
if let Some(value) = number_input.value {
DocumentMessage::SetOpacityForSelectedLayers { opacity: value / 100. }.into()

View File

@@ -5,7 +5,7 @@ use crate::messages::layout::utility_types::misc::LayoutTarget;
use crate::messages::layout::utility_types::widgets::assist_widgets::PivotAssist;
use crate::messages::layout::utility_types::widgets::button_widgets::{IconButton, PopoverButton, TextButton};
use crate::messages::layout::utility_types::widgets::input_widgets::{
CheckboxInput, ColorInput, DropdownEntryData, DropdownInput, FontInput, NumberInput, RadioEntryData, RadioInput, TextAreaInput, TextInput,
CheckboxInput, ColorInput, DropdownEntryData, DropdownInput, FontInput, NumberInput, NumberInputMode, RadioEntryData, RadioInput, TextAreaInput, TextInput,
};
use crate::messages::layout::utility_types::widgets::label_widgets::{IconLabel, Separator, SeparatorDirection, SeparatorType, TextLabel};
use crate::messages::portfolio::utility_types::{ImaginateServerStatus, PersistentData};
@@ -405,8 +405,10 @@ fn node_section_transform(layer: &Layer, persistent_data: &PersistentData) -> La
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: Some(layer.transform.rotation() * 180. / PI),
label: "".into(),
unit: "°".into(),
mode: NumberInputMode::Range,
range_min: Some(-180.),
range_max: Some(180.),
on_update: WidgetCallback::new(|number_input: &NumberInput| {
PropertiesPanelMessage::ModifyTransform {
value: number_input.value.unwrap() / 180. * PI,
@@ -776,6 +778,10 @@ fn node_section_imaginate(imaginate_layer: &ImaginateLayer, layer: &Layer, persi
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: Some(imaginate_layer.samples.into()),
mode: NumberInputMode::Range,
range_min: Some(0.),
range_max: Some(150.),
is_integer: true,
min: Some(0.),
max: Some(150.),
tooltip,
@@ -862,8 +868,12 @@ fn node_section_imaginate(imaginate_layer: &ImaginateLayer, layer: &Layer, persi
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: Some(imaginate_layer.denoising_strength),
mode: NumberInputMode::Range,
range_min: Some(0.),
range_max: Some(1.),
min: Some(0.),
max: Some(1.),
display_decimal_places: 2,
disabled: !imaginate_layer.use_img2img,
tooltip,
on_update: WidgetCallback::new(move |number_input: &NumberInput| {
@@ -894,6 +904,9 @@ fn node_section_imaginate(imaginate_layer: &ImaginateLayer, layer: &Layer, persi
})),
WidgetHolder::new(Widget::NumberInput(NumberInput {
value: Some(imaginate_layer.cfg_scale),
mode: NumberInputMode::Range,
range_min: Some(0.),
range_max: Some(30.),
min: Some(0.),
max: Some(30.),
tooltip,