2019-03-24 21:31:54 +00:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Windows;
|
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
using System.Windows.Data;
|
|
|
|
|
using System.Windows.Documents;
|
|
|
|
|
using System.Windows.Input;
|
|
|
|
|
using System.Windows.Media.Imaging;
|
|
|
|
|
using System.Windows.Navigation;
|
|
|
|
|
using System.Windows.Shapes;
|
|
|
|
|
using Profiler.Data;
|
|
|
|
|
using System.Windows.Media;
|
|
|
|
|
using System.Windows.Controls.Primitives;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using Profiler.DirectX;
|
|
|
|
|
using System.Windows.Threading;
|
2018-12-16 14:26:48 +00:00
|
|
|
using System.Diagnostics;
|
2019-02-24 22:24:12 +00:00
|
|
|
using Profiler.Controls;
|
2019-04-14 18:30:30 +01:00
|
|
|
using System.Threading.Tasks;
|
2018-12-16 14:26:48 +00:00
|
|
|
|
2020-02-05 20:51:54 +00:00
|
|
|
namespace Profiler.Controls
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
2019-03-24 21:31:54 +00:00
|
|
|
/// <summary>
|
|
|
|
|
/// Interaction logic for ThreadView.xaml
|
|
|
|
|
/// </summary>
|
2020-02-05 20:51:54 +00:00
|
|
|
public partial class ThreadViewControl : UserControl
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
public ThreadScroll Scroll { get; set; } = new ThreadScroll();
|
|
|
|
|
private List<ThreadRow> Rows = new List<ThreadRow>();
|
2018-10-07 21:00:14 +01:00
|
|
|
|
2020-02-11 03:23:46 +00:00
|
|
|
|
|
|
|
|
private SolidColorBrush _optickBackground;
|
|
|
|
|
public SolidColorBrush OptickBackground { get { if (_optickBackground == null) _optickBackground = FindResource("OptickBackground") as SolidColorBrush; return _optickBackground; } }
|
|
|
|
|
|
|
|
|
|
private SolidColorBrush _optickAlternativeBackground;
|
|
|
|
|
public SolidColorBrush OptickAlternativeBackground { get { if (_optickAlternativeBackground == null) _optickAlternativeBackground = FindResource("OptickAlternative") as SolidColorBrush; return _optickAlternativeBackground; } }
|
|
|
|
|
|
|
|
|
|
private SolidColorBrush _frameSelection;
|
|
|
|
|
public SolidColorBrush FrameSelection { get { if (_frameSelection == null) _frameSelection = FindResource("OptickFrameSelection") as SolidColorBrush; return _frameSelection; } }
|
|
|
|
|
|
|
|
|
|
private SolidColorBrush _frameHover;
|
|
|
|
|
public SolidColorBrush FrameHover { get { if (_frameHover == null) _frameHover = FindResource("OptickFrameHover") as SolidColorBrush; return _frameHover; } }
|
|
|
|
|
|
2018-10-18 19:25:33 +01:00
|
|
|
Color MeasureBackground;
|
|
|
|
|
Color HoverBackground;
|
2018-10-07 21:00:14 +01:00
|
|
|
|
2018-10-18 19:25:33 +01:00
|
|
|
|
|
|
|
|
void InitColors()
|
|
|
|
|
{
|
|
|
|
|
MeasureBackground = Color.FromArgb(100, 0, 0, 0);
|
|
|
|
|
HoverBackground = Color.FromArgb(170, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-04 00:06:27 +00:00
|
|
|
public bool ShowThreadHeaders { get; set; } = true;
|
2020-08-06 14:07:14 +02:00
|
|
|
public bool ShowFrameLines { get; set; } = true;
|
2018-10-18 19:25:33 +01:00
|
|
|
|
|
|
|
|
Mesh BackgroundMesh { get; set; }
|
2019-04-22 11:44:25 +01:00
|
|
|
Mesh ForegroundMesh { get; set; }
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-04-22 11:44:25 +01:00
|
|
|
public delegate void HighlightFrameEventHandler(object sender, HighlightFrameEventArgs e);
|
2020-02-05 20:51:54 +00:00
|
|
|
public static readonly RoutedEvent HighlightFrameEvent = EventManager.RegisterRoutedEvent("HighlightFrameEvent", RoutingStrategy.Bubble, typeof(HighlightFrameEventHandler), typeof(ThreadViewControl));
|
2019-02-24 22:24:12 +00:00
|
|
|
|
2019-04-14 18:30:30 +01:00
|
|
|
public void UpdateRows()
|
2018-12-16 21:52:57 +00:00
|
|
|
{
|
2018-12-16 14:26:48 +00:00
|
|
|
ThreadList.Children.Clear();
|
2019-04-14 18:30:30 +01:00
|
|
|
ThreadList.RowDefinitions.Clear();
|
|
|
|
|
ThreadList.Margin = new Thickness(0, 0, 3, 0);
|
2018-10-18 19:25:33 +01:00
|
|
|
double offset = 0.0;
|
2019-04-14 18:30:30 +01:00
|
|
|
bool isAlternative = false;
|
2019-04-20 00:45:50 +01:00
|
|
|
int rowCount = 0;
|
2019-04-14 18:30:30 +01:00
|
|
|
for (int threadIndex = 0; threadIndex < Rows.Count; ++threadIndex)
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
2019-04-14 18:30:30 +01:00
|
|
|
ThreadRow row = Rows[threadIndex];
|
|
|
|
|
row.Offset = offset;
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-04-14 18:30:30 +01:00
|
|
|
if (!row.IsVisible)
|
|
|
|
|
continue;
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-04-14 18:30:30 +01:00
|
|
|
if (ShowThreadHeaders)
|
2019-03-04 00:06:27 +00:00
|
|
|
{
|
2019-04-14 18:30:30 +01:00
|
|
|
ThreadList.RowDefinitions.Add(new RowDefinition());
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-04-14 18:30:30 +01:00
|
|
|
Border border = new Border()
|
2019-03-04 00:06:27 +00:00
|
|
|
{
|
2019-04-14 18:30:30 +01:00
|
|
|
Height = row.Height / RenderSettings.dpiScaleY,
|
|
|
|
|
};
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-04-14 18:30:30 +01:00
|
|
|
FrameworkElement header = row.Header;
|
|
|
|
|
if (header != null && header.Parent != null && (header.Parent is Border))
|
|
|
|
|
(header.Parent as Border).Child = null;
|
|
|
|
|
|
|
|
|
|
border.Child = row.Header;
|
|
|
|
|
border.Background = isAlternative ? OptickAlternativeBackground : OptickBackground;
|
2019-04-20 00:45:50 +01:00
|
|
|
Grid.SetRow(border, rowCount);
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-04-14 18:30:30 +01:00
|
|
|
ThreadList.Children.Add(border);
|
2019-03-04 00:06:27 +00:00
|
|
|
}
|
2019-04-14 18:30:30 +01:00
|
|
|
isAlternative = !isAlternative;
|
|
|
|
|
offset += row.Height;
|
2019-04-20 00:45:50 +01:00
|
|
|
rowCount += 1;
|
2018-10-18 19:25:33 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-14 18:30:30 +01:00
|
|
|
Scroll.Height = offset;
|
|
|
|
|
|
2019-04-22 01:05:47 +01:00
|
|
|
double controlHeight = offset / RenderSettings.dpiScaleY;
|
|
|
|
|
surface.Height = controlHeight;
|
|
|
|
|
surface.MaxHeight = controlHeight;
|
|
|
|
|
|
2019-04-14 18:30:30 +01:00
|
|
|
InitBackgroundMesh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void InitRows(List<ThreadRow> rows, IDurable timeslice)
|
|
|
|
|
{
|
|
|
|
|
Rows = rows;
|
|
|
|
|
|
|
|
|
|
if (rows.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
Scroll.TimeSlice = new Durable(timeslice.Start, timeslice.Finish);
|
|
|
|
|
Scroll.Width = surface.ActualWidth * RenderSettings.dpiScaleX;
|
|
|
|
|
rows.ForEach(row => row.BuildMesh(surface, Scroll));
|
|
|
|
|
rows.ForEach(row => row.ExpandChanged += Row_ExpandChanged);
|
2019-04-20 00:45:50 +01:00
|
|
|
rows.ForEach(row => row.VisibilityChanged += Row_VisibilityChanged);
|
2019-04-14 18:30:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UpdateRows();
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-20 00:45:50 +01:00
|
|
|
public void ReinitRows(List<ThreadRow> rows)
|
|
|
|
|
{
|
|
|
|
|
rows.ForEach(row => row.BuildMesh(surface, Scroll));
|
|
|
|
|
UpdateRowsAsync();
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-14 18:30:30 +01:00
|
|
|
private void Row_ExpandChanged(ThreadRow row)
|
|
|
|
|
{
|
|
|
|
|
//Task.Run(()=>
|
|
|
|
|
//{
|
|
|
|
|
row.BuildMesh(surface, Scroll);
|
2019-04-20 00:45:50 +01:00
|
|
|
UpdateRowsAsync();
|
2019-04-14 18:30:30 +01:00
|
|
|
//});
|
2018-10-18 19:25:33 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-20 00:45:50 +01:00
|
|
|
private void UpdateRowsAsync()
|
|
|
|
|
{
|
|
|
|
|
Application.Current.Dispatcher.BeginInvoke(new Action(() => UpdateRows()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Row_VisibilityChanged(ThreadRow row)
|
|
|
|
|
{
|
|
|
|
|
//throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-18 19:25:33 +01:00
|
|
|
private void InitBackgroundMesh()
|
|
|
|
|
{
|
|
|
|
|
if (BackgroundMesh != null)
|
|
|
|
|
BackgroundMesh.Dispose();
|
|
|
|
|
|
|
|
|
|
DynamicMesh backgroundBuilder = surface.CreateMesh();
|
|
|
|
|
backgroundBuilder.Projection = Mesh.ProjectionType.Pixel;
|
|
|
|
|
|
|
|
|
|
double offset = 0.0;
|
2019-04-14 18:30:30 +01:00
|
|
|
bool isAlternative = false;
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-03-04 00:06:27 +00:00
|
|
|
for (int threadIndex = 0; threadIndex < Rows.Count; ++threadIndex)
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
ThreadRow row = Rows[threadIndex];
|
2019-04-14 18:30:30 +01:00
|
|
|
if (!row.IsVisible)
|
|
|
|
|
continue;
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-04-14 18:30:30 +01:00
|
|
|
backgroundBuilder.AddRect(new Rect(0.0, offset, Scroll.Width, row.Height), isAlternative ? OptickAlternativeBackground.Color : OptickBackground.Color);
|
|
|
|
|
isAlternative = !isAlternative;
|
2018-10-18 19:25:33 +01:00
|
|
|
|
|
|
|
|
offset += row.Height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BackgroundMesh = backgroundBuilder.Freeze(surface.RenderDevice);
|
2019-03-24 21:31:54 +00:00
|
|
|
}
|
|
|
|
|
|
2019-04-22 11:44:25 +01:00
|
|
|
public void InitForegroundLines(List<ITick> lines)
|
|
|
|
|
{
|
|
|
|
|
if (ForegroundMesh != null)
|
|
|
|
|
ForegroundMesh.Dispose();
|
|
|
|
|
|
|
|
|
|
DynamicMesh builder = surface.CreateMesh();
|
|
|
|
|
builder.Geometry = Mesh.GeometryType.Lines;
|
|
|
|
|
|
|
|
|
|
// Adding Frame separators
|
|
|
|
|
if (lines != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (ITick line in lines)
|
|
|
|
|
{
|
|
|
|
|
double x = Scroll.TimeToUnit(line);
|
|
|
|
|
builder.AddLine(new Point(x, 0.0), new Point(x, 1.0), OptickAlternativeBackground.Color);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ForegroundMesh = builder.Freeze(surface.RenderDevice);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-18 19:25:33 +01:00
|
|
|
DynamicMesh SelectionMesh;
|
|
|
|
|
DynamicMesh HoverMesh;
|
|
|
|
|
DynamicMesh HoverLines;
|
|
|
|
|
DynamicMesh MeasureMesh;
|
2019-03-04 00:06:27 +00:00
|
|
|
public TooltipInfo ToolTipPanel { get; set; }
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-03-04 00:06:27 +00:00
|
|
|
public class TooltipInfo
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
|
|
|
|
public String Text;
|
|
|
|
|
public Rect Rect;
|
|
|
|
|
|
2020-02-05 20:51:54 +00:00
|
|
|
public void Reset()
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
|
|
|
|
Text = String.Empty;
|
|
|
|
|
Rect = new Rect();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-10 01:04:19 +00:00
|
|
|
const double DefaultFrameZoom = 1.10;
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-02-24 22:24:12 +00:00
|
|
|
public void Highlight(IEnumerable<Selection> items, bool focus = true)
|
|
|
|
|
{
|
|
|
|
|
SelectionList = new List<Selection>(items);
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-02-24 22:24:12 +00:00
|
|
|
if (focus)
|
|
|
|
|
{
|
|
|
|
|
foreach (Selection s in items)
|
|
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
Interval interval = Scroll.TimeToUnit(s.Focus != null ? s.Focus : (IDurable)s.Frame);
|
2019-12-08 20:55:55 +00:00
|
|
|
if (!Scroll.ViewUnit.IsValid || (!Scroll.ViewUnit.Contains(interval) && !interval.Contains(Scroll.ViewUnit)))
|
2019-02-24 22:24:12 +00:00
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
Scroll.ViewUnit.Width = interval.Width * DefaultFrameZoom;
|
|
|
|
|
Scroll.ViewUnit.Left = interval.Left - (Scroll.ViewUnit.Width - interval.Width) * 0.5;
|
|
|
|
|
Scroll.ViewUnit.Normalize();
|
2019-02-24 22:24:12 +00:00
|
|
|
UpdateBar();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-02-24 22:24:12 +00:00
|
|
|
UpdateSurface();
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-05 20:51:54 +00:00
|
|
|
public ThreadViewControl()
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
|
|
|
|
|
surface.SizeChanged += new SizeChangedEventHandler(ThreadView_SizeChanged);
|
|
|
|
|
surface.OnDraw += OnDraw;
|
|
|
|
|
|
|
|
|
|
InitInputEvent();
|
|
|
|
|
|
|
|
|
|
InitColors();
|
|
|
|
|
|
|
|
|
|
SelectionMesh = surface.CreateMesh();
|
|
|
|
|
SelectionMesh.Projection = Mesh.ProjectionType.Pixel;
|
|
|
|
|
SelectionMesh.Geometry = Mesh.GeometryType.Lines;
|
|
|
|
|
|
|
|
|
|
HoverLines = surface.CreateMesh();
|
|
|
|
|
HoverLines.Projection = Mesh.ProjectionType.Pixel;
|
|
|
|
|
HoverLines.Geometry = Mesh.GeometryType.Lines;
|
|
|
|
|
|
|
|
|
|
HoverMesh = surface.CreateMesh();
|
|
|
|
|
HoverMesh.Projection = Mesh.ProjectionType.Pixel;
|
|
|
|
|
HoverMesh.Geometry = Mesh.GeometryType.Polygons;
|
|
|
|
|
HoverMesh.UseAlpha = true;
|
|
|
|
|
|
|
|
|
|
MeasureMesh = surface.CreateMesh();
|
|
|
|
|
MeasureMesh.Projection = Mesh.ProjectionType.Pixel;
|
|
|
|
|
MeasureMesh.UseAlpha = true;
|
2019-03-24 21:31:54 +00:00
|
|
|
}
|
|
|
|
|
|
2018-10-18 19:25:33 +01:00
|
|
|
class InputState
|
|
|
|
|
{
|
|
|
|
|
public bool IsDrag { get; set; }
|
|
|
|
|
public bool IsSelect { get; set; }
|
|
|
|
|
public bool IsMeasure { get; set; }
|
|
|
|
|
public Durable MeasureInterval { get; set; }
|
|
|
|
|
public System.Drawing.Point SelectStartPosition { get; set; }
|
2019-03-24 21:31:54 +00:00
|
|
|
public System.Drawing.Point DragPosition { get; set; }
|
2018-10-18 19:25:33 +01:00
|
|
|
public System.Drawing.Point MousePosition { get; set; }
|
|
|
|
|
|
|
|
|
|
public InputState()
|
|
|
|
|
{
|
|
|
|
|
MeasureInterval = new Durable();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InputState Input = new InputState();
|
|
|
|
|
|
|
|
|
|
private void InitInputEvent()
|
|
|
|
|
{
|
|
|
|
|
surface.RenderCanvas.MouseWheel += RenderCanvas_MouseWheel;
|
|
|
|
|
surface.RenderCanvas.MouseDown += RenderCanvas_MouseDown;
|
|
|
|
|
surface.RenderCanvas.MouseUp += RenderCanvas_MouseUp;
|
|
|
|
|
surface.RenderCanvas.MouseMove += RenderCanvas_MouseMove;
|
|
|
|
|
surface.RenderCanvas.MouseLeave += RenderCanvas_MouseLeave;
|
|
|
|
|
|
|
|
|
|
scrollBar.Scroll += ScrollBar_Scroll;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RenderCanvas_MouseLeave(object sender, EventArgs e)
|
2019-03-24 21:31:54 +00:00
|
|
|
{
|
2018-10-18 19:25:33 +01:00
|
|
|
Mouse.OverrideCursor = null;
|
|
|
|
|
Input.IsDrag = false;
|
|
|
|
|
Input.IsSelect = false;
|
2019-03-24 21:31:54 +00:00
|
|
|
ToolTipPanel?.Reset();
|
2018-10-18 19:25:33 +01:00
|
|
|
UpdateSurface();
|
2019-03-04 00:06:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public delegate void OnShowPopupHandler(List<Object> dataContext);
|
2019-03-24 21:31:54 +00:00
|
|
|
public event OnShowPopupHandler OnShowPopup;
|
|
|
|
|
|
|
|
|
|
private void MouseShowPopup(System.Windows.Forms.MouseEventArgs args)
|
|
|
|
|
{
|
|
|
|
|
System.Drawing.Point e = new System.Drawing.Point(args.X, args.Y);
|
|
|
|
|
List<Object> dataContext = new List<object>();
|
|
|
|
|
foreach (ThreadRow row in Rows)
|
|
|
|
|
{
|
|
|
|
|
if (row.Offset <= e.Y && e.Y <= row.Offset + row.Height)
|
|
|
|
|
{
|
|
|
|
|
row.OnMouseHover(new Point(e.X, e.Y - row.Offset), Scroll, dataContext);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
OnShowPopup?.Invoke(dataContext);
|
2018-10-18 19:25:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void MouseClickLeft(System.Windows.Forms.MouseEventArgs args)
|
2019-03-24 21:31:54 +00:00
|
|
|
{
|
|
|
|
|
System.Drawing.Point e = new System.Drawing.Point(args.X, args.Y);
|
|
|
|
|
foreach (ThreadRow row in Rows)
|
|
|
|
|
{
|
|
|
|
|
if (row.Offset <= e.Y && e.Y <= row.Offset + row.Height)
|
|
|
|
|
{
|
|
|
|
|
row.OnMouseClick(new Point(e.X, e.Y - row.Offset), Scroll);
|
|
|
|
|
}
|
2018-10-18 19:25:33 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThreadRow GetRow(double posY)
|
|
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
foreach (ThreadRow row in Rows)
|
2018-10-18 19:25:33 +01:00
|
|
|
if (row.Offset <= posY && posY <= row.Offset + row.Height)
|
|
|
|
|
return row;
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RenderCanvas_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
|
2019-03-24 21:31:54 +00:00
|
|
|
{
|
2018-10-18 19:25:33 +01:00
|
|
|
Input.MousePosition = e.Location;
|
2019-03-24 21:31:54 +00:00
|
|
|
bool updateSurface = false;
|
|
|
|
|
|
2018-10-18 19:25:33 +01:00
|
|
|
if (Input.IsDrag)
|
|
|
|
|
{
|
|
|
|
|
double deltaPixel = e.X - Input.DragPosition.X;
|
|
|
|
|
|
2019-03-04 00:06:27 +00:00
|
|
|
double deltaUnit = Scroll.PixelToUnitLength(deltaPixel);
|
|
|
|
|
Scroll.ViewUnit.Left -= deltaUnit;
|
|
|
|
|
Scroll.ViewUnit.Normalize();
|
2018-10-18 19:25:33 +01:00
|
|
|
|
|
|
|
|
UpdateBar();
|
|
|
|
|
updateSurface = true;
|
|
|
|
|
|
|
|
|
|
Input.DragPosition = e.Location;
|
|
|
|
|
}
|
|
|
|
|
else if (Input.IsMeasure)
|
|
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
Input.MeasureInterval.Finish = Scroll.PixelToTime(e.X).Start;
|
2018-10-18 19:25:33 +01:00
|
|
|
updateSurface = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ThreadRow row = GetRow(e.Y);
|
|
|
|
|
if (row != null)
|
|
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
row.OnMouseMove(new Point(e.X, e.Y - row.Offset), Scroll);
|
2018-10-18 19:25:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateSurface = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (updateSurface)
|
|
|
|
|
UpdateSurface();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RenderCanvas_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Button == System.Windows.Forms.MouseButtons.Right)
|
2019-03-24 21:31:54 +00:00
|
|
|
{
|
2018-10-18 19:25:33 +01:00
|
|
|
Mouse.OverrideCursor = null;
|
|
|
|
|
Input.IsDrag = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e.Button == System.Windows.Forms.MouseButtons.Left)
|
|
|
|
|
{
|
2019-05-13 00:19:27 +01:00
|
|
|
if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && !IsMeasuring())
|
|
|
|
|
{
|
|
|
|
|
Input.IsSelect = true;
|
|
|
|
|
Input.SelectStartPosition = e.Location;
|
|
|
|
|
MouseClickLeft(e);
|
|
|
|
|
}
|
2018-10-18 19:25:33 +01:00
|
|
|
Input.IsMeasure = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-13 00:19:27 +01:00
|
|
|
private bool IsMeasuring()
|
|
|
|
|
{
|
|
|
|
|
Interval interval = Scroll.TimeToPixel(Input.MeasureInterval);
|
|
|
|
|
return Math.Abs(interval.Right - interval.Left) > 3;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-18 19:25:33 +01:00
|
|
|
private void RenderCanvas_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Button == System.Windows.Forms.MouseButtons.Right)
|
2019-03-24 21:31:54 +00:00
|
|
|
{
|
2018-10-18 19:25:33 +01:00
|
|
|
Mouse.OverrideCursor = Cursors.ScrollWE;
|
|
|
|
|
Input.IsDrag = true;
|
|
|
|
|
Input.DragPosition = e.Location;
|
|
|
|
|
}
|
|
|
|
|
else if (e.Button == System.Windows.Forms.MouseButtons.Left)
|
2019-03-24 21:31:54 +00:00
|
|
|
{
|
|
|
|
|
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
|
|
|
|
{
|
|
|
|
|
MouseShowPopup(e);
|
2018-10-18 19:25:33 +01:00
|
|
|
}
|
2019-03-24 21:31:54 +00:00
|
|
|
else
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
|
|
|
|
Input.IsMeasure = true;
|
2019-03-04 00:06:27 +00:00
|
|
|
long time = Scroll.PixelToTime(e.X).Start;
|
2018-10-18 19:25:33 +01:00
|
|
|
Input.MeasureInterval.Start = time;
|
|
|
|
|
Input.MeasureInterval.Finish = time;
|
2019-03-24 21:31:54 +00:00
|
|
|
}
|
2018-10-18 19:25:33 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ScrollBar_Scroll(object sender, ScrollEventArgs e)
|
|
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
Scroll.ViewUnit.Left = scrollBar.Value;
|
|
|
|
|
Scroll.ViewUnit.Normalize();
|
2018-10-18 19:25:33 +01:00
|
|
|
UpdateSurface();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const double ZoomSpeed = 1.2 / 120.0;
|
|
|
|
|
|
|
|
|
|
private void RenderCanvas_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if (e.Delta != 0)
|
|
|
|
|
{
|
|
|
|
|
double delta = e.Delta * ZoomSpeed;
|
|
|
|
|
double scale = delta > 0.0 ? 1 / delta : -delta;
|
|
|
|
|
|
|
|
|
|
double ratio = (double)e.X / surface.RenderCanvas.Width;
|
|
|
|
|
|
2019-03-04 00:06:27 +00:00
|
|
|
double prevWidth = Scroll.ViewUnit.Width;
|
|
|
|
|
Scroll.ViewUnit.Width *= scale;
|
|
|
|
|
Scroll.ViewUnit.Left += (prevWidth - Scroll.ViewUnit.Width) * ratio;
|
|
|
|
|
Scroll.ViewUnit.Normalize();
|
2018-10-18 19:25:33 +01:00
|
|
|
|
|
|
|
|
ThreadRow row = GetRow(e.Y);
|
|
|
|
|
if (row != null)
|
|
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
row.OnMouseMove(new Point(e.X, e.Y - row.Offset), Scroll);
|
2018-10-18 19:25:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UpdateBar();
|
|
|
|
|
UpdateSurface();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-04 00:06:27 +00:00
|
|
|
public void UpdateSurface()
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
|
|
|
|
surface.Update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateBar()
|
|
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
scrollBar.Value = Scroll.ViewUnit.Left;
|
|
|
|
|
scrollBar.Maximum = 1.0 - Scroll.ViewUnit.Width;
|
|
|
|
|
scrollBar.ViewportSize = Scroll.ViewUnit.Width;
|
2018-10-18 19:25:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int SelectionBorderCount = 3;
|
|
|
|
|
const double SelectionBorderStep = 0.75;
|
|
|
|
|
|
|
|
|
|
void DrawSelection(DirectX.DirectXCanvas canvas)
|
|
|
|
|
{
|
|
|
|
|
foreach (Selection selection in SelectionList)
|
|
|
|
|
{
|
2019-03-14 12:21:50 +00:00
|
|
|
if (selection.Frame != null && selection.Row != null)
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
ThreadRow row = selection.Row;
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-02-24 22:24:12 +00:00
|
|
|
IDurable intervalTime = selection.Focus == null ? selection.Frame.Header : selection.Focus;
|
2019-03-04 00:06:27 +00:00
|
|
|
Interval intervalPx = Scroll.TimeToPixel(intervalTime);
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2018-10-21 19:12:48 +01:00
|
|
|
Rect rect = new Rect(intervalPx.Left, row.Offset /*+ 2.0 * RenderParams.BaseMargin*/, intervalPx.Width, row.Height /*- 4.0 * RenderParams.BaseMargin*/);
|
2018-10-18 19:25:33 +01:00
|
|
|
|
|
|
|
|
for (int i = 0; i < SelectionBorderCount; ++i)
|
|
|
|
|
{
|
|
|
|
|
rect.Inflate(SelectionBorderStep, SelectionBorderStep);
|
|
|
|
|
SelectionMesh.AddRect(rect, FrameSelection.Color);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SelectionMesh.Update(canvas.RenderDevice);
|
|
|
|
|
canvas.Draw(SelectionMesh);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawMeasure(DirectX.DirectXCanvas canvas)
|
|
|
|
|
{
|
2019-05-13 00:19:27 +01:00
|
|
|
if (IsMeasuring())
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
|
|
|
|
Durable activeInterval = Input.MeasureInterval.Normalize();
|
2019-03-04 00:06:27 +00:00
|
|
|
Interval pixelInterval = Scroll.TimeToPixel(activeInterval);
|
|
|
|
|
MeasureMesh.AddRect(new Rect(pixelInterval.Left, 0, pixelInterval.Width, Scroll.Height), MeasureBackground);
|
|
|
|
|
canvas.Text.Draw(new Point(pixelInterval.Left, Scroll.Height * 0.5), activeInterval.DurationF3, Colors.White, TextAlignment.Center, pixelInterval.Width);
|
2018-10-18 19:25:33 +01:00
|
|
|
|
|
|
|
|
MeasureMesh.Update(canvas.RenderDevice);
|
|
|
|
|
canvas.Draw(MeasureMesh);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Size ToolTipMargin = new Size(4, 2);
|
|
|
|
|
static Vector ToolTipOffset = new Vector(0, -3);
|
|
|
|
|
|
|
|
|
|
void DrawHover(DirectXCanvas canvas)
|
|
|
|
|
{
|
2019-05-13 00:19:27 +01:00
|
|
|
if (Input.IsDrag)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-03-04 00:06:27 +00:00
|
|
|
if (ToolTipPanel != null && !String.IsNullOrWhiteSpace(ToolTipPanel.Text))
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
Size size = surface.Text.Measure(ToolTipPanel.Text);
|
2018-10-18 19:25:33 +01:00
|
|
|
|
2019-03-04 00:06:27 +00:00
|
|
|
Rect textArea = new Rect(Input.MousePosition.X - size.Width * 0.5 + ToolTipOffset.X, ToolTipPanel.Rect.Top - size.Height + ToolTipOffset.Y, size.Width, size.Height);
|
|
|
|
|
surface.Text.Draw(textArea.TopLeft, ToolTipPanel.Text, Colors.White, TextAlignment.Left);
|
2018-10-18 19:25:33 +01:00
|
|
|
|
|
|
|
|
textArea.Inflate(ToolTipMargin);
|
|
|
|
|
HoverMesh.AddRect(textArea, HoverBackground);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-04 00:06:27 +00:00
|
|
|
if (ToolTipPanel != null && !ToolTipPanel.Rect.IsEmpty)
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
HoverLines.AddRect(ToolTipPanel.Rect, FrameHover.Color);
|
2018-10-18 19:25:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HoverLines.Update(canvas.RenderDevice);
|
|
|
|
|
canvas.Draw(HoverLines);
|
|
|
|
|
|
|
|
|
|
HoverMesh.Update(canvas.RenderDevice);
|
|
|
|
|
canvas.Draw(HoverMesh);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnDraw(DirectX.DirectXCanvas canvas, DirectXCanvas.Layer layer)
|
|
|
|
|
{
|
|
|
|
|
if (layer == DirectXCanvas.Layer.Background)
|
|
|
|
|
{
|
|
|
|
|
canvas.Draw(BackgroundMesh);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-04 00:06:27 +00:00
|
|
|
Rect box = new Rect(0, 0, Scroll.Width, Scroll.Height);
|
|
|
|
|
foreach (ThreadRow row in Rows)
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
|
|
|
|
box.Height = row.Height;
|
2019-03-04 00:06:27 +00:00
|
|
|
row.Render(canvas, Scroll, layer, box);
|
2018-10-18 19:25:33 +01:00
|
|
|
box.Y = box.Y + row.Height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (layer == DirectXCanvas.Layer.Foreground)
|
|
|
|
|
{
|
2020-08-06 14:07:14 +02:00
|
|
|
if (ShowFrameLines && ForegroundMesh != null)
|
2019-04-22 20:55:08 +01:00
|
|
|
{
|
|
|
|
|
Matrix world = new Matrix(Scroll.Zoom, 0.0, 0.0, 1.0, -Scroll.ViewUnit.Left * Scroll.Zoom, 0.0);
|
|
|
|
|
ForegroundMesh.WorldTransform = world;
|
|
|
|
|
canvas.Draw(ForegroundMesh);
|
|
|
|
|
}
|
2019-04-22 11:44:25 +01:00
|
|
|
|
2018-10-18 19:25:33 +01:00
|
|
|
DrawSelection(canvas);
|
|
|
|
|
DrawHover(canvas);
|
|
|
|
|
DrawMeasure(canvas);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ThreadView_SizeChanged(object sender, SizeChangedEventArgs e)
|
|
|
|
|
{
|
2019-03-04 00:06:27 +00:00
|
|
|
Scroll.Width = surface.ActualWidth * RenderSettings.dpiScaleX;
|
2018-10-18 19:25:33 +01:00
|
|
|
InitBackgroundMesh();
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-24 22:24:12 +00:00
|
|
|
public struct Selection
|
2018-10-18 19:25:33 +01:00
|
|
|
{
|
|
|
|
|
public EventFrame Frame { get; set; }
|
2019-02-24 22:24:12 +00:00
|
|
|
public IDurable Focus { get; set; }
|
2019-03-04 00:06:27 +00:00
|
|
|
public ThreadRow Row { get; set; }
|
2018-10-18 19:25:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<Selection> SelectionList = new List<Selection>();
|
2019-03-24 21:31:54 +00:00
|
|
|
}
|
|
|
|
|
}
|