Add focus document toggle (#3672)
This commit is contained in:
parent
2be7790d4d
commit
7a5790744f
|
|
@ -232,6 +232,7 @@ impl Dispatcher {
|
|||
Message::MenuBar(message) => {
|
||||
let menu_bar_message_handler = &mut self.message_handlers.menu_bar_message_handler;
|
||||
|
||||
menu_bar_message_handler.focus_document = self.message_handlers.portfolio_message_handler.focus_document;
|
||||
menu_bar_message_handler.data_panel_open = self.message_handlers.portfolio_message_handler.data_panel_open;
|
||||
menu_bar_message_handler.layers_panel_open = self.message_handlers.portfolio_message_handler.layers_panel_open;
|
||||
menu_bar_message_handler.properties_panel_open = self.message_handlers.portfolio_message_handler.properties_panel_open;
|
||||
|
|
|
|||
|
|
@ -334,7 +334,8 @@ pub fn input_mappings(zoom_with_scroll: bool) -> Mapping {
|
|||
entry!(KeyDown(KeyX); modifiers=[Shift], action_dispatch=ToolMessage::SwapColors),
|
||||
entry!(KeyDown(KeyC); modifiers=[Alt], action_dispatch=ToolMessage::SelectRandomWorkingColor { primary: true }),
|
||||
entry!(KeyDown(KeyC); modifiers=[Alt, Shift], action_dispatch=ToolMessage::SelectRandomWorkingColor { primary: false }),
|
||||
entry!(KeyDownNoRepeat(Tab); action_dispatch=ToolMessage::ToggleSelectVsPath),
|
||||
// TODO: Change to KeyDownNoRepeat when https://github.com/GraphiteEditor/Graphite/issues/2266 is resolved
|
||||
entry!(KeyDown(Tab); action_dispatch=ToolMessage::ToggleSelectVsPath),
|
||||
//
|
||||
// DocumentMessage
|
||||
entry!(KeyDown(Space); modifiers=[Control], action_dispatch=DocumentMessage::GraphViewOverlayToggle),
|
||||
|
|
@ -448,6 +449,7 @@ pub fn input_mappings(zoom_with_scroll: bool) -> Mapping {
|
|||
entry!(KeyDown(KeyC); modifiers=[Accel], action_dispatch=PortfolioMessage::Copy { clipboard: Clipboard::Device }),
|
||||
entry!(KeyDown(KeyR); modifiers=[Alt], action_dispatch=PortfolioMessage::ToggleRulers),
|
||||
entry!(KeyDown(KeyD); modifiers=[Alt], action_dispatch=PortfolioMessage::ToggleDataPanelOpen),
|
||||
entry!(KeyDown(Enter); modifiers=[Alt], action_dispatch=PortfolioMessage::ToggleFocusDocument),
|
||||
//
|
||||
// DialogMessage
|
||||
entry!(KeyDown(KeyE); modifiers=[Accel], action_dispatch=DialogMessage::RequestExportDialog),
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ pub struct MenuBarMessageHandler {
|
|||
pub data_panel_open: bool,
|
||||
pub layers_panel_open: bool,
|
||||
pub properties_panel_open: bool,
|
||||
pub focus_document: bool,
|
||||
}
|
||||
|
||||
#[message_handler_data]
|
||||
|
|
@ -628,23 +629,31 @@ impl LayoutHolder for MenuBarMessageHandler {
|
|||
.icon("FullscreenEnter")
|
||||
.tooltip_shortcut(action_shortcut!(AppWindowMessageDiscriminant::Fullscreen))
|
||||
.on_commit(|_| AppWindowMessage::Fullscreen.into()),
|
||||
MenuListEntry::new("Focus Document")
|
||||
.label("Focus Document")
|
||||
.icon(if self.focus_document { "CheckboxChecked" } else { "CheckboxUnchecked" })
|
||||
.tooltip_shortcut(action_shortcut!(PortfolioMessageDiscriminant::ToggleFocusDocument))
|
||||
.on_commit(|_| PortfolioMessage::ToggleFocusDocument.into()),
|
||||
],
|
||||
vec![
|
||||
MenuListEntry::new("Properties")
|
||||
.label("Properties")
|
||||
.icon(if self.properties_panel_open { "CheckboxChecked" } else { "CheckboxUnchecked" })
|
||||
.tooltip_shortcut(action_shortcut!(PortfolioMessageDiscriminant::TogglePropertiesPanelOpen))
|
||||
.on_commit(|_| PortfolioMessage::TogglePropertiesPanelOpen.into()),
|
||||
.on_commit(|_| PortfolioMessage::TogglePropertiesPanelOpen.into())
|
||||
.disabled(self.focus_document),
|
||||
MenuListEntry::new("Layers")
|
||||
.label("Layers")
|
||||
.icon(if self.layers_panel_open { "CheckboxChecked" } else { "CheckboxUnchecked" })
|
||||
.tooltip_shortcut(action_shortcut!(PortfolioMessageDiscriminant::ToggleLayersPanelOpen))
|
||||
.on_commit(|_| PortfolioMessage::ToggleLayersPanelOpen.into()),
|
||||
.on_commit(|_| PortfolioMessage::ToggleLayersPanelOpen.into())
|
||||
.disabled(self.focus_document),
|
||||
MenuListEntry::new("Data")
|
||||
.label("Data")
|
||||
.icon(if self.data_panel_open { "CheckboxChecked" } else { "CheckboxUnchecked" })
|
||||
.tooltip_shortcut(action_shortcut!(PortfolioMessageDiscriminant::ToggleDataPanelOpen))
|
||||
.on_commit(|_| PortfolioMessage::ToggleDataPanelOpen.into()),
|
||||
.on_commit(|_| PortfolioMessage::ToggleDataPanelOpen.into())
|
||||
.disabled(self.focus_document),
|
||||
],
|
||||
])
|
||||
.widget_instance(),
|
||||
|
|
|
|||
|
|
@ -316,8 +316,10 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||
}
|
||||
DocumentMessage::ClearLayersPanel => {
|
||||
// Send an empty layer list
|
||||
let data_buffer: RawBuffer = Self::default().serialize_root();
|
||||
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer });
|
||||
if layers_panel_open {
|
||||
let data_buffer: RawBuffer = Self::default().serialize_root();
|
||||
responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer });
|
||||
}
|
||||
|
||||
// Clear the control bar
|
||||
responses.add(LayoutMessage::SendLayout {
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ pub enum PortfolioMessage {
|
|||
ignore_hash: bool,
|
||||
},
|
||||
ToggleResetNodesToDefinitionsOnOpen,
|
||||
ToggleFocusDocument,
|
||||
ToggleDataPanelOpen,
|
||||
TogglePropertiesPanelOpen,
|
||||
ToggleLayersPanelOpen,
|
||||
|
|
|
|||
|
|
@ -60,11 +60,12 @@ pub struct PortfolioMessageHandler {
|
|||
pub executor: NodeGraphExecutor,
|
||||
pub selection_mode: SelectionMode,
|
||||
pub reset_node_definitions_on_open: bool,
|
||||
pub data_panel_open: bool,
|
||||
#[derivative(Default(value = "true"))]
|
||||
pub layers_panel_open: bool,
|
||||
pub focus_document: bool,
|
||||
#[derivative(Default(value = "true"))]
|
||||
pub properties_panel_open: bool,
|
||||
#[derivative(Default(value = "true"))]
|
||||
pub layers_panel_open: bool,
|
||||
pub data_panel_open: bool,
|
||||
}
|
||||
|
||||
#[message_handler_data]
|
||||
|
|
@ -94,9 +95,9 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||
current_tool,
|
||||
preferences,
|
||||
viewport,
|
||||
data_panel_open: self.data_panel_open,
|
||||
layers_panel_open: self.layers_panel_open,
|
||||
properties_panel_open: self.properties_panel_open,
|
||||
data_panel_open: self.data_panel_open && !self.focus_document,
|
||||
layers_panel_open: self.layers_panel_open && !self.focus_document,
|
||||
properties_panel_open: self.properties_panel_open && !self.focus_document,
|
||||
};
|
||||
document.process_message(message, responses, document_inputs)
|
||||
}
|
||||
|
|
@ -158,9 +159,9 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||
current_tool,
|
||||
preferences,
|
||||
viewport,
|
||||
data_panel_open: self.data_panel_open,
|
||||
layers_panel_open: self.layers_panel_open,
|
||||
properties_panel_open: self.properties_panel_open,
|
||||
data_panel_open: self.data_panel_open && !self.focus_document,
|
||||
layers_panel_open: self.layers_panel_open && !self.focus_document,
|
||||
properties_panel_open: self.properties_panel_open && !self.focus_document,
|
||||
};
|
||||
document.process_message(message, responses, document_inputs)
|
||||
}
|
||||
|
|
@ -452,7 +453,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||
responses.add(NavigationMessage::CanvasPan { delta: (0., 0.).into() });
|
||||
}
|
||||
|
||||
self.load_document(new_document, document_id, self.layers_panel_open, responses, false);
|
||||
self.load_document(new_document, document_id, responses, false);
|
||||
responses.add(PortfolioMessage::SelectDocument { document_id });
|
||||
}
|
||||
PortfolioMessage::NextDocument => {
|
||||
|
|
@ -655,7 +656,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||
}
|
||||
|
||||
// Load the document into the portfolio so it opens in the editor
|
||||
self.load_document(document, document_id, self.layers_panel_open, responses, to_front);
|
||||
self.load_document(document, document_id, responses, to_front);
|
||||
|
||||
if select_after_open {
|
||||
responses.add(PortfolioMessage::SelectDocument { document_id });
|
||||
|
|
@ -1150,7 +1151,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||
let node_to_inspect = self.node_to_inspect();
|
||||
|
||||
let Some(document) = self.documents.get_mut(&document_id) else {
|
||||
log::error!("Tried to render non-existent document");
|
||||
log::error!("Tried to render non-existent document {:?}", document_id);
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -1177,7 +1178,101 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||
Ok(message) => responses.add_front(message),
|
||||
}
|
||||
}
|
||||
PortfolioMessage::ToggleFocusDocument => {
|
||||
self.focus_document = !self.focus_document;
|
||||
responses.add(MenuBarMessage::SendLayout);
|
||||
|
||||
if self.focus_document {
|
||||
if self.properties_panel_open {
|
||||
responses.add(PropertiesPanelMessage::Clear);
|
||||
responses.add(FrontendMessage::UpdatePropertiesPanelState { open: false });
|
||||
}
|
||||
|
||||
if self.layers_panel_open {
|
||||
responses.add(DocumentMessage::ClearLayersPanel);
|
||||
responses.add(FrontendMessage::UpdateLayersPanelState { open: false });
|
||||
}
|
||||
|
||||
if self.data_panel_open {
|
||||
responses.add(DataPanelMessage::ClearLayout);
|
||||
responses.add(FrontendMessage::UpdateDataPanelState { open: false });
|
||||
}
|
||||
} else {
|
||||
if self.properties_panel_open {
|
||||
responses.add(FrontendMessage::UpdatePropertiesPanelState { open: true });
|
||||
}
|
||||
if self.layers_panel_open {
|
||||
responses.add(FrontendMessage::UpdateLayersPanelState { open: true });
|
||||
}
|
||||
if self.data_panel_open {
|
||||
responses.add(FrontendMessage::UpdateDataPanelState { open: true });
|
||||
}
|
||||
|
||||
// Run the graph to grab the data
|
||||
if self.properties_panel_open || self.layers_panel_open || self.data_panel_open {
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
|
||||
if self.properties_panel_open {
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
}
|
||||
if self.layers_panel_open && self.active_document_id.is_some() {
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![NodeGraphMessage::UpdateLayerPanel.into(), DocumentMessage::DocumentStructureChanged.into()],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
PortfolioMessage::TogglePropertiesPanelOpen => {
|
||||
if self.focus_document {
|
||||
return;
|
||||
}
|
||||
|
||||
self.properties_panel_open = !self.properties_panel_open;
|
||||
responses.add(MenuBarMessage::SendLayout);
|
||||
|
||||
// Run the graph to grab the data
|
||||
if self.properties_panel_open {
|
||||
responses.add(FrontendMessage::UpdatePropertiesPanelState { open: self.properties_panel_open });
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
} else {
|
||||
responses.add(PropertiesPanelMessage::Clear);
|
||||
responses.add(FrontendMessage::UpdatePropertiesPanelState { open: self.properties_panel_open });
|
||||
}
|
||||
}
|
||||
PortfolioMessage::ToggleLayersPanelOpen => {
|
||||
if self.focus_document {
|
||||
return;
|
||||
}
|
||||
|
||||
self.layers_panel_open = !self.layers_panel_open;
|
||||
responses.add(MenuBarMessage::SendLayout);
|
||||
|
||||
// Run the graph to grab the data
|
||||
if self.layers_panel_open {
|
||||
// When opening, we make the frontend show the panel first so it can start receiving its message subscriptions for the data it will display
|
||||
responses.add(FrontendMessage::UpdateLayersPanelState { open: self.layers_panel_open });
|
||||
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
if self.active_document_id.is_some() {
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![NodeGraphMessage::UpdateLayerPanel.into(), DocumentMessage::DocumentStructureChanged.into()],
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// If we don't clear the panel, the layout diffing system will assume widgets still exist when it attempts to update the layers panel next time it is opened
|
||||
responses.add(DocumentMessage::ClearLayersPanel);
|
||||
|
||||
// When closing, we make the frontend hide the panel last so it can finish receiving its message subscriptions before it is destroyed
|
||||
responses.add(FrontendMessage::UpdateLayersPanelState { open: self.layers_panel_open });
|
||||
}
|
||||
}
|
||||
PortfolioMessage::ToggleDataPanelOpen => {
|
||||
if self.focus_document {
|
||||
return;
|
||||
}
|
||||
|
||||
self.data_panel_open = !self.data_panel_open;
|
||||
responses.add(MenuBarMessage::SendLayout);
|
||||
|
||||
|
|
@ -1195,40 +1290,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||
responses.add(FrontendMessage::UpdateDataPanelState { open: self.data_panel_open });
|
||||
}
|
||||
}
|
||||
PortfolioMessage::TogglePropertiesPanelOpen => {
|
||||
self.properties_panel_open = !self.properties_panel_open;
|
||||
responses.add(MenuBarMessage::SendLayout);
|
||||
|
||||
responses.add(FrontendMessage::UpdatePropertiesPanelState { open: self.properties_panel_open });
|
||||
|
||||
// Run the graph to grab the data
|
||||
if self.properties_panel_open {
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
}
|
||||
|
||||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
}
|
||||
PortfolioMessage::ToggleLayersPanelOpen => {
|
||||
self.layers_panel_open = !self.layers_panel_open;
|
||||
responses.add(MenuBarMessage::SendLayout);
|
||||
|
||||
// Run the graph to grab the data
|
||||
if self.layers_panel_open {
|
||||
// When opening, we make the frontend show the panel first so it can start receiving its message subscriptions for the data it will display
|
||||
responses.add(FrontendMessage::UpdateLayersPanelState { open: self.layers_panel_open });
|
||||
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
responses.add(DeferMessage::AfterGraphRun {
|
||||
messages: vec![NodeGraphMessage::UpdateLayerPanel.into(), DocumentMessage::DocumentStructureChanged.into()],
|
||||
});
|
||||
} else {
|
||||
// If we don't clear the panel, the layout diffing system will assume widgets still exist when it attempts to update the layers panel next time it is opened
|
||||
responses.add(DocumentMessage::ClearLayersPanel);
|
||||
|
||||
// When closing, we make the frontend hide the panel last so it can finish receiving its message subscriptions before it is destroyed
|
||||
responses.add(FrontendMessage::UpdateLayersPanelState { open: self.layers_panel_open });
|
||||
}
|
||||
}
|
||||
PortfolioMessage::ToggleRulers => {
|
||||
if let Some(document) = self.active_document_mut() {
|
||||
document.rulers_visible = !document.rulers_visible;
|
||||
|
|
@ -1280,7 +1341,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||
fn actions(&self) -> ActionList {
|
||||
let mut common = actions!(PortfolioMessageDiscriminant;
|
||||
Open,
|
||||
ToggleDataPanelOpen,
|
||||
ToggleFocusDocument,
|
||||
);
|
||||
|
||||
// Extend with actions that require an active document
|
||||
|
|
@ -1305,6 +1366,15 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||
}
|
||||
}
|
||||
|
||||
// Extend with actions that are disabled when focusing the document
|
||||
if !self.focus_document {
|
||||
common.extend(actions!(PortfolioMessageDiscriminant;
|
||||
TogglePropertiesPanelOpen,
|
||||
ToggleLayersPanelOpen,
|
||||
ToggleDataPanelOpen,
|
||||
));
|
||||
}
|
||||
|
||||
common
|
||||
}
|
||||
}
|
||||
|
|
@ -1385,14 +1455,14 @@ impl PortfolioMessageHandler {
|
|||
}
|
||||
}
|
||||
|
||||
fn load_document(&mut self, mut new_document: DocumentMessageHandler, document_id: DocumentId, layers_panel_open: bool, responses: &mut VecDeque<Message>, to_front: bool) {
|
||||
fn load_document(&mut self, mut new_document: DocumentMessageHandler, document_id: DocumentId, responses: &mut VecDeque<Message>, to_front: bool) {
|
||||
if to_front {
|
||||
self.document_ids.push_front(document_id);
|
||||
} else {
|
||||
self.document_ids.push_back(document_id);
|
||||
}
|
||||
new_document.update_layers_panel_control_bar_widgets(layers_panel_open, responses);
|
||||
new_document.update_layers_panel_bottom_bar_widgets(layers_panel_open, responses);
|
||||
new_document.update_layers_panel_control_bar_widgets(self.layers_panel_open && !self.focus_document, responses);
|
||||
new_document.update_layers_panel_bottom_bar_widgets(self.layers_panel_open && !self.focus_document, responses);
|
||||
|
||||
self.documents.insert(document_id, new_document);
|
||||
|
||||
|
|
@ -1439,7 +1509,7 @@ impl PortfolioMessageHandler {
|
|||
/// Get the ID of the selected node that should be used as the current source for the Data panel.
|
||||
pub fn node_to_inspect(&self) -> Option<NodeId> {
|
||||
// Skip if the Data panel is not open
|
||||
if !self.data_panel_open {
|
||||
if !self.data_panel_open || self.focus_document {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,13 @@ export function createInputManager(editor: Editor, dialog: DialogState, portfoli
|
|||
|
||||
// Don't redirect tab or enter if not in canvas (to allow navigating elements)
|
||||
potentiallyRestoreCanvasFocus(e);
|
||||
if (!canvasFocused && !targetIsTextField(e.target || undefined) && ["Tab", "Enter", "NumpadEnter", "Space", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowUp"].includes(key)) return false;
|
||||
if (
|
||||
!canvasFocused &&
|
||||
!targetIsTextField(e.target || undefined) &&
|
||||
["Tab", "Enter", "NumpadEnter", "Space", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowUp"].includes(key) &&
|
||||
!(e.ctrlKey || e.metaKey || e.altKey)
|
||||
)
|
||||
return false;
|
||||
|
||||
// Don't redirect if a MenuList is open
|
||||
if (window.document.querySelector("[data-floating-menu-content]")) return false;
|
||||
|
|
|
|||
Loading…
Reference in New Issue