maint: added livewatch asset

This commit is contained in:
Chris
2025-08-31 18:14:07 -04:00
parent 7f5d95787b
commit ae2371a6fa
385 changed files with 150792 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Ingvar.LiveWatch.Editor
{
public static class AssetExtensions
{
public static IEnumerable<T> FindAssetsByType<T>() where T : Object
{
var guids = AssetDatabase.FindAssets($"t:{typeof(T)}");
foreach (var guid in guids)
{
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
var asset = AssetDatabase.LoadAssetAtPath<T>(assetPath);
if (asset != null)
{
yield return asset;
}
}
}
public static void SaveAndRefresh(Object asset)
{
EditorUtility.SetDirty(asset);
AssetDatabase.SaveAssetIfDirty(asset);
AssetDatabase.Refresh();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 727b5540f1294567b2d7b4d379f0a531
timeCreated: 1686934776
AssetOrigin:
serializedVersion: 1
productId: 324001
packageName: LiveWatch Lite | Debug with full history of changes
packageVersion: 1.0.1
assetPath: Assets/LiveWatchLite/Scripts/Editor/Utilities/AssetExtensions.cs
uploadId: 770587

View File

@@ -0,0 +1,71 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Ingvar.LiveWatch.Editor
{
public abstract class EditorProperty<T>
{
public string Key { get; }
public T Value
{
get => value;
set
{
if (IsEqual(this.value, value))
return;
this.value = value;
Save(value);
}
}
public EditorPropertyDrawer<T> PropertyDrawer
{
get
{
if (propertyDrawer != null)
return propertyDrawer;
propertyDrawer = GetDrawer();
return propertyDrawer;
}
}
private T value;
private readonly T defaultValue;
private EditorPropertyDrawer<T> propertyDrawer;
public EditorProperty(string key, T defaultValue)
{
this.defaultValue = defaultValue;
Key = key;
value = EditorPrefs.HasKey(key) ? Load() : defaultValue;
}
public void SetToDefault()
{
Value = defaultValue;
}
protected abstract bool IsEqual(T left, T right);
protected abstract T Load();
protected abstract void Save(T value);
protected abstract EditorPropertyDrawer<T> GetDrawer();
public static implicit operator T(EditorProperty<T> p) => p.Value;
}
public abstract class EditorPropertyDrawer<T>
{
protected EditorProperty<T> Property { get; }
public EditorPropertyDrawer(EditorProperty<T> property)
{
Property = property;
}
public abstract void Draw(params GUILayoutOption[] options);
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 9276ecf1d7404d54b0906d24bd5dd03f
timeCreated: 1724871250
AssetOrigin:
serializedVersion: 1
productId: 324001
packageName: LiveWatch Lite | Debug with full history of changes
packageVersion: 1.0.1
assetPath: Assets/LiveWatchLite/Scripts/Editor/Utilities/EditorProperty.cs
uploadId: 770587

View File

@@ -0,0 +1,34 @@
using UnityEditor;
using UnityEngine;
namespace Ingvar.LiveWatch.Editor
{
public static class GUIExtensions
{
public static void DrawSelectionFrame(Rect rect, int density = 2)
{
if (Event.current.type != EventType.Repaint)
{
return;
}
Styles.ElementBackground.Draw(rect.CropFromStartToPosition(CropEdge.LeftLocal, density), false, true, true, true);
Styles.ElementBackground.Draw(rect.CropFromStartToPosition(CropEdge.TopLocal, density), false, true, true, true);
Styles.ElementBackground.Draw(rect.CropFromStartToPosition(CropEdge.RightLocal, density), false, true, true, true);
Styles.ElementBackground.Draw(rect.CropFromStartToPosition(CropEdge.BottomLocal, density), false, true, true, true);
}
public static void DrawColorFrame(Rect rect, Color color, int density = 2)
{
if (Event.current.type != EventType.Repaint)
{
return;
}
EditorGUI.DrawRect(rect.CropFromStartToPosition(CropEdge.LeftLocal, density), color);
EditorGUI.DrawRect(rect.CropFromStartToPosition(CropEdge.TopLocal, density), color);
EditorGUI.DrawRect(rect.CropFromStartToPosition(CropEdge.RightLocal, density), color);
EditorGUI.DrawRect(rect.CropFromStartToPosition(CropEdge.BottomLocal, density), color);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: b5c9bb7e96fc4d03be73970eeea90597
timeCreated: 1684672374
AssetOrigin:
serializedVersion: 1
productId: 324001
packageName: LiveWatch Lite | Debug with full history of changes
packageVersion: 1.0.1
assetPath: Assets/LiveWatchLite/Scripts/Editor/Utilities/GUIExtensions.cs
uploadId: 770587

View File

@@ -0,0 +1,307 @@
using System;
using UnityEngine;
namespace Ingvar.LiveWatch.Editor
{
public enum CropEdge
{
LeftLocal = 1,
RightLocal = 2,
TopLocal = 3,
BottomLocal = 4,
HorizontalGlobal = 5,
VerticalGlobal = 6
}
public enum WidthSetSpace
{
Left = 0,
Center = 1,
Right = 2
}
public enum HeightSetSpace
{
Top = 0,
Center = 1,
Bottom = 2
}
[Flags]
public enum ExtrudeFlags
{
Left = 1 << 1,
Right = 1 << 2,
Top = 1 << 3,
Bottom = 1 << 4,
None = 0,
All = ~None
}
public static class RectExtensions
{
#region Offset
public static Rect Offset(this Rect rect, float xDelta, float yDelta, float widthDelta, float heightDelta)
{
return new Rect(rect.x + xDelta, rect.y + yDelta, rect.width + widthDelta, rect.height + heightDelta);
}
public static Rect OffsetByX(this Rect rect, float xDelta)
{
return new Rect(rect.x + xDelta, rect.y, rect.width, rect.height);
}
public static Rect OffsetByY(this Rect rect, float yDelta)
{
return new Rect(rect.x, rect.y + yDelta, rect.width, rect.height);
}
public static Rect OffsetByWidth(this Rect rect, float widthDelta)
{
return new Rect(rect.x, rect.y, rect.width + widthDelta, rect.height);
}
public static Rect OffsetByHeight(this Rect rect, float heightDelta)
{
return new Rect(rect.x, rect.y, rect.width, rect.height + heightDelta);
}
#endregion
#region Extrude
public static Rect Extrude(this Rect rect, ExtrudeFlags flags, float size)
{
var xMin = rect.xMin;
var xMax = rect.xMax;
var yMin = rect.yMin;
var yMax = rect.yMax;
if ((flags & ExtrudeFlags.Left) == ExtrudeFlags.Left)
xMin -= size;
if ((flags & ExtrudeFlags.Right) == ExtrudeFlags.Right)
xMax += size;
if ((flags & ExtrudeFlags.Top) == ExtrudeFlags.Top)
yMin -= size;
if ((flags & ExtrudeFlags.Bottom) == ExtrudeFlags.Bottom)
yMax += size;
return Rect.MinMaxRect(xMin, yMin, xMax, yMax);
}
#endregion
#region Set
public static Rect SetX(this Rect rect, float x)
{
return new Rect(x, rect.y, rect.width, rect.height);
}
public static Rect SetY(this Rect rect, float y)
{
return new Rect(rect.x, y, rect.width, rect.height);
}
public static Rect SetWidth(this Rect rect, float width, WidthSetSpace setSpace = WidthSetSpace.Left)
{
switch (setSpace)
{
case WidthSetSpace.Left:
return new Rect(rect.x, rect.y, width, rect.height);
case WidthSetSpace.Center:
return new Rect(rect.center.x - width/2, rect.y, width, rect.height);
case WidthSetSpace.Right:
return new Rect(rect.xMax - width, rect.y, width, rect.height);
default:
throw new ArgumentOutOfRangeException(nameof(setSpace), setSpace, null);
}
}
public static Rect SetHeight(this Rect rect, float height, HeightSetSpace setSpace = HeightSetSpace.Top)
{
switch (setSpace)
{
case HeightSetSpace.Top:
return new Rect(rect.x, rect.y, rect.width, height);
case HeightSetSpace.Center:
return new Rect(rect.x, rect.center.y - height / 2, rect.width, height);
case HeightSetSpace.Bottom:
return new Rect(rect.x, rect.yMax - height, rect.width, height);
default:
throw new ArgumentOutOfRangeException(nameof(setSpace), setSpace, null);
}
}
#endregion
#region TakeEdge
public static Rect CropFromStartToPosition(this Rect rect, CropEdge crop, float position)
{
switch (crop)
{
case CropEdge.LeftLocal:
return new Rect(rect.x, rect.y, position, rect.height);
case CropEdge.RightLocal:
return new Rect(rect.xMax - position, rect.y, position, rect.height);
case CropEdge.TopLocal:
return new Rect(rect.x, rect.y, rect.width, position);
case CropEdge.BottomLocal:
return new Rect(rect.x, rect.yMax - position, rect.width, position);
case CropEdge.HorizontalGlobal:
return new Rect(rect.x, rect.y, position - rect.x, rect.height);
case CropEdge.VerticalGlobal:
return new Rect(rect.x, rect.y, rect.width, position - rect.y);
default:
throw new ArgumentOutOfRangeException(nameof(crop), crop, null);
}
}
public static Rect CropFromPositionToEnd(this Rect rect, CropEdge crop, float position)
{
switch (crop)
{
case CropEdge.LeftLocal:
return new Rect(rect.x + position, rect.y, rect.width - position, rect.height);
case CropEdge.RightLocal:
return new Rect(rect.x, rect.y, rect.width - position, rect.height);
case CropEdge.TopLocal:
return new Rect(rect.x, rect.y + position, rect.width, rect.height - position);
case CropEdge.BottomLocal:
return new Rect(rect.x, rect.y, rect.width, rect.height - position);
case CropEdge.HorizontalGlobal:
return new Rect(position, rect.y, rect.xMax - position, rect.height);
case CropEdge.VerticalGlobal:
return new Rect(rect.x, position, rect.width, rect.yMax - position);
default:
throw new ArgumentOutOfRangeException(nameof(crop), crop, null);
}
}
public static Rect CropFromPositionWithSize(this Rect rect, CropEdge crop, float position, float size)
{
switch (crop)
{
case CropEdge.LeftLocal:
return new Rect(rect.x + position, rect.y, size, rect.height);
case CropEdge.RightLocal:
return new Rect(rect.xMax - position - size, rect.y, size, rect.height);
case CropEdge.TopLocal:
return new Rect(rect.x, rect.y + position, rect.width, size);
case CropEdge.BottomLocal:
return new Rect(rect.x, rect.yMax - position - size, rect.width, size);
case CropEdge.HorizontalGlobal:
return new Rect(position, rect.y, size, rect.height);
case CropEdge.VerticalGlobal:
return new Rect(rect.x, position, rect.width, size);
default:
throw new ArgumentOutOfRangeException(nameof(crop), crop, null);
}
}
public static Rect CropFromPositionToPosition(this Rect rect, CropEdge crop, float positionStart, float positionEnd)
{
switch (crop)
{
case CropEdge.LeftLocal:
return new Rect(rect.x + positionStart, rect.y, positionEnd - positionStart, rect.height);
case CropEdge.RightLocal:
return new Rect(rect.xMax - positionEnd, rect.y, positionEnd - positionStart, rect.height);
case CropEdge.TopLocal:
return new Rect(rect.x, rect.y + positionStart, rect.width, positionEnd - positionStart);
case CropEdge.BottomLocal:
return new Rect(rect.x, rect.yMax - positionEnd, rect.width, positionEnd - positionStart);
case CropEdge.HorizontalGlobal:
return new Rect(positionStart, rect.y, positionEnd - positionStart, rect.height);
case CropEdge.VerticalGlobal:
return new Rect(rect.x, positionStart, rect.width, positionEnd - positionStart);
default:
throw new ArgumentOutOfRangeException(nameof(crop), crop, null);
}
}
#endregion
#region Clamp
public static float ClampPositionX(this Rect rect, float xPosition)
{
return Mathf.Clamp(xPosition, rect.xMin, rect.xMax);
}
public static float ClampPositionY(this Rect rect, float yPosition)
{
return Mathf.Clamp(yPosition, rect.yMin, rect.yMax);
}
public static Vector2 ClampPosition(this Rect rect, Vector2 position)
{
return new Vector2(rect.ClampPositionX(position.x), rect.ClampPositionY(position.y));
}
#endregion
public static Rect FitInRect(this Rect rect, Rect rectToFitIn)
{
return Rect.MinMaxRect(
Mathf.Max(rect.xMin, rectToFitIn.xMin),
Mathf.Max(rect.yMin, rectToFitIn.yMin),
Mathf.Min(rect.xMax, rectToFitIn.xMax),
Mathf.Min(rect.yMax, rectToFitIn.yMax));
}
public static Rect RelativeToOther(this Rect rect, Rect otherRect)
{
return new Rect(
rect.x - otherRect.x,
rect.y - otherRect.y,
rect.width,
rect.height);
}
public static RectInt ToRectInt(this Rect rect)
{
return new RectInt(
Mathf.RoundToInt(rect.x),
Mathf.RoundToInt(rect.y),
Mathf.RoundToInt(rect.width),
Mathf.RoundToInt(rect.height));
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 35b0bc8d29614c17a7195521d142a91b
timeCreated: 1637089732
AssetOrigin:
serializedVersion: 1
productId: 324001
packageName: LiveWatch Lite | Debug with full history of changes
packageVersion: 1.0.1
assetPath: Assets/LiveWatchLite/Scripts/Editor/Utilities/RectExtensions.cs
uploadId: 770587

View File

@@ -0,0 +1,88 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Ingvar.LiveWatch.Editor
{
[Serializable]
public class ResizerGUI
{
public bool IsHorizontal;
public float HandleSize = 8;
public float LineSize = 1;
public Color LineColor = Color.black;
public Rect LocalArea;
public float NormPosition;
public float Position => GetPositionFromNorm(NormPosition);
public bool IsResizing { get; private set; }
public ResizerGUI(bool isHorizontal, float handleSize, float lineSize, Color lineColor, float normaPosition = 0)
{
IsHorizontal = isHorizontal;
HandleSize = handleSize;
LineSize = lineSize;
LineColor = lineColor;
NormPosition = normaPosition;
}
public void ProcessHandle()
{
var controlId = GUIUtility.GetControlID(FocusType.Passive);
var resizerControlRect = LocalArea.CropFromPositionWithSize(
IsHorizontal ? CropEdge.VerticalGlobal : CropEdge.HorizontalGlobal,
Position - HandleSize / 2,
HandleSize);
EditorGUIUtility.AddCursorRect(resizerControlRect, IsHorizontal ? MouseCursor.ResizeVertical : MouseCursor.ResizeHorizontal, controlId);
if (Event.current.type == EventType.MouseDown
&& Event.current.button == 0
&& resizerControlRect.Contains(Event.current.mousePosition))
{
IsResizing = true;
GUIUtility.hotControl = controlId;
Event.current.Use();
}
if (IsResizing && Event.current.type == EventType.Layout)
{
var previousNormPos = NormPosition;
NormPosition = GetNormFromPosition(IsHorizontal ? Event.current.mousePosition.y : Event.current.mousePosition.x);
if (Mathf.Abs(NormPosition - previousNormPos) > 0.0001f)
GUI.changed = true;
}
if (Event.current.GetTypeForControl(controlId) == EventType.MouseUp)
{
IsResizing = false;
}
}
public void DrawLine()
{
var resizerLineRect = LocalArea.CropFromPositionWithSize(
IsHorizontal ? CropEdge.VerticalGlobal : CropEdge.HorizontalGlobal,
Position - LineSize / 2,
LineSize);
EditorGUI.DrawRect(resizerLineRect, LineColor);
}
private float GetPositionFromNorm(float normPosition)
{
return IsHorizontal
? Mathf.Lerp(LocalArea.yMin, LocalArea.yMax, normPosition)
: Mathf.Lerp(LocalArea.xMin, LocalArea.xMax, normPosition);
}
private float GetNormFromPosition(float position)
{
return IsHorizontal
? Mathf.InverseLerp(LocalArea.yMin, LocalArea.yMax, position)
: Mathf.InverseLerp(LocalArea.xMin, LocalArea.xMax, position);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 18f1196977484d65b2374f25347869d2
timeCreated: 1644830319
AssetOrigin:
serializedVersion: 1
productId: 324001
packageName: LiveWatch Lite | Debug with full history of changes
packageVersion: 1.0.1
assetPath: Assets/LiveWatchLite/Scripts/Editor/Utilities/ResizerGUI.cs
uploadId: 770587

View File

@@ -0,0 +1,103 @@
using System;
using UnityEngine;
namespace Ingvar.LiveWatch.Editor
{
[Serializable]
public class ScrollbarGUI
{
public bool AllowStickToLast;
public bool IsHorizontal;
public Rect ScrollRect;
public float Size;
public float StartValue;
public float EndValue;
public float ScrollValue;
public float ScrollValueNormalized => EndValue - Size <= 0 ? 0 : ScrollValue / (EndValue - Size);
public bool IsStickingToLast { get; set; }
public ScrollbarGUI(bool isHorizontal)
{
IsHorizontal = isHorizontal;
IsStickingToLast = false;
}
public void Prepare(Rect scrollRect, float size, float startValue, float endValue)
{
ScrollRect = scrollRect;
Size = size;
StartValue = startValue;
EndValue = endValue;
}
public void DrawPlaceholder()
{
if (Event.current.type == EventType.Repaint)
{
var style = new GUIStyle(GUI.skin.horizontalScrollbar);
style.Draw(ScrollRect, false, false, false, false);
}
}
public void Draw()
{
if (EndValue <= Size)
{
ScrollValue = 0;
return;
}
if (IsStickingToLast)
ScrollValue = EndValue - Size;
var scrollValueBefore = ScrollValue;
ScrollValue = IsHorizontal
? GUI.HorizontalScrollbar(ScrollRect, ScrollValue, Size, StartValue, EndValue)
: GUI.VerticalScrollbar(ScrollRect, ScrollValue, Size, StartValue, EndValue);
var scrollValueAfter = ScrollValue;
if (AllowStickToLast && !IsStickingToLast && scrollValueBefore < scrollValueAfter &&
ScrollValueNormalized >= 0.99f)
{
IsStickingToLast = true;
}
else if (IsStickingToLast && scrollValueAfter < scrollValueBefore)
{
IsStickingToLast = false;
}
}
public void SetNormalizedPosition(float normPos, float normAnchor = 0.5f)
{
normPos = Mathf.Clamp01(normPos);
normAnchor = Mathf.Clamp01(normAnchor);
ScrollValue = Mathf.Lerp(StartValue, EndValue, normPos);
ScrollValue = Mathf.Clamp(ScrollValue - Size * normAnchor, 0, EndValue - Size);
}
public void ScrollToValue(float value, float normAnchor = 0.5f)
{
ScrollValue = Mathf.Clamp(
value - Mathf.Clamp01(normAnchor) * Size,
0,
EndValue - Size);
}
public void ResizeRelativeToPointer(float pointerPosition, float resizeFactor)
{
var normAnchor = IsHorizontal
? Mathf.InverseLerp(ScrollRect.xMin, ScrollRect.xMax, pointerPosition)
: Mathf.InverseLerp(ScrollRect.yMin, ScrollRect.yMax, pointerPosition);
var newScrollPos = resizeFactor * (ScrollValue + Size * normAnchor);
EndValue *= resizeFactor;
ScrollToValue(newScrollPos, normAnchor);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 511b306726d94ec89e2a370f56e86396
timeCreated: 1656676186
AssetOrigin:
serializedVersion: 1
productId: 324001
packageName: LiveWatch Lite | Debug with full history of changes
packageVersion: 1.0.1
assetPath: Assets/LiveWatchLite/Scripts/Editor/Utilities/ScrollbarGUI.cs
uploadId: 770587

View File

@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Ingvar.LiveWatch.Editor
{
[Serializable]
public class TextureDrawGUI
{
[SerializeField] private Texture2D _mainTexture;
private int _textureWidth;
private int _textureHeight;
private Rect _frameRect;
private Color[] _colorsArray = new Color[2048 * 2048];
public void Prepare(Rect frameRect)
{
_frameRect = frameRect;
_textureWidth = Mathf.CeilToInt(frameRect.width);
_textureHeight = Mathf.CeilToInt(frameRect.height);
if (_mainTexture == null)
{
_mainTexture = new Texture2D(_textureWidth, _textureHeight);
}
else if (_mainTexture.width != _textureWidth || _mainTexture.height != _textureHeight)
{
_mainTexture.Reinitialize(_textureWidth, _textureHeight);
_mainTexture.Apply(false);
}
}
public void DrawResult()
{
_mainTexture.Apply(false);
GUI.DrawTexture(_frameRect, _mainTexture);
}
public void DrawColorAll(Color color)
{
FillColorArray(_textureWidth * _textureHeight + 1, color);
_mainTexture.SetPixels(0, 0, _textureWidth, _textureHeight, _colorsArray);
}
public void DrawTestGraph(Color backColor, GraphPointInfo[] graphPoints, int pointsCount)
{
var pixelIndex = 0;
for (var y = 0; y < _textureHeight; y++)
{
for (var x = 0; x < _textureWidth; x++)
{
if (x >= pointsCount)
{
_colorsArray[pixelIndex++] = backColor;
continue;
}
var color = backColor;
var point = graphPoints[x];
if (point.IsEmpty)
{
_colorsArray[pixelIndex++] = color;
continue;
}
if (y <= 0)
{
color = point.BottomLineColor;
}
else if (y == point.PixelHeight || y == point.PixelHeight - 1)
{
if (point.WithLine)
color = point.TopLineColor;
}
else if (y < point.PixelHeight)
{
color = point.FillColor;
}
_colorsArray[pixelIndex++] = color;
}
}
_mainTexture.SetPixels(_colorsArray);
}
public void DrawColorRect(Rect rect, Color color)
{
var fitRect = rect.FitInRect(_frameRect);
if (fitRect.width <= 0 || fitRect.height <= 0)
return;
var drawRect = fitRect
.RelativeToOther(_frameRect)
.ToRectInt();
FillColorArray(drawRect.width * drawRect.height + 1, color);
_mainTexture.SetPixels(drawRect.x, drawRect.y, drawRect.width, drawRect.height, _colorsArray);
}
private void FillColorArray(int count, Color color)
{
if (_colorsArray.Length < count)
Array.Resize(ref _colorsArray, 2048*2048);
for (var i = 0; i < count; i++)
_colorsArray[i] = color;
}
public struct GraphPointInfo
{
public bool IsEmpty;
public bool WithLine;
public int PixelHeight;
public Color TopLineColor;
public Color BottomLineColor;
public Color FillColor;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f4c3ee7718d44610bafd7e0860d9ca06
timeCreated: 1715513207
AssetOrigin:
serializedVersion: 1
productId: 324001
packageName: LiveWatch Lite | Debug with full history of changes
packageVersion: 1.0.1
assetPath: Assets/LiveWatchLite/Scripts/Editor/Utilities/TextureDrawGUI.cs
uploadId: 770587