From 77388d3900ab749336a3c1c40f8d1b4e72e63a9f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Fri, 28 Aug 2020 17:46:30 +0200
Subject: [PATCH] [dome] TS splitters

---
 ivette/src/dome/src/renderer/layout/split.tsx | 272 ++++++++++++++++++
 1 file changed, 272 insertions(+)
 create mode 100644 ivette/src/dome/src/renderer/layout/split.tsx

diff --git a/ivette/src/dome/src/renderer/layout/split.tsx b/ivette/src/dome/src/renderer/layout/split.tsx
new file mode 100644
index 00000000000..132c98cdf08
--- /dev/null
+++ b/ivette/src/dome/src/renderer/layout/split.tsx
@@ -0,0 +1,272 @@
+// --------------------------------------------------------------------------
+// --- Splitters
+// --------------------------------------------------------------------------
+
+/**
+    @packageDocumentation
+    @module dome/layout/split
+*/
+
+import _ from 'lodash';
+import * as React from 'react';
+import * as Dome from 'dome';
+import * as Utils from 'dome/misc/utils';
+import { DraggableCore, DraggableEventHandler } from 'react-draggable';
+import { AutoSizer, Size } from 'react-virtualized';
+
+// --------------------------------------------------------------------------
+// --- Splitter
+// --------------------------------------------------------------------------
+
+export interface SplitterBaseProps {
+  /** Use window settings to store the splitter position */
+  settings?: string;
+  /** Minimal margin from container edges (minimum 32) */
+  margin?: number;
+  /** Splitter children components. */
+  children: [JSX.Element, JSX.Element];
+}
+
+export interface SplitterFoldProps extends SplitterBaseProps {
+  /** Visibility of the folder component. */
+  unfold?: boolean;
+}
+
+export enum Direction {
+  /** Horizontal split. */
+  HORIZONTAL,
+  /** Vertical split. */
+  VERTICAL,
+  /** Stacked, foldable left component. */
+  LEFT,
+  /** Stacked, foldable right component. */
+  RIGHT,
+  /** Stacked, foldable top component. */
+  TOP,
+  /** Stacked, foldable bottom component. */
+  BOTTOM,
+}
+
+export interface SplitterDirProps extends SplitterFoldProps {
+  /** Direction of the splitter. */
+  direction: Direction;
+}
+
+/* --------------------------------------------------------------------------*/
+/* --- Splitter Layout                                                    ---*/
+/* --------------------------------------------------------------------------*/
+
+type Layout = {
+  hsplit: boolean;
+  cssA: string;
+  cssB: string;
+};
+
+const CONTAINER = 'dome-xSplitter-container';
+const NOCURSOR = 'dome-xSplitter-no-cursor';
+const HCURSOR = 'dome-xSplitter-h-cursor';
+const VCURSOR = 'dome-xSplitter-v-cursor';
+
+const HIDDEN = 'dome-xSplitter-hidden';
+const BLOCK = 'dome-xSplitter-block';
+const HFLEX = 'dome-xSplitter-hflex';
+const VFLEX = 'dome-xSplitter-vflex';
+
+const PANEL = 'dome-container';
+const HPANE = 'dome-xSplitter-hpane';
+const VPANE = 'dome-xSplitter-vpane';
+const HFOLD = 'dome-xSplitter-hfold';
+const VFOLD = 'dome-xSplitter-vfold';
+const HLINE = 'dome-xSplitter-hline';
+const VLINE = 'dome-xSplitter-vline';
+const HGRAB = 'dome-xSplitter-hgrab';
+const VGRAB = 'dome-xSplitter-vgrab';
+const DRAGGING = 'dome-color-dragging';
+const DRAGZONE = 'dome-color-dragzone';
+
+type CSS = {
+  container: string;
+  primary: string;
+  resizer: string;
+  secondary: string;
+};
+
+const getCSS = (
+  unfold: boolean,
+  position: number,
+  { hsplit, cssA, cssB }: Layout,
+): CSS => {
+  // FOLDED
+  if (!unfold) return {
+    container: BLOCK,
+    resizer: HIDDEN,
+    primary: (cssA === HFOLD || cssA === VFOLD) ? HIDDEN : PANEL,
+    secondary: (cssB === HFOLD || cssB === VFOLD) ? HIDDEN : PANEL,
+  };
+  // POSITION
+  if (position > 0) return {
+    container: BLOCK,
+    resizer: hsplit ? HLINE : VLINE,
+    primary: PANEL,
+    secondary: PANEL,
+  };
+  // FLEX
+  return {
+    container: hsplit ? HFLEX : VFLEX,
+    resizer: hsplit ? HLINE : VLINE,
+    primary: cssA,
+    secondary: cssB,
+  };
+};
+
+/* --------------------------------------------------------------------------*/
+/* --- Splitter Engine                                                    ---*/
+/* --------------------------------------------------------------------------*/
+
+interface SplitterLayoutProps extends SplitterFoldProps {
+  layout: Layout;
+}
+
+interface SplitterEngineProps extends SplitterLayoutProps {
+  size: Size;
+}
+
+function SplitterEngine(props: SplitterEngineProps) {
+  const [position] = Dome.useNumberSettings(props.settings, 0);
+  const [dragging, setDragging] = React.useState(false);
+  const { hsplit } = props.layout;
+  const dimension = hsplit ? props.size.width : props.size.height;
+  const savedim = React.useRef(dimension);
+  const { unfold = true } = props;
+  const [A, B] = props.children;
+  const css = getCSS(unfold, position, props.layout);
+  const cursor = dragging ? (hsplit ? HCURSOR : VCURSOR) : NOCURSOR;
+  const container = Utils.classes(css.container, cursor);
+  const primary = Utils.classes(css.primary, PANEL);
+  const secondary = Utils.classes(css.secondary, PANEL);
+  const dragger = Utils.classes(
+    hsplit ? HGRAB : VGRAB,
+    dragging ? DRAGGING : DRAGZONE,
+  );
+
+  const onStart: DraggableEventHandler = (_elt, _data) => {
+    // const p = hsplit ? data.x : data.y;
+    // console.log('START', p);
+    setDragging(true);
+  };
+  const onDrag: DraggableEventHandler = (_elt, _data) => {
+    // const p = hsplit ? data.x : data.y;
+    // console.log('DRAG', p);
+  };
+  const onStop: DraggableEventHandler = (_elt, _data) => {
+    // const p = hsplit ? data.x : data.y;
+    // console.log('STOP', p);
+    setDragging(false);
+  };
+
+  if (savedim.current !== dimension) {
+    // console.log('RESIZED', dimension);
+    savedim.current = dimension;
+  }
+
+  return (
+    <div
+      key="container"
+      className={container}
+      style={props.size}
+    >
+      <div
+        key="primary"
+        className={primary}
+        style={{}}
+      >
+        {A}
+      </div>
+      <div
+        key="resizer"
+        className={css.resizer}
+        style={{}}
+      >
+        <DraggableCore
+          onStart={onStart}
+          onDrag={onDrag}
+          onStop={onStop}
+        >
+          <div className={dragger} style={{}} />
+        </DraggableCore>
+      </div>
+      <div
+        key="secondary"
+        className={secondary}
+        style={{}}
+      >
+        {B}
+      </div>
+    </div>
+  );
+}
+
+const SplitterLayout = (props: SplitterLayoutProps) => (
+  <div className={CONTAINER}>
+    <AutoSizer>
+      {(size: Size) => (
+        <SplitterEngine size={size} {...props} />
+      )}
+    </AutoSizer>
+  </div>
+);
+
+// --------------------------------------------------------------------------
+// --- Short Cuts
+// --------------------------------------------------------------------------
+
+const HLayout = { hsplit: true, cssA: HPANE, cssB: HPANE };
+const LLayout = { hsplit: true, cssA: HFOLD, cssB: HPANE };
+const RLayout = { hsplit: true, cssA: HPANE, cssB: HFOLD };
+const VLayout = { hsplit: false, cssA: VPANE, cssB: VPANE };
+const TLayout = { hsplit: false, cssA: VFOLD, cssB: VPANE };
+const BLayout = { hsplit: false, cssA: VPANE, cssB: VFOLD };
+
+const getLayout = (d: Direction): Layout => {
+  switch (d) {
+    case Direction.HORIZONTAL: return HLayout;
+    case Direction.LEFT: return LLayout;
+    case Direction.RIGHT: return RLayout;
+    case Direction.VERTICAL: return VLayout;
+    case Direction.TOP: return TLayout;
+    case Direction.BOTTOM: return BLayout;
+  }
+};
+
+/** Splitter with specified direction. */
+export const Splitter = ({ direction, ...props }: SplitterDirProps) => (
+  <SplitterLayout layout={getLayout(direction)} {...props} />
+);
+
+const BASE = (L: Layout) => (props: SplitterBaseProps) => (
+  <SplitterLayout layout={L} {...props} />
+);
+
+const FOLD = (L: Layout) => (props: SplitterFoldProps) => (
+  <SplitterLayout layout={L} {...props} />
+);
+
+/** Horizontal Splitter. */
+export const HSplit = BASE(HLayout);
+
+/** Vertical Splitter. */
+export const VSplit = BASE(VLayout);
+
+/** Horizontal Splitter with stacked and foldable top element. */
+export const TSplit = FOLD(TLayout);
+
+/** Horizontal Splitter with stacked and foldable bottom element. */
+export const BSplit = FOLD(BLayout);
+
+/** Horizontal Splitter with stacked and foldable left element. */
+export const LSplit = FOLD(LLayout);
+
+/** Horizontal Splitter with stacked and foldable right element. */
+export const RSplit = FOLD(RLayout);
+
+// --------------------------------------------------------------------------
-- 
GitLab