/******************************************************
 * EasyX Library for C++ (Ver:2023´óÊî°æ)
 * https://easyx.cn
 *
 * EasyX.h
 *		Provides the latest API.
 ******************************************************/

#pragma once

#ifndef WINVER
#define WINVER 0x0400			// Specifies that the minimum required platform is Windows 95 and Windows NT 4.0.
#endif

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500		// Specifies that the minimum required platform is Windows 2000
#endif

#ifndef _WIN32_WINDOWS
#define _WIN32_WINDOWS 0x0410	// Specifies that the minimum required platform is Windows 98
#endif

#ifdef UNICODE
	#pragma comment(lib,"EasyXw.lib")
#else
	#pragma comment(lib,"EasyXa.lib")
#endif


#ifndef __cplusplus
#error EasyX is only for C++
#endif

#include <windows.h>
#include <tchar.h>

// EasyX Window Properties
#define EX_SHOWCONSOLE		1		// Maintain the console window when creating a graphics window
#define EX_NOCLOSE			2		// Disable the close button
#define EX_NOMINIMIZE		4		// Disable the minimize button
#define EX_DBLCLKS			8		// Support double-click events


// Color constant
#define	BLACK			0
#define	BLUE			0xAA0000
#define	GREEN			0x00AA00
#define	CYAN			0xAAAA00
#define	RED				0x0000AA
#define	MAGENTA			0xAA00AA
#define	BROWN			0x0055AA
#define	LIGHTGRAY		0xAAAAAA
#define	DARKGRAY		0x555555
#define	LIGHTBLUE		0xFF5555
#define	LIGHTGREEN		0x55FF55
#define	LIGHTCYAN		0xFFFF55
#define	LIGHTRED		0x5555FF
#define	LIGHTMAGENTA	0xFF55FF
#define	YELLOW			0x55FFFF
#define	WHITE			0xFFFFFF

// Color conversion macro
#define BGR(color)	( (((color) & 0xFF) << 16) | ((color) & 0xFF00FF00) | (((color) & 0xFF0000) >> 16) )


class IMAGE;

// Line style class
class LINESTYLE
{
public:
	LINESTYLE();
	LINESTYLE(const LINESTYLE &style);
	LINESTYLE& operator = (const LINESTYLE &style);
	virtual ~LINESTYLE();

	DWORD	style;
	DWORD	thickness;
	DWORD	*puserstyle;
	DWORD	userstylecount;
};

// Fill style class
class FILLSTYLE
{
public:
	FILLSTYLE();
	FILLSTYLE(const FILLSTYLE &style);
	FILLSTYLE& operator = (const FILLSTYLE &style);
	virtual ~FILLSTYLE();

	int			style;				// Fill style
	long		hatch;				// Hatch pattern
	IMAGE*		ppattern;			// Fill image
};

// Image class
class IMAGE
{
public:
	int getwidth() const;			// Get the width of the image
	int getheight() const;			// Get the height of the image

private:
	int			width, height;		// Width and height of the image
	HBITMAP		m_hBmp;
	HDC			m_hMemDC;
	float		m_data[6];
	COLORREF	m_LineColor;		// Current line color
	COLORREF	m_FillColor;		// Current fill color
	COLORREF	m_TextColor;		// Current text color
	COLORREF	m_BkColor;			// Current background color
	DWORD*		m_pBuffer;			// Memory buffer of the image

	LINESTYLE	m_LineStyle;		// Current line style
	FILLSTYLE	m_FillStyle;		// Current fill style

	virtual void SetDefault();		// Set the graphics environment as default

public:
	IMAGE(int _width = 0, int _height = 0);
	IMAGE(const IMAGE &img);
	IMAGE& operator = (const IMAGE &img);
	virtual ~IMAGE();
	virtual void Resize(int _width, int _height);			// Resize image
};



// Graphics window related functions

HWND initgraph(int width, int height, int flag = 0);		// Create graphics window
void closegraph();											// Close graphics window


// Graphics environment related functions

void cleardevice();											// Clear device
void setcliprgn(HRGN hrgn);									// Set clip region
void clearcliprgn();										// Clear clip region

