Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion desktop/src/cef/internal/display_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ impl<H: CefEventHandler> ImplDisplayHandler for DisplayHandlerImpl<H> {
CT_PROGRESS => CursorIcon::Progress,
CT_NODROP => CursorIcon::NoDrop,
CT_COPY => CursorIcon::Copy,
CT_NONE => CursorIcon::Default,
CT_NOTALLOWED => CursorIcon::NotAllowed,
CT_ZOOMIN => CursorIcon::ZoomIn,
CT_ZOOMOUT => CursorIcon::ZoomOut,
Expand All @@ -91,6 +90,10 @@ impl<H: CefEventHandler> ImplDisplayHandler for DisplayHandlerImpl<H> {
CT_DND_COPY => CursorIcon::Copy,
CT_DND_LINK => CursorIcon::Alias,
CT_NUM_VALUES => CursorIcon::Default,
CT_NONE => {
self.event_handler.cursor_change(crate::window::Cursor::None);
return 1; // We handled the cursor change.
}
_ => CursorIcon::Default,
};

Expand Down
6 changes: 6 additions & 0 deletions desktop/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,12 @@ impl Window {
};
custom_cursor.into()
}
Cursor::None => {
self.winit_window.set_cursor_visible(false);
return;
}
};
self.winit_window.set_cursor_visible(true);
self.winit_window.set_cursor(cursor);
}

Expand Down Expand Up @@ -215,6 +220,7 @@ impl Window {
pub(crate) enum Cursor {
Icon(CursorIcon),
Custom(CustomCursorSource),
None,
}
impl From<CursorIcon> for Cursor {
fn from(icon: CursorIcon) -> Self {
Expand Down
3 changes: 3 additions & 0 deletions editor/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ pub const LINE_ROTATE_SNAP_ANGLE: f64 = 15.;
pub const BRUSH_SIZE_CHANGE_KEYBOARD: f64 = 5.;
pub const DEFAULT_BRUSH_SIZE: f64 = 20.;

// EYEDROPPER TOOL
pub const EYEDROPPER_PREVIEW_AREA_RESOLUTION: u32 = 11;

// GIZMOS
pub const POINT_RADIUS_HANDLE_SNAP_THRESHOLD: f64 = 8.;
pub const POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD: f64 = 7.9;
Expand Down
2 changes: 2 additions & 0 deletions editor/src/messages/frontend/frontend_message.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::utility_types::{DocumentDetails, MouseCursorIcon, OpenDocument};
use crate::messages::app_window::app_window_message_handler::AppWindowPlatform;
use crate::messages::frontend::utility_types::EyedropperPreviewImage;
use crate::messages::input_mapper::utility_types::misc::ActionShortcut;
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::node_graph::utility_types::{
Expand Down Expand Up @@ -253,6 +254,7 @@ pub enum FrontendMessage {
multiplier: (f64, f64),
},
UpdateEyedropperSamplingState {
image: Option<EyedropperPreviewImage>,
#[serde(rename = "mousePosition")]
mouse_position: Option<(f64, f64)>,
#[serde(rename = "primaryColor")]
Expand Down
7 changes: 7 additions & 0 deletions editor/src/messages/frontend/utility_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,10 @@ pub enum ExportBounds {
Selection,
Artboard(LayerNodeIdentifier),
}

#[derive(Clone, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct EyedropperPreviewImage {
pub data: Vec<u8>,
pub width: u32,
pub height: u32,
}
1 change: 1 addition & 0 deletions editor/src/messages/portfolio/portfolio_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ pub enum PortfolioMessage {
document_id: DocumentId,
ignore_hash: bool,
},
SubmitEyedropperPreviewRender,
ToggleResetNodesToDefinitionsOnOpen,
ToggleFocusDocument,
ToggleDataPanelOpen,
Expand Down
35 changes: 35 additions & 0 deletions editor/src/messages/portfolio/portfolio_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,41 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
Ok(message) => responses.add_front(message),
}
}
#[cfg(not(target_family = "wasm"))]
PortfolioMessage::SubmitEyedropperPreviewRender => {
use crate::consts::EYEDROPPER_PREVIEW_AREA_RESOLUTION;

let Some(document_id) = self.active_document_id else { return };
let Some(document) = self.documents.get_mut(&document_id) else { return };

let resolution = glam::UVec2::splat(EYEDROPPER_PREVIEW_AREA_RESOLUTION);

let preview_offset_in_viewport = ipp.mouse.position - (glam::DVec2::splat(EYEDROPPER_PREVIEW_AREA_RESOLUTION as f64 / 2.));
let preview_offset_in_viewport = DAffine2::from_translation(preview_offset_in_viewport);

let document_to_viewport = document.metadata().document_to_viewport;

let preview_transform = preview_offset_in_viewport.inverse() * document_to_viewport;
let pointer_position = document_to_viewport.inverse().transform_point2(ipp.mouse.position);

let result = self
.executor
.submit_eyedropper_preview(document_id, preview_transform, pointer_position, resolution, timing_information);

match result {
Err(description) => {
responses.add(DialogMessage::DisplayDialogError {
title: "Unable to update node graph".to_string(),
description,
});
}
Ok(message) => responses.add_front(message),
}
}
#[cfg(target_family = "wasm")]
PortfolioMessage::SubmitEyedropperPreviewRender => {
// TODO: Currently for Wasm, this is implemented through SVG rendering but the Eyedropper tool doesn't work at all when Vello is enabled as the renderer
}
PortfolioMessage::ToggleFocusDocument => {
self.focus_document = !self.focus_document;
responses.add(MenuBarMessage::SendLayout);
Expand Down
73 changes: 63 additions & 10 deletions editor/src/messages/tool/tool_messages/eyedropper_tool.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::tool_prelude::*;
use crate::messages::frontend::utility_types::EyedropperPreviewImage;
use crate::messages::tool::utility_types::DocumentToolData;

#[derive(Default, ExtractField)]
Expand All @@ -19,6 +20,8 @@ pub enum EyedropperToolMessage {
PointerMove,
SampleSecondaryColorBegin,
SampleSecondaryColorEnd,

PreviewImage { data: Vec<u8>, width: u32, height: u32 },
}

impl ToolMetadata for EyedropperTool {
Expand All @@ -42,6 +45,17 @@ impl LayoutHolder for EyedropperTool {
#[message_handler_data]
impl<'a> MessageHandler<ToolMessage, &mut ToolActionMessageContext<'a>> for EyedropperTool {
fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque<Message>, context: &mut ToolActionMessageContext<'a>) {
if let ToolMessage::Eyedropper(EyedropperToolMessage::PreviewImage { data, width, height }) = message {
let image = EyedropperPreviewImage { data, width, height };

update_cursor_preview_common(responses, Some(image), context.input, context.global_tool_data, self.data.color_choice.clone());

if !self.data.preview {
disable_cursor_preview(responses, &mut self.data);
}
return;
}

self.fsm_state.process_event(message, &mut self.data, context, &(), responses, true);
}

Expand Down Expand Up @@ -74,13 +88,16 @@ enum EyedropperToolFsmState {
}

#[derive(Clone, Debug, Default)]
struct EyedropperToolData {}
struct EyedropperToolData {
preview: bool,
color_choice: Option<String>,
}

impl Fsm for EyedropperToolFsmState {
type ToolData = EyedropperToolData;
type ToolOptions = ();

fn transition(self, event: ToolMessage, _tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionMessageContext, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
fn transition(self, event: ToolMessage, tool_data: &mut Self::ToolData, tool_action_data: &mut ToolActionMessageContext, _tool_options: &(), responses: &mut VecDeque<Message>) -> Self {
let ToolActionMessageContext {
global_tool_data, input, viewport, ..
} = tool_action_data;
Expand All @@ -89,7 +106,7 @@ impl Fsm for EyedropperToolFsmState {
match (self, event) {
// Ready -> Sampling
(EyedropperToolFsmState::Ready, mouse_down) if matches!(mouse_down, EyedropperToolMessage::SamplePrimaryColorBegin | EyedropperToolMessage::SampleSecondaryColorBegin) => {
update_cursor_preview(responses, input, global_tool_data, None);
update_cursor_preview(responses, tool_data, input, global_tool_data, None);

if mouse_down == EyedropperToolMessage::SamplePrimaryColorBegin {
EyedropperToolFsmState::SamplingPrimary
Expand All @@ -101,24 +118,24 @@ impl Fsm for EyedropperToolFsmState {
(EyedropperToolFsmState::SamplingPrimary | EyedropperToolFsmState::SamplingSecondary, EyedropperToolMessage::PointerMove) => {
let mouse_position = viewport.logical(input.mouse.position);
if viewport.is_in_bounds(mouse_position + viewport.offset()) {
update_cursor_preview(responses, input, global_tool_data, None);
update_cursor_preview(responses, tool_data, input, global_tool_data, None);
} else {
disable_cursor_preview(responses);
disable_cursor_preview(responses, tool_data);
}

self
}
// Sampling -> Ready
(EyedropperToolFsmState::SamplingPrimary, EyedropperToolMessage::SamplePrimaryColorEnd) | (EyedropperToolFsmState::SamplingSecondary, EyedropperToolMessage::SampleSecondaryColorEnd) => {
let set_color_choice = if self == EyedropperToolFsmState::SamplingPrimary { "Primary" } else { "Secondary" }.to_string();
update_cursor_preview(responses, input, global_tool_data, Some(set_color_choice));
disable_cursor_preview(responses);
update_cursor_preview(responses, tool_data, input, global_tool_data, Some(set_color_choice));
disable_cursor_preview(responses, tool_data);

EyedropperToolFsmState::Ready
}
// Any -> Ready
(_, EyedropperToolMessage::Abort) => {
disable_cursor_preview(responses);
disable_cursor_preview(responses, tool_data);

EyedropperToolFsmState::Ready
}
Expand Down Expand Up @@ -151,17 +168,53 @@ impl Fsm for EyedropperToolFsmState {
}
}

fn disable_cursor_preview(responses: &mut VecDeque<Message>) {
fn disable_cursor_preview(responses: &mut VecDeque<Message>, tool_data: &mut EyedropperToolData) {
tool_data.preview = false;
responses.add(FrontendMessage::UpdateEyedropperSamplingState {
image: None,
mouse_position: None,
primary_color: "".into(),
secondary_color: "".into(),
set_color_choice: None,
});
}

fn update_cursor_preview(responses: &mut VecDeque<Message>, input: &InputPreprocessorMessageHandler, global_tool_data: &DocumentToolData, set_color_choice: Option<String>) {
#[cfg(not(target_family = "wasm"))]
fn update_cursor_preview(
responses: &mut VecDeque<Message>,
tool_data: &mut EyedropperToolData,
_input: &InputPreprocessorMessageHandler,
_global_tool_data: &DocumentToolData,
set_color_choice: Option<String>,
) {
tool_data.preview = true;
tool_data.color_choice = set_color_choice;
responses.add(PortfolioMessage::SubmitEyedropperPreviewRender);
}

#[cfg(target_family = "wasm")]
fn update_cursor_preview(
responses: &mut VecDeque<Message>,
tool_data: &mut EyedropperToolData,
input: &InputPreprocessorMessageHandler,
global_tool_data: &DocumentToolData,
set_color_choice: Option<String>,
) {
tool_data.preview = true;
tool_data.color_choice = set_color_choice.clone();

update_cursor_preview_common(responses, None, input, global_tool_data, set_color_choice);
}

fn update_cursor_preview_common(
responses: &mut VecDeque<Message>,
image: Option<EyedropperPreviewImage>,
input: &InputPreprocessorMessageHandler,
global_tool_data: &DocumentToolData,
set_color_choice: Option<String>,
) {
responses.add(FrontendMessage::UpdateEyedropperSamplingState {
image,
mouse_position: Some(input.mouse.position.into()),
primary_color: "#".to_string() + global_tool_data.primary_color.to_rgb_hex_srgb().as_str(),
secondary_color: "#".to_string() + global_tool_data.secondary_color.to_rgb_hex_srgb().as_str(),
Expand Down
Loading