forked from chickensoft-games/GodotTestDriver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGraphNodeDriver.cs
263 lines (227 loc) · 8.74 KB
/
GraphNodeDriver.cs
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
256
257
258
259
260
261
262
263
namespace Chickensoft.GodotTestDriver.Drivers;
using System;
using Godot;
using GodotTestDriver.Input;
using JetBrains.Annotations;
/// <summary>
/// Driver for a <see cref="GraphNode"/>
/// </summary>
/// <typeparam name="T">GraphNode type.</typeparam>
[PublicAPI]
public class GraphNodeDriver<T> : ControlDriver<T> where T : GraphNode
{
/// <summary>
/// Creates a new generic GraphNodeDriver.
/// </summary>
/// <param name="producer">Producer that creates a GraphNode subclass.</param>
/// <param name="description">Driver description.</param>
public GraphNodeDriver(Func<T> producer, string description = "") : base(producer, description)
{
}
/// <summary>
/// The title of the node.
/// </summary>
public string Title => PresentRoot.Title;
/// <summary>
/// The offset of the node inside the graph.
/// </summary>
public Vector2 Offset => PresentRoot.PositionOffset;
/// <summary>
/// The relative position and size of the node.
/// </summary>
public Rect2 Rect => PresentRoot.GetRect();
/// <summary>
/// Whether the node is currently selected.
/// </summary>
public bool Selected => PresentRoot.Selected;
/// <summary>
/// The amount of input ports the node has.
/// </summary>
public int InputPortCount => PresentRoot.GetInputPortCount();
/// <summary>
/// The amount of output ports the node has.
/// </summary>
public int OutputPortCount => PresentRoot.GetOutputPortCount();
/// <summary>
/// Returns the port type of the given port.
/// </summary>
/// <param name="port">Connection port.</param>
/// <exception cref="ArgumentException" />
public int GetPortType(Port port)
{
if (!port.IsDefined)
{
throw new ArgumentException("Port is not defined.");
}
if (port.IsInput)
{
if (InputPortCount < port.PortIndex)
{
throw new ArgumentException("Port index is out of range.");
}
return PresentRoot.GetInputPortType(port.PortIndex);
}
if (OutputPortCount < port.PortIndex)
{
throw new ArgumentException("Port index is out of range.");
}
return PresentRoot.GetOutputPortType(port.PortIndex);
}
/// <summary>
/// Global position of a spot where the node can be safely clicked and dragged. Will fail if the node is not visible.
/// </summary>
protected virtual Vector2 SelectionSpot
{
get
{
var node = VisibleRoot;
var rect = node.GetGlobalRect();
// we assume that a position 5 pixels below the top border horizontally centered is a safe selection
// spot as the node will have a title there.
return rect.Position + new Vector2(rect.Size.X / 2, 5);
}
}
/// <summary>
/// Drags the node by the given amount of pixels.
/// </summary>
/// <param name="delta">Change in distance.</param>
public void DragBy(Vector2 delta)
{
var dragStart = SelectionSpot;
var dragEnd = dragStart + delta;
// drag it
Viewport.DragMouse(dragStart, dragEnd);
}
/// <summary>
/// Drags the node by the given amount of pixels.
/// </summary>
/// <param name="x">Horizontal cartesian coordinate component.</param>
/// <param name="y">Vertical cartesian coordinate component.</param>
public void DragBy(float x, float y)
{
DragBy(new Vector2(x, y));
}
/// <summary>
/// Drags the node by a multiple of its own size multiplied by the given factor.
/// </summary>
/// <param name="delta">Change in distance.</param>
public void DragByOwnSize(Vector2 delta)
{
var node = VisibleRoot;
var rect = node.GetRect();
DragBy(new Vector2(rect.Size.X * delta.X, rect.Size.X * delta.Y));
}
/// <summary>
/// Drags the node by a multiple of its own size multiplied by the given factor.
/// </summary>
/// <param name="x">Horizontal cartesian coordinate component.</param>
/// <param name="y">Vertical cartesian coordinate component.</param>
public void DragByOwnSize(float x, float y)
{
DragByOwnSize(new Vector2(x, y));
}
/// <summary>
/// Selects the given node by clicking on it. Same as <see cref="ClickAtSelectionSpot"/>.
/// </summary>
public void Select()
{
ClickAtSelectionSpot();
}
/// <summary>
/// Clicks the mouse at the safe selection spot of this graph node.
/// </summary>
/// <param name="button">Button to use.</param>
public void ClickAtSelectionSpot(MouseButton button = MouseButton.Left)
{
Viewport.ClickMouseAt(SelectionSpot, button);
}
/// <summary>
/// Drags a connection from the given source port of this node to the given target port of the given target node.
/// </summary>
/// <param name="sourcePort">Source port.</param>
/// <param name="targetNode">Target node.</param>
/// <param name="targetPort">Target node connection port.</param>
/// <exception cref="ArgumentException"/>
public void DragConnection(Port sourcePort, GraphNodeDriver<T> targetNode, Port targetPort)
{
if (!sourcePort.IsDefined)
{
throw new ArgumentException("Source port is not defined.");
}
if (!targetPort.IsDefined)
{
throw new ArgumentException("Target port is not defined.");
}
var thisRoot = VisibleRoot;
var targetRoot = targetNode.VisibleRoot;
if (sourcePort.IsInput && sourcePort.PortIndex >= thisRoot.GetInputPortCount())
{
throw new ArgumentException($"Node has no input port at the given index {sourcePort.PortIndex}.");
}
if (sourcePort.IsOutput && sourcePort.PortIndex >= thisRoot.GetOutputPortCount())
{
throw new ArgumentException($"Node has no output port at the given index {sourcePort.PortIndex}.");
}
if (targetPort.IsInput && targetPort.PortIndex >= targetRoot.GetInputPortCount())
{
throw new ArgumentException(
$"Target node has no input port at the given index {targetPort.PortIndex}.");
}
if (targetPort.IsOutput && targetPort.PortIndex >= targetRoot.GetOutputPortCount())
{
throw new ArgumentException(
$"Target node has no output port at the given index {targetPort.PortIndex}.");
}
var startPosition = sourcePort.IsInput
? thisRoot.GetInputPortPosition(sourcePort.PortIndex)
: thisRoot.GetOutputPortPosition(sourcePort.PortIndex);
var endPosition = targetPort.IsInput
? targetRoot.GetInputPortPosition(targetPort.PortIndex)
: targetRoot.GetOutputPortPosition(targetPort.PortIndex);
Viewport.DragMouse(startPosition + thisRoot.GlobalPosition,
endPosition + targetRoot.GlobalPosition);
}
/// <summary>
/// Drags a connection from the given source port of this node to a position relative to this port.
/// </summary>
/// <param name="sourcePort">Source port.</param>
/// <param name="relativePosition">Position offset.</param>
/// <exception cref="ArgumentException"/>
public void DragConnection(Port sourcePort, Vector2 relativePosition)
{
if (!sourcePort.IsDefined)
{
throw new ArgumentException("Source port is not defined.");
}
var thisRoot = VisibleRoot;
if (sourcePort.IsInput && sourcePort.PortIndex >= thisRoot.GetInputPortCount())
{
throw new ArgumentException($"Node has no input port at the given index {sourcePort.PortIndex}.");
}
if (sourcePort.IsOutput && sourcePort.PortIndex >= thisRoot.GetOutputPortCount())
{
throw new ArgumentException($"Node has no output port at the given index {sourcePort.PortIndex}.");
}
var startPosition = sourcePort.IsInput
? thisRoot.GetInputPortPosition(sourcePort.PortIndex)
: thisRoot.GetOutputPortPosition(sourcePort.PortIndex);
var endPosition = startPosition + relativePosition;
Viewport.DragMouse(startPosition + thisRoot.GlobalPosition,
endPosition + thisRoot.GlobalPosition);
}
}
/// <summary>
/// Driver for a <see cref="GraphNode"/>
/// </summary>
[PublicAPI]
public sealed class GraphNodeDriver : GraphNodeDriver<GraphNode>
{
/// <summary>
/// Creates a new GraphNodeDriver.
/// </summary>
/// <param name="producer">Producer that creates a GraphNode subclass.</param>
/// <param name="description">Driver description.</param>
public GraphNodeDriver(Func<GraphNode> producer, string description = "") : base(producer, description)
{
}
}