Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor text visualizer to use buffered updates #1446

Merged
merged 5 commits into from
Jul 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
using System;
using System.Collections.Generic;
using System.Reactive;
using System.Reactive.Linq;
using System.Windows.Forms;

namespace Bonsai.Design.Visualizers
namespace Bonsai.Design
{
/// <summary>
/// Provides an abstract base class for type visualizers with an update
/// frequency potentially much higher than the screen refresh rate.
/// </summary>
public abstract class BufferedVisualizer : DialogTypeVisualizer
{
const int TargetInterval = 1000 / 50;

internal BufferedVisualizer()
{
}
/// <summary>
/// Gets or sets the target interval, in milliseconds, between visualizer updates.
/// </summary>
protected virtual int TargetInterval => 1000 / 50;

/// <inheritdoc/>
public override IObservable<object> Visualize(IObservable<IObservable<object>> source, IServiceProvider provider)
Expand All @@ -39,17 +40,26 @@ public override IObservable<object> Visualize(IObservable<IObservable<object>> s
return mergedSource
.Timestamp(HighResolutionScheduler.Default)
.Buffer(() => timerTick)
.Do(buffer =>
{
foreach (var timestamped in buffer)
{
var time = timestamped.Timestamp.LocalDateTime;
Show(time, timestamped.Value);
}
}).Finally(timer.Stop);
.Do(ShowBuffer).Finally(timer.Stop);
});
}

/// <summary>
/// Updates the type visualizer with a new buffer of timestamped values.
/// </summary>
/// <param name="values">
/// A buffer of timestamped values where each timestamp indicates the
/// time at which the value was received.
/// </param>
protected virtual void ShowBuffer(IList<Timestamped<object>> values)
{
foreach (var timestamped in values)
{
var time = timestamped.Timestamp.LocalDateTime;
Show(time, timestamped.Value);
}
}

/// <summary>
/// Updates the type visualizer to display a buffered value object
/// received at the specified time.
Expand Down
27 changes: 20 additions & 7 deletions Bonsai.Design/ObjectTextVisualizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Bonsai;
using Bonsai.Design;
using System.Drawing;
using System.Reactive;

[assembly: TypeVisualizer(typeof(ObjectTextVisualizer), Target = typeof(object))]

Expand All @@ -12,16 +13,30 @@ namespace Bonsai.Design
/// <summary>
/// Provides a type visualizer for displaying any object type as text.
/// </summary>
public class ObjectTextVisualizer : DialogTypeVisualizer
public class ObjectTextVisualizer : BufferedVisualizer
{
const int AutoScaleHeight = 13;
const float DefaultDpi = 96f;

TextBox textBox;
RichTextBox textBox;
UserControl textPanel;
Queue<string> buffer;
int bufferSize;

/// <inheritdoc/>
protected override int TargetInterval => 1000 / 30;

/// <inheritdoc/>
protected override void ShowBuffer(IList<Timestamped<object>> values)
{
if (values.Count > 0)
{
base.ShowBuffer(values);
textBox.Text = string.Join(Environment.NewLine, buffer);
textPanel.Invalidate();
}
}

/// <inheritdoc/>
public override void Show(object value)
{
Expand All @@ -31,18 +46,17 @@ public override void Show(object value)
{
buffer.Dequeue();
}
textBox.Text = string.Join(Environment.NewLine, buffer);
}

/// <inheritdoc/>
public override void Load(IServiceProvider provider)
{
buffer = new Queue<string>();
textBox = new TextBox { Dock = DockStyle.Fill };
textBox = new RichTextBox { Dock = DockStyle.Fill };
textBox.ReadOnly = true;
textBox.Multiline = true;
textBox.WordWrap = false;
textBox.TextChanged += (sender, e) => textPanel.Invalidate();
textBox.ScrollBars = RichTextBoxScrollBars.Horizontal;

textPanel = new UserControl();
textPanel.SuspendLayout();
Expand All @@ -66,9 +80,8 @@ void textPanel_Paint(object sender, PaintEventArgs e)
var lineHeight = AutoScaleHeight * e.Graphics.DpiY / DefaultDpi;
bufferSize = (int)((textBox.ClientSize.Height - 2) / lineHeight);
var textSize = TextRenderer.MeasureText(textBox.Text, textBox.Font);
if (textBox.ScrollBars == ScrollBars.None && textBox.ClientSize.Width < textSize.Width)
if (textBox.ClientSize.Width < textSize.Width)
{
textBox.ScrollBars = ScrollBars.Horizontal;
var offset = 2 * lineHeight + SystemInformation.HorizontalScrollBarHeight - textPanel.Height;
if (offset > 0)
{
Expand Down
Loading