msDestiny14 4 năm trước cách đây
mục cha
commit
b3cff35d92

+ 31 - 0
guiEditor/src/sharedUiComponents/lines/booleanLineComponent.tsx

@@ -0,0 +1,31 @@
+import * as React from "react";
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faCheck, faTimesCircle } from "@fortawesome/free-solid-svg-icons";
+
+export interface IBooleanLineComponentProps {
+    label: string;
+    value: boolean;
+}
+
+export class BooleanLineComponent extends React.Component<IBooleanLineComponentProps> {
+    constructor(props: IBooleanLineComponentProps) {
+        super(props);
+    }
+
+    render() {
+
+        const check = this.props.value ? <FontAwesomeIcon icon={faCheck} /> : <FontAwesomeIcon icon={faTimesCircle} />
+        const className = this.props.value ? "value check" : "value uncheck";
+
+        return (
+            <div className="textLine">
+                <div className="label" title={this.props.label}>
+                    {this.props.label}
+                </div>
+                <div className={className}>
+                    {check}
+                </div>
+            </div>
+        );
+    }
+}

+ 21 - 0
guiEditor/src/sharedUiComponents/lines/buttonLineComponent.tsx

@@ -0,0 +1,21 @@
+import * as React from "react";
+
+export interface IButtonLineComponentProps {
+    label: string;
+    onClick: () => void;
+}
+
+export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
+    constructor(props: IButtonLineComponentProps) {
+        super(props);
+    }
+
+    render() {
+
+        return (
+            <div className="buttonLine">
+                <button onClick={() => this.props.onClick()}>{this.props.label}</button>
+            </div>
+        );
+    }
+}

+ 39 - 0
guiEditor/src/sharedUiComponents/lines/fileButtonLineComponent.tsx

@@ -0,0 +1,39 @@
+import * as React from "react";
+
+interface IFileButtonLineComponentProps {
+    label: string;
+    onClick: (file: File) => void;
+    accept: string;
+}
+
+export class FileButtonLineComponent extends React.Component<IFileButtonLineComponentProps> {
+    private static _IDGenerator = 0;
+    private _id = FileButtonLineComponent._IDGenerator++;
+    private uploadInputRef: React.RefObject<HTMLInputElement>;
+
+
+    constructor(props: IFileButtonLineComponentProps) {
+        super(props);
+        this.uploadInputRef = React.createRef();
+    }
+
+    onChange(evt: any) {
+        var files: File[] = evt.target.files;
+        if (files && files.length) {
+            this.props.onClick(files[0]);
+        }
+
+        evt.target.value = "";
+    }
+
+    render() {
+        return (
+            <div className="buttonLine">
+                <label htmlFor={"file-upload" + this._id} className="file-upload">
+                    {this.props.label}
+                </label>
+                <input ref={this.uploadInputRef} id={"file-upload" + this._id} type="file" accept={this.props.accept} onChange={evt => this.onChange(evt)} />
+            </div>
+        );
+    }
+}

+ 27 - 0
guiEditor/src/sharedUiComponents/lines/iconButtonLineComponent.tsx

@@ -0,0 +1,27 @@
+import * as React from 'react';
+
+export interface IIconButtonLineComponentProps {
+  icon: string;
+  onClick: () => void;
+  tooltip: string;
+  active?: boolean;
+}
+
+export class IconButtonLineComponent extends React.Component<
+  IIconButtonLineComponentProps
+> {
+  constructor(props: IIconButtonLineComponentProps) {
+    super(props);
+  }
+
+  render() {
+    return (
+      <div
+        style={{ backgroundColor: this.props.active ? '#111111' : '' }}
+        title={this.props.tooltip}
+        className={`icon ${this.props.icon}`}
+        onClick={() => this.props.onClick()}
+      />
+    );
+  }
+}

+ 51 - 0
guiEditor/src/sharedUiComponents/lines/indentedTextLineComponent.tsx

