Add color picker gradient color stop duplication by holding Alt (#4291)

* Add color picker gradient color stop duplication by holding Alt

* Fix bugs

* Bug fix
This commit is contained in:
Keavon Chambers
2026-06-28 17:34:27 -07:00
committed by GitHub
parent a979ccd5bd
commit 244b25708d
5 changed files with 171 additions and 8 deletions

View File

@@ -339,6 +339,31 @@ impl ColorPickerMessageHandler {
self.snapshot_old();
}
}
SpectrumInputUpdate::InsertDuplicate { index, position } => {
let source = index as usize;
let Some(insert_index) = gradient.duplicate_stop(source, position) else { return };
// The dragged stop (the duplication source) stays active. Its index shifts up if the frozen copy landed at or before it.
let dragged_index = if insert_index <= source { source + 1 } else { source };
self.active_marker_index = Some(dragged_index as u32);
self.active_marker_is_midpoint = false;
}
SpectrumInputUpdate::RemoveDuplicate { index } => {
let anchor = index as usize;
if anchor >= gradient.position.len() || gradient.position.len() <= 2 {
return;
}
// Never remove the active (dragged) stop itself, this should only ever target the frozen copy.
if self.active_marker_index == Some(anchor as u32) {
return;
}
gradient.remove(anchor);
// Keep the dragged stop active. Its index shifts down if the removed copy came before it.
if let Some(active) = self.active_marker_index
&& (anchor as u32) < active
{
self.active_marker_index = Some(active - 1);
}
}
SpectrumInputUpdate::DeleteMarker { index } => {
// Enforce minimum stop count. The gradient editor needs at least 2 stops to remain meaningful.
if gradient.position.len() <= 2 || (index as usize) >= gradient.position.len() {

View File

@@ -612,6 +612,16 @@ pub enum SpectrumInputUpdate {
DeleteMarker {
index: u32,
},
/// Insert a copy (same color and midpoint) of the marker at `index` at `position`, keeping the marker at `index` active.
InsertDuplicate {
index: u32,
position: f64,
},
/// Remove the marker at `index` while keeping the currently active marker active (renumbered to account for the removal).
/// Used to un-duplicate when Alt is released mid-drag, deleting the frozen copy left by [`InsertDuplicate`](Self::InsertDuplicate).
RemoveDuplicate {
index: u32,
},
/// Emitted when the user double-clicks a marker. The consumer decides what (if anything) to reset the marker to.
ResetMarker {
index: u32,

View File

@@ -1785,6 +1785,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
responses.add(OverlaysMessage::Draw);
}
if is_stroke_node || is_fill_node || is_shape_generator_node || is_text_node {
responses.add(SelectToolMessage::SelectionChanged);
responses.add(PenToolMessage::SelectionChanged);
responses.add(FreehandToolMessage::SelectionChanged);
responses.add(SplineToolMessage::SelectionChanged);