1 | using System;
|
---|
2 | using System.Drawing;
|
---|
3 | using System.Drawing.Drawing2D;
|
---|
4 |
|
---|
5 | namespace Netron.Diagramming.Core {
|
---|
6 | // ----------------------------------------------------------------------
|
---|
7 | /// <summary>
|
---|
8 | /// The default connector. Represents an endpoint of a connection or a
|
---|
9 | /// location of a bundle to which a connection can be attached.
|
---|
10 | /// </summary>
|
---|
11 | // ----------------------------------------------------------------------
|
---|
12 | public partial class Connector : ConnectorBase {
|
---|
13 | #region Fields
|
---|
14 |
|
---|
15 | // ------------------------------------------------------------------
|
---|
16 | /// <summary>
|
---|
17 | /// Implementation of IVersion - the current version of
|
---|
18 | /// Connector.
|
---|
19 | /// </summary>
|
---|
20 | // ------------------------------------------------------------------
|
---|
21 | protected const double connectorVersion = 1.0;
|
---|
22 |
|
---|
23 | // ------------------------------------------------------------------
|
---|
24 | /// <summary>
|
---|
25 | /// Specifies how the connector is drawn on the canvas when 'IsVisible'
|
---|
26 | /// is true. The default style is 'Simple', which is a transparent
|
---|
27 | /// background with a blue 'x' (similar to Visio).
|
---|
28 | /// </summary>
|
---|
29 | // ------------------------------------------------------------------
|
---|
30 | protected ConnectorStyle myStyle = ConnectorStyle.Simple;
|
---|
31 |
|
---|
32 | #endregion
|
---|
33 |
|
---|
34 | #region Properties
|
---|
35 |
|
---|
36 | // ------------------------------------------------------------------
|
---|
37 | /// <summary>
|
---|
38 | /// Gets the current version.
|
---|
39 | /// </summary>
|
---|
40 | // ------------------------------------------------------------------
|
---|
41 | public override double Version {
|
---|
42 | get {
|
---|
43 | return connectorVersion;
|
---|
44 | }
|
---|
45 | }
|
---|
46 |
|
---|
47 | // ------------------------------------------------------------------
|
---|
48 | /// <summary>
|
---|
49 | /// Gets or sets how the connector is drawn on the canvas when
|
---|
50 | /// 'IsVisible' is true.
|
---|
51 | /// </summary>
|
---|
52 | // ------------------------------------------------------------------
|
---|
53 | public ConnectorStyle ConnectorStyle {
|
---|
54 | get {
|
---|
55 | return this.myStyle;
|
---|
56 | }
|
---|
57 | set {
|
---|
58 | this.myStyle = value;
|
---|
59 | }
|
---|
60 | }
|
---|
61 |
|
---|
62 | // ------------------------------------------------------------------
|
---|
63 | /// <summary>
|
---|
64 | /// Gets the friendly name of the entity to be displayed in the UI
|
---|
65 | /// </summary>
|
---|
66 | /// <value></value>
|
---|
67 | // ------------------------------------------------------------------
|
---|
68 | public override string EntityName {
|
---|
69 | get { return "Connector"; }
|
---|
70 | }
|
---|
71 |
|
---|
72 | // ------------------------------------------------------------------
|
---|
73 | /// <summary>
|
---|
74 | /// The bounds of the paintable entity.
|
---|
75 | /// </summary>
|
---|
76 | /// <value></value>
|
---|
77 | // ------------------------------------------------------------------
|
---|
78 | public override Rectangle Rectangle {
|
---|
79 | get {
|
---|
80 | return new Rectangle(Point.X - 2, Point.Y - 2, 4, 4);
|
---|
81 | }
|
---|
82 | //set { Point = value.Location;
|
---|
83 | //TODO: think about what to do when setting the size }
|
---|
84 | }
|
---|
85 |
|
---|
86 | #endregion
|
---|
87 |
|
---|
88 | #region Constructor
|
---|
89 |
|
---|
90 | // ------------------------------------------------------------------
|
---|
91 | /// <summary>
|
---|
92 | /// Initializes a new instance of the <see cref="T:Connector"/> class.
|
---|
93 | /// </summary>
|
---|
94 | /// <param name="site">The site.</param>
|
---|
95 | // ------------------------------------------------------------------
|
---|
96 | public Connector(IModel site)
|
---|
97 | : base(site) {
|
---|
98 | }
|
---|
99 |
|
---|
100 | // ------------------------------------------------------------------
|
---|
101 | /// <summary>
|
---|
102 | /// Initializes a new instance of the <see cref="T:Connector"/> class.
|
---|
103 | /// </summary>
|
---|
104 | /// <param name="p">The p.</param>
|
---|
105 | /// <param name="site">The site.</param>
|
---|
106 | // ------------------------------------------------------------------
|
---|
107 | public Connector(Point p, IModel site)
|
---|
108 | : base(p, site) {
|
---|
109 | }
|
---|
110 |
|
---|
111 | // ------------------------------------------------------------------
|
---|
112 | /// <summary>
|
---|
113 | /// Initializes a new instance of the <see cref="T:Connector"/> class.
|
---|
114 | /// </summary>
|
---|
115 | /// <param name="p">The p.</param>
|
---|
116 | // ------------------------------------------------------------------
|
---|
117 | public Connector(Point p)
|
---|
118 | : base(p) {
|
---|
119 | }
|
---|
120 |
|
---|
121 | #endregion
|
---|
122 |
|
---|
123 | #region Methods
|
---|
124 |
|
---|
125 | // ------------------------------------------------------------------
|
---|
126 | /// <summary>
|
---|
127 | /// Paints the connector on the canvas.
|
---|
128 | /// </summary>
|
---|
129 | /// <param name="g"></param>
|
---|
130 | // ------------------------------------------------------------------
|
---|
131 | public override void Paint(Graphics g) {
|
---|
132 | if (g == null) {
|
---|
133 | throw new ArgumentNullException(
|
---|
134 | "The Graphics object is 'null'");
|
---|
135 | }
|
---|
136 |
|
---|
137 | if (Hovered || IsSelected) {
|
---|
138 | Rectangle area = Rectangle;
|
---|
139 | area.Inflate(3, 3);
|
---|
140 | g.DrawRectangle(
|
---|
141 | ArtPalette.ConnectionHighlightPen,
|
---|
142 | area);
|
---|
143 | //g.FillRectangle(
|
---|
144 | // Brushes.Green,
|
---|
145 | // Point.X - 4,
|
---|
146 | // Point.Y - 4,
|
---|
147 | // 8,
|
---|
148 | // 8);
|
---|
149 | } else {
|
---|
150 | if (Visible) {
|
---|
151 | switch (this.myStyle) {
|
---|
152 | case ConnectorStyle.Simple:
|
---|
153 | DrawSimpleConnector(g);
|
---|
154 | break;
|
---|
155 |
|
---|
156 | case ConnectorStyle.Round:
|
---|
157 | break;
|
---|
158 |
|
---|
159 | case ConnectorStyle.Square:
|
---|
160 | DrawSquareConnector(g);
|
---|
161 | break;
|
---|
162 | }
|
---|
163 |
|
---|
164 | if (this.mShowName) {
|
---|
165 | DrawName(g);
|
---|
166 | }
|
---|
167 | }
|
---|
168 | }
|
---|
169 | }
|
---|
170 |
|
---|
171 | // ------------------------------------------------------------------
|
---|
172 | /// <summary>
|
---|
173 | /// Draws the name of this connector.
|
---|
174 | /// </summary>
|
---|
175 | /// <param name="g">Graphics</param>
|
---|
176 | // ------------------------------------------------------------------
|
---|
177 | void DrawName(Graphics g) {
|
---|
178 | Size size = Size.Round(
|
---|
179 | g.MeasureString(mName, mFont));
|
---|
180 |
|
---|
181 | int xOffset = (size.Width - Rectangle.Width) / 2;
|
---|
182 | int yOffset = (size.Height - Rectangle.Height) / 2;
|
---|
183 |
|
---|
184 | System.Drawing.Point location = Rectangle.Location;
|
---|
185 |
|
---|
186 | switch (this.mNameLocation) {
|
---|
187 | case ConnectorNameLocation.Top:
|
---|
188 | location = new Point(
|
---|
189 | Rectangle.X - xOffset,
|
---|
190 | Rectangle.Y - size.Height);
|
---|
191 | break;
|
---|
192 |
|
---|
193 | case ConnectorNameLocation.Bottom:
|
---|
194 | location = new Point(
|
---|
195 | Rectangle.X - xOffset,
|
---|
196 | Rectangle.Bottom + size.Height);
|
---|
197 | break;
|
---|
198 |
|
---|
199 | case ConnectorNameLocation.Left:
|
---|
200 | location = new Point(
|
---|
201 | Rectangle.X - size.Width,
|
---|
202 | Rectangle.Y - yOffset);
|
---|
203 | break;
|
---|
204 |
|
---|
205 | case ConnectorNameLocation.Right:
|
---|
206 | location = new Point(
|
---|
207 | Rectangle.Right,
|
---|
208 | Rectangle.Y - yOffset);
|
---|
209 | break;
|
---|
210 | }
|
---|
211 |
|
---|
212 | Rectangle textArea = new Rectangle(location, size);
|
---|
213 | StringFormat format = new StringFormat();
|
---|
214 | format.FormatFlags = StringFormatFlags.FitBlackBox;
|
---|
215 | g.DrawString(
|
---|
216 | mName,
|
---|
217 | mFont,
|
---|
218 | new SolidBrush(mForeColor),
|
---|
219 | location);
|
---|
220 | }
|
---|
221 |
|
---|
222 | // ------------------------------------------------------------------
|
---|
223 | /// <summary>
|
---|
224 | /// Draws a blue 'x' using 'Dot' as the line style, with a transparent
|
---|
225 | /// color.
|
---|
226 | /// </summary>
|
---|
227 | /// <param name="g">Graphics</param>
|
---|
228 | // ------------------------------------------------------------------
|
---|
229 | protected virtual void DrawSimpleConnector(Graphics g) {
|
---|
230 | Pen pen = ArtPalette.GetSimpleConnectorPenStyle().DrawingPen();
|
---|
231 | Brush brush =
|
---|
232 | ArtPalette.GetSimpleConnectorPaintStyle().GetBrush(
|
---|
233 | this.Rectangle);
|
---|
234 |
|
---|
235 | GraphicsPath path = new GraphicsPath();
|
---|
236 | // Diagonal line from top left to bottom right.
|
---|
237 | g.DrawLine(pen, this.TopLeftCorner, this.BottomRightCorner);
|
---|
238 |
|
---|
239 |
|
---|
240 | // Diagonal line from top right to bottom lrft.
|
---|
241 | g.DrawLine(pen, this.TopRightCorner, this.BottomLeftCorner);
|
---|
242 | }
|
---|
243 |
|
---|
244 | protected virtual void DrawSquareConnector(Graphics g) {
|
---|
245 | Pen pen = ArtPalette.GetSimpleConnectorPenStyle().DrawingPen();
|
---|
246 | Brush brush = ArtPalette.GetSimpleConnectorPaintStyle().GetBrush(this.Rectangle);
|
---|
247 | g.DrawRectangle(pen, this.Rectangle);
|
---|
248 | }
|
---|
249 |
|
---|
250 |
|
---|
251 | // ------------------------------------------------------------------
|
---|
252 | /// <summary>
|
---|
253 | /// Tests if the mouse hits this connector.
|
---|
254 | /// </summary>
|
---|
255 | /// <param name="p">Point</param>
|
---|
256 | /// <returns>bool</returns>
|
---|
257 | // ------------------------------------------------------------------
|
---|
258 | public override bool Hit(Point p) {
|
---|
259 | Point a = p;
|
---|
260 | Point b = Point;
|
---|
261 | b.Offset(-7, -7);
|
---|
262 | //a.Offset(-1,-1);
|
---|
263 | Rectangle r = new Rectangle(a, new Size(0, 0));
|
---|
264 | Rectangle d = new Rectangle(b, new Size(15, 15));
|
---|
265 | return d.Contains(r);
|
---|
266 | }
|
---|
267 |
|
---|
268 | // ------------------------------------------------------------------
|
---|
269 | /// <summary>
|
---|
270 | /// Invalidates the connector
|
---|
271 | /// </summary>
|
---|
272 | // ------------------------------------------------------------------
|
---|
273 | public override void Invalidate() {
|
---|
274 | Point p = Point;
|
---|
275 | p.Offset(-5, -5);
|
---|
276 | if (Model != null)
|
---|
277 | Model.RaiseOnInvalidateRectangle(
|
---|
278 | new Rectangle(p, new Size(10, 10)));
|
---|
279 | }
|
---|
280 |
|
---|
281 | // ------------------------------------------------------------------
|
---|
282 | /// <summary>
|
---|
283 | /// Moves the connector with the given shift-vector.
|
---|
284 | /// </summary>
|
---|
285 | /// <param name="p">Point</param>
|
---|
286 | // ------------------------------------------------------------------
|
---|
287 | public override void MoveBy(Point p) {
|
---|
288 | Point pt = new Point(this.Point.X + p.X, this.Point.Y + p.Y);
|
---|
289 | IConnection con = null;
|
---|
290 | Point p1 = Point.Empty, p2 = Point.Empty;
|
---|
291 |
|
---|
292 | Rectangle rec = new Rectangle(
|
---|
293 | Point.X - 10,
|
---|
294 | Point.Y - 10,
|
---|
295 | 20,
|
---|
296 | 20);
|
---|
297 |
|
---|
298 | this.Point = pt;
|
---|
299 |
|
---|
300 | #region Case of connection
|
---|
301 | if (typeof(IConnection).IsInstanceOfType(this.Parent)) {
|
---|
302 | (Parent as IConnection).Invalidate();
|
---|
303 | }
|
---|
304 | #endregion
|
---|
305 |
|
---|
306 | #region Case of attached connectors
|
---|
307 | for (int k = 0; k < AttachedConnectors.Count; k++) {
|
---|
308 | if (typeof(IConnection).IsInstanceOfType(AttachedConnectors[k].Parent)) {
|
---|
309 | //keep a reference to the two points so we can invalidate the region afterwards
|
---|
310 | con = AttachedConnectors[k].Parent as IConnection;
|
---|
311 | p1 = con.From.Point;
|
---|
312 | p2 = con.To.Point;
|
---|
313 | }
|
---|
314 | AttachedConnectors[k].MoveBy(p);
|
---|
315 | if (con != null) {
|
---|
316 | //invalidate the 'before the move'-region
|
---|
317 | Rectangle f = new Rectangle(p1, new Size(10, 10));
|
---|
318 | Rectangle t = new Rectangle(p2, new Size(10, 10));
|
---|
319 | Model.RaiseOnInvalidateRectangle(Rectangle.Union(f, t));
|
---|
320 | //finally, invalidate the region where the connection is now
|
---|
321 | (AttachedConnectors[k].Parent as IConnection).Invalidate();
|
---|
322 | }
|
---|
323 | }
|
---|
324 | #endregion
|
---|
325 | //invalidate this connector, since it's been moved
|
---|
326 | Invalidate(rec);//before the move
|
---|
327 | this.Invalidate();//after the move
|
---|
328 |
|
---|
329 | }
|
---|
330 |
|
---|
331 | // ------------------------------------------------------------------
|
---|
332 | /// <summary>
|
---|
333 | /// Moves the connector with the given shift-vector
|
---|
334 | /// </summary>
|
---|
335 | /// <param name="x">The x.</param>
|
---|
336 | /// <param name="y">The y.</param>
|
---|
337 | // ------------------------------------------------------------------
|
---|
338 | public void MoveBy(int x, int y) {
|
---|
339 | Point pt = new Point(x, y);
|
---|
340 | MoveBy(pt);
|
---|
341 | }
|
---|
342 |
|
---|
343 | #endregion
|
---|
344 | }
|
---|
345 | }
|
---|