diff --git a/src/Gemini.Demo/Gemini.Demo.csproj b/src/Gemini.Demo/Gemini.Demo.csproj index a69fa219..6b2d4890 100644 --- a/src/Gemini.Demo/Gemini.Demo.csproj +++ b/src/Gemini.Demo/Gemini.Demo.csproj @@ -44,6 +44,9 @@ true + + ..\packages\C5.2.3.0.1\lib\net40\C5.dll + ..\packages\Caliburn.Micro.Core.2.0.2\lib\net45\Caliburn.Micro.dll True @@ -52,6 +55,15 @@ ..\packages\Caliburn.Micro.2.0.2\lib\net45\Caliburn.Micro.Platform.dll True + + ..\packages\Common.Logging.2.2.0\lib\net40\Common.Logging.dll + + + ..\packages\Common.Logging.Core.2.2.0\lib\net40\Common.Logging.Core.dll + + + ..\packages\Gridsum.DataflowEx.1.1.3\lib\net45\Gridsum.DataflowEx.dll + ..\packages\Gu.Localization.6.1.0.0\lib\net45\Gu.Localization.dll True @@ -81,18 +93,46 @@ True - - ..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + ..\packages\System.Collections.Immutable.1.3.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll True + + ..\packages\System.Interactive.Async.3.1.1\lib\net46\System.Interactive.Async.dll + + + ..\packages\System.Reactive.Core.3.1.1\lib\net45\System.Reactive.Core.dll + + + ..\packages\System.Reactive.Interfaces.3.1.1\lib\net45\System.Reactive.Interfaces.dll + + + ..\packages\System.Reactive.Linq.3.1.1\lib\net45\System.Reactive.Linq.dll + + + ..\packages\System.Reactive.PlatformServices.3.1.1\lib\net45\System.Reactive.PlatformServices.dll + + + ..\packages\System.Reactive.Windows.Threading.3.1.1\lib\net45\System.Reactive.Windows.Threading.dll + + + ..\packages\System.Reflection.4.1.0\lib\net462\System.Reflection.dll + ..\packages\System.Reflection.Metadata.1.1.0\lib\portable-net45+win8\System.Reflection.Metadata.dll True + + ..\packages\System.Threading.Tasks.Dataflow.4.7.0\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll + + + ..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll + + @@ -150,6 +190,8 @@ + + @@ -158,22 +200,32 @@ - - - + + + + + + + + + - + - - + + + GraphView.xaml + + ImagePreview.xaml + @@ -286,6 +338,10 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -332,6 +388,7 @@ + diff --git a/src/Gemini.Demo/Modules/FilterDesigner/JoinAnyBlock.cs b/src/Gemini.Demo/Modules/FilterDesigner/JoinAnyBlock.cs new file mode 100644 index 00000000..bcdb88c1 --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/JoinAnyBlock.cs @@ -0,0 +1,41 @@ +using Gridsum.DataflowEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; + +namespace Gemini.Demo.Modules.FilterDesigner +{ + public class JoinAny + { + public Task Completion => throw new NotImplementedException(); + public Dataflow Target1; + public Dataflow Target2; + public Dataflow<(T1, T2), (T1, T2)> source; + public bool first; + T1 I1; + T2 I2; + public JoinAny() + { + Target1 = new BufferBlock(new DataflowBlockOptions()).ToDataflow(); + Target2 = new BufferBlock(new DataflowBlockOptions()).ToDataflow(); + Target1.OutputBlock.AsObservable().Subscribe(x => _in1(x)); + Target2.OutputBlock.AsObservable().Subscribe(x => _in2(x)); + + source = new BufferBlock<(T1, T2)>().ToDataflow(); + + } + private void _in2(T2 x) + { + I2 = x; + if (I1 != null) source.SendAsync((I1, I2)); + } + private void _in1(T1 x) + { + I1 = x; + if (I2 != null) source.SendAsync((I1, I2)); + } + } +} diff --git a/src/Gemini.Demo/Modules/FilterDesigner/Logger.cs b/src/Gemini.Demo/Modules/FilterDesigner/Logger.cs new file mode 100644 index 00000000..ac8d229e --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/Logger.cs @@ -0,0 +1,45 @@ +using Common.Logging.Simple; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Common.Logging; +using Common.Logging.Factory; +using System.ComponentModel.Composition; +using Gemini.Modules.ErrorList; + +namespace Gemini.Demo.Modules.FilterDesigner +{ + public class Logger : AbstractLogger + { + public override bool IsTraceEnabled => true; + + public override bool IsDebugEnabled => true; + + public override bool IsInfoEnabled => true; + + public override bool IsWarnEnabled => true; + + public override bool IsErrorEnabled => true; + + public override bool IsFatalEnabled => true; + + IErrorList _display; + + + public Logger(IErrorList display) + { + _display = display; + } + + + protected override void WriteInternal(LogLevel level, object message, Exception exception) + { + + if(message !=null) _display.AddItem(ErrorListItemType.Message, message.ToString()); + if(exception != null) _display.AddItem(ErrorListItemType.Error, exception.ToString()); + + } + } +} diff --git a/src/Gemini.Demo/Modules/FilterDesigner/LoggerFacory.cs b/src/Gemini.Demo/Modules/FilterDesigner/LoggerFacory.cs new file mode 100644 index 00000000..97e89f69 --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/LoggerFacory.cs @@ -0,0 +1,31 @@ +using Common.Logging.Factory; +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Common.Logging; +using Gemini.Modules.ErrorList; + +namespace Gemini.Demo.Modules.FilterDesigner +{ + [Export(typeof(LoggerFacory))] + public class LoggerFacory : AbstractCachingLoggerFactoryAdapter + { + Logger l; + IErrorList _display; + + [ImportingConstructor] + public LoggerFacory(IErrorList display) + { + _display = display; + } + + + protected override ILog CreateLogger(string name) + { + return l = l ?? new Logger(_display); + } + } +} diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/BitmapSourceConnection.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/BitmapSourceConnection.cs new file mode 100644 index 00000000..a7594402 --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/BitmapSourceConnection.cs @@ -0,0 +1,26 @@ +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input; +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connection +{ + class BitmapSourceConnection : GenericConnectionViewModel + { + public BitmapSourceConnection(GenericOutputConnectorViewModel from, GenericInputConnectorViewModel to) :base(from,to) + { + } + + public BitmapSourceConnection(GenericOutputConnectorViewModel from) : base(from) + { + } + + Brush __color = new SolidColorBrush(System.Windows.Media.Color.FromRgb(36, 97, 121)); + internal override Brush _color { get { return __color; } set { __color = value; } } + } +} diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectionViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/ConnectionViewModel.cs similarity index 67% rename from src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectionViewModel.cs rename to src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/ConnectionViewModel.cs index 90b4a8c1..73aea21f 100644 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectionViewModel.cs +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/ConnectionViewModel.cs @@ -1,17 +1,22 @@ using System; using System.Windows; using Caliburn.Micro; +using System.Windows.Media; +using System.ComponentModel; namespace Gemini.Demo.Modules.FilterDesigner.ViewModels { - public class ConnectionViewModel : PropertyChangedBase + public abstract class ConnectionViewModel : PropertyChangedBase, IsSelectable { - private OutputConnectorViewModel _from; + public abstract Type ConnectionType { get; set; } + + internal abstract OutputConnectorViewModel _from { get; set; } public OutputConnectorViewModel From { get { return _from; } private set { + if (value.Type != ConnectionType) throw new Exception(); if (_from != null) { _from.PositionChanged -= OnFromPositionChanged; @@ -31,16 +36,31 @@ private set } } - private InputConnectorViewModel _to; + [Browsable(false)] + private bool _isSelected; + + public bool IsSelected + { + get { return _isSelected; } + set + { + _isSelected = value; + NotifyOfPropertyChange(() => IsSelected); + } + } + + + internal abstract InputConnectorViewModel _to { get; set; } public InputConnectorViewModel To { get { return _to; } set { + if (value.Type != ConnectionType) throw new Exception(); if (_to != null) { _to.PositionChanged -= OnToPositionChanged; - _to.Connection = null; + _to.Connections.Remove(this); } _to = value; @@ -48,7 +68,7 @@ public InputConnectorViewModel To if (_to != null) { _to.PositionChanged += OnToPositionChanged; - _to.Connection = this; + _to.Connections.Add(this); ToPosition = _to.Position; } @@ -67,6 +87,18 @@ public Point FromPosition } } + internal abstract Brush _color { get; set; } + public Brush Color + { + get { return _color; } + set + { + _color = value; + NotifyOfPropertyChange(() => Color); + } + } + + private Point _toPosition; public Point ToPosition { diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/GenericConnectionViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/GenericConnectionViewModel.cs new file mode 100644 index 00000000..a511609a --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/GenericConnectionViewModel.cs @@ -0,0 +1,49 @@ +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input; +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; +using System.Windows.Media; + +namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connection +{ + abstract class GenericConnectionViewModel : ConnectionViewModel + { + public override Type ConnectionType { get; set; } = typeof(T); + + GenericOutputConnectorViewModel from; + internal override OutputConnectorViewModel _from { get { return from; } set { from = (GenericOutputConnectorViewModel) value; _restoreLink(); } } + + GenericInputConnectorViewModel to; + internal override InputConnectorViewModel _to { get { return to; } set { + to = (GenericInputConnectorViewModel)value; _restoreLink(); } } + + + private IDisposable _link; + + //raise condition + void _restoreLink() + { + if(_link !=null) _link.Dispose(); + if (_from == null || _to == null) return; + _link = from.output.LinkTo(to.target,new DataflowLinkOptions()); + } + + private void _exception(Exception x) + { + + } + + public GenericConnectionViewModel(GenericOutputConnectorViewModel from, GenericInputConnectorViewModel to) :base(from,to) + { + } + + public GenericConnectionViewModel(GenericOutputConnectorViewModel from) : base(from) + { + } + + } +} diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectorDirection.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/ConnectorDirection.cs similarity index 100% rename from src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectorDirection.cs rename to src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/ConnectorDirection.cs diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/ConnectorViewModel.cs similarity index 92% rename from src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectorViewModel.cs rename to src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/ConnectorViewModel.cs index 6b12fd18..10e8b5d1 100644 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectorViewModel.cs +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/ConnectorViewModel.cs @@ -5,15 +5,13 @@ namespace Gemini.Demo.Modules.FilterDesigner.ViewModels { - public enum ConnectorDataType - { - - } public abstract class ConnectorViewModel : PropertyChangedBase { public event EventHandler PositionChanged; + public abstract Type Type { get; set; } + private readonly ElementViewModel _element; public ElementViewModel Element { @@ -44,6 +42,7 @@ public Point Position } } + public abstract ConnectionViewModel GetNewConnection(); public abstract ConnectorDirection ConnectorDirection { get; } protected ConnectorViewModel(ElementViewModel element, string name, Color color) diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/BitmapSourceInputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/BitmapSourceInputConnectorViewModel.cs new file mode 100644 index 00000000..d6b52704 --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/BitmapSourceInputConnectorViewModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input +{ + class BitmapSourceInputConnectorViewModel : GenericInputConnectorViewModel + { + public BitmapSourceInputConnectorViewModel(ITargetBlock target, ElementViewModel element, string name, Color color) : base(target, element, name, color) + { + } + } +} diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/GenericInputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/GenericInputConnectorViewModel.cs new file mode 100644 index 00000000..668f6b58 --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/GenericInputConnectorViewModel.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; +using System.Windows.Media; + +namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input +{ + abstract class GenericInputConnectorViewModel : InputConnectorViewModel + { + public ITargetBlock target; + + public GenericInputConnectorViewModel(ITargetBlock target, ElementViewModel element, string name, Color color) : base( element, name, color) + { + this.target = target; + Type = typeof(T); + } + public override ConnectionViewModel GetNewConnection() + { + //throw new NotImplementedException(); + return null; + } + + public override Type Type { get; set; } + } +} diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/InputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/InputConnectorViewModel.cs new file mode 100644 index 00000000..8bace996 --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/InputConnectorViewModel.cs @@ -0,0 +1,28 @@ +using Caliburn.Micro; +using System; +using System.Threading.Tasks.Dataflow; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace Gemini.Demo.Modules.FilterDesigner.ViewModels +{ + public abstract class InputConnectorViewModel : ConnectorViewModel + { + + public override ConnectorDirection ConnectorDirection + { + get { return ConnectorDirection.Input; } + } + + private readonly BindableCollection _connections = new BindableCollection(); + public IObservableCollection Connections + { + get { return _connections; } + } + + public InputConnectorViewModel(ElementViewModel element, string name, Color color) + : base(element, name, color) + { + } + } +} \ No newline at end of file diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/BitmapSourceOutputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/BitmapSourceOutputConnectorViewModel.cs new file mode 100644 index 00000000..7dcd5569 --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/BitmapSourceOutputConnectorViewModel.cs @@ -0,0 +1,25 @@ +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connection; +using Gridsum.DataflowEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output +{ + class BitmapSourceOutputConnectorViewModel : GenericOutputConnectorViewModel + { + public BitmapSourceOutputConnectorViewModel(ElementViewModel element, string name, Color color, ISourceBlock valueCallback) : base(element, name, color, valueCallback) + { + } + + public override ConnectionViewModel GetNewConnection() + { + return new BitmapSourceConnection(this); + } + } +} diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/GenericOutputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/GenericOutputConnectorViewModel.cs new file mode 100644 index 00000000..448fb84f --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/GenericOutputConnectorViewModel.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output +{ + abstract class GenericOutputConnectorViewModel : OutputConnectorViewModel + { + public ISourceBlock output; + + public GenericOutputConnectorViewModel(ElementViewModel element, string name, Color color, ISourceBlock valueCallback) : base(element, name, color) + { + output = valueCallback; + Type = typeof(T); + } + + public override Type Type { get; set; } + } +} diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/OutputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/OutputConnectorViewModel.cs similarity index 68% rename from src/Gemini.Demo/Modules/FilterDesigner/ViewModels/OutputConnectorViewModel.cs rename to src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/OutputConnectorViewModel.cs index 45409d34..00a11646 100644 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/OutputConnectorViewModel.cs +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/OutputConnectorViewModel.cs @@ -2,12 +2,12 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using Caliburn.Micro; +using System.Threading.Tasks.Dataflow; namespace Gemini.Demo.Modules.FilterDesigner.ViewModels { - public class OutputConnectorViewModel : ConnectorViewModel + public abstract class OutputConnectorViewModel : ConnectorViewModel { - private readonly Func _valueCallback; public override ConnectorDirection ConnectorDirection { @@ -20,16 +20,17 @@ public IObservableCollection Connections get { return _connections; } } - public BitmapSource Value + public OutputConnectorViewModel(ElementViewModel element, string name, Color color) + : base(element, name, color) { - get { return _valueCallback(); } + _connections = new BindableCollection(); } - public OutputConnectorViewModel(ElementViewModel element, string name, Color color, Func valueCallback) - : base(element, name, color) + internal ConnectionViewModel Connect(InputConnectorViewModel inputConnectorViewModel) { - _connections = new BindableCollection(); - _valueCallback = valueCallback; + var x = GetNewConnection(); + x.To = inputConnectorViewModel; + return x; } } } \ No newline at end of file diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ElementViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ElementViewModel.cs index 66fbe0f6..8a8feffb 100644 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ElementViewModel.cs +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ElementViewModel.cs @@ -8,10 +8,13 @@ namespace Gemini.Demo.Modules.FilterDesigner.ViewModels { - public abstract class ElementViewModel : PropertyChangedBase + public interface IsSelectable { - public event EventHandler OutputChanged; + bool IsSelected { get; set; } + } + public abstract class ElementViewModel : PropertyChangedBase, IsSelectable + { public const double PreviewSize = 100; private double _x; @@ -74,54 +77,36 @@ public IList InputConnectors get { return _inputConnectors; } } - private OutputConnectorViewModel _outputConnector; - public OutputConnectorViewModel OutputConnector + private readonly BindableCollection _outputConnectors; + public IList OutputConnectors { - get { return _outputConnector; } - set - { - _outputConnector = value; - NotifyOfPropertyChange(() => OutputConnector); - } + get { return _outputConnectors; } } public IEnumerable AttachedConnections { get { - return _inputConnectors.Select(x => x.Connection) - .Union(_outputConnector.Connections) - .Where(x => x != null); + return _inputConnectors.SelectMany(x => x.Connections).Union(_outputConnectors.SelectMany(x => x.Connections)); } } protected ElementViewModel() { _inputConnectors = new BindableCollection(); + _outputConnectors = new BindableCollection(); + _name = GetType().Name; } - protected void AddInputConnector(string name, Color color) + protected void AddInputConnector(InputConnectorViewModel inputConnector) { - var inputConnector = new InputConnectorViewModel(this, name, color); - inputConnector.SourceChanged += (sender, e) => OnInputConnectorConnectionChanged(); _inputConnectors.Add(inputConnector); } - protected void SetOutputConnector(string name, Color color, Func valueCallback) - { - OutputConnector = new OutputConnectorViewModel(this, name, color, valueCallback); - } - - protected virtual void OnInputConnectorConnectionChanged() - { - - } - - protected virtual void RaiseOutputChanged() + protected void AddOutputConnector(OutputConnectorViewModel outputConnector) { - EventHandler handler = OutputChanged; - if (handler != null) handler(this, EventArgs.Empty); + OutputConnectors.Add(outputConnector); } } } \ No newline at end of file diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Add.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Add.cs index 694eff16..6c2cea7e 100644 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Add.cs +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Add.cs @@ -2,25 +2,34 @@ using System.Windows.Media.Effects; using Gemini.Demo.Modules.FilterDesigner.ShaderEffects; using Gemini.Modules.Toolbox; +using System.Windows.Media.Imaging; +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input; +using System.Threading.Tasks.Dataflow; +using Gridsum.DataflowEx; +using System; +using System.Threading.Tasks; namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements { [ToolboxItem(typeof(GraphViewModel), "Add", "Maths", "pack://application:,,,/Modules/FilterDesigner/Resources/action_add_16xLG.png")] public class Add : ShaderEffectElement { - protected override Effect GetEffect() + public Add() : base() { - return new AddEffect - { - Input1 = new ImageBrush(InputConnectors[0].Value), - Input2 = new ImageBrush(InputConnectors[1].Value) - }; + } - public Add() + + internal override DrawingVisual GetEffect(BitmapSource Input1, BitmapSource Input2) { - AddInputConnector("Left", Colors.DarkSeaGreen); - AddInputConnector("Right", Colors.DarkSeaGreen); + return new DrawingVisual() + { + Effect = new AddEffect + { + Input1 = new ImageBrush(Input1), + Input2 = new ImageBrush(Input2) + } + }; } } } \ No newline at end of file diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/BitmapSourceElement.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/BitmapSourceElement.cs new file mode 100644 index 00000000..9927e078 --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/BitmapSourceElement.cs @@ -0,0 +1,39 @@ +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input; +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output; +using Gridsum.DataflowEx; +using System; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; +namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements +{ + public abstract class BitmapSourceElement : ElementViewModel + { + private BitmapSource _previewImage; + + public override BitmapSource PreviewImage + { + get { return _previewImage; } + } + + public Dataflow source { get; set; } + + protected BitmapSourceElement() + { + source = new TransformBlock(X => displayImage(X), + new ExecutionDataflowBlockOptions() { TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()}) + .ToDataflow(DataflowOptions.Default, Name); + AddOutputConnector(new BitmapSourceOutputConnectorViewModel(this, "Output", Colors.DarkSeaGreen, source.OutputBlock)); + } + + private BitmapSource displayImage(BitmapSource arg) + { + _previewImage = arg; + NotifyOfPropertyChange("PreviewImage"); + return arg; + } + } +} \ No newline at end of file diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ColorInput.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ColorInput.cs index 63bdb6ed..64643130 100644 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ColorInput.cs +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ColorInput.cs @@ -1,33 +1,51 @@ using System.Windows; using System.Windows.Media; using Gemini.Modules.Toolbox; +using System.Threading.Tasks.Dataflow; +using Gridsum.DataflowEx; +using System.Windows.Media.Imaging; +using System; +using System.Threading.Tasks; namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements { [ToolboxItem(typeof(GraphViewModel), "Color", "Generators", "pack://application:,,,/Modules/FilterDesigner/Resources/color_swatch.png")] - public class ColorInput : DynamicElement + public class ColorInput : BitmapSourceElement { private Color _color; + + public ColorInput() + { + Color = Colors.Red; + } + + private BitmapSource _transform(Color arg) + { + var dv = new DrawingVisual(); + DrawingContext dc = dv.RenderOpen(); + dc.DrawRectangle(new SolidColorBrush(arg), null, new Rect(0, 0, PreviewSize, PreviewSize)); + dc.Close(); + return Render(dv); + } + internal BitmapSource Render(DrawingVisual dv) + { + var rtb = new RenderTargetBitmap((int)PreviewSize, (int)PreviewSize, 96, 96, PixelFormats.Pbgra32); + rtb.Render(dv); + + if (dv.Effect is IDisposable) + ((IDisposable)dv.Effect).Dispose(); + rtb.Freeze(); + return rtb; + } public Color Color { get { return _color; } set { _color = value; - UpdatePreviewImage(); + source.SendAsync(_transform(value)); NotifyOfPropertyChange(() => Color); } } - - public ColorInput() - { - Color = Colors.Red; - UpdatePreviewImage(); - } - - protected override void Draw(DrawingContext drawingContext, Rect bounds) - { - drawingContext.DrawRectangle(new SolidColorBrush(Color), null, bounds); - } } } \ No newline at end of file diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/DynamicElement.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/DynamicElement.cs deleted file mode 100644 index 4eef3aa9..00000000 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/DynamicElement.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Windows; -using System.Windows.Media; -using System.Windows.Media.Imaging; - -namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements -{ - public abstract class DynamicElement : ElementViewModel - { - private BitmapSource _previewImage; - - public override BitmapSource PreviewImage - { - get { return _previewImage; } - } - - protected DynamicElement() - { - SetOutputConnector("Output", Colors.DarkSeaGreen, () => PreviewImage); - } - - protected virtual void PrepareDrawingVisual(DrawingVisual drawingVisual) - { - - } - - protected abstract void Draw(DrawingContext drawingContext, Rect bounds); - - protected void UpdatePreviewImage() - { - var dv = new DrawingVisual(); - PrepareDrawingVisual(dv); - - DrawingContext dc = dv.RenderOpen(); - Draw(dc, new Rect(0, 0, PreviewSize, PreviewSize)); - dc.Close(); - - var rtb = new RenderTargetBitmap((int) PreviewSize, (int) PreviewSize, 96, 96, PixelFormats.Pbgra32); - rtb.Render(dv); - - if (dv.Effect is IDisposable) - ((IDisposable) dv.Effect).Dispose(); - - _previewImage = rtb; - NotifyOfPropertyChange("PreviewImage"); - - RaiseOutputChanged(); - } - - protected override void OnInputConnectorConnectionChanged() - { - UpdatePreviewImage(); - } - } -} \ No newline at end of file diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ImageSource.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ImageSource.cs index 5ffd6c9b..ba89b205 100644 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ImageSource.cs +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ImageSource.cs @@ -1,12 +1,19 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using Gemini.Modules.Toolbox; +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output; +using System.Threading.Tasks.Dataflow; +using System; +using Gridsum.DataflowEx; +using System.Threading.Tasks; namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements { [ToolboxItem(typeof(GraphViewModel), "Image Source", "Generators", "pack://application:,,,/Modules/FilterDesigner/Resources/image.png")] public class ImageSource : ElementViewModel { + public Dataflow source; + private BitmapSource _bitmap; public BitmapSource Bitmap { @@ -15,7 +22,8 @@ public BitmapSource Bitmap { _bitmap = value; NotifyOfPropertyChange(() => PreviewImage); - RaiseOutputChanged(); + _bitmap.Freeze(); + source.SendAsync(value); } } @@ -26,7 +34,8 @@ public override BitmapSource PreviewImage public ImageSource() { - SetOutputConnector("Output", Colors.DarkSeaGreen, () => Bitmap); + source = new DataBroadcaster(DataflowOptions.Default) { Name = this.Name }; + AddOutputConnector(new BitmapSourceOutputConnectorViewModel(this, "Output", Colors.DarkSeaGreen, source.OutputBlock)); } } } \ No newline at end of file diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Multiply.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Multiply.cs index b65a611a..b90dd504 100644 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Multiply.cs +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Multiply.cs @@ -2,25 +2,34 @@ using System.Windows.Media.Effects; using Gemini.Demo.Modules.FilterDesigner.ShaderEffects; using Gemini.Modules.Toolbox; +using System.Windows.Media.Imaging; +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input; +using Gridsum.DataflowEx; +using System; +using System.Threading.Tasks.Dataflow; +using System.Threading.Tasks; namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements { [ToolboxItem(typeof(GraphViewModel), "Multiply", "Maths", "pack://application:,,,/Modules/FilterDesigner/Resources/active_x_16xLG.png")] public class Multiply : ShaderEffectElement { - protected override Effect GetEffect() + + public Multiply() : base() { - return new MultiplyEffect - { - Input1 = new ImageBrush(InputConnectors[0].Value), - Input2 = new ImageBrush(InputConnectors[1].Value) - }; + } - public Multiply() + internal override DrawingVisual GetEffect(BitmapSource Input1, BitmapSource Input2) { - AddInputConnector("Left", Colors.DarkSeaGreen); - AddInputConnector("Right", Colors.DarkSeaGreen); + return new DrawingVisual + { + Effect = new MultiplyEffect + { + Input1 = new ImageBrush(Input1), + Input2 = new ImageBrush(Input2) + } + }; } } } \ No newline at end of file diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ShaderEffectElement.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ShaderEffectElement.cs index 562f7bbf..f2e1991a 100644 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ShaderEffectElement.cs +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ShaderEffectElement.cs @@ -1,23 +1,49 @@ -using System.Windows; +using Gridsum.DataflowEx; +using System.Threading.Tasks.Dataflow; +using System.Windows; using System.Windows.Media; using System.Windows.Media.Effects; +using System.Windows.Media.Imaging; +using System; +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input; +using Common.Logging; +using System.Threading.Tasks; +using Common.Logging.Simple; namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements { - public abstract class ShaderEffectElement : DynamicElement + public abstract class ShaderEffectElement : BitmapSourceElement { - protected override void PrepareDrawingVisual(DrawingVisual drawingVisual) + public JoinAny inputJoin = new JoinAny(); + public Dataflow<(BitmapSource, BitmapSource), BitmapSource> shaderTransformer { get; set; } + + + public ShaderEffectElement() { - drawingVisual.Effect = GetEffect(); + shaderTransformer = new TransformBlock<(BitmapSource, BitmapSource), BitmapSource>(x => UpdatePreviewImage(x.Item1, x.Item2)) + .ToDataflow(DataflowOptions.Default, "Shader"); + AddInputConnector(new BitmapSourceInputConnectorViewModel(inputJoin.Target1.InputBlock, this, "Left", Colors.DarkSeaGreen)); + AddInputConnector(new BitmapSourceInputConnectorViewModel(inputJoin.Target2.InputBlock, this, "Right", Colors.DarkSeaGreen)); + inputJoin.source.LinkTo(shaderTransformer); + shaderTransformer.LinkTo(source); } - protected override void Draw(DrawingContext drawingContext, Rect bounds) + internal abstract DrawingVisual GetEffect(BitmapSource Input1, BitmapSource Input2); + + internal BitmapSource UpdatePreviewImage(BitmapSource Input1, BitmapSource Input2) { - drawingContext.DrawRectangle( - new SolidColorBrush(Colors.Transparent), null, - bounds); + var x = GetEffect(Input1, Input2); + DrawingContext dc = x.RenderOpen(); + dc.DrawRectangle( + new SolidColorBrush(Colors.Transparent), null, + new Rect(0, 0, PreviewSize, PreviewSize)); + dc.Close(); + var rtb = new RenderTargetBitmap((int)PreviewSize, (int)PreviewSize, 96, 96, PixelFormats.Pbgra32); + rtb.Render(x); + if (x.Effect is IDisposable) + ((IDisposable)x.Effect).Dispose(); + rtb.Freeze(); + return (BitmapSource)rtb; } - - protected abstract Effect GetEffect(); } -} \ No newline at end of file +} diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/GraphViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/GraphViewModel.cs index 361f3855..96bc3c53 100644 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/GraphViewModel.cs +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/GraphViewModel.cs @@ -10,6 +10,9 @@ using Gemini.Framework; using Gemini.Modules.Inspector; using ImageSource = Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements.ImageSource; +using System.Windows.Media.Imaging; +using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connection; +using System; namespace Gemini.Demo.Modules.FilterDesigner.ViewModels { @@ -31,9 +34,9 @@ public IObservableCollection Connections get { return _connections; } } - public IEnumerable SelectedElements + public IEnumerable SelectedElements { - get { return _elements.Where(x => x.IsSelected); } + get { return _elements.Where(x => x.IsSelected).Concat(_connections.Where(x=>x.IsSelected)); } } [ImportingConstructor] @@ -46,7 +49,7 @@ public GraphViewModel(IInspectorTool inspectorTool) _inspectorTool = inspectorTool; - var element1 = AddElement(100, 50); + ImageSource element1 = AddElement(100, 50); element1.Bitmap = BitmapUtility.CreateFromBytes(DesignTimeImages.Desert); var element2 = AddElement(100, 300); @@ -54,13 +57,8 @@ public GraphViewModel(IInspectorTool inspectorTool) var element3 = AddElement(400, 250); - Connections.Add(new ConnectionViewModel( - element1.OutputConnector, - element3.InputConnectors[0])); - - Connections.Add(new ConnectionViewModel( - element2.OutputConnector, - element3.InputConnectors[1])); + Connections.Add(element1.OutputConnectors[0].Connect(element3.InputConnectors[0])); + Connections.Add(element2.OutputConnectors[0].Connect(element3.InputConnectors[1])); element1.IsSelected = true; } @@ -77,11 +75,11 @@ public ConnectionViewModel OnConnectionDragStarted(ConnectorViewModel sourceConn { if (!(sourceConnector is OutputConnectorViewModel)) return null; + var tt = sourceConnector.Type; - var connection = new ConnectionViewModel((OutputConnectorViewModel) sourceConnector) - { - ToPosition = currentDragPoint - }; + var connection = sourceConnector.GetNewConnection(); + connection.ToPosition = currentDragPoint; + Connections.Add(connection); @@ -91,7 +89,7 @@ public ConnectionViewModel OnConnectionDragStarted(ConnectorViewModel sourceConn public void OnConnectionDragging(Point currentDragPoint, ConnectionViewModel connection) { // If current drag point is close to an input connector, show its snapped position. - var nearbyConnector = FindNearbyInputConnector(currentDragPoint); + var nearbyConnector = FindNearbyInputConnector(currentDragPoint, connection.ConnectionType); connection.ToPosition = (nearbyConnector != null) ? nearbyConnector.Position : currentDragPoint; @@ -99,7 +97,7 @@ public void OnConnectionDragging(Point currentDragPoint, ConnectionViewModel con public void OnConnectionDragCompleted(Point currentDragPoint, ConnectionViewModel newConnection, ConnectorViewModel sourceConnector) { - var nearbyConnector = FindNearbyInputConnector(currentDragPoint); + var nearbyConnector = FindNearbyInputConnector(currentDragPoint, newConnection.ConnectionType); if (nearbyConnector == null || sourceConnector.Element == nearbyConnector.Element) { @@ -107,17 +105,13 @@ public void OnConnectionDragCompleted(Point currentDragPoint, ConnectionViewMode return; } - var existingConnection = nearbyConnector.Connection; - if (existingConnection != null) - Connections.Remove(existingConnection); - newConnection.To = nearbyConnector; } - private InputConnectorViewModel FindNearbyInputConnector(Point mousePosition) + private InputConnectorViewModel FindNearbyInputConnector(Point mousePosition, Type t) { return Elements.SelectMany(x => x.InputConnectors) - .FirstOrDefault(x => AreClose(x.Position, mousePosition, 10)); + .FirstOrDefault(x => x.Type == t && AreClose(x.Position, mousePosition, 10)); } private static bool AreClose(Point point1, Point point2, double distance) diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/InputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/InputConnectorViewModel.cs deleted file mode 100644 index a8ab77fc..00000000 --- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/InputConnectorViewModel.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Windows.Media; -using System.Windows.Media.Imaging; - -namespace Gemini.Demo.Modules.FilterDesigner.ViewModels -{ - public class InputConnectorViewModel : ConnectorViewModel - { - public event EventHandler SourceChanged; - - public override ConnectorDirection ConnectorDirection - { - get { return ConnectorDirection.Input; } - } - - private ConnectionViewModel _connection; - public ConnectionViewModel Connection - { - get { return _connection; } - set - { - if (_connection != null) - _connection.From.Element.OutputChanged -= OnSourceElementOutputChanged; - _connection = value; - if (_connection != null) - _connection.From.Element.OutputChanged += OnSourceElementOutputChanged; - RaiseSourceChanged(); - NotifyOfPropertyChange(() => Connection); - } - } - - private void OnSourceElementOutputChanged(object sender, EventArgs e) - { - RaiseSourceChanged(); - } - - public BitmapSource Value - { - get - { - if (Connection == null || Connection.From == null) - return null; - - return Connection.From.Value; - } - } - - public InputConnectorViewModel(ElementViewModel element, string name, Color color) - : base(element, name, color) - { - - } - - private void RaiseSourceChanged() - { - var handler = SourceChanged; - if (handler!= null) - handler(this, EventArgs.Empty); - } - } -} \ No newline at end of file diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/JoinAnyBlock.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/JoinAnyBlock.cs new file mode 100644 index 00000000..bcdb88c1 --- /dev/null +++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/JoinAnyBlock.cs @@ -0,0 +1,41 @@ +using Gridsum.DataflowEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; + +namespace Gemini.Demo.Modules.FilterDesigner +{ + public class JoinAny + { + public Task Completion => throw new NotImplementedException(); + public Dataflow Target1; + public Dataflow Target2; + public Dataflow<(T1, T2), (T1, T2)> source; + public bool first; + T1 I1; + T2 I2; + public JoinAny() + { + Target1 = new BufferBlock(new DataflowBlockOptions()).ToDataflow(); + Target2 = new BufferBlock(new DataflowBlockOptions()).ToDataflow(); + Target1.OutputBlock.AsObservable().Subscribe(x => _in1(x)); + Target2.OutputBlock.AsObservable().Subscribe(x => _in2(x)); + + source = new BufferBlock<(T1, T2)>().ToDataflow(); + + } + private void _in2(T2 x) + { + I2 = x; + if (I1 != null) source.SendAsync((I1, I2)); + } + private void _in1(T1 x) + { + I1 = x; + if (I2 != null) source.SendAsync((I1, I2)); + } + } +} diff --git a/src/Gemini.Demo/Modules/FilterDesigner/Views/GraphView.xaml b/src/Gemini.Demo/Modules/FilterDesigner/Views/GraphView.xaml index 28c403ff..c67b9f33 100644 --- a/src/Gemini.Demo/Modules/FilterDesigner/Views/GraphView.xaml +++ b/src/Gemini.Demo/Modules/FilterDesigner/Views/GraphView.xaml @@ -8,6 +8,7 @@ xmlns:vm="clr-namespace:Gemini.Demo.Modules.FilterDesigner.ViewModels" mc:Ignorable="d" d:DesignHeight="500" d:DesignWidth="700" + xmlns:dd="clr-namespace:Gemini.Demo.Modules.FilterDesigner.Design" d:DataContext="{d:DesignInstance dd:DesignTimeGraphViewModel, IsDesignTimeCreatable=True}" Background="WhiteSmoke" Focusable="True"> @@ -39,14 +40,14 @@ - +