Skip to content

Commit

Permalink
Merge pull request #8 from bonsai-rx/feature-dev
Browse files Browse the repository at this point in the history
Add two way binding for check button state
  • Loading branch information
glopesdev authored Feb 16, 2024
2 parents 10ffbd8 + e3f99d6 commit 0fb8df2
Show file tree
Hide file tree
Showing 12 changed files with 78 additions and 75 deletions.
21 changes: 2 additions & 19 deletions src/Bonsai.Gui/ButtonBuilderBase.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,9 @@
using System.ComponentModel;
using System.Reactive.Subjects;

namespace Bonsai.Gui
namespace Bonsai.Gui
{
/// <summary>
/// Provides an abstract base class with common button control functionality.
/// </summary>
/// <inheritdoc/>
[DefaultProperty(nameof(Text))]
public abstract class ButtonBuilderBase<TEvent> : ControlBuilderBase<TEvent>
public abstract class ButtonBuilderBase<TEvent> : TextControlBuilderBase<TEvent>
{
internal readonly BehaviorSubject<string> _Text = new(string.Empty);

/// <summary>
/// Gets or sets the text associated with this control.
/// </summary>
[Category(nameof(CategoryAttribute.Appearance))]
[Description("The text associated with this control.")]
public string Text
{
get => _Text.Value;
set => _Text.OnNext(value);
}
}
}
1 change: 0 additions & 1 deletion src/Bonsai.Gui/ButtonVisualizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ protected override Button CreateControl(IServiceProvider provider, ButtonBuilder
var button = new Button();
button.Dock = DockStyle.Fill;
button.Size = new Size(300, 150);
button.SubscribeTo(builder._Text, value => button.Text = value);
button.Click += (sender, e) =>
{
builder._Click.OnNext(button.Name);
Expand Down
20 changes: 2 additions & 18 deletions src/Bonsai.Gui/CheckBoxBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.ComponentModel;
using System.Reactive.Subjects;
using System.ComponentModel;

namespace Bonsai.Gui
{
Expand All @@ -10,21 +8,7 @@ namespace Bonsai.Gui
/// </summary>
[TypeVisualizer(typeof(CheckBoxVisualizer))]
[Description("Interfaces with a check box control and generates a sequence of notifications whenever the checked status changes.")]
public class CheckBoxBuilder : ButtonBuilderBase<bool>
public class CheckBoxBuilder : CheckButtonBuilderBase
{
internal readonly Subject<bool> _CheckedChanged = new();

/// <summary>
/// Gets or sets a value specifying the initial state of the check box.
/// </summary>
[Category(nameof(CategoryAttribute.Appearance))]
[Description("Specifies the initial state of the check box.")]
public bool Checked { get; set; }

/// <inheritdoc/>
protected override IObservable<bool> Generate()
{
return _CheckedChanged;
}
}
}
4 changes: 2 additions & 2 deletions src/Bonsai.Gui/CheckBoxVisualizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ protected override CheckBox CreateControl(IServiceProvider provider, CheckBoxBui
checkBox.Dock = DockStyle.Fill;
checkBox.Size = new Size(300, 75);
checkBox.Checked = builder.Checked;
checkBox.SubscribeTo(builder._Text, value => checkBox.Text = value);
checkBox.SubscribeTo(builder._Checked, value => checkBox.Checked = value);
checkBox.CheckedChanged += (sender, e) =>
{
builder._CheckedChanged.OnNext(checkBox.Checked);
builder._Checked.OnNext(checkBox.Checked);
};
return checkBox;
}
Expand Down
31 changes: 31 additions & 0 deletions src/Bonsai.Gui/CheckButtonBuilderBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.ComponentModel;
using System.Reactive.Subjects;

namespace Bonsai.Gui
{
/// <summary>
/// Provides an abstract base class with common check button control functionality.
/// </summary>
public class CheckButtonBuilderBase : ButtonBuilderBase<bool>
{
internal readonly BehaviorSubject<bool> _Checked = new(false);

/// <summary>
/// Gets or sets a value indicating whether the button is checked.
/// </summary>
[Category(nameof(CategoryAttribute.Appearance))]
[Description("Indicates whether the button is checked.")]
public bool Checked
{
get => _Checked.Value;
set => _Checked.OnNext(value);
}

/// <inheritdoc/>
protected override IObservable<bool> Generate()
{
return _Checked;
}
}
}
5 changes: 5 additions & 0 deletions src/Bonsai.Gui/ControlExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ internal static void SubscribeTo(this Control control, ExpressionBuilder builder
control.SubscribeTo(controlBuilder._Visible, value => control.Visible = value);
control.SubscribeTo(controlBuilder._Font, value => control.Font = value);
}

if (builder is TextControlBuilderBase textControlBuilder)
{
control.SubscribeTo(textControlBuilder._Text, value => control.Text = value);
}
}
}
}
1 change: 0 additions & 1 deletion src/Bonsai.Gui/GroupBoxVisualizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ protected override GroupBox CreateControl(IServiceProvider provider, GroupBoxBui
var groupBox = new GroupBox();
groupBox.Dock = DockStyle.Fill;
groupBox.Size = new Size(320, 240);
groupBox.SubscribeTo(builder._Text, value => groupBox.Text = value);
return groupBox;
}
}
Expand Down
20 changes: 2 additions & 18 deletions src/Bonsai.Gui/RadioButtonBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.ComponentModel;
using System.Reactive.Subjects;
using System.ComponentModel;

