// @flow
import { type I18n as I18nType } from '@lingui/core';
import { t, Trans } from '@lingui/macro';
import * as React from 'react';
import {
type TreeViewItemContent,
type TreeItemProps,
layersRootFolderId,
} from '.';
import Tooltip from '@material-ui/core/Tooltip';
import { type HTMLDataset } from '../Utils/HTMLDataset';
import VisibilityIcon from '../UI/CustomSvgIcons/Visibility';
import VisibilityOffIcon from '../UI/CustomSvgIcons/VisibilityOff';
import LockIcon from '../UI/CustomSvgIcons/Lock';
import LockOpenIcon from '../UI/CustomSvgIcons/LockOpen';
import Radio from '@material-ui/core/Radio';
const styles = {
tooltip: { marginRight: 5, verticalAlign: 'bottom' },
};
export type LayerTreeViewItemProps = {|
...TreeItemProps,
layersContainer: gdLayersContainer,
chosenLayer: string,
onChooseLayer: (layerName: string) => void,
onSelectLayer: (layer: gdLayer | null) => void,
onEditLayer: (layer: ?gdLayer) => void,
onDeleteLayer: (layer: gdLayer) => void,
onLayersModified: () => void,
onRenameLayer: (oldName: string, newName: string) => void,
triggerOnLayersModified: () => void,
|};
export const getLayerTreeViewItemId = (layer: gdLayer): string => {
// Pointers are used because they stay the same even when the names are
// changed.
return `layer-${layer.ptr}`;
};
export class LayerTreeViewItemContent implements TreeViewItemContent {
layer: gdLayer;
props: LayerTreeViewItemProps;
constructor(layer: gdLayer, props: LayerTreeViewItemProps) {
this.layer = layer;
this.props = props;
}
isDescendantOf(itemContent: TreeViewItemContent): boolean {
return itemContent.getId() === layersRootFolderId;
}
getRootId(): string {
// This is not actually a parent, but it's useful to check where layers
// can be dropped.
return layersRootFolderId;
}
getName(i18n: I18nType): string | React.Node {
return this._isBaseLayer() ? i18n._(t`Base layer`) : this.layer.getName();
}
_isBaseLayer(): any {
return !this.layer.getName();
}
getId(): string {
return getLayerTreeViewItemId(this.layer);
}
getHtmlId(nodeIndex: number): ?string {
// This index is not reversed with `_getRevertedIndex`
return `layer-${this.props.layersContainer.getLayerPosition(
this.layer.getName()
)}`;
}
getDataSet(): ?HTMLDataset {
return {
scene: this.layer.getName(),
};
}
getThumbnail(): ?string {
return null;
}
onClick(): void {
this.props.onSelectLayer(this.layer);
}
rename(newName: string): void {
if (!newName) {
return;
}
const oldName = this.layer.getName();
if (oldName === newName) {
return;
}
this.props.onRenameLayer(oldName, newName);
}
edit(): void {
this.props.onEditLayer(this.layer);
this.props.onSelectLayer(null);
}
_isVisible(): boolean {
return this.layer.getVisibility();
}
_isLocked(): boolean {
return this.layer.isLocked();
}
_setVisibility(visible: boolean): void {
this.layer.setVisibility(visible);
this.props.triggerOnLayersModified();
}
_setLocked(isLocked: boolean): void {
this.layer.setLocked(isLocked);
this.props.triggerOnLayersModified();
}
getRightButton(i18n: I18nType): any {
return [
{
icon: this._isVisible() ? : ,
label: i18n._(t`Visible`),
click: () => this._setVisibility(!this._isVisible()),
id: 'layer-visibility',
},
{
icon:
this._isLocked() || !this._isVisible() ? (
) : (
),
label: i18n._(t`Locked`),
enabled: this._isVisible(),
click: () => this._setLocked(!this._isLocked()),
id: 'layer-lock',
},
];
}
buildMenuTemplate(i18n: I18nType, index: number): any {
return [
{
label: i18n._(t`Rename`),
click: () => this.props.editName(this.getId()),
accelerator: 'F2',
enabled: !this._isBaseLayer(),
},
{
label: i18n._(t`Delete`),
click: () => this.delete(),
accelerator: 'Backspace',
enabled: !this._isBaseLayer(),
},
{
type: 'separator',
},
{
label: i18n._(t`Open layer editor`),
click: () => {
this.props.onEditLayer(this.layer);
this.props.onSelectLayer(null);
},
},
{
type: 'separator',
},
{
type: 'checkbox',
label: i18n._(t`Visible`),
checked: this._isVisible(),
click: () => this._setVisibility(!this._isVisible()),
},
{
type: 'checkbox',
label: i18n._(t`Locked`),
enabled: this._isVisible(),
checked: this._isLocked() || !this._isVisible(),
click: () => this._setLocked(!this._isLocked()),
},
];
}
_isChosenLayer(): boolean {
return this.layer.getName() === this.props.chosenLayer;
}
renderRightComponent(i18n: I18nType): ?React.Node {
return (
Layer where instances are added by default}
>
this.props.onChooseLayer(this.layer.getName())}
size="small"
id={`layer-selected-${
this._isChosenLayer() ? 'checked' : 'unchecked'
}`}
/>
);
}
delete(): void {
this.props.onDeleteLayer(this.layer);
}
getIndex(): number {
return this._getRevertedIndex(
this.props.layersContainer.getLayerPosition(this.layer.getName())
);
}
_getRevertedIndex(index: number): number {
return this.props.layersContainer.getLayersCount() - 1 - index;
}
moveAt(destinationIndex: number): void {
const originIndex = this.getIndex();
if (destinationIndex !== originIndex) {
this.props.layersContainer.moveLayer(
this._getRevertedIndex(originIndex),
// When moving the item down, it must not be counted.
this._getRevertedIndex(
destinationIndex + (destinationIndex <= originIndex ? 0 : -1)
)
);
this._onProjectItemModified();
}
}
_onProjectItemModified() {
if (this.props.unsavedChanges)
this.props.unsavedChanges.triggerUnsavedChanges();
this.props.forceUpdate();
}
}