mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 00:38:11 +08:00
Add an in-viewport color picker to the Gradient tool when double-clicking a color stop (#3834)
* Hide batched blocked debug print messages * Implement the color picker on double-clicking stops * Code review
This commit is contained in:
@@ -359,10 +359,15 @@ impl Dispatcher {
|
||||
/// with a discriminant or the entire payload (depending on settings)
|
||||
fn log_message(&self, message: &Message, queues: &[VecDeque<Message>], message_logging_verbosity: MessageLoggingVerbosity) {
|
||||
let discriminant = MessageDiscriminant::from(message);
|
||||
let is_blocked = DEBUG_MESSAGE_BLOCK_LIST.contains(&discriminant) || DEBUG_MESSAGE_ENDING_BLOCK_LIST.iter().any(|blocked_name| discriminant.local_name().ends_with(blocked_name));
|
||||
let is_empty_batched = if let Message::Batched { messages } = message { messages.is_empty() } else { false };
|
||||
let is_blocked =
|
||||
|discriminant| DEBUG_MESSAGE_BLOCK_LIST.contains(&discriminant) || DEBUG_MESSAGE_ENDING_BLOCK_LIST.iter().any(|blocked_name| discriminant.local_name().ends_with(blocked_name));
|
||||
let is_batch_all_blocked = if let Message::Batched { messages } = message {
|
||||
messages.iter().all(|message| is_blocked(MessageDiscriminant::from(message)))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if !is_blocked && !is_empty_batched {
|
||||
if !is_blocked(discriminant) && !is_batch_all_blocked {
|
||||
match message_logging_verbosity {
|
||||
MessageLoggingVerbosity::Off => {}
|
||||
MessageLoggingVerbosity::Names => {
|
||||
|
||||
@@ -151,6 +151,11 @@ pub enum FrontendMessage {
|
||||
#[serde(rename = "documentId")]
|
||||
document_id: DocumentId,
|
||||
},
|
||||
UpdateGradientStopColorPickerPosition {
|
||||
color: Color,
|
||||
x: f64,
|
||||
y: f64,
|
||||
},
|
||||
UpdateImportsExports {
|
||||
/// If the primary import is not visible, then it is None.
|
||||
imports: Vec<Option<FrontendGraphOutput>>,
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
|
||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::{NodeGraphLayer, get_gradient};
|
||||
use crate::messages::tool::common_functionality::snapping::{SnapCandidatePoint, SnapConstraint, SnapData, SnapManager, SnapTypeConfiguration};
|
||||
use graphene_std::raster::color::Color;
|
||||
use graphene_std::vector::style::{Fill, Gradient, GradientStops, GradientType};
|
||||
|
||||
#[derive(Default, ExtractField)]
|
||||
@@ -38,6 +39,10 @@ pub enum GradientToolMessage {
|
||||
PointerMove { constrain_axis: Key, lock_angle: Key },
|
||||
PointerOutsideViewport { constrain_axis: Key, lock_angle: Key },
|
||||
PointerUp,
|
||||
StartTransactionForColorStop,
|
||||
CommitTransactionForColorStop,
|
||||
CloseStopColorPicker,
|
||||
UpdateStopColor { color: Color },
|
||||
UpdateOptions { options: GradientOptionsUpdate },
|
||||
}
|
||||
|
||||
@@ -63,29 +68,59 @@ impl ToolMetadata for GradientTool {
|
||||
#[message_handler_data]
|
||||
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for GradientTool {
|
||||
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
|
||||
let ToolMessage::Gradient(GradientToolMessage::UpdateOptions { options }) = message else {
|
||||
self.fsm_state.process_event(message, &mut self.data, context, &self.options, responses, false);
|
||||
match message {
|
||||
ToolMessage::Gradient(GradientToolMessage::UpdateOptions { options }) => match options {
|
||||
GradientOptionsUpdate::Type(gradient_type) => {
|
||||
self.options.gradient_type = gradient_type;
|
||||
apply_gradient_update(&mut self.data, context, responses, |g| g.gradient_type != gradient_type, |g| g.gradient_type = gradient_type);
|
||||
responses.add(ToolMessage::UpdateHints);
|
||||
responses.add(ToolMessage::UpdateCursor);
|
||||
}
|
||||
GradientOptionsUpdate::ReverseStops => {
|
||||
apply_gradient_update(&mut self.data, context, responses, |_| true, |g| g.stops = g.stops.reversed());
|
||||
}
|
||||
GradientOptionsUpdate::ReverseDirection => {
|
||||
apply_gradient_update(&mut self.data, context, responses, |_| true, |g| std::mem::swap(&mut g.start, &mut g.end));
|
||||
}
|
||||
},
|
||||
ToolMessage::Gradient(GradientToolMessage::StartTransactionForColorStop) => {
|
||||
if self.data.color_picker_transaction_open {
|
||||
responses.add(DocumentMessage::EndTransaction);
|
||||
}
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
self.data.color_picker_transaction_open = true;
|
||||
}
|
||||
ToolMessage::Gradient(GradientToolMessage::CommitTransactionForColorStop) => {
|
||||
if self.data.color_picker_transaction_open {
|
||||
responses.add(DocumentMessage::EndTransaction);
|
||||
self.data.color_picker_transaction_open = false;
|
||||
}
|
||||
}
|
||||
ToolMessage::Gradient(GradientToolMessage::UpdateStopColor { color }) => {
|
||||
if let Some(stop_index) = self.data.color_picker_editing_color_stop
|
||||
&& let Some(selected_gradient) = &mut self.data.selected_gradient
|
||||
&& stop_index < selected_gradient.gradient.stops.color.len()
|
||||
{
|
||||
selected_gradient.gradient.stops.color[stop_index] = color;
|
||||
selected_gradient.render_gradient(responses);
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
}
|
||||
}
|
||||
ToolMessage::Gradient(GradientToolMessage::CloseStopColorPicker) => {
|
||||
if self.data.color_picker_transaction_open {
|
||||
responses.add(DocumentMessage::EndTransaction);
|
||||
self.data.color_picker_transaction_open = false;
|
||||
}
|
||||
self.data.color_picker_editing_color_stop = None;
|
||||
}
|
||||
_ => {
|
||||
self.fsm_state.process_event(message, &mut self.data, context, &self.options, responses, false);
|
||||
|
||||
let has_gradient = has_gradient_on_selected_layers(context.document);
|
||||
if has_gradient != self.data.has_selected_gradient {
|
||||
self.data.has_selected_gradient = has_gradient;
|
||||
responses.add(ToolMessage::RefreshToolOptions);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
match options {
|
||||
GradientOptionsUpdate::Type(gradient_type) => {
|
||||
self.options.gradient_type = gradient_type;
|
||||
apply_gradient_update(&mut self.data, context, responses, |g| g.gradient_type != gradient_type, |g| g.gradient_type = gradient_type);
|
||||
responses.add(ToolMessage::UpdateHints);
|
||||
responses.add(ToolMessage::UpdateCursor);
|
||||
}
|
||||
GradientOptionsUpdate::ReverseStops => {
|
||||
apply_gradient_update(&mut self.data, context, responses, |_| true, |g| g.stops = g.stops.reversed());
|
||||
}
|
||||
GradientOptionsUpdate::ReverseDirection => {
|
||||
apply_gradient_update(&mut self.data, context, responses, |_| true, |g| std::mem::swap(&mut g.start, &mut g.end));
|
||||
let has_gradient = has_gradient_on_selected_layers(context.document);
|
||||
if has_gradient != self.data.has_selected_gradient {
|
||||
self.data.has_selected_gradient = has_gradient;
|
||||
responses.add(ToolMessage::RefreshToolOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -515,6 +550,8 @@ struct GradientToolData {
|
||||
auto_pan_shift: DVec2,
|
||||
gradient_angle: f64,
|
||||
has_selected_gradient: bool,
|
||||
color_picker_editing_color_stop: Option<usize>,
|
||||
color_picker_transaction_open: bool,
|
||||
}
|
||||
|
||||
impl Fsm for GradientToolFsmState {
|
||||
@@ -723,9 +760,31 @@ impl Fsm for GradientToolFsmState {
|
||||
let snap_data = SnapData::new(document, input, viewport);
|
||||
tool_data.snap_manager.draw_overlays(snap_data, &mut overlay_context);
|
||||
|
||||
// Update color picker position if active (keeps it anchored to the stop during pan/zoom)
|
||||
if let Some(stop_index) = tool_data.color_picker_editing_color_stop
|
||||
&& let Some(selected_gradient) = tool_data.selected_gradient.as_ref()
|
||||
&& let Some(layer) = selected_gradient.layer
|
||||
{
|
||||
let transform = gradient_space_transform(layer, document);
|
||||
let gradient = &selected_gradient.gradient;
|
||||
if stop_index < gradient.stops.position.len() {
|
||||
let color = gradient.stops.color[stop_index].to_gamma_srgb();
|
||||
let position = gradient.stops.position[stop_index];
|
||||
let DVec2 { x, y } = transform.transform_point2(gradient.start.lerp(gradient.end, position));
|
||||
responses.add(FrontendMessage::UpdateGradientStopColorPickerPosition { color, x, y });
|
||||
}
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
(GradientToolFsmState::Ready { .. }, GradientToolMessage::SelectionChanged) => {
|
||||
if tool_data.color_picker_editing_color_stop.is_some() {
|
||||
if tool_data.color_picker_transaction_open {
|
||||
responses.add(DocumentMessage::EndTransaction);
|
||||
tool_data.color_picker_transaction_open = false;
|
||||
}
|
||||
tool_data.color_picker_editing_color_stop = None;
|
||||
}
|
||||
tool_data.selected_gradient = None;
|
||||
GradientToolFsmState::Ready {
|
||||
hovering: GradientHoverTarget::None,
|
||||
@@ -737,11 +796,45 @@ impl Fsm for GradientToolFsmState {
|
||||
let drag_start_viewport = document.metadata().document_to_viewport.transform_point2(tool_data.drag_start);
|
||||
if input.mouse.position.distance(drag_start_viewport) <= DRAG_THRESHOLD
|
||||
&& let Some(selected_gradient) = &mut tool_data.selected_gradient
|
||||
&& let GradientDragTarget::Midpoint(index) = selected_gradient.dragging
|
||||
{
|
||||
selected_gradient.gradient.stops.midpoint[index] = 0.5;
|
||||
selected_gradient.render_gradient(responses);
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
match selected_gradient.dragging {
|
||||
GradientDragTarget::Midpoint(index) => {
|
||||
selected_gradient.gradient.stops.midpoint[index] = 0.5;
|
||||
selected_gradient.render_gradient(responses);
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
}
|
||||
GradientDragTarget::Start | GradientDragTarget::End | GradientDragTarget::Stop(_) => {
|
||||
// Find the stop index from the drag target
|
||||
let stop_index = match selected_gradient.dragging {
|
||||
GradientDragTarget::Stop(i) => Some(i),
|
||||
GradientDragTarget::Start => selected_gradient.gradient.stops.position.iter().position(|&p| p.abs() < f64::EPSILON * 1000.),
|
||||
GradientDragTarget::End => selected_gradient.gradient.stops.position.iter().position(|&p| (1. - p).abs() < f64::EPSILON * 1000.),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(stop_index) = stop_index
|
||||
&& stop_index < selected_gradient.gradient.stops.color.len()
|
||||
{
|
||||
// Dismiss any existing color picker first
|
||||
if tool_data.color_picker_editing_color_stop.is_some() && tool_data.color_picker_transaction_open {
|
||||
responses.add(DocumentMessage::EndTransaction);
|
||||
tool_data.color_picker_transaction_open = false;
|
||||
}
|
||||
|
||||
let stop_pos = selected_gradient.gradient.stops.position[stop_index];
|
||||
let viewport_pos = selected_gradient
|
||||
.transform
|
||||
.transform_point2(selected_gradient.gradient.start.lerp(selected_gradient.gradient.end, stop_pos));
|
||||
let color = selected_gradient.gradient.stops.color[stop_index].to_gamma_srgb();
|
||||
tool_data.color_picker_editing_color_stop = Some(stop_index);
|
||||
responses.add(FrontendMessage::UpdateGradientStopColorPickerPosition {
|
||||
color,
|
||||
x: viewport_pos.x,
|
||||
y: viewport_pos.y,
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
@@ -1178,15 +1271,21 @@ impl Fsm for GradientToolFsmState {
|
||||
tool_data.selected_gradient = None;
|
||||
responses.add(OverlaysMessage::Draw);
|
||||
|
||||
dismiss_color_stop_color_picker(tool_data, responses);
|
||||
|
||||
GradientToolFsmState::Ready {
|
||||
hovering: GradientHoverTarget::None,
|
||||
selected: GradientSelectedTarget::None,
|
||||
}
|
||||
}
|
||||
(_, GradientToolMessage::Abort) => {
|
||||
dismiss_color_stop_color_picker(tool_data, responses);
|
||||
|
||||
GradientToolFsmState::Ready {
|
||||
hovering: GradientHoverTarget::None,
|
||||
selected: GradientSelectedTarget::None,
|
||||
}
|
||||
}
|
||||
(_, GradientToolMessage::Abort) => GradientToolFsmState::Ready {
|
||||
hovering: GradientHoverTarget::None,
|
||||
selected: GradientSelectedTarget::None,
|
||||
},
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
@@ -1273,6 +1372,16 @@ impl Fsm for GradientToolFsmState {
|
||||
}
|
||||
}
|
||||
|
||||
fn dismiss_color_stop_color_picker(tool_data: &mut GradientToolData, responses: &mut VecDeque<Message>) {
|
||||
if tool_data.color_picker_editing_color_stop.is_some() {
|
||||
if tool_data.color_picker_transaction_open {
|
||||
responses.add(DocumentMessage::EndTransaction);
|
||||
tool_data.color_picker_transaction_open = false;
|
||||
}
|
||||
tool_data.color_picker_editing_color_stop = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_hover_target(mouse: DVec2, document: &DocumentMessageHandler) -> GradientHoverTarget {
|
||||
let stop_tolerance = (MANIPULATOR_GROUP_MARKER_SIZE * 2.).powi(2);
|
||||
let midpoint_tolerance = GRADIENT_MIDPOINT_DIAMOND_RADIUS.powi(2);
|
||||
@@ -1380,7 +1489,7 @@ fn apply_gradient_update(
|
||||
}
|
||||
|
||||
if transaction_started {
|
||||
responses.add(DocumentMessage::AddTransaction);
|
||||
responses.add(DocumentMessage::EndTransaction);
|
||||
}
|
||||
if let Some(selected_gradient) = &mut data.selected_gradient
|
||||
&& let Some(layer) = selected_gradient.layer
|
||||
|
||||
Reference in New Issue
Block a user