Skip to content
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
Expand Up @@ -4,6 +4,7 @@
using System.Windows.Forms.Design;
using System.Windows.Forms;
using Bonsai.Design;
using System.Reactive;

namespace Bonsai.Scripting.Expressions.Design
{
Expand Down Expand Up @@ -53,7 +54,7 @@ public override object EditValue(ITypeDescriptorContext context, IServiceProvide
var editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
if (editorService != null)
{
var itType = GetDataSource(context, provider)?.ObservableType;
var itType = context.Instance is ExpressionSource ? typeof(Unit) : GetDataSource(context, provider)?.ObservableType;
using var editorDialog = new ExpressionScriptEditorDialog(itType);
editorDialog.Script = (string)value;
return editorService.ShowDialog(editorDialog) == DialogResult.OK
Expand Down
78 changes: 78 additions & 0 deletions src/Bonsai.Scripting.Expressions/ExpressionSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using Bonsai.Expressions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reactive;
using System.Reactive.Linq;

namespace Bonsai.Scripting.Expressions
{
/// <summary>
/// Represents an operator that uses an expression script to generate an
/// observable sequence with a single element.
/// </summary>
[DefaultProperty(nameof(Expression))]
[WorkflowElementCategory(ElementCategory.Source)]
[TypeDescriptionProvider(typeof(ExpressionSourceTypeDescriptionProvider))]
[Description("An expression script used to generate a sequence with a single element.")]
public class ExpressionSource : ZeroArgumentExpressionBuilder, IScriptingElement
{
/// <summary>
/// Gets or sets the name of the expression source.
/// </summary>
[Externalizable(false)]
[Category(nameof(CategoryAttribute.Design))]
[Description("The name of the expression source.")]
public string Name { get; set; }

/// <summary>
/// Gets or sets a description for the expression source.
/// </summary>
[Externalizable(false)]
[Category(nameof(CategoryAttribute.Design))]
[Description("A description for the expression source.")]
[Editor(DesignTypes.MultilineStringEditor, DesignTypes.UITypeEditor)]
public string Description { get; set; }

/// <summary>
/// Gets or sets the expression that generates the singleton element.
/// </summary>
/// <remarks>
/// The <c>it</c> parameter stores the singleton <see cref="Unit"/> object
/// representing no data.
/// </remarks>
[Editor("Bonsai.Scripting.Expressions.Design.ExpressionScriptEditor, Bonsai.Scripting.Expressions.Design", DesignTypes.UITypeEditor)]
[Description("The expression that generates the singleton element.")]
public string Expression { get; set; } = "it";

/// <inheritdoc/>
public override Expression Build(IEnumerable<Expression> arguments)
{
var config = ParsingConfigHelper.CreateParsingConfig(typeof(Unit));
var generator = DynamicExpressionHelper.ParseLambda(config, typeof(Unit), null, Expression);
return System.Linq.Expressions.Expression.Call(typeof(ExpressionSource), nameof(Process), new[] { generator.ReturnType }, generator);
}

static IObservable<TResult> Process<TResult>(Func<Unit, TResult> generator)
{
return Observable.Return(Unit.Default).Select(generator);
}

class ExpressionSourceTypeDescriptionProvider : TypeDescriptionProvider
{
static readonly TypeDescriptionProvider parentProvider = TypeDescriptor.GetProvider(typeof(ExpressionSource));

public ExpressionSourceTypeDescriptionProvider()
: base(parentProvider)
{
}

public override ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance)
{
return new ScriptingElementTypeDescriptor(instance,
"An expression script used to generate a sequence with a single element.");
}
}
}
}
Loading