Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to paste from clipboard to various places #78

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions RuntimeUnityEditor/Features/ContextMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class ContextMenu : FeatureBase<ContextMenu>
{
private object _obj;
private MemberInfo _objMemberInfo;
private object _objMemberInstance;
private string _objName;

private Rect _windowRect;
Expand Down Expand Up @@ -80,6 +81,10 @@ protected override void Initialize(InitSettings initSettings)
if (Clipboard.ClipboardWindow.Contents.LastOrDefault() != o)
Clipboard.ClipboardWindow.Contents.Add(o);
}),
new MenuEntry("Paste from clipboard", o => _objMemberInfo != null && Clipboard.ClipboardWindow.Initialized && Clipboard.ClipboardWindow.Contents.Any(), o =>
{
Clipboard.ClipboardWindow.Instance.EnterPasteMode(o, _objMemberInfo, _objMemberInstance);
}),
//todo Paste from clipboard, kind of difficult

new MenuEntry("Export texture...",
Expand Down Expand Up @@ -164,26 +169,29 @@ o is Sprite ||
/// </summary>
/// <param name="obj">Object to show the menu for. Set to null to hide the menu.</param>
/// <param name="objMemberInfo">MemberInfo of wherever the object came from. Can be null.</param>
public void Show(object obj, MemberInfo objMemberInfo)
/// <param name="objMemberInstance">Instance of wherever the object came from. Can be null for static.</param>
public void Show(object obj, MemberInfo objMemberInfo, object objMemberInstance)
{
var m = UnityInput.Current.mousePosition;
Show(obj, objMemberInfo, new Vector2(m.x, Screen.height - m.y));
Show(obj, objMemberInfo, objMemberInstance, new Vector2(m.x, Screen.height - m.y));
}

/// <summary>
/// Show the context menu at a specific screen position.
/// </summary>
/// <param name="obj">Object to show the menu for. Set to null to hide the menu.</param>
/// <param name="objMemberInfo">MemberInfo of wherever the object came from. Can be null.</param>
/// <param name="objMemberInstance">Instance of wherever the object came from. Can be null for static.</param>
/// <param name="clickPoint">Screen position to show the menu at.</param>
public void Show(object obj, MemberInfo objMemberInfo, Vector2 clickPoint)
public void Show(object obj, MemberInfo objMemberInfo, object objMemberInstance, Vector2 clickPoint)
{
_windowRect = new Rect(clickPoint, new Vector2(100, 100));

if (obj != null)
{
_obj = obj;
_objMemberInfo = objMemberInfo;
_objMemberInstance = objMemberInstance;
_objName = objMemberInfo != null ? $"{objMemberInfo.DeclaringType?.Name}.{objMemberInfo.Name}" : obj.GetType().FullDescription();

_currentContents = MenuContents.Where(x => x.IsVisible(_obj)).ToList();
Expand All @@ -203,10 +211,10 @@ public void Show(object obj, MemberInfo objMemberInfo, Vector2 clickPoint)
/// <summary>
/// Draw a GUILayout button that opens the context menu when clicked. It's only shown if the object is not null.
/// </summary>
public void DrawContextButton(object obj, MemberInfo objMemberInfo)
public void DrawContextButton(object obj, MemberInfo objMemberInfo, object objMemberInstance)
{
if (obj != null && GUILayout.Button("...", GUILayout.ExpandWidth(false)))
Show(obj, objMemberInfo);
Show(obj, objMemberInfo, objMemberInstance);
}

/// <inheritdoc />
Expand Down
92 changes: 89 additions & 3 deletions RuntimeUnityEditor/Windows/Clipboard/ClipboardWindow.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using RuntimeUnityEditor.Core.Inspector;
using RuntimeUnityEditor.Core.Inspector.Entries;
using RuntimeUnityEditor.Core.Utils;
Expand All @@ -21,6 +22,11 @@ public class ClipboardWindow : Window<ClipboardWindow>
public static readonly List<object> Contents = new List<object>();
private Vector2 _scrollPos;

private string _pasteModeCurrentValueString;
private MemberInfo _pasteModeMemberInfo;
private object _pasteModeOwnerInstance;
public bool InPasteMode => _pasteModeMemberInfo != null;

protected override void Initialize(InitSettings initSettings)
{
Title = "Clipboard";
Expand All @@ -32,8 +38,12 @@ protected override void DrawContents()
{
_scrollPos = GUILayout.BeginScrollView(_scrollPos, false, true);

var inPasteMode = InPasteMode;

if (Contents.Count == 0)
{
if (inPasteMode) ExitPasteMode();

GUILayout.BeginVertical();
{
GUILayout.FlexibleSpace();
Expand All @@ -49,6 +59,14 @@ protected override void DrawContents()
// Draw clipboard items
GUILayout.BeginVertical();
{
if (inPasteMode)
{
GUILayout.BeginHorizontal();
GUILayout.Label($"Select which value to paste into {_pasteModeMemberInfo.GetFancyDescription()} (current value: {_pasteModeCurrentValueString ?? "NULL"})");
if (GUILayout.Button("Cancel")) ExitPasteMode();
GUILayout.EndHorizontal();
}

const int widthIndex = 35;
const int widthName = 70;

Expand All @@ -66,13 +84,23 @@ protected override void DrawContents()
{
var content = Contents[index];

if (GUILayout.Button(index.ToString(), GUI.skin.label, GUILayout.Width(widthIndex), GUILayout.ExpandWidth(false)) && IMGUIUtils.IsMouseRightClick())
ContextMenu.Instance.Show(content, null);
if (inPasteMode)
{
if (GUILayout.Button("Paste", GUILayout.Width(widthIndex), GUILayout.ExpandWidth(false)))
{
DoPaste(content);
}
}
else
{
if (GUILayout.Button(index.ToString(), GUI.skin.label, GUILayout.Width(widthIndex), GUILayout.ExpandWidth(false)) && IMGUIUtils.IsMouseRightClick())
ContextMenu.Instance.Show(content, null, null);
}

var type = content?.GetType();

if (GUILayout.Button(type?.Name ?? "NULL", GUI.skin.label, GUILayout.Width(widthName), GUILayout.ExpandWidth(false)) && IMGUIUtils.IsMouseRightClick())
ContextMenu.Instance.Show(content, null);
ContextMenu.Instance.Show(content, null, null);

var prevEnabled = GUI.enabled;
GUI.enabled = type != null && typeof(IConvertible).IsAssignableFrom(type);
Expand Down Expand Up @@ -103,5 +131,63 @@ protected override void DrawContents()

GUILayout.EndScrollView();
}

private void DoPaste(object content)
{
switch (_pasteModeMemberInfo)
{
case PropertyInfo propertyInfo:
propertyInfo.SetValue(_pasteModeOwnerInstance, content, null);
break;
case FieldInfo fieldInfo:
fieldInfo.SetValue(_pasteModeOwnerInstance, content);
break;
}

ExitPasteMode();
}

public void EnterPasteMode(object currentValue, MemberInfo memberInfo, object ownerInstance)
{
if (Contents.Count == 0 || memberInfo == null)
{
ExitPasteMode();
return;
}

switch (memberInfo)
{
case PropertyInfo propertyInfo:
if (!propertyInfo.CanWrite)
{
ExitPasteMode();
return;
}

break;
case FieldInfo fieldInfo:
if (fieldInfo.IsLiteral)
{
ExitPasteMode();
return;
}

break;
default:
ExitPasteMode();
return;
}

_pasteModeCurrentValueString = currentValue?.ToString() ?? "NULL";
_pasteModeMemberInfo = memberInfo;
_pasteModeOwnerInstance = ownerInstance;
}

public void ExitPasteMode()
{
_pasteModeCurrentValueString = null;
_pasteModeMemberInfo = null;
_pasteModeOwnerInstance = null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ public abstract class CacheEntryBase : ICacheEntry
// todo add gui option
public static bool CachingEnabled { get; set; } = false;

protected CacheEntryBase(string name, string description, Type owner = null)
protected CacheEntryBase(string name, string description, Type owner, object ownerInstance)
{
Owner = owner;
_name = name;
_nameContent = new GUIContent(_name, description + "\n\nLeft click to inspect in current tab\nMiddle click to inspect in a new tab\nRight click to open a menu with more options");
OwnerInstance = ownerInstance;
}

public GUIContent GetNameContent() => _nameContent;
Expand Down Expand Up @@ -48,6 +49,7 @@ public void SetValue(object newValue)
private readonly string _name;
private string _typeName;
public Type Owner { get; }
public object OwnerInstance { get; }

public string Name() => _name;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class CallbackCacheEntry : CacheEntryBase
private readonly string _message;
private readonly Action _callback;

public CallbackCacheEntry(string name, string message, Action callback) : base(name, "RUE Callback / Feature")
public CallbackCacheEntry(string name, string message, Action callback) : base(name, "RUE Callback / Feature", null, null)
{
_message = message;
_callback = callback ?? throw new ArgumentNullException(nameof(callback));
Expand Down Expand Up @@ -50,7 +50,7 @@ public class CallbackCacheEntry<T> : CacheEntryBase
private readonly string _message;
private readonly Func<T> _callback;

public CallbackCacheEntry(string name, string message, Func<T> callback) : base(name, "RUE Callback / Feature")
public CallbackCacheEntry(string name, string message, Func<T> callback) : base(name, "RUE Callback / Feature", null, null)
{
_message = message;
_callback = callback ?? throw new ArgumentNullException(nameof(callback));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ namespace RuntimeUnityEditor.Core.Inspector.Entries
{
public class EventCacheEntry : CacheEntryBase
{
public object Instance { get; }
[Obsolete]
public object Instance => OwnerInstance;
public EventInfo EventInfo { get; }
public EventCacheEntry(object ins, EventInfo e, Type owner) : base(FieldCacheEntry.GetMemberName(ins, e), e.GetFancyDescription(), owner)
public EventCacheEntry(object ownerInstance, EventInfo e, Type owner) : base(FieldCacheEntry.GetMemberName(ownerInstance, e), e.GetFancyDescription(), owner, ownerInstance)
{
if (owner == null) throw new ArgumentNullException(nameof(owner));
Instance = ins;
EventInfo = e ?? throw new ArgumentNullException(nameof(e));
BackingField = owner.GetField(e.Name, BindingFlags.NonPublic | (ins == null ? BindingFlags.Static : BindingFlags.Instance));
BackingField = owner.GetField(e.Name, BindingFlags.NonPublic | (ownerInstance == null ? BindingFlags.Static : BindingFlags.Instance));
}

public FieldInfo BackingField { get; }
public override bool CanEnterValue() => BackingField != null;
public override object GetValueToCache() => BackingField?.GetValue(Instance);
public override object GetValueToCache() => BackingField?.GetValue(OwnerInstance);
protected override bool OnSetValue(object newValue) => throw new InvalidOperationException();
public override Type Type() => EventInfo.EventHandlerType;
public override bool CanSetValue() => false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ namespace RuntimeUnityEditor.Core.Inspector.Entries
{
public class FieldCacheEntry : CacheEntryBase
{
public FieldCacheEntry(object ins, FieldInfo f, Type owner) : this(ins, f, owner, null) { }
public FieldCacheEntry(object ins, FieldInfo f, Type owner, ICacheEntry parent) : base(GetMemberName(ins, f), f.GetFancyDescription(), owner)
public FieldCacheEntry(object ins, FieldInfo f, Type owner, object ownerInstance) : this(ins, f, owner, ownerInstance, null) { }
public FieldCacheEntry(object ins, FieldInfo f, Type owner, object ownerInstance, ICacheEntry parent) : base(GetMemberName(ins, f), f.GetFancyDescription(), owner, ownerInstance)
{
_instance = ins;
FieldInfo = f ?? throw new ArgumentNullException(nameof(f));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ public interface ICacheEntry
/// </summary>
Type Owner { get; }
/// <summary>
/// Instance of type that owns this member.
/// </summary>
object OwnerInstance { get; }
/// <summary>
/// Get object that is entered when variable name is clicked in inspector
/// </summary>
object EnterValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class ListCacheEntry : CacheEntryBase
private readonly IList _list;
private readonly int _index;

public ListCacheEntry(IList container, int index) : base(ReadonlyListCacheEntry.GetListItemName(index), $"Item contained inside of a list.\n\nIndex: {index}\n\nList type: {container.GetType().FullDescription()}", null)
public ListCacheEntry(IList container, int index) : base(ReadonlyListCacheEntry.GetListItemName(index), $"Item contained inside of a list.\n\nIndex: {index}\n\nList type: {container.GetType().FullDescription()}", null, null)
{
_index = index;
_list = container;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ namespace RuntimeUnityEditor.Core.Inspector.Entries
{
public class MethodCacheEntry : ICacheEntry
{
public MethodCacheEntry(object instance, MethodInfo methodInfo, Type owner)
[Obsolete]
public object Instance => OwnerInstance;

public MethodCacheEntry(object ownerInstance, MethodInfo methodInfo, Type owner)
{
Instance = instance;
OwnerInstance = ownerInstance;
MethodInfo = methodInfo ?? throw new ArgumentNullException(nameof(methodInfo));
Owner = owner ?? throw new ArgumentNullException(nameof(owner));

_name = FieldCacheEntry.GetMemberName(instance, methodInfo);
_name = FieldCacheEntry.GetMemberName(ownerInstance, methodInfo);
_returnTypeName = MethodInfo.ReturnType.GetSourceCodeRepresentation();

ParameterString = GetParameterPreviewString(methodInfo);
Expand All @@ -35,7 +38,7 @@ internal static string GetParameterPreviewString(MethodBase methodInfo)
public MethodInfo MethodInfo { get; }
public bool IsDeclared => Owner == MethodInfo.DeclaringType;
public Type Owner { get; }
public object Instance { get; }
public object OwnerInstance { get; }
public string ParameterString { get; }
private readonly string _name;
private readonly string _returnTypeName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ namespace RuntimeUnityEditor.Core.Inspector.Entries
{
public class PropertyCacheEntry : CacheEntryBase
{
public PropertyCacheEntry(object ins, PropertyInfo p, Type owner) : this(ins, p, owner, null) { }
public PropertyCacheEntry(object ins, PropertyInfo p, Type owner, ICacheEntry parent) : base(FieldCacheEntry.GetMemberName(ins, p), p.GetFancyDescription(), owner)
public PropertyCacheEntry(object ins, PropertyInfo p, Type owner, object ownerInstance) : this(ins, p, owner,ownerInstance, null) { }
public PropertyCacheEntry(object ins, PropertyInfo p, Type owner, object ownerInstance, ICacheEntry parent) : base(FieldCacheEntry.GetMemberName(ins, p), p.GetFancyDescription(), owner, ownerInstance ?? parent.GetValue())
{
_instance = ins;
PropertyInfo = p ?? throw new ArgumentNullException(nameof(p));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class ReadonlyCacheEntry : CacheEntryBase
private readonly Type _type;
private string _tostringCache;

public ReadonlyCacheEntry(string name, object obj) : base(name, "Read-only item (RUE-only, it doesn't actually exist).")
public ReadonlyCacheEntry(string name, object obj) : base(name, "Read-only item (RUE-only, it doesn't actually exist).", null, null)
{
Object = obj;
_type = obj.GetType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public override bool EntryIsValid()

public override void ShowContextMenu()
{
ContextMenu.Instance.Show(Instance, Parent?.GetMemberInfo(false));
ContextMenu.Instance.Show(Instance, Parent?.GetMemberInfo(false), Parent?.GetValue());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public override bool EntryIsValid()

public override void ShowContextMenu()
{
ContextMenu.Instance.Show(StaticType, null);
ContextMenu.Instance.Show(StaticType, null, null);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,11 @@ private void CacheStaticMembersHelper(Type type)
{
_fieldCache.AddRange(type.GetAllFields(true)
.Where(f => !f.IsDefined(typeof(CompilerGeneratedAttribute), false))
.Select(f => new FieldCacheEntry(null, f, type)).Cast<ICacheEntry>());
.Select(f => new FieldCacheEntry(null, f, type, null)).Cast<ICacheEntry>());

_fieldCache.AddRange(type.GetAllProperties(true)
.Where(f => !f.IsDefined(typeof(CompilerGeneratedAttribute), false))
.Select(p => new PropertyCacheEntry(null, p, type)).Cast<ICacheEntry>());
.Select(p => new PropertyCacheEntry(null, p, type, null)).Cast<ICacheEntry>());

_fieldCache.AddRange(type.GetAllEvents(true)
.Where(f => !f.IsDefined(typeof(CompilerGeneratedAttribute), false))
Expand Down
2 changes: 1 addition & 1 deletion RuntimeUnityEditor/Windows/Inspector/Inspector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private void DrawVariableNameEnterButton(ICacheEntry field)
if (IMGUIUtils.IsMouseRightClick())
{
if (val != null)
ContextMenu.Instance.Show(val, field.GetMemberInfo(false));
ContextMenu.Instance.Show(val, field.GetMemberInfo(false), field.OwnerInstance);
}
else if (canEnterValue || val is Exception)
{
Expand Down
Loading