mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 17:18:12 +08:00
fix: make hard controls also limit range movement
This commit is contained in:
@@ -255,6 +255,15 @@ pub struct NumberInput {
|
|||||||
#[serde(rename = "rangeMax")]
|
#[serde(rename = "rangeMax")]
|
||||||
pub range_max: Option<f64>,
|
pub range_max: Option<f64>,
|
||||||
|
|
||||||
|
// TODO: Make this (and range_max) apply to both Range and Increment modes when dragging with the mouse
|
||||||
|
#[serde(rename = "hardMin")]
|
||||||
|
#[widget_builder(skip)]
|
||||||
|
pub hard_min: Option<f64>,
|
||||||
|
|
||||||
|
#[serde(rename = "hardMax")]
|
||||||
|
#[widget_builder(skip)]
|
||||||
|
pub hard_max: Option<f64>,
|
||||||
|
|
||||||
// Styling
|
// Styling
|
||||||
#[serde(rename = "minWidth")]
|
#[serde(rename = "minWidth")]
|
||||||
pub min_width: u32,
|
pub min_width: u32,
|
||||||
@@ -295,6 +304,14 @@ impl NumberInput {
|
|||||||
self.range_max = Some(val);
|
self.range_max = Some(val);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
pub fn hard_min(mut self, val: f64) -> Self {
|
||||||
|
self.hard_min = Some(val);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn hard_max(mut self, val: f64) -> Self {
|
||||||
|
self.hard_max = Some(val);
|
||||||
|
self
|
||||||
|
}
|
||||||
pub fn mode_range(mut self) -> Self {
|
pub fn mode_range(mut self) -> Self {
|
||||||
self.mode = NumberInputMode::Range;
|
self.mode = NumberInputMode::Range;
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -2653,6 +2653,8 @@ impl DocumentMessageHandler {
|
|||||||
.disabled(disabled)
|
.disabled(disabled)
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max(100.)
|
.max(100.)
|
||||||
|
.hard_min(0.)
|
||||||
|
.hard_max(100.)
|
||||||
.range_min(Some(0.))
|
.range_min(Some(0.))
|
||||||
.range_max(Some(100.))
|
.range_max(Some(100.))
|
||||||
.mode_range()
|
.mode_range()
|
||||||
@@ -2675,6 +2677,8 @@ impl DocumentMessageHandler {
|
|||||||
.disabled(disabled)
|
.disabled(disabled)
|
||||||
.min(0.)
|
.min(0.)
|
||||||
.max(100.)
|
.max(100.)
|
||||||
|
.hard_min(0.)
|
||||||
|
.hard_max(100.)
|
||||||
.range_min(Some(0.))
|
.range_min(Some(0.))
|
||||||
.range_max(Some(100.))
|
.range_max(Some(100.))
|
||||||
.mode_range()
|
.mode_range()
|
||||||
|
|||||||
@@ -118,19 +118,25 @@ pub(crate) fn property_from_type(
|
|||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
index: usize,
|
index: usize,
|
||||||
ty: &Type,
|
ty: &Type,
|
||||||
number_options: (Option<f64>, Option<f64>, Option<(f64, f64)>),
|
number_options: (Option<f64>, Option<f64>, Option<f64>, Option<f64>, Option<(f64, f64)>),
|
||||||
unit: Option<&str>,
|
unit: Option<&str>,
|
||||||
display_decimal_places: Option<u32>,
|
display_decimal_places: Option<u32>,
|
||||||
step: Option<f64>,
|
step: Option<f64>,
|
||||||
context: &mut NodePropertiesContext,
|
context: &mut NodePropertiesContext,
|
||||||
) -> Result<Vec<LayoutGroup>, Vec<LayoutGroup>> {
|
) -> Result<Vec<LayoutGroup>, Vec<LayoutGroup>> {
|
||||||
let (mut number_min, mut number_max, range) = number_options;
|
let (mut number_min, mut number_max, number_hard_min, number_hard_max, range) = number_options;
|
||||||
let mut number_input = NumberInput::default();
|
let mut number_input = NumberInput::default();
|
||||||
if let Some((range_start, range_end)) = range {
|
if let Some((range_start, range_end)) = range {
|
||||||
number_min = Some(range_start);
|
number_min = Some(range_start);
|
||||||
number_max = Some(range_end);
|
number_max = Some(range_end);
|
||||||
number_input = number_input.mode_range().min(range_start).max(range_end);
|
number_input = number_input.mode_range().min(range_start).max(range_end);
|
||||||
}
|
}
|
||||||
|
if let Some(hard_min) = number_hard_min {
|
||||||
|
number_input = number_input.hard_min(hard_min)
|
||||||
|
}
|
||||||
|
if let Some(hard_max) = number_hard_max {
|
||||||
|
number_input = number_input.hard_max(hard_max)
|
||||||
|
}
|
||||||
if let Some(unit) = unit {
|
if let Some(unit) = unit {
|
||||||
number_input = number_input.unit(unit);
|
number_input = number_input.unit(unit);
|
||||||
}
|
}
|
||||||
@@ -1427,7 +1433,7 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
|
|||||||
return Vec::new();
|
return Vec::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut number_options = (None, None, None);
|
let mut number_options = (None, None, None, None, None);
|
||||||
let mut display_decimal_places = None;
|
let mut display_decimal_places = None;
|
||||||
let mut step = None;
|
let mut step = None;
|
||||||
let mut unit_suffix = None;
|
let mut unit_suffix = None;
|
||||||
@@ -1439,7 +1445,7 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper
|
|||||||
.get(&proto_node_identifier)
|
.get(&proto_node_identifier)
|
||||||
.and_then(|metadata| metadata.fields.get(input_index))
|
.and_then(|metadata| metadata.fields.get(input_index))
|
||||||
{
|
{
|
||||||
number_options = (field.number_min, field.number_max, field.number_mode_range);
|
number_options = (field.number_min, field.number_max, field.number_hard_min, field.number_hard_max, field.number_mode_range);
|
||||||
display_decimal_places = field.number_display_decimal_places;
|
display_decimal_places = field.number_display_decimal_places;
|
||||||
unit_suffix = field.unit;
|
unit_suffix = field.unit;
|
||||||
step = field.number_step;
|
step = field.number_step;
|
||||||
|
|||||||
@@ -25,8 +25,12 @@
|
|||||||
// Value
|
// Value
|
||||||
// When `value` is not provided (i.e. it's `undefined`), a dash is displayed.
|
// When `value` is not provided (i.e. it's `undefined`), a dash is displayed.
|
||||||
export let value: number | undefined = undefined; // NOTE: Do not update this directly, do so by calling `updateValue()` instead.
|
export let value: number | undefined = undefined; // NOTE: Do not update this directly, do so by calling `updateValue()` instead.
|
||||||
|
|
||||||
export let min: number | undefined = undefined;
|
export let min: number | undefined = undefined;
|
||||||
export let max: number | undefined = undefined;
|
export let max: number | undefined = undefined;
|
||||||
|
export let hardMin: number | undefined = undefined;
|
||||||
|
export let hardMax: number | undefined = undefined;
|
||||||
|
|
||||||
export let isInteger = false;
|
export let isInteger = false;
|
||||||
|
|
||||||
// Number presentation
|
// Number presentation
|
||||||
@@ -130,6 +134,9 @@
|
|||||||
if (mode == "Increment") {
|
if (mode == "Increment") {
|
||||||
if (typeof min === "number") sanitized = Math.max(sanitized, min);
|
if (typeof min === "number") sanitized = Math.max(sanitized, min);
|
||||||
if (typeof max === "number") sanitized = Math.min(sanitized, max);
|
if (typeof max === "number") sanitized = Math.min(sanitized, max);
|
||||||
|
} else {
|
||||||
|
if (typeof hardMin === "number") sanitized = Math.max(sanitized, hardMin);
|
||||||
|
if (typeof hardMax === "number") sanitized = Math.min(sanitized, hardMax);
|
||||||
}
|
}
|
||||||
text = displayText(sanitized, unit);
|
text = displayText(sanitized, unit);
|
||||||
}
|
}
|
||||||
@@ -145,6 +152,9 @@
|
|||||||
if (mode == "Increment") {
|
if (mode == "Increment") {
|
||||||
if (typeof min === "number" && !Number.isNaN(min)) newValueValidated = Math.max(newValueValidated, min);
|
if (typeof min === "number" && !Number.isNaN(min)) newValueValidated = Math.max(newValueValidated, min);
|
||||||
if (typeof max === "number" && !Number.isNaN(max)) newValueValidated = Math.min(newValueValidated, max);
|
if (typeof max === "number" && !Number.isNaN(max)) newValueValidated = Math.min(newValueValidated, max);
|
||||||
|
} else {
|
||||||
|
if (typeof hardMin === "number" && !Number.isNaN(hardMin)) newValueValidated = Math.max(newValueValidated, hardMin);
|
||||||
|
if (typeof hardMax === "number" && !Number.isNaN(hardMax)) newValueValidated = Math.min(newValueValidated, hardMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInteger) newValueValidated = Math.round(newValueValidated);
|
if (isInteger) newValueValidated = Math.round(newValueValidated);
|
||||||
|
|||||||
@@ -162,8 +162,14 @@ fn blending<T: SetBlendMode + MultiplyAlpha + MultiplyFill + SetClip>(
|
|||||||
)]
|
)]
|
||||||
mut value: T,
|
mut value: T,
|
||||||
blend_mode: BlendMode,
|
blend_mode: BlendMode,
|
||||||
#[default(100.)] opacity: Percentage,
|
#[hard_min(0.)]
|
||||||
#[default(100.)] fill: Percentage,
|
#[hard_max(100.)]
|
||||||
|
#[default(100.)]
|
||||||
|
opacity: Percentage,
|
||||||
|
#[hard_min(0.)]
|
||||||
|
#[hard_max(100.)]
|
||||||
|
#[default(100.)]
|
||||||
|
fill: Percentage,
|
||||||
#[default(false)] clip: bool,
|
#[default(false)] clip: bool,
|
||||||
) -> T {
|
) -> T {
|
||||||
// TODO: Find a way to make this apply once to the table's parent (i.e. its row in its parent table or Instance<T>) rather than applying to each row in its own table, which produces the undesired result
|
// TODO: Find a way to make this apply once to the table's parent (i.e. its row in its parent table or Instance<T>) rather than applying to each row in its own table, which produces the undesired result
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ pub struct FieldMetadata {
|
|||||||
pub default_type: Option<Type>,
|
pub default_type: Option<Type>,
|
||||||
pub number_min: Option<f64>,
|
pub number_min: Option<f64>,
|
||||||
pub number_max: Option<f64>,
|
pub number_max: Option<f64>,
|
||||||
|
pub number_hard_min: Option<f64>,
|
||||||
|
pub number_hard_max: Option<f64>,
|
||||||
pub number_mode_range: Option<(f64, f64)>,
|
pub number_mode_range: Option<(f64, f64)>,
|
||||||
pub number_display_decimal_places: Option<u32>,
|
pub number_display_decimal_places: Option<u32>,
|
||||||
pub number_step: Option<f64>,
|
pub number_step: Option<f64>,
|
||||||
|
|||||||
@@ -154,6 +154,23 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result<TokenStre
|
|||||||
_ => quote!(None),
|
_ => quote!(None),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let number_hard_min_values: Vec<_> = fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| match field {
|
||||||
|
ParsedField::Regular { number_hard_min: Some(hard_min), .. } => quote!(Some(#hard_min)),
|
||||||
|
_ => quote!(None),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let number_hard_max_values: Vec<_> = fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| match field {
|
||||||
|
ParsedField::Regular { number_hard_max: Some(hard_max), .. } => quote!(Some(#hard_max)),
|
||||||
|
_ => quote!(None),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let number_mode_range_values: Vec<_> = fields
|
let number_mode_range_values: Vec<_> = fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|field| match field {
|
.map(|field| match field {
|
||||||
@@ -419,6 +436,8 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result<TokenStre
|
|||||||
default_type: #default_types,
|
default_type: #default_types,
|
||||||
number_min: #number_min_values,
|
number_min: #number_min_values,
|
||||||
number_max: #number_max_values,
|
number_max: #number_max_values,
|
||||||
|
number_hard_min: #number_hard_min_values,
|
||||||
|
number_hard_max: #number_hard_max_values,
|
||||||
number_mode_range: #number_mode_range_values,
|
number_mode_range: #number_mode_range_values,
|
||||||
number_display_decimal_places: #number_display_decimal_places,
|
number_display_decimal_places: #number_display_decimal_places,
|
||||||
number_step: #number_step,
|
number_step: #number_step,
|
||||||
|
|||||||
Reference in New Issue
Block a user