Paint

13.01.2013
23
0
#1
продолжаю мучить Paint =)) короче щас я так резко продвинулся уже, в общем посмотрите код, проблема в том что все инструменты получаются одного цвета :( что то перемудрил с лямбдами... и еще никак не соображу как мне сделать выделение области (как в паинте), с одной стороны мне кажется это вообще должен быть еще один UserControl, с другой стороны хочется все наследовать от ToolBase...

Код:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
 
 
 
 
public class PaintBox : UserControl
{
	public enum PaintTools : int { Curve, Line, Figure, Eraser };
 
 
 
 
	public class PaintProperties
	{
		public Color Color = Color.Black;
 
 
 
 
		public int Transparency = 255;
 
 
 
 
		public int Size = 10;
 
 
 
 
		public readonly ReadOnlyCollection<Func<Bitmap>> DefaultTextures;
 
 
 
 
		public Func<Bitmap> Texture;
 
 
 
 
		public Brush Brush
		{
			get
			{
				return new TextureBrush(Texture());
			}
		}
 
 
 
 
		public Pen Pen
		{
			get
			{
				return new Pen(Brush, Size);
			}
		}
 
 
 
 
		public Rectangle GetPaintRect(Point center, int padding = 0)
		{
			int x = center.X - Size - padding;
			int y = center.Y - Size - padding;
			int width = (Size + padding) * 2 + 1;
			int height = (Size + padding) * 2 + 1;
			return new Rectangle(x, y, width, height);
		}
 
 
 
 
		public PaintProperties()
		{
			var dt = new List<Func<Bitmap>>();
 
 
 
 
			dt.Add(() =>
			{
				var bmp = new Bitmap(100, 100);
				var gr = Graphics.FromImage(bmp);
				gr.FillRectangle(new SolidBrush(Color), 0, 0, bmp.Width, bmp.Height);
				return bmp;
			});
 
 
 
 
			dt.Add(() =>
			{
				var bmp = new Bitmap(100, 100);
				var gr = Graphics.FromImage(bmp);
				var pen = new Pen(Color);
				for (int i = 0; i < bmp.Height; i += 10)
					gr.DrawLine(pen, 0, i, bmp.Width, i);
				return bmp;
			});
 
 
 
 
			dt.Add(() =>
			{
				var bmp = new Bitmap(100, 100);
				var gr = Graphics.FromImage(bmp);
				var pen = new Pen(Color);
				for (int i = 0; i <= bmp.Width; i += 10)
					gr.DrawLine(pen, i, 0, i, bmp.Height);
				return bmp;
			});
 
 
 
 
			DefaultTextures = new ReadOnlyCollection<Func<Bitmap>>(dt);
			Texture = DefaultTextures[0];
		}
 
 
 
 
		public PaintProperties(PaintProperties prop) : this()
		{
			Color = prop.Color;
			Transparency = prop.Transparency;
			Size = prop.Size;
			Texture = prop.Texture;
		}
	}
 
 
 
 
	private abstract class ToolBase
	{
		public PaintProperties Properties = new PaintProperties();
 
 
 
 
		protected List<Point> Points = new List<Point>();
 
 
 
 
		public abstract void Draw(Graphics graphics);
 
 
 
 
		public virtual void Add(Point point)
		{
			Points.Add(point);
		}
 
 
 
 
		public virtual void Clear()
		{
			Points.Clear();
		}
	}
 
 
 
 
	private class Curve : ToolBase
	{
		public override void Draw(Graphics graphics)
		{
			if (Points.Count > 1)
				graphics.DrawLines(Properties.Pen, Points.ToArray());
 
 
 
 
			if (Points.Count == 1)
				graphics.FillEllipse(Properties.Brush, Properties.GetPaintRect(Points[0]));
		}
	}
 
 
 
 
	private class Line : ToolBase
	{
		public override void Draw(Graphics graphics)
		{
			if (Points.Count > 1)
				graphics.DrawLine(Properties.Pen, Points[0], Points[1]);
		}
 
 
 
 
		public override void Add(Point point)
		{
			if (Points.Count < 2)
				Points.Add(point);
			else
				Points[0] = point;
		}
	}
 
 
 
 
	public PaintProperties Properties = new PaintProperties();
	public PaintTools CurrentTool = PaintTools.Curve;
	private ToolBase Tool;
	private Bitmap Buffer;
	private List<ToolBase> History = new List<ToolBase>();
	private const int MaxHystoryLength = 100;
	private List<ToolBase> HistoryReceive = new List<ToolBase>();
 
 
 
 
	public PaintBox()
	{
		SetStyle(ControlStyles.AllPaintingInWmPaint |
				 ControlStyles.OptimizedDoubleBuffer |
				 ControlStyles.UserPaint,
				 true);
	}
 
 
 
 
	protected override void OnLoad(EventArgs e)
	{
		base.OnLoad(e);
		Buffer = new Bitmap(ClientSize.Width, ClientSize.Height);
		var graphics = Graphics.FromImage(Buffer);
		graphics.FillRectangle(Brushes.White, 0, 0, Buffer.Width, Buffer.Height);
	}
 
 
 
 
	protected override void OnPaintBackground(PaintEventArgs e)
	{
		e.Graphics.DrawImageUnscaled(Buffer, Point.Empty);
	}
 
 
 
 
	protected override void OnPaint(PaintEventArgs e)
	{
		e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
 
 
 
 
		foreach (var tool in History)
			tool.Draw(e.Graphics);
 
 
 
 
		if (Tool != null)
			Tool.Draw(e.Graphics);
	}
 
 
 
 
	protected override void OnMouseMove(MouseEventArgs e)
	{
		base.OnMouseMove(e);
		if (e.Button == MouseButtons.Left)
		{
			Tool.Add(e.Location);
			Invalidate(Tool.Properties.GetPaintRect(e.Location, 5));
		}
	}
 
 
 
 
	protected override void OnMouseDown(MouseEventArgs e)
	{
		base.OnMouseMove(e);
		if (e.Button == MouseButtons.Left)
		{
			switch (CurrentTool)
			{
				case PaintTools.Curve: Tool = new Curve(); break;
				case PaintTools.Line: Tool = new Line(); break;
				default: Tool = null; break;
			}
			Tool.Properties = new PaintProperties(Properties);
		}
	}
 
 
 
 
	protected override void OnMouseUp(MouseEventArgs e)
	{
		base.OnMouseUp(e);
 
 
 
 
		if (Tool != null)
		{
			History.Add(Tool);
			HistoryReceive.Clear();
		}
 
 
 
 
		Tool = null;
 
 
 
 
		if (History.Count > MaxHystoryLength)
		{
			Rasterize(new[] { History[0] }, Buffer);
			History.RemoveAt(0);
		}
 
 
 
 
		Invalidate();
	}
 
 
 
 
	private void Rasterize(IEnumerable<ToolBase> tools, Bitmap bitmap)
	{
		var graphics = Graphics.FromImage(bitmap);
		foreach (var tool in tools)
			tool.Draw(graphics);
	}
 
 
 
 
	public Bitmap Image
	{
		get
		{
			var result = new Bitmap(Buffer);
			var graphics = Graphics.FromImage(result);
			graphics.DrawImageUnscaled(Buffer, Point.Empty);
			Rasterize(History, result);
			return result;
		}
		set
		{
			Buffer = new Bitmap(value);
		}
	}
 
 
 
 
	public bool CanCancel
	{
		get
		{
			return History.Count > 0;
		}
	}
 
 
 
 
	public bool CanReceive
	{
		get
		{
			return HistoryReceive.Count > 0;
		}
	}
 
 
 
 
	public void Cancel()
	{
		if (CanCancel)
		{
			HistoryReceive.Add(History[History.Count - 1]);
			History.RemoveAt(History.Count - 1);
			Invalidate();
		}
	}
 
 
 
 
	public void Receive()
	{
		if (CanReceive)
		{
			History.Add(HistoryReceive[HistoryReceive.Count - 1]);
			HistoryReceive.RemoveAt(HistoryReceive.Count - 1);
			Invalidate();
		}
	}
}
Код:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
 
 
 
namespace Paint
{
	public partial class Form1 : Form
	{
		PaintBox pb = new PaintBox { Left = 100, Top = 100, Width = 600, Height = 600 };
		SaveFileDialog sfdlg = new SaveFileDialog() { Filter = "Image|*.png;*.bmp;*.jpg", DefaultExt = ".png" };
		ColorDialog cdlg = new ColorDialog();
 
 
 
 
		public Form1()
		{
			InitializeComponent();
 
 
 
 
			pb.Parent = this;
 
 
 
 
			var btn = new Button { Parent = this, Text = "Color" };
			btn.Click += SelectColor;
 
 
 
 
			int index = 1;
			btn = new Button { Parent = this, Text = "Fill", Left = 100 };
			btn.Click += delegate { pb.Properties.Texture = 
				pb.Properties.DefaultTextures[index++ % pb.Properties.DefaultTextures.Count]; };
 
 
 
 
			btn = new Button { Parent = this, Text = "Size", Left = 200 };
			btn.Click += delegate { pb.Properties.Size = (pb.Properties.Size + 2) % 11; };
 
 
 
 
			btn = new Button { Parent = this, Text = "Transparency", Left = 300 };
			btn.Click += delegate { pb.Properties.Transparency = (pb.Properties.Transparency + 40) % 255; };
 
 
 
 
			btn = new Button { Parent = this, Text = "Type", Left = 400 };
			btn.Click += delegate { pb.CurrentTool = (PaintBox.PaintTools)((int)(pb.CurrentTool + 1) % 2); };
 
 
 
 
			btn = new Button { Parent = this, Text = "Cancel", Left = 500 };
			btn.Click += delegate { pb.Cancel(); };
 
 
 
 
			btn = new Button { Parent = this, Text = "Receive", Left = 600 };
			btn.Click += delegate { pb.Receive(); };
 
 
 
 
			btn = new Button { Parent = this, Text = "Save", Left = 700 };
			btn.Click += SaveDialog;
 
 
 
 
			Size = new Size(800, 800);
		}
 
 
 
 
		private void SaveDialog(object sender, EventArgs e)
		{
			if (sfdlg.ShowDialog() == DialogResult.OK)
				pb.Image.Save(sfdlg.FileName);
		}
 
 
 
 
		private void SelectColor(object sender, EventArgs e)
		{
			if (cdlg.ShowDialog() == DialogResult.OK)
				pb.Properties.Color = cdlg.Color;
		}
	}
}
з.ы. в редакторе кодов есть все языки кроме шарпа -_- странно)))
 
13.01.2013
23
0
#2
короче с изменением цветов разобрался, оказывается я то присваивал функцию от объекта, она продолжала на него ссылаться и цвет менялся соответственно, щас сделал весь этот список статическим и норм... остается вопрос с выделением и пожалуй надо сделать какие то стандартные фигуры (прямоугольник, треугольник, эллипс...) тоже чет пока никак не соображу