diff --git a/modules/lstream/lazyStreams.ts b/modules/lstream/lazyStreams.ts new file mode 100644 index 00000000..704febfc --- /dev/null +++ b/modules/lstream/lazyStreams.ts @@ -0,0 +1,22 @@ +import {state, StateStream} from "lstream/index"; + +export class LazyStreams { + + index = new Map>(); + proto: (id: string) => T; + + constructor(proto?: (id: string) => T) { + this.proto = proto || ((id: string) => null); + } + + get(id: string) { + + let state$: StateStream = this.index[id]; + if (state$ == null) { + state$ = state(this.proto(id)); + this.index[id] = state$; + } + return state$; + } + +} \ No newline at end of file diff --git a/modules/ui/components/Dialog.tsx b/modules/ui/components/Dialog.tsx index df7b9464..7d7452c9 100644 --- a/modules/ui/components/Dialog.tsx +++ b/modules/ui/components/Dialog.tsx @@ -4,16 +4,18 @@ import cx from 'classnames'; import ButtonGroup from "ui/components/controls/ButtonGroup"; import Button from "ui/components/controls/Button"; -export function Dialog({children, className, okText, cancelText, onOK, ...props}: WindowProps & { +export function Dialog({children, compact, className, okText, cancelText, onOK, ...props}: WindowProps & { cancelText?: string, okText?: string, - onOK?: () => void + onOK?: () => void, + compact?: boolean, }) { - return - + {!compact && } {onOK && } } diff --git a/modules/ui/components/Folder.jsx b/modules/ui/components/Folder.jsx index feb7fe11..961f0f9c 100644 --- a/modules/ui/components/Folder.jsx +++ b/modules/ui/components/Folder.jsx @@ -1,42 +1,40 @@ -import React from 'react'; +import React, {useState} from 'react'; import ls from './Folder.less' import Fa from "./Fa"; -import cx from 'classnames'; +import cx from "classnames"; -export default class Folder extends React.Component{ - - constructor() { - super(); - this.state = { - closed: null - } - } +export function InnerFolder(props) { - isClosed() { - let {closable, defaultClosed} = this.props; + const [closed, setClosed] = useState(null) + + function isClosed(){ + let {closable, defaultClosed} = props; if (!closable) return false; - return closable && (this.state.closed === null ? defaultClosed : this.state.closed) + return closable && (closed === null ? defaultClosed : closed) } - tweakClose = () => { - this.setState({closed: !this.isClosed()}); - }; - - render() { - let {title, closable, className, children} = this.props; - return
- {title} - {!this.isClosed() && children} -
+ function tweakClose( ) { + setClosed(!isClosed()) } + + const {title, titleClass, closable, children} = props; + return + {title} + {!isClosed() && children} + } -export function Title({children, isClosed, onClick}) { +export default function Folder({className, ...props}) { + return
+ +
+} +export function Title({children, isClosed, onClick, className}) { const titleCss = onClick ? { cursor: 'pointer' } : {}; - return
+ return
{' '}{children}
; diff --git a/modules/ui/components/Folder.less b/modules/ui/components/Folder.less index a83f2352..3cc8e4f1 100644 --- a/modules/ui/components/Folder.less +++ b/modules/ui/components/Folder.less @@ -1,8 +1,5 @@ @import "~ui/styles/theme.less"; -.root { -} - .title { border-bottom: 1px solid @border-color; background-color: @bg-base-color; diff --git a/modules/ui/components/GenericExplorer.less b/modules/ui/components/GenericExplorer.less new file mode 100644 index 00000000..ea313a4c --- /dev/null +++ b/modules/ui/components/GenericExplorer.less @@ -0,0 +1,72 @@ +.objectItem { + @itemRadius: 5px; + @alt-color: #9c9c9c; + + .button { + cursor: pointer; + &:hover { + background-color: #0074D9; + } + &:active { + background-color: #000d7f; + } + } + + + background-color: rgba(0,0,0, 0.6); + border: 1px solid #000; + border-radius: 5px; + margin: 2px @itemRadius; + pointer-events: auto; + display: flex; + align-items: stretch; + + .expandHandleInactive { + border-radius: @itemRadius 0 0 @itemRadius; + padding: 3px 3px; + } + .expandHandle { + .expandHandleInactive; + .button; + //background-color: @alt-color; + } + + .menuButton { + border-radius: 0 @itemRadius @itemRadius 0; + background-color: @alt-color; + padding: 0 3px; + .button; + } + + .objectLabel { + display: flex; + align-items: center; + flex: 1; + padding: 0 5px; + .button; + + &.selected { + background: linear-gradient(#59acff, #0074D9); + } + } + + .onOffButton { + display: flex; + align-items: center; + padding: 0 4px; + } + + .onOffButton.on { + cursor: pointer; + background-color: #005e82; + .button; + } + .onOffButton.off { + cursor: pointer; + background-color: #5f5f5f; + .button; + } + +} + + diff --git a/modules/ui/components/GenericExplorer.tsx b/modules/ui/components/GenericExplorer.tsx new file mode 100644 index 00000000..58438e3e --- /dev/null +++ b/modules/ui/components/GenericExplorer.tsx @@ -0,0 +1,58 @@ +import ls from "./GenericExplorer.less"; + +import React, {useState} from 'react'; +import cx from 'classnames'; +import {AiFillCaretDown, AiFillCaretRight} from "react-icons/ai"; +import {BsDot} from "react-icons/bs"; + +interface GenericExplorerControlProps { + title: string; + onClick: any; + on: boolean; + children: any; +} + +export function GenericExplorerControl(props: GenericExplorerControlProps) { + + return {props.children} +} + +interface GenericExplorerNodeProps { + children: any; + controls: any; + label: any; + selected: boolean; + defaultExpanded?: boolean; + expandable: boolean; + select: any; +} + +export function GenericExplorerNode(props: GenericExplorerNodeProps) { + + const [expanded, setExpanded] = useState(!!props.defaultExpanded); + const expandable = props.expandable; + + const toggle = expandable ? (() => setExpanded(expanded => !expanded)) : undefined; + + return <> +
+ + {expandable ? (expanded ? : ) + : } + + {props.controls} + + + {props.label} + + + ... + +
+ {expanded &&
+ {props.children} +
} + ; +} diff --git a/modules/ui/components/SceneInlineSection.less b/modules/ui/components/SceneInlineSection.less new file mode 100644 index 00000000..c9e2081d --- /dev/null +++ b/modules/ui/components/SceneInlineSection.less @@ -0,0 +1,25 @@ +.titleBar { + background: rgba(0,0,0,0.7); + color: white; + text-transform: uppercase; + padding: 3px 5px; + pointer-events: auto; + flex: 0 0 ; + margin-top: 4px; +} + +.scrollableArea { + overflow-y: auto; + flex: 1 1; + pointer-events: auto; +} + +.delineation { + background: rgba(0,0,0,0.5); + color: white; + padding: 0; + pointer-events: auto; + flex: 0 0 ; + margin-top: 2px; +} + diff --git a/modules/ui/components/SceneInlineSection.tsx b/modules/ui/components/SceneInlineSection.tsx new file mode 100644 index 00000000..6f3284cd --- /dev/null +++ b/modules/ui/components/SceneInlineSection.tsx @@ -0,0 +1,26 @@ +import React from "react"; +import ls from "./SceneInlineSection.less"; + +interface SceneInlineSectionProps { + title: any; + children: any; +} + +export function SceneInlineSection(props: SceneInlineSectionProps) { + + return + {props.title} +
+ {props.children} +
+
+ +} + +export function SceneInlineTitleBar({children, ...props}) { + return
{children}
; +} + +export function SceneInlineDelineation({children, ...props}) { + return
{children}
; +} \ No newline at end of file diff --git a/modules/ui/components/Stack.jsx b/modules/ui/components/Stack.jsx index 40766825..c50eb36e 100644 --- a/modules/ui/components/Stack.jsx +++ b/modules/ui/components/Stack.jsx @@ -1,9 +1,10 @@ import React from 'react'; import ls from './Stack.less' +import cx from "classnames"; -export default function Stack(props) { - return
+export default function Stack({className, ...props}) { + return
} diff --git a/modules/ui/components/Stack.less b/modules/ui/components/Stack.less index 55e77344..c519909d 100644 --- a/modules/ui/components/Stack.less +++ b/modules/ui/components/Stack.less @@ -6,3 +6,8 @@ padding: 3px 6px; line-height: 1.7; } + +.root > .root { + padding: 0; + border-bottom: none; +} diff --git a/modules/ui/components/Window.less b/modules/ui/components/Window.less index dae50cf6..fba6c39b 100644 --- a/modules/ui/components/Window.less +++ b/modules/ui/components/Window.less @@ -12,6 +12,10 @@ pointer-events: auto; } +.root.compact { + font-size: 11px; +} + .mandatoryBorder { border: 5px solid @bg-color-4; } diff --git a/modules/ui/components/Window.tsx b/modules/ui/components/Window.tsx index 556c5de0..6bb11524 100644 --- a/modules/ui/components/Window.tsx +++ b/modules/ui/components/Window.tsx @@ -28,6 +28,7 @@ export interface WindowProps { onClose: () => void; props?: JSX.IntrinsicAttributes; footer?: JSX.Element; + compact?: boolean; } export default class Window extends React.Component { @@ -45,9 +46,9 @@ export default class Window extends React.Component { render() { let {initWidth, initHeight, initLeft, initTop, initRight, initBottom, centerScreen, setFocus, className, resizeCapturingBuffer, - resize, enableResize, children, title, icon, minimizable = false, onClose, controlButtons, footer, ...props} = this.props; + resize, enableResize, children, title, icon, minimizable = false, onClose, controlButtons, footer, compact, ...props} = this.props; - return
+ return
{icon}{title.toUpperCase()}
diff --git a/modules/ui/components/controls/ColorControl.tsx b/modules/ui/components/controls/ColorControl.tsx new file mode 100644 index 00000000..61a8afcb --- /dev/null +++ b/modules/ui/components/controls/ColorControl.tsx @@ -0,0 +1,50 @@ +import React, {useState} from 'react'; +import {SketchPicker} from 'react-color'; +import Button from "ui/components/controls/Button"; +import {CgColorPicker} from "react-icons/cg"; +import {Dialog} from "ui/components/Dialog"; +import ButtonGroup from "ui/components/controls/ButtonGroup"; +import {RiDeleteBack2Line} from "react-icons/ri"; + +interface ColorControlProps { + + value: string; + + onChange: any; + + dialogTitle?: any + +} + +export function ColorControl(props: ColorControlProps) { + const [open, setOpen] = useState(false); + const {onChange, value} = props; + const style = value ? { backgroundColor: value } : undefined; + + return + + {value||} + + + + {open && setOpen(false)} title={props.dialogTitle}/>} + +} + +function ColorDialog({onChange, value, title, onClose}) { + const change = (color) => { + onChange(color.hex); + } + return + + +} + +function NoValue() { + return {''}; +} \ No newline at end of file diff --git a/modules/ui/effects.ts b/modules/ui/effects.ts index f67304ee..388c707a 100644 --- a/modules/ui/effects.ts +++ b/modules/ui/effects.ts @@ -2,13 +2,14 @@ import {useCallback, useContext, useEffect, useState} from 'react'; import {StreamsContext} from "./streamsContext"; import {ApplicationContext} from "context"; import {Emitter, Stream} from "lstream"; +import produce from "immer"; export function useStream(getStream: Stream | ((ctx: ApplicationContext) => Stream)) : T { const basicStreams = useContext(StreamsContext); const [state, setState] = useState<{data: T}>(); - const stream = resolveStream(getStream, basicStreams); + const stream: Emitter = resolveStream(getStream, basicStreams); if (!stream) { console.log(getStream); @@ -41,6 +42,26 @@ export function useStreamWithUpdater(getStream: (ctx: ApplicationContext) => } -function resolveStream(getStream, basicStreams) { +export type Patcher = (draft: T) => void; + +export function useStreamWithPatcher(getStream: (ctx: ApplicationContext) => Emitter) : [T, (patcher: Patcher) => void] { + + const data = useStream(getStream); + const basicStreams = useContext(StreamsContext); + + const stream: Emitter = resolveStream(getStream, basicStreams); + + const patch = (patcher: Patcher) => { + const newData: T = produce(data, (draft:T) => { + patcher(draft) + }) + stream.next(newData); + } + + return [data, patch]; + +} + +function resolveStream(getStream, basicStreams): Emitter { return typeof getStream === 'function' ? getStream(basicStreams) : getStream } diff --git a/modules/ui/styles/global/main.less b/modules/ui/styles/global/main.less index ecd3781a..2111efe9 100644 --- a/modules/ui/styles/global/main.less +++ b/modules/ui/styles/global/main.less @@ -36,4 +36,15 @@ path { .warning-text { color: @on-color-highlight-variant-yellow; -} \ No newline at end of file +} + +.bg-color-0 { background-color: @bg-color-0; } +.bg-color-1 { background-color: @bg-color-1; } +.bg-color-2 { background-color: @bg-color-2; } +.bg-color-3 { background-color: @bg-color-3; } +.bg-color-4 { background-color: @bg-color-4; } +.bg-color-5 { background-color: @bg-color-5; } +.bg-color-6 { background-color: @bg-color-6; } +.bg-color-7 { background-color: @bg-color-7; } +.bg-color-8 { background-color: @bg-color-8; } +.bg-color-9 { background-color: @bg-color-9; } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 905437de..5b19eec4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "opencascade.js": "^1.1.1", "prop-types": "15.6.0", "react": "^16.13.1", + "react-color": "^2.19.3", "react-dom": "^16.13.1", "react-icons": "^4.2.0", "react-toastify": "^5.5.0", @@ -8915,6 +8916,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -9173,6 +9179,11 @@ "node": ">= 8.16.2" } }, + "node_modules/material-colors": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", + "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" + }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -11110,6 +11121,31 @@ "node": ">=0.10.0" } }, + "node_modules/react-color": { + "version": "2.19.3", + "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", + "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==", + "dependencies": { + "@icons/material": "^0.2.4", + "lodash": "^4.17.15", + "lodash-es": "^4.17.15", + "material-colors": "^1.2.1", + "prop-types": "^15.5.10", + "reactcss": "^1.2.0", + "tinycolor2": "^1.4.1" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-color/node_modules/@icons/material": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", + "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-dom": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", @@ -11242,6 +11278,14 @@ "loose-envify": "cli.js" } }, + "node_modules/reactcss": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", + "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", + "dependencies": { + "lodash": "^4.0.1" + } + }, "node_modules/read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -13036,6 +13080,14 @@ "node": ">=0.6.0" } }, + "node_modules/tinycolor2": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", + "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==", + "engines": { + "node": "*" + } + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -22536,6 +22588,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -22731,6 +22788,11 @@ "resolved": "https://registry.npmjs.org/marked/-/marked-1.0.0.tgz", "integrity": "sha512-Wo+L1pWTVibfrSr+TTtMuiMfNzmZWiOPeO7rZsQUY5bgsxpHesBEcIWJloWVTFnrMXnf/TL30eTFSGJddmQAng==" }, + "material-colors": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", + "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -24344,6 +24406,28 @@ } } }, + "react-color": { + "version": "2.19.3", + "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", + "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==", + "requires": { + "@icons/material": "^0.2.4", + "lodash": "^4.17.15", + "lodash-es": "^4.17.15", + "material-colors": "^1.2.1", + "prop-types": "^15.5.10", + "reactcss": "^1.2.0", + "tinycolor2": "^1.4.1" + }, + "dependencies": { + "@icons/material": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", + "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==", + "requires": {} + } + } + }, "react-dom": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", @@ -24454,6 +24538,14 @@ } } }, + "reactcss": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", + "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", + "requires": { + "lodash": "^4.0.1" + } + }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -25966,6 +26058,11 @@ "setimmediate": "^1.0.4" } }, + "tinycolor2": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", + "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", diff --git a/package.json b/package.json index a1db187c..e1e36572 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "opencascade.js": "^1.1.1", "prop-types": "15.6.0", "react": "^16.13.1", + "react-color": "^2.19.3", "react-dom": "^16.13.1", "react-icons": "^4.2.0", "react-toastify": "^5.5.0", diff --git a/web/app/cad/attributes/attributesPlugin.ts b/web/app/cad/attributes/attributesPlugin.ts new file mode 100644 index 00000000..c72ccf29 --- /dev/null +++ b/web/app/cad/attributes/attributesPlugin.ts @@ -0,0 +1,32 @@ +import {Plugin} from "plugable/pluginSystem"; +import {AttributesService} from "cad/attributes/attributesService"; + +interface AttributesPluginInputContext { +} + +export interface AttributesPluginContext { + attributesService: AttributesService; +} + +type AttributesPluginWorkingContext = AttributesPluginInputContext&AttributesPluginContext; + +declare module 'context' { + interface ApplicationContext extends AttributesPluginContext {} +} + +export const AttributesPlugin: Plugin = { + + inputContextSpec: { + }, + + outputContextSpec: { + attributesService: 'required', + }, + + activate(ctx: AttributesPluginWorkingContext) { + ctx.attributesService = new AttributesService(); + }, + +} + + diff --git a/web/app/cad/attributes/attributesService.ts b/web/app/cad/attributes/attributesService.ts new file mode 100644 index 00000000..56d2888e --- /dev/null +++ b/web/app/cad/attributes/attributesService.ts @@ -0,0 +1,19 @@ +import {LazyStreams} from "lstream/lazyStreams"; + +export class AttributesService { + + streams = new LazyStreams(id => ({ + hidden: false, + label: null, + color: null + })); + +} + +export interface ModelAttributes { + hidden: boolean; + label: string; + color: string; +} + + diff --git a/web/app/cad/craft/craftPlugin.ts b/web/app/cad/craft/craftPlugin.ts index 17711ebf..ddc1a9a9 100644 --- a/web/app/cad/craft/craftPlugin.ts +++ b/web/app/cad/craft/craftPlugin.ts @@ -7,6 +7,7 @@ import {intercept} from "lstream/intercept"; import {CoreContext} from "context"; import {MFace} from "../model/mface"; import {OperationParams} from "cad/craft/schema/schema"; +import {clearImplicitModels} from "cad/craft/e0/occCommandInterface"; export function activate(ctx: CoreContext) { @@ -69,6 +70,7 @@ export function activate(ctx: CoreContext) { } function runRequest(request): Promise { + clearImplicitModels(); try { let op = ctx.operationService.get(request.type); if (!op) { @@ -90,6 +92,8 @@ export function activate(ctx: CoreContext) { return result.then ? result : Promise.resolve(result); } catch (e) { return Promise.reject(e); + } finally { + clearImplicitModels(); } } diff --git a/web/app/cad/craft/ui/ObjectExplorer.jsx b/web/app/cad/craft/ui/ObjectExplorer.jsx index 03997490..5af1739e 100644 --- a/web/app/cad/craft/ui/ObjectExplorer.jsx +++ b/web/app/cad/craft/ui/ObjectExplorer.jsx @@ -1,30 +1,40 @@ import React from 'react'; import connect from 'ui/connect'; import {Section} from 'ui/components/Section'; -import Fa from 'ui/components/Fa'; import {constant} from 'lstream'; import ls from './ObjectExplorer.less'; import cx from 'classnames'; -import {MShell} from '../../model/mshell'; -import {MDatum} from '../../model/mdatum'; +import {MShell} from 'cad/model/mshell'; +import {MDatum} from 'cad/model/mdatum'; import mapContext from 'ui/mapContext'; import decoratorChain from 'ui/decoratorChain'; +import {MOpenFaceShell} from "cad/model/mopenFace"; export default connect(streams => streams.craft.models.map(models => ({models}))) (function ObjectExplorer({models}) { - return models.map(m => (m instanceof MShell) ? -
- { - m.faces.map(f => ) - } -
-
- {m.edges.map(e => )} -
- -
: (m instanceof MDatum) ? : null); + return
{models.map(m => { + if (m instanceof MOpenFaceShell) { + return + } else if (m instanceof MShell) { + return +
+ { + m.faces.map(f => ) + } +
+
+ {m.edges.map(e => )} +
+
+ } else if (m instanceof MDatum) { + return ; + } else { + return null; + } + })} +
}); function EdgeSection({edge}) { @@ -36,36 +46,44 @@ function EdgeSection({edge}) { function FaceSection({face}) { return - {(face.productionInfo && face.productionInfo.role) &&
role: {face.productionInfo.role}} />} - {(face.productionInfo && face.productionInfo.originatedFromPrimitive) &&
origin: {face.productionInfo.originatedFromPrimitive}} />} -
{''}}> - {face.sketchObjects.map(o =>
{o.id + ':' + o.sketchPrimitive.constructor.name}
)} -
+ {(face.productionInfo && face.productionInfo.role) && +
role: {face.productionInfo.role}}/>} + {(face.productionInfo && face.productionInfo.originatedFromPrimitive) && +
origin: {face.productionInfo.originatedFromPrimitive}}/>} + {face.edges &&
{face.edges.map(e => )}
} ; } +function SketchesList({face}) { + return
{''}}> + {face.sketchObjects.map(o =>
{o.id + ':' + o.sketchPrimitive.constructor.name}
)} +
; +} + const ModelSection = decoratorChain( mapContext((ctx, props) => ({ select: () => ctx.services.pickControl.pick(props.model) })), connect((streams, props) => (streams.selection[props.type] || constant([])).map(selection => ({selection})))) ( - function ModelSection({model, type, selection, select, ...props}) { + function ModelSection({model, type, typeLabel, selection, select, ...props}) { let labelClasses = cx(ls.modelLabel, { [ls.selected]: selection.indexOf(model.id) !== -1 }); - let label = - {type} {model.id} + let label = + {typeLabel||type} {model.id} ; return
; } ); -function CommonControls() { - return - - ; +function OpenFaceSection({shell}) { + return + + ; } + diff --git a/web/app/cad/craft/ui/ObjectExplorer.less b/web/app/cad/craft/ui/ObjectExplorer.less index 96c9fdfd..09f9c203 100644 --- a/web/app/cad/craft/ui/ObjectExplorer.less +++ b/web/app/cad/craft/ui/ObjectExplorer.less @@ -1,9 +1,13 @@ .selected { - background-color: #7d7d7d; + background-color: #f3fb8a; + color: black; } .modelLabel { cursor: pointer; + display: flex; + align-items: center; + flex-wrap: nowrap; } .hint { diff --git a/web/app/cad/craft/ui/SceneInlineObjectExplorer.tsx b/web/app/cad/craft/ui/SceneInlineObjectExplorer.tsx new file mode 100644 index 00000000..360b3905 --- /dev/null +++ b/web/app/cad/craft/ui/SceneInlineObjectExplorer.tsx @@ -0,0 +1,152 @@ +import React, {useContext, useState} from 'react'; +import {MShell} from 'cad/model/mshell'; +import {MDatum} from 'cad/model/mdatum'; +import {MOpenFaceShell} from "cad/model/mopenFace"; +import {useStream, useStreamWithPatcher} from "ui/effects"; +import {AppContext} from "cad/dom/components/AppContext"; +import {MObject} from "cad/model/mobject"; +import {SceneInlineDelineation, SceneInlineSection, SceneInlineTitleBar} from "ui/components/SceneInlineSection"; +import {GenericExplorerControl, GenericExplorerNode} from "ui/components/GenericExplorer"; +import ls from "cad/craft/ui/ObjectExplorer.less"; +import Fa from "ui/components/Fa"; +import {AiOutlineEye, AiOutlineEyeInvisible} from "react-icons/ai"; +import {ModelAttributes} from "cad/craft/ui/VisibleSwitch"; + + +export function SceneInlineObjectExplorer() { + + const models = useStream(ctx => ctx.craftService.models$); + + if (!models) { + return null; + } + + return {models.map(m => { + if (m instanceof MOpenFaceShell) { + return + } else if (m instanceof MShell) { + return +
+ { + m.faces.map(f => ) + } +
+
+ {m.edges.map(e => )} +
+ +
+ } else if (m instanceof MDatum) { + return ; + } else { + return null; + } + })} +
+} + +function EdgeSection({edge}) { + return + {edge.adjacentFaces.map(f => )} + +} + +function FaceSection({face}) { + return + + {(face.productionInfo && face.productionInfo.role) && +
role: {face.productionInfo.role}}/>} + {(face.productionInfo && face.productionInfo.originatedFromPrimitive) && +
origin: {face.productionInfo.originatedFromPrimitive}}/>} + + {face.edges &&
+ {face.edges.map(e => )} +
} + ; +} + +function SketchesList({face}) { + return
{''}}> + {face.sketchObjects.map(o => )} +
; +} + + +function ModelSection({model, type, typeLabel, expandable = true, controlVisibility = false, visibilityOf = null, ...props}: { + model: MObject, + visibilityOf?: MObject, + typeLabel?: any, + type: string, + children?: any, + controlVisibility?: boolean, + expandable?: boolean, +}) { + const ctx = useContext(AppContext); + const selection: string[] = useStream(ctx => ctx.streams.selection[type]); + + const select = () => ctx.services.pickControl.pick(model); + const selected = selection.indexOf(model.id) !== -1; + + let label = <>{typeLabel === undefined ? type:typeLabel} {model.id}; + visibilityOf = visibilityOf||model; + return + {controlVisibility && } + + + }> + {props.children} + +} + +function OpenFaceSection({shell}) { + return + + ; +} + +function Section(props) { + + const [expanded, setExpanded] = useState(!props.defaultCollapsed); + + const tweakClose = () => { + setExpanded(exp => !exp); + }; + + return <> + + + {props.label} + + {expanded && props.children} + ; +} + +export function VisibleSwitch({modelId}) { + + let [attrs, patch] = useStreamWithPatcher(ctx => ctx.attributesService.streams.get(modelId)); + + const onClick = () => { + patch(attr => { + attr.hidden = !attr.hidden + }) + } + + return + {attrs.hidden ? : } + +} \ No newline at end of file diff --git a/web/app/cad/craft/ui/VisibleSwitch.tsx b/web/app/cad/craft/ui/VisibleSwitch.tsx new file mode 100644 index 00000000..ea77f726 --- /dev/null +++ b/web/app/cad/craft/ui/VisibleSwitch.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import {AiOutlineEye} from "react-icons/ai"; +import {state, StateStream} from "lstream"; +import {useStreamWithPatcher} from "ui/effects"; + +class LazyStreams { + + index = new Map>(); + proto: (id: string) => T; + + constructor(proto?: (id: string) => T) { + this.proto = proto || ((id: string) => null); + } + + get(id: string) { + + let state$: StateStream = this.index[id]; + if (state$ == null) { + state$ = state(this.proto(id)); + this.index[id] = state$; + } + return state$; + } + +} + +export interface ModelAttributes { + + hidden: boolean + +} + +const modelAttrStreams = new LazyStreams(id => ({} as ModelAttributes)); + diff --git a/web/app/cad/craft/wizard/components/form/Form.tsx b/web/app/cad/craft/wizard/components/form/Form.tsx index 81bcde3a..4f13c21e 100644 --- a/web/app/cad/craft/wizard/components/form/Form.tsx +++ b/web/app/cad/craft/wizard/components/form/Form.tsx @@ -51,7 +51,7 @@ export function attachToForm(Control): any { state.activeParam = isActive ? fullPathFlatten : null; }); - const value = _.get(params, fullPath); + const value = params[name]; return + return {props.children} diff --git a/web/app/cad/dom/components/Explorer.jsx b/web/app/cad/dom/components/Explorer.jsx index bf06b6e0..e15fd574 100644 --- a/web/app/cad/dom/components/Explorer.jsx +++ b/web/app/cad/dom/components/Explorer.jsx @@ -1,20 +1,9 @@ import React from 'react'; -import decoratorChain from 'ui/decoratorChain'; -import connect from 'ui/connect'; -import mapContext from 'ui/mapContext'; -import {combine} from 'lstream'; import ObjectExplorer from '../../craft/ui/ObjectExplorer'; import ls from './Explorer.less'; -function Explorer() { +export function Explorer() { return
; -} - -export default decoratorChain( - connect(streams => combine( - - )), - mapContext(ctx => ({})) -)(Explorer); \ No newline at end of file +} \ No newline at end of file diff --git a/web/app/cad/dom/components/Explorer.less b/web/app/cad/dom/components/Explorer.less index 1210052a..0b2afff2 100644 --- a/web/app/cad/dom/components/Explorer.less +++ b/web/app/cad/dom/components/Explorer.less @@ -1,10 +1,10 @@ .root { - overflow: auto; - position: absolute; - top:0; - left:0; - bottom:80px; - max-width: 300px; + //overflow: auto; + //position: absolute; + //top:0; + //left:0; + //bottom:80px; + //max-width: 300px; } .root :global(.sectionHeader) { @@ -15,4 +15,7 @@ border-radius: 3px; pointer-events: initial; cursor: pointer; + display: flex; + align-items: center; + flex-wrap: nowrap; } \ No newline at end of file diff --git a/web/app/cad/dom/components/SelectionView.tsx b/web/app/cad/dom/components/SelectionView.tsx index ac9a9b38..9d8dbccb 100644 --- a/web/app/cad/dom/components/SelectionView.tsx +++ b/web/app/cad/dom/components/SelectionView.tsx @@ -1,6 +1,14 @@ -import React from 'react'; -import {useStream} from "ui/effects"; +import React, {useContext} from 'react'; +import {useStream, useStreamWithPatcher} from "ui/effects"; import {SELECTABLE_ENTITIES} from "../../scene/entityContextPlugin"; +import {AppContext} from "cad/dom/components/AppContext"; +import Field from "ui/components/controls/Field"; +import {InnerFolder} from "ui/components/Folder"; +import Label from "ui/components/controls/Label"; +import TextControl from "ui/components/controls/TextControl"; +import Stack from "ui/components/Stack"; +import {ColorControl} from "ui/components/controls/ColorControl"; + export function SelectionView() { @@ -11,6 +19,7 @@ export function SelectionView() { }); + return
{SELECTABLE_ENTITIES.map((entity, i) => { @@ -20,18 +29,44 @@ export function SelectionView() { if (selection.length === 0) { return null; } - - - return
- {entity} -
    - - {selection.map(id =>
  • {id}
  • )} - -
-
- + return + + {selection.map(id => )} + + })}
+} + +interface SelectedModelViewProps { + + modelId, + type + +} + +function SelectedModelView(props: SelectedModelViewProps) { + + const ctx = useContext(AppContext); + const model = ctx.cadRegistry.find(props.modelId); + const [attrs, patchAttrs] = useStreamWithPatcher(ctx => ctx.attributesService.streams.get(props.modelId)); + + const DO_NOTHING = ()=>{}; + return + + + + patchAttrs(attrs => attrs.label = val)}/> + + + + patchAttrs(attrs => attrs.color = val)}/> + + + ; + + } \ No newline at end of file diff --git a/web/app/cad/dom/components/View3d.jsx b/web/app/cad/dom/components/View3d.jsx index d7b289e9..db9e7035 100644 --- a/web/app/cad/dom/components/View3d.jsx +++ b/web/app/cad/dom/components/View3d.jsx @@ -20,6 +20,7 @@ import SketcherOperationWizard from "../../../sketcher/components/SketcherOperat import {ToastContainer} from "react-toastify"; import 'react-toastify/dist/ReactToastify.css'; import {ContributedComponents} from "./ContributedComponents"; +import {SceneInlineObjectExplorer} from "cad/craft/ui/SceneInlineObjectExplorer"; export default class View3d extends React.Component { @@ -41,7 +42,11 @@ export default class View3d extends React.Component {
- + + +
+ }>
diff --git a/web/app/cad/dom/components/View3d.less b/web/app/cad/dom/components/View3d.less index 66c567a8..32de8596 100644 --- a/web/app/cad/dom/components/View3d.less +++ b/web/app/cad/dom/components/View3d.less @@ -45,6 +45,7 @@ display: flex; align-items: flex-start; flex-grow: 1; + overflow: hidden; } .overlayingPanel { diff --git a/web/app/cad/init/startApplication.js b/web/app/cad/init/startApplication.js index d92f8880..6e060de9 100644 --- a/web/app/cad/init/startApplication.js +++ b/web/app/cad/init/startApplication.js @@ -40,6 +40,7 @@ import * as LocationPlugin from "../location/LocationPlugin"; import * as AssemblyPlugin from "../assembly/assemblyPlugin"; import {WorkbenchesLoaderPlugin} from "cad/workbench/workbenchesLoaderPlugin"; import {PluginSystem} from "plugable/pluginSystem"; +import {AttributesPlugin} from "cad/attributes/attributesPlugin"; export default function startApplication(callback) { @@ -83,7 +84,8 @@ export default function startApplication(callback) { AssemblyPlugin, RemotePartsPlugin, ViewSyncPlugin, - WizardSelectionPlugin + WizardSelectionPlugin, + AttributesPlugin ]; let allPlugins = [...preUIPlugins, ...plugins]; diff --git a/web/app/cad/model/medge.ts b/web/app/cad/model/medge.ts index f006579f..edb41450 100644 --- a/web/app/cad/model/medge.ts +++ b/web/app/cad/model/medge.ts @@ -52,7 +52,7 @@ export class MEdge extends MObject { tan = he.tangentAtStart(); origin = he.vertexA.point; } else { - tan = he.tangentAtEnd(); + tan = he.tangentAtEnd().negate(); origin = he.vertexB.point; } return new Axis(origin, tan); diff --git a/web/app/cad/model/mface.ts b/web/app/cad/model/mface.ts index 3fe13a04..92b3cf6c 100644 --- a/web/app/cad/model/mface.ts +++ b/web/app/cad/model/mface.ts @@ -160,7 +160,7 @@ export class MFace extends MObject { get productionInfo() { if (this._productionInfo === undefined) { - this._productionInfo = !this.brepFace.data.productionInfo ? null : + this._productionInfo = !this.brepFace?.data?.productionInfo ? null : ProductionInfo.fromRawData(this.brepFace.data.productionInfo); } return this._productionInfo; diff --git a/web/app/cad/scene/viewSyncPlugin.js b/web/app/cad/scene/viewSyncPlugin.js index b44b134c..f9030477 100644 --- a/web/app/cad/scene/viewSyncPlugin.js +++ b/web/app/cad/scene/viewSyncPlugin.js @@ -7,6 +7,7 @@ import {MShell} from '../model/mshell'; import {MDatum} from '../model/mdatum'; import DatumView from './views/datumView'; import {View} from './views/view'; +import {SketchingView} from "cad/scene/views/faceView"; export function activate(context) { let {streams} = context; @@ -14,7 +15,8 @@ export function activate(context) { streams.sketcher.update.attach(mFace => mFace.ext.view.updateSketch()); } -function sceneSynchronizer({services: {cadScene, cadRegistry, viewer, wizard, action, pickControl}}) { +function sceneSynchronizer(ctx) { + const {services: {cadScene, cadRegistry, viewer, wizard, action, pickControl}} = ctx; return function() { let wgChildren = cadScene.workGroup.children; let existent = new Set(); @@ -48,6 +50,22 @@ function sceneSynchronizer({services: {cadScene, cadRegistry, viewer, wizard, ac } else { console.warn('unsupported model ' + model); } + const attrStream = ctx.attributesService.streams.get(model.id); + const disposer = attrStream.attach(attrs => { + modelView.rootGroup.visible = !attrs.hidden + viewer.requestRender(); + }); + + modelView.traverse(view => { + if (view instanceof SketchingView) { + const stream = ctx.attributesService.streams.get(view.model.id); + modelView.addDisposer(stream.attach(attr => { + view.setColor(attr.color); + viewer.requestRender(); + })) + } + }); + modelView.addDisposer(disposer) SceneGraph.addToGroup(cadScene.workGroup, modelView.rootGroup); } } diff --git a/web/app/cad/scene/views/edgeView.js b/web/app/cad/scene/views/edgeView.js index 6df56d1f..a95bc651 100644 --- a/web/app/cad/scene/views/edgeView.js +++ b/web/app/cad/scene/views/edgeView.js @@ -5,6 +5,6 @@ export class EdgeView extends CurveBasedView { constructor(edge) { let brepEdge = edge.brepEdge; let tess = brepEdge.data.tessellation ? brepEdge.data.tessellation : brepEdge.curve.tessellateToData(); - super(edge, tess, 2, 3, 0x2B3856, 0xd1726c); + super(edge, tess, 2, 3, 0x2B3856, 0xc42720); } } diff --git a/web/app/cad/scene/views/faceView.js b/web/app/cad/scene/views/faceView.js index 880ab8dd..9d34324f 100644 --- a/web/app/cad/scene/views/faceView.js +++ b/web/app/cad/scene/views/faceView.js @@ -69,15 +69,15 @@ export class FaceView extends SketchingView { } mark(color) { - this.setColor(color || SELECTION_COLOR); + this.updateColor(color || SELECTION_COLOR); } withdraw(color) { - this.setColor(null); + this.updateColor(null); } - - setColor(color) { - setFacesColor(this.meshFaces, color); + + updateColor(color) { + setFacesColor(this.meshFaces, color||this.color); this.geometry.colorsNeedUpdate = true; } } @@ -93,4 +93,4 @@ export function setFacesColor(faces, color) { } export const NULL_COLOR = new THREE.Color(); -export const SELECTION_COLOR = 0xFAFAD2; +export const SELECTION_COLOR = 0xffff80; diff --git a/web/app/cad/scene/views/openFaceView.js b/web/app/cad/scene/views/openFaceView.js index bdc78cd8..17a8612b 100644 --- a/web/app/cad/scene/views/openFaceView.js +++ b/web/app/cad/scene/views/openFaceView.js @@ -28,14 +28,14 @@ export class OpenFaceView extends SketchingView { super(mFace); this.material = new THREE.MeshPhongMaterial({ vertexColors: THREE.FaceColors, - color: 0xB0C4DE, + // color: 0xB0C4DE, shininess: 0, polygonOffset : true, polygonOffsetFactor : 1, polygonOffsetUnits : 2, side : THREE.DoubleSide, transparent: true, - opacity: 0.5 + opacity: 0.3 }); this.updateBounds(); } @@ -60,7 +60,7 @@ export class OpenFaceView extends SketchingView { } updateBounds() { - let markedColor = this.color; + let markedColor = this.markedColor; this.dropGeometry(); let bounds2d = []; @@ -72,9 +72,11 @@ export class OpenFaceView extends SketchingView { surface.northEastPoint(), surface.northWestPoint()]; this.createGeometry(); - if (markedColor) { - this.mark(markedColor); - } + this.updateColor(markedColor || this.color); + } + + traverse(visitor) { + super.traverse(visitor); } updateSketch() { @@ -83,19 +85,19 @@ export class OpenFaceView extends SketchingView { } mark(color) { - this.setColor(color || SELECTION_COLOR); + this.updateColor(color || SELECTION_COLOR); } withdraw(color) { - this.setColor(null); + this.updateColor(null); } - setColor(color) { - setFacesColor(this.mesh.geometry.faces, color); + updateColor(color) { + setFacesColor(this.mesh.geometry.faces, color||this.color); this.mesh.geometry.colorsNeedUpdate = true; } - get color() { + get markedColor() { let face = this.mesh && this.mesh.geometry && this.mesh.geometry.faces[0]; if (face) { return face.color === NULL_COLOR ? null : face.color; diff --git a/web/app/cad/scene/views/shellView.js b/web/app/cad/scene/views/shellView.js index f2b0c257..760a23f7 100644 --- a/web/app/cad/scene/views/shellView.js +++ b/web/app/cad/scene/views/shellView.js @@ -71,6 +71,13 @@ export class ShellView extends View { this.faceViews.forEach(faceView => faceView.setColor(null)); } + traverse(visitor) { + super.traverse(visitor); + this.faceViews.forEach(f => f.traverse(visitor)); + this.edgeViews.forEach(e => e.traverse(visitor)); + this.vertexViews.forEach(e => e.traverse(visitor)); + } + dispose() { this.mesh.material.dispose(); this.mesh.geometry.dispose(); diff --git a/web/app/cad/scene/views/sketchObjectView.js b/web/app/cad/scene/views/sketchObjectView.js index 87cf9377..e8c81b5e 100644 --- a/web/app/cad/scene/views/sketchObjectView.js +++ b/web/app/cad/scene/views/sketchObjectView.js @@ -3,8 +3,8 @@ import {CurveBasedView} from './curveBasedView'; export class SketchObjectView extends CurveBasedView { constructor(mSketchObject, sketchToWorldTransformation) { - const color = mSketchObject.construction ? 0x777777 : 0xFFFFFF; + const color = mSketchObject.construction ? 0x777777 : 0x0000FF; const tess = mSketchObject.sketchPrimitive.tessellate(10).map(sketchToWorldTransformation.apply).map(v => v.data()); - super(mSketchObject, tess, 1, 2, color, 0x49FFA5); + super(mSketchObject, tess, 3, 4, color, 0x49FFA5); } } diff --git a/web/app/cad/scene/views/view.js b/web/app/cad/scene/views/view.js index a6518374..91b8b12a 100644 --- a/web/app/cad/scene/views/view.js +++ b/web/app/cad/scene/views/view.js @@ -1,7 +1,13 @@ +import {createFunctionList} from "gems/func"; +import {Color} from "three"; + export class View { static MARKER = 'ModelView'; - + + disposers = createFunctionList(); + color = new Color(); + constructor(model) { this.model = model; model.ext.view = this; @@ -15,8 +21,25 @@ export class View { withdraw(priority) { } - + + setColor(color) { + if (!color) { + this.color = new Color(); + } else { + this.color.setStyle(color); + } + } + + traverse(visitor) { + visitor(this); + } + + addDisposer(disposer) { + this.disposers.add(disposer); + } + dispose() { + this.disposers.call(); this.model.ext.view = null; this.model = null; }; diff --git a/web/app/cad/scene/wrappers/sceneObject.js b/web/app/cad/scene/wrappers/sceneObject.js index 6af25f5f..f0041c7c 100644 --- a/web/app/cad/scene/wrappers/sceneObject.js +++ b/web/app/cad/scene/wrappers/sceneObject.js @@ -48,7 +48,7 @@ export class SceneSolid { export function createSolidMaterial(skin) { return new THREE.MeshPhongMaterial(Object.assign({ vertexColors: THREE.FaceColors, - color: 0xB0C4DE, + // color: 0xB0C4DE, shininess: 0, polygonOffset : true, polygonOffsetFactor : 1, diff --git a/web/app/cad/sketch/components/SketcherMode.jsx b/web/app/cad/sketch/components/SketcherMode.jsx index e36a6e71..138bc63b 100644 --- a/web/app/cad/sketch/components/SketcherMode.jsx +++ b/web/app/cad/sketch/components/SketcherMode.jsx @@ -1,12 +1,12 @@ import React from 'react'; import {useStream} from "ui/effects"; -export default function SketcherMode({children}) { +export default function SketcherMode({children, whenOff}) { const visible = useStream(ctx => ctx.streams.sketcher.sketchingMode); if (!visible) { - return null; + return whenOff; } return children; diff --git a/web/app/cad/workbench/uiConfigPlugin.js b/web/app/cad/workbench/uiConfigPlugin.js index 499c3d61..3132a244 100644 --- a/web/app/cad/workbench/uiConfigPlugin.js +++ b/web/app/cad/workbench/uiConfigPlugin.js @@ -9,6 +9,7 @@ import OperationHistory from '../craft/ui/OperationHistory'; import Expressions from '../expressions/Expressions'; import {SelectionView} from "../dom/components/SelectionView"; import {GrSelect} from "react-icons/gr"; +import {Explorer} from "cad/dom/components/Explorer"; export function activate(ctx) { const {services, streams} = ctx; @@ -28,7 +29,7 @@ export function activate(ctx) { services.menu.registerMenus(menuConfig); - services.ui.registerFloatView('project', ObjectExplorer, 'Model', 'cubes'); + services.ui.registerFloatView('project', Explorer, 'Model', 'cubes'); services.ui.registerFloatView('history', OperationHistory, 'Modifications', 'history'); services.ui.registerFloatView('expressions', Expressions, 'Expressions', 'percent'); services.ui.registerFloatView('selection', SelectionView, 'Selection', GrSelect); diff --git a/web/app/sketcher/components/ConstraintExplorer.less b/web/app/sketcher/components/ConstraintExplorer.less index 4b9f78b7..20f80c2a 100644 --- a/web/app/sketcher/components/ConstraintExplorer.less +++ b/web/app/sketcher/components/ConstraintExplorer.less @@ -1,4 +1,4 @@ -@import "inSceneUI"; +@import "inSceneUI-sketcher"; .objectItem { background-color: rgba(0,0,0, 0.6); diff --git a/web/app/sketcher/components/SketchObjectExplorer.less b/web/app/sketcher/components/SketchObjectExplorer.less index 64e690a0..8aebf7f3 100644 --- a/web/app/sketcher/components/SketchObjectExplorer.less +++ b/web/app/sketcher/components/SketchObjectExplorer.less @@ -1,4 +1,4 @@ -@import "inSceneUI"; +@import "inSceneUI-sketcher"; .objectItem { background-color: rgba(0,0,0, 0.6); diff --git a/web/app/sketcher/components/inSceneUI.less b/web/app/sketcher/components/inSceneUI-sketcher.less similarity index 100% rename from web/app/sketcher/components/inSceneUI.less rename to web/app/sketcher/components/inSceneUI-sketcher.less