@@ -0,0 +1,51 @@
+import * as React from "react";
+
+interface IIndentedTextLineComponentProps {
+    value?: string;
+    color?: string;
+    underline?: boolean;
+    onLink?: () => void;
+    url?: string;
+    additionalClass?: string;
+}
+
+export class IndentedTextLineComponent extends React.Component<IIndentedTextLineComponentProps> {
+    constructor(props: IIndentedTextLineComponentProps) {
+        super(props);
+    }
+
+    onLink() {
+        if (this.props.url) {
+            window.open(this.props.url, '_blank');
+            return;
+        }
+        if (!this.props.onLink) {
+            return;
+        }
+
+        this.props.onLink();
+    }
+
+    renderContent() {
+        if (this.props.onLink || this.props.url) {
+            return (
+                <div className="link-value" title={this.props.value} onClick={() => this.onLink()}>
+                    {this.props.url ? "doc" : (this.props.value || "no name")}
+                </div>
+            )
+        }
+        return (
+            <div className="value" title={this.props.value} style={{ color: this.props.color ? this.props.color : "" }}>
+                {this.props.value || "no name"}
+            </div>
+        )
+    }
+
+    render() {
+        return (
+            <div className={"indented " + (this.props.underline ? "textLine underline" : "textLine" + (this.props.additionalClass ? " " + this.props.additionalClass : ""))}>
+                {this.renderContent()}
+            </div>
+        );
+    }
+}

+ 47 - 0
guiEditor/src/sharedUiComponents/lines/linkButtonComponent.tsx

@@ -0,0 +1,47 @@
+import * as React from "react";
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+interface ILinkButtonComponentProps {
+    label: string;
+    buttonLabel: string;
+    url?: string;
+    onClick: () => void;
+    icon?: IconProp;
+    onIconClick?: () => void;
+}
+
+export class LinkButtonComponent extends React.Component<ILinkButtonComponentProps> {
+    constructor(props: ILinkButtonComponentProps) {
+        super(props);
+    }
+
+    onLink() {
+        if (this.props.url) {
+            window.open(this.props.url, '_blank');
+        }
+    }
+
+    render() {
+        return (
+            <div className={"linkButtonLine"}>
+                <div className="link" title={this.props.label} onClick={() => this.onLink()}>
+                    {this.props.label}
+                </div>
+                <div className="link-button">
+                    <button onClick={() => this.props.onClick()}>{this.props.buttonLabel}</button>
+                </div> 
+                {
+                    this.props.icon &&
+                    <div className="link-icon hoverIcon" onClick={() => {
+                        if (this.props.onIconClick) {
+                            this.props.onIconClick();
+                        }
+                    }}>
+                        <FontAwesomeIcon icon={this.props.icon} />
+                    </div> 
+                }
+            </div>
+        );
+    }
+}

+ 38 - 0
guiEditor/src/sharedUiComponents/lines/messageLineComponent.tsx

@@ -0,0 +1,38 @@
+import * as React from "react";
+import { IconProp } from "@fortawesome/fontawesome-svg-core";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+
+interface IMessageLineComponentProps {
+    text: string;
+    color?: string;
+    icon?: IconProp;
+}
+
+export class MessageLineComponent extends React.Component<IMessageLineComponentProps> {
+    constructor(props: IMessageLineComponentProps) {
+        super(props);
+    }
+
+    render() {
+        if (this.props.icon) {
+            return (
+                <div className="iconMessageLine">
+                    <div className="icon" style={{ color: this.props.color ? this.props.color : "" }}>
+                        <FontAwesomeIcon icon={this.props.icon}/>
+                    </div>
+                    <div className="value" title={this.props.text}>
+                        {this.props.text}
+                    </div>
+                </div>
+            );
+        }
+
+        return (
+            <div className="messageLine">
+                <div className="value" title={this.props.text} style={{ color: this.props.color ? this.props.color : "" }}>
+                    {this.props.text}
+                </div>
+            </div>
+        );
+    }
+}

+ 80 - 0
guiEditor/src/sharedUiComponents/lines/numericInputComponent.tsx

@@ -0,0 +1,80 @@
+import * as React from "react";
+
+interface INumericInputComponentProps {
+    label: string;
+    value: number;
+    step?: number;
+    onChange: (value: number) => void;
+    precision?: number;
+}
+
+export class NumericInputComponent extends React.Component<INumericInputComponentProps, { value: string }> {
+
+    static defaultProps = {
+        step: 1,
+    };
+
+    private _localChange = false;
+    constructor(props: INumericInputComponentProps) {
+        super(props);
+
+        this.state = { value: this.props.value.toFixed(this.props.precision !== undefined ? this.props.precision : 3) }
+    }
+
+    shouldComponentUpdate(nextProps: INumericInputComponentProps, nextState: { value: string }) {
+        if (this._localChange) {
+            return true;
+        }
+
+        if (nextProps.value.toString() !== nextState.value) {
+            nextState.value = nextProps.value.toFixed(this.props.precision !== undefined ? this.props.precision : 3);
+            return true;
+        }
+        return false;
+    }
+
+    updateValue(evt: any) {
+        let value = evt.target.value;
+
+        if (/[^0-9\.\-]/g.test(value)) {
+            return;
+        }
+
+        let valueAsNumber = parseFloat(value);
+
+        this._localChange = true;
+        this.setState({ value: value });
+
+        if (isNaN(valueAsNumber)) {
+            return;
+        }
+
+        this.props.onChange(valueAsNumber);
+    }
+
+    onBlur() {
+        this._localChange = false;
+        let valueAsNumber = parseFloat(this.state.value);
+
+        if (isNaN(valueAsNumber)) {
+            this.props.onChange(this.props.value);
+            return;
+        }
+
+        this.props.onChange(valueAsNumber);
+    }
+
+    render() {
+        return (
+            <div className="numeric">
+                {
+                    this.props.label &&
+                    <div className="numeric-label" title={this.props.label}>
+                        {`${this.props.label}: `}
+                    </div>
+                }
+                <input type="number" step={this.props.step} className="numeric-input" value={this.state.value} onChange={evt => this.updateValue(evt)} onBlur={() => this.onBlur()}/>
+            </div>
+        )
+    }
+}

