Files
FlaxEngine/Source/Editor/Windows/Profiler/SingleChart.cs
Luke Schneider ad28a3fdbf Better light theme (Style) support, and a Default light theme (as a secondary option)
1) Added ForegroundViewport as a new color.  It is used in the main game viewport (ViewportWidgetButton), and the viewport for rendering of particles and materials.  It is needed because the default foreground in a Light theme is black, but black does not work well in a viewport.  A new color seemed appropriate.

2) Fixed the profiler window to use the Foreground color in multiple text elements, instead of Color.White (or no default TitleColor).  This includes  the Row class, Asset class, SingleChart class, Timeline Class, and more.

3) Added a second theme/Style (DefaultLight) to include with the engine.  It uses RGB float values because those were easier to transfer from the saved values that I had created (and they're easier for me to edit if necessary).  I tried to emulate how the Default theme is created/loaded/etc as closely as possible.
2023-09-27 21:54:34 -05:00

196 lines
6.5 KiB
C#

// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Windows.Profiler
{
/// <summary>
/// Draws simple chart.
/// </summary>
/// <seealso cref="FlaxEngine.GUI.Control" />
internal class SingleChart : Control
{
private const float TitleHeight = 20;
private const float PointsOffset = 4;
private readonly SamplesBuffer<float> _samples;
private string _sample;
private int _selectedSampleIndex = -1;
private bool _isSelecting;
/// <summary>
/// Gets or sets the chart title.
/// </summary>
public string Title { get; set; }
/// <summary>
/// Gets the index of the selected sample. Value -1 is used to indicate no selection (using the latest sample).
/// </summary>
public int SelectedSampleIndex
{
get => _selectedSampleIndex;
set
{
value = Mathf.Clamp(value, -1, _samples.Count - 1);
if (_selectedSampleIndex != value)
{
_selectedSampleIndex = value;
_sample = _samples.Count == 0 ? string.Empty : FormatSample(_samples.Get(_selectedSampleIndex));
SelectedSampleChanged?.Invoke(_selectedSampleIndex);
}
}
}
/// <summary>
/// Gets the selected sample value.
/// </summary>
public float SelectedSample => _samples.Get(_selectedSampleIndex);
/// <summary>
/// Occurs when selected sample gets changed.
/// </summary>
public event Action<int> SelectedSampleChanged;
/// <summary>
/// The handler function to format sample value for label text.
/// </summary>
public Func<float, string> FormatSample = (v) => v.ToString();
/// <summary>
/// Initializes a new instance of the <see cref="SingleChart"/> class.
/// </summary>
/// <param name="maxSamples">The maximum samples to collect.</param>
public SingleChart(int maxSamples = ProfilerMode.MaxSamples)
: base(0, 0, 100, 60 + TitleHeight)
{
_samples = new SamplesBuffer<float>(maxSamples);
_sample = string.Empty;
}
/// <summary>
/// Clears all the samples.
/// </summary>
public void Clear()
{
_samples.Clear();
_sample = string.Empty;
}
/// <summary>
/// Adds the sample value.
/// </summary>
/// <param name="value">The value.</param>
public void AddSample(float value)
{
_samples.Add(value);
_sample = FormatSample(value);
}
/// <inheritdoc />
public override void Draw()
{
base.Draw();
var style = Style.Current;
float chartHeight = Height - TitleHeight;
// Draw chart
if (_samples.Count > 0)
{
var chartRect = new Rectangle(0, 0, Width, chartHeight);
Render2D.PushClip(ref chartRect);
if (_selectedSampleIndex != -1)
{
float selectedX = Width - (_samples.Count - _selectedSampleIndex - 1) * PointsOffset;
Render2D.DrawLine(new Float2(selectedX, 0), new Float2(selectedX, chartHeight), Style.Current.Foreground, 1.5f);
}
int samplesInViewCount = Math.Min((int)(Width / PointsOffset), _samples.Count) - 1;
float maxValue = _samples[_samples.Count - 1];
for (int i = 2; i < samplesInViewCount; i++)
{
maxValue = Mathf.Max(maxValue, _samples[_samples.Count - i]);
}
Color chartColor = style.BackgroundSelected;
var chartRoot = chartRect.BottomRight;
float samplesRange = maxValue * 1.1f;
float samplesCoeff = -chartHeight / samplesRange;
var posPrev = chartRoot + new Float2(0, _samples.Last * samplesCoeff);
float posX = 0;
for (int i = _samples.Count - 1; i >= 0; i--)
{
float sample = _samples[i];
var pos = chartRoot + new Float2(posX, sample * samplesCoeff);
Render2D.DrawLine(posPrev, pos, chartColor);
posPrev = pos;
posX -= PointsOffset;
}
Render2D.PopClip();
}
// Draw title
var headerRect = new Rectangle(0, chartHeight, Width, TitleHeight);
var headerTextRect = new Rectangle(2, chartHeight, Width - 4, TitleHeight);
Render2D.FillRectangle(headerRect, style.BackgroundNormal);
Render2D.DrawText(style.FontMedium, Title, headerTextRect, Style.Current.ForegroundGrey, TextAlignment.Near, TextAlignment.Center);
Render2D.DrawText(style.FontMedium, _sample, headerTextRect, Style.Current.Foreground, TextAlignment.Far, TextAlignment.Center);
}
private void OnClick(ref Float2 location)
{
float samplesWidth = _samples.Count * PointsOffset;
SelectedSampleIndex = (int)((samplesWidth - Width + location.X) / PointsOffset);
}
/// <inheritdoc />
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && location.Y < (Height - TitleHeight))
{
_isSelecting = true;
OnClick(ref location);
StartMouseCapture();
return true;
}
return base.OnMouseDown(location, button);
}
/// <inheritdoc />
public override void OnMouseMove(Float2 location)
{
if (_isSelecting)
{
OnClick(ref location);
}
base.OnMouseMove(location);
}
/// <inheritdoc />
public override bool OnMouseUp(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _isSelecting)
{
_isSelecting = false;
EndMouseCapture();
return true;
}
return base.OnMouseUp(location, button);
}
/// <inheritdoc />
public override void OnEndMouseCapture()
{
_isSelecting = false;
}
}
}