-
Notifications
You must be signed in to change notification settings - Fork 0
KeyHandler with a custom window
PostCyberPunk edited this page Sep 15, 2023
·
2 revisions
SVBMData.cs
using UnityEngine;
using PCP.WhichKey.Types;
using Unity.Mathematics;
using UnityEditor;
using System.Collections.Generic;
[System.Serializable]
public struct SVBMSet
{
public WkKeySeq Key;
public string Hint;
[SerializeReference]
public Texture2D Texture;
[HideInInspector]
public Vector3 Pos;
[HideInInspector]
public quaternion Rot;
[HideInInspector]
public bool Mode;
[HideInInspector]
public float Size;
public SVBMSet(int key, SceneView sv, Texture2D tex)
{
//wkkeyseq has implicit operator from int and int[],so we can use int directly
Key = key;
Hint = "Bookmark";
Pos = sv.pivot;
Rot = sv.rotation;
Size = sv.size;
Mode = sv.in2DMode;
Texture = tex;
}
}
public static class SVBMExtension
{
public static bool HasKey(this SVBMSet[] array, int key)
{
foreach (var set in array)
{
if (set.Key == key)
return true;
}
return false;
}
}
[CreateAssetMenu(fileName = "SVBMData", menuName = "WhichkeyDemo/SVBMData")]
public class SVBMData : ScriptableObject
{
public List<SVBMSet> mSVBMSets=new();
}
SVBMWin.cs
using System.Collections.Generic;
using UnityEngine.UIElements;
using PCP.WhichKey.Types;
using UnityEngine;
public class SVBMWin : WkBaseWindow
{
private readonly float itemWidth = 400;
private readonly float itemHeight = 200;
public List<SVBMSet> Bookmarks { get; set; }
protected override void ShowHints()
{
if (Bookmarks == null)
return;
rootVisualElement.style.flexDirection = FlexDirection.Row;
rootVisualElement.style.flexWrap = Wrap.Wrap;
rootVisualElement.style.backgroundColor = new Color(0.118f, 0.118f, 0.18f);
foreach (var set in Bookmarks)
{
var e = CreateItem(set.Key.KeyLabel, set.Hint, set.Texture);
rootVisualElement.Add(e);
}
// the size of the window is based on mHeight and mWidth
//
winWidth = 800;
winHeight = Mathf.CeilToInt(Bookmarks.Count / 2f) * itemHeight;
//You can use this method to make your window follow the Preferences
SetWindowPosition();
//alternatively,you can set the position manually
}
// you should use uxml or some custom controls for this.
private VisualElement CreateItem(string key, string hint, Texture2D tex)
{
var e = new VisualElement();
e.style.width = itemWidth;
e.style.height = itemHeight;
var keyl = new Label(key);
var img = new Image() { image = tex };
var hintl = new Label(hint);
hintl.style.fontSize = 20;
hintl.style.alignSelf = Align.Center;
keyl.style.fontSize = 40;
keyl.style.unityTextAlign = TextAnchor.MiddleCenter;
keyl.style.alignSelf = Align.Center;
keyl.style.color = new Color(0.651f, 0.89f, 0.631f);
keyl.style.backgroundColor = new Color(0, 0, 0, 0.5f);
img.style.flexGrow = 1;
img.style.justifyContent = Justify.Center;
img.Add(keyl);
e.Add(img);
e.Add(hintl);
return e;
}
}
SVBMHandler.cs
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using PCP.WhichKey.Types;
using System.Collections.Generic;
public class SVBMHandler : WindowKeyHandler<SVBMWin>
{
private SVBMData mSVBMDATA;
private List<SVBMSet> bookmarks => mSVBMDATA.mSVBMSets;
public bool Save { get; set; }
//!!!Minimal example,for demonstration only,this is a very BAD way to save Bookmarks
//you can use EditorPrefs or ScriptableObject to save data
//if you dont know how ,take a look at extra wkExtraManager.cs and SceneNav
//every project is different,there are many way to save bookmark data,even use mono script,you need find a way that fits your project
public SVBMHandler()
{
mSVBMDATA = AssetDatabase.LoadAssetAtPath<SVBMData>("Assets/SVBMData.asset");
if (mSVBMDATA == null)
{
AssetDatabase.CreateAsset(ScriptableObject.CreateInstance<SVBMData>(), "Assets/SVBMData.asset");
AssetDatabase.Refresh();
mSVBMDATA = AssetDatabase.LoadAssetAtPath<SVBMData>("Assets/SVBMData.asset");
}
}
//this method will be called before handler processing key,so we can assign data to window or reset some data
//HINT: whichkey use PopuuWindow,the window will be an new instance when you active this handler,so you need to assign window data here or use a static data.
public override void OnActive()
{
window.Bookmarks = bookmarks;
}
//the int key is ASCII code of the key pressed,there is some change,you can take a look at core/editor/utils/keycodeExtesnion.cs
public override void HandleKey(int key)
{
if (mSVBMDATA == null)
Debug.Log("SVBMData not found");
if (SceneView.lastActiveSceneView == null)
Debug.Log("No SceneView found");
else if (Save)
SaveBookmark(key);
else
LoadBookmark(key);
//!!You MUST close the window after everything is done!
//if want use a multi-layer handle,you can update your hints first ,then call window.UpdateHints() to notify window to update
window.Close();
}
private void LoadBookmark(int key)
{
foreach (SVBMSet set in bookmarks)
{
if (set.Key == key)
{
var sv = SceneView.lastActiveSceneView;
sv.in2DMode = set.Mode;
sv.pivot = set.Pos;
if (!set.Mode)
sv.rotation = set.Rot;
sv.size = set.Size;
return;
}
}
Debug.Log("No bookmark found");
}
private void SaveBookmark(int key)
{
for (int i = 0; i < bookmarks.Count; i++)
{
if (bookmarks[i].Key == key)
{
bookmarks[i] = new SVBMSet(key, SceneView.lastActiveSceneView, CreateThumbnail(key));
return;
}
}
bookmarks.Add(new SVBMSet(key, SceneView.lastActiveSceneView, CreateThumbnail(key)));
}
//an utils function to create thumbnail,
private Texture2D CreateThumbnail(int key)
{
var sv = SceneView.lastActiveSceneView;
//create texturea
sv.Show();
var rect = sv.position;
Texture2D tex = new((int)rect.width, (int)rect.height);
tex.SetPixels(InternalEditorUtility.ReadScreenPixel(new Vector2(rect.x, rect.y), tex.width, tex.height));
//save to sprite
var bytes = tex.EncodeToPNG();
var path = "Assets/WhichKeyDemo/" + key.ToString() + ".png";
System.IO.File.WriteAllBytes(path, bytes);
AssetDatabase.Refresh();
tex = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
return tex;
}
}
SVBMCmd.cs
using PCP.WhichKey.Types;
using UnityEngine;
public class SVBMCommand : ChangeWinHandlerCmd
{
//lets create a static handler for this command,because every factory will create a command object,we only need one handler
public static SVBMHandler handler = new SVBMHandler();
//assgin the handler to the command
public override BaseWinKeyHandler Handler => handler;
// add a bool so we can know if the bookmark is save or load
public bool Save;
//this method will be called before handler processing key
public override void OnActive()
{
handler.Save = Save;
}
}
public class SVBMCmdFactory : WKCommandFactory
{
//the id of this Factory, must be unique,this is the CmdType of keyset.
//since i may develop some addtinal commands,so lets start from 101
public override int TID => 101;
//the name of the command, the name that shows in Type Dropdown
public override string CommandName => "SceneViewBookMark";
//we dont need arg for this command,i mean you can set Commaand save or load by using arg,but lets keep arg empty in case we may need it later
//i will add some serialization later,so you can use multiple arg with defined type,stay tune for update notes
public override WKCommand CreateCommand(string arg)
{
return new SVBMCommand();
}
}
public class SVBMSaveCmdFactory : WKCommandFactory
{
//dont forget to change your factory id
public override int TID => 102;
public override string CommandName => "SceneViewBookMarkSave";
//in this command we set Save to true
public override WKCommand CreateCommand(string arg)
{
return new SVBMCommand() { Save = true };
}
}