+ 52 - 0
guiEditor/src/sharedUiComponents/lines/radioLineComponent.tsx

@@ -0,0 +1,52 @@
+import * as React from "react";
+import { Nullable } from "babylonjs/types";
+import { Observer, Observable } from "babylonjs/Misc/observable";
+
+interface IRadioButtonLineComponentProps {
+    onSelectionChangedObservable: Observable<RadioButtonLineComponent>;
+    label: string;
+    isSelected: () => boolean;
+    onSelect: () => void;
+}
+
+export class RadioButtonLineComponent extends React.Component<IRadioButtonLineComponentProps, { isSelected: boolean }> {
+    private _onSelectionChangedObserver: Nullable<Observer<RadioButtonLineComponent>>;
+
+    constructor(props: IRadioButtonLineComponentProps) {
+        super(props);
+
+        this.state = { isSelected: this.props.isSelected() };
+    }
+
+    componentDidMount() {
+        this._onSelectionChangedObserver = this.props.onSelectionChangedObservable.add((value) => {
+            this.setState({ isSelected: value === this });
+        });
+    }
+
+    componentWillUnmount() {
+        if (this._onSelectionChangedObserver) {
+            this.props.onSelectionChangedObservable.remove(this._onSelectionChangedObserver);
+            this._onSelectionChangedObserver = null;
+        }
+    }
+
+    onChange() {
+        this.props.onSelect();
+        this.props.onSelectionChangedObservable.notifyObservers(this);
+    }
+
+    render() {
+        return (
+            <div className="radioLine">
+                <div className="label" title={this.props.label}>
+                    {this.props.label}
+                </div>
+                <div className="radioContainer">
+                    <input id={this.props.label} className="radio" type="radio" checked={this.state.isSelected} onChange={() => this.onChange()} />
+                    <label htmlFor={this.props.label} className="labelForRadio" />
+                </div>
+            </div>
+        );
+    }
+}

+ 60 - 0
guiEditor/src/sharedUiComponents/lines/textLineComponent.tsx

@@ -0,0 +1,60 @@
+import * as React from "react";
+
+interface ITextLineComponentProps {
+    label?: string;
+    value?: string;
+    color?: string;
+    underline?: boolean;
+    onLink?: () => void;
+    url?: string;
+    ignoreValue?: boolean;
+    additionalClass?: string;
+}
+
+export class TextLineComponent extends React.Component<ITextLineComponentProps> {
+    constructor(props: ITextLineComponentProps) {
+        super(props);
+    }
+
+    onLink() {
+        if (this.props.url) {
+            window.open(this.props.url, '_blank');
+            return;
+        }
+        if (!this.props.onLink) {
+            return;
+        }
+
+        this.props.onLink();
+    }
+
+    renderContent() {
+        if (this.props.ignoreValue) {
+            return null;
+        }
+
+        if (this.props.onLink || this.props.url) {
+            return (
+                <div className="link-value" title={this.props.value} onClick={() => this.onLink()}>
+                    {this.props.url ? "doc" : (this.props.value || "no name")}
+                </div>
+            )
+        }
+        return (
+            <div className="value" title={this.props.value} style={{ color: this.props.color ? this.props.color : "" }}>
+                {this.props.value || "no name"}
+            </div>
+        )
+    }
+
+    render() {
+        return (
+            <div className={this.props.underline ? "textLine underline" : "textLine" + (this.props.additionalClass ? " " + this.props.additionalClass : "")}>
+                <div className="label"  title={this.props.label ?? ""}>
+                    {this.props.label ?? ""}
+                </div>
+                {this.renderContent()}
+            </div>
+        );
+    }
+}