/////////////////
// C# Atelier.cs
/////////////////
using System;
using System.Collections.Generic;	//Stackを使用する為
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

namespace Atelier					//Atelier.dllを使用する為
{
	/*	"using System.Collections.Generic;"
		"using System.Drawing;"
		"using System.Drawing.Drawing2D;"
		"using System.Drawing.Imaging;"が必要 */
	public partial class Easel
	{
		//変数
		private Pen _gpen;							//描画用ペン
		private Brush gBrush;						//描画用代表ブラシ（以下のブラシの代入用）
		private SolidBrush _gsbrush;				//描画用ソリッドブラシ
		private HatchBrush _ghbrush;				//描画用ハッチブラシ
		private LinearGradientBrush _glgbrush;		//描画用リニアグラディエントブラシ
		private TextureBrush _gtbrush;				//描画用テクスチュァブラシ
		private Font _gfont;						//描画用フォント
		private Image _gimage;						//画像入出力用イメージ
		//プロパティ
		public Bitmap Canvas {set; get;}			//仮想画面ビットマップ
		public Graphics gHandle {set; get;}			//仮想画面のグラフィック
		public Color gFtColor {set; get;}			//仮想画面の前景色
		public Color gBkColor {set; get;}			//仮想画面の背景色
		public Pen gPen								//描画用ペン
		{
			set
			{
				if(_gpen != null)
					_gpen.Dispose();
				_gpen = value;
			}
			get
			{
				return _gpen;
			}
		}
		public SolidBrush gsBrush					//描画用ソリッドブラシ
		{
			set
			{
				if(_gsbrush != null)
					_gsbrush.Dispose();
				_gsbrush = value;
			}
			get
			{
				return _gsbrush;
			}
		}
		public HatchBrush ghBrush					//描画用ハッチブラシ
		{
			set
			{
				if(_ghbrush != null)
					_ghbrush.Dispose();
				_ghbrush = value;
			}
			get
			{
				return _ghbrush;
			}
		}
		public LinearGradientBrush glgBrush			//描画用リニアグラディエントブラシ
		{
			set
			{
				if(_glgbrush != null)
					_glgbrush.Dispose();
				_glgbrush = value;
			}
			get
			{
				return _glgbrush;
			}
		}
		public TextureBrush gtBrush					//描画用テクスチュァブラシ
		{
			set
			{
				if(_gtbrush != null)
					_gtbrush.Dispose();
				_gtbrush = value;
			}
			get
			{
				return _gtbrush;
			}
		}
		public Font gFont							//描画用フォント
		{
			set
			{
				if(_gfont != null)
					_gfont.Dispose();
				_gfont = value;
			}
			get
			{
				return _gfont;
			}
		}
		public Image gImage							//画像入出力用イメージ
		{
			set
			{
				if(_gimage != null)
					_gimage.Dispose();
				_gimage = value;
			}
			get
			{
				return _gimage;
			}
		}
		//コンストラクター１
		public Easel()
		{
			//デスクトップサイズのビットマップ仮想画面の作成
			InitCanvas(	System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width,
						System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height
			);
		}
		//コンストラクター２
		public Easel(int w, int h)
		{
			//指定サイズのビットマップ仮想画面の作成
			InitCanvas(w, h);
		}
		//デストラクター
		~Easel()
		{
			if(gImage != null)
				gImage.Dispose();					//イメージリソースの開放
			if(gFont != null)
				gFont.Dispose();					//フォントリソースの開放
			if(gtBrush != null)
				gtBrush.Dispose();					//テクスチュァブラシリソースの開放
			if(glgBrush != null)
				glgBrush.Dispose();					//リニアグラディエントブラシリソースの開放
			if(ghBrush != null)
				ghBrush.Dispose();					//ハッチブラシリソースの開放
			if(gsBrush != null)
				gsBrush.Dispose();					//ソリッドブラシリソースの開放
			if(gBrush != null)
				gBrush.Dispose();					//ブラシリソースの開放
			if(gPen != null)
				gPen.Dispose();						//ペンリソースの開放
			if(gHandle != null)
				gHandle.Dispose();					//ビットマップリソースの開放
			if(Canvas != null)
				Canvas.Dispose();					//ビットマップリソースの開放
		}
		//Easelクラスオブジェクトの初期化
		public bool InitCanvas(int w, int h)
		{
			//wまたはhが0の場合、「使用されたパラメーターが有効ではありません」エラーとなる為
			if(w * h == 0)
				return false;
			//デスクトップサイズのビットマップ仮想画面の作成
			if(Canvas == null)	//最初のインスタンス生成時
			{
				Canvas = new Bitmap(w, h);
				//前景色（ウィンドウ文字色）
				gFtColor = SystemColors.WindowText;
				//背景色（コントロール背景色）
				gBkColor = SystemColors.Control;
				//描画ペン
				gPen = new Pen(gFtColor, 1);			//初期値は細黒字Pen
				//描画ブラシ
				//gtBrush = new TextureBrush(Image);	//テクスチュァブラシ(https://learn.microsoft.com/ja-jp/dotnet/api/system.drawing.texturebrush?view=windowsdesktop-8.0)
				//glgBrush = new LinearGradientBrush(Point, Point, Color, Color);	//リニアグラディエントブラシ(https://learn.microsoft.com/ja-jp/dotnet/api/system.drawing.drawing2d.lineargradientbrush.-ctor?view=windowsdesktop-8.0#system-drawing-drawing2d-lineargradientbrush-ctor(system-drawing-point-system-drawing-point-system-drawing-color-system-drawing-color))
				//ghBrush = new HatchBrush(HatchStyle.Cross, gFtColor, gBkColor);		//ハッチブラシ(https://learn.microsoft.com/ja-jp/dotnet/api/system.drawing.drawing2d.hatchbrush?view=windowsdesktop-8.0)
				gsBrush = new SolidBrush(gFtColor);		//ソリッドブラシ
				gBrush = gsBrush;						//初期値はソリッドブラシ
			}
			else
			{
				Rectangle srcRect;
				Rectangle desRect;
				Image img = (Bitmap)Canvas.Clone();		//旧画像をBitmapで保存
				Canvas.Dispose();						//Canvasを一旦開放
				Canvas = new Bitmap(w, h);				//新しいサイズで作成
				Graphics g = Graphics.FromImage(Canvas);
				if(w > img.Width)
				{
					if(h > img.Height)
					{
						srcRect = new Rectangle(0, 0, img.Width, img.Height);
						desRect = new Rectangle(0, 0, img.Width, img.Height);
					}
					else
					{
						srcRect = new Rectangle(0, 0, img.Width, h);
						desRect = new Rectangle(0, 0, img.Width, h);
					}
				}
				else
				{
					if(h > img.Height)
					{
						srcRect = new Rectangle(0, 0, w, img.Height);
						desRect = new Rectangle(0, 0, w, img.Height);
					}
					else
					{
						srcRect = new Rectangle(0, 0, w, h);
						desRect = new Rectangle(0, 0, w, h);
					}
				}
				g.DrawImage(img, desRect, srcRect, GraphicsUnit.Pixel);	//コピー
				g.Dispose();
			}
			//Graphicsクラス（アンチエイリアス）
			if(gHandle != null)		//既存のCanvasを変更する場合、一旦Graphicsを開放する
				gHandle.Dispose();
			gHandle = Graphics.FromImage(Canvas);
			gHandle.SmoothingMode = SmoothingMode.AntiAlias;
			gHandle.PixelOffsetMode = PixelOffsetMode.HighQuality;
			return true;
		}
		//前景色に合わせてペン、ブラシの色を変える
		private void UpdateColor()
		{
			gPen.Color = gFtColor;
			gsBrush.Color = gFtColor;
		}
		//描画ブラシを選択する（インスタンスが無ければエラー）
		public bool SelectBrush(int n)
		{
			switch(n)
			{
			case 0:	//ソリッドブラシ
				gBrush = gsBrush;
				break;
			case 1:	//ハッチブラシ
				if(ghBrush != null)
					gBrush = ghBrush;
				else
					return false;
				break;
			case 2:	//リニアグラディエントブラシ
				if(glgBrush != null)
					gBrush = glgBrush;
				else
					return false;
				break;
			case 3:	//テキスチュァブラシ
				if(gtBrush != null)
					gBrush = gtBrush;
				else
					return false;
				break;
			default:
				return false;
			}
			return true;
		}
		//サイズ変更
		public bool Resize(int w, int h)
		{
			return InitCanvas(w, h);
		}
		//画面消去１
		public void Clear()
		{
			gHandle.Clear(gBkColor);
		}
		//画面消去２
		public void Clear(Color c)
		{
			gHandle.Clear(c);
		}
		//点を描画
		public void Dot(int x, int y)
		{
			Canvas.SetPixel(x, y, gFtColor);
		}
		//線を描画
		public void Line(int x1, int y1, int x2, int y2)
		{
			UpdateColor();
			gHandle.DrawLine(gPen, x1, y1, x2, y2);
		}
		//矩形を描画（フラグf－塗りつぶし有無）
		public void Box(int x1, int y1, int x2, int y2, bool f = false)
		{
			UpdateColor();
			if(f)
				gHandle.FillRectangle(gBrush, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
			else
				gHandle.DrawRectangle(gPen, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
		}
		//円を描画（フラグf－塗りつぶし有無）
		public void Circle(int x, int y, int r, bool f = false)
		{
			UpdateColor();
			if(f)
				gHandle.FillEllipse(gBrush, x - r, y - r, 2 * r, 2 * r);
			else
				gHandle.DrawEllipse(gPen, x - r, y - r, 2 * r, 2 * r);
		}
		//矩形内接楕円を描画（フラグf－塗りつぶし有無）
		public void Ellipse(int x1, int y1, int x2, int y2, bool f = false)
		{
			UpdateColor();
			if(f)
				gHandle.FillEllipse(gBrush, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
			else
				gHandle.DrawEllipse(gPen, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
		}
		//円弧(線無)を描画
		public void Arced(int x1, int y1, int x2, int y2, int dg1, int dg2)
		{
			UpdateColor();
			gHandle.DrawArc(gPen, x1, y1, x2 - x1 + 1, y2 - y1 + 1, dg1, dg2);
		}
		//円弧(線有)を描画
		public void Chorded(int x1, int y1, int x2, int y2, int dg1, int dg2, bool f = false)
		{
			UpdateColor();
			if(f)
				gHandle.FillPie(gBrush, x1, y1, x2 - x1, y2 - y1, dg1, dg2);
			else
				gHandle.DrawPie(gPen, x1, y1, x2 - x1, y2 - y1, dg1, dg2);
		}
		//指定色で塗潰す
		public void Paint(int x, int y, Color col)
		{
			Color AreaCol = Canvas.GetPixel(x, y);		//塗潰す領域色を取得
			Stack<Point> stack = new Stack<Point>();	//領域塗潰し用スタック
			stack.Push(new Point(x, y));				//始点の保存
			while (stack.Count > 0)
			{
				Point currentPoint = stack.Pop();		//塗潰しスタックから取り出し
				int currentX = currentPoint.X;
				int currentY = currentPoint.Y;
				if(currentX >= 0 && currentX < Canvas.Width && currentY >= 0 && currentY < Canvas.Height)
				{
					if(Canvas.GetPixel(currentX, currentY) == AreaCol)
					{
						//領域色であれば塗潰す
						Canvas.SetPixel(currentX, currentY, col);
						//現在座標の上下左右のピクセルをスタックに追加
						stack.Push(new Point(currentX - 1, currentY));
						stack.Push(new Point(currentX + 1, currentY));
						stack.Push(new Point(currentX, currentY - 1));
						stack.Push(new Point(currentX, currentY + 1));
					}
				}
			}
		}
		//ビットマップ画像取込み
		public void GetBMP(PictureBox pb, int x1, int y1, int x2, int y2)
		{
			Bitmap bmp = new Bitmap(x2 - x1 + 1, y2 - y1 + 1, PixelFormat.Format32bppArgb);
			Graphics g = Graphics.FromImage(bmp);
			Point pt = pb.PointToScreen(new Point(x1, y1));
			g.CopyFromScreen(pt, new Point(0, 0), bmp.Size, CopyPixelOperation.SourceCopy);
			g.Dispose();
			bmp.Save("Temp.bmp", ImageFormat.Bmp);
			gImage = bmp;
		}
		//内部ビットマップ画像張付け
		public void PutBMP(int x, int y)
		{
			gHandle.DrawImage(gImage, x, y);	//今のところAND、OR、XORで表示できない
		}
		//外部画像張付け
		public void PutBMP(Image img, int x, int y)
		{
			gHandle.DrawImage(img, x, y);		//今のところAND、OR、XORで表示できない
		}
		//外部画像を指定サイズに変えて張付け
		public void PutBMP(Image img, int x1, int y1, int x2, int y2)
		{
			Rectangle rec = new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
			gHandle.DrawImage(img, rec);
		}
		//文字を描画
		public void PrintText(String str, Single x, Single y, StringFormat format)
		{
			UpdateColor();
			gFont = System.Drawing.SystemFonts.DefaultFont;
			gHandle.DrawString(str, gFont, gBrush, x, y, format);
		}
	}
}
