Skip to content

Add full support for Mac-specific keyboard layouts #736

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Aug 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8da6f40
IPP for Mac, flawed initial experiments
Keavon Jul 24, 2022
57e84e0
Cleanup and progress, but not compiling yet
Keavon Jul 24, 2022
62590e2
Fix error and rename nonmac -> standard
Keavon Jul 24, 2022
41fe002
Extentd ipp macros to accomodate mac input
TrueDoctor Jul 24, 2022
654f513
Add Mac versions of shortcuts; refactor and document the input mapper…
Keavon Jul 25, 2022
9f4275e
Change frontend styling for user input labels in floating menus
Keavon Jul 25, 2022
3871228
Additional macro documentation
Keavon Jul 25, 2022
3b0e4bf
A little more documentation
Keavon Jul 25, 2022
5ce54e4
Improve entry macro syntax
Keavon Jul 26, 2022
9dd786b
Move input mapper macros to a separate file
Keavon Jul 26, 2022
9f9aa24
Adapt the keyboard shortcuts to the user's OS
Keavon Jul 26, 2022
49fc1e4
Display keyboard shortcuts in the menu bar based on OS
Keavon Jul 28, 2022
357df60
Change Input Mapper macro syntax from {} to ()
Keavon Jul 28, 2022
fdb5424
Fix esc key bug in Vue
Keavon Jul 28, 2022
cea7553
Tweaks
Keavon Jul 28, 2022
a8cc120
Interim solution for Mac-specific hints
Keavon Jul 30, 2022
4661004
Feed tooltip input hotkeys from their actions
Keavon Jul 31, 2022
9fac94c
Fix hotkeys for tools because of missing actions
Keavon Aug 1, 2022
09b2228
Make Vue respect Ctrl/Cmd differences per platform
Keavon Aug 1, 2022
2fbf3d5
Merge branch 'master' into ipp-for-mac
Keavon Aug 1, 2022
a0c0ba0
Remove commented lines
Keavon Aug 1, 2022
15d0bae
Code review pass by me
Keavon Aug 1, 2022
253228a
Code review suggestions with TrueDoctor
Keavon Aug 2, 2022
80cdfb5
Turn FutureKeyMapping struct into ActionKeys enum which is a bit cleaner
Keavon Aug 3, 2022
de4b9b0
Add serde derive attributes for message discriminants
TrueDoctor Aug 3, 2022
60c49c5
Re-add serde deserialize
Keavon Aug 3, 2022
3c2f58d
Merge branch 'master' into ipp-for-mac
Keavon Aug 3, 2022
bff11aa
Fix not mutating ActionKeys conversion; remove custom serializer
Keavon Aug 3, 2022
d6df317
Add serde to dev dependencies
TrueDoctor Aug 3, 2022
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
2 changes: 1 addition & 1 deletion bezier-rs/docs/interactive-docs/wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "bezier-rs-wasm"
publish = false
version = "0.0.0"
rust-version = "1.56.0"
rust-version = "1.62.0"
authors = ["Graphite Authors <[email protected]>"]
edition = "2021"
readme = "../../README.md"
Expand Down
2 changes: 1 addition & 1 deletion bezier-rs/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "bezier-rs"
publish = false
version = "0.0.0"
rust-version = "1.56.0"
rust-version = "1.62.0"
authors = ["Graphite Authors <[email protected]>"]
edition = "2021"
readme = "./README.md"
Expand Down
2 changes: 1 addition & 1 deletion editor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "graphite-editor"
publish = false
version = "0.0.0"
rust-version = "1.56.0"
rust-version = "1.62.0"
authors = ["Graphite Authors <[email protected]>"]
edition = "2021"
readme = "../README.md"
Expand Down
23 changes: 17 additions & 6 deletions editor/src/communication/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,14 +138,25 @@ impl Dispatcher {
}
InputMapper(message) => {
let actions = self.collect_actions();
let keyboard_platform = self.message_handlers.portfolio_message_handler.platform.as_keyboard_platform_layout();

self.message_handlers
.input_mapper_message_handler
.process_action(message, (&self.message_handlers.input_preprocessor_message_handler, actions), &mut queue);
.process_action(message, (&self.message_handlers.input_preprocessor_message_handler, keyboard_platform, actions), &mut queue);
}
InputPreprocessor(message) => {
self.message_handlers.input_preprocessor_message_handler.process_action(message, (), &mut queue);
let keyboard_platform = self.message_handlers.portfolio_message_handler.platform.as_keyboard_platform_layout();

self.message_handlers.input_preprocessor_message_handler.process_action(message, keyboard_platform, &mut queue);
}
Layout(message) => {
let keyboard_platform = self.message_handlers.portfolio_message_handler.platform.as_keyboard_platform_layout();
let action_input_mapping = &|action_to_find: &MessageDiscriminant| self.message_handlers.input_mapper_message_handler.action_input_mapping(action_to_find, keyboard_platform);

self.message_handlers
.layout_message_handler
.process_action(message, (action_input_mapping, keyboard_platform), &mut queue);
}
Layout(message) => self.message_handlers.layout_message_handler.process_action(message, (), &mut queue),
Portfolio(message) => {
self.message_handlers
.portfolio_message_handler
Expand Down Expand Up @@ -518,15 +529,15 @@ mod test {
replacement_selected_layers: sorted_layers[..2].to_vec(),
});

