Rename the SpectrumInput widget to SliderInput (#4541)

Rename the 'SpectrumInput' widget to 'SliderInput'
This commit is contained in:
Keavon Chambers
2026-09-15 20:12:31 -07:00
committed by GitHub
parent 358eb317d2
commit eb4a122322
9 changed files with 127 additions and 127 deletions
@@ -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, &params, &mut layout); build_shared_slider_section(node_id, context, &hue_track, &params, &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(), &params, &mut layout); build_shared_slider_section(node_id, context, &bw_track(), &params, &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: {
@@ -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;