// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using FlaxEditor.Content;
using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Elements;
using FlaxEditor.CustomEditors.GUI;
using FlaxEditor.GUI;
using FlaxEditor.GUI.Drag;
using FlaxEditor.GUI.Tabs;
using FlaxEditor.History;
using FlaxEditor.Scripting;
using FlaxEditor.Viewport.Previews;
using FlaxEditor.Windows.Assets;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Surface
{
///
/// The base interface for editor windows that use for content editing.
///
///
interface IVisjectSurfaceWindow : IVisjectSurfaceOwner
{
///
/// Gets the asset edited by the window.
///
Asset VisjectAsset { get; }
///
/// Gets the Visject surface editor.
///
VisjectSurface VisjectSurface { get; }
///
/// The new parameter types enum type to use. Null to disable adding new parameters.
///
IEnumerable NewParameterTypes { get; }
///
/// Event called when surface gets loaded (eg. after opening the window).
///
event Action SurfaceLoaded;
///
/// Called when parameter rename undo action is performed.
///
void OnParamRenameUndo();
///
/// Called when parameter edit attributes undo action is performed.
///
void OnParamEditAttributesUndo();
///
/// Called when parameter add undo action is performed.
///
void OnParamAddUndo();
///
/// Called when parameter remove undo action is performed.
///
void OnParamRemoveUndo();
///
/// Gets the asset parameter.
///
/// The zero-based parameter index.
/// The value.
object GetParameter(int index);
///
/// Sets the asset parameter.
///
/// The zero-based parameter index.
/// The value to set.
void SetParameter(int index, object value);
}
///
/// The surface parameter rename action for undo.
///
///
sealed class RenameParamAction : IUndoAction
{
///
/// The window reference.
///
public IVisjectSurfaceWindow Window;
///
/// The index of the parameter.
///
public int Index;
///
/// The name before.
///
public string Before;
///
/// The name after.
///
public string After;
///
public string ActionString => "Rename parameter";
///
public void Do()
{
Set(After);
}
///
public void Undo()
{
Set(Before);
}
private void Set(string value)
{
var param = Window.VisjectSurface.Parameters[Index];
param.Name = value;
Window.VisjectSurface.OnParamRenamed(param);
Window.OnParamRenameUndo();
}
///
public void Dispose()
{
Window = null;
Before = null;
After = null;
}
}
///
/// The attributes edit action for undo.
///
///
abstract class EditAttributesAction : IUndoAction
{
///
/// The window reference.
///
public IVisjectSurfaceWindow Window;
///
/// The attributes before.
///
public Attribute[] Before;
///
/// The attributes after.
///
public Attribute[] After;
///
public string ActionString => "Edit attributes";
///
public void Do()
{
Set(After);
}
///
public void Undo()
{
Set(Before);
}
///
/// Sets the specified attributes.
///
/// The value.
protected abstract void Set(Attribute[] value);
///
public void Dispose()
{
Window = null;
Before = null;
After = null;
}
}
///
/// The surface attributes edit action for undo.
///
///
sealed class EditSurfaceAttributesAction : EditAttributesAction
{
///
protected override void Set(Attribute[] value)
{
Window.VisjectSurface.Context.Meta.SetAttributes(value);
Window.VisjectSurface.MarkAsEdited();
}
}
///
/// The surface node attributes edit action for undo.
///
///
sealed class EditNodeAttributesAction : EditAttributesAction
{
///
/// The id of the node.
///
public uint ID;
///
protected override void Set(Attribute[] value)
{
var node = Window.VisjectSurface.FindNode(ID);
node.Meta.SetAttributes(value);
Window.VisjectSurface.MarkAsEdited();
}
}
///
/// The surface parameter attributes edit action for undo.
///
///
sealed class EditParamAttributesAction : EditAttributesAction
{
///
/// The index of the parameter.
///
public int Index;
///
protected override void Set(Attribute[] value)
{
var param = Window.VisjectSurface.Parameters[Index];
param.Meta.SetAttributes(value);
Window.VisjectSurface.OnParamEdited(param);
Window.VisjectSurface.MarkAsEdited();
Window.OnParamEditAttributesUndo();
}
}
///
/// The undo action for adding or removing surface parameter.
///
///
///
sealed class AddRemoveParamAction : IUndoAction
{
///
/// The window reference.
///
public IVisjectSurfaceWindow Window;
///
/// True if adding, false if removing parameter.
///
public bool IsAdd;
///
/// The index of the parameter.
///
public int Index;
///
/// The name of the parameter.
///
public string Name;
///
/// The type of the parameter.
///
public ScriptType Type;
///
public string ActionString => IsAdd ? "Add parameter" : "Remove parameter";
///
public void Do()
{
if (IsAdd)
Add();
else
Remove();
}
///
public void Undo()
{
if (IsAdd)
Remove();
else
Add();
}
private void Add()
{
var type = Type;
if (IsAdd && type.Type == typeof(NormalMap))
type = new ScriptType(typeof(Texture));
var param = SurfaceParameter.Create(type, Name);
if (IsAdd && Type.Type == typeof(NormalMap))
param.Value = FlaxEngine.Content.LoadAsyncInternal("Engine/Textures/NormalTexture");
Window.VisjectSurface.Parameters.Insert(Index, param);
Window.VisjectSurface.OnParamCreated(param);
Window.OnParamAddUndo();
}
private void Remove()
{
var param = Window.VisjectSurface.Parameters[Index];
if (!IsAdd)
{
Name = param.Name;
Type = param.Type;
}
Window.VisjectSurface.Parameters.RemoveAt(Index);
Window.VisjectSurface.OnParamDeleted(param);
Window.OnParamRemoveUndo();
}
///
public void Dispose()
{
Window = null;
}
}
///
/// Custom editor for editing Visject Surface parameters collection.
///
///
public class ParametersEditor : CustomEditor
{
private static readonly Attribute[] DefaultAttributes =
{
//new LimitAttribute(float.MinValue, float.MaxValue, 0.1f),
};
///
/// True if show only public properties, otherwise will display all properties.
///
protected bool ShowOnlyPublic = true;
///
public override DisplayStyle Style => DisplayStyle.InlineIntoParent;
///
public override void Initialize(LayoutElementsContainer layout)
{
var window = Values[0] as IVisjectSurfaceWindow;
var asset = window?.VisjectAsset;
if (asset == null)
{
layout.Label("No parameters");
return;
}
if (asset.LastLoadFailed)
{
layout.Label("Failed to load asset");
return;
}
if (!asset.IsLoaded)
{
layout.Label("Loading...", TextAlignment.Center);
return;
}
var parameters = window.VisjectSurface.Parameters;
CustomEditors.Editors.GenericEditor.OnGroupsBegin();
for (int i = 0; i < parameters.Count; i++)
{
var p = parameters[i];
if (!p.IsPublic && ShowOnlyPublic)
continue;
var pIndex = i;
var pValue = p.Value;
var attributes = p.Meta.GetAttributes();
if (attributes == null || attributes.Length == 0)
attributes = DefaultAttributes;
var name = p.Name;
// Editor Display
var editorDisplay = (EditorDisplayAttribute)attributes.FirstOrDefault(x => x is EditorDisplayAttribute);
var itemLayout = CustomEditors.Editors.GenericEditor.OnGroup(layout, editorDisplay);
if (itemLayout is GroupElement groupElement)
groupElement.Panel.Open(false);
if (editorDisplay?.Name != null)
name = editorDisplay.Name;
// Space
var space = (SpaceAttribute)attributes.FirstOrDefault(x => x is SpaceAttribute);
if (space != null)
itemLayout.Space(space.Height);
// Header
var header = (HeaderAttribute)attributes.FirstOrDefault(x => x is HeaderAttribute);
if (header != null)
itemLayout.Header(header);
var propertyValue = new CustomValueContainer
(
p.Type,
pValue,
(instance, index) => ((IVisjectSurfaceWindow)instance).GetParameter(pIndex),
(instance, index, value) => ((IVisjectSurfaceWindow)instance).SetParameter(pIndex, value),
attributes
);
var propertyLabel = new DraggablePropertyNameLabel(name)
{
Tag = pIndex,
Drag = OnDragParameter
};
if (!p.IsPublic)
propertyLabel.TextColor = propertyLabel.TextColor.RGBMultiplied(0.7f);
var tooltipText = "Type: " + window.VisjectSurface.GetTypeName(p.Type);
var tooltip = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute);
if (tooltip != null)
tooltipText += '\n' + tooltip.Text;
propertyLabel.MouseLeftDoubleClick += (label, location) => StartParameterRenaming(pIndex, label);
propertyLabel.SetupContextMenu += OnPropertyLabelSetupContextMenu;
var property = itemLayout.AddPropertyItem(propertyLabel, tooltipText);
property.Property("Value", propertyValue);
}
CustomEditors.Editors.GenericEditor.OnGroupsEnd();
// Parameters creating
var newParameterTypes = window.NewParameterTypes;
if (newParameterTypes != null)
{
layout.Space(parameters.Count > 0 ? 10 : 4);
var newParam = layout.Button("Add parameter...");
newParam.Button.ButtonClicked += OnAddParameterButtonClicked;
layout.Space(10);
}
}
private void OnAddParameterButtonClicked(Button button)
{
var window = (IVisjectSurfaceWindow)Values[0];
var newParameterTypes = window.NewParameterTypes;
// Show context menu with list of parameter types to add
var cm = new ItemsListContextMenu(180);
foreach (var newParameterType in newParameterTypes)
{
var item = new TypeSearchPopup.TypeItemView(newParameterType);
if (newParameterType.Type != null)
item.Name = window.VisjectSurface.GetTypeName(newParameterType);
cm.AddItem(item);
}
cm.ItemClicked += OnAddParameterItemClicked;
cm.SortItems();
cm.Show(button.Parent, button.BottomLeft);
}
private void OnAddParameterItemClicked(ItemsListContextMenu.Item item)
{
var type = (ScriptType)item.Tag;
var window = (IVisjectSurfaceWindow)Values[0];
var asset = window?.VisjectAsset;
if (asset == null || !asset.IsLoaded)
return;
var action = new AddRemoveParamAction
{
Window = window,
IsAdd = true,
Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)),
Type = type,
Index = window.VisjectSurface.Parameters.Count,
};
window.VisjectSurface.Undo.AddAction(action);
action.Do();
}
private DragData OnDragParameter(DraggablePropertyNameLabel label)
{
var window = (IVisjectSurfaceWindow)Values[0];
var parameter = window.VisjectSurface.Parameters[(int)label.Tag];
return DragNames.GetDragData(SurfaceParameter.DragPrefix, parameter.Name);
}
private void OnPropertyLabelSetupContextMenu(PropertyNameLabel label, FlaxEditor.GUI.ContextMenu.ContextMenu menu, CustomEditor linkedEditor)
{
var index = (int)label.Tag;
menu.AddSeparator();
menu.AddButton("Rename", () => StartParameterRenaming(index, label));
menu.AddButton("Edit attributes...", () => EditAttributesParameter(index, label));
menu.AddButton("Delete", () => DeleteParameter(index));
OnParamContextMenu(index, menu);
}
private void StartParameterRenaming(int index, Control label)
{
var window = (IVisjectSurfaceWindow)Values[0];
var parameter = window.VisjectSurface.Parameters[(int)label.Tag];
var dialog = RenamePopup.Show(label, new Rectangle(0, 0, label.Width - 2, label.Height), parameter.Name, false);
dialog.Tag = index;
dialog.Validate += OnParameterRenameValidate;
dialog.Renamed += OnParameterRenamed;
}
private bool OnParameterRenameValidate(RenamePopup popup, string value)
{
var window = (IVisjectSurfaceWindow)Values[0];
return !string.IsNullOrWhiteSpace(value) && window.VisjectSurface.Parameters.All(x => x.Name != value);
}
private void OnParameterRenamed(RenamePopup renamePopup)
{
var window = (IVisjectSurfaceWindow)Values[0];
var index = (int)renamePopup.Tag;
var action = new RenameParamAction
{
Window = window,
Index = index,
Before = window.VisjectSurface.Parameters[index].Name,
After = renamePopup.Text,
};
window.VisjectSurface.Undo.AddAction(action);
action.Do();
}
private void EditAttributesParameter(int index, Control label)
{
var window = (IVisjectSurfaceWindow)Values[0];
var attributes = window.VisjectSurface.Parameters[index].Meta.GetAttributes();
var editor = new AttributesEditor(attributes, NodeFactory.ParameterAttributeTypes);
editor.Edited += newValue =>
{
var action = new EditParamAttributesAction
{
Window = window,
Index = index,
Before = window.VisjectSurface.Parameters[index].Meta.GetAttributes(),
After = newValue,
};
window.VisjectSurface.Undo.AddAction(action);
action.Do();
};
editor.Show(label, label.Size * 0.5f);
}
private void DeleteParameter(int index)
{
var window = (IVisjectSurfaceWindow)Values[0];
var action = new AddRemoveParamAction
{
Window = window,
IsAdd = false,
Index = index,
};
window.VisjectSurface.Undo.AddAction(action);
action.Do();
}
///
/// Called to display additional context options for a parameter.
///
/// The zero-based parameter index.
/// The context menu.
protected virtual void OnParamContextMenu(int index, FlaxEditor.GUI.ContextMenu.ContextMenu menu)
{
menu.AddSeparator();
menu.AddButton("Find references...", () => OnFindReferences(index));
}
private void OnFindReferences(int index)
{
var window = (IVisjectSurfaceWindow)Values[0];
var param = window.VisjectSurface.Parameters[index];
Editor.Instance.ContentFinding.ShowSearch(window.VisjectSurface, '\"' + FlaxEngine.Json.JsonSerializer.GetStringID(param.ID) + '\"');
}
}
///
/// Dummy class to inject Normal Map parameter type for the material parameter adding picker.
///
[Tooltip("Texture asset contains a normal map that is stored on a GPU and is used during rendering graphics to implement normal mapping (aka bump mapping).")]
internal sealed class NormalMap
{
}
///
/// The base class for editor windows that use for content editing.
/// Note: it uses ClonedAssetEditorWindowBase which is creating cloned asset to edit/preview.
///
///
///
///
public abstract class VisjectSurfaceWindow : ClonedAssetEditorWindowBase, IVisjectSurfaceWindow
where TAsset : Asset
where TSurface : VisjectSurface
where TPreview : AssetPreview
{
///
/// The tab.
///
///
///
protected class Tab : FlaxEditor.GUI.Tabs.Tab
{
///
/// The presenter.
///
public CustomEditorPresenter Presenter;
///
/// Initializes a new instance of the class.
///
/// The tab title text.
/// The undo to use for the editing.
public Tab(string text, FlaxEditor.Undo undo = null)
: base(text)
{
var scrollPanel = new Panel(ScrollBars.Vertical)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
Parent = this
};
Presenter = new CustomEditorPresenter(undo, "Loading...");
Presenter.Panel.Parent = scrollPanel;
}
///
public override void OnDestroy()
{
Presenter.Deselect();
Presenter = null;
base.OnDestroy();
}
}
///
/// The primary split panel.
///
protected readonly SplitPanel _split1;
///
/// The secondary split panel.
///
protected readonly SplitPanel _split2;
///
/// The asset preview.
///
protected TPreview _preview;
///
/// The surface.
///
protected TSurface _surface;
///
/// The tabs control. Valid only if window is using tabs instead of just properties.
///
protected Tabs _tabs;
private readonly ToolStripButton _saveButton;
private readonly ToolStripButton _undoButton;
private readonly ToolStripButton _redoButton;
private bool _showWholeGraphOnLoad = true;
///
/// The properties editor.
///
protected CustomEditorPresenter _propertiesEditor;
///
/// True if temporary asset is dirty, otherwise false.
///
protected bool _tmpAssetIsDirty;
///
/// True if window is waiting for asset load to load surface.
///
protected bool _isWaitingForSurfaceLoad;
///
/// True if window is waiting for asset load to refresh properties editor.
///
protected bool _refreshPropertiesOnLoad;
///
/// True if parameter value has been changed (special path for handling modifying surface parameters in properties editor).
///
protected bool _paramValueChange;
///
/// The undo.
///
protected FlaxEditor.Undo _undo;
///
/// Gets the Visject Surface.
///
public TSurface Surface => _surface;
///
/// Gets the asset preview.
///
public TPreview Preview => _preview;
///
/// Gets the undo history context for this window.
///
public FlaxEditor.Undo Undo => _undo;
///
/// Initializes a new instance of the class.
///
/// The editor.
/// The item.
/// if set to true [use tabs].
protected VisjectSurfaceWindow(Editor editor, AssetItem item, bool useTabs = false)
: base(editor, item)
{
// Undo
_undo = new FlaxEditor.Undo();
_undo.UndoDone += OnUndoRedo;
_undo.RedoDone += OnUndoRedo;
_undo.ActionDone += OnUndoRedo;
// Split Panel 1
_split1 = new SplitPanel(Orientation.Horizontal, ScrollBars.None, ScrollBars.None)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = new Margin(0, 0, _toolstrip.Bottom, 0),
SplitterValue = 0.7f,
Parent = this
};
// Split Panel 2
_split2 = new SplitPanel(Orientation.Vertical, ScrollBars.None, ScrollBars.Vertical)
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
SplitterValue = 0.4f,
Parent = _split1.Panel2
};
// Properties editor
if (useTabs)
{
_tabs = new Tabs
{
AnchorPreset = AnchorPresets.StretchAll,
Offsets = Margin.Zero,
TabsSize = new Float2(60, 20),
TabsTextHorizontalAlignment = TextAlignment.Center,
UseScroll = true,
Parent = _split2.Panel2
};
var propertiesTab = new Tab("Properties", _undo);
_propertiesEditor = propertiesTab.Presenter;
_tabs.AddTab(propertiesTab);
}
else
{
_propertiesEditor = new CustomEditorPresenter(_undo, "Loading...");
_propertiesEditor.Panel.Parent = _split2.Panel2;
}
_propertiesEditor.Modified += OnPropertyEdited;
// Toolstrip
_saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddSeparator();
_undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
_redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolstrip.AddSeparator();
_toolstrip.AddButton(Editor.Icons.Search64, Editor.ContentFinding.ShowSearch).LinkTooltip("Open content search tool (Ctrl+F)");
_toolstrip.AddButton(editor.Icons.CenterView64, ShowWholeGraph).LinkTooltip("Show whole graph");
// Setup input actions
InputActions.Add(options => options.Undo, _undo.PerformUndo);
InputActions.Add(options => options.Redo, _undo.PerformRedo);
InputActions.Add(options => options.Search, Editor.ContentFinding.ShowSearch);
}
private void OnUndoRedo(IUndoAction action)
{
// Hack for emitter properties proxy object
if (action is MultiUndoAction multiUndo &&
multiUndo.Actions.Length == 1 &&
multiUndo.Actions[0] is UndoActionObject undoActionObject &&
undoActionObject.Target == _propertiesEditor.Selection[0])
{
OnPropertyEdited();
UpdateToolstrip();
return;
}
_paramValueChange = false;
MarkAsEdited();
UpdateToolstrip();
_propertiesEditor.BuildLayoutOnUpdate();
}
///
/// Called when the asset properties proxy object gets edited.
///
protected virtual void OnPropertyEdited()
{
_surface.MarkAsEdited(!_paramValueChange);
_paramValueChange = false;
}
///
/// Shows the whole surface graph.
///
public void ShowWholeGraph()
{
_surface.ShowWholeGraph();
}
///
/// Refreshes temporary asset to see changes live when editing the surface.
///
/// True if cannot refresh it, otherwise false.
public bool RefreshTempAsset()
{
// Early check
if (_asset == null || _isWaitingForSurfaceLoad)
return true;
// Check if surface has been edited
if (_surface.IsEdited)
{
return SaveSurface();
}
return false;
}
///
public override void Save()
{
if (!IsEdited)
return;
if (RefreshTempAsset())
{
return;
}
if (SaveToOriginal())
{
return;
}
ClearEditedFlag();
OnSurfaceEditedChanged();
_item.RefreshThumbnail();
}
///
protected override void UpdateToolstrip()
{
_saveButton.Enabled = IsEdited;
_undoButton.Enabled = _undo.CanUndo;
_redoButton.Enabled = _undo.CanRedo;
base.UpdateToolstrip();
}
///
protected override void UnlinkItem()
{
_isWaitingForSurfaceLoad = false;
base.UnlinkItem();
}
///
protected override void OnAssetLinked()
{
_isWaitingForSurfaceLoad = true;
_refreshPropertiesOnLoad = false;
base.OnAssetLinked();
}
///
public Asset SurfaceAsset => Asset;
///
public abstract string SurfaceName { get; }
///
public abstract byte[] SurfaceData { get; set; }
///
public VisjectSurfaceContext ParentContext => null;
///
public void OnContextCreated(VisjectSurfaceContext context)
{
}
///
public void OnSurfaceEditedChanged()
{
if (_surface.IsEdited)
MarkAsEdited();
}
///
public void OnSurfaceGraphEdited()
{
// Mark as dirty
_tmpAssetIsDirty = true;
}
///
public void OnSurfaceClose()
{
Close();
}
///
/// Called when surface gets loaded and user can edit it.
///
protected virtual void OnSurfaceEditingStart()
{
_undo.Clear();
_surface.Enabled = true;
_propertiesEditor.BuildLayout();
}
///
/// Loads the surface from the asset. Called during when asset is loaded and surface is missing.
///
/// True if failed, otherwise false.
protected abstract bool LoadSurface();
///
/// Saves the surface to the asset. Called during when asset is loaded and surface is missing.
///
/// True if failed, otherwise false.
protected abstract bool SaveSurface();
///
/// Gets a value indicating whether this window can edit asset surface on asset load error (eg. to fix asset loading issue due to graph problem).
///
protected virtual bool CanEditSurfaceOnAssetLoadError => false;
///
public override void Update(float deltaTime)
{
base.Update(deltaTime);
if (_tmpAssetIsDirty)
{
_tmpAssetIsDirty = false;
RefreshTempAsset();
}
if (_isWaitingForSurfaceLoad && (_asset.IsLoaded || (CanEditSurfaceOnAssetLoadError && _asset.LastLoadFailed)))
{
_isWaitingForSurfaceLoad = false;
if (!_asset.IsLoaded)
{
Editor.LogWarning("Loading surface for asset that is not loaded: " + OriginalAsset);
}
if (LoadSurface())
{
Close();
return;
}
OnSurfaceEditingStart();
ClearEditedFlag();
if (_showWholeGraphOnLoad)
{
_showWholeGraphOnLoad = false;
_surface.ShowWholeGraph();
}
SurfaceLoaded?.Invoke();
}
else if (_refreshPropertiesOnLoad && _asset.IsLoaded)
{
_refreshPropertiesOnLoad = false;
_propertiesEditor.BuildLayout();
}
}
///
public override bool UseLayoutData => true;
///
public override void OnLayoutSerialize(XmlWriter writer)
{
LayoutSerializeSplitter(writer, "Split1", _split1);
LayoutSerializeSplitter(writer, "Split2", _split2);
}
///
public override void OnLayoutDeserialize(XmlElement node)
{
LayoutDeserializeSplitter(node, "Split1", _split1);
LayoutDeserializeSplitter(node, "Split2", _split2);
}
///
public override void OnLayoutDeserialize()
{
_split1.SplitterValue = 0.7f;
_split2.SplitterValue = 0.4f;
}
///
public override void OnDestroy()
{
_undo.Enabled = false;
_propertiesEditor.Deselect();
_undo.Clear();
base.OnDestroy();
}
///
public abstract IEnumerable NewParameterTypes { get; }
///
public event Action SurfaceLoaded;
///
public virtual void OnParamRenameUndo()
{
}
///
public virtual void OnParamEditAttributesUndo()
{
_propertiesEditor.BuildLayout();
}
///
public virtual void OnParamAddUndo()
{
_refreshPropertiesOnLoad = true;
}
///
public virtual void OnParamRemoveUndo()
{
_refreshPropertiesOnLoad = true;
//_propertiesEditor.BuildLayoutOnUpdate();
_propertiesEditor.BuildLayout();
}
///
public object GetParameter(int index)
{
var param = Surface.Parameters[index];
return param.Value;
}
///
public virtual void SetParameter(int index, object value)
{
var param = Surface.Parameters[index];
param.Value = value;
_paramValueChange = true;
}
///
public Asset VisjectAsset => Asset;
///
public VisjectSurface VisjectSurface => _surface;
}
}