396 lines
15 KiB
C#
396 lines
15 KiB
C#
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;
|
|
}
|
|
}
|
|
} |