|
@@ -0,0 +1,174 @@
|
|
|
+import * as React from "react";
|
|
|
+import { Observable } from "babylonjs/Misc/observable";
|
|
|
+import { Color3, Color4 } from "babylonjs/Maths/math";
|
|
|
+import { PropertyChangedEvent } from "./propertyChangedEvent";
|
|
|
+import { NumericInputComponent } from "./numericInputComponent";
|
|
|
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
|
+import { faMinus, faPlus, faCopy } from "@fortawesome/free-solid-svg-icons";
|
|
|
+import { GlobalState } from '../globalState';
|
|
|
+
|
|
|
+export interface IColor4LineComponentProps {
|
|
|
+ label: string;
|
|
|
+ target: any;
|
|
|
+ propertyName: string;
|
|
|
+ onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
|
|
|
+ onChange?: () => void;
|
|
|
+ globalState: GlobalState;
|
|
|
+}
|
|
|
+
|
|
|
+export class Color4LineComponent extends React.Component<IColor4LineComponentProps, { isExpanded: boolean, color: Color4 }> {
|
|
|
+ private _localChange = false;
|
|
|
+ constructor(props: IColor4LineComponentProps) {
|
|
|
+ super(props);
|
|
|
+
|
|
|
+ this.state = { isExpanded: false, color: this.props.target[this.props.propertyName].clone() };
|
|
|
+ }
|
|
|
+
|
|
|
+ shouldComponentUpdate(nextProps: IColor4LineComponentProps, nextState: { color: Color4 }) {
|
|
|
+ const currentState = nextProps.target[nextProps.propertyName];
|
|
|
+
|
|
|
+ if (!currentState.equals(nextState.color) || this._localChange) {
|
|
|
+ nextState.color = currentState.clone();
|
|
|
+ this._localChange = false;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ onChange(newValue: string) {
|
|
|
+ this._localChange = true;
|
|
|
+ const newColor = Color3.FromHexString(newValue);
|
|
|
+
|
|
|
+ if (this.props.onPropertyChangedObservable) {
|
|
|
+ this.props.onPropertyChangedObservable.notifyObservers({
|
|
|
+ object: this.props.target,
|
|
|
+ property: this.props.propertyName,
|
|
|
+ value: newColor,
|
|
|
+ initialValue: this.state.color
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ this.props.target[this.props.propertyName] = new Color4(newColor.r, newColor.g, newColor.b, this.props.target[this.props.propertyName].a);
|
|
|
+
|
|
|
+ this.setState({ color: this.props.target[this.props.propertyName] });
|
|
|
+
|
|
|
+ if (this.props.onChange) {
|
|
|
+ this.props.onChange();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ switchExpandState() {
|
|
|
+ this._localChange = true;
|
|
|
+ this.setState({ isExpanded: !this.state.isExpanded });
|
|
|
+ }
|
|
|
+
|
|
|
+ raiseOnPropertyChanged(previousValue: Color4) {
|
|
|
+ if (!this.props.onPropertyChangedObservable) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.props.onPropertyChangedObservable.notifyObservers({
|
|
|
+ object: this.props.target,
|
|
|
+ property: this.props.propertyName,
|
|
|
+ value: this.state.color,
|
|
|
+ initialValue: previousValue
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ updateStateR(value: number) {
|
|
|
+ this._localChange = true;
|
|
|
+
|
|
|
+ const store = this.state.color.clone();
|
|
|
+ this.props.target[this.props.propertyName].x = value;
|
|
|
+ this.state.color.r = value;
|
|
|
+ this.props.target[this.props.propertyName] = this.state.color;
|
|
|
+ this.setState({ color: this.state.color });
|
|
|
+
|
|
|
+ this.raiseOnPropertyChanged(store);
|
|
|
+ }
|
|
|
+
|
|
|
+ updateStateG(value: number) {
|
|
|
+ this._localChange = true;
|
|
|
+
|
|
|
+ const store = this.state.color.clone();
|
|
|
+ this.props.target[this.props.propertyName].g = value;
|
|
|
+ this.state.color.g = value;
|
|
|
+ this.props.target[this.props.propertyName] = this.state.color;
|
|
|
+ this.setState({ color: this.state.color });
|
|
|
+
|
|
|
+ this.raiseOnPropertyChanged(store);
|
|
|
+ }
|
|
|
+
|
|
|
+ updateStateB(value: number) {
|
|
|
+ this._localChange = true;
|
|
|
+
|
|
|
+ const store = this.state.color.clone();
|
|
|
+ this.props.target[this.props.propertyName].b = value;
|
|
|
+ this.state.color.b = value;
|
|
|
+ this.props.target[this.props.propertyName] = this.state.color;
|
|
|
+ this.setState({ color: this.state.color });
|
|
|
+
|
|
|
+ this.raiseOnPropertyChanged(store);
|
|
|
+ }
|
|
|
+
|
|
|
+ updateStateA(value: number) {
|
|
|
+ this._localChange = true;
|
|
|
+
|
|
|
+ const store = this.state.color.clone();
|
|
|
+ this.props.target[this.props.propertyName].a = value;
|
|
|
+ this.state.color.a = value;
|
|
|
+ this.props.target[this.props.propertyName] = this.state.color;
|
|
|
+ this.setState({ color: this.state.color });
|
|
|
+
|
|
|
+ this.raiseOnPropertyChanged(store);
|
|
|
+ }
|
|
|
+
|
|
|
+ copyToClipboard() {
|
|
|
+ var element = document.createElement('div');
|
|
|
+ element.textContent = this.state.color.toHexString();
|
|
|
+ document.body.appendChild(element);
|
|
|
+
|
|
|
+ if (window.getSelection) {
|
|
|
+ var range = document.createRange();
|
|
|
+ range.selectNode(element);
|
|
|
+ window.getSelection()!.removeAllRanges();
|
|
|
+ window.getSelection()!.addRange(range);
|
|
|
+ }
|
|
|
+
|
|
|
+ document.execCommand('copy');
|
|
|
+ element.remove();
|
|
|
+ }
|
|
|
+
|
|
|
+ render() {
|
|
|
+
|
|
|
+ const chevron = this.state.isExpanded ? <FontAwesomeIcon icon={faMinus} /> : <FontAwesomeIcon icon={faPlus} />
|
|
|
+ const colorAsColor3 = this.state.color.getClassName() === "Color3" ? this.state.color : new Color3(this.state.color.r, this.state.color.g, this.state.color.b);
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className="color3Line">
|
|
|
+ <div className="firstLine">
|
|
|
+ <div className="label">
|
|
|
+ {this.props.label}
|
|
|
+ </div>
|
|
|
+ <div className="color3">
|
|
|
+ <input type="color" value={colorAsColor3.toHexString()} onChange={(evt) => this.onChange(evt.target.value)} />
|
|
|
+ </div>
|
|
|
+ <div className="copy hoverIcon" onClick={() => this.copyToClipboard()} title="Copy to clipboard">
|
|
|
+ <FontAwesomeIcon icon={faCopy} />
|
|
|
+ </div>
|
|
|
+ <div className="expand hoverIcon" onClick={() => this.switchExpandState()} title="Expand">
|
|
|
+ {chevron}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ {
|
|
|
+ this.state.isExpanded &&
|
|
|
+ <div className="secondLine">
|
|
|
+ <NumericInputComponent globalState={this.props.globalState} label="r" value={this.state.color.r} onChange={value => this.updateStateR(value)} />
|
|
|
+ <NumericInputComponent globalState={this.props.globalState} label="g" value={this.state.color.g} onChange={value => this.updateStateG(value)} />
|
|
|
+ <NumericInputComponent globalState={this.props.globalState} label="b" value={this.state.color.b} onChange={value => this.updateStateB(value)} />
|
|
|
+ <NumericInputComponent globalState={this.props.globalState} label="a" value={this.state.color.a} onChange={value => this.updateStateA(value)} />
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|