void getlinestyle(LINESTYLE* pstyle);						// Get line style
void setlinestyle(const LINESTYLE* pstyle);					// Set line style
void setlinestyle(int style, int thickness = 1, const DWORD *puserstyle = NULL, DWORD userstylecount = 0);	// Set line style
void getfillstyle(FILLSTYLE* pstyle);						// Get fill style
void setfillstyle(const FILLSTYLE* pstyle);					// Set fill style
void setfillstyle(int style, long hatch = NULL, IMAGE* ppattern = NULL);		// Set fill style
void setfillstyle(BYTE* ppattern8x8);						// Set fill style

void setorigin(int x, int y);								// Set coordinate origin
void getaspectratio(float *pxasp, float *pyasp);			// Get aspect ratio
void setaspectratio(float xasp, float yasp);				// Set aspect ratio

int  getrop2();						// Get binary raster operation mode
void setrop2(int mode);				// Set binary raster operation mode
int  getpolyfillmode();				// Get polygon fill mode
void setpolyfillmode(int mode);		// Set polygon fill mode

void graphdefaults();				// Reset the graphics environment as default

COLORREF getlinecolor();			// Get line color
void setlinecolor(COLORREF color);	// Set line color
COLORREF gettextcolor();			// Get text color
void settextcolor(COLORREF color);	// Set text color
COLORREF getfillcolor();			// Get fill color
void setfillcolor(COLORREF color);	// Set fill color
COLORREF getbkcolor();				// Get background color
void setbkcolor(COLORREF color);	// Set background color
int  getbkmode();					// Get background mode
void setbkmode(int mode);			// Set background mode

// Color model transformation related functions
COLORREF RGBtoGRAY(COLORREF rgb);
void RGBtoHSL(COLORREF rgb, float *H, float *S, float *L);
void RGBtoHSV(COLORREF rgb, float *H, float *S, float *V);
COLORREF HSLtoRGB(float H, float S, float L);
COLORREF HSVtoRGB(float H, float S, float V);


// Drawing related functions

COLORREF getpixel(int x, int y);				// Get pixel color
void putpixel(int x, int y, COLORREF color);	// Set pixel color

void line(int x1, int y1, int x2, int y2);		// Draw a line

void rectangle	   (int left, int top, int right, int bottom);	// Draw a rectangle without filling
void fillrectangle (int left, int top, int right, int bottom);	// Draw a filled rectangle with a border
void solidrectangle(int left, int top, int right, int bottom);	// Draw a filled rectangle without a border
void clearrectangle(int left, int top, int right, int bottom);	// Clear a rectangular region

void circle		(int x, int y, int radius);		// Draw a circle without filling
void fillcircle (int x, int y, int radius);		// Draw a filled circle with a border
void solidcircle(int x, int y, int radius);		// Draw a filled circle without a border
void clearcircle(int x, int y, int radius);		// Clear a circular region

void ellipse	 (int left, int top, int right, int bottom);	// Draw an ellipse without filling
void fillellipse (int left, int top, int right, int bottom);	// Draw a filled ellipse with a border
void solidellipse(int left, int top, int right, int bottom);	// Draw a filled ellipse without a border
void clearellipse(int left, int top, int right, int bottom);	// Clear an elliptical region

void roundrect	   (int left, int top, int right, int bottom, int ellipsewidth, int ellipseheight);		// Draw a rounded rectangle without filling
void fillroundrect (int left, int top, int right, int bottom, int ellipsewidth, int ellipseheight);		// Draw a filled rounded rectangle with a border
void solidroundrect(int left, int top, int right, int bottom, int ellipsewidth, int ellipseheight);		// Draw a filled rounded rectangle without a border
void clearroundrect(int left, int top, int right, int bottom, int ellipsewidth, int ellipseheight);		// Clear a rounded rectangular region

void arc	 (int left, int top, int right, int bottom, double stangle, double endangle);	// Draw an arc
void pie	 (int left, int top, int right, int bottom, double stangle, double endangle);	// Draw a sector without filling
void fillpie (int left, int top, int right, int bottom, double stangle, double endangle);	// Draw a filled sector with a border
void solidpie(int left, int top, int right, int bottom, double stangle, double endangle);	// Draw a filled sector without a border
void clearpie(int left, int top, int right, int bottom, double stangle, double endangle);	// Clear a rounded rectangular region

