CraftSynth.ImageEditor – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System;
2 using System.Drawing;
3 using System.Drawing.Drawing2D;
4 using System.Globalization;
5 using System.Runtime.Serialization;
6 using System.Windows.Forms;
7  
8 namespace CraftSynth.ImageEditor
9 {
10 /// <summary>
11 /// Line graphic object
12 /// </summary>
13 //[Serializable]
14 public class DrawLine : DrawObject
15 {
16 private Point startPoint;
17 private Point endPoint;
18  
19 private const string entryStart = "Start";
20 private const string entryEnd = "End";
21  
22 /// <summary>
23 /// Graphic objects for hit test
24 /// </summary>
25 private GraphicsPath areaPath = null;
26  
27 private Pen areaPen = null;
28 private Region areaRegion = null;
29  
30 private bool _disposed = false;
31  
32 public DrawLine()
33 {
34 startPoint.X = 0;
35 startPoint.Y = 0;
36 endPoint.X = 1;
37 endPoint.Y = 1;
38 ZOrder = 0;
39  
40 Initialize();
41 }
42  
43 #region Destruction
44 protected override void Dispose(bool disposing)
45 {
46 if (!this._disposed)
47 {
48 if (disposing)
49 {
50 // Free any managed objects here.
51 if (this.areaPath!=null)
52 {
53 this.areaPath.Dispose();
54 }
55 if (this.areaPen!=null)
56 {
57 this.areaPen.Dispose();
58 }
59 if (this.areaRegion!=null)
60 {
61 this.areaRegion.Dispose();
62 }
63 }
64  
65 // Free any unmanaged objects here.
66  
67 this._disposed = true;
68 }
69 base.Dispose(disposing);
70 }
71  
72 ~DrawLine()
73 {
74 this.Dispose(false);
75 }
76 #endregion
77  
78 public DrawLine(int x1, int y1, int x2, int y2, Color lineColor, int lineWidth, DrawingPens.PenType penType, LineCap endCap)
79 {
80 startPoint.X = x1;
81 startPoint.Y = y1;
82 endPoint.X = x2;
83 endPoint.Y = y2;
84 Color = lineColor;
85 PenWidth = lineWidth;
86 PenType = penType;
87 EndCap = endCap;
88 ZOrder = 0;
89 TipText = String.Format("Line Start @ {0}-{1}, End @ {2}-{3}", x1, y1, x2, y2);
90  
91 Initialize();
92 }
93  
94 public override void Draw(Graphics g)
95 {
96 g.SmoothingMode = SmoothingMode.AntiAlias;
97  
98 Pen pen;
99 if (DrawPen == null)
100 {
101 pen = new Pen(Color, PenWidth);
102 DrawingPens.SetCurrentPen(ref pen, PenType, EndCap);
103 }
104 else
105 pen = (Pen) DrawPen.Clone();
106 GraphicsPath gp = new GraphicsPath();
107 gp.AddLine(startPoint, endPoint);
108 // Rotate the path about it's center if necessary
109 if (Rotation != 0)
110 {
111 RectangleF pathBounds = gp.GetBounds();
112 Matrix m = new Matrix();
113 m.RotateAt(Rotation, new PointF(pathBounds.Left + (pathBounds.Width / 2), pathBounds.Top + (pathBounds.Height / 2)), MatrixOrder.Append);
114 gp.Transform(m);
115 }
116 g.DrawPath(pen, gp);
117 gp.Dispose();
118 pen.Dispose();
119 }
120  
121 /// <summary>
122 /// Clone this instance
123 /// </summary>
124 public override DrawObject Clone()
125 {
126 DrawLine drawLine = new DrawLine();
127 drawLine.startPoint = startPoint;
128 drawLine.endPoint = endPoint;
129  
130 FillDrawObjectFields(drawLine);
131 return drawLine;
132 }
133  
134 public override int HandleCount
135 {
136 get { return 2; }
137 }
138  
139 /// <summary>
140 /// Get handle point by 1-based number
141 /// </summary>
142 /// <param name="handleNumber"></param>
143 /// <returns></returns>
144 public override Point GetHandle(int handleNumber)
145 {
146 GraphicsPath gp = new GraphicsPath();
147 Matrix m = new Matrix();
148 gp.AddLine(startPoint, endPoint);
149 RectangleF pathBounds = gp.GetBounds();
150 m.RotateAt(Rotation, new PointF(pathBounds.Left + (pathBounds.Width / 2), pathBounds.Top + (pathBounds.Height / 2)), MatrixOrder.Append);
151 gp.Transform(m);
152 Point start, end;
153 start = Point.Truncate(gp.PathPoints[0]);
154 end = Point.Truncate(gp.PathPoints[1]);
155 gp.Dispose();
156 m.Dispose();
157 if (handleNumber == 1)
158 return start;
159 else
160 return end;
161 }
162  
163 /// <summary>
164 /// Hit test.
165 /// Return value: -1 - no hit
166 /// 0 - hit anywhere
167 /// > 1 - handle number
168 /// </summary>
169 /// <param name="point"></param>
170 /// <returns></returns>
171 public override int HitTest(Point point)
172 {
173 if (Selected)
174 for (int i = 1; i <= HandleCount; i++)
175 {
176 GraphicsPath gp = new GraphicsPath();
177 gp.AddRectangle(GetHandleRectangle(i));
178 bool vis = gp.IsVisible(point);
179 gp.Dispose();
180 if (vis)
181 return i;
182 }
183 // OK, so the point is not on a selection handle, is it anywhere else on the line?
184 if (PointInObject(point))
185 return 0;
186 return -1;
187 }
188  
189 protected override bool PointInObject(Point point)
190 {
191 CreateObjects();
192 //return AreaPath.IsVisible(point);
193 return AreaRegion.IsVisible(point);
194 }
195  
196 public override Rectangle GetBounds(Graphics g)
197 {
198 var rectF = areaRegion.GetBounds(g);
199 rectF = GetNormalizedRectangle(rectF);
200 var rect = new Rectangle((int)Math.Floor(rectF.X), (int)Math.Floor(rectF.Y), (int)Math.Ceiling(rectF.Width), (int)Math.Ceiling(rectF.Height));
201 return rect;
202 }
203  
204  
205 public override bool IntersectsWith(Rectangle rectangle)
206 {
207 CreateObjects();
208  
209 return AreaRegion.IsVisible(rectangle);
210 }
211  
212 public override Cursor GetHandleCursor(int handleNumber)
213 {
214 switch (handleNumber)
215 {
216 case 1:
217 case 2:
218 return Cursors.SizeAll;
219 default:
220 return Cursors.Default;
221 }
222 }
223  
224 public override void MoveHandleTo(Point point, int handleNumber)
225 {
226 //GraphicsPath gp = new GraphicsPath();
227 //Matrix m = new Matrix();
228 //if (handleNumber == 1)
229 // gp.AddLine(point, endPoint);
230 //else
231 // gp.AddLine(startPoint, point);
232  
233 //RectangleF pathBounds = gp.GetBounds();
234 //m.RotateAt(Rotation, new PointF(pathBounds.Left + (pathBounds.Width / 2), pathBounds.Top + (pathBounds.Height / 2)), MatrixOrder.Append);
235 //gp.Transform(m);
236 //Point start, end;
237 //start = Point.Truncate(gp.PathPoints[0]);
238 //end = Point.Truncate(gp.PathPoints[1]);
239 //gp.Dispose();
240 //m.Dispose();
241 //if (handleNumber == 1)
242 // startPoint = start;
243 //else
244 // endPoint = end;
245  
246 if (handleNumber == 1)
247 startPoint = point;
248 else
249 endPoint = point;
250  
251 Dirty = true;
252 Invalidate();
253 }
254  
255 public override void Move(int deltaX, int deltaY)
256 {
257 startPoint.X += deltaX;
258 startPoint.Y += deltaY;
259  
260 endPoint.X += deltaX;
261 endPoint.Y += deltaY;
262 Dirty = true;
263 Invalidate();
264 }
265  
266 public override void SaveToStream(SerializationInfo info, int orderNumber, int objectIndex)
267 {
268 info.AddValue(
269 String.Format(CultureInfo.InvariantCulture,
270 "{0}{1}-{2}",
271 entryStart, orderNumber, objectIndex),
272 startPoint);
273  
274 info.AddValue(
275 String.Format(CultureInfo.InvariantCulture,
276 "{0}{1}-{2}",
277 entryEnd, orderNumber, objectIndex),
278 endPoint);
279  
280 base.SaveToStream(info, orderNumber, objectIndex);
281 }
282  
283 public override void LoadFromStream(SerializationInfo info, int orderNumber, int objectIndex)
284 {
285 startPoint = (Point)info.GetValue(
286 String.Format(CultureInfo.InvariantCulture,
287 "{0}{1}-{2}",
288 entryStart, orderNumber, objectIndex),
289 typeof(Point));
290  
291 endPoint = (Point)info.GetValue(
292 String.Format(CultureInfo.InvariantCulture,
293 "{0}{1}-{2}",
294 entryEnd, orderNumber, objectIndex),
295 typeof(Point));
296  
297 base.LoadFromStream(info, orderNumber, objectIndex);
298 }
299  
300 /// <summary>
301 /// Invalidate object.
302 /// When object is invalidated, path used for hit test
303 /// is released and should be created again.
304 /// </summary>
305 protected void Invalidate()
306 {
307 if (AreaPath != null)
308 {
309 AreaPath.Dispose();
310 AreaPath = null;
311 }
312  
313 if (AreaPen != null)
314 {
315 AreaPen.Dispose();
316 AreaPen = null;
317 }
318  
319 if (AreaRegion != null)
320 {
321 AreaRegion.Dispose();
322 AreaRegion = null;
323 }
324 }
325  
326 /// <summary>
327 /// Create graphic objects used for hit test.
328 /// </summary>
329 protected virtual void CreateObjects()
330 {
331 if (AreaPath != null)
332 return;
333  
334 // Create path which contains wide line
335 // for easy mouse selection
336 AreaPath = new GraphicsPath();
337 // Take into account the width of the pen used to draw the actual object
338 AreaPen = new Pen(Color.Black, PenWidth < 7 ? 7 : PenWidth);
339 // Prevent Out of Memory crash when startPoint == endPoint
340 if (startPoint.Equals((Point)endPoint))
341 {
342 endPoint.X++;
343 endPoint.Y++;
344 }
345 AreaPath.AddLine(startPoint.X, startPoint.Y, endPoint.X, endPoint.Y);
346 AreaPath.Widen(AreaPen);
347 // Rotate the path about it's center if necessary
348 if (Rotation != 0)
349 {
350 RectangleF pathBounds = AreaPath.GetBounds();
351 Matrix m = new Matrix();
352 m.RotateAt(Rotation, new PointF(pathBounds.Left + (pathBounds.Width / 2), pathBounds.Top + (pathBounds.Height / 2)), MatrixOrder.Append);
353 AreaPath.Transform(m);
354 m.Dispose();
355 }
356  
357 // Create region from the path
358 AreaRegion = new Region(AreaPath);
359 }
360  
361 protected GraphicsPath AreaPath
362 {
363 get { return areaPath; }
364 set { areaPath = value; }
365 }
366  
367 protected Pen AreaPen
368 {
369 get { return areaPen; }
370 set { areaPen = value; }
371 }
372  
373 protected Region AreaRegion
374 {
375 get { return areaRegion; }
376 set { areaRegion = value; }
377 }
378  
379 #region Helper gunctions
380 public static RectangleF GetNormalizedRectangle(float x1, float y1, float x2, float y2)
381 {
382 if (x2 < x1)
383 {
384 float tmp = x2;
385 x2 = x1;
386 x1 = tmp;
387 }
388  
389 if (y2 < y1)
390 {
391 float tmp = y2;
392 y2 = y1;
393 y1 = tmp;
394 }
395 return new RectangleF(x1, y1, x2 - x1, y2 - y1);
396 }
397  
398 public static RectangleF GetNormalizedRectangle(PointF p1, PointF p2)
399 {
400 return GetNormalizedRectangle(p1.X, p1.Y, p2.X, p2.Y);
401 }
402  
403 public static RectangleF GetNormalizedRectangle(RectangleF r)
404 {
405 return GetNormalizedRectangle(r.X, r.Y, r.X + r.Width, r.Y + r.Height);
406 }
407 #endregion
408 }
409 }