forked from Wouterdek/NodeNetwork
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEndpoint.cs
More file actions
255 lines (229 loc) · 8.27 KB
/
Copy pathEndpoint.cs
File metadata and controls
255 lines (229 loc) · 8.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using DynamicData;
using NodeNetwork.Utilities;
using ReactiveUI;
using Splat;
namespace NodeNetwork.ViewModels
{
/// <summary>
/// Enum type that indicates the position of the port in the endpoint
/// </summary>
public enum PortPosition
{
Left, Right
}
/// <summary>
/// Enum types that indicates the visibility behaviour of an endpoint
/// </summary>
public enum EndpointVisibility
{
/// <summary>
/// Automatically decide whether or not to show this endpoint based on the collapse status of the node
/// </summary>
Auto,
/// <summary>
/// Always show this endpoint, even if the node is collapsed
/// </summary>
AlwaysVisible,
/// <summary>
/// Always hide this endpoint
/// </summary>
AlwaysHidden
}
/// <summary>
/// Parent interface for the inputs/outputs of nodes between which connections can be made.
/// </summary>
public abstract class Endpoint : ReactiveObject
{
#region Parent
/// <summary>
/// The node that owns this endpoint
/// </summary>
public NodeViewModel Parent
{
get => _parent;
internal set => this.RaiseAndSetIfChanged(ref _parent, value);
}
private NodeViewModel _parent;
#endregion
#region Name
/// <summary>
/// The name of this endpoint.
/// In the default view, this string is displayed in the node next to the port.
/// </summary>
public string Name
{
get => _name;
set => this.RaiseAndSetIfChanged(ref _name, value);
}
private string _name = "";
#endregion
#region Group
/// <summary>
/// The group the end point belongs to. Can be null.
/// </summary>
public EndpointGroup Group
{
get => _group;
set => this.RaiseAndSetIfChanged(ref _group, value);
}
private EndpointGroup _group;
#endregion
#region Icon
/// <summary>
/// The icon displayed near the endpoint label
/// If this is null, no icon is displayed.
/// </summary>
public IBitmap Icon
{
get => _icon;
set => this.RaiseAndSetIfChanged(ref _icon, value);
}
private IBitmap _icon;
#endregion
#region Editor
/// <summary>
/// The editor viewmodel associated with this endpoint.
/// It can be used to configure the behaviour of this endpoint or provide a default value when there is no connection.
/// The editor, if not null, will be displayed in the node, under the endpoint name next to the port.
/// </summary>
public NodeEndpointEditorViewModel Editor
{
get => _editor;
set => this.RaiseAndSetIfChanged(ref _editor, value);
}
private NodeEndpointEditorViewModel _editor;
#endregion
#region Port
/// <summary>
/// The viewmodel for the port of this endpoint. (the part the user can create connections from.)
/// </summary>
public PortViewModel Port
{
get => _port;
set => this.RaiseAndSetIfChanged(ref _port, value);
}
private PortViewModel _port;
#endregion
#region PortPosition
/// <summary>
/// Where should the port be positioned in the endpoint?
/// </summary>
public PortPosition PortPosition
{
get => _portPosition;
set => this.RaiseAndSetIfChanged(ref _portPosition, value);
}
private PortPosition _portPosition;
#endregion
#region Connections
/// <summary>
/// List of connections between this endpoint and other endpoints in the network.
/// To add a new connection, do not add it here but instead add it to the Connections property in the network.
/// </summary>
public IObservableList<ConnectionViewModel> Connections { get; }
#endregion
#region MaxConnections
/// <summary>
/// The maximum amount of connections this endpoint accepts.
/// When Connections.Count == MaxConnections, the user cannot add more connections to this endpoint
/// until a connection is removed.
/// </summary>
public int MaxConnections
{
get => _maxConnections;
set => this.RaiseAndSetIfChanged(ref _maxConnections, value);
}
private int _maxConnections;
#endregion
#region Visibility
/// <summary>
/// Visibility behaviour of this endpoint
/// </summary>
public EndpointVisibility Visibility
{
get => _visibility;
set => this.RaiseAndSetIfChanged(ref _visibility, value);
}
private EndpointVisibility _visibility;
#endregion
#region SortIndex
/// <summary>
/// Inputs and outputs are sorted by increasing values of SortIndex before being displayed.
/// </summary>
public int SortIndex
{
get => _sortIndex;
set => this.RaiseAndSetIfChanged(ref _sortIndex, value);
}
private int _sortIndex;
#endregion
protected Endpoint()
{
Port = new PortViewModel();
Visibility = EndpointVisibility.Auto;
// Setup parent relationship with Port.
this.WhenAnyValue(vm => vm.Port).PairWithPreviousValue().Subscribe(p =>
{
if (p.OldValue != null)
{
p.OldValue.Parent = null;
}
if (p.NewValue != null)
{
p.NewValue.Parent = this;
}
});
// Setup Parent relationship with Editor.
this.WhenAnyValue(vm => vm.Editor).PairWithPreviousValue().Subscribe(e =>
{
if (e.OldValue != null)
{
e.OldValue.Parent = null;
}
if (e.NewValue != null)
{
e.NewValue.Parent = this;
}
});
// Mirror the port if the endpoint is on the left instead of the right.
this.WhenAnyValue(vm => vm.Port, vm => vm.PortPosition).Subscribe(_ =>
{
if (Port == null)
{
return;
}
Port.IsMirrored = PortPosition == PortPosition.Left;
});
// Setup a binding between the Connections list in the network and in this endpoint,
// selecting only the connections where this endpoint is the input or output.
// We need the latest network connections list, but we want a null value when this endpoint is
// removed from the node, or the node is removed from the network.
var networkConnections = this.WhenAnyValue(
vm => vm.Parent,
vm => vm.Parent.Parent,
vm => vm.Parent.Parent.Connections,
(x, y, z) => Parent?.Parent?.Connections ?? new SourceList<ConnectionViewModel>())
.Switch();
Connections = networkConnections
.AutoRefresh(c => c.Input)
.AutoRefresh(c => c.Output)
.Filter(c => c.Input == this || c.Output == this)
.AsObservableList();
// Setup bindings between port mouse events and connection creation.
this.WhenAnyObservable(vm => vm.Port.ConnectionDragStarted).Subscribe(_ => CreatePendingConnection());
this.WhenAnyObservable(vm => vm.Port.ConnectionPreviewActive).Subscribe(SetConnectionPreview);
this.WhenAnyObservable(vm => vm.Port.ConnectionDragFinished).Subscribe(_ => FinishPendingConnection());
}
protected abstract void CreatePendingConnection();
protected abstract void SetConnectionPreview(bool previewActive);
protected abstract void FinishPendingConnection();
}
}