void polyline	 (const POINT *points, int num);								// Draw multiple consecutive lines
void polygon	 (const POINT *points, int num);								// Draw a polygon without filling
void fillpolygon (const POINT *points, int num);								// Draw a filled polygon with a border
void solidpolygon(const POINT *points, int num);								// Draw a filled polygon without a border
void clearpolygon(const POINT *points, int num);								// Clear a polygon region

void polybezier(const POINT *points, int num);									// Draw three square Bezier curves
void floodfill(int x, int y, COLORREF color, int filltype = FLOODFILLBORDER);	// Fill the area



// Text related functions
void outtextxy(int x, int y, LPCTSTR str);				// Output a string at the specified location
void outtextxy(int x, int y, TCHAR c);					// Output a char at the specified location
int textwidth(LPCTSTR str);								// Get the width of a string
int textwidth(TCHAR c);									// Get the width of a char
int textheight(LPCTSTR str);							// Get the height of a string
int textheight(TCHAR c);								// Get the height of a char
int drawtext(LPCTSTR str, RECT* pRect, UINT uFormat);	// Output a string in the specified format within the specified area.
int drawtext(TCHAR c, RECT* pRect, UINT uFormat);		// Output a char in the specified format within the specified area.

// Set current text style.
//		nHeight: The height of the text
//		nWidth: The average width of the character. If 0, the scale is adaptive.
//		lpszFace: The font name
//		nEscapement: The writing angle of the string, 0.1 degrees, defaults to 0.
//		nOrientation: The writing angle of each character, 0.1 degrees, defaults to 0.
//		nWeight: The stroke weight of the character
//		bItalic: Specify whether the font is italic
//		bUnderline: Specify whether the font is underlined
//		bStrikeOut: Specify whether the font has a strikeout
//		fbCharSet: Specifies the character set
//		fbOutPrecision: Specifies the output accuracy of the text
//		fbClipPrecision: Specifies the clip accuracy of the text
//		fbQuality: Specifies the output quality of the text
//		fbPitchAndFamily: Specifies a font family that describes a font in a general way
void settextstyle(int nHeight, int nWidth, LPCTSTR lpszFace);
void settextstyle(int nHeight, int nWidth, LPCTSTR lpszFace, int nEscapement, int nOrientation, int nWeight, bool bItalic, bool bUnderline, bool bStrikeOut);
void settextstyle(int nHeight, int nWidth, LPCTSTR lpszFace, int nEscapement, int nOrientation, int nWeight, bool bItalic, bool bUnderline, bool bStrikeOut, BYTE fbCharSet, BYTE fbOutPrecision, BYTE fbClipPrecision, BYTE fbQuality, BYTE fbPitchAndFamily);
void settextstyle(const LOGFONT *font);	// Set current text style
void gettextstyle(LOGFONT *font);		// Get current text style



// Image related functions
void loadimage(IMAGE *pDstImg, LPCTSTR pImgFile, int nWidth = 0, int nHeight = 0, bool bResize = false);					// Load image from a file (bmp/gif/jpg/png/tif/emf/wmf/ico)
void loadimage(IMAGE *pDstImg, LPCTSTR pResType, LPCTSTR pResName, int nWidth = 0, int nHeight = 0, bool bResize = false);	// Load image from resources (bmp/gif/jpg/png/tif/emf/wmf/ico)
void saveimage(LPCTSTR pImgFile, IMAGE* pImg = NULL);																		// Save image to a file (bmp/gif/jpg/png/tif)
void getimage(IMAGE *pDstImg, int srcX, int srcY, int srcWidth, int srcHeight);												// Get image from device
void putimage(int dstX, int dstY, const IMAGE *pSrcImg, DWORD dwRop = SRCCOPY);												// Put image to device
void putimage(int dstX, int dstY, int dstWidth, int dstHeight, const IMAGE *pSrcImg, int srcX, int srcY, DWORD dwRop = SRCCOPY);		// Put image to device
void rotateimage(IMAGE *dstimg, IMAGE *srcimg, double radian, COLORREF bkcolor = BLACK, bool autosize = false, bool highquality = true);// Rotate image
void Resize(IMAGE* pImg, int width, int height);	// Resize the device
DWORD* GetImageBuffer(IMAGE* pImg = NULL);			// Get the display buffer of the graphics device
IMAGE* GetWorkingImage();							// Get current graphics device
void SetWorkingImage(IMAGE* pImg = NULL);			// Set current graphics device
HDC GetImageHDC(IMAGE* pImg = NULL);				// Get the graphics device handle


