CraftSynth.ImageEditor – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System;
2 using System.Collections.Generic;
3 using System.Drawing;
4 using System.Drawing.Drawing2D;
5 using System.Windows.Forms;
6  
7 using DocToolkit;
8  
9 namespace CraftSynth.ImageEditor
10 {
11 /// <summary>
12 /// Working area.
13 /// Handles mouse input and draws graphics objects.
14 /// </summary>
15 internal partial class DrawArea : UserControl, IDisposable
16 {
17 #region Constructor, Dispose
18 public DrawArea()
19 {
20 // create list of Layers, with one default active visible layer
21 _layers = new Layers();
22 _layers.CreateNewLayer("Default");
23 _panning = false;
24 _panX = 0;
25 _panY = 0;
26 this.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.DrawArea_MouseWheel);
27 // This call is required by the Windows.Forms Form Designer.
28 InitializeComponent();
29 //DrawImage o = new DrawImage(0, 0);
30 //DrawTools.ToolObject.AddNewObject(this, new DrawImage(0, 0));
31  
32 }
33  
34 // Public implementation of Dispose pattern callable by consumers.
35 public new void Dispose()
36 {
37 this.Dispose(true);
38 GC.SuppressFinalize(this);
39 }
40  
41 // Flag: Has Dispose already been called?
42 bool _disposed = false;
43  
44 // Protected implementation of Dispose pattern.
45 protected override void Dispose(bool disposing)
46 {
47 if (!this._disposed)
48 {
49  
50  
51 if (disposing)
52 {
53 // Free any managed objects here.
54 //
55 if (this._currentBrush != null)
56 {
57 this._currentBrush.Dispose();
58 }
59 if (this.CurrentPen != null)
60 {
61 this._currentPen.Dispose();
62 }
63 if (this._layers != null)
64 {
65 this._layers.Dispose();
66 }
67 if (this.tools != null)
68 {
69 foreach (Tool tool in tools)
70 {
71 if (tool != null)
72 {
73 tool.Dispose();
74 }
75 }
76 }
77 if (this.undoManager != null)
78 {
79 this.undoManager.Dispose();
80 }
81  
82 if (components != null)
83 {
84 components.Dispose();
85 }
86  
87 // Free any unmanaged objects here.
88 }
89  
90 this._disposed = true;
91  
92 }
93 base.Dispose(disposing);
94 }
95  
96 ~DrawArea()
97 {
98 this.Dispose(false);
99 }
100 #endregion Constructor, Dispose
101  
102 #region Enumerations
103 public enum DrawToolType
104 {
105 Pointer,
106 Rectangle,
107 Ellipse,
108 Line,
109 PolyLine,
110 Polygon,
111 Text,
112 Image,
113 Connector,
114 NumberOfDrawTools
115 } ;
116 #endregion Enumerations
117  
118 #region Members
119 private float _zoom = 1.0f;
120 private float _rotation = 0f;
121 private int _panX = 0;
122 private int _panY;
123 private int _originalPanY;
124 private bool _panning = false;
125 private Point lastPoint;
126 private Color _lineColor = Color.Red;
127 private Color _fillColor = Color.White;
128 private bool _drawFilled = false;
129 private int _lineWidth = 5;
130 private LineCap _endCap = LineCap.Round;
131 private Pen _currentPen;
132 private DrawingPens.PenType _penType;
133 private Brush _currentBrush;
134 private FillBrushes.BrushType _brushType;
135  
136 // Define the Layers collection
137 private Layers _layers;
138  
139 private DrawToolType activeTool; // active drawing tool
140 private Tool[] tools; // array of tools
141  
142 // Information about owner form
143 private MainForm owner;
144 private DocManager docManager;
145  
146 // group selection rectangle
147 private Rectangle netRectangle;
148 private bool drawNetRectangle = false;
149  
150 private MainForm myparent;
151  
152 public MainForm MyParent
153 {
154 get { return myparent; }
155 set { myparent = value; }
156 }
157  
158 private UndoManager undoManager;
159 #endregion Members
160  
161 #region Properties
162 /// <summary>
163 /// Allow tools and objects to see the type of brush set
164 /// </summary>
165 public FillBrushes.BrushType BrushType
166 {
167 get { return _brushType; }
168 set { _brushType = value; }
169 }
170  
171 public Brush CurrentBrush
172 {
173 get { return _currentBrush; }
174 set { _currentBrush = value; }
175 }
176  
177 /// <summary>
178 /// Allow tools and objects to see the type of pen set
179 /// </summary>
180 public DrawingPens.PenType PenType
181 {
182 get { return _penType; }
183 set { _penType = value; }
184 }
185  
186 /// <summary>
187 /// Arrow or Rounded.
188 /// </summary>
189 public LineCap EndCap
190 {
191 get { return _endCap; }
192 set { _endCap = value; }
193 }
194  
195 /// <summary>
196 /// Current Drawing Pen
197 /// </summary>
198 public Pen CurrentPen
199 {
200 get { return _currentPen; }
201 set { _currentPen = value; }
202 }
203  
204 /// <summary>
205 /// Current Line Width
206 /// </summary>
207 public int LineWidth
208 {
209 get { return _lineWidth; }
210 set { _lineWidth = value; }
211 }
212  
213 /// <summary>
214 /// Flag determines if objects will be drawn filled or not
215 /// </summary>
216 public bool DrawFilled
217 {
218 get { return _drawFilled; }
219 set { _drawFilled = value; }
220 }
221  
222 /// <summary>
223 /// Color to draw filled objects with
224 /// </summary>
225 public Color FillColor
226 {
227 get { return _fillColor; }
228 set { _fillColor = value; }
229 }
230  
231 /// <summary>
232 /// Color for drawing lines
233 /// </summary>
234 public Color LineColor
235 {
236 get { return _lineColor; }
237 set { _lineColor = value; }
238 }
239  
240 /// <summary>
241 /// Original Y position - used when panning
242 /// </summary>
243 public int OriginalPanY
244 {
245 get { return _originalPanY; }
246 set { _originalPanY = value; }
247 }
248  
249 /// <summary>
250 /// Flag is true if panning active
251 /// </summary>
252 public bool Panning
253 {
254 get { return _panning; }
255 set { _panning = value; }
256 }
257  
258 /// <summary>
259 /// Current pan offset along X-axis
260 /// </summary>
261 public int PanX
262 {
263 get { return _panX; }
264 set { _panX = value; }
265 }
266  
267 /// <summary>
268 /// Current pan offset along Y-axis
269 /// </summary>
270 public int PanY
271 {
272 get { return _panY; }
273 set { _panY = value; }
274 }
275  
276 /// <summary>
277 /// Degrees of rotation of the drawing
278 /// </summary>
279 public float Rotation
280 {
281 get { return _rotation; }
282 set { _rotation = value; }
283 }
284  
285 /// <summary>
286 /// Current Zoom factor
287 /// </summary>
288 public float Zoom
289 {
290 get { return _zoom; }
291 set { _zoom = value; }
292 }
293  
294 /// <summary>
295 /// Group selection rectangle. Used for drawing.
296 /// </summary>
297 public Rectangle NetRectangle
298 {
299 get { return netRectangle; }
300 set { netRectangle = value; }
301 }
302  
303 /// <summary>
304 /// Flag is set to true if group selection rectangle should be drawn.
305 /// </summary>
306 public bool DrawNetRectangle
307 {
308 get { return drawNetRectangle; }
309 set { drawNetRectangle = value; }
310 }
311  
312 /// <summary>
313 /// Reference to the owner form
314 /// </summary>
315 public MainForm Owner
316 {
317 get { return owner; }
318 set { owner = value; }
319 }
320  
321 /// <summary>
322 /// Reference to DocManager
323 /// </summary>
324 public DocManager DocManager
325 {
326 get { return docManager; }
327 set { docManager = value; }
328 }
329  
330 /// <summary>
331 /// Active drawing tool.
332 /// </summary>
333 public DrawToolType ActiveTool
334 {
335 get { return activeTool; }
336 set { activeTool = value; }
337 }
338  
339 /// <summary>
340 /// List of Layers in the drawing
341 /// </summary>
342 public Layers TheLayers
343 {
344 get { return _layers; }
345 set { _layers = value; }
346 }
347  
348 /// <summary>
349 /// Return True if Undo operation is possible
350 /// </summary>
351 public bool CanUndo
352 {
353 get
354 {
355 if (undoManager != null)
356 {
357 return undoManager.CanUndo;
358 }
359  
360 return false;
361 }
362 }
363  
364 /// <summary>
365 /// Return True if Redo operation is possible
366 /// </summary>
367 public bool CanRedo
368 {
369 get
370 {
371 if (undoManager != null)
372 {
373 return undoManager.CanRedo;
374 }
375  
376 return false;
377 }
378 }
379  
380 public Rectangle GetBounds()
381 {
382 int furthestLeft = int.MaxValue;
383 int furthestTop = int.MaxValue;
384 int furthestRight = int.MinValue;
385 int furthestBottom = int.MinValue;
386 Rectangle rect;
387 Graphics g = this.CreateGraphics();
388 if (_layers != null)
389 {
390 int lc = _layers.Count;
391 for (int i = 0; i < lc; i++)
392 {
393 // Console.WriteLine(String.Format("Layer {0} is Visible: {1}", i.ToString(), _layers[i].IsVisible.ToString()));
394 if (_layers[i].IsVisible)
395 {
396 if (_layers[i].Graphics != null)
397 {
398 for (int ig = 0; ig < _layers[i].Graphics.Count; ig++)
399 {
400 rect = _layers[i].Graphics[ig].GetBounds(g);
401 furthestLeft = Math.Min(furthestLeft, rect.Left);
402 furthestTop = Math.Min(furthestTop, rect.Left);
403 furthestRight = Math.Max(furthestRight, rect.Right);
404 furthestBottom = Math.Max(furthestBottom, rect.Bottom);
405 }
406 }
407 }
408 }
409 }
410 rect = new Rectangle(furthestLeft, furthestTop, Math.Abs(furthestRight-furthestLeft), Math.Abs(furthestBottom-furthestTop));
411 return rect;
412 }
413  
414 internal void ReplaceInitialImage(Image image)
415 {
416 ((CraftSynth.ImageEditor.DrawImage) (this._layers[0].Graphics[this._layers[0].Graphics.Count - 1])).TheImage = (Bitmap)image;
417 // this.AddCommandToHistory(new CommandAdd(this.TheLayers[0].Graphics[this._layers[0].Graphics.Count - 1]));
418 this.Invalidate();
419 }
420  
421 internal KeyValuePair<int,DrawImage>? GetInitialImageGraphic()
422 {
423 for (int i = this._layers[0].Graphics.Count - 1; i >= 0; i--)
424 {
425 if (this._layers[0].Graphics[i] is DrawImage && (this._layers[0].Graphics[i] as DrawImage).IsInitialImage)
426 {
427 return new KeyValuePair<int, DrawImage>(i, this._layers[0].Graphics[i] as DrawImage);
428 }
429 }
430 return null;
431 }
432  
433 internal void DeselectAll()
434 {
435 ActiveTool = DrawToolType.Pointer;
436 int al = this.TheLayers.ActiveLayerIndex;
437 this.TheLayers[al].Graphics.UnselectAll();
438 this.Invalidate();
439 }
440 #endregion
441  
442 #region Event Handlers
443 /// <summary>
444 /// Draw graphic objects and group selection rectangle (optionally)
445 /// </summary>
446 /// <param name="sender"></param>
447 /// <param name="e"></param>
448 private void DrawArea_Paint(object sender, PaintEventArgs e)
449 {
450 Matrix mx = new Matrix();
451 mx.Translate(-ClientSize.Width / 2f, -ClientSize.Height / 2f, MatrixOrder.Append);
452 mx.Rotate(_rotation, MatrixOrder.Append);
453 mx.Translate(ClientSize.Width / 2f + _panX, ClientSize.Height / 2f + _panY, MatrixOrder.Append);
454 mx.Scale(_zoom, _zoom, MatrixOrder.Append);
455 e.Graphics.Transform = mx;
456 // Determine center of ClientRectangle
457 Point centerRectangle = new Point();
458 centerRectangle.X = ClientRectangle.Left + ClientRectangle.Width / 2;
459 centerRectangle.Y = ClientRectangle.Top + ClientRectangle.Height / 2;
460 // Get true center point
461 centerRectangle = BackTrackMouse(centerRectangle);
462 // Determine offset from current mouse position
463  
464 SolidBrush brush = new SolidBrush(Color.FromArgb(255, 255, 255));
465 e.Graphics.FillRectangle(brush,
466 ClientRectangle);
467 // Draw objects on each layer, in succession so we get the correct layering. Only draw layers that are visible
468 if (_layers != null)
469 {
470 int lc = _layers.Count;
471 for (int i = 0; i < lc; i++)
472 {
473 Console.WriteLine(String.Format("Layer {0} is Visible: {1}", i.ToString(), _layers[i].IsVisible.ToString()));
474 if (_layers[i].IsVisible)
475 {
476 if (_layers[i].Graphics != null)
477 _layers[i].Graphics.Draw(e.Graphics);
478 }
479 }
480 }
481  
482 DrawNetSelection(e.Graphics);
483  
484 brush.Dispose();
485 }
486  
487 /// <summary>
488 /// Back Track the Mouse to return accurate coordinates regardless of zoom or pan effects.
489 /// Courtesy of BobPowell.net <seealso cref="http://www.bobpowell.net/backtrack.htm"/>
490 /// </summary>
491 /// <param name="p">Point to backtrack</param>
492 /// <returns>Backtracked point</returns>
493 public Point BackTrackMouse(Point p)
494 {
495 // Backtrack the mouse...
496 Point[] pts = new Point[] { p };
497 Matrix mx = new Matrix();
498 mx.Translate(-ClientSize.Width / 2f, -ClientSize.Height / 2f, MatrixOrder.Append);
499 mx.Rotate(_rotation, MatrixOrder.Append);
500 mx.Translate(ClientSize.Width / 2f + _panX, ClientSize.Height / 2f + _panY, MatrixOrder.Append);
501 mx.Scale(_zoom, _zoom, MatrixOrder.Append);
502 mx.Invert();
503 mx.TransformPoints(pts);
504 return pts[0];
505 }
506  
507 /// <summary>
508 /// Mouse down.
509 /// Left button down event is passed to active tool.
510 /// Right button down event is handled in this class.
511 /// </summary>
512 /// <param name="sender"></param>
513 /// <param name="e"></param>
514 private void DrawArea_MouseDown(object sender, MouseEventArgs e)
515 {
516 lastPoint = BackTrackMouse(e.Location);
517 if (e.Button ==
518 MouseButtons.Left)
519 tools[(int)activeTool].OnMouseDown(this, e);
520 else if (e.Button ==
521 MouseButtons.Right)
522 {
523 if (_panning)
524 _panning = false;
525 if (activeTool == DrawToolType.PolyLine || activeTool == DrawToolType.Connector)
526 tools[(int)activeTool].OnMouseDown(this, e);
527 ActiveTool = DrawToolType.Pointer;
528 OnContextMenu(e);
529 }
530 }
531  
532 // else if (e.Button == MouseButtons.Right)
533 //{
534 //if (_panning == true)
535 //_panning = false;
536  
537 //if (activeTool == DrawToolType.PolyLine)
538 //tools[(int)activeTool].OnMouseDown(this, e);
539  
540 //ActiveTool = TETemplateDrawArea.DrawToolType.Pointer;
541 //}
542  
543 /// <summary>
544 /// Mouse move.
545 /// Moving without button pressed or with left button pressed
546 /// is passed to active tool.
547 /// </summary>
548 /// <param name="sender"></param>
549 /// <param name="e"></param>
550 private void DrawArea_MouseMove(object sender, MouseEventArgs e)
551 {
552 Point curLoc = BackTrackMouse(e.Location);
553 if (e.Button == MouseButtons.Left ||
554 e.Button == MouseButtons.None)
555 if (e.Button == MouseButtons.Left && _panning)
556 {
557 if (curLoc.X !=
558 lastPoint.X)
559 _panX += curLoc.X - lastPoint.X;
560 //this.MyParent.ManualScroll(true, -curLoc.X + lastPoint.X);
561 if (curLoc.Y !=
562 lastPoint.Y)
563 _panY += curLoc.Y - lastPoint.Y;
564 //this.MyParent.ManualScroll(false, -curLoc.Y + lastPoint.Y);
565 Invalidate();
566 }
567 else
568 tools[(int)activeTool].OnMouseMove(this, e);
569 else
570 Cursor = Cursors.Default;
571 lastPoint = BackTrackMouse(e.Location);
572 }
573  
574 /// <summary>
575 /// Mouse up event.
576 /// Left button up event is passed to active tool.
577 /// </summary>
578 /// <param name="sender"></param>
579 /// <param name="e"></param>
580 private void DrawArea_MouseUp(object sender, MouseEventArgs e)
581 {
582 //lastPoint = BackTrackMouse(e.Location);
583 if (e.Button == MouseButtons.Left)
584 {
585  
586 tools[(int)activeTool].OnMouseUp(this, e);
587 if (activeTool != DrawToolType.Pointer && activeTool!= DrawToolType.Text && activeTool!= DrawToolType.Image)
588 {
589 int al = this.TheLayers.ActiveLayerIndex;
590 this.AddCommandToHistory(new CommandAdd(this.TheLayers[al].Graphics[0]));
591 }
592  
593 if (this.PanX != 0 || this.PanY != 0)
594 {
595 this.myparent.ManualScroll(true, -(int)Math.Round(this.PanX*this._zoom));
596 this.myparent.ManualScroll(false, -(int)Math.Round(this.PanY*this._zoom));
597 this.PanX = 0;
598 this.PanY = 0;
599 this.Invalidate();
600 this.myparent.pnlDrawArea.Invalidate();
601 }
602  
603 this.ActiveTool = DrawArea.DrawToolType.Pointer;//Selected tool is automatically dropped after drawing item
604 }
605 }
606  
607 public void CutObject()
608 {
609 MessageBox.Show("Cut (from drawarea)");
610 }
611  
612 private void DrawArea_MouseWheel(object sender, MouseEventArgs e)
613 {
614 }
615  
616 #endregion
617  
618 #region Other Functions
619 /// <summary>
620 /// Initialization
621 /// </summary>
622 /// <param name="owner">Reference to the owner form</param>
623 /// <param name="docManager">Reference to Document manager</param>
624 public void Initialize(MainForm owner, DocManager docManager, Image initialImage, string initialImageAsFilePath, byte[] initialImageAsPngBytes)
625 {
626 SetStyle(ControlStyles.AllPaintingInWmPaint |
627 ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
628 Invalidate();
629  
630 // Keep reference to owner form
631 Owner = owner;
632 DocManager = docManager;
633  
634 // set default tool
635 activeTool = DrawToolType.Pointer;
636  
637 // Create undo manager
638 undoManager = new UndoManager(_layers);
639  
640 // create array of drawing tools
641 tools = new Tool[(int)DrawToolType.NumberOfDrawTools];
642 tools[(int)DrawToolType.Pointer] = new ToolPointer();
643 tools[(int)DrawToolType.Rectangle] = new ToolRectangle();
644 tools[(int)DrawToolType.Ellipse] = new ToolEllipse();
645 tools[(int)DrawToolType.Line] = new ToolLine();
646 tools[(int)DrawToolType.PolyLine] = new ToolPolyLine();
647 tools[(int)DrawToolType.Polygon] = new ToolPolygon();
648 tools[(int)DrawToolType.Text] = new ToolText();
649 tools[(int)DrawToolType.Image] = new ToolImage();
650 tools[(int)DrawToolType.Connector] = new ToolConnector();
651  
652 LineColor = Color.Red;
653 FillColor = Color.White;
654 LineWidth = 5;
655  
656 LoadInitialImage(initialImage, initialImageAsFilePath, initialImageAsPngBytes, null);
657 }
658  
659 public void LoadInitialImage(Image initialImage, string initialImageAsFilePath, byte[] initialImageAsPngBytes, DrawImage paradigm)
660 {
661 if (initialImage != null)
662 {
663 ((ToolImage) tools[(int) DrawToolType.Image]).InsertImage(this, initialImage, true, true, paradigm);
664 }
665  
666 if (initialImageAsFilePath != null)
667 {
668 ((ToolImage) tools[(int) DrawToolType.Image]).InsertImage(this, initialImageAsFilePath, true, true, paradigm);
669 }
670  
671 if (initialImageAsPngBytes != null)
672 {
673 ((ToolImage) tools[(int) DrawToolType.Image]).InsertImage(this, initialImageAsPngBytes, true, true, paradigm);
674 }
675 // int al = _layers.ActiveLayerIndex;
676 //var temp = this.TheLayers[al].Graphics[0];
677 //this.TheLayers[al].Graphics.RemoveAt(0);
678 //this.TheLayers[al].Graphics.Add(temp);
679 this.Invalidate();
680 }
681  
682 /// <summary>
683 /// Add command to history.
684 /// </summary>
685 public void AddCommandToHistory(Command command)
686 {
687 undoManager.AddCommandToHistory(command);
688 }
689  
690 /// <summary>
691 /// Clear Undo history.
692 /// </summary>
693 public void ClearHistory()
694 {
695 undoManager.ClearHistory();
696 }
697  
698 /// <summary>
699 /// Undo
700 /// </summary>
701 public void Undo()
702 {
703 undoManager.Undo();
704 Refresh();
705 }
706  
707 /// <summary>
708 /// Redo
709 /// </summary>
710 public void Redo()
711 {
712 undoManager.Redo();
713 Refresh();
714 }
715  
716 /// <summary>
717 /// Draw group selection rectangle
718 /// </summary>
719 /// <param name="g"></param>
720 public void DrawNetSelection(Graphics g)
721 {
722 if (!DrawNetRectangle)
723 return;
724  
725 ControlPaint.DrawFocusRectangle(g, NetRectangle, Color.Black, Color.Transparent);
726 }
727  
728 /// <summary>
729 /// Right-click handler
730 /// </summary>
731 /// <param name="e"></param>
732 private void OnContextMenu(MouseEventArgs e)
733 {
734 // Change current selection if necessary
735  
736 Point point = BackTrackMouse(new Point(e.X, e.Y));
737 Point menuPoint = new Point(e.X, e.Y);
738 int al = _layers.ActiveLayerIndex;
739 int n = _layers[al].Graphics.Count;
740 DrawObject o = null;
741  
742 for (int i = 0; i < n; i++)
743 {
744 if (_layers[al].Graphics[i].HitTest(point) == 0)
745 {
746 o = _layers[al].Graphics[i];
747 break;
748 }
749 }
750  
751 if (o != null)
752 {
753 if (!o.Selected)
754 _layers[al].Graphics.UnselectAll();
755  
756 // Select clicked object
757 o.Selected = true;
758 }
759 else
760 {
761 _layers[al].Graphics.UnselectAll();
762 }
763  
764 Refresh();
765 Owner.ctxtMenu.Show(this, menuPoint);
766 }
767 #endregion
768  
769  
770 }
771 }