editor.handle_message(DocumentMessage::ReorderSelectedLayers { relative_index_offset: 1 });
editor.handle_message(DocumentMessage::SelectedLayersRaise);
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap());
assert_eq!(all, non_selected.into_iter().chain(selected.into_iter()).collect::<Vec<_>>());

editor.handle_message(DocumentMessage::ReorderSelectedLayers { relative_index_offset: -1 });
editor.handle_message(DocumentMessage::SelectedLayersLower);
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap());
assert_eq!(all, selected.into_iter().chain(non_selected.into_iter()).collect::<Vec<_>>());

editor.handle_message(DocumentMessage::ReorderSelectedLayers { relative_index_offset: isize::MAX });
editor.handle_message(DocumentMessage::SelectedLayersRaiseToFront);
let (all, non_selected, selected) = verify_order(editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap());
assert_eq!(all, non_selected.into_iter().chain(selected.into_iter()).collect::<Vec<_>>());
}
Expand Down
2 changes: 2 additions & 0 deletions editor/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub const PATH_OUTLINE_WEIGHT: f64 = 2.;
pub const ROTATE_SNAP_ANGLE: f64 = 15.;
pub const SCALE_SNAP_INTERVAL: f64 = 0.1;
pub const SLOWING_DIVISOR: f64 = 10.;
pub const NUDGE_AMOUNT: f64 = 1.;
pub const BIG_NUDGE_AMOUNT: f64 = 10.;

// Select tool
pub const SELECTION_TOLERANCE: f64 = 5.;
Expand Down
4 changes: 2 additions & 2 deletions editor/src/dialog/dialog_message.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{ExportDialogUpdate, NewDocumentDialogUpdate};
use crate::message_prelude::*;
use serde::{Deserialize, Serialize};

use super::{ExportDialogUpdate, NewDocumentDialogUpdate};
use serde::{Deserialize, Serialize};