// Other functions

int	getwidth();			// Get the width of current graphics device
int	getheight();		// Get the height of current graphics device

void BeginBatchDraw();	// Begin batch drawing mode
void FlushBatchDraw();	// Refreshes the undisplayed drawing
void FlushBatchDraw(int left, int top, int right, int bottom);	// Refreshes the undisplayed drawing
void EndBatchDraw();	// End batch drawing mode and refreshes the undisplayed drawing
void EndBatchDraw(int left, int top, int right, int bottom);	// End batch drawing mode and refreshes the undisplayed drawing

HWND GetHWnd();								// Get the handle of the graphics window
const TCHAR* GetEasyXVer();						// Get version of EasyX library

// Get user input as a dialog box
bool InputBox(LPTSTR pString, int nMaxCount, LPCTSTR pPrompt = NULL, LPCTSTR pTitle = NULL, LPCTSTR pDefault = NULL, int width = 0, int height = 0, bool bOnlyOK = true);



// Message
//
//	Category	Type				Description
//
//	EX_MOUSE	WM_MOUSEMOVE		Mouse moves
//				WM_MOUSEWHEEL		Mouse wheel is rotated
//				WM_LBUTTONDOWN		Left mouse button is pressed
//				WM_LBUTTONUP		Left mouse button is released
//				WM_LBUTTONDBLCLK	Left mouse button is double-clicked
//				WM_MBUTTONDOWN		Middle mouse button is pressed
//				WM_MBUTTONUP		Middle mouse button is released
//				WM_MBUTTONDBLCLK	Middle mouse button is double-clicked
//				WM_RBUTTONDOWN		Right mouse button is pressed
//				WM_RBUTTONUP		Right mouse button is released
//				WM_RBUTTONDBLCLK	Right mouse button is double-clicked
//
//	EX_KEY		WM_KEYDOWN			A key is pressed
//				WM_KEYUP			A key is released
//
//	EX_CHAR		WM_CHAR
//
//	EX_WINDOW	WM_ACTIVATE			The window is activated or deactivated
//				WM_MOVE				The window has been moved
//				WM_SIZE				The size of window has changed

// Message Category
#define EX_MOUSE	1
#define EX_KEY		2
#define EX_CHAR		4
#define EX_WINDOW	8

// Message Structure
struct ExMessage
{
	USHORT message;					// The message identifier
	union
	{
		// Data of the mouse message
		struct
		{
			bool ctrl		:1;		// Indicates whether the CTRL key is pressed
			bool shift		:1;		// Indicates whether the SHIFT key is pressed
			bool lbutton	:1;		// Indicates whether the left mouse button is pressed
			bool mbutton	:1;		// Indicates whether the middle mouse button is pressed
			bool rbutton	:1;		// Indicates whether the right mouse button is pressed
			short x;				// The x-coordinate of the cursor
			short y;				// The y-coordinate of the cursor
			short wheel;			// The distance the wheel is rotated, expressed in multiples or divisions of 120
		};

		// Data of the key message
		struct
		{
			BYTE vkcode;			// The virtual-key code of the key
			BYTE scancode;			// The scan code of the key. The value depends on the OEM
			bool extended	:1;		// Indicates whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is true if the key is an extended key; otherwise, it is false.
			bool prevdown	:1;		// Indicates whether the key is previously up or down
		};

		// Data of the char message
		TCHAR ch;

		// Data of the window message
		struct
		{
			WPARAM wParam;
			LPARAM lParam;
		};
	};
};

// Message Function
ExMessage getmessage(BYTE filter = -1);										// Get a message until a message is available for retrieval
void getmessage(ExMessage *msg, BYTE filter = -1);							// Get a message until a message is available for retrieval
bool peekmessage(ExMessage *msg, BYTE filter = -1, bool removemsg = true);	// Get a message if any exist, otherwise return false
void flushmessage(BYTE filter = -1);										// Flush the message buffer
void setcapture();				// Enable the ability to capture mouse messages outside of the graphics window
void releasecapture();			// Disable the ability to capture mouse messages outside of the graphics window