text: import { NumberInput, StringInput, LabelElement } from '../../libs/flow.module.js';
  import { BaseNode } from '../core/BaseNode.js';
  import { Mesh, MathUtils, Vector3 } from 'three';
  
  export class MeshEditor extends BaseNode {
  
  	constructor( mesh = null ) {
  
  		if ( mesh === null ) {
  
  			mesh = new Mesh();
  
  		}
  
  		super( 'Mesh', 1, mesh );
  
  		this.material = null;
  
  		this.defaultMaterial = null;
  		this.defaultPosition = new Vector3();
  		this.defaultRotation = new Vector3();
  		this.defaultScale = new Vector3( 100, 100, 100 );
  
  		this._initTags();
  		this._initTransform();
  		this._initMaterial();
  
  		this.updateDefault();
  		this.update();
  
  		this.onValidElement = () => {};
  
  	}
  
  	setEditor( editor ) {
  
  		if ( this.editor ) {
  
  			this._restoreDefault();
  
  		}
  
  		super.setEditor( editor );
  
  		if ( editor ) {
  
  			const name = this.nameInput.getValue();
  			const mesh = editor.scene.getObjectByName( name );
  
  			this.value = mesh;
  
  			this.updateDefault();
  			this.update();
  
  		}
  
  		return this;
  
  	}
  
  	get mesh() {
  
  		return this.value;
  
  	}
  
  	_initMaterial() {
  
  		const materialElement = new LabelElement( 'Material' ).setInputColor( 'forestgreen' ).setInput( 1 );
  
  		materialElement.onValid( ( source, target, stage ) => {
  
  			const object = target.getObject();
  
  			if ( object && object.isMaterial !== true ) {
  
  				if ( stage === 'dragged' ) {
  
  					const name = target.node.getName();
  
  					this.editor.tips.error( `"${name}" is not a Material.` );
  
  				}
  
  				return false;
  
  			}
  
  		} ).onConnect( () => {
  
  			this.material = materialElement.getLinkedObject() || this.defaultMaterial;
  
  			this.update();
  
  		} );
  
  		this.add( materialElement );
  
  	}
  
  	_initTags() {
  
  		this.nameInput = new StringInput( this.mesh.name ).setReadOnly( true )
  			.onChange( () => this.mesh.name = this.nameInput.getValue() );
  
  		this.add( new LabelElement( 'Name' ).add( this.nameInput ) );
  
  	}
  
  	_initTransform() {
  
  		const update = () => this.update();
  
  		const posX = new NumberInput().setTagColor( 'red' ).onChange( update );
  		const posY = new NumberInput().setTagColor( 'green' ).onChange( update );
  		const posZ = new NumberInput().setTagColor( 'blue' ).onChange( update );
  
  		const rotationStep = 1;
  
  		const rotX = new NumberInput().setTagColor( 'red' ).setStep( rotationStep ).onChange( update );
  		const rotY = new NumberInput().setTagColor( 'green' ).setStep( rotationStep ).onChange( update );
  		const rotZ = new NumberInput().setTagColor( 'blue' ).setStep( rotationStep ).onChange( update );
  
  		const scaleX = new NumberInput( 100 ).setTagColor( 'red' ).setStep( rotationStep ).onChange( update );
  		const scaleY = new NumberInput( 100 ).setTagColor( 'green' ).setStep( rotationStep ).onChange( update );
  		const scaleZ = new NumberInput( 100 ).setTagColor( 'blue' ).setStep( rotationStep ).onChange( update );
  
  		this.add( new LabelElement( 'Position' ).add( posX ).add( posY ).add( posZ ) )
  			.add( new LabelElement( 'Rotation' ).add( rotX ).add( rotY ).add( rotZ ) )
  			.add( new LabelElement( 'Scale' ).add( scaleX ).add( scaleY ).add( scaleZ ) );
  
  		this.posX = posX;
  		this.posY = posY;
  		this.posZ = posZ;
  
  		this.rotX = rotX;
  		this.rotY = rotY;
  		this.rotZ = rotZ;
  
  		this.scaleX = scaleX;
  		this.scaleY = scaleY;
  		this.scaleZ = scaleZ;
  
  	}
  
  	update() {
  
  		const mesh = this.mesh;
  
  		if ( mesh ) {
  
  			const { position, rotation, scale } = mesh;
  
  			position.x = this.posX.getValue();
  			position.y = this.posY.getValue();
  			position.z = this.posZ.getValue();
  
  			rotation.x = MathUtils.degToRad( this.rotX.getValue() );
  			rotation.y = MathUtils.degToRad( this.rotY.getValue() );
  			rotation.z = MathUtils.degToRad( this.rotZ.getValue() );
  
  			scale.x = this.scaleX.getValue() / 100;
  			scale.y = this.scaleY.getValue() / 100;
  			scale.z = this.scaleZ.getValue() / 100;
  
  			mesh.material = this.material || this.defaultMaterial;
  
  		}
  
  	}
  
  	updateDefault() {
  
  		const { material, position, rotation, scale } = this.mesh;
  
  		this.defaultMaterial = material;
  
  		this.defaultPosition = position.clone();
  		this.defaultRotation = new Vector3( MathUtils.radToDeg( rotation.x ), MathUtils.radToDeg( rotation.y ), MathUtils.radToDeg( rotation.z ) );
  		this.defaultScale = scale.clone().multiplyScalar( 100 );
  
  		this._restoreDefault();
  
  	}
  
  	_restoreDefault() {
  
  		const position = this.defaultPosition;
  		const rotation = this.defaultRotation;
  		const scale = this.defaultScale;
  
  		this.posX.setValue( position.x );
  		this.posY.setValue( position.y );
  		this.posZ.setValue( position.z );
  
  		this.rotX.setValue( rotation.x );
  		this.rotY.setValue( rotation.y );
  		this.rotZ.setValue( rotation.z );
  
  		this.scaleX.setValue( scale.x );
  		this.scaleY.setValue( scale.y );
  		this.scaleZ.setValue( scale.z );
  
  		this.mesh.material = this.defaultMaterial;
  
  	}
  
  }
  