maint: added livewatch asset
This commit is contained in:
@@ -0,0 +1,396 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ingvar.LiveWatch.Editor
|
||||
{
|
||||
[Serializable]
|
||||
public class VariableGUI
|
||||
{
|
||||
public int Index { get; set; }
|
||||
public int IndentLevel { get; set; }
|
||||
public float LabelAreaWidth { get; set; }
|
||||
public float ValueColumnWidth { get; set; }
|
||||
public float ValueRowHeight { get; set; }
|
||||
public bool IsMouseDraggingOverValues { get; set; }
|
||||
public float HorizontalScrollValue { get; set; }
|
||||
public int SelectedColumnIndex { get; set; }
|
||||
public bool Search { get; set; }
|
||||
public bool Collapse { get; set; }
|
||||
public Rect VariablesTotalArea { get; set; }
|
||||
public int StartIndex { get; set; }
|
||||
public float RectOffset { get; set; }
|
||||
public List<int> IndicesToDisplay { get; set; }
|
||||
public int IndicesCount { get; set; }
|
||||
public bool IsSelected { get; set; }
|
||||
public VariableSelectedFitInfo SelectedFitInfo { get; set; }
|
||||
public bool PreferRightSelection { get; set; }
|
||||
public double MinValue { get; set; }
|
||||
public double MaxValue { get; set; }
|
||||
public bool IsNarrowMode => ValueColumnWidth <= 12;
|
||||
public VariableClickInfo ClickInfo => _clickInfo;
|
||||
|
||||
protected Color BackgroundColor => Index % 2 == 0 ? Colors.Background : Colors.BackgroundOdd;
|
||||
protected VariableCellGUI CellGUI
|
||||
{
|
||||
get { return _cellGUI ??= new VariableCellGUI(); }
|
||||
}
|
||||
protected VariableGraphGUI GraphGUI
|
||||
{
|
||||
get { return _graphGUI ??= new VariableGraphGUI(); }
|
||||
}
|
||||
|
||||
[SerializeField] private VariableCellGUI _cellGUI;
|
||||
[SerializeField] private VariableGraphGUI _graphGUI;
|
||||
|
||||
private WatchVariable _variable;
|
||||
private VariableClickInfo _clickInfo;
|
||||
private List<int> _segmentIndices = new(100);
|
||||
|
||||
public void Draw(Rect rect, WatchVariable variable)
|
||||
{
|
||||
_variable = variable;
|
||||
|
||||
_clickInfo = new VariableClickInfo()
|
||||
{
|
||||
CurrentPositionIndex = -1
|
||||
};
|
||||
|
||||
var valuesRect = rect.CropFromPositionToEnd(CropEdge.LeftLocal, LabelAreaWidth);
|
||||
|
||||
CellGUI.IsSelected = IsSelected;
|
||||
CellGUI.Variable = variable;
|
||||
CellGUI.SelectedColumnIndex = SelectedColumnIndex;
|
||||
CellGUI.IsNarrowMode = IsNarrowMode;
|
||||
CellGUI.ValueColumnWidth = ValueColumnWidth;
|
||||
CellGUI.ValuesRect = valuesRect;
|
||||
CellGUI.SelectedFitInfo = SelectedFitInfo;
|
||||
CellGUI.PreferRightSelection = PreferRightSelection;
|
||||
CellGUI.IndicesToDisplay = IndicesToDisplay;
|
||||
|
||||
ProcessRowEvents(rect);
|
||||
|
||||
DrawValuesBackground(valuesRect);
|
||||
DrawValues(valuesRect);
|
||||
|
||||
var labelBackgroundRect = rect.CropFromPositionToPosition(CropEdge.LeftLocal, 0, LabelAreaWidth);
|
||||
var labelRect = rect.CropFromPositionToPosition(CropEdge.LeftLocal,
|
||||
Constants.VariableLabelOffset + Constants.VariableLabelIndentWidth * IndentLevel, LabelAreaWidth);
|
||||
|
||||
DrawLabelBackground(labelBackgroundRect);
|
||||
ProcessLabelEvents(labelRect);
|
||||
DrawLabelContent(labelRect);
|
||||
DrawMinMaxForGraph(labelRect);
|
||||
|
||||
if (IsSelected && variable.HasValues)
|
||||
{
|
||||
GUIExtensions.DrawColorFrame(SelectedColumnIndex > 0 ? rect : labelBackgroundRect, Colors.CellSelectionLine, 3);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawLabelBackground(Rect rect)
|
||||
{
|
||||
EditorGUI.DrawRect(rect, BackgroundColor);
|
||||
}
|
||||
|
||||
#region Full row
|
||||
|
||||
private void ProcessRowEvents(Rect rect)
|
||||
{
|
||||
if (!VariablesTotalArea.Contains(Event.current.mousePosition)
|
||||
|| Event.current.type != EventType.MouseDown && GUIUtility.hotControl != 0)
|
||||
return;
|
||||
|
||||
GUIUtility.hotControl = 0;
|
||||
|
||||
if (rect.Contains(Event.current.mousePosition))
|
||||
{
|
||||
if (Event.current.isMouse && Event.current.button == 0)
|
||||
{
|
||||
_clickInfo.IsMouse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Label zone
|
||||
|
||||
private void ProcessLabelEvents(Rect rect)
|
||||
{
|
||||
if (!VariablesTotalArea.Contains(Event.current.mousePosition) || IsMouseDraggingOverValues)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (rect.Contains(Event.current.mousePosition))
|
||||
{
|
||||
_clickInfo.CurrentPositionIndex = -1;
|
||||
_clickInfo.IsOverTitleArea = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawLabelContent(Rect rect)
|
||||
{
|
||||
if (!_variable.HasChilds)
|
||||
{
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
DrawLabelWitchSearchResult(
|
||||
rect,
|
||||
_variable.Name,
|
||||
_variable.EditorMeta.SearchResult.NameResult,
|
||||
Styles.VariableLabel);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (Event.current.type == EventType.Layout || Event.current.type == EventType.Repaint || rect.Contains(Event.current.mousePosition))
|
||||
{
|
||||
_variable.EditorMeta.IsExpanded = EditorGUI.Foldout(
|
||||
rect,
|
||||
_variable.EditorMeta.IsExpanded,
|
||||
string.Empty,
|
||||
Styles.VariableFoldoutLabel);
|
||||
|
||||
if (Event.current.type == EventType.Used)
|
||||
_clickInfo.IsOverTitleArea = false;
|
||||
}
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
DrawLabelWitchSearchResult(
|
||||
rect.CropFromPositionToEnd(CropEdge.LeftLocal, 15),
|
||||
_variable.Name,
|
||||
_variable.EditorMeta.SearchResult.NameResult,
|
||||
Styles.VariableLabel);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMinMaxForGraph(Rect rect)
|
||||
{
|
||||
if (Event.current.type != EventType.Repaint
|
||||
|| _variable.Values.Type is WatchValueType.String or WatchValueType.Bool or WatchValueType.NotSet
|
||||
|| !IsNarrowMode
|
||||
|| ValueRowHeight < 38)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var maxValueRect = rect
|
||||
.CropFromPositionWithSize(CropEdge.TopLocal, 2 , Constants.VariableGraphMinValueHeight)
|
||||
.CropFromPositionToEnd(CropEdge.RightLocal, 2);
|
||||
|
||||
var minValueRect = rect
|
||||
.CropFromPositionWithSize(CropEdge.BottomLocal, 2, Constants.VariableGraphMinValueHeight)
|
||||
.CropFromPositionToEnd(CropEdge.RightLocal, 2);
|
||||
|
||||
GUI.Label(maxValueRect, Math.Round(MaxValue, _variable.RuntimeMeta.DecimalPlaces).ToString(), Styles.VariableGraphMaxLabel);
|
||||
GUI.Label(minValueRect, Math.Round(MinValue, _variable.RuntimeMeta.DecimalPlaces).ToString(), Styles.VariableGraphMinLabel);
|
||||
}
|
||||
|
||||
private void DrawLabelWitchSearchResult(Rect labelRect, string text, SearchQueryResult searchResult, GUIStyle style)
|
||||
{
|
||||
if (searchResult.IsPositive)
|
||||
{
|
||||
var charStartIndex = searchResult.IsWholeSelection ? 0 : searchResult.SelectionStartIndex;
|
||||
var charEndIndex = searchResult.IsWholeSelection ? text.Length : searchResult.SelectionEndIndex;
|
||||
|
||||
style.DrawWithTextSelection(
|
||||
labelRect,
|
||||
WatchEditorServices.GUICache.GetContent(text),
|
||||
-1,
|
||||
charStartIndex,
|
||||
charEndIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
style.Draw(labelRect, WatchEditorServices.GUICache.GetContent(text), 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Values zone
|
||||
|
||||
private void DrawValuesBackground(Rect rect)
|
||||
{
|
||||
if (Event.current.type is not EventType.Repaint)
|
||||
return;
|
||||
|
||||
EditorGUI.DrawRect(rect, BackgroundColor);
|
||||
}
|
||||
|
||||
private void DrawValues(Rect rect)
|
||||
{
|
||||
if (IndicesToDisplay.Count > 0
|
||||
&& (Event.current.type is EventType.MouseDown && VariablesTotalArea.Contains(Event.current.mousePosition)
|
||||
|| IsMouseDraggingOverValues)
|
||||
&& Event.current.isMouse
|
||||
&& Event.current.button == 0
|
||||
&& GUIUtility.hotControl == 0)
|
||||
{
|
||||
if (rect.Contains(Event.current.mousePosition))
|
||||
{
|
||||
var clickedValueIndex = (int)Mathf.Floor((Event.current.mousePosition.x - (rect.x + RectOffset)) / ValueColumnWidth);
|
||||
clickedValueIndex = Mathf.Clamp(clickedValueIndex, 0, IndicesToDisplay.Count - 1);
|
||||
|
||||
_clickInfo.IsMouse = true;
|
||||
_clickInfo.CurrentPositionIndex = IndicesToDisplay[clickedValueIndex];
|
||||
_clickInfo.MouseButton = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedIndex = 0;
|
||||
_clickInfo.CurrentPositionIndex = IndicesToDisplay[selectedIndex];
|
||||
}
|
||||
}
|
||||
|
||||
if (IndicesCount == 0 || Event.current.type != EventType.Repaint)
|
||||
{
|
||||
TryDrawSelectedCell();
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsNarrowMode)
|
||||
DrawValuesAsGraph();
|
||||
else
|
||||
DrawValuesAsCells();
|
||||
|
||||
TryDrawSelectedCell();
|
||||
|
||||
if (_variable.HasChilds && !_variable.EditorMeta.IsExpanded)
|
||||
{
|
||||
var previewRect = rect
|
||||
.CropFromPositionWithSize(CropEdge.LeftLocal, RectOffset, IndicesCount * ValueColumnWidth)
|
||||
.Extrude(ExtrudeFlags.Top | ExtrudeFlags.Bottom, -1);
|
||||
var drawRect = IsSelected ? previewRect.Extrude(ExtrudeFlags.Top | ExtrudeFlags.Bottom, -3) : previewRect;
|
||||
|
||||
WatchEditorServices.PreviewDrawer.Search = Search;
|
||||
WatchEditorServices.PreviewDrawer.DrawPreview(previewRect, drawRect, _variable, IndicesToDisplay, Mathf.CeilToInt(ValueColumnWidth));
|
||||
}
|
||||
|
||||
void DrawValuesAsGraph()
|
||||
{
|
||||
GraphGUI.RowIndex = Index;
|
||||
GraphGUI.Variable = _variable;
|
||||
GraphGUI.IndicesToDisplay = IndicesToDisplay;
|
||||
GraphGUI.StartIndex = StartIndex;
|
||||
GraphGUI.IndicesCount = IndicesCount;
|
||||
GraphGUI.MinValue = MinValue;
|
||||
GraphGUI.MaxValue = MaxValue;
|
||||
GraphGUI.ValueColumnWidth = ValueColumnWidth;
|
||||
GraphGUI.BackgroundColor = BackgroundColor;
|
||||
|
||||
var graphRect = rect.CropFromPositionWithSize(CropEdge.LeftLocal, RectOffset, IndicesCount * ValueColumnWidth);
|
||||
GraphGUI.DrawValues(graphRect);
|
||||
}
|
||||
|
||||
void DrawValuesAsCells()
|
||||
{
|
||||
_segmentIndices.Clear();
|
||||
var previousLocalIndex = 0;
|
||||
var previousKeyIndex = _variable.Values.GetOriginalKey(IndicesToDisplay[0]);
|
||||
|
||||
for (var localIndex = 0; localIndex < IndicesCount; localIndex++)
|
||||
{
|
||||
var key = IndicesToDisplay[localIndex];
|
||||
var keyIndex = _variable.Values.GetOriginalKey(key);
|
||||
|
||||
var isOriginal = localIndex != 0 && previousKeyIndex != keyIndex;
|
||||
|
||||
if (isOriginal)
|
||||
{
|
||||
previousKeyIndex = keyIndex;
|
||||
|
||||
DrawSegment(previousLocalIndex, localIndex - 1, _segmentIndices);
|
||||
previousLocalIndex = localIndex;
|
||||
_segmentIndices.Clear();
|
||||
}
|
||||
|
||||
_segmentIndices.Add(key);
|
||||
}
|
||||
|
||||
DrawSegment(previousLocalIndex, IndicesCount - 1, _segmentIndices);
|
||||
}
|
||||
|
||||
void TryDrawSelectedCell()
|
||||
{
|
||||
var isAnySelected = IndicesToDisplay.Contains(SelectedColumnIndex);
|
||||
|
||||
if (!isAnySelected)
|
||||
return;
|
||||
|
||||
var cellRect = rect.CropFromPositionWithSize(
|
||||
CropEdge.LeftLocal,
|
||||
RectOffset + IndicesToDisplay.IndexOf(SelectedColumnIndex) * ValueColumnWidth,
|
||||
ValueColumnWidth);
|
||||
|
||||
if (!_variable.Values.IsEmptyAt(SelectedColumnIndex) && SelectedColumnIndex < _variable.Values.Count)
|
||||
{
|
||||
CellGUI.DrawSelectedCell(cellRect, _variable.GetValueText(SelectedColumnIndex), SelectedColumnIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
CellGUI.DrawSelectedCelLine(cellRect);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSegment(int startLocalIndex, int endLocalIndex, List<int> contentIndices)
|
||||
{
|
||||
var valueIndex = contentIndices[0];
|
||||
var numberValue = _variable.GetValueNumber(valueIndex);
|
||||
|
||||
var segmentRect = rect.CropFromPositionWithSize(
|
||||
CropEdge.LeftLocal,
|
||||
RectOffset + startLocalIndex * ValueColumnWidth,
|
||||
ValueColumnWidth * (endLocalIndex - startLocalIndex + 1));
|
||||
|
||||
var progress = 0f;
|
||||
|
||||
if (!double.IsNaN(numberValue))
|
||||
{
|
||||
progress = (float)((MaxValue - MinValue) < 0.000001
|
||||
? 1
|
||||
: (numberValue - MinValue) / (MaxValue - MinValue));
|
||||
}
|
||||
|
||||
CellGUI.DrawValueCellSegment(
|
||||
segmentRect,
|
||||
_variable.GetValueText(valueIndex),
|
||||
contentIndices,
|
||||
(float)progress);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public struct VariableClickInfo
|
||||
{
|
||||
public bool IsMouse;
|
||||
public int MouseButton;
|
||||
public int CurrentPositionIndex;
|
||||
public bool IsOverTitleArea;
|
||||
}
|
||||
|
||||
public class VariableSelectedFitInfo
|
||||
{
|
||||
public bool CanFitLeft = true;
|
||||
public bool CanFitRight = true;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
CanFitLeft = true;
|
||||
CanFitRight = true;
|
||||
}
|
||||
|
||||
public void MergeWith(VariableSelectedFitInfo other)
|
||||
{
|
||||
CanFitLeft &= other.CanFitLeft;
|
||||
CanFitRight &= other.CanFitRight;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user