Skip to content
Snippets Groups Projects
Commit ae42ad92 authored by Loïc Correnson's avatar Loïc Correnson
Browse files

[dome] splitter draggable

parent b5b79e49
No related branches found
No related tags found
No related merge requests found
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
@module dome/layout/split @module dome/layout/split
*/ */
import _ from 'lodash';
import * as React from 'react'; import * as React from 'react';
import * as Dome from 'dome'; import * as Dome from 'dome';
import * as Utils from 'dome/misc/utils'; import * as Utils from 'dome/misc/utils';
...@@ -58,8 +57,8 @@ export interface SplitterDirProps extends SplitterFoldProps { ...@@ -58,8 +57,8 @@ export interface SplitterDirProps extends SplitterFoldProps {
type Layout = { type Layout = {
hsplit: boolean; hsplit: boolean;
cssA: string; foldA: boolean;
cssB: string; foldB: boolean;
}; };
const PANEL = 'dome-container'; const PANEL = 'dome-container';
...@@ -82,41 +81,52 @@ const HFOLD = 'dome-xSplitter-hfold'; ...@@ -82,41 +81,52 @@ const HFOLD = 'dome-xSplitter-hfold';
const VFOLD = 'dome-xSplitter-vfold'; const VFOLD = 'dome-xSplitter-vfold';
const HLINE = 'dome-xSplitter-hline'; const HLINE = 'dome-xSplitter-hline';
const VLINE = 'dome-xSplitter-vline'; const VLINE = 'dome-xSplitter-vline';
const HGRAB = 'dome-xSplitter-hgrab'; const HANDLE = '.dome-xSplitter-grab';
const VGRAB = 'dome-xSplitter-vgrab'; const HGRAB = 'dome-xSplitter-grab dome-xSplitter-hgrab';
const VGRAB = 'dome-xSplitter-grab dome-xSplitter-vgrab';
const HPOSA = 'dome-xSplitter-hpos-A';
const VPOSA = 'dome-xSplitter-vpos-A';
const HPOSB = 'dome-xSplitter-hpos-B';
const VPOSB = 'dome-xSplitter-vpos-B';
const HPOSR = 'dome-xSplitter-hline dome-xSplitter-hpos-R';
const VPOSR = 'dome-xSplitter-vline dome-xSplitter-vpos-R';
type CSS = { type CSS = {
container: string; container: string;
primary: string; sideA: string;
resizer: string; sideB: string;
secondary: string; split: string;
}; };
const getFlexCSS = (hsplit: boolean, fold: boolean) => (
hsplit ? (fold ? HFOLD : HPANE) : (fold ? VFOLD : VPANE)
);
const getCSS = ( const getCSS = (
unfold: boolean, unfold: boolean,
position: number, dragged: boolean,
{ hsplit, cssA, cssB }: Layout, { hsplit, foldA, foldB }: Layout,
): CSS => { ): CSS => {
// FOLDED // FOLDED
if (!unfold) return { if (!unfold) return {
container: BLOCK, container: BLOCK,
resizer: HIDDEN, sideA: foldA ? HIDDEN : BLOCK,
primary: (cssA === HFOLD || cssA === VFOLD) ? HIDDEN : BLOCK, split: HIDDEN,
secondary: (cssB === HFOLD || cssB === VFOLD) ? HIDDEN : BLOCK, sideB: foldB ? HIDDEN : BLOCK,
}; };
// POSITION // DRAGGED
if (position > 0) return { if (dragged) return {
container: BLOCK, container: BLOCK,
resizer: hsplit ? HLINE : VLINE, sideA: hsplit ? HPOSA : VPOSA,
primary: BLOCK, split: hsplit ? HPOSR : VPOSR,
secondary: BLOCK, sideB: hsplit ? HPOSB : VPOSB,
}; };
// FLEX // FLEX
return { return {
container: hsplit ? HFLEX : VFLEX, container: hsplit ? HFLEX : VFLEX,
resizer: hsplit ? HLINE : VLINE, sideA: getFlexCSS(hsplit, foldA),
primary: cssA, split: hsplit ? HLINE : VLINE,
secondary: cssB, sideB: getFlexCSS(hsplit, foldB),
}; };
}; };
...@@ -132,41 +142,76 @@ interface SplitterEngineProps extends SplitterLayoutProps { ...@@ -132,41 +142,76 @@ interface SplitterEngineProps extends SplitterLayoutProps {
size: Size; size: Size;
} }
type Dragging = undefined | {
position: number;
anchor: number;
offset: number;
}
function SplitterEngine(props: SplitterEngineProps) { function SplitterEngine(props: SplitterEngineProps) {
const [position] = Dome.useNumberSettings(props.settings, 0); const [position, setPosition] = Dome.useNumberSettings(props.settings, 0);
const [dragging, setDragging] = React.useState(false); const [dragging, setDragging] = React.useState<Dragging>(undefined);
const { hsplit } = props.layout; const { hsplit } = props.layout;
const dimension = hsplit ? props.size.width : props.size.height; const dimension = hsplit ? props.size.width : props.size.height;
const savedim = React.useRef(dimension); const savedim = React.useRef(dimension);
const { unfold = true } = props; const { unfold = true } = props;
const [A, B] = props.children; const [A, B] = props.children;
const css = getCSS(unfold, position, props.layout); const dragged = position > 0 || dragging !== undefined;
const css = getCSS(unfold, dragged, props.layout);
const cursor = dragging ? (hsplit ? HCURSOR : VCURSOR) : NOCURSOR; const cursor = dragging ? (hsplit ? HCURSOR : VCURSOR) : NOCURSOR;
const container = Utils.classes(css.container, cursor); const container = Utils.classes(css.container, cursor);
const primary = Utils.classes(css.primary, PANEL); const sideA = Utils.classes(css.sideA, PANEL);
const secondary = Utils.classes(css.secondary, PANEL); const sideB = Utils.classes(css.sideB, PANEL);
const dragger = Utils.classes( const dragger = Utils.classes(
hsplit ? HGRAB : VGRAB, hsplit ? HGRAB : VGRAB,
dragging ? DRAGGING : DRAGZONE, dragging ? DRAGGING : DRAGZONE,
); );
const onStart: DraggableEventHandler = (_elt, _data) => { let styleA: undefined | React.CSSProperties;
// const p = hsplit ? data.x : data.y; let styleB: undefined | React.CSSProperties;
// console.log('START', p); let styleR: undefined | React.CSSProperties;
setDragging(true);
}; if (dragged) {
const onDrag: DraggableEventHandler = (_elt, _data) => { const { margin = 32, size } = props;
// const p = hsplit ? data.x : data.y; const M = Math.max(margin, 32);
// console.log('DRAG', p); const D = hsplit ? size.width : size.height;
}; const P = dragging ? dragging.position : position;
const onStop: DraggableEventHandler = (_elt, _data) => { const X = dragging ? dragging.offset - dragging.anchor : 0;
// const p = hsplit ? data.x : data.y; const Q = D < M ? D / 2 : Math.min(Math.max(P + X, M), D - M);
// console.log('STOP', p); styleA = hsplit ? { width: Q } : { height: Q };
setDragging(false); styleR = hsplit ? { left: Q } : { top: Q };
}; styleB = hsplit ? { left: Q + 1 } : { top: Q + 1 };
}
const onStart: DraggableEventHandler =
(_evt, data) => {
const client = data.node.getBoundingClientRect();
const position = hsplit ? client.x : client.y;
const anchor = hsplit ? data.x : data.y;
setDragging({ position, offset: anchor, anchor });
};
const onDrag: DraggableEventHandler =
(_evt, data) => {
if (dragging) {
const { position, anchor } = dragging;
const offset = hsplit ? data.x : data.y;
setDragging({ position, anchor, offset });
}
};
const onStop: DraggableEventHandler =
(evt, _data) => {
if (evt.metaKey || evt.altKey || evt.ctrlKey) {
setPosition(0);
} else if (dragging) {
setPosition(dragging.position + dragging.offset - dragging.anchor);
}
setDragging(undefined);
};
if (savedim.current !== dimension) { if (savedim.current !== dimension) {
// console.log('RESIZED', dimension); console.log('RESIZED', dimension);
savedim.current = dimension; savedim.current = dimension;
} }
...@@ -177,29 +222,30 @@ function SplitterEngine(props: SplitterEngineProps) { ...@@ -177,29 +222,30 @@ function SplitterEngine(props: SplitterEngineProps) {
style={props.size} style={props.size}
> >
<div <div
key="primary" key="sideA"
className={primary} className={sideA}
style={{}} style={styleA}
> >
{A} {A}
</div> </div>
<div <DraggableCore
key="resizer" handle={HANDLE}
className={css.resizer} onStart={onStart}
style={{}} onDrag={onDrag}
onStop={onStop}
> >
<DraggableCore <div
onStart={onStart} key="split"
onDrag={onDrag} className={css.split}
onStop={onStop} style={styleR}
> >
<div className={dragger} style={{}} /> <div className={dragger} />
</DraggableCore> </div>
</div> </DraggableCore>
<div <div
key="secondary" key="sideB"
className={secondary} className={sideB}
style={{}} style={styleB}
> >
{B} {B}
</div> </div>
...@@ -221,12 +267,12 @@ const SplitterLayout = (props: SplitterLayoutProps) => ( ...@@ -221,12 +267,12 @@ const SplitterLayout = (props: SplitterLayoutProps) => (
// --- Short Cuts // --- Short Cuts
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
const HLayout = { hsplit: true, cssA: HPANE, cssB: HPANE }; const HLayout = { hsplit: true, foldA: false, foldB: false };
const LLayout = { hsplit: true, cssA: HFOLD, cssB: HPANE }; const LLayout = { hsplit: true, foldA: true, foldB: false };
const RLayout = { hsplit: true, cssA: HPANE, cssB: HFOLD }; const RLayout = { hsplit: true, foldA: false, foldB: true };
const VLayout = { hsplit: false, cssA: VPANE, cssB: VPANE }; const VLayout = { hsplit: false, foldA: false, foldB: false };
const TLayout = { hsplit: false, cssA: VFOLD, cssB: VPANE }; const TLayout = { hsplit: false, foldA: true, foldB: false };
const BLayout = { hsplit: false, cssA: VPANE, cssB: VFOLD }; const BLayout = { hsplit: false, foldA: false, foldB: true };
const getLayout = (d: Direction): Layout => { const getLayout = (d: Direction): Layout => {
switch (d) { switch (d) {
......
...@@ -157,33 +157,41 @@ ...@@ -157,33 +157,41 @@
height: 1px; height: 1px;
} }
.dome-xSplitter-hgrab { .dome-xSplitter-grab {
position: relative ; position: relative ;
z-index: 1 ; z-index: 1 ;
border: 0px ;
}
.dome-xSplitter-hgrab {
left: -1px ; left: -1px ;
width: 3px ; width: 3px ;
height: 100% ; height: 100% ;
cursor: col-resize ; cursor: col-resize ;
border: 0px ;
} }
.dome-xSplitter-vgrab { .dome-xSplitter-vgrab {
position: relative ;
z-index: 1 ;
top: -1px ; top: -1px ;
height: 3px ; height: 3px ;
width: 100% ; width: 100% ;
border: 0px ;
cursor: row-resize ; cursor: row-resize ;
} }
.dome-xSplitter-hpos-A { position: absolute; left: 0px; height: 100% }
.dome-xSplitter-hpos-R { position: absolute; width: 1px; height: 100% }
.dome-xSplitter-hpos-B { position: absolute; right: 0px; height: 100% }
.dome-xSplitter-vpos-A { position: absolute; top: 0px; width: 100% }
.dome-xSplitter-vpos-R { position: absolute; height: 1px; width: 100% }
.dome-xSplitter-vpos-B { position: absolute; bottom: 0px; width: 100% }
.dome-window-active .dome-xSplitter-hline, .dome-window-active .dome-xSplitter-hline,
.dome-window-active .dome-xSplitter-vline .dome-window-active .dome-xSplitter-vline
{ {
background: #afafaf ; background: #afafaf ;
} }
.dome-window-inactive .dome-xSplitter-hline .dome-window-inactive .dome-xSplitter-hline,
.dome-window-inactive .dome-xSplitter-vline .dome-window-inactive .dome-xSplitter-vline
{ {
background: #d6d6d6 ; background: #d6d6d6 ;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment