Skip to content

Commit

Permalink
Creates a toolbar to configure the grid helper
Browse files Browse the repository at this point in the history
  • Loading branch information
hbcarlos committed Jan 13, 2023
1 parent aa8ca1a commit d642f18
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 24 deletions.
2 changes: 1 addition & 1 deletion binder/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ channels:
dependencies:
# runtime dependencies
- python >=3.8,<3.9.0a0
- jupyterlab >=4.0.0a30,<5.0.0a0
- jupyterlab >=4.0.0a32,<5.0.0a0
# extra pins for solveability
- notebook-shim >=0.2.0
- jupyterlab_server >=2.16.1
Expand Down
44 changes: 30 additions & 14 deletions src/mainview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
import { v4 as uuid } from 'uuid';
import { JupyterCadModel } from './model';
import {
GridHelper,
IDict,
IDisplayShape,
IJupyterCadClientState,
Expand All @@ -35,6 +36,8 @@ import {
} from './types';

import { FloatingAnnotation } from './annotation/view';
import { IChangedArgs } from '@jupyterlab/coreutils';
import { JSONValue } from '@lumino/coreutils';

// Apply the BVH extension
THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
Expand Down Expand Up @@ -113,6 +116,7 @@ export class MainView extends React.Component<IProps, IStates> {
this._onClientSharedStateChanged,
this
);
this._model.viewChanged.connect(this._onViewChanged, this);
this._model.sharedMetadataChanged.connect(
this._onSharedMetadataChanged,
this
Expand Down Expand Up @@ -149,6 +153,7 @@ export class MainView extends React.Component<IProps, IStates> {
this._onClientSharedStateChanged,
this
);
this._model.viewChanged.disconnect(this._onViewChanged, this);
this._model.sharedMetadataChanged.disconnect(
this._onSharedMetadataChanged,
this
Expand Down Expand Up @@ -234,19 +239,6 @@ export class MainView extends React.Component<IProps, IStates> {
this._camera.up.set(0, 0, 1);

this._scene = new THREE.Scene();
const size = 40;
const divisions = 40;
this._gridHelper = new THREE.GridHelper(
size,
divisions,
this.state.lightTheme ? LIGHT_GRID_COLOR : DARK_GRID_COLOR,
this.state.lightTheme ? LIGHT_GRID_COLOR : DARK_GRID_COLOR
// 0x888888,
// 0x888888
);
this._gridHelper.geometry.rotateX(Math.PI / 2);

this._scene.add(this._gridHelper);
this.addSceneAxe(new THREE.Vector3(1, 0, 0), 0x00ff00);
this.addSceneAxe(new THREE.Vector3(0, 1, 0), 0xff0000);
this.addSceneAxe(new THREE.Vector3(0, 0, 1), 0xffff00);
Expand Down Expand Up @@ -801,6 +793,30 @@ export class MainView extends React.Component<IProps, IStates> {
}
}

private _onViewChanged(
sender: JupyterCadModel,
change: IChangedArgs<JSONValue>
): void {
if (change.name === 'grid') {
this._gridHelper?.removeFromParent();
this._gridHelper = null;
const grid = change.newValue as GridHelper | undefined;

if (grid && grid.visible) {
this._gridHelper = new THREE.GridHelper(
grid.size,
grid.divisions,
this.state.lightTheme ? LIGHT_GRID_COLOR : DARK_GRID_COLOR,
this.state.lightTheme ? LIGHT_GRID_COLOR : DARK_GRID_COLOR
// 0x888888,
// 0x888888
);
this._gridHelper.geometry.rotateX(Math.PI / 2);
this._scene.add(this._gridHelper);
}
}
}

private _handleThemeChange = (): void => {
const lightTheme =
document.body.getAttribute('data-jp-theme-light') === 'true';
Expand Down Expand Up @@ -899,7 +915,7 @@ export class MainView extends React.Component<IProps, IStates> {
private _requestID: any = null; // ID of window.requestAnimationFrame
private _geometry: THREE.BufferGeometry; // Threejs BufferGeometry
private _refLength: number | null = null; // Length of bounding box of current object
private _gridHelper: THREE.GridHelper; // Threejs grid
private _gridHelper: THREE.GridHelper | null = null; // Threejs grid
private _sceneAxe: (THREE.ArrowHelper | Line2)[]; // Array of X, Y and Z axe
private _controls: OrbitControls; // Threejs control
private _resizeTimeout: any;
Expand Down
28 changes: 26 additions & 2 deletions src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export class JupyterCadModel implements IJupyterCadModel {
this.sharedModel.changed.connect(this._onSharedModelChanged);
this.sharedModel.awareness.on('change', this._onClientStateChanged);
this.annotationModel = annotationModel;

this._view = new Map<string, JSONValue>();
}

readonly collaborative = true;
Expand All @@ -50,6 +52,10 @@ export class JupyterCadModel implements IJupyterCadModel {
return this._sharedModelChanged;
}

get viewChanged(): ISignal<this, IChangedArgs<JSONValue>> {
return this._viewChanged;
}

get themeChanged(): Signal<
this,
IChangedArgs<string, string | null, string>
Expand Down Expand Up @@ -96,7 +102,6 @@ export class JupyterCadModel implements IJupyterCadModel {
}

fromString(data: string): void {
console.debug('fromString:', data);
const jsonData: IJCadContent = JSON.parse(data);
const ajv = new Ajv();
const validate = ajv.compile(jcadSchema);
Expand Down Expand Up @@ -177,6 +182,22 @@ export class JupyterCadModel implements IJupyterCadModel {
return this.sharedModel.awareness.clientID;
}

getView(key: string): JSONValue | undefined {
return this._view.get(key);
}

setView(key: string, value: JSONValue): void {
const oldValue = this._view.get(key) ?? null;
this._view.set(key, value);
this._viewChanged.emit({ name: key, oldValue, newValue: value });
}

deleteView(key: string): void {
const oldValue = this._view.get(key) ?? null;
this._view.delete(key);
this._viewChanged.emit({ name: key, oldValue, newValue: null });
}

addMetadata(key: string, value: string): void {
this.sharedModel.setMetadata(key, value);
}
Expand Down Expand Up @@ -209,9 +230,13 @@ export class JupyterCadModel implements IJupyterCadModel {
private _dirty = false;
private _readOnly = false;
private _isDisposed = false;

private _view: Map<string, JSONValue>;

private _contentChanged = new Signal<this, void>(this);
private _stateChanged = new Signal<this, IChangedArgs<any>>(this);
private _themeChanged = new Signal<this, IChangedArgs<any>>(this);
private _viewChanged = new Signal<this, IChangedArgs<JSONValue>>(this);
private _clientStateChanged = new Signal<
this,
Map<number, IJupyterCadClientState>
Expand All @@ -226,7 +251,6 @@ export class JupyterCadDoc
{
constructor() {
super();

this._options = this.ydoc.getMap<any>('options');
this._objects = this.ydoc.getArray<Y.Map<any>>('objects');
this._metadata = this.ydoc.getMap<string>('metadata');
Expand Down
21 changes: 21 additions & 0 deletions src/schema/grid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"type": "object",
"description": "Grid::Helper",
"title": "IGrid",
"required": ["Size", "Divisions", "Visible"],
"additionalProperties": false,
"properties": {
"Size": {
"type": "number",
"description": "The size of the grid"
},
"Divisions": {
"type": "number",
"description": "The number of divisions"
},
"Visible": {
"type": "boolean",
"description": "Whether the grid is visible or not"
}
}
}
78 changes: 78 additions & 0 deletions src/toolbar/gridtoolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Button } from '@jupyterlab/ui-components';

import * as React from 'react';

import { GridHelper, IDict, IJupyterCadModel } from '../types';
import { FormDialog } from './formdialog';
import { ToolbarModel } from './model';

interface IProps {
toolbarModel: ToolbarModel;
}

export class HelpersToolbarReact extends React.Component<IProps> {
private _schema: IDict;
private _model: IJupyterCadModel;

constructor(props: IProps) {
super(props);
this._model = this.props.toolbarModel.jcadModel!;
}

async componentDidMount(): Promise<void> {
this._updateGrid();
this._model.viewChanged.connect(this._updateGrid, this);
}

async componentWillUnmount(): Promise<void> {
this._model.viewChanged.disconnect(this._updateGrid, this);
}

private _updateGrid(): void {
const grid = this._model.getView('grid') as GridHelper | undefined;
this._schema = {
title: 'Grid Helper',
shape: 'Grid::Helper',
schema: this.props.toolbarModel.formSchema['Grid::Helper'],
default: {
Name: 'Grid Helper',
Size: grid?.size ?? 40,
Divisions: grid?.divisions ?? 40,
Visible: grid?.visible ?? true
},
syncData: (props: IDict) => {
const { Size, Divisions, Visible } = props;
const grid: GridHelper = {
size: Size,
divisions: Divisions,
visible: Visible
};
this._model.setView('grid', grid);
}
};
}

render(): React.ReactNode {
return (
<div style={{ paddingLeft: '10px', display: 'flex' }}>
<Button
className={'jp-ToolbarButtonComponent'}
style={{ color: 'var(--jp-ui-font-color1)' }}
onClick={async () => {
const dialog = new FormDialog({
toolbarModel: this.props.toolbarModel,
title: this._schema.title,
sourceData: this._schema.default,
schema: this._schema.schema,
syncData: this._schema.syncData,
cancelButton: true
});
await dialog.launch();
}}
>
Grid
</Button>
</div>
);
}
}
8 changes: 6 additions & 2 deletions src/toolbar/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import { ToolbarModel } from './model';
import { OperatorToolbarReact } from './operatortoolbar';
import { PartToolbarReact } from './parttoolbar';
import { UserToolbarReact } from './usertoolbar';
import { HelpersToolbarReact } from './gridtoolbar';

interface IProps {
toolbarModel: ToolbarModel;
}

interface IState {
selected: 'PART' | 'OPERATOR';
selected: 'PART' | 'OPERATOR' | 'HELPERS';
}
export class ToolbarReact extends React.Component<IProps, IState> {
constructor(props: IProps) {
Expand Down Expand Up @@ -108,11 +109,14 @@ export class ToolbarReact extends React.Component<IProps, IState> {
{this.state.selected === 'OPERATOR' && (
<OperatorToolbarReact toolbarModel={this.props.toolbarModel} />
)}
{this.state.selected === 'HELPERS' && (
<HelpersToolbarReact toolbarModel={this.props.toolbarModel} />
)}
<UserToolbarReact toolbarModel={this.props.toolbarModel} />
</div>
);
}

private _lastForm?: { dialog: FormDialog; title: string };
private _toolbarOption = ['PART', 'OPERATOR'];
private _toolbarOption = ['PART', 'OPERATOR', 'HELPERS'];
}
28 changes: 23 additions & 5 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { User } from '@jupyterlab/services';
import { MapChange, YDocument, StateChange } from '@jupyter/ydoc';

import { ISignal, Signal } from '@lumino/signaling';
import { JSONObject } from '@lumino/coreutils';
import { JSONObject, JSONValue } from '@lumino/coreutils';

import { IJupyterCadTracker } from './token';
import { IJCadContent, IJCadObject, IJCadModel } from './_interface/jcad';
Expand Down Expand Up @@ -109,6 +109,15 @@ export type Camera = {
up: number[];
};

/**
* Grid's dimensions
*/
export type GridHelper = {
size: number;
divisions: number;
visible: boolean;
};

export interface IJcadObjectDocChange {
contextChange?: MapChange;
objectChange?: MapChange;
Expand All @@ -131,6 +140,8 @@ export interface IJupyterCadDoc extends YDocument<IJupyterCadDocChange> {
options: JSONObject;
metadata: JSONObject;

metadataChanged: ISignal<IJupyterCadDoc, MapChange>;

objectExists(name: string): boolean;
getObjectByName(name: string): IJCadObject | undefined;
removeObjectByName(name: string): void;
Expand All @@ -145,8 +156,6 @@ export interface IJupyterCadDoc extends YDocument<IJupyterCadDocChange> {
getMetadata(key: string): string | undefined;
setMetadata(key: string, value: string): void;
removeMetadata(key: string): void;

metadataChanged: ISignal<IJupyterCadDoc, MapChange>;
}

export interface IJupyterCadClientState {
Expand All @@ -165,21 +174,25 @@ export interface IJupyterCadClientState {

export interface IJupyterCadModel extends DocumentRegistry.IModel {
isDisposed: boolean;
sharedModel: IJupyterCadDoc;
localState: IJupyterCadClientState | null;

sharedModelChanged: ISignal<IJupyterCadModel, IJupyterCadDocChange>;
themeChanged: Signal<
IJupyterCadModel,
IChangedArgs<string, string | null, string>
>;
viewChanged: ISignal<IJupyterCadModel, IChangedArgs<JSONValue>>;
clientStateChanged: ISignal<
IJupyterCadModel,
Map<number, IJupyterCadClientState>
>;
sharedMetadataChanged: ISignal<IJupyterCadDoc, MapChange>;
sharedModel: IJupyterCadDoc;
localState: IJupyterCadClientState | null;

getWorker(): Worker;
getContent(): IJCadContent;
getAllObject(): IJCadModel;

syncPointer(position: PointerPosition | undefined, emitter?: string): void;
syncCamera(camera: Camera | undefined, emitter?: string): void;
syncSelectedObject(name: string | undefined, emitter?: string): void;
Expand All @@ -188,8 +201,13 @@ export interface IJupyterCadModel extends DocumentRegistry.IModel {
value: any;
parentType: 'panel' | 'dialog';
});

getClientId(): number;

getView(key: string): JSONValue | undefined;
setView(key: string, value: JSONValue): void;
deleteView(key: string): void;

addMetadata(key: string, value: string): void;
removeMetadata(key: string): void;
}
Expand Down

0 comments on commit d642f18

Please sign in to comment.