color4LineComponent.tsx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import * as React from "react";
  2. import { Observable } from "babylonjs/Misc/observable";
  3. import { Color4 } from "babylonjs/Maths/math.color";
  4. import { NumericInputComponent } from "../lines/numericInputComponent";
  5. import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
  6. import { faMinus, faPlus } from "@fortawesome/free-solid-svg-icons";
  7. import { PropertyChangedEvent } from '../propertyChangedEvent';
  8. import { ColorPickerLineComponent } from './colorPickerComponent';
  9. const copyIcon: string = require("./copy.svg");
  10. export interface IColor4LineComponentProps {
  11. label: string;
  12. target: any;
  13. propertyName: string;
  14. onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
  15. onChange?: () => void;
  16. isLinear?: boolean;
  17. }
  18. export class Color4LineComponent extends React.Component<IColor4LineComponentProps, { isExpanded: boolean, color: Color4 }> {
  19. private _localChange = false;
  20. constructor(props: IColor4LineComponentProps) {
  21. super(props);
  22. let value = this.props.target[this.props.propertyName];
  23. let currentColor = value.getClassName() === "Color4" ? value.clone() : new Color4(value.r, value.g, value.b, 1.0);
  24. this.state = { isExpanded: false, color: currentColor };
  25. if (props.isLinear) {
  26. this.state.color.toGammaSpaceToRef(this.state.color);
  27. }
  28. props.target._isLinearColor = props.isLinear; // so that replayRecorder can append toLinearSpace() as appropriate
  29. }
  30. shouldComponentUpdate(nextProps: IColor4LineComponentProps, nextState: { color: Color4 }) {
  31. let value = this.props.target[this.props.propertyName];
  32. let currentColor = value.getClassName() === "Color4" ? value : new Color4(value.r, value.g, value.b, 1.0);
  33. if (this.props.isLinear) {
  34. currentColor.toGammaSpaceRef(currentColor);
  35. }
  36. if (!currentColor.equals(nextState.color) || this._localChange) {
  37. nextState.color = currentColor.clone();
  38. this._localChange = false;
  39. return true;
  40. }
  41. return false;
  42. }
  43. setPropertyValue(newColor: Color4) {
  44. this.props.target[this.props.propertyName] = newColor;
  45. if (this.props.isLinear) {
  46. this.props.target[this.props.propertyName] = newColor.toLinearSpace();
  47. }
  48. }
  49. onChange(newValue: string) {
  50. this._localChange = true;
  51. const newColor = Color4.FromHexString(newValue);
  52. if (this.props.onPropertyChangedObservable) {
  53. this.props.onPropertyChangedObservable.notifyObservers({
  54. object: this.props.target,
  55. property: this.props.propertyName,
  56. value: newColor,
  57. initialValue: this.state.color,
  58. });
  59. }
  60. this.setPropertyValue(newColor);
  61. this.setState({ color: newColor });
  62. if (this.props.onChange) {
  63. this.props.onChange();
  64. }
  65. }
  66. switchExpandState() {
  67. this._localChange = true;
  68. this.setState({ isExpanded: !this.state.isExpanded });
  69. }
  70. raiseOnPropertyChanged(previousValue: Color4) {
  71. if (!this.props.onPropertyChangedObservable) {
  72. return;
  73. }
  74. this.props.onPropertyChangedObservable.notifyObservers({
  75. object: this.props.target,
  76. property: this.props.propertyName,
  77. value: this.state.color,
  78. initialValue: previousValue,
  79. });
  80. }
  81. updateStateR(value: number) {
  82. this._localChange = true;
  83. const store = this.state.color.clone();
  84. this.state.color.r = value;
  85. this.setPropertyValue(this.state.color);
  86. this.setState({ color: this.state.color });
  87. this.raiseOnPropertyChanged(store);
  88. }
  89. updateStateG(value: number) {
  90. this._localChange = true;
  91. const store = this.state.color.clone();
  92. this.state.color.g = value;
  93. this.setPropertyValue(this.state.color);
  94. this.setState({ color: this.state.color });
  95. this.raiseOnPropertyChanged(store);
  96. }
  97. updateStateB(value: number) {
  98. this._localChange = true;
  99. const store = this.state.color.clone();
  100. this.state.color.b = value;
  101. this.setPropertyValue(this.state.color);
  102. this.setState({ color: this.state.color });
  103. this.raiseOnPropertyChanged(store);
  104. }
  105. updateStateA(value: number) {
  106. this._localChange = true;
  107. const store = this.state.color.clone();
  108. this.props.target[this.props.propertyName].a = value;
  109. this.state.color.a = value;
  110. this.props.target[this.props.propertyName] = this.state.color;
  111. this.setState({ color: this.state.color });
  112. this.raiseOnPropertyChanged(store);
  113. }
  114. copyToClipboard() {
  115. var element = document.createElement('div');
  116. element.textContent = this.state.color.toHexString();
  117. document.body.appendChild(element);
  118. if (window.getSelection) {
  119. var range = document.createRange();
  120. range.selectNode(element);
  121. window.getSelection()!.removeAllRanges();
  122. window.getSelection()!.addRange(range);
  123. }
  124. document.execCommand('copy');
  125. element.remove();
  126. }
  127. render() {
  128. const chevron = this.state.isExpanded ? <FontAwesomeIcon icon={faMinus} /> : <FontAwesomeIcon icon={faPlus} />;
  129. return (
  130. <div className="color3Line">
  131. <div className="firstLine">
  132. <div className="label" title={this.props.label}>
  133. {this.props.label}
  134. </div>
  135. <div className="color3">
  136. <ColorPickerLineComponent value={this.state.color} onColorChanged={color => {
  137. this.onChange(color);
  138. }} />
  139. </div>
  140. <div className="copy hoverIcon" onClick={() => this.copyToClipboard()} title="Copy to clipboard">
  141. <img src={copyIcon} alt=""/>
  142. </div>
  143. <div className="expand hoverIcon" onClick={() => this.switchExpandState()} title="Expand">
  144. {chevron}
  145. </div>
  146. </div>
  147. {
  148. this.state.isExpanded &&
  149. <div className="secondLine">
  150. <NumericInputComponent label="r" value={this.state.color.r} onChange={(value) => this.updateStateR(value)} />
  151. <NumericInputComponent label="g" value={this.state.color.g} onChange={(value) => this.updateStateG(value)} />
  152. <NumericInputComponent label="b" value={this.state.color.b} onChange={(value) => this.updateStateB(value)} />
  153. <NumericInputComponent label="a" value={this.state.color.a} onChange={(value) => this.updateStateA(value)} />
  154. </div>
  155. }
  156. </div>
  157. );
  158. }
  159. }