namespace Bonsai.Gui
{
Expand All @@ -10,21 +8,7 @@ namespace Bonsai.Gui
/// </summary>
[TypeVisualizer(typeof(RadioButtonVisualizer))]
[Description("Interfaces with a radio button control and generates a sequence of notifications whenever the checked status changes.")]
public class RadioButtonBuilder : ButtonBuilderBase<bool>
public class RadioButtonBuilder : CheckButtonBuilderBase
{
internal readonly Subject<bool> _CheckedChanged = new();

/// <summary>
/// Gets or sets a value specifying the initial state of the radio button.
/// </summary>
[Category(nameof(CategoryAttribute.Appearance))]
[Description("Specifies the initial state of the radio button.")]
public bool Checked { get; set; }

/// <inheritdoc/>
protected override IObservable<bool> Generate()
{
return _CheckedChanged;
}
}
}
4 changes: 2 additions & 2 deletions src/Bonsai.Gui/RadioButtonVisualizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ protected override RadioButton CreateControl(IServiceProvider provider, RadioBut
radioButton.Dock = DockStyle.Fill;
radioButton.Size = new Size(300, 75);
radioButton.Checked = builder.Checked;
radioButton.SubscribeTo(builder._Text, value => radioButton.Text = value);
radioButton.SubscribeTo(builder._Checked, value => radioButton.Checked = value);
radioButton.CheckedChanged += (sender, e) =>
{
builder._CheckedChanged.OnNext(radioButton.Checked);
builder._Checked.OnNext(radioButton.Checked);
};
return radioButton;
}
Expand Down
29 changes: 28 additions & 1 deletion src/Bonsai.Gui/TextControlBuilderBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System.ComponentModel;
using System.Collections.Generic;
using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reactive.Subjects;

namespace Bonsai.Gui
Expand All @@ -22,4 +25,28 @@ public string Text
set => _Text.OnNext(value);
}
}

/// <summary>
/// Provides an abstract base class with common UI text and event source control functionality.
/// </summary>
/// <typeparam name="TEvent">The type of event notifications emitted by the UI control.</typeparam>
public abstract class TextControlBuilderBase<TEvent> : TextControlBuilderBase, INamedElement
{
/// <summary>
/// Builds the expression tree for configuring and calling the UI control.
/// </summary>
/// <inheritdoc/>
public override Expression Build(IEnumerable<Expression> arguments)
{
return Expression.Call(Expression.Constant(this), nameof(Generate), null);
}

/// <summary>
/// Generates an observable sequence of event notifications from the UI control.
/// </summary>
/// <returns>
/// An observable sequence of events of type <typeparamref name="TEvent"/>.
/// </returns>
protected abstract IObservable<TEvent> Generate();
}
}
13 changes: 2 additions & 11 deletions src/Bonsai.Gui/ToggleButtonBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.ComponentModel;
using System.Reactive.Subjects;
using System.ComponentModel;

namespace Bonsai.Gui
{
Expand All @@ -10,14 +8,7 @@ namespace Bonsai.Gui
/// </summary>
[TypeVisualizer(typeof(ToggleButtonVisualizer))]
[Description("Interfaces with a toggle button control and generates a sequence of notifications whenever the toggle status changes.")]
public class ToggleButtonBuilder : ButtonBuilderBase<bool>
public class ToggleButtonBuilder : CheckButtonBuilderBase
{
internal readonly Subject<bool> _CheckedChanged = new();

/// <inheritdoc/>
protected override IObservable<bool> Generate()
{
return _CheckedChanged;
}
}
}
4 changes: 2 additions & 2 deletions src/Bonsai.Gui/ToggleButtonVisualizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ protected override CheckBox CreateControl(IServiceProvider provider, ToggleButto
checkBox.Size = new Size(300, 150);
checkBox.Appearance = Appearance.Button;
checkBox.TextAlign = ContentAlignment.MiddleCenter;
checkBox.SubscribeTo(builder._Text, value => checkBox.Text = value);
checkBox.SubscribeTo(builder._Checked, value => checkBox.Checked = value);
checkBox.CheckedChanged += (sender, e) =>
{
builder._CheckedChanged.OnNext(checkBox.Checked);
builder._Checked.OnNext(checkBox.Checked);
};
return checkBox;
}
Expand Down

0 comments on commit 0fb8df2

Please sign in to comment.