Add support for resizing workspace panels (#443)

* Resize panels

* Removing move_selection test pending #444 resolved

* Bind event listners and cursor to the document

* Fix flex grow on document being reset when drawing

* Call onresize when the boundry is dragged

* Add min panel size

* Add explicit function return types

* Dispatch resize event

* Lock pointer instead of setting cursor on document

Co-authored-by: otdavies <oliver@psyfer.io>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube
2022-01-08 08:02:02 -08:00
committed by GitHub
co-authored by otdavies Keavon Chambers
parent 54e9121115
commit a2c2f7fc9d
3 changed files with 56 additions and 5 deletions
+1
View File
@@ -330,6 +330,7 @@ mod test {
assert_eq!(&layers_after_copy[4], rect_before_copy); assert_eq!(&layers_after_copy[4], rect_before_copy);
assert_eq!(&layers_after_copy[5], ellipse_before_copy); assert_eq!(&layers_after_copy[5], ellipse_before_copy);
} }
#[test] #[test]
#[ignore] // TODO: Re-enable test, see issue #444 (https://github.com/GraphiteEditor/Graphite/pull/444) #[ignore] // TODO: Re-enable test, see issue #444 (https://github.com/GraphiteEditor/Graphite/pull/444)
/// - create rect, shape and ellipse /// - create rect, shape and ellipse
+1 -1
View File
@@ -241,7 +241,7 @@ declare module "@vue/runtime-core" {
editor: EditorState; editor: EditorState;
// This must be set to optional because there is a time in the lifecycle of the component where inputManager is undefined. // This must be set to optional because there is a time in the lifecycle of the component where inputManager is undefined.
// That's because we initialize inputManager in `mounted()` rather than `data()` since the div hasn't been created yet. // That's because we initialize inputManager in `mounted()` rather than `data()` since the div hasn't been created yet.
inputManger?: InputManager; inputManager?: InputManager;
} }
} }
@@ -1,6 +1,6 @@
<template> <template>
<LayoutRow class="workspace-grid-subdivision"> <LayoutRow class="workspace-grid-subdivision">
<LayoutCol class="workspace-grid-subdivision" style="flex-grow: 1597"> <LayoutCol class="workspace-grid-subdivision">
<Panel <Panel
:panelType="'Document'" :panelType="'Document'"
:tabCloseButtons="true" :tabCloseButtons="true"
@@ -22,12 +22,12 @@
ref="documentsPanel" ref="documentsPanel"
/> />
</LayoutCol> </LayoutCol>
<LayoutCol class="workspace-grid-resize-gutter"></LayoutCol> <LayoutCol class="workspace-grid-resize-gutter" @pointerdown="resizePanel($event)"></LayoutCol>
<LayoutCol class="workspace-grid-subdivision" style="flex-grow: 319"> <LayoutCol class="workspace-grid-subdivision" style="flex-grow: 0.17">
<LayoutRow class="workspace-grid-subdivision" style="flex-grow: 402"> <LayoutRow class="workspace-grid-subdivision" style="flex-grow: 402">
<Panel :panelType="'Properties'" :tabLabels="['Properties']" :tabActiveIndex="0" /> <Panel :panelType="'Properties'" :tabLabels="['Properties']" :tabActiveIndex="0" />
</LayoutRow> </LayoutRow>
<LayoutRow class="workspace-grid-resize-gutter"></LayoutRow> <LayoutRow class="workspace-grid-resize-gutter" @pointerdown="resizePanel($event)"></LayoutRow>
<LayoutRow class="workspace-grid-subdivision" style="flex-grow: 590"> <LayoutRow class="workspace-grid-subdivision" style="flex-grow: 590">
<Panel :panelType="'LayerTree'" :tabLabels="['Layer Tree']" :tabActiveIndex="0" /> <Panel :panelType="'LayerTree'" :tabLabels="['Layer Tree']" :tabActiveIndex="0" />
</LayoutRow> </LayoutRow>
@@ -72,6 +72,8 @@ import LayoutRow from "@/components/layout/LayoutRow.vue";
import DialogModal from "@/components/widgets/floating-menus/DialogModal.vue"; import DialogModal from "@/components/widgets/floating-menus/DialogModal.vue";
import Panel from "@/components/workspace/Panel.vue"; import Panel from "@/components/workspace/Panel.vue";
const MIN_PANEL_SIZE = 100;
export default defineComponent({ export default defineComponent({
inject: ["documents", "dialog", "editor"], inject: ["documents", "dialog", "editor"],
components: { components: {
@@ -85,6 +87,54 @@ export default defineComponent({
return this.documents.state.activeDocumentIndex; return this.documents.state.activeDocumentIndex;
}, },
}, },
methods: {
resizePanel(event: PointerEvent) {
const gutter = event.target as HTMLElement;
const nextSibling = gutter.nextElementSibling as HTMLElement;
const previousSibling = gutter.previousElementSibling as HTMLElement;
// Are we resizing horizontally?
const horizontal = gutter.classList.contains("layout-col");
// Get the current size in px of the panels being resized
const nextSiblingSize = horizontal ? nextSibling.getBoundingClientRect().width : nextSibling.getBoundingClientRect().height;
const previousSiblingSize = horizontal ? previousSibling.getBoundingClientRect().width : previousSibling.getBoundingClientRect().height;
// Prevent cursor flicker as mouse temporarily leaves the gutter
gutter.setPointerCapture(event.pointerId);
const mouseStart = horizontal ? event.clientX : event.clientY;
function updatePosition(event: PointerEvent): void {
const mouseCurrent = horizontal ? event.clientX : event.clientY;
let mouseDelta = mouseStart - mouseCurrent;
mouseDelta = Math.max(nextSiblingSize + mouseDelta, MIN_PANEL_SIZE) - nextSiblingSize;
mouseDelta = previousSiblingSize - Math.max(previousSiblingSize - mouseDelta, MIN_PANEL_SIZE);
nextSibling.style.flexGrow = (nextSiblingSize + mouseDelta).toString();
previousSibling.style.flexGrow = (previousSiblingSize - mouseDelta).toString();
window.dispatchEvent(
new CustomEvent("resize", {
detail: {},
})
);
}
document.addEventListener("pointermove", updatePosition);
function cleanup(event: PointerEvent): void {
gutter.releasePointerCapture(event.pointerId);
document.removeEventListener("pointermove", updatePosition);
document.removeEventListener("pointerleave", cleanup);
document.removeEventListener("pointerup", cleanup);
}
document.addEventListener("pointerleave", cleanup);
document.addEventListener("pointerup", cleanup);
},
},
watch: { watch: {
activeDocumentIndex(newIndex: number) { activeDocumentIndex(newIndex: number) {
this.$nextTick(() => { this.$nextTick(() => {