#[remain::sorted]
#[impl_message(Message, Dialog)]
Expand Down
10 changes: 7 additions & 3 deletions editor/src/document/document_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,16 @@ pub enum DocumentMessage {
new_name: String,
},
RenderDocument,
ReorderSelectedLayers {
relative_index_offset: isize,
},
RollbackTransaction,
SaveDocument,
SelectAllLayers,
SelectedLayersLower,
SelectedLayersLowerToBack,
SelectedLayersRaise,
SelectedLayersRaiseToFront,
SelectedLayersReorder {
relative_index_offset: isize,
},
SelectLayer {
layer_path: Vec<LayerId>,
ctrl: bool,
Expand Down
141 changes: 83 additions & 58 deletions editor/src/document/document_message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use super::{vectorize_layer_metadata, PropertiesPanelMessageHandler};
use super::{ArtboardMessageHandler, MovementMessageHandler, OverlaysMessageHandler, TransformLayerMessageHandler};
use crate::consts::{ASYMPTOTIC_EFFECT, DEFAULT_DOCUMENT_NAME, FILE_SAVE_SUFFIX, GRAPHITE_DOCUMENT_VERSION, SCALE_EFFECT, SCROLLBAR_SPACING, VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR};
use crate::frontend::utility_types::{FileType, FrontendImageData};
use crate::input::input_mapper::action_keys::action_shortcut;
use crate::input::InputPreprocessorMessageHandler;
use crate::layout::layout_message::LayoutTarget;
use crate::layout::widgets::{
Expand Down Expand Up @@ -549,6 +550,7 @@ impl DocumentMessageHandler {
icon: "Snapping".into(),
tooltip: "Snapping".into(),
on_update: WidgetCallback::new(|optional_input: &OptionalInput| DocumentMessage::SetSnapping { snap: optional_input.checked }.into()),
..Default::default()
})),
WidgetHolder::new(Widget::PopoverButton(PopoverButton {
header: "Snapping".into(),
Expand All @@ -564,6 +566,7 @@ impl DocumentMessageHandler {
icon: "Grid".into(),
tooltip: "Grid".into(),
on_update: WidgetCallback::new(|_| DialogMessage::RequestComingSoonDialog { issue: Some(318) }.into()),
..Default::default()
})),
WidgetHolder::new(Widget::PopoverButton(PopoverButton {
header: "Grid".into(),
Expand All @@ -579,6 +582,7 @@ impl DocumentMessageHandler {
icon: "Overlays".into(),
tooltip: "Overlays".into(),
on_update: WidgetCallback::new(|optional_input: &OptionalInput| DocumentMessage::SetOverlaysVisibility { visible: optional_input.checked }.into()),
..Default::default()
})),
WidgetHolder::new(Widget::PopoverButton(PopoverButton {
header: "Overlays".into(),
Expand Down Expand Up @@ -841,14 +845,16 @@ impl DocumentMessageHandler {
})),
WidgetHolder::new(Widget::IconButton(IconButton {
icon: "NodeFolder".into(),
tooltip: "New Folder (Ctrl+Shift+N)".into(), // TODO: Customize this tooltip for the Mac version of the keyboard shortcut
tooltip: "New Folder".into(),
tooltip_shortcut: action_shortcut!(DocumentMessageDiscriminant::CreateEmptyFolder),
size: 24,
on_update: WidgetCallback::new(|_| DocumentMessage::CreateEmptyFolder { container_path: vec![] }.into()),
..Default::default()
})),
WidgetHolder::new(Widget::IconButton(IconButton {
icon: "Trash".into(),
tooltip: "Delete Selected (Del)".into(), // TODO: Customize this tooltip for the Mac version of the keyboard shortcut
tooltip: "Delete Selected".into(),
tooltip_shortcut: action_shortcut!(DocumentMessageDiscriminant::DeleteSelectedLayers),
size: 24,
on_update: WidgetCallback::new(|_| DocumentMessage::DeleteSelectedLayers.into()),
..Default::default()
Expand All @@ -864,6 +870,62 @@ impl DocumentMessageHandler {
.into(),
);
}

pub fn selected_layers_reorder(&mut self, relative_index_offset: isize, responses: &mut VecDeque<Message>) {
self.backup(responses);

let all_layer_paths = self.all_layers_sorted();
let selected_layers = self.selected_layers_sorted();

let first_or_last_selected_layer = match relative_index_offset.signum() {
-1 => selected_layers.first(),
1 => selected_layers.last(),
_ => panic!("selected_layers_reorder() must be given a non-zero value"),
};

if let Some(pivot_layer) = first_or_last_selected_layer {
let sibling_layer_paths: Vec<_> = all_layer_paths
.iter()
.filter(|layer| {
// Check if this is a sibling of the pivot layer
// TODO: Break this out into a reusable function `fn are_layers_siblings(layer_a, layer_b) -> bool`
let containing_folder_path = &pivot_layer[0..pivot_layer.len() - 1];
layer.starts_with(containing_folder_path) && pivot_layer.len() == layer.len()
})
.collect();

// TODO: Break this out into a reusable function: `fn layer_index_in_containing_folder(layer_path) -> usize`
let pivot_index_among_siblings = sibling_layer_paths.iter().position(|path| *path == pivot_layer);

if let Some(pivot_index) = pivot_index_among_siblings {
let max = sibling_layer_paths.len() as i64 - 1;
let insert_index = (pivot_index as i64 + relative_index_offset as i64).clamp(0, max) as usize;

let existing_layer_to_insert_beside = sibling_layer_paths.get(insert_index);

// TODO: Break this block out into a call to a message called `MoveSelectedLayersNextToLayer { neighbor_path, above_or_below }`
if let Some(neighbor_path) = existing_layer_to_insert_beside {
let (neighbor_id, folder_path) = neighbor_path.split_last().expect("Can't move the root folder");

if let Some(folder) = self.graphene_document.layer(folder_path).ok().and_then(|layer| layer.as_folder().ok()) {
let neighbor_layer_index = folder.layer_ids.iter().position(|id| id == neighbor_id).unwrap() as isize;

// If moving down, insert below this layer. If moving up, insert above this layer.
let insert_index = if relative_index_offset < 0 { neighbor_layer_index } else { neighbor_layer_index + 1 };

responses.push_back(
DocumentMessage::MoveSelectedLayersTo {
folder_path: folder_path.to_vec(),
insert_index,
reverse_index: false,
}
.into(),
);
}
}
}
}
}
}

impl MessageHandler<DocumentMessage, (&InputPreprocessorMessageHandler, &FontCache)> for DocumentMessageHandler {
Expand Down Expand Up @@ -1318,61 +1380,6 @@ impl MessageHandler<DocumentMessage, (&InputPreprocessorMessageHandler, &FontCac
.into(),
);
}
ReorderSelectedLayers { relative_index_offset } => {
self.backup(responses);

let all_layer_paths = self.all_layers_sorted();
let selected_layers = self.selected_layers_sorted();

let first_or_last_selected_layer = match relative_index_offset.signum() {
-1 => selected_layers.first(),
1 => selected_layers.last(),
_ => panic!("ReorderSelectedLayers must be given a non-zero value"),
};

if let Some(pivot_layer) = first_or_last_selected_layer {
let sibling_layer_paths: Vec<_> = all_layer_paths
.iter()
.filter(|layer| {
// Check if this is a sibling of the pivot layer
// TODO: Break this out into a reusable function `fn are_layers_siblings(layer_a, layer_b) -> bool`
let containing_folder_path = &pivot_layer[0..pivot_layer.len() - 1];
layer.starts_with(containing_folder_path) && pivot_layer.len() == layer.len()
})
.collect();

// TODO: Break this out into a reusable function: `fn layer_index_in_containing_folder(layer_path) -> usize`
let pivot_index_among_siblings = sibling_layer_paths.iter().position(|path| *path == pivot_layer);

if let Some(pivot_index) = pivot_index_among_siblings {
let max = sibling_layer_paths.len() as i64 - 1;
let insert_index = (pivot_index as i64 + relative_index_offset as i64).clamp(0, max) as usize;

let existing_layer_to_insert_beside = sibling_layer_paths.get(insert_index);

// TODO: Break this block out into a call to a message called `MoveSelectedLayersNextToLayer { neighbor_path, above_or_below }`
if let Some(neighbor_path) = existing_layer_to_insert_beside {
let (neighbor_id, folder_path) = neighbor_path.split_last().expect("Can't move the root folder");

if let Some(folder) = self.graphene_document.layer(folder_path).ok().and_then(|layer| layer.as_folder().ok()) {
let neighbor_layer_index = folder.layer_ids.iter().position(|id| id == neighbor_id).unwrap() as isize;

// If moving down, insert below this layer. If moving up, insert above this layer.
let insert_index = if relative_index_offset < 0 { neighbor_layer_index } else { neighbor_layer_index + 1 };

responses.push_back(
DocumentMessage::MoveSelectedLayersTo {
folder_path: folder_path.to_vec(),
insert_index,
reverse_index: false,
}
.into(),
);
}
}
}
}
}
RollbackTransaction => {
self.rollback(responses).unwrap_or_else(|e| log::warn!("{}", e));
responses.extend([RenderDocument.into(), DocumentStructureChanged.into()]);
Expand All @@ -1399,6 +1406,21 @@ impl MessageHandler<DocumentMessage, (&InputPreprocessorMessageHandler, &FontCac
let all = self.all_layers().map(|path| path.to_vec()).collect();
responses.push_front(SetSelectedLayers { replacement_selected_layers: all }.into());
}
SelectedLayersLower => {
responses.push_front(DocumentMessage::SelectedLayersReorder { relative_index_offset: -1 }.into());
}
SelectedLayersLowerToBack => {
responses.push_front(DocumentMessage::SelectedLayersReorder { relative_index_offset: isize::MIN }.into());
}
SelectedLayersRaise => {
responses.push_front(DocumentMessage::SelectedLayersReorder { relative_index_offset: 1 }.into());
}
SelectedLayersRaiseToFront => {
responses.push_front(DocumentMessage::SelectedLayersReorder { relative_index_offset: isize::MAX }.into());
}
SelectedLayersReorder { relative_index_offset } => {
self.selected_layers_reorder(relative_index_offset, responses);
}
SelectLayer { layer_path, ctrl, shift } => {
let mut paths = vec![];
let last_selection_exists = !self.layer_range_selection_reference.is_empty();
Expand Down Expand Up @@ -1611,7 +1633,10 @@ impl MessageHandler<DocumentMessage, (&InputPreprocessorMessageHandler, &FontCac
DeleteSelectedLayers,
DuplicateSelectedLayers,
NudgeSelectedLayers,
ReorderSelectedLayers,
SelectedLayersLower,
SelectedLayersLowerToBack,
SelectedLayersRaise,
SelectedLayersRaiseToFront,
GroupSelectedLayers,
UngroupSelectedLayers,
);
Expand Down
Loading