mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-05 17:38:11 +08:00
Replace globals with editor environment (#3656)
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
+5
-10
@@ -1,3 +1,4 @@
|
|||||||
|
use rand::Rng;
|
||||||
use rfd::AsyncFileDialog;
|
use rfd::AsyncFileDialog;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -16,7 +17,7 @@ use crate::event::{AppEvent, AppEventScheduler};
|
|||||||
use crate::persist::PersistentData;
|
use crate::persist::PersistentData;
|
||||||
use crate::render::{RenderError, RenderState};
|
use crate::render::{RenderError, RenderState};
|
||||||
use crate::window::Window;
|
use crate::window::Window;
|
||||||
use crate::wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage, InputMessage, MouseKeys, MouseState, Platform};
|
use crate::wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage, InputMessage, MouseKeys, MouseState};
|
||||||
use crate::wrapper::{DesktopWrapper, NodeGraphExecutionResult, WgpuContext, serialize_frontend_messages};
|
use crate::wrapper::{DesktopWrapper, NodeGraphExecutionResult, WgpuContext, serialize_frontend_messages};
|
||||||
|
|
||||||
pub(crate) struct App {
|
pub(crate) struct App {
|
||||||
@@ -78,6 +79,8 @@ impl App {
|
|||||||
let mut persistent_data = PersistentData::default();
|
let mut persistent_data = PersistentData::default();
|
||||||
persistent_data.load_from_disk();
|
persistent_data.load_from_disk();
|
||||||
|
|
||||||
|
let desktop_wrapper = DesktopWrapper::new(rand::rng().random());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
render_state: None,
|
render_state: None,
|
||||||
wgpu_context,
|
wgpu_context,
|
||||||
@@ -91,7 +94,7 @@ impl App {
|
|||||||
ui_scale: 1.,
|
ui_scale: 1.,
|
||||||
app_event_receiver,
|
app_event_receiver,
|
||||||
app_event_scheduler,
|
app_event_scheduler,
|
||||||
desktop_wrapper: DesktopWrapper::new(),
|
desktop_wrapper,
|
||||||
last_ui_update: Instant::now(),
|
last_ui_update: Instant::now(),
|
||||||
cef_context,
|
cef_context,
|
||||||
cef_schedule: Some(Instant::now()),
|
cef_schedule: Some(Instant::now()),
|
||||||
@@ -478,14 +481,6 @@ impl ApplicationHandler for App {
|
|||||||
self.resize();
|
self.resize();
|
||||||
|
|
||||||
self.desktop_wrapper.init(self.wgpu_context.clone());
|
self.desktop_wrapper.init(self.wgpu_context.clone());
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
let platform = Platform::Windows;
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
let platform = Platform::Mac;
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
let platform = Platform::Linux;
|
|
||||||
self.dispatch_desktop_wrapper_message(DesktopWrapperMessage::UpdatePlatform(platform));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) {
|
fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||||
|
|||||||
+3
-2
@@ -66,6 +66,7 @@ pub fn start() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Must be called before event loop initialization or native window integrations will break
|
||||||
App::init();
|
App::init();
|
||||||
|
|
||||||
let wgpu_context = futures::executor::block_on(gpu_context::create_wgpu_context());
|
let wgpu_context = futures::executor::block_on(gpu_context::create_wgpu_context());
|
||||||
@@ -78,9 +79,9 @@ pub fn start() {
|
|||||||
|
|
||||||
let cef_handler = cef::CefHandler::new(wgpu_context.clone(), app_event_scheduler.clone(), cef_view_info_receiver);
|
let cef_handler = cef::CefHandler::new(wgpu_context.clone(), app_event_scheduler.clone(), cef_view_info_receiver);
|
||||||
let cef_context = match cef_context_builder.initialize(cef_handler, cli.disable_ui_acceleration) {
|
let cef_context = match cef_context_builder.initialize(cef_handler, cli.disable_ui_acceleration) {
|
||||||
Ok(c) => {
|
Ok(context) => {
|
||||||
tracing::info!("CEF initialized successfully");
|
tracing::info!("CEF initialized successfully");
|
||||||
c
|
context
|
||||||
}
|
}
|
||||||
Err(cef::InitError::AlreadyRunning) => {
|
Err(cef::InitError::AlreadyRunning) => {
|
||||||
tracing::error!("Another instance is already running, Exiting.");
|
tracing::error!("Another instance is already running, Exiting.");
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
use graphene_std::Color;
|
use graphene_std::Color;
|
||||||
use graphene_std::raster::Image;
|
use graphene_std::raster::Image;
|
||||||
use graphite_editor::messages::app_window::app_window_message_handler::AppWindowPlatform;
|
|
||||||
use graphite_editor::messages::clipboard::utility_types::ClipboardContentRaw;
|
use graphite_editor::messages::clipboard::utility_types::ClipboardContentRaw;
|
||||||
use graphite_editor::messages::prelude::*;
|
use graphite_editor::messages::prelude::*;
|
||||||
|
|
||||||
use super::DesktopWrapperMessageDispatcher;
|
use super::DesktopWrapperMessageDispatcher;
|
||||||
use super::messages::{DesktopFrontendMessage, DesktopWrapperMessage, EditorMessage, OpenFileDialogContext, Platform, SaveFileDialogContext};
|
use super::messages::{DesktopFrontendMessage, DesktopWrapperMessage, EditorMessage, OpenFileDialogContext, SaveFileDialogContext};
|
||||||
|
|
||||||
pub(super) fn handle_desktop_wrapper_message(dispatcher: &mut DesktopWrapperMessageDispatcher, message: DesktopWrapperMessage) {
|
pub(super) fn handle_desktop_wrapper_message(dispatcher: &mut DesktopWrapperMessageDispatcher, message: DesktopWrapperMessage) {
|
||||||
match message {
|
match message {
|
||||||
@@ -111,15 +110,6 @@ pub(super) fn handle_desktop_wrapper_message(dispatcher: &mut DesktopWrapperMess
|
|||||||
dispatcher.queue_editor_message(message);
|
dispatcher.queue_editor_message(message);
|
||||||
}
|
}
|
||||||
DesktopWrapperMessage::PollNodeGraphEvaluation => dispatcher.poll_node_graph_evaluation(),
|
DesktopWrapperMessage::PollNodeGraphEvaluation => dispatcher.poll_node_graph_evaluation(),
|
||||||
DesktopWrapperMessage::UpdatePlatform(platform) => {
|
|
||||||
let platform = match platform {
|
|
||||||
Platform::Windows => AppWindowPlatform::Windows,
|
|
||||||
Platform::Mac => AppWindowPlatform::Mac,
|
|
||||||
Platform::Linux => AppWindowPlatform::Linux,
|
|
||||||
};
|
|
||||||
let message = AppWindowMessage::UpdatePlatform { platform };
|
|
||||||
dispatcher.queue_editor_message(message);
|
|
||||||
}
|
|
||||||
DesktopWrapperMessage::UpdateMaximized { maximized } => {
|
DesktopWrapperMessage::UpdateMaximized { maximized } => {
|
||||||
let message = FrontendMessage::UpdateMaximized { maximized };
|
let message = FrontendMessage::UpdateMaximized { maximized };
|
||||||
dispatcher.queue_editor_message(message);
|
dispatcher.queue_editor_message(message);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use graph_craft::wasm_application_io::WasmApplicationIo;
|
use graph_craft::wasm_application_io::WasmApplicationIo;
|
||||||
use graphite_editor::application::Editor;
|
use graphite_editor::application::{Editor, Environment, Host, Platform};
|
||||||
use graphite_editor::messages::prelude::{FrontendMessage, Message};
|
use graphite_editor::messages::prelude::{FrontendMessage, Message};
|
||||||
|
|
||||||
// TODO: Remove usage of this reexport in desktop create and remove this line
|
// TODO: Remove usage of this reexport in desktop create and remove this line
|
||||||
@@ -27,8 +27,18 @@ pub struct DesktopWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DesktopWrapper {
|
impl DesktopWrapper {
|
||||||
pub fn new() -> Self {
|
pub fn new(uuid_random_seed: u64) -> Self {
|
||||||
Self { editor: Editor::new() }
|
#[cfg(target_os = "windows")]
|
||||||
|
let host = Host::Windows;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
let host = Host::Mac;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
let host = Host::Linux;
|
||||||
|
let env = Environment { platform: Platform::Desktop, host };
|
||||||
|
|
||||||
|
Self {
|
||||||
|
editor: Editor::new(env, uuid_random_seed),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&self, wgpu_context: WgpuContext) {
|
pub fn init(&self, wgpu_context: WgpuContext) {
|
||||||
@@ -51,12 +61,6 @@ impl DesktopWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DesktopWrapper {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum NodeGraphExecutionResult {
|
pub enum NodeGraphExecutionResult {
|
||||||
HasRun(Option<wgpu::Texture>),
|
HasRun(Option<wgpu::Texture>),
|
||||||
NotRun,
|
NotRun,
|
||||||
|
|||||||
@@ -109,7 +109,6 @@ pub enum DesktopWrapperMessage {
|
|||||||
content: Vec<u8>,
|
content: Vec<u8>,
|
||||||
},
|
},
|
||||||
PollNodeGraphEvaluation,
|
PollNodeGraphEvaluation,
|
||||||
UpdatePlatform(Platform),
|
|
||||||
UpdateMaximized {
|
UpdateMaximized {
|
||||||
maximized: bool,
|
maximized: bool,
|
||||||
},
|
},
|
||||||
@@ -163,12 +162,6 @@ pub enum SaveFileDialogContext {
|
|||||||
File { content: Vec<u8> },
|
File { content: Vec<u8> },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Platform {
|
|
||||||
Windows,
|
|
||||||
Mac,
|
|
||||||
Linux,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum MenuItem {
|
pub enum MenuItem {
|
||||||
Action {
|
Action {
|
||||||
id: String,
|
id: String,
|
||||||
|
|||||||
@@ -1,24 +1,31 @@
|
|||||||
use crate::dispatcher::Dispatcher;
|
use crate::dispatcher::Dispatcher;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
pub use graphene_std::uuid::*;
|
pub use graphene_std::uuid::*;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
// TODO: serialize with serde to save the current editor state
|
|
||||||
pub struct Editor {
|
pub struct Editor {
|
||||||
pub dispatcher: Dispatcher,
|
pub dispatcher: Dispatcher,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Editor {
|
impl Editor {
|
||||||
/// Construct the editor.
|
pub fn new(environment: Environment, uuid_random_seed: u64) -> Self {
|
||||||
/// Remember to provide a random seed with `editor::set_uuid_seed(seed)` before any editors can be used.
|
ENVIRONMENT.set(environment).expect("Editor shoud only be initialized once");
|
||||||
pub fn new() -> Self {
|
graphene_std::uuid::set_uuid_seed(uuid_random_seed);
|
||||||
|
|
||||||
Self { dispatcher: Dispatcher::new() }
|
Self { dispatcher: Dispatcher::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) fn new_local_executor() -> (Self, crate::node_graph_executor::NodeRuntime) {
|
pub(crate) fn new_local_executor() -> (Self, crate::node_graph_executor::NodeRuntime) {
|
||||||
|
let _ = ENVIRONMENT.set(*Editor::environment());
|
||||||
|
graphene_std::uuid::set_uuid_seed(0);
|
||||||
|
|
||||||
let (runtime, executor) = crate::node_graph_executor::NodeGraphExecutor::new_with_local_runtime();
|
let (runtime, executor) = crate::node_graph_executor::NodeGraphExecutor::new_with_local_runtime();
|
||||||
let dispatcher = Dispatcher::with_executor(executor);
|
let editor = Self {
|
||||||
(Self { dispatcher }, runtime)
|
dispatcher: Dispatcher::with_executor(executor),
|
||||||
|
};
|
||||||
|
|
||||||
|
(editor, runtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_message<T: Into<Message>>(&mut self, message: T) -> Vec<FrontendMessage> {
|
pub fn handle_message<T: Into<Message>>(&mut self, message: T) -> Vec<FrontendMessage> {
|
||||||
@@ -32,9 +39,53 @@ impl Editor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Editor {
|
static ENVIRONMENT: OnceLock<Environment> = OnceLock::new();
|
||||||
fn default() -> Self {
|
impl Editor {
|
||||||
Self::new()
|
#[cfg(not(test))]
|
||||||
|
pub fn environment() -> &'static Environment {
|
||||||
|
ENVIRONMENT.get().expect("Editor environment accessed before initialization")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn environment() -> &'static Environment {
|
||||||
|
&Environment {
|
||||||
|
platform: Platform::Desktop,
|
||||||
|
host: Host::Linux,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Environment {
|
||||||
|
pub platform: Platform,
|
||||||
|
pub host: Host,
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Platform {
|
||||||
|
Desktop,
|
||||||
|
Web,
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum Host {
|
||||||
|
Windows,
|
||||||
|
Mac,
|
||||||
|
Linux,
|
||||||
|
}
|
||||||
|
impl Environment {
|
||||||
|
pub fn is_desktop(&self) -> bool {
|
||||||
|
matches!(self.platform, Platform::Desktop)
|
||||||
|
}
|
||||||
|
pub fn is_web(&self) -> bool {
|
||||||
|
matches!(self.platform, Platform::Web)
|
||||||
|
}
|
||||||
|
pub fn is_windows(&self) -> bool {
|
||||||
|
matches!(self.host, Host::Windows)
|
||||||
|
}
|
||||||
|
pub fn is_mac(&self) -> bool {
|
||||||
|
matches!(self.host, Host::Mac)
|
||||||
|
}
|
||||||
|
pub fn is_linux(&self) -> bool {
|
||||||
|
matches!(self.host, Host::Linux)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,11 @@ pub struct DispatcherMessageHandlers {
|
|||||||
debug_message_handler: DebugMessageHandler,
|
debug_message_handler: DebugMessageHandler,
|
||||||
defer_message_handler: DeferMessageHandler,
|
defer_message_handler: DeferMessageHandler,
|
||||||
dialog_message_handler: DialogMessageHandler,
|
dialog_message_handler: DialogMessageHandler,
|
||||||
globals_message_handler: GlobalsMessageHandler,
|
|
||||||
input_preprocessor_message_handler: InputPreprocessorMessageHandler,
|
input_preprocessor_message_handler: InputPreprocessorMessageHandler,
|
||||||
key_mapping_message_handler: KeyMappingMessageHandler,
|
key_mapping_message_handler: KeyMappingMessageHandler,
|
||||||
layout_message_handler: LayoutMessageHandler,
|
layout_message_handler: LayoutMessageHandler,
|
||||||
menu_bar_message_handler: MenuBarMessageHandler,
|
menu_bar_message_handler: MenuBarMessageHandler,
|
||||||
pub portfolio_message_handler: PortfolioMessageHandler,
|
pub(crate) portfolio_message_handler: PortfolioMessageHandler,
|
||||||
preferences_message_handler: PreferencesMessageHandler,
|
preferences_message_handler: PreferencesMessageHandler,
|
||||||
tool_message_handler: ToolMessageHandler,
|
tool_message_handler: ToolMessageHandler,
|
||||||
viewport_message_handler: ViewportMessageHandler,
|
viewport_message_handler: ViewportMessageHandler,
|
||||||
@@ -192,17 +191,11 @@ impl Dispatcher {
|
|||||||
self.responses.push(message);
|
self.responses.push(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Globals(message) => {
|
|
||||||
self.message_handlers.globals_message_handler.process_message(message, &mut queue, ());
|
|
||||||
}
|
|
||||||
Message::InputPreprocessor(message) => {
|
Message::InputPreprocessor(message) => {
|
||||||
let keyboard_platform = GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout();
|
|
||||||
|
|
||||||
self.message_handlers.input_preprocessor_message_handler.process_message(
|
self.message_handlers.input_preprocessor_message_handler.process_message(
|
||||||
message,
|
message,
|
||||||
&mut queue,
|
&mut queue,
|
||||||
InputPreprocessorMessageContext {
|
InputPreprocessorMessageContext {
|
||||||
keyboard_platform,
|
|
||||||
viewport: &self.message_handlers.viewport_message_handler,
|
viewport: &self.message_handlers.viewport_message_handler,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
use super::app_window_message_handler::AppWindowPlatform;
|
|
||||||
|
|
||||||
#[impl_message(Message, AppWindow)]
|
#[impl_message(Message, AppWindow)]
|
||||||
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum AppWindowMessage {
|
pub enum AppWindowMessage {
|
||||||
UpdatePlatform { platform: AppWindowPlatform },
|
|
||||||
PointerLock,
|
PointerLock,
|
||||||
PointerLockMove { x: f64, y: f64 },
|
PointerLockMove { x: f64, y: f64 },
|
||||||
Close,
|
Close,
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
use crate::messages::app_window::AppWindowMessage;
|
use crate::application::{Environment, Platform};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
use crate::{application::Host, messages::app_window::AppWindowMessage};
|
||||||
use graphite_proc_macros::{ExtractField, message_handler_data};
|
use graphite_proc_macros::{ExtractField, message_handler_data};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, ExtractField)]
|
#[derive(Debug, Clone, Default, ExtractField)]
|
||||||
pub struct AppWindowMessageHandler {
|
pub struct AppWindowMessageHandler {}
|
||||||
platform: AppWindowPlatform,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[message_handler_data]
|
#[message_handler_data]
|
||||||
impl MessageHandler<AppWindowMessage, ()> for AppWindowMessageHandler {
|
impl MessageHandler<AppWindowMessage, ()> for AppWindowMessageHandler {
|
||||||
fn process_message(&mut self, message: AppWindowMessage, responses: &mut std::collections::VecDeque<Message>, _: ()) {
|
fn process_message(&mut self, message: AppWindowMessage, responses: &mut std::collections::VecDeque<Message>, _: ()) {
|
||||||
match message {
|
match message {
|
||||||
AppWindowMessage::UpdatePlatform { platform } => {
|
|
||||||
self.platform = platform;
|
|
||||||
responses.add(FrontendMessage::UpdatePlatform { platform: self.platform });
|
|
||||||
}
|
|
||||||
AppWindowMessage::PointerLock => {
|
AppWindowMessage::PointerLock => {
|
||||||
responses.add(FrontendMessage::WindowPointerLock);
|
responses.add(FrontendMessage::WindowPointerLock);
|
||||||
}
|
}
|
||||||
@@ -66,3 +61,14 @@ pub enum AppWindowPlatform {
|
|||||||
Mac,
|
Mac,
|
||||||
Linux,
|
Linux,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Environment> for AppWindowPlatform {
|
||||||
|
fn from(environment: &Environment) -> Self {
|
||||||
|
match (environment.platform, environment.host) {
|
||||||
|
(Platform::Web, _) => AppWindowPlatform::Web,
|
||||||
|
(Platform::Desktop, Host::Linux) => AppWindowPlatform::Linux,
|
||||||
|
(Platform::Desktop, Host::Mac) => AppWindowPlatform::Mac,
|
||||||
|
(Platform::Desktop, Host::Windows) => AppWindowPlatform::Windows,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
use crate::messages::portfolio::utility_types::Platform;
|
|
||||||
use std::sync::OnceLock;
|
|
||||||
|
|
||||||
pub static GLOBAL_PLATFORM: OnceLock<Platform> = OnceLock::new();
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
use crate::messages::portfolio::utility_types::Platform;
|
|
||||||
use crate::messages::prelude::*;
|
|
||||||
|
|
||||||
#[impl_message(Message, Globals)]
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub enum GlobalsMessage {
|
|
||||||
SetPlatform { platform: Platform },
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
use crate::messages::prelude::*;
|
|
||||||
|
|
||||||
#[derive(Debug, Default, ExtractField)]
|
|
||||||
pub struct GlobalsMessageHandler {}
|
|
||||||
|
|
||||||
#[message_handler_data]
|
|
||||||
impl MessageHandler<GlobalsMessage, ()> for GlobalsMessageHandler {
|
|
||||||
fn process_message(&mut self, message: GlobalsMessage, _responses: &mut VecDeque<Message>, _: ()) {
|
|
||||||
match message {
|
|
||||||
GlobalsMessage::SetPlatform { platform } => {
|
|
||||||
if GLOBAL_PLATFORM.get() != Some(&platform) {
|
|
||||||
GLOBAL_PLATFORM.set(platform).expect("Failed to set GLOBAL_PLATFORM");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
advertise_actions!(GlobalsMessageDiscriminant;
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
mod globals_message;
|
|
||||||
mod globals_message_handler;
|
|
||||||
|
|
||||||
pub mod global_variables;
|
|
||||||
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use globals_message::{GlobalsMessage, GlobalsMessageDiscriminant};
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use globals_message_handler::GlobalsMessageHandler;
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
use super::utility_types::input_keyboard::KeysGroup;
|
use super::utility_types::input_keyboard::KeysGroup;
|
||||||
use super::utility_types::misc::Mapping;
|
use super::utility_types::misc::Mapping;
|
||||||
|
use crate::application::Editor;
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::{self, Key};
|
use crate::messages::input_mapper::utility_types::input_keyboard::{self, Key};
|
||||||
use crate::messages::input_mapper::utility_types::misc::MappingEntry;
|
use crate::messages::input_mapper::utility_types::misc::MappingEntry;
|
||||||
use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
#[derive(ExtractField)]
|
#[derive(ExtractField)]
|
||||||
@@ -48,11 +48,7 @@ impl InputMapperMessageHandler {
|
|||||||
let found_actions = all_mapping_entries.filter(|entry| entry.action.to_discriminant() == *action_to_find);
|
let found_actions = all_mapping_entries.filter(|entry| entry.action.to_discriminant() == *action_to_find);
|
||||||
|
|
||||||
// Get the `Key` for this platform's accelerator key
|
// Get the `Key` for this platform's accelerator key
|
||||||
let keyboard_layout = || GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout();
|
let platform_accel_key = if Editor::environment().is_mac() { Key::Command } else { Key::Control };
|
||||||
let platform_accel_key = match keyboard_layout() {
|
|
||||||
KeyboardPlatformLayout::Standard => Key::Control,
|
|
||||||
KeyboardPlatformLayout::Mac => Key::Command,
|
|
||||||
};
|
|
||||||
|
|
||||||
let entry_to_key = |entry: &MappingEntry| {
|
let entry_to_key = |entry: &MappingEntry| {
|
||||||
// Get the modifier keys for the entry (and convert them to Key)
|
// Get the modifier keys for the entry (and convert them to Key)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::application::Editor;
|
||||||
use crate::consts::{BIG_NUDGE_AMOUNT, BRUSH_SIZE_CHANGE_KEYBOARD, NUDGE_AMOUNT};
|
use crate::consts::{BIG_NUDGE_AMOUNT, BRUSH_SIZE_CHANGE_KEYBOARD, NUDGE_AMOUNT};
|
||||||
use crate::messages::input_mapper::key_mapping::MappingVariant;
|
use crate::messages::input_mapper::key_mapping::MappingVariant;
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeyStates};
|
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeyStates};
|
||||||
@@ -8,7 +9,6 @@ use crate::messages::input_mapper::utility_types::misc::{KeyMappingEntries, Mapp
|
|||||||
use crate::messages::portfolio::document::node_graph::utility_types::Direction;
|
use crate::messages::portfolio::document::node_graph::utility_types::Direction;
|
||||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||||
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
|
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
|
||||||
use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::tool_messages::brush_tool::BrushToolMessageOptionsUpdate;
|
use crate::messages::tool::tool_messages::brush_tool::BrushToolMessageOptionsUpdate;
|
||||||
use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys;
|
use crate::messages::tool::tool_messages::select_tool::SelectToolPointerKeys;
|
||||||
@@ -27,8 +27,7 @@ pub fn input_mappings(zoom_with_scroll: bool) -> Mapping {
|
|||||||
use InputMapperMessage::*;
|
use InputMapperMessage::*;
|
||||||
use Key::*;
|
use Key::*;
|
||||||
|
|
||||||
// TODO: Fix this failing to load the correct data (and throwing a console warning) because it's occurring before the value has been supplied during initialization from the JS `initAfterFrontendReady`
|
let is_mac = Editor::environment().is_mac();
|
||||||
let keyboard_platform = GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout();
|
|
||||||
|
|
||||||
// NOTICE:
|
// NOTICE:
|
||||||
// If a new mapping you added here isn't working (and perhaps another lower-precedence one is instead), make sure to advertise
|
// If a new mapping you added here isn't working (and perhaps another lower-precedence one is instead), make sure to advertise
|
||||||
@@ -58,8 +57,8 @@ pub fn input_mappings(zoom_with_scroll: bool) -> Mapping {
|
|||||||
entry!(KeyDown(KeyZ); modifiers=[Accel, MouseLeft], action_dispatch=DocumentMessage::Noop),
|
entry!(KeyDown(KeyZ); modifiers=[Accel, MouseLeft], action_dispatch=DocumentMessage::Noop),
|
||||||
//
|
//
|
||||||
// AppWindowMessage
|
// AppWindowMessage
|
||||||
entry!(KeyDown(F11); disabled=(keyboard_platform == KeyboardPlatformLayout::Mac), action_dispatch=AppWindowMessage::Fullscreen),
|
entry!(KeyDown(F11); disabled=is_mac, action_dispatch=AppWindowMessage::Fullscreen),
|
||||||
entry!(KeyDown(KeyF); modifiers=[Command, Control], disabled=(keyboard_platform != KeyboardPlatformLayout::Mac), action_dispatch=AppWindowMessage::Fullscreen),
|
entry!(KeyDown(KeyF); modifiers=[Command, Control], disabled=!is_mac, action_dispatch=AppWindowMessage::Fullscreen),
|
||||||
entry!(KeyDown(KeyQ); modifiers=[Command], disabled=cfg!(not(target_os = "macos")), action_dispatch=AppWindowMessage::Close),
|
entry!(KeyDown(KeyQ); modifiers=[Command], disabled=cfg!(not(target_os = "macos")), action_dispatch=AppWindowMessage::Close),
|
||||||
//
|
//
|
||||||
// ClipboardMessage
|
// ClipboardMessage
|
||||||
@@ -429,8 +428,8 @@ pub fn input_mappings(zoom_with_scroll: bool) -> Mapping {
|
|||||||
entry!(WheelScroll; modifiers=[Shift], disabled=zoom_with_scroll, action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: true }),
|
entry!(WheelScroll; modifiers=[Shift], disabled=zoom_with_scroll, action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: true }),
|
||||||
entry!(WheelScroll; disabled=zoom_with_scroll, action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: false }),
|
entry!(WheelScroll; disabled=zoom_with_scroll, action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: false }),
|
||||||
// On Mac, the OS already converts Shift+scroll into horizontal scrolling so we have to reverse the behavior from normal to produce the same outcome
|
// On Mac, the OS already converts Shift+scroll into horizontal scrolling so we have to reverse the behavior from normal to produce the same outcome
|
||||||
entry!(WheelScroll; modifiers=[Control], disabled=!zoom_with_scroll, action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: keyboard_platform == KeyboardPlatformLayout::Mac }),
|
entry!(WheelScroll; modifiers=[Control], disabled=!zoom_with_scroll, action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: is_mac }),
|
||||||
entry!(WheelScroll; modifiers=[Shift], disabled=!zoom_with_scroll, action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: keyboard_platform != KeyboardPlatformLayout::Mac }),
|
entry!(WheelScroll; modifiers=[Shift], disabled=!zoom_with_scroll, action_dispatch=NavigationMessage::CanvasPanMouseWheel { use_y_as_x: !is_mac }),
|
||||||
entry!(WheelScroll; disabled=!zoom_with_scroll, action_dispatch=NavigationMessage::CanvasZoomMouseWheel),
|
entry!(WheelScroll; disabled=!zoom_with_scroll, action_dispatch=NavigationMessage::CanvasZoomMouseWheel),
|
||||||
entry!(KeyDown(PageUp); modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanByViewportFraction { delta: DVec2::new(1., 0.) }),
|
entry!(KeyDown(PageUp); modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanByViewportFraction { delta: DVec2::new(1., 0.) }),
|
||||||
entry!(KeyDown(PageDown); modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanByViewportFraction { delta: DVec2::new(-1., 0.) }),
|
entry!(KeyDown(PageDown); modifiers=[Shift], action_dispatch=NavigationMessage::CanvasPanByViewportFraction { delta: DVec2::new(-1., 0.) }),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
|
use crate::application::Editor;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
@@ -258,7 +258,7 @@ impl fmt::Display for Key {
|
|||||||
return write!(f, "{}", key_name.chars().skip(KEY_PREFIX.len()).collect::<String>());
|
return write!(f, "{}", key_name.chars().skip(KEY_PREFIX.len()).collect::<String>());
|
||||||
}
|
}
|
||||||
|
|
||||||
let keyboard_layout = || GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout();
|
let is_mac = Editor::environment().is_mac();
|
||||||
|
|
||||||
let name = match self {
|
let name = match self {
|
||||||
// Writing system keys
|
// Writing system keys
|
||||||
@@ -275,21 +275,21 @@ impl fmt::Display for Key {
|
|||||||
Self::Slash => "/",
|
Self::Slash => "/",
|
||||||
|
|
||||||
// Functional keys
|
// Functional keys
|
||||||
Self::Alt => match keyboard_layout() {
|
Self::Alt => match is_mac {
|
||||||
KeyboardPlatformLayout::Standard => "Alt",
|
true => "⌥",
|
||||||
KeyboardPlatformLayout::Mac => "⌥",
|
false => "Alt",
|
||||||
},
|
},
|
||||||
Self::Meta => match keyboard_layout() {
|
Self::Meta => match is_mac {
|
||||||
KeyboardPlatformLayout::Standard => "⊞",
|
true => "⌘",
|
||||||
KeyboardPlatformLayout::Mac => "⌘",
|
false => "⊞",
|
||||||
},
|
},
|
||||||
Self::Shift => match keyboard_layout() {
|
Self::Shift => match is_mac {
|
||||||
KeyboardPlatformLayout::Standard => "Shift",
|
true => "⇧",
|
||||||
KeyboardPlatformLayout::Mac => "⇧",
|
false => "Shift",
|
||||||
},
|
},
|
||||||
Self::Control => match keyboard_layout() {
|
Self::Control => match is_mac {
|
||||||
KeyboardPlatformLayout::Standard => "Ctrl",
|
true => "⌃",
|
||||||
KeyboardPlatformLayout::Mac => "⌃",
|
false => "Ctrl",
|
||||||
},
|
},
|
||||||
Self::Backspace => "⌫",
|
Self::Backspace => "⌫",
|
||||||
|
|
||||||
@@ -317,9 +317,9 @@ impl fmt::Display for Key {
|
|||||||
|
|
||||||
// Other keys that aren't part of the W3C spec
|
// Other keys that aren't part of the W3C spec
|
||||||
Self::Command => "⌘",
|
Self::Command => "⌘",
|
||||||
Self::Accel => match keyboard_layout() {
|
Self::Accel => match is_mac {
|
||||||
KeyboardPlatformLayout::Standard => "Ctrl",
|
true => "⌘",
|
||||||
KeyboardPlatformLayout::Mac => "⌘",
|
false => "Ctrl",
|
||||||
},
|
},
|
||||||
Self::MouseLeft => "Click",
|
Self::MouseLeft => "Click",
|
||||||
Self::MouseRight => "R.Click",
|
Self::MouseRight => "R.Click",
|
||||||
@@ -356,10 +356,9 @@ impl fmt::Display for KeysGroup {
|
|||||||
.0
|
.0
|
||||||
.iter()
|
.iter()
|
||||||
.map(|key| {
|
.map(|key| {
|
||||||
let keyboard_layout = GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout();
|
|
||||||
let key_is_modifier = matches!(*key, Key::Control | Key::Command | Key::Alt | Key::Shift | Key::Meta | Key::Accel);
|
let key_is_modifier = matches!(*key, Key::Control | Key::Command | Key::Alt | Key::Shift | Key::Meta | Key::Accel);
|
||||||
|
|
||||||
if keyboard_layout == KeyboardPlatformLayout::Mac && key_is_modifier {
|
if Editor::environment().is_mac() && key_is_modifier {
|
||||||
key.to_string()
|
key.to_string()
|
||||||
} else {
|
} else {
|
||||||
key.to_string() + JOINER_MARK
|
key.to_string() + JOINER_MARK
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
|
use crate::application::Editor;
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeyStates, ModifierKeys};
|
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeyStates, ModifierKeys};
|
||||||
use crate::messages::input_mapper::utility_types::input_mouse::{MouseButton, MouseKeys, MouseState};
|
use crate::messages::input_mapper::utility_types::input_mouse::{MouseButton, MouseKeys, MouseState};
|
||||||
use crate::messages::input_mapper::utility_types::misc::FrameTimeInfo;
|
use crate::messages::input_mapper::utility_types::misc::FrameTimeInfo;
|
||||||
use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[derive(ExtractField)]
|
#[derive(ExtractField)]
|
||||||
pub struct InputPreprocessorMessageContext<'a> {
|
pub struct InputPreprocessorMessageContext<'a> {
|
||||||
pub keyboard_platform: KeyboardPlatformLayout,
|
|
||||||
pub viewport: &'a ViewportMessageHandler,
|
pub viewport: &'a ViewportMessageHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,11 +21,11 @@ pub struct InputPreprocessorMessageHandler {
|
|||||||
#[message_handler_data]
|
#[message_handler_data]
|
||||||
impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContext<'a>> for InputPreprocessorMessageHandler {
|
impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContext<'a>> for InputPreprocessorMessageHandler {
|
||||||
fn process_message(&mut self, message: InputPreprocessorMessage, responses: &mut VecDeque<Message>, context: InputPreprocessorMessageContext<'a>) {
|
fn process_message(&mut self, message: InputPreprocessorMessage, responses: &mut VecDeque<Message>, context: InputPreprocessorMessageContext<'a>) {
|
||||||
let InputPreprocessorMessageContext { keyboard_platform, viewport } = context;
|
let InputPreprocessorMessageContext { viewport } = context;
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
InputPreprocessorMessage::DoubleClick { editor_mouse_state, modifier_keys } => {
|
InputPreprocessorMessage::DoubleClick { editor_mouse_state, modifier_keys } => {
|
||||||
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
||||||
self.mouse.position = mouse_state.position;
|
self.mouse.position = mouse_state.position;
|
||||||
@@ -43,7 +42,7 @@ impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::KeyDown { key, key_repeat, modifier_keys } => {
|
InputPreprocessorMessage::KeyDown { key, key_repeat, modifier_keys } => {
|
||||||
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, responses);
|
||||||
self.keyboard.set(key as usize);
|
self.keyboard.set(key as usize);
|
||||||
if !key_repeat {
|
if !key_repeat {
|
||||||
responses.add(InputMapperMessage::KeyDownNoRepeat(key));
|
responses.add(InputMapperMessage::KeyDownNoRepeat(key));
|
||||||
@@ -51,7 +50,7 @@ impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContex
|
|||||||
responses.add(InputMapperMessage::KeyDown(key));
|
responses.add(InputMapperMessage::KeyDown(key));
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::KeyUp { key, key_repeat, modifier_keys } => {
|
InputPreprocessorMessage::KeyUp { key, key_repeat, modifier_keys } => {
|
||||||
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, responses);
|
||||||
self.keyboard.unset(key as usize);
|
self.keyboard.unset(key as usize);
|
||||||
if !key_repeat {
|
if !key_repeat {
|
||||||
responses.add(InputMapperMessage::KeyUpNoRepeat(key));
|
responses.add(InputMapperMessage::KeyUpNoRepeat(key));
|
||||||
@@ -59,7 +58,7 @@ impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContex
|
|||||||
responses.add(InputMapperMessage::KeyUp(key));
|
responses.add(InputMapperMessage::KeyUp(key));
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys } => {
|
InputPreprocessorMessage::PointerDown { editor_mouse_state, modifier_keys } => {
|
||||||
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
||||||
self.mouse.position = mouse_state.position;
|
self.mouse.position = mouse_state.position;
|
||||||
@@ -67,7 +66,7 @@ impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContex
|
|||||||
self.translate_mouse_event(mouse_state, true, responses);
|
self.translate_mouse_event(mouse_state, true, responses);
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys } => {
|
InputPreprocessorMessage::PointerMove { editor_mouse_state, modifier_keys } => {
|
||||||
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
||||||
self.mouse.position = mouse_state.position;
|
self.mouse.position = mouse_state.position;
|
||||||
@@ -78,7 +77,7 @@ impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContex
|
|||||||
self.translate_mouse_event(mouse_state, false, responses);
|
self.translate_mouse_event(mouse_state, false, responses);
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys } => {
|
InputPreprocessorMessage::PointerUp { editor_mouse_state, modifier_keys } => {
|
||||||
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
||||||
self.mouse.position = mouse_state.position;
|
self.mouse.position = mouse_state.position;
|
||||||
@@ -86,7 +85,7 @@ impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContex
|
|||||||
self.translate_mouse_event(mouse_state, false, responses);
|
self.translate_mouse_event(mouse_state, false, responses);
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::PointerShake { editor_mouse_state, modifier_keys } => {
|
InputPreprocessorMessage::PointerShake { editor_mouse_state, modifier_keys } => {
|
||||||
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
||||||
self.mouse.position = mouse_state.position;
|
self.mouse.position = mouse_state.position;
|
||||||
@@ -99,7 +98,7 @@ impl<'a> MessageHandler<InputPreprocessorMessage, InputPreprocessorMessageContex
|
|||||||
self.frame_time.advance_timestamp(Duration::from_millis(timestamp));
|
self.frame_time.advance_timestamp(Duration::from_millis(timestamp));
|
||||||
}
|
}
|
||||||
InputPreprocessorMessage::WheelScroll { editor_mouse_state, modifier_keys } => {
|
InputPreprocessorMessage::WheelScroll { editor_mouse_state, modifier_keys } => {
|
||||||
self.update_states_of_modifier_keys(modifier_keys, keyboard_platform, responses);
|
self.update_states_of_modifier_keys(modifier_keys, responses);
|
||||||
|
|
||||||
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
let mouse_state = editor_mouse_state.to_mouse_state(viewport);
|
||||||
self.mouse.position = mouse_state.position;
|
self.mouse.position = mouse_state.position;
|
||||||
@@ -148,7 +147,7 @@ impl InputPreprocessorMessageHandler {
|
|||||||
self.mouse = new_state;
|
self.mouse = new_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_states_of_modifier_keys(&mut self, pressed_modifier_keys: ModifierKeys, keyboard_platform: KeyboardPlatformLayout, responses: &mut VecDeque<Message>) {
|
fn update_states_of_modifier_keys(&mut self, pressed_modifier_keys: ModifierKeys, responses: &mut VecDeque<Message>) {
|
||||||
let is_key_pressed = |key_to_check: ModifierKeys| pressed_modifier_keys.contains(key_to_check);
|
let is_key_pressed = |key_to_check: ModifierKeys| pressed_modifier_keys.contains(key_to_check);
|
||||||
|
|
||||||
// Update the state of the concrete modifier keys based on the source state
|
// Update the state of the concrete modifier keys based on the source state
|
||||||
@@ -157,16 +156,16 @@ impl InputPreprocessorMessageHandler {
|
|||||||
self.update_modifier_key(Key::Control, is_key_pressed(ModifierKeys::CONTROL), responses);
|
self.update_modifier_key(Key::Control, is_key_pressed(ModifierKeys::CONTROL), responses);
|
||||||
|
|
||||||
// Update the state of either the concrete Meta or the Command keys based on which one is applicable for this platform
|
// Update the state of either the concrete Meta or the Command keys based on which one is applicable for this platform
|
||||||
let meta_or_command = match keyboard_platform {
|
let meta_or_command = match Editor::environment().is_mac() {
|
||||||
KeyboardPlatformLayout::Mac => Key::Command,
|
true => Key::Command,
|
||||||
KeyboardPlatformLayout::Standard => Key::Meta,
|
false => Key::Meta,
|
||||||
};
|
};
|
||||||
self.update_modifier_key(meta_or_command, is_key_pressed(ModifierKeys::META_OR_COMMAND), responses);
|
self.update_modifier_key(meta_or_command, is_key_pressed(ModifierKeys::META_OR_COMMAND), responses);
|
||||||
|
|
||||||
// Update the state of the virtual Accel key (the primary accelerator key) based on the source state of the Control or Command key, whichever is relevant on this platform
|
// Update the state of the virtual Accel key (the primary accelerator key) based on the source state of the Control or Command key, whichever is relevant on this platform
|
||||||
let accel_virtual_key_state = match keyboard_platform {
|
let accel_virtual_key_state = match Editor::environment().is_mac() {
|
||||||
KeyboardPlatformLayout::Mac => is_key_pressed(ModifierKeys::META_OR_COMMAND),
|
true => is_key_pressed(ModifierKeys::META_OR_COMMAND),
|
||||||
KeyboardPlatformLayout::Standard => is_key_pressed(ModifierKeys::CONTROL),
|
false => is_key_pressed(ModifierKeys::CONTROL),
|
||||||
};
|
};
|
||||||
self.update_modifier_key(Key::Accel, accel_virtual_key_state, responses);
|
self.update_modifier_key(Key::Accel, accel_virtual_key_state, responses);
|
||||||
}
|
}
|
||||||
@@ -188,7 +187,6 @@ impl InputPreprocessorMessageHandler {
|
|||||||
mod test {
|
mod test {
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys};
|
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, ModifierKeys};
|
||||||
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta};
|
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta};
|
||||||
use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -206,7 +204,6 @@ mod test {
|
|||||||
let mut responses = VecDeque::new();
|
let mut responses = VecDeque::new();
|
||||||
|
|
||||||
let context = InputPreprocessorMessageContext {
|
let context = InputPreprocessorMessageContext {
|
||||||
keyboard_platform: KeyboardPlatformLayout::Standard,
|
|
||||||
viewport: &ViewportMessageHandler::default(),
|
viewport: &ViewportMessageHandler::default(),
|
||||||
};
|
};
|
||||||
input_preprocessor.process_message(message, &mut responses, context);
|
input_preprocessor.process_message(message, &mut responses, context);
|
||||||
@@ -226,7 +223,6 @@ mod test {
|
|||||||
let mut responses = VecDeque::new();
|
let mut responses = VecDeque::new();
|
||||||
|
|
||||||
let context = InputPreprocessorMessageContext {
|
let context = InputPreprocessorMessageContext {
|
||||||
keyboard_platform: KeyboardPlatformLayout::Standard,
|
|
||||||
viewport: &ViewportMessageHandler::default(),
|
viewport: &ViewportMessageHandler::default(),
|
||||||
};
|
};
|
||||||
input_preprocessor.process_message(message, &mut responses, context);
|
input_preprocessor.process_message(message, &mut responses, context);
|
||||||
@@ -246,7 +242,6 @@ mod test {
|
|||||||
let mut responses = VecDeque::new();
|
let mut responses = VecDeque::new();
|
||||||
|
|
||||||
let context = InputPreprocessorMessageContext {
|
let context = InputPreprocessorMessageContext {
|
||||||
keyboard_platform: KeyboardPlatformLayout::Standard,
|
|
||||||
viewport: &ViewportMessageHandler::default(),
|
viewport: &ViewportMessageHandler::default(),
|
||||||
};
|
};
|
||||||
input_preprocessor.process_message(message, &mut responses, context);
|
input_preprocessor.process_message(message, &mut responses, context);
|
||||||
@@ -268,7 +263,6 @@ mod test {
|
|||||||
let mut responses = VecDeque::new();
|
let mut responses = VecDeque::new();
|
||||||
|
|
||||||
let context = InputPreprocessorMessageContext {
|
let context = InputPreprocessorMessageContext {
|
||||||
keyboard_platform: KeyboardPlatformLayout::Standard,
|
|
||||||
viewport: &ViewportMessageHandler::default(),
|
viewport: &ViewportMessageHandler::default(),
|
||||||
};
|
};
|
||||||
input_preprocessor.process_message(message, &mut responses, context);
|
input_preprocessor.process_message(message, &mut responses, context);
|
||||||
@@ -289,7 +283,6 @@ mod test {
|
|||||||
let mut responses = VecDeque::new();
|
let mut responses = VecDeque::new();
|
||||||
|
|
||||||
let context = InputPreprocessorMessageContext {
|
let context = InputPreprocessorMessageContext {
|
||||||
keyboard_platform: KeyboardPlatformLayout::Standard,
|
|
||||||
viewport: &ViewportMessageHandler::default(),
|
viewport: &ViewportMessageHandler::default(),
|
||||||
};
|
};
|
||||||
input_preprocessor.process_message(message, &mut responses, context);
|
input_preprocessor.process_message(message, &mut responses, context);
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ pub enum Message {
|
|||||||
#[child]
|
#[child]
|
||||||
Frontend(FrontendMessage),
|
Frontend(FrontendMessage),
|
||||||
#[child]
|
#[child]
|
||||||
Globals(GlobalsMessage),
|
|
||||||
#[child]
|
|
||||||
InputPreprocessor(InputPreprocessorMessage),
|
InputPreprocessor(InputPreprocessorMessage),
|
||||||
#[child]
|
#[child]
|
||||||
KeyMapping(KeyMappingMessage),
|
KeyMapping(KeyMappingMessage),
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ pub mod debug;
|
|||||||
pub mod defer;
|
pub mod defer;
|
||||||
pub mod dialog;
|
pub mod dialog;
|
||||||
pub mod frontend;
|
pub mod frontend;
|
||||||
pub mod globals;
|
|
||||||
pub mod input_mapper;
|
pub mod input_mapper;
|
||||||
pub mod input_preprocessor;
|
pub mod input_preprocessor;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::application::Editor;
|
||||||
use crate::consts::{
|
use crate::consts::{
|
||||||
VIEWPORT_ROTATE_SNAP_INTERVAL, VIEWPORT_SCROLL_RATE, VIEWPORT_ZOOM_LEVELS, VIEWPORT_ZOOM_MIN_FRACTION_COVER, VIEWPORT_ZOOM_MOUSE_RATE, VIEWPORT_ZOOM_SCALE_MAX, VIEWPORT_ZOOM_SCALE_MIN,
|
VIEWPORT_ROTATE_SNAP_INTERVAL, VIEWPORT_SCROLL_RATE, VIEWPORT_ZOOM_LEVELS, VIEWPORT_ZOOM_MIN_FRACTION_COVER, VIEWPORT_ZOOM_MOUSE_RATE, VIEWPORT_ZOOM_SCALE_MAX, VIEWPORT_ZOOM_SCALE_MIN,
|
||||||
VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR,
|
VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR,
|
||||||
@@ -8,7 +9,6 @@ use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition;
|
|||||||
use crate::messages::portfolio::document::navigation::utility_types::NavigationOperation;
|
use crate::messages::portfolio::document::navigation::utility_types::NavigationOperation;
|
||||||
use crate::messages::portfolio::document::utility_types::misc::PTZ;
|
use crate::messages::portfolio::document::utility_types::misc::PTZ;
|
||||||
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
|
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
|
||||||
use crate::messages::portfolio::utility_types::KeyboardPlatformLayout;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
@@ -176,9 +176,7 @@ impl MessageHandler<NavigationMessage, NavigationMessageContext<'_>> for Navigat
|
|||||||
}
|
}
|
||||||
NavigationMessage::CanvasPanMouseWheel { use_y_as_x } => {
|
NavigationMessage::CanvasPanMouseWheel { use_y_as_x } => {
|
||||||
// On Mac, the OS already converts Shift+scroll into horizontal scrolling
|
// On Mac, the OS already converts Shift+scroll into horizontal scrolling
|
||||||
let keyboard_platform = GLOBAL_PLATFORM.get().copied().unwrap_or_default().as_keyboard_platform_layout();
|
let delta = if use_y_as_x && !Editor::environment().is_mac() {
|
||||||
|
|
||||||
let delta = if use_y_as_x && keyboard_platform == KeyboardPlatformLayout::Standard {
|
|
||||||
(ipp.mouse.scroll_delta.y, 0.).into()
|
(ipp.mouse.scroll_delta.y, 0.).into()
|
||||||
} else {
|
} else {
|
||||||
ipp.mouse.scroll_delta.as_dvec2()
|
ipp.mouse.scroll_delta.as_dvec2()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use super::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use super::document::utility_types::network_interface;
|
use super::document::utility_types::network_interface;
|
||||||
use super::utility_types::{PanelType, PersistentData};
|
use super::utility_types::{PanelType, PersistentData};
|
||||||
use crate::application::generate_uuid;
|
use crate::application::{Editor, generate_uuid};
|
||||||
use crate::consts::{DEFAULT_DOCUMENT_NAME, DEFAULT_STROKE_WIDTH, FILE_EXTENSION};
|
use crate::consts::{DEFAULT_DOCUMENT_NAME, DEFAULT_STROKE_WIDTH, FILE_EXTENSION};
|
||||||
use crate::messages::animation::TimingInformation;
|
use crate::messages::animation::TimingInformation;
|
||||||
use crate::messages::clipboard::utility_types::ClipboardContent;
|
use crate::messages::clipboard::utility_types::ClipboardContent;
|
||||||
@@ -101,9 +101,17 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||||||
|
|
||||||
// Messages
|
// Messages
|
||||||
PortfolioMessage::Init => {
|
PortfolioMessage::Init => {
|
||||||
|
// Initialize the frontend with environment information
|
||||||
|
responses.add(FrontendMessage::UpdatePlatform {
|
||||||
|
platform: Editor::environment().into(),
|
||||||
|
});
|
||||||
|
|
||||||
// Tell frontend to load persistent preferences
|
// Tell frontend to load persistent preferences
|
||||||
responses.add(FrontendMessage::TriggerLoadPreferences);
|
responses.add(FrontendMessage::TriggerLoadPreferences);
|
||||||
|
|
||||||
|
// Before loading any documents, initially prepare the welcome screen buttons layout
|
||||||
|
responses.add(PortfolioMessage::RequestWelcomeScreenButtonsLayout);
|
||||||
|
|
||||||
// Tell frontend to load the current document
|
// Tell frontend to load the current document
|
||||||
responses.add(FrontendMessage::TriggerLoadFirstAutoSaveDocument);
|
responses.add(FrontendMessage::TriggerLoadFirstAutoSaveDocument);
|
||||||
|
|
||||||
@@ -128,15 +136,13 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||||||
shortcut: action_shortcut_manual!(Key::Shift, Key::MouseLeft),
|
shortcut: action_shortcut_manual!(Key::Shift, Key::MouseLeft),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Before loading any documents, initially prepare the welcome screen buttons layout
|
|
||||||
responses.add(PortfolioMessage::RequestWelcomeScreenButtonsLayout);
|
|
||||||
|
|
||||||
// Request status bar info layout
|
// Request status bar info layout
|
||||||
responses.add(PortfolioMessage::RequestStatusBarInfoLayout);
|
responses.add(PortfolioMessage::RequestStatusBarInfoLayout);
|
||||||
|
|
||||||
// Tell frontend to finish loading persistent documents
|
// Tell frontend to finish loading persistent documents
|
||||||
responses.add(FrontendMessage::TriggerLoadRestAutoSaveDocuments);
|
responses.add(FrontendMessage::TriggerLoadRestAutoSaveDocuments);
|
||||||
|
|
||||||
|
// Tell frontend to load documented passed in as launch arguments
|
||||||
responses.add(FrontendMessage::TriggerOpenLaunchDocuments);
|
responses.add(FrontendMessage::TriggerOpenLaunchDocuments);
|
||||||
}
|
}
|
||||||
PortfolioMessage::DocumentPassMessage { document_id, message } => {
|
PortfolioMessage::DocumentPassMessage { document_id, message } => {
|
||||||
|
|||||||
@@ -82,37 +82,6 @@ impl FontCatalogStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub enum Platform {
|
|
||||||
#[default]
|
|
||||||
Unknown,
|
|
||||||
Windows,
|
|
||||||
Mac,
|
|
||||||
Linux,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Platform {
|
|
||||||
pub fn as_keyboard_platform_layout(&self) -> KeyboardPlatformLayout {
|
|
||||||
match self {
|
|
||||||
Platform::Mac => KeyboardPlatformLayout::Mac,
|
|
||||||
Platform::Windows | Platform::Linux => KeyboardPlatformLayout::Standard,
|
|
||||||
Platform::Unknown => {
|
|
||||||
warn!("The platform has not been set, remember to send `GlobalsMessage::SetPlatform` during editor initialization.");
|
|
||||||
KeyboardPlatformLayout::Standard
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Default, Debug, serde::Serialize, serde::Deserialize)]
|
|
||||||
pub enum KeyboardPlatformLayout {
|
|
||||||
/// Standard keyboard mapping used by Windows and Linux
|
|
||||||
#[default]
|
|
||||||
Standard,
|
|
||||||
/// Keyboard mapping used by Macs where Command is sometimes used in favor of Control
|
|
||||||
Mac,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, Default, serde::Serialize, serde::Deserialize)]
|
#[derive(PartialEq, Eq, Clone, Copy, Debug, Default, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum PanelType {
|
pub enum PanelType {
|
||||||
#[default]
|
#[default]
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ pub use crate::messages::dialog::new_document_dialog::{NewDocumentDialogMessage,
|
|||||||
pub use crate::messages::dialog::preferences_dialog::{PreferencesDialogMessage, PreferencesDialogMessageContext, PreferencesDialogMessageDiscriminant, PreferencesDialogMessageHandler};
|
pub use crate::messages::dialog::preferences_dialog::{PreferencesDialogMessage, PreferencesDialogMessageContext, PreferencesDialogMessageDiscriminant, PreferencesDialogMessageHandler};
|
||||||
pub use crate::messages::dialog::{DialogMessage, DialogMessageContext, DialogMessageDiscriminant, DialogMessageHandler};
|
pub use crate::messages::dialog::{DialogMessage, DialogMessageContext, DialogMessageDiscriminant, DialogMessageHandler};
|
||||||
pub use crate::messages::frontend::{FrontendMessage, FrontendMessageDiscriminant};
|
pub use crate::messages::frontend::{FrontendMessage, FrontendMessageDiscriminant};
|
||||||
pub use crate::messages::globals::{GlobalsMessage, GlobalsMessageDiscriminant, GlobalsMessageHandler};
|
|
||||||
pub use crate::messages::input_mapper::key_mapping::{KeyMappingMessage, KeyMappingMessageContext, KeyMappingMessageDiscriminant, KeyMappingMessageHandler};
|
pub use crate::messages::input_mapper::key_mapping::{KeyMappingMessage, KeyMappingMessageContext, KeyMappingMessageDiscriminant, KeyMappingMessageHandler};
|
||||||
pub use crate::messages::input_mapper::{InputMapperMessage, InputMapperMessageContext, InputMapperMessageDiscriminant, InputMapperMessageHandler};
|
pub use crate::messages::input_mapper::{InputMapperMessage, InputMapperMessageContext, InputMapperMessageDiscriminant, InputMapperMessageHandler};
|
||||||
pub use crate::messages::input_preprocessor::{InputPreprocessorMessage, InputPreprocessorMessageContext, InputPreprocessorMessageDiscriminant, InputPreprocessorMessageHandler};
|
pub use crate::messages::input_preprocessor::{InputPreprocessorMessage, InputPreprocessorMessageContext, InputPreprocessorMessageDiscriminant, InputPreprocessorMessageHandler};
|
||||||
@@ -51,7 +50,6 @@ pub use crate::messages::tool::tool_messages::spline_tool::{SplineToolMessage, S
|
|||||||
pub use crate::messages::tool::tool_messages::text_tool::{TextToolMessage, TextToolMessageDiscriminant};
|
pub use crate::messages::tool::tool_messages::text_tool::{TextToolMessage, TextToolMessageDiscriminant};
|
||||||
|
|
||||||
// Helper/miscellaneous
|
// Helper/miscellaneous
|
||||||
pub use crate::messages::globals::global_variables::*;
|
|
||||||
pub use crate::messages::portfolio::document::utility_types::misc::DocumentId;
|
pub use crate::messages::portfolio::document::utility_types::misc::DocumentId;
|
||||||
pub use graphite_proc_macros::*;
|
pub use graphite_proc_macros::*;
|
||||||
pub use std::collections::{HashMap, HashSet, VecDeque};
|
pub use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
use crate::application::Editor;
|
use crate::application::Editor;
|
||||||
use crate::application::set_uuid_seed;
|
|
||||||
use crate::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
|
use crate::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
|
||||||
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta, ViewportPosition};
|
use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta, ViewportPosition};
|
||||||
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier;
|
||||||
use crate::messages::portfolio::utility_types::Platform;
|
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::tool_messages::tool_prelude::Key;
|
use crate::messages::tool::tool_messages::tool_prelude::Key;
|
||||||
use crate::messages::tool::utility_types::ToolType;
|
use crate::messages::tool::utility_types::ToolType;
|
||||||
@@ -25,15 +23,11 @@ pub struct EditorTestUtils {
|
|||||||
impl EditorTestUtils {
|
impl EditorTestUtils {
|
||||||
pub fn create() -> Self {
|
pub fn create() -> Self {
|
||||||
let _ = env_logger::builder().is_test(true).try_init();
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
set_uuid_seed(0);
|
|
||||||
|
|
||||||
let (mut editor, runtime) = Editor::new_local_executor();
|
let (mut editor, runtime) = Editor::new_local_executor();
|
||||||
|
|
||||||
// We have to set this directly instead of using `GlobalsMessage::SetPlatform` because race conditions with multiple tests can cause that message handler to set it more than once, which is a failure.
|
|
||||||
// It isn't sufficient to guard the message dispatch here with a check if the once_cell is empty, because that isn't atomic and the time between checking and handling the dispatch can let multiple through.
|
|
||||||
let _ = GLOBAL_PLATFORM.set(Platform::Windows).is_ok();
|
|
||||||
|
|
||||||
editor.handle_message(PortfolioMessage::Init);
|
editor.handle_message(PortfolioMessage::Init);
|
||||||
|
|
||||||
Self { editor, runtime }
|
Self { editor, runtime }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
import { createNodeGraphState } from "@graphite/state-providers/node-graph";
|
import { createNodeGraphState } from "@graphite/state-providers/node-graph";
|
||||||
import { createPortfolioState } from "@graphite/state-providers/portfolio";
|
import { createPortfolioState } from "@graphite/state-providers/portfolio";
|
||||||
import { createTooltipState } from "@graphite/state-providers/tooltip";
|
import { createTooltipState } from "@graphite/state-providers/tooltip";
|
||||||
import { operatingSystem } from "@graphite/utility-functions/platform";
|
|
||||||
|
|
||||||
import MainWindow from "@graphite/components/window/MainWindow.svelte";
|
import MainWindow from "@graphite/components/window/MainWindow.svelte";
|
||||||
|
|
||||||
@@ -51,7 +50,7 @@
|
|||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
// Initialize certain setup tasks required by the editor backend to be ready for the user now that the frontend is ready
|
// Initialize certain setup tasks required by the editor backend to be ready for the user now that the frontend is ready
|
||||||
editor.handle.initAfterFrontendReady(operatingSystem());
|
editor.handle.initAfterFrontendReady();
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
|
|||||||
+17
-14
@@ -1,8 +1,12 @@
|
|||||||
// import { panicProxy } from "@graphite/utility-functions/panic-proxy";
|
// import { panicProxy } from "@graphite/utility-functions/panic-proxy";
|
||||||
import init, { setRandomSeed, wasmMemory, EditorHandle, receiveNativeMessage } from "@graphite/../wasm/pkg/graphite_wasm";
|
|
||||||
|
import { EditorHandle } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||||
|
import init, { wasmMemory, receiveNativeMessage } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||||
import { type JsMessageType } from "@graphite/messages";
|
import { type JsMessageType } from "@graphite/messages";
|
||||||
import { createSubscriptionRouter, type SubscriptionRouter } from "@graphite/subscription-router";
|
import { createSubscriptionRouter, type SubscriptionRouter } from "@graphite/subscription-router";
|
||||||
|
import { operatingSystem } from "@graphite/utility-functions/platform";
|
||||||
|
|
||||||
|
// TODO: Remove `raw`, split out `subscriptions`, and unwrap the remaining `handle` so `EditorHandle` can replace `Editor` and then it can also be renamed to `Editor` to fully remove `EditorHandle`.
|
||||||
export type Editor = {
|
export type Editor = {
|
||||||
raw: WebAssembly.Memory;
|
raw: WebAssembly.Memory;
|
||||||
handle: EditorHandle;
|
handle: EditorHandle;
|
||||||
@@ -14,10 +18,10 @@ let wasmImport: WebAssembly.Memory | undefined;
|
|||||||
|
|
||||||
// Should be called asynchronously before `createEditor()`.
|
// Should be called asynchronously before `createEditor()`.
|
||||||
export async function initWasm() {
|
export async function initWasm() {
|
||||||
// Skip if the WASM module is already initialized
|
// Skip if the Wasm module is already initialized
|
||||||
if (wasmImport !== undefined) return;
|
if (wasmImport !== undefined) return;
|
||||||
|
|
||||||
// Import the WASM module JS bindings and wrap them in the panic proxy
|
// Import the Wasm module JS bindings and wrap them in the panic proxy
|
||||||
const wasm = await init();
|
const wasm = await init();
|
||||||
for (const [name, f] of Object.entries(wasm)) {
|
for (const [name, f] of Object.entries(wasm)) {
|
||||||
if (name.startsWith("__node_registry")) f();
|
if (name.startsWith("__node_registry")) f();
|
||||||
@@ -28,28 +32,27 @@ export async function initWasm() {
|
|||||||
(window as any).imageCanvases = {};
|
(window as any).imageCanvases = {};
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(window as any).receiveNativeMessage = receiveNativeMessage;
|
(window as any).receiveNativeMessage = receiveNativeMessage;
|
||||||
|
|
||||||
// Provide a random starter seed which must occur after initializing the WASM module, since WASM can't generate its own random numbers
|
|
||||||
const randomSeedFloat = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
|
||||||
const randomSeed = BigInt(randomSeedFloat);
|
|
||||||
setRandomSeed(randomSeed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be called after running `initWasm()` and its promise resolving.
|
// Should be called after running `initWasm()` and its promise resolving.
|
||||||
export function createEditor(): Editor {
|
export function createEditor(): Editor {
|
||||||
// Raw: object containing several callable functions from `editor_api.rs` defined directly on the WASM module, not the `EditorHandle` struct (generated by wasm-bindgen)
|
// Raw: object containing several callable functions from `editor_api.rs` defined directly on the Wasm module, not the `EditorHandle` struct (generated by wasm-bindgen)
|
||||||
if (!wasmImport) throw new Error("Editor WASM backend was not initialized at application startup");
|
if (!wasmImport) throw new Error("Editor Wasm backend was not initialized at application startup");
|
||||||
const raw: WebAssembly.Memory = wasmImport;
|
const raw: WebAssembly.Memory = wasmImport;
|
||||||
|
|
||||||
|
// Provide a random starter seed which must occur after initializing the Wasm module, since Wasm can't generate its own random numbers
|
||||||
|
const randomSeedFloat = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
||||||
|
const randomSeed = BigInt(randomSeedFloat);
|
||||||
|
|
||||||
// Handle: object containing many functions from `editor_api.rs` that are part of the `EditorHandle` struct (generated by wasm-bindgen)
|
// Handle: object containing many functions from `editor_api.rs` that are part of the `EditorHandle` struct (generated by wasm-bindgen)
|
||||||
const handle: EditorHandle = new EditorHandle((messageType: JsMessageType, messageData: Record<string, unknown>) => {
|
const handle = EditorHandle.create(operatingSystem(), randomSeed, (messageType: JsMessageType, messageData: Record<string, unknown>) => {
|
||||||
// This callback is called by WASM when a FrontendMessage is received from the WASM wrapper `EditorHandle`
|
// This callback is called by Wasm when a FrontendMessage is received from the Wasm wrapper `EditorHandle`
|
||||||
// We pass along the first two arguments then add our own `raw` and `handle` context for the last two arguments
|
// We pass along the first two arguments then add our own `raw` and `handle` context for the last two arguments
|
||||||
subscriptions.handleJsMessage(messageType, messageData, raw, handle);
|
subscriptions.handleJsMessage(messageType, messageData, raw, handle);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Subscriptions: allows subscribing to messages in JS that are sent from the WASM backend
|
// Subscriptions: allows subscribing to messages in JS that are sent from the Wasm backend
|
||||||
const subscriptions: SubscriptionRouter = createSubscriptionRouter();
|
const subscriptions = createSubscriptionRouter();
|
||||||
|
|
||||||
// Check if the URL hash fragment has any demo artwork to be loaded
|
// Check if the URL hash fragment has any demo artwork to be loaded
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export function githubUrl(panicDetails: string): string {
|
|||||||
Provide any further information or context that you think would be helpful in fixing the issue. Screenshots or video can be linked or attached to this issue.
|
Provide any further information or context that you think would be helpful in fixing the issue. Screenshots or video can be linked or attached to this issue.
|
||||||
|
|
||||||
**Browser and OS**
|
**Browser and OS**
|
||||||
${browserVersion()}, ${operatingSystem().replace("Unknown", "YOUR OPERATING SYSTEM")}
|
${browserVersion()}, ${operatingSystem()}
|
||||||
|
|
||||||
**Stack Trace**
|
**Stack Trace**
|
||||||
Copied from the crash dialog in the Graphite editor:
|
Copied from the crash dialog in the Graphite editor:
|
||||||
|
|||||||
@@ -25,18 +25,17 @@ export function browserVersion(): string {
|
|||||||
return `${match[0]} ${match[1]}`;
|
return `${match[0]} ${match[1]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OperatingSystem = "Windows" | "Mac" | "Linux" | "Unknown";
|
export type OperatingSystem = "Windows" | "Mac" | "Linux";
|
||||||
|
|
||||||
export function operatingSystem(): OperatingSystem {
|
export function operatingSystem(): OperatingSystem {
|
||||||
const osTable: Record<string, OperatingSystem> = {
|
const osTable: Record<string, OperatingSystem> = {
|
||||||
Windows: "Windows",
|
Windows: "Windows",
|
||||||
Mac: "Mac",
|
Mac: "Mac",
|
||||||
Linux: "Linux",
|
Linux: "Linux",
|
||||||
Unknown: "Unknown",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const userAgentOS = Object.keys(osTable).find((key) => window.navigator.userAgent.includes(key));
|
const userAgentOS = Object.keys(osTable).find((key) => window.navigator.userAgent.includes(key));
|
||||||
return osTable[userAgentOS || "Unknown"];
|
return osTable[userAgentOS || "Windows"];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isDesktop(): boolean {
|
export function isDesktop(): boolean {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use editor::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
|
|||||||
use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ScrollDelta};
|
use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ScrollDelta};
|
||||||
use editor::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use editor::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use editor::messages::portfolio::document::utility_types::network_interface::ImportOrExport;
|
use editor::messages::portfolio::document::utility_types::network_interface::ImportOrExport;
|
||||||
use editor::messages::portfolio::utility_types::{FontCatalog, FontCatalogFamily, Platform};
|
use editor::messages::portfolio::utility_types::{FontCatalog, FontCatalogFamily};
|
||||||
use editor::messages::prelude::*;
|
use editor::messages::prelude::*;
|
||||||
use editor::messages::tool::tool_messages::tool_prelude::WidgetId;
|
use editor::messages::tool::tool_messages::tool_prelude::WidgetId;
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
@@ -31,7 +31,7 @@ use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, ImageData, window};
|
|||||||
#[cfg(not(feature = "native"))]
|
#[cfg(not(feature = "native"))]
|
||||||
use crate::EDITOR;
|
use crate::EDITOR;
|
||||||
#[cfg(not(feature = "native"))]
|
#[cfg(not(feature = "native"))]
|
||||||
use editor::application::Editor;
|
use editor::application::{Editor, Environment, Host, Platform};
|
||||||
|
|
||||||
static IMAGE_DATA_HASH: AtomicU64 = AtomicU64::new(0);
|
static IMAGE_DATA_HASH: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
@@ -43,14 +43,7 @@ fn calculate_hash<T: std::hash::Hash>(t: &T) -> u64 {
|
|||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the random seed used by the editor by calling this from JS upon initialization.
|
/// Provides a handle to access the raw Wasm memory.
|
||||||
/// This is necessary because WASM doesn't have a random number generator.
|
|
||||||
#[wasm_bindgen(js_name = setRandomSeed)]
|
|
||||||
pub fn set_random_seed(seed: u64) {
|
|
||||||
editor::application::set_uuid_seed(seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Provides a handle to access the raw WASM memory.
|
|
||||||
#[wasm_bindgen(js_name = wasmMemory)]
|
#[wasm_bindgen(js_name = wasmMemory)]
|
||||||
pub fn wasm_memory() -> JsValue {
|
pub fn wasm_memory() -> JsValue {
|
||||||
wasm_bindgen::memory()
|
wasm_bindgen::memory()
|
||||||
@@ -89,9 +82,20 @@ impl EditorHandle {
|
|||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
impl EditorHandle {
|
impl EditorHandle {
|
||||||
#[cfg(not(feature = "native"))]
|
#[cfg(not(feature = "native"))]
|
||||||
#[wasm_bindgen(constructor)]
|
pub fn create(platform: String, uuid_random_seed: u64, frontend_message_handler_callback: js_sys::Function) -> EditorHandle {
|
||||||
pub fn new(frontend_message_handler_callback: js_sys::Function) -> Self {
|
let editor = Editor::new(
|
||||||
let editor = Editor::new();
|
Environment {
|
||||||
|
platform: Platform::Web,
|
||||||
|
host: match platform.as_str() {
|
||||||
|
"Linux" => Host::Linux,
|
||||||
|
"Mac" => Host::Mac,
|
||||||
|
"Windows" => Host::Windows,
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uuid_random_seed,
|
||||||
|
);
|
||||||
|
|
||||||
let editor_handle = EditorHandle { frontend_message_handler_callback };
|
let editor_handle = EditorHandle { frontend_message_handler_callback };
|
||||||
if EDITOR.with(|handle| handle.lock().ok().map(|mut guard| *guard = Some(editor))).is_none() {
|
if EDITOR.with(|handle| handle.lock().ok().map(|mut guard| *guard = Some(editor))).is_none() {
|
||||||
log::error!("Attempted to initialize the editor more than once");
|
log::error!("Attempted to initialize the editor more than once");
|
||||||
@@ -103,8 +107,7 @@ impl EditorHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "native")]
|
#[cfg(feature = "native")]
|
||||||
#[wasm_bindgen(constructor)]
|
pub fn create(_platform: String, _uuid_random_seed: u64, frontend_message_handler_callback: js_sys::Function) -> EditorHandle {
|
||||||
pub fn new(frontend_message_handler_callback: js_sys::Function) -> Self {
|
|
||||||
let editor_handle = EditorHandle { frontend_message_handler_callback };
|
let editor_handle = EditorHandle { frontend_message_handler_callback };
|
||||||
if EDITOR_HANDLE.with(|handle| handle.lock().ok().map(|mut guard| *guard = Some(editor_handle.clone()))).is_none() {
|
if EDITOR_HANDLE.with(|handle| handle.lock().ok().map(|mut guard| *guard = Some(editor_handle.clone()))).is_none() {
|
||||||
log::error!("Attempted to initialize the editor handle more than once");
|
log::error!("Attempted to initialize the editor handle more than once");
|
||||||
@@ -184,18 +187,10 @@ impl EditorHandle {
|
|||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
#[wasm_bindgen(js_name = initAfterFrontendReady)]
|
#[wasm_bindgen(js_name = initAfterFrontendReady)]
|
||||||
pub fn init_after_frontend_ready(&self, platform: String) {
|
pub fn init_after_frontend_ready(&self) {
|
||||||
#[cfg(feature = "native")]
|
#[cfg(feature = "native")]
|
||||||
crate::native_communcation::initialize_native_communication();
|
crate::native_communcation::initialize_native_communication();
|
||||||
|
|
||||||
// Send initialization messages
|
|
||||||
let platform = match platform.as_str() {
|
|
||||||
"Windows" => Platform::Windows,
|
|
||||||
"Mac" => Platform::Mac,
|
|
||||||
"Linux" => Platform::Linux,
|
|
||||||
_ => Platform::Unknown,
|
|
||||||
};
|
|
||||||
self.dispatch(GlobalsMessage::SetPlatform { platform });
|
|
||||||
self.dispatch(PortfolioMessage::Init);
|
self.dispatch(PortfolioMessage::Init);
|
||||||
|
|
||||||
// Poll node graph evaluation on `requestAnimationFrame`
|
// Poll node graph evaluation on `requestAnimationFrame`
|
||||||
|
|||||||
Reference in New Issue
Block a user