mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-04 06:38:11 +08:00
Rename the SpectrumInput widget to SliderInput (#4541)
Rename the 'SpectrumInput' widget to 'SliderInput'
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
use crate::messages::layout::utility_types::widgets::input_widgets::{SpectrumInputUpdate, VisualColorPickersInputUpdate};
|
use crate::messages::layout::utility_types::widgets::input_widgets::{SliderInputUpdate, VisualColorPickersInputUpdate};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use graphene_std::vector::style::{FillChoice, GradientHueDirection, GradientInterpolation, GradientSpace, GradientSpread};
|
use graphene_std::vector::style::{FillChoice, GradientHueDirection, GradientInterpolation, GradientSpace, GradientSpread};
|
||||||
|
|
||||||
@@ -45,8 +45,8 @@ pub enum ColorPickerMessage {
|
|||||||
/// Swap the current "new" color with the captured "old" color.
|
/// Swap the current "new" color with the captured "old" color.
|
||||||
SwapNewWithOld,
|
SwapNewWithOld,
|
||||||
|
|
||||||
/// `SpectrumInput` change: marker move/insert/delete, midpoint move/reset, or active marker selection changed.
|
/// `SliderInput` change: marker move/insert/delete, midpoint move/reset, or active marker selection changed.
|
||||||
GradientUpdate { update: SpectrumInputUpdate },
|
GradientUpdate { update: SliderInputUpdate },
|
||||||
/// Gradient spread choice from the gradient "Ends" selection.
|
/// Gradient spread choice from the gradient "Ends" selection.
|
||||||
SetGradientSpread { gradient_spread: GradientSpread },
|
SetGradientSpread { gradient_spread: GradientSpread },
|
||||||
/// Gradient cyclic choice: whether the stops wrap as a cycle, from the "Cyclic" checkbox.
|
/// Gradient cyclic choice: whether the stops wrap as a cycle, from the "Cyclic" checkbox.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::messages::color_picker::color_picker_message::{HsvChannel, RgbChannel};
|
use crate::messages::color_picker::color_picker_message::{HsvChannel, RgbChannel};
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::layout::utility_types::widgets::input_widgets::{ColorPresetsInputUpdate, SpectrumInputUpdate, SpectrumMarker, VisualColorPickersInputUpdate};
|
use crate::messages::layout::utility_types::widgets::input_widgets::{ColorPresetsInputUpdate, SliderInputUpdate, SliderMarker, VisualColorPickersInputUpdate};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use graphene_std::Color;
|
use graphene_std::Color;
|
||||||
use graphene_std::color::SRGBA8;
|
use graphene_std::color::SRGBA8;
|
||||||
@@ -377,10 +377,10 @@ impl ColorPickerMessageHandler {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply an incoming `SpectrumInput` intent to the gradient state and broadcast the result.
|
/// Apply an incoming `SliderInput` intent to the gradient state and broadcast the result.
|
||||||
fn apply_gradient_update(&mut self, update: SpectrumInputUpdate, responses: &mut VecDeque<Message>) {
|
fn apply_gradient_update(&mut self, update: SliderInputUpdate, responses: &mut VecDeque<Message>) {
|
||||||
// Active marker selection is the one update that doesn't mutate the gradient
|
// Active marker selection is the one update that doesn't mutate the gradient
|
||||||
if let SpectrumInputUpdate::ActiveMarker {
|
if let SliderInputUpdate::ActiveMarker {
|
||||||
active_marker_index,
|
active_marker_index,
|
||||||
active_marker_is_midpoint,
|
active_marker_is_midpoint,
|
||||||
} = update
|
} = update
|
||||||
@@ -401,19 +401,19 @@ impl ColorPickerMessageHandler {
|
|||||||
let Some(mut gradient) = self.gradient.clone() else { return };
|
let Some(mut gradient) = self.gradient.clone() else { return };
|
||||||
|
|
||||||
match update {
|
match update {
|
||||||
SpectrumInputUpdate::MoveMarker { index, position } => {
|
SliderInputUpdate::MoveMarker { index, position } => {
|
||||||
let new_index = gradient.move_stop(index as usize, position, self.gradient_cyclic);
|
let new_index = gradient.move_stop(index as usize, position, self.gradient_cyclic);
|
||||||
if Some(index) == self.active_marker_index {
|
if Some(index) == self.active_marker_index {
|
||||||
self.active_marker_index = Some(new_index as u32);
|
self.active_marker_index = Some(new_index as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SpectrumInputUpdate::MoveMidpoint { index, position } => {
|
SliderInputUpdate::MoveMidpoint { index, position } => {
|
||||||
if (index as usize) >= gradient.len() {
|
if (index as usize) >= gradient.len() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gradient.set_midpoint(index as usize, position.clamp(MIN_MIDPOINT, MAX_MIDPOINT));
|
gradient.set_midpoint(index as usize, position.clamp(MIN_MIDPOINT, MAX_MIDPOINT));
|
||||||
}
|
}
|
||||||
SpectrumInputUpdate::InsertMarker { position } => {
|
SliderInputUpdate::InsertMarker { position } => {
|
||||||
let new_index = gradient.insert_stop(position, self.gradient_settings());
|
let new_index = gradient.insert_stop(position, self.gradient_settings());
|
||||||
self.active_marker_index = Some(new_index as u32);
|
self.active_marker_index = Some(new_index as u32);
|
||||||
self.active_marker_is_midpoint = false;
|
self.active_marker_is_midpoint = false;
|
||||||
@@ -422,7 +422,7 @@ impl ColorPickerMessageHandler {
|
|||||||
self.snapshot_old();
|
self.snapshot_old();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SpectrumInputUpdate::InsertDuplicate { index, position } => {
|
SliderInputUpdate::InsertDuplicate { index, position } => {
|
||||||
let source = index as usize;
|
let source = index as usize;
|
||||||
let Some(insert_index) = gradient.duplicate_stop(source, position, self.gradient_cyclic) else {
|
let Some(insert_index) = gradient.duplicate_stop(source, position, self.gradient_cyclic) else {
|
||||||
return;
|
return;
|
||||||
@@ -432,7 +432,7 @@ impl ColorPickerMessageHandler {
|
|||||||
self.active_marker_index = Some(dragged_index as u32);
|
self.active_marker_index = Some(dragged_index as u32);
|
||||||
self.active_marker_is_midpoint = false;
|
self.active_marker_is_midpoint = false;
|
||||||
}
|
}
|
||||||
SpectrumInputUpdate::RemoveDuplicate { index } => {
|
SliderInputUpdate::RemoveDuplicate { index } => {
|
||||||
let anchor = index as usize;
|
let anchor = index as usize;
|
||||||
if anchor >= gradient.len() || gradient.len() <= 2 {
|
if anchor >= gradient.len() || gradient.len() <= 2 {
|
||||||
return;
|
return;
|
||||||
@@ -449,7 +449,7 @@ impl ColorPickerMessageHandler {
|
|||||||
self.active_marker_index = Some(active - 1);
|
self.active_marker_index = Some(active - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SpectrumInputUpdate::DeleteMarker { index } => {
|
SliderInputUpdate::DeleteMarker { index } => {
|
||||||
// Enforce minimum stop count. The gradient editor needs at least 2 stops to remain meaningful.
|
// Enforce minimum stop count. The gradient editor needs at least 2 stops to remain meaningful.
|
||||||
if gradient.len() <= 2 || (index as usize) >= gradient.len() {
|
if gradient.len() <= 2 || (index as usize) >= gradient.len() {
|
||||||
return;
|
return;
|
||||||
@@ -463,10 +463,10 @@ impl ColorPickerMessageHandler {
|
|||||||
self.snapshot_old();
|
self.snapshot_old();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SpectrumInputUpdate::ResetMidpoint { index } => {
|
SliderInputUpdate::ResetMidpoint { index } => {
|
||||||
gradient.reset_midpoint(index as usize);
|
gradient.reset_midpoint(index as usize);
|
||||||
}
|
}
|
||||||
SpectrumInputUpdate::ResetMarker { index } => {
|
SliderInputUpdate::ResetMarker { index } => {
|
||||||
let i = index as usize;
|
let i = index as usize;
|
||||||
let count = gradient.len();
|
let count = gradient.len();
|
||||||
if i >= count {
|
if i >= count {
|
||||||
@@ -483,7 +483,7 @@ impl ColorPickerMessageHandler {
|
|||||||
self.active_marker_index = Some(new_index as u32);
|
self.active_marker_index = Some(new_index as u32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SpectrumInputUpdate::ActiveMarker { .. } => unreachable!("handled above"),
|
SliderInputUpdate::ActiveMarker { .. } => unreachable!("handled above"),
|
||||||
}
|
}
|
||||||
|
|
||||||
responses.add(FrontendMessage::ColorPickerColorChanged {
|
responses.add(FrontendMessage::ColorPickerColorChanged {
|
||||||
@@ -514,10 +514,10 @@ impl ColorPickerMessageHandler {
|
|||||||
if let Some(gradient) = &self.gradient {
|
if let Some(gradient) = &self.gradient {
|
||||||
// For gradient editing, the markers' handle colors mirror their gradient stop colors
|
// For gradient editing, the markers' handle colors mirror their gradient stop colors
|
||||||
let markers = (0..gradient.len())
|
let markers = (0..gradient.len())
|
||||||
.filter_map(|i| Some(SpectrumMarker::new(gradient.position(i, self.gradient_cyclic), gradient.midpoint(i), gradient.color(i)?)))
|
.filter_map(|i| Some(SliderMarker::new(gradient.position(i, self.gradient_cyclic), gradient.midpoint(i), gradient.color(i)?)))
|
||||||
.collect();
|
.collect();
|
||||||
let mut row_widgets = vec![
|
let mut row_widgets = vec![
|
||||||
SpectrumInput::new(GradientStops::from(gradient))
|
SliderInput::new(GradientStops::from(gradient))
|
||||||
.track_space(self.gradient_space)
|
.track_space(self.gradient_space)
|
||||||
.track_cyclic(self.gradient_cyclic)
|
.track_cyclic(self.gradient_cyclic)
|
||||||
.track_hue_direction(self.gradient_hue_direction)
|
.track_hue_direction(self.gradient_hue_direction)
|
||||||
@@ -531,7 +531,7 @@ impl ColorPickerMessageHandler {
|
|||||||
.allow_reorder(true)
|
.allow_reorder(true)
|
||||||
.allow_select(true)
|
.allow_select(true)
|
||||||
.disabled(self.disabled)
|
.disabled(self.disabled)
|
||||||
.on_update(|update: &SpectrumInputUpdate| ColorPickerMessage::GradientUpdate { update: update.clone() }.into())
|
.on_update(|update: &SliderInputUpdate| ColorPickerMessage::GradientUpdate { update: update.clone() }.into())
|
||||||
.widget_instance(),
|
.widget_instance(),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -556,12 +556,12 @@ impl ColorPickerMessageHandler {
|
|||||||
return Message::NoOp;
|
return Message::NoOp;
|
||||||
};
|
};
|
||||||
let update = if is_midpoint {
|
let update = if is_midpoint {
|
||||||
SpectrumInputUpdate::MoveMidpoint {
|
SliderInputUpdate::MoveMidpoint {
|
||||||
index: captured_index,
|
index: captured_index,
|
||||||
position: new_value / 100.,
|
position: new_value / 100.,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SpectrumInputUpdate::MoveMarker {
|
SliderInputUpdate::MoveMarker {
|
||||||
index: captured_index,
|
index: captured_index,
|
||||||
position: new_value / 100.,
|
position: new_value / 100.,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,20 +255,20 @@ impl LayoutMessageHandler {
|
|||||||
|
|
||||||
responses.add(callback_message);
|
responses.add(callback_message);
|
||||||
}
|
}
|
||||||
Widget::SpectrumInput(spectrum_input) => {
|
Widget::SliderInput(slider_input) => {
|
||||||
let callback_message = match action {
|
let callback_message = match action {
|
||||||
WidgetValueAction::Commit => (spectrum_input.on_commit.callback)(&()),
|
WidgetValueAction::Commit => (slider_input.on_commit.callback)(&()),
|
||||||
WidgetValueAction::Update => {
|
WidgetValueAction::Update => {
|
||||||
let Ok(update) = serde_json::from_value::<SpectrumInputUpdate>(value) else {
|
let Ok(update) = serde_json::from_value::<SliderInputUpdate>(value) else {
|
||||||
warn!("SpectrumInput update was not able to be parsed as SpectrumInputUpdate");
|
warn!("SliderInput update was not able to be parsed as SliderInputUpdate");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
// Don't mutate the stored widget here: leaving its old values lets the layout diff detect a change
|
// Don't mutate the stored widget here: leaving its old values lets the layout diff detect a change
|
||||||
// when the new layout is rebuilt with the updated state. Otherwise the frontend's stored layout
|
// when the new layout is rebuilt with the updated state. Otherwise the frontend's stored layout
|
||||||
// keeps stale values for `activeMarkerIndex`, etc., and any other widget's diff (e.g. the position
|
// keeps stale values for `activeMarkerIndex`, etc., and any other widget's diff (e.g. the position
|
||||||
// NumberInput) will trigger Svelte to re-spread those stale props onto SpectrumInput, clobbering
|
// NumberInput) will trigger Svelte to re-spread those stale props onto SliderInput, clobbering
|
||||||
// its local `activeMarkerIndex` and making subsequent drags target the wrong stop.
|
// its local `activeMarkerIndex` and making subsequent drags target the wrong stop.
|
||||||
(spectrum_input.on_update.callback)(&update)
|
(slider_input.on_update.callback)(&update)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -565,20 +565,20 @@ fn populate_computed_display_fields(layout: &mut Layout) {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
Widget::SpectrumInput(spectrum_input) => {
|
Widget::SliderInput(slider_input) => {
|
||||||
// The track strip spans exactly 0 to 1, which no spread affects, so the widget carries no spread of its own
|
// The track strip spans exactly 0 to 1, which no spread affects, so the widget carries no spread of its own
|
||||||
let settings = graphene_std::vector::style::GradientSettings {
|
let settings = graphene_std::vector::style::GradientSettings {
|
||||||
spread: Default::default(),
|
spread: Default::default(),
|
||||||
cyclic: spectrum_input.track_cyclic,
|
cyclic: slider_input.track_cyclic,
|
||||||
space: spectrum_input.track_space,
|
space: slider_input.track_space,
|
||||||
hue_direction: spectrum_input.track_hue_direction,
|
hue_direction: slider_input.track_hue_direction,
|
||||||
interpolation: spectrum_input.track_interpolation,
|
interpolation: slider_input.track_interpolation,
|
||||||
};
|
};
|
||||||
let track_gradient = graphene_std::vector::style::Gradient::from(&spectrum_input.track);
|
let track_gradient = graphene_std::vector::style::Gradient::from(&slider_input.track);
|
||||||
spectrum_input.track_samples = track_gradient
|
slider_input.track_samples = track_gradient
|
||||||
.interpolated_samples_or_black(settings)
|
.interpolated_samples_or_black(settings)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(position, color, _)| SpectrumSample::new(position, color))
|
.map(|(position, color, _)| SliderSample::new(position, color))
|
||||||
.collect();
|
.collect();
|
||||||
// The end caps sample the track's boundary colors, which a cyclic wrap makes the wrapped interval's boundary-crossing color rather than the outermost stops'
|
// The end caps sample the track's boundary colors, which a cyclic wrap makes the wrapped interval's boundary-crossing color rather than the outermost stops'
|
||||||
let track_evaluator = track_gradient.evaluator(settings);
|
let track_evaluator = track_gradient.evaluator(settings);
|
||||||
@@ -586,8 +586,8 @@ fn populate_computed_display_fields(layout: &mut Layout) {
|
|||||||
let color = track_evaluator.evaluate(t);
|
let color = track_evaluator.evaluate(t);
|
||||||
SRGBA8::from(color).to_css_hex()
|
SRGBA8::from(color).to_css_hex()
|
||||||
};
|
};
|
||||||
spectrum_input.track_start_css = cap(0.);
|
slider_input.track_start_css = cap(0.);
|
||||||
spectrum_input.track_end_css = cap(1.);
|
slider_input.track_end_css = cap(1.);
|
||||||
}
|
}
|
||||||
Widget::ColorComparisonInput(comparison) => {
|
Widget::ColorComparisonInput(comparison) => {
|
||||||
let contrasting = |color: Option<SRGBA8>| color.map_or(SRGBA8::BLACK, |color| color.contrasting_text_color()).to_css_hex();
|
let contrasting = |color: Option<SRGBA8>| color.map_or(SRGBA8::BLACK, |color| color.contrasting_text_color()).to_css_hex();
|
||||||
|
|||||||
@@ -470,7 +470,7 @@ impl LayoutGroup {
|
|||||||
| Widget::ParameterExposeButton(_)
|
| Widget::ParameterExposeButton(_)
|
||||||
| Widget::ColorComparisonInput(_)
|
| Widget::ColorComparisonInput(_)
|
||||||
| Widget::ColorPresetsInput(_)
|
| Widget::ColorPresetsInput(_)
|
||||||
| Widget::SpectrumInput(_)
|
| Widget::SliderInput(_)
|
||||||
| Widget::TransferCurveInput(_)
|
| Widget::TransferCurveInput(_)
|
||||||
| Widget::VisualColorPickersInput(_) => continue,
|
| Widget::VisualColorPickersInput(_) => continue,
|
||||||
};
|
};
|
||||||
@@ -823,7 +823,7 @@ pub enum Widget {
|
|||||||
PopoverButton(PopoverButton),
|
PopoverButton(PopoverButton),
|
||||||
RadioInput(RadioInput),
|
RadioInput(RadioInput),
|
||||||
Separator(Separator),
|
Separator(Separator),
|
||||||
SpectrumInput(SpectrumInput),
|
SliderInput(SliderInput),
|
||||||
TextAreaInput(TextAreaInput),
|
TextAreaInput(TextAreaInput),
|
||||||
TextButton(TextButton),
|
TextButton(TextButton),
|
||||||
TextInput(TextInput),
|
TextInput(TextInput),
|
||||||
@@ -888,7 +888,7 @@ impl DiffUpdate {
|
|||||||
| Widget::WorkingColorsInput(_)
|
| Widget::WorkingColorsInput(_)
|
||||||
| Widget::ColorComparisonInput(_)
|
| Widget::ColorComparisonInput(_)
|
||||||
| Widget::ColorPresetsInput(_)
|
| Widget::ColorPresetsInput(_)
|
||||||
| Widget::SpectrumInput(_)
|
| Widget::SliderInput(_)
|
||||||
| Widget::TransferCurveInput(_)
|
| Widget::TransferCurveInput(_)
|
||||||
| Widget::VisualColorPickersInput(_) => None,
|
| Widget::VisualColorPickersInput(_) => None,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -624,7 +624,7 @@ pub enum TransferCurveInputUpdate {
|
|||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||||
#[derive(Clone, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder)]
|
#[derive(Clone, Derivative, serde::Serialize, serde::Deserialize, WidgetBuilder)]
|
||||||
#[derivative(Debug, PartialEq, Default)]
|
#[derivative(Debug, PartialEq, Default)]
|
||||||
pub struct SpectrumInput {
|
pub struct SliderInput {
|
||||||
// Content
|
// Content
|
||||||
/// The colored gradient drawn behind the markers (display-only, caller-owned).
|
/// The colored gradient drawn behind the markers (display-only, caller-owned).
|
||||||
#[widget_builder(constructor)]
|
#[widget_builder(constructor)]
|
||||||
@@ -644,7 +644,7 @@ pub struct SpectrumInput {
|
|||||||
/// Straight-alpha samples the frontend draws as the stops of an SVG gradient filling the track strip. Auto-populated from `track` at layout-send time.
|
/// Straight-alpha samples the frontend draws as the stops of an SVG gradient filling the track strip. Auto-populated from `track` at layout-send time.
|
||||||
#[serde(rename = "trackSamples")]
|
#[serde(rename = "trackSamples")]
|
||||||
#[widget_builder(skip)]
|
#[widget_builder(skip)]
|
||||||
pub track_samples: Vec<SpectrumSample>,
|
pub track_samples: Vec<SliderSample>,
|
||||||
/// Hex string for the track strip's leftmost solid-color end-cap. Auto-populated by evaluating `track` at position 0.
|
/// Hex string for the track strip's leftmost solid-color end-cap. Auto-populated by evaluating `track` at position 0.
|
||||||
#[serde(rename = "trackStartCSS")]
|
#[serde(rename = "trackStartCSS")]
|
||||||
#[widget_builder(skip)]
|
#[widget_builder(skip)]
|
||||||
@@ -654,7 +654,7 @@ pub struct SpectrumInput {
|
|||||||
#[widget_builder(skip)]
|
#[widget_builder(skip)]
|
||||||
pub track_end_css: String,
|
pub track_end_css: String,
|
||||||
/// The handles the user can drag along the track. Their handle colors are caller-owned (e.g., for a gradient editor they follow the stop colors, for a "Shadows/Midpoints/Highlights" widget they're hardcoded).
|
/// The handles the user can drag along the track. Their handle colors are caller-owned (e.g., for a gradient editor they follow the stop colors, for a "Shadows/Midpoints/Highlights" widget they're hardcoded).
|
||||||
pub markers: Vec<SpectrumMarker>,
|
pub markers: Vec<SliderMarker>,
|
||||||
#[serde(rename = "activeMarkerIndex")]
|
#[serde(rename = "activeMarkerIndex")]
|
||||||
pub active_marker_index: Option<u32>,
|
pub active_marker_index: Option<u32>,
|
||||||
#[serde(rename = "activeMarkerIsMidpoint")]
|
#[serde(rename = "activeMarkerIsMidpoint")]
|
||||||
@@ -689,7 +689,7 @@ pub struct SpectrumInput {
|
|||||||
// Callbacks
|
// Callbacks
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
pub on_update: WidgetCallback<SpectrumInputUpdate>,
|
pub on_update: WidgetCallback<SliderInputUpdate>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
#[derivative(Debug = "ignore", PartialEq = "ignore")]
|
||||||
pub on_commit: WidgetCallback<()>,
|
pub on_commit: WidgetCallback<()>,
|
||||||
@@ -697,12 +697,12 @@ pub struct SpectrumInput {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||||
#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct SpectrumMarker {
|
pub struct SliderMarker {
|
||||||
/// Position along the track, normally 0..1. A shifted or stretched non-cyclic ramp can push it outside, where it is not drawn.
|
/// Position along the track, normally 0..1. A shifted or stretched non-cyclic ramp can push it outside, where it is not drawn.
|
||||||
position: f64,
|
position: f64,
|
||||||
/// Midpoint (0..1) of the interval to the next marker, used only with `show_midpoints`. The last marker's midpoint spans the wrap of a cyclic track, or is otherwise ignored.
|
/// Midpoint (0..1) of the interval to the next marker, used only with `show_midpoints`. The last marker's midpoint spans the wrap of a cyclic track, or is otherwise ignored.
|
||||||
midpoint: f64,
|
midpoint: f64,
|
||||||
/// CSS color string for the marker handle's fill. Set via `SpectrumMarker::new` from a linear [`Color`],
|
/// CSS color string for the marker handle's fill. Set via `SliderMarker::new` from a linear [`Color`],
|
||||||
/// discarding any transparency so the handle always shows the RGB that steers the interpolation.
|
/// discarding any transparency so the handle always shows the RGB that steers the interpolation.
|
||||||
#[serde(rename = "handleColorCSS")]
|
#[serde(rename = "handleColorCSS")]
|
||||||
handle_color_css: String,
|
handle_color_css: String,
|
||||||
@@ -717,7 +717,7 @@ pub struct SpectrumMarker {
|
|||||||
between_neighbors: bool,
|
between_neighbors: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpectrumMarker {
|
impl SliderMarker {
|
||||||
pub fn new(position: f64, midpoint: f64, handle_color: Color) -> Self {
|
pub fn new(position: f64, midpoint: f64, handle_color: Color) -> Self {
|
||||||
let handle_color_css = format!("#{}", SRGBA8::from(handle_color).to_rgb_hex());
|
let handle_color_css = format!("#{}", SRGBA8::from(handle_color).to_rgb_hex());
|
||||||
Self {
|
Self {
|
||||||
@@ -748,8 +748,8 @@ impl SpectrumMarker {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||||
#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct SpectrumSample {
|
pub struct SliderSample {
|
||||||
/// Position (0..1) of the sample along the spectrum track, drawn as the SVG stop's `offset`.
|
/// Position (0..1) of the sample along the slider track, drawn as the SVG stop's `offset`.
|
||||||
position: f64,
|
position: f64,
|
||||||
/// `#rrggbb` hex of the sample's color, drawn as the SVG stop's `stop-color`.
|
/// `#rrggbb` hex of the sample's color, drawn as the SVG stop's `stop-color`.
|
||||||
color: String,
|
color: String,
|
||||||
@@ -757,7 +757,7 @@ pub struct SpectrumSample {
|
|||||||
alpha: f32,
|
alpha: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpectrumSample {
|
impl SliderSample {
|
||||||
pub fn new(position: f64, color: Color) -> Self {
|
pub fn new(position: f64, color: Color) -> Self {
|
||||||
Self {
|
Self {
|
||||||
position,
|
position,
|
||||||
@@ -769,7 +769,7 @@ impl SpectrumSample {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
|
||||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum SpectrumInputUpdate {
|
pub enum SliderInputUpdate {
|
||||||
MoveMarker {
|
MoveMarker {
|
||||||
index: u32,
|
index: u32,
|
||||||
position: f64,
|
position: f64,
|
||||||
|
|||||||
@@ -1346,12 +1346,12 @@ pub fn query_assign_colors_randomize(node_id: NodeId, context: &NodePropertiesCo
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 2-stop black-to-white gradient track for spectrum sliders that map a value to a grayscale axis.
|
/// 2-stop black-to-white gradient track for sliders that map a value to a grayscale axis.
|
||||||
fn bw_track() -> Gradient {
|
fn bw_track() -> Gradient {
|
||||||
Gradient::from(vec![Color::BLACK, Color::WHITE])
|
Gradient::from(vec![Color::BLACK, Color::WHITE])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 3-stop black-to-color-to-white gradient track for spectrum sliders that map a value to a hue's full luminance range.
|
/// 3-stop black-to-color-to-white gradient track for sliders that map a value to a hue's full luminance range.
|
||||||
fn color_track(color: Color) -> Gradient {
|
fn color_track(color: Color) -> Gradient {
|
||||||
Gradient::from(vec![Color::BLACK, color, Color::WHITE])
|
Gradient::from(vec![Color::BLACK, color, Color::WHITE])
|
||||||
}
|
}
|
||||||
@@ -1369,7 +1369,7 @@ pub(crate) fn brightness_contrast_properties(node_id: NodeId, context: &mut Node
|
|||||||
let brightness_min = if use_classic_value { -100. } else { -150. };
|
let brightness_min = if use_classic_value { -100. } else { -150. };
|
||||||
let brightness_max = if use_classic_value { 100. } else { 150. };
|
let brightness_max = if use_classic_value { 100. } else { 150. };
|
||||||
|
|
||||||
let brightness = spectrum_slider_row(
|
let brightness = gradient_slider_row(
|
||||||
node_id,
|
node_id,
|
||||||
context,
|
context,
|
||||||
BrightnessInput,
|
BrightnessInput,
|
||||||
@@ -1385,7 +1385,7 @@ pub(crate) fn brightness_contrast_properties(node_id: NodeId, context: &mut Node
|
|||||||
let zero_position = -contrast_min / (100. - contrast_min);
|
let zero_position = -contrast_min / (100. - contrast_min);
|
||||||
let mut contrast_track = Gradient::from(vec![Color::MIDDLE_GRAY, Color::BLACK, Color::MIDDLE_GRAY]);
|
let mut contrast_track = Gradient::from(vec![Color::MIDDLE_GRAY, Color::BLACK, Color::MIDDLE_GRAY]);
|
||||||
contrast_track.set_positions(&[0., zero_position, 1.]);
|
contrast_track.set_positions(&[0., zero_position, 1.]);
|
||||||
let contrast = spectrum_slider_row(
|
let contrast = gradient_slider_row(
|
||||||
node_id,
|
node_id,
|
||||||
context,
|
context,
|
||||||
ContrastInput,
|
ContrastInput,
|
||||||
@@ -1402,7 +1402,7 @@ pub(crate) fn brightness_contrast_properties(node_id: NodeId, context: &mut Node
|
|||||||
let mut layout = vec![brightness, contrast, LayoutGroup::row(use_classic)];
|
let mut layout = vec![brightness, contrast, LayoutGroup::row(use_classic)];
|
||||||
if use_classic_value {
|
if use_classic_value {
|
||||||
let number_input = NumberInput::default().mode_increment().min(0.).max(255.);
|
let number_input = NumberInput::default().mode_increment().min(0.).max(255.);
|
||||||
layout.push(spectrum_slider_row(node_id, context, ClassicPivotInput, bw_track(), Color::WHITE, 0., 255., 127., number_input));
|
layout.push(gradient_slider_row(node_id, context, ClassicPivotInput, bw_track(), Color::WHITE, 0., 255., 127., number_input));
|
||||||
}
|
}
|
||||||
|
|
||||||
layout
|
layout
|
||||||
@@ -1481,22 +1481,22 @@ pub(crate) fn levels_properties(node_id: NodeId, context: &mut NodePropertiesCon
|
|||||||
};
|
};
|
||||||
|
|
||||||
let input_range_params = [
|
let input_range_params = [
|
||||||
SpectrumSectionParam::new(shadows, Color::BLACK, 0., MarkerScale::Percent),
|
SliderSectionParam::new(shadows, Color::BLACK, 0., MarkerScale::Percent),
|
||||||
SpectrumSectionParam::new(midtones, Color::MIDDLE_GRAY, 1., MarkerScale::Gamma).between_neighbors(),
|
SliderSectionParam::new(midtones, Color::MIDDLE_GRAY, 1., MarkerScale::Gamma).between_neighbors(),
|
||||||
SpectrumSectionParam::new(highlights, Color::WHITE, 100., MarkerScale::Percent),
|
SliderSectionParam::new(highlights, Color::WHITE, 100., MarkerScale::Percent),
|
||||||
];
|
];
|
||||||
let output_range_params = [
|
let output_range_params = [
|
||||||
SpectrumSectionParam::new(output_minimums, Color::BLACK, 0., MarkerScale::Percent),
|
SliderSectionParam::new(output_minimums, Color::BLACK, 0., MarkerScale::Percent),
|
||||||
SpectrumSectionParam::new(output_maximums, Color::WHITE, 100., MarkerScale::Percent),
|
SliderSectionParam::new(output_maximums, Color::WHITE, 100., MarkerScale::Percent),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut layout = vec![channel];
|
let mut layout = vec![channel];
|
||||||
build_shared_spectrum_section(node_id, context, &bw_track(), &input_range_params, &mut layout);
|
build_shared_slider_section(node_id, context, &bw_track(), &input_range_params, &mut layout);
|
||||||
build_shared_spectrum_section(node_id, context, &bw_track(), &output_range_params, &mut layout);
|
build_shared_slider_section(node_id, context, &bw_track(), &output_range_params, &mut layout);
|
||||||
layout
|
layout
|
||||||
}
|
}
|
||||||
|
|
||||||
/// How a shared spectrum marker's value maps onto its track.
|
/// How a shared slider marker's value maps onto its track.
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum MarkerScale {
|
enum MarkerScale {
|
||||||
/// A 0..100 percentage, placed linearly.
|
/// A 0..100 percentage, placed linearly.
|
||||||
@@ -1545,8 +1545,8 @@ impl MarkerScale {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One parameter of a shared spectrum section and how its marker sits on the track.
|
/// One parameter of a shared slider section and how its marker sits on the track.
|
||||||
struct SpectrumSectionParam {
|
struct SliderSectionParam {
|
||||||
parameter: ParameterRef,
|
parameter: ParameterRef,
|
||||||
handle_color: Color,
|
handle_color: Color,
|
||||||
/// The value a double-click resets to.
|
/// The value a double-click resets to.
|
||||||
@@ -1560,7 +1560,7 @@ struct SpectrumSectionParam {
|
|||||||
between_neighbors: bool,
|
between_neighbors: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpectrumSectionParam {
|
impl SliderSectionParam {
|
||||||
fn new(parameter: impl Into<ParameterRef>, handle_color: Color, default_value: f64, scale: MarkerScale) -> Self {
|
fn new(parameter: impl Into<ParameterRef>, handle_color: Color, default_value: f64, scale: MarkerScale) -> Self {
|
||||||
Self {
|
Self {
|
||||||
parameter: parameter.into(),
|
parameter: parameter.into(),
|
||||||
@@ -1589,10 +1589,10 @@ impl SpectrumSectionParam {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append a section of related parameters as rows: a shared spectrum over `track` (with one marker per non-exposed parameter) sits on the first non-exposed row
|
/// Append a section of related parameters as rows: a shared slider over `track` (with one marker per non-exposed parameter) sits on the first non-exposed row
|
||||||
/// alongside its 60px number input, and the remaining non-exposed rows show only their 60px number input. Exposed parameters render as the standard exposed-row display.
|
/// alongside its 60px number input, and the remaining non-exposed rows show only their 60px number input. Exposed parameters render as the standard exposed-row display.
|
||||||
/// Marker positions are clamped to non-decreasing display order so they never visually cross even if the underlying values do.
|
/// Marker positions are clamped to non-decreasing display order so they never visually cross even if the underlying values do.
|
||||||
fn build_shared_spectrum_section(node_id: NodeId, context: &mut NodePropertiesContext, track: &Gradient, params: &[SpectrumSectionParam], layout: &mut Vec<LayoutGroup>) {
|
fn build_shared_slider_section(node_id: NodeId, context: &mut NodePropertiesContext, track: &Gradient, params: &[SliderSectionParam], layout: &mut Vec<LayoutGroup>) {
|
||||||
// Snapshot exposure and values before the mutable-borrow loop
|
// Snapshot exposure and values before the mutable-borrow loop
|
||||||
let exposure_and_value: Vec<(bool, f64)> = match get_document_node(node_id, context) {
|
let exposure_and_value: Vec<(bool, f64)> = match get_document_node(node_id, context) {
|
||||||
Ok(document_node) => params
|
Ok(document_node) => params
|
||||||
@@ -1608,7 +1608,7 @@ fn build_shared_spectrum_section(node_id: NodeId, context: &mut NodePropertiesCo
|
|||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
log::error!("Could not get document node in build_shared_spectrum_section: {err}");
|
log::error!("Could not get document node in build_shared_slider_section: {err}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1655,12 +1655,12 @@ fn build_shared_spectrum_section(node_id: NodeId, context: &mut NodePropertiesCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let spectrum_markers: Vec<SpectrumMarker> = marker_positions
|
let slider_markers: Vec<SliderMarker> = marker_positions
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&marker_colors_and_links)
|
.zip(&marker_colors_and_links)
|
||||||
.zip(&marker_between)
|
.zip(&marker_between)
|
||||||
.map(|((&position, &(handle_color, paired, dashed)), &between)| {
|
.map(|((&position, &(handle_color, paired, dashed)), &between)| {
|
||||||
let mut marker = SpectrumMarker::new(position, 0.5, handle_color);
|
let mut marker = SliderMarker::new(position, 0.5, handle_color);
|
||||||
if paired {
|
if paired {
|
||||||
marker = marker.pair_with_next();
|
marker = marker.pair_with_next();
|
||||||
}
|
}
|
||||||
@@ -1674,11 +1674,11 @@ fn build_shared_spectrum_section(node_id: NodeId, context: &mut NodePropertiesCo
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Build the shared spectrum widget (placed on the first non-exposed row)
|
// Build the shared slider widget (placed on the first non-exposed row)
|
||||||
let spectrum_widget = (!spectrum_markers.is_empty()).then(|| {
|
let slider_widget = (!slider_markers.is_empty()).then(|| {
|
||||||
SpectrumInput::new(GradientStops::from(track))
|
SliderInput::new(GradientStops::from(track))
|
||||||
.track_space(GradientSpace::RgbGamma)
|
.track_space(GradientSpace::RgbGamma)
|
||||||
.markers(spectrum_markers)
|
.markers(slider_markers)
|
||||||
.show_midpoints(false)
|
.show_midpoints(false)
|
||||||
.allow_insert(false)
|
.allow_insert(false)
|
||||||
.allow_delete(false)
|
.allow_delete(false)
|
||||||
@@ -1691,9 +1691,9 @@ fn build_shared_spectrum_section(node_id: NodeId, context: &mut NodePropertiesCo
|
|||||||
let marker_scales = marker_scales.clone();
|
let marker_scales = marker_scales.clone();
|
||||||
let marker_positions = marker_positions.clone();
|
let marker_positions = marker_positions.clone();
|
||||||
let marker_between = marker_between.clone();
|
let marker_between = marker_between.clone();
|
||||||
move |update: &SpectrumInputUpdate| {
|
move |update: &SliderInputUpdate| {
|
||||||
let i = match update {
|
let i = match update {
|
||||||
SpectrumInputUpdate::MoveMarker { index, .. } | SpectrumInputUpdate::ResetMarker { index } => *index as usize,
|
SliderInputUpdate::MoveMarker { index, .. } | SliderInputUpdate::ResetMarker { index } => *index as usize,
|
||||||
_ => return Message::NoOp,
|
_ => return Message::NoOp,
|
||||||
};
|
};
|
||||||
let (Some(&input_index), Some(&scale), Some(&between), Some(&default_position)) =
|
let (Some(&input_index), Some(&scale), Some(&between), Some(&default_position)) =
|
||||||
@@ -1709,17 +1709,17 @@ fn build_shared_spectrum_section(node_id: NodeId, context: &mut NodePropertiesCo
|
|||||||
let right = (i + 1..marker_positions.len()).find(|&j| bounding(j)).map_or(1., |j| marker_positions[j]);
|
let right = (i + 1..marker_positions.len()).find(|&j| bounding(j)).map_or(1., |j| marker_positions[j]);
|
||||||
|
|
||||||
let scale_position = match update {
|
let scale_position = match update {
|
||||||
SpectrumInputUpdate::MoveMarker { position, .. } if between => {
|
SliderInputUpdate::MoveMarker { position, .. } if between => {
|
||||||
let span = right - left;
|
let span = right - left;
|
||||||
if span <= f64::EPSILON {
|
if span <= f64::EPSILON {
|
||||||
return Message::NoOp;
|
return Message::NoOp;
|
||||||
}
|
}
|
||||||
((position - left) / span).clamp(0., 1.)
|
((position - left) / span).clamp(0., 1.)
|
||||||
}
|
}
|
||||||
SpectrumInputUpdate::MoveMarker { position, .. } => *position,
|
SliderInputUpdate::MoveMarker { position, .. } => *position,
|
||||||
// A default that would cross a neighbor falls back to the midpoint between them
|
// A default that would cross a neighbor falls back to the midpoint between them
|
||||||
SpectrumInputUpdate::ResetMarker { .. } if between || cyclic || (left..=right).contains(&default_position) => default_position,
|
SliderInputUpdate::ResetMarker { .. } if between || cyclic || (left..=right).contains(&default_position) => default_position,
|
||||||
SpectrumInputUpdate::ResetMarker { .. } => (left + right) / 2.,
|
SliderInputUpdate::ResetMarker { .. } => (left + right) / 2.,
|
||||||
_ => return Message::NoOp,
|
_ => return Message::NoOp,
|
||||||
};
|
};
|
||||||
NodeGraphMessage::SetInputValue {
|
NodeGraphMessage::SetInputValue {
|
||||||
@@ -1733,9 +1733,9 @@ fn build_shared_spectrum_section(node_id: NodeId, context: &mut NodePropertiesCo
|
|||||||
.on_commit(commit_value)
|
.on_commit(commit_value)
|
||||||
.widget_instance()
|
.widget_instance()
|
||||||
});
|
});
|
||||||
let spectrum_owner = marker_input_indices.first().copied();
|
let slider_owner = marker_input_indices.first().copied();
|
||||||
|
|
||||||
// One row per parameter: first non-exposed carries the shared spectrum, others get just a number input
|
// One row per parameter: first non-exposed carries the shared slider, others get just a number input
|
||||||
for (i, param) in params.iter().enumerate() {
|
for (i, param) in params.iter().enumerate() {
|
||||||
let (exposed, current) = exposure_and_value[i];
|
let (exposed, current) = exposure_and_value[i];
|
||||||
let input_index = param.parameter.input_index;
|
let input_index = param.parameter.input_index;
|
||||||
@@ -1748,10 +1748,10 @@ fn build_shared_spectrum_section(node_id: NodeId, context: &mut NodePropertiesCo
|
|||||||
let mut row = start_widgets(&ParameterWidgetsInfo::at_index(node_id, input_index, true, context));
|
let mut row = start_widgets(&ParameterWidgetsInfo::at_index(node_id, input_index, true, context));
|
||||||
row.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
|
row.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
|
||||||
|
|
||||||
if Some(input_index) == spectrum_owner
|
if Some(input_index) == slider_owner
|
||||||
&& let Some(spectrum) = &spectrum_widget
|
&& let Some(slider) = &slider_widget
|
||||||
{
|
{
|
||||||
row.push(spectrum.clone());
|
row.push(slider.clone());
|
||||||
row.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
|
row.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1898,7 +1898,7 @@ pub(crate) fn hue_saturation_properties(node_id: NodeId, context: &mut NodePrope
|
|||||||
let mut layout = vec![enum_choice::<HueSaturationRange>().for_socket(range_info).disabled(colorize_value).property_row()];
|
let mut layout = vec![enum_choice::<HueSaturationRange>().for_socket(range_info).disabled(colorize_value).property_row()];
|
||||||
|
|
||||||
layout.extend([
|
layout.extend([
|
||||||
spectrum_slider_row(
|
gradient_slider_row(
|
||||||
node_id,
|
node_id,
|
||||||
context,
|
context,
|
||||||
hue,
|
hue,
|
||||||
@@ -1909,7 +1909,7 @@ pub(crate) fn hue_saturation_properties(node_id: NodeId, context: &mut NodePrope
|
|||||||
hue_default,
|
hue_default,
|
||||||
NumberInput::default().mode_increment().unit("°").min(hue_min).max(hue_max),
|
NumberInput::default().mode_increment().unit("°").min(hue_min).max(hue_max),
|
||||||
),
|
),
|
||||||
spectrum_slider_row(
|
gradient_slider_row(
|
||||||
node_id,
|
node_id,
|
||||||
context,
|
context,
|
||||||
saturation,
|
saturation,
|
||||||
@@ -1920,7 +1920,7 @@ pub(crate) fn hue_saturation_properties(node_id: NodeId, context: &mut NodePrope
|
|||||||
saturation_default,
|
saturation_default,
|
||||||
NumberInput::default().mode_increment().unit("%").min(saturation_min).max(100.),
|
NumberInput::default().mode_increment().unit("%").min(saturation_min).max(100.),
|
||||||
),
|
),
|
||||||
spectrum_slider_row(
|
gradient_slider_row(
|
||||||
node_id,
|
node_id,
|
||||||
context,
|
context,
|
||||||
lightness,
|
lightness,
|
||||||
@@ -1937,12 +1937,12 @@ pub(crate) fn hue_saturation_properties(node_id: NodeId, context: &mut NodePrope
|
|||||||
if !colorize_value && let (Some(values), Some(defaults)) = (range_values, range_defaults) {
|
if !colorize_value && let (Some(values), Some(defaults)) = (range_values, range_defaults) {
|
||||||
let [falloff_start, range_start, range_end, falloff_end] = values;
|
let [falloff_start, range_start, range_end, falloff_end] = values;
|
||||||
let params = [
|
let params = [
|
||||||
SpectrumSectionParam::new(falloff_start, Color::WHITE, defaults[0], MarkerScale::Degrees).pair_with_next(),
|
SliderSectionParam::new(falloff_start, Color::WHITE, defaults[0], MarkerScale::Degrees).pair_with_next(),
|
||||||
SpectrumSectionParam::new(range_start, Color::WHITE, defaults[1], MarkerScale::Degrees).dash_to_next(),
|
SliderSectionParam::new(range_start, Color::WHITE, defaults[1], MarkerScale::Degrees).dash_to_next(),
|
||||||
SpectrumSectionParam::new(range_end, Color::WHITE, defaults[2], MarkerScale::Degrees).pair_with_next(),
|
SliderSectionParam::new(range_end, Color::WHITE, defaults[2], MarkerScale::Degrees).pair_with_next(),
|
||||||
SpectrumSectionParam::new(falloff_end, Color::WHITE, defaults[3], MarkerScale::Degrees),
|
SliderSectionParam::new(falloff_end, Color::WHITE, defaults[3], MarkerScale::Degrees),
|
||||||
];
|
];
|
||||||
build_shared_spectrum_section(node_id, context, &hue_track, ¶ms, &mut layout);
|
build_shared_slider_section(node_id, context, &hue_track, ¶ms, &mut layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
let colorize = bool_widget(ParameterWidgetsInfo::new(node_id, ColorizeInput, true, context), CheckboxInput::default());
|
let colorize = bool_widget(ParameterWidgetsInfo::new(node_id, ColorizeInput, true, context), CheckboxInput::default());
|
||||||
@@ -1951,7 +1951,7 @@ pub(crate) fn hue_saturation_properties(node_id: NodeId, context: &mut NodePrope
|
|||||||
layout
|
layout
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single-marker `SpectrumInput` over `track` driving the number at `input_index`: the marker sits at `position`, double-click
|
/// A single-marker `SliderInput` over `track` driving the number at `input_index`: the marker sits at `position`, double-click
|
||||||
/// returns it to `default_position`, and each move sets the input to `value_at` the new position.
|
/// returns it to `default_position`, and each move sets the input to `value_at` the new position.
|
||||||
fn value_slider(
|
fn value_slider(
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
@@ -1961,18 +1961,18 @@ fn value_slider(
|
|||||||
position: f64,
|
position: f64,
|
||||||
default_position: Option<f64>,
|
default_position: Option<f64>,
|
||||||
value_at: impl Fn(f64) -> TaggedValue + 'static + Send + Sync,
|
value_at: impl Fn(f64) -> TaggedValue + 'static + Send + Sync,
|
||||||
) -> SpectrumInput {
|
) -> SliderInput {
|
||||||
SpectrumInput::new(track)
|
SliderInput::new(track)
|
||||||
.track_space(GradientSpace::RgbGamma)
|
.track_space(GradientSpace::RgbGamma)
|
||||||
.markers(vec![SpectrumMarker::new(position, 0.5, handle_color)])
|
.markers(vec![SliderMarker::new(position, 0.5, handle_color)])
|
||||||
.show_midpoints(false)
|
.show_midpoints(false)
|
||||||
.allow_insert(false)
|
.allow_insert(false)
|
||||||
.allow_delete(false)
|
.allow_delete(false)
|
||||||
.allow_reorder(false)
|
.allow_reorder(false)
|
||||||
.on_update(move |update: &SpectrumInputUpdate| {
|
.on_update(move |update: &SliderInputUpdate| {
|
||||||
let new_position = match update {
|
let new_position = match update {
|
||||||
SpectrumInputUpdate::MoveMarker { index: 0, position } => Some(*position),
|
SliderInputUpdate::MoveMarker { index: 0, position } => Some(*position),
|
||||||
SpectrumInputUpdate::ResetMarker { index: 0 } => default_position,
|
SliderInputUpdate::ResetMarker { index: 0 } => default_position,
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let Some(new_position) = new_position else { return Message::NoOp };
|
let Some(new_position) = new_position else { return Message::NoOp };
|
||||||
@@ -2048,8 +2048,8 @@ pub(crate) fn range_slider_widget(parameter_widgets_info: ParameterWidgetsInfo,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a row with a single-marker `SpectrumInput` and a 60px `NumberInput`. The marker maps `value_min..value_max` to position 0..1, and double-click resets to `default_value`.
|
/// Build a row with a single-marker `SliderInput` over `track` and a 60px `NumberInput`. The marker maps `value_min..value_max` to position 0..1, and double-click resets to `default_value`.
|
||||||
fn spectrum_slider_row(
|
fn gradient_slider_row(
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
context: &mut NodePropertiesContext,
|
context: &mut NodePropertiesContext,
|
||||||
parameter: impl Into<ParameterRef>,
|
parameter: impl Into<ParameterRef>,
|
||||||
@@ -2069,7 +2069,7 @@ fn spectrum_slider_row(
|
|||||||
.and_then(|input| input.as_non_exposed_value())
|
.and_then(|input| input.as_non_exposed_value())
|
||||||
.and_then(|tagged| if let TaggedValue::F32(value) = tagged { Some(*value as f64) } else { None });
|
.and_then(|tagged| if let TaggedValue::F32(value) = tagged { Some(*value as f64) } else { None });
|
||||||
|
|
||||||
// Only add the spectrum and number widgets when the input is not exposed
|
// Only add the slider and number widgets when the input is not exposed
|
||||||
if let Some(current) = current {
|
if let Some(current) = current {
|
||||||
let slider = SliderRange {
|
let slider = SliderRange {
|
||||||
min: value_min,
|
min: value_min,
|
||||||
@@ -2116,12 +2116,12 @@ pub(crate) fn threshold_properties(node_id: NodeId, context: &mut NodeProperties
|
|||||||
use graphene_std::raster::threshold::*;
|
use graphene_std::raster::threshold::*;
|
||||||
|
|
||||||
let params = [
|
let params = [
|
||||||
SpectrumSectionParam::new(MinLuminanceInput, Color::WHITE, 50., MarkerScale::Percent).dash_to_next(),
|
SliderSectionParam::new(MinLuminanceInput, Color::WHITE, 50., MarkerScale::Percent).dash_to_next(),
|
||||||
SpectrumSectionParam::new(MaxLuminanceInput, Color::WHITE, 100., MarkerScale::Percent),
|
SliderSectionParam::new(MaxLuminanceInput, Color::WHITE, 100., MarkerScale::Percent),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut layout = Vec::with_capacity(2);
|
let mut layout = Vec::with_capacity(2);
|
||||||
build_shared_spectrum_section(node_id, context, &bw_track(), ¶ms, &mut layout);
|
build_shared_slider_section(node_id, context, &bw_track(), ¶ms, &mut layout);
|
||||||
|
|
||||||
layout
|
layout
|
||||||
}
|
}
|
||||||
@@ -2179,7 +2179,7 @@ pub(crate) fn color_balance_properties(node_id: NodeId, context: &mut NodeProper
|
|||||||
|
|
||||||
let mut layout = vec![tone];
|
let mut layout = vec![tone];
|
||||||
for (parameter, track) in parameters.into_iter().zip(tracks) {
|
for (parameter, track) in parameters.into_iter().zip(tracks) {
|
||||||
layout.push(spectrum_slider_row(node_id, context, parameter, track, Color::WHITE, -100., 100., 0., number_input.clone()));
|
layout.push(gradient_slider_row(node_id, context, parameter, track, Color::WHITE, -100., 100., 0., number_input.clone()));
|
||||||
}
|
}
|
||||||
layout.push(LayoutGroup::row(preserve_luminosity));
|
layout.push(LayoutGroup::row(preserve_luminosity));
|
||||||
|
|
||||||
@@ -2204,7 +2204,7 @@ pub(crate) fn black_and_white_properties(node_id: NodeId, context: &mut NodeProp
|
|||||||
(MagentasInput.into(), Color::MAGENTA, 80.),
|
(MagentasInput.into(), Color::MAGENTA, 80.),
|
||||||
];
|
];
|
||||||
for (parameter, color, default) in params {
|
for (parameter, color, default) in params {
|
||||||
layout.push(spectrum_slider_row(
|
layout.push(gradient_slider_row(
|
||||||
node_id,
|
node_id,
|
||||||
context,
|
context,
|
||||||
parameter.clone(),
|
parameter.clone(),
|
||||||
@@ -2268,7 +2268,7 @@ pub(crate) fn channel_mixer_properties(node_id: NodeId, context: &mut NodeProper
|
|||||||
layout.push(output_channel);
|
layout.push(output_channel);
|
||||||
}
|
}
|
||||||
for (i, (parameter, &default)) in parameters.into_iter().zip(defaults.iter()).enumerate() {
|
for (i, (parameter, &default)) in parameters.into_iter().zip(defaults.iter()).enumerate() {
|
||||||
layout.push(spectrum_slider_row(
|
layout.push(gradient_slider_row(
|
||||||
node_id,
|
node_id,
|
||||||
context,
|
context,
|
||||||
parameter,
|
parameter,
|
||||||
@@ -2329,7 +2329,7 @@ pub(crate) fn selective_color_properties(node_id: NodeId, context: &mut NodeProp
|
|||||||
|
|
||||||
let mut layout = vec![colors];
|
let mut layout = vec![colors];
|
||||||
for (i, parameter) in parameters.into_iter().enumerate() {
|
for (i, parameter) in parameters.into_iter().enumerate() {
|
||||||
layout.push(spectrum_slider_row(node_id, context, parameter, tracks[i].clone(), Color::WHITE, -100., 100., 0., number_input.clone()));
|
layout.push(gradient_slider_row(node_id, context, parameter, tracks[i].clone(), Color::WHITE, -100., 100., 0., number_input.clone()));
|
||||||
}
|
}
|
||||||
layout.push(mode);
|
layout.push(mode);
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@
|
|||||||
.pickers-and-gradient .widget-span {
|
.pickers-and-gradient .widget-span {
|
||||||
--row-height: 24px;
|
--row-height: 24px;
|
||||||
|
|
||||||
&:has(.spectrum-input) {
|
&:has(.slider-input) {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
|
|
||||||
.number-input {
|
.number-input {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
import NumberInput from "/src/components/widgets/inputs/NumberInput.svelte";
|
import NumberInput from "/src/components/widgets/inputs/NumberInput.svelte";
|
||||||
import RadioInput from "/src/components/widgets/inputs/RadioInput.svelte";
|
import RadioInput from "/src/components/widgets/inputs/RadioInput.svelte";
|
||||||
import ReferencePointInput from "/src/components/widgets/inputs/ReferencePointInput.svelte";
|
import ReferencePointInput from "/src/components/widgets/inputs/ReferencePointInput.svelte";
|
||||||
import SpectrumInput from "/src/components/widgets/inputs/SpectrumInput.svelte";
|
import SliderInput from "/src/components/widgets/inputs/SliderInput.svelte";
|
||||||
import TextAreaInput from "/src/components/widgets/inputs/TextAreaInput.svelte";
|
import TextAreaInput from "/src/components/widgets/inputs/TextAreaInput.svelte";
|
||||||
import TextInput from "/src/components/widgets/inputs/TextInput.svelte";
|
import TextInput from "/src/components/widgets/inputs/TextInput.svelte";
|
||||||
import TransferCurveInput from "/src/components/widgets/inputs/TransferCurveInput.svelte";
|
import TransferCurveInput from "/src/components/widgets/inputs/TransferCurveInput.svelte";
|
||||||
@@ -243,8 +243,8 @@
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
SpectrumInput: {
|
SliderInput: {
|
||||||
component: SpectrumInput,
|
component: SliderInput,
|
||||||
getProps: (props, index) => ({
|
getProps: (props, index) => ({
|
||||||
...props,
|
...props,
|
||||||
$$events: {
|
$$events: {
|
||||||
|
|||||||
+11
-11
@@ -3,22 +3,22 @@
|
|||||||
import { preventEscapeClosingParentFloatingMenu } from "/src/components/layout/FloatingMenu.svelte";
|
import { preventEscapeClosingParentFloatingMenu } from "/src/components/layout/FloatingMenu.svelte";
|
||||||
import LayoutCol from "/src/components/layout/LayoutCol.svelte";
|
import LayoutCol from "/src/components/layout/LayoutCol.svelte";
|
||||||
import LayoutRow from "/src/components/layout/LayoutRow.svelte";
|
import LayoutRow from "/src/components/layout/LayoutRow.svelte";
|
||||||
import type { GradientInterpolation, SpectrumInputUpdate, SpectrumMarker, SpectrumSample } from "/wrapper/pkg/graphite_wasm_wrapper";
|
import type { GradientInterpolation, SliderInputUpdate, SliderMarker, SliderSample } from "/wrapper/pkg/graphite_wasm_wrapper";
|
||||||
|
|
||||||
const BUTTON_LEFT = 0;
|
const BUTTON_LEFT = 0;
|
||||||
const BUTTON_RIGHT = 2;
|
const BUTTON_RIGHT = 2;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{ update: SpectrumInputUpdate; dragging: boolean }>();
|
const dispatch = createEventDispatcher<{ update: SliderInputUpdate; dragging: boolean }>();
|
||||||
|
|
||||||
// Document-unique `id` for this instance's SVG gradient, referenced by its `url(#...)`
|
// Document-unique `id` for this instance's SVG gradient, referenced by its `url(#...)`
|
||||||
const gradientId = `spectrum-input-gradient-${String(Math.random()).substring(2)}`;
|
const gradientId = `slider-input-gradient-${String(Math.random()).substring(2)}`;
|
||||||
|
|
||||||
export let trackSamples: SpectrumSample[];
|
export let trackSamples: SliderSample[];
|
||||||
export let trackStartCSS: string;
|
export let trackStartCSS: string;
|
||||||
export let trackEndCSS: string;
|
export let trackEndCSS: string;
|
||||||
export let trackCyclic = false;
|
export let trackCyclic = false;
|
||||||
export let trackInterpolation: GradientInterpolation = "Linear";
|
export let trackInterpolation: GradientInterpolation = "Linear";
|
||||||
export let markers: SpectrumMarker[];
|
export let markers: SliderMarker[];
|
||||||
export let activeMarkerIndex: number | undefined = 0;
|
export let activeMarkerIndex: number | undefined = 0;
|
||||||
export let activeMarkerIsMidpoint = false;
|
export let activeMarkerIsMidpoint = false;
|
||||||
export let showMidpoints = true;
|
export let showMidpoints = true;
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
return WHOLE_PATHS;
|
return WHOLE_PATHS;
|
||||||
}
|
}
|
||||||
|
|
||||||
function emit(intent: SpectrumInputUpdate) {
|
function emit(intent: SliderInputUpdate) {
|
||||||
dispatch("update", intent);
|
dispatch("update", intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A marker paired with its successor draws as one marker split down the middle while the two coincide (the successor drawing nothing) and as a half once apart
|
// A marker paired with its successor draws as one marker split down the middle while the two coincide (the successor drawing nothing) and as a half once apart
|
||||||
function markerShape(markers: SpectrumMarker[], index: number): MarkerShape {
|
function markerShape(markers: SliderMarker[], index: number): MarkerShape {
|
||||||
const marker = markers[index];
|
const marker = markers[index];
|
||||||
const previous = markers[index - 1];
|
const previous = markers[index - 1];
|
||||||
const next = markers[index + 1];
|
const next = markers[index + 1];
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The spans from each marker passing `linked` to its successor, which on a wrapping track may cross the track's ends in two pieces
|
// The spans from each marker passing `linked` to its successor, which on a wrapping track may cross the track's ends in two pieces
|
||||||
function markerSpans(markers: SpectrumMarker[], allowWrap: boolean, linked: (marker: SpectrumMarker) => boolean): { index: number; left: number; width: number }[] {
|
function markerSpans(markers: SliderMarker[], allowWrap: boolean, linked: (marker: SliderMarker) => boolean): { index: number; left: number; width: number }[] {
|
||||||
const spans: { index: number; left: number; width: number }[] = [];
|
const spans: { index: number; left: number; width: number }[] = [];
|
||||||
|
|
||||||
markers.forEach((marker, index) => {
|
markers.forEach((marker, index) => {
|
||||||
@@ -616,7 +616,7 @@
|
|||||||
|
|
||||||
// Map midpoint pairs to absolute track positions for rendering the diamond markers.
|
// Map midpoint pairs to absolute track positions for rendering the diamond markers.
|
||||||
// A rendered diamond's index is the index of the interval's left marker, which for the cyclic wrapped interval's diamond is the last marker.
|
// A rendered diamond's index is the index of the interval's left marker, which for the cyclic wrapped interval's diamond is the last marker.
|
||||||
function diamondPositions(markers: SpectrumMarker[], showMidpoints: boolean, trackCyclic: boolean, trackInterpolation: GradientInterpolation): number[] {
|
function diamondPositions(markers: SliderMarker[], showMidpoints: boolean, trackCyclic: boolean, trackInterpolation: GradientInterpolation): number[] {
|
||||||
// A stepped ramp jumps at its stops, so no midpoint has anything to bias
|
// A stepped ramp jumps at its stops, so no midpoint has anything to bias
|
||||||
if (!showMidpoints || trackInterpolation === "Stepped" || markers.length < 2) return [];
|
if (!showMidpoints || trackInterpolation === "Stepped" || markers.length < 2) return [];
|
||||||
const positions = markers.slice(0, -1).map((marker, i) => marker.position + marker.midpoint * (markers[i + 1].position - marker.position));
|
const positions = markers.slice(0, -1).map((marker, i) => marker.position + marker.midpoint * (markers[i + 1].position - marker.position));
|
||||||
@@ -645,7 +645,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<LayoutCol
|
<LayoutCol
|
||||||
class="spectrum-input"
|
class="slider-input"
|
||||||
classes={{ narrow, disabled, "range-slider": rangeSlider }}
|
classes={{ narrow, disabled, "range-slider": rangeSlider }}
|
||||||
styles={{
|
styles={{
|
||||||
"--gradient-start": trackStartCSS,
|
"--gradient-start": trackStartCSS,
|
||||||
@@ -743,7 +743,7 @@
|
|||||||
</LayoutCol>
|
</LayoutCol>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.spectrum-input {
|
.slider-input {
|
||||||
position: relative;
|
position: relative;
|
||||||
--marker-half-width: 6px;
|
--marker-half-width: 6px;
|
||||||
|
|
||||||
Reference in New Issue
Block a user