/**
 * 3D Foundation Project
 * Copyright 2019 Smithsonian Institution
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ import Node from "@ff/graph/Node" ; import Component from "@ff/graph/Component" ; import Property from "@ff/graph/Property" ; import "@ff/scene/ui/PropertyView" ; import { customElement , property , html } from "@ff/ui/CustomElement" ; import Tree from "@ff/ui/Tree" ; import CVSettingsTask from "../../components/CVSettingsTask" ; import { TaskView } from "../../components/CVTask" ; import NVNode from "../../nodes/NVNode" ; @ customElement ( "sv-settings-task-view" ) export default class SettingsTaskView extends TaskView < CVSettingsTask > { protected render ( ) { const node = this . activeNode ; if ( ! node ) { return html `<div class="sv-placeholder">Please select a node to display its properties.</div>` ; } return html `<div class="ff-flex-item-stretch ff-scroll-y">
            <sv-settings-tree .node=${ node }></sv-settings-tree>
        </div>` ; } protected onActiveNode ( previous , next ) { this . requestUpdate ( ) ; } } interface ITreeNode { id : string ; children : ITreeNode [ ] ; text : string ; classes : string ; property ? : Property ; } @ customElement ( "sv-settings-tree" ) export class SettingsTree extends Tree < ITreeNode > { @ property ( { attribute : false } ) node : NVNode = null ; protected firstConnected ( ) { super . firstConnected ( ) ; this . classList . add ( "ff-property-tree" , "sv-settings-tree" ) ; } protected getClasses ( treeNode ) { return treeNode . classes ; } protected update ( changedProperties ) { if ( changedProperties . has ( "node" ) ) { this . root = this . createNodeTreeNode ( this . node ) ; } super . update ( changedProperties ) ; } protected renderNodeHeader ( node ) { if ( node . property ) { return html `<div class="ff-text ff-property-label ff-ellipsis">${ node . text }</div>
                <ff-property-view .property=${ node . property }></ff-property-view>` ; } return html `<div class="ff-text ff-label ff-ellipsis">${ node . text }</div>` ; } protected createNodeTreeNode ( node ) { const components = node . components . getArray ( ) . filter ( component => component [ "settingProperties" ] ) ; return { id : node . id , text : node . displayName , classes : "ff-node" , children : components . map ( component => ( { id : component . id , text : component . displayName , classes : "ff-component" , property : null , children : this . createPropertyNodes ( component [ "settingProperties" ] ) , } ) ) , } ; } protected createPropertyNodes ( properties ) { const root = { children : [ ] } ; properties . forEach ( property => { const fragments = property . path . split ( "." ) ; let node = root ; const count = fragments . length ; const last = count - 1 ; for ( let i = 0 ; i < count ; ++ i ) { const fragment = fragments [ i ] ; let child = node . children . find ( node => node . text === fragment ) ; if ( ! child ) { const id = i === last ? property . key : fragment ; child = { id , text : fragment , classes : "" , children : [ ] , property : i === last ? property : null } ; node . children . push ( child ) ; } node = child ; } } ) ; return root . children ; } }