#include <windows.h>
#include <tchar.h>
#include <assert.h>
#include <math.h>
#include <stdio.h> //To get FILENAME_MAX
#include "..\egg.h"
#include "egg_priv.h"
//////////////////////////////////////////////////////////////////////////
//
// 定义宏
//
//////////////////////////////////////////////////////////////////////////
/**
* Egg窗口类名
*
* Win32在建窗口时需要这样的东西,虽然它好像用处不大(或者我不知道用处)
*/
#define EGG_WINDOW_CLASS_NAME _T("Easy Graphical egG Window")
/**
* 缺省的画笔颜色
*/
#define DEFAULT_PEN_COLOR BLACK //黑色
/**
* 缺省的画笔宽度
*/
#define DEFAULT_PEN_WIDTH 1
/**
* 缺省的画刷颜色
*/
#define DEFAULT_BRUSH_COLOR BLACK //黑色
/**
* 缺省的透明色
*/
#define DEFAULT_TRANSPARENT_COLOR TRANSPARENT_COLOR
/**
* π
*/
#define PI 3.1415926535
//////////////////////////////////////////////////////////////////////////
//
// 定义数据类型
//
//////////////////////////////////////////////////////////////////////////
/**
* egg的数据结构
*
* egg是Egg平台里的绘图单元。可以针对每个egg进行具体的绘图操作,并可以移动
* egg的位置。
*/
typedef struct egg
{
struct egg *pPrev; /**< 指向前一个被绘制的egg */
HDC hdc; /**< 内存dc */
HBITMAP hbm; /**< 位图 */
HPEN hPen; /**< 画笔 */
HBRUSH hBrush; /**< 画刷 */
COLORREF rgbTransparent; /**< 透明色 */
double fX; /**< egg左上角的x坐标(盘子坐标系) */
double fY; /**< egg左上角的y坐标(盘子坐标系) */
double fPX; /**< 当前画笔位置的x坐标(egg坐标系) */
double fPY; /**< 当前画笔位置的y坐标(egg坐标系) */
double fPenWidth; /**< 画笔粗 */
int bShow; /**< 是否显示 */
struct egg *pNext; /**< 指向下一个要绘制的egg */
} egg;
//////////////////////////////////////////////////////////////////////////
//
// 定义在此文件内有效的全局变量
//
//////////////////////////////////////////////////////////////////////////
//!盘子,里面装满彩蛋(egg)!
static egg ePlate;
//!指向最后一个蛋
static egg* pLastEgg = &ePlate;
//!当前的活动egg
static egg* pActiveEgg = NULL;
//!盘子的矩形范围(像素)。每个egg也都是此大小
static RECT rcPlate;
//!盘子背景刷子
static HBRUSH hbrBkgrd;
//!是否自动更新
static int bAutoUpdate = 1;
//!ePlate.hdc临界区
static CRITICAL_SECTION hCriticalSection;
//////////////////////////////////////////////////////////////////////////
//
// 声明仅在此文件内有效的私有函数
//
//////////////////////////////////////////////////////////////////////////
//核心
static BOOL UpdatePlate(const RECT* pRect);
//功能支持
static egg* Valid(HEGG hEgg);
static double Deg2Rad(double deg);
void DeleteEgg(egg* pEgg);
//////////////////////////////////////////////////////////////////////////
//
// Egg API定义,可被其它程序调用
//
//////////////////////////////////////////////////////////////////////////
void MovePen(double x, double y)
{
InitCheck();
assert(pActiveEgg != NULL);
MoveToEx(pActiveEgg->hdc, X_CM2P(pActiveEgg->fPX = x), Y_CM2P(pActiveEgg->fPY = y), NULL);
}
void OffsetPen(double dx, double dy)
{
MovePen(pActiveEgg->fPX += dx, pActiveEgg->fPY += dy);
}
double GetPenXPos(void)
{
return pActiveEgg->fPX;
}
double GetPenYPos(void)
{
return pActiveEgg->fPY;
}
void DrawLine(double dx, double dy)
{
InitCheck();
assert(pActiveEgg != NULL);
LineTo(pActiveEgg->hdc,
X_CM2P(pActiveEgg->fPX += dx),
Y_CM2P(pActiveEgg->fPY += dy));
UpdatePlate(&rcPlate);
}
void DrawString(char* pString)
{
InitCheck();
assert(pActiveEgg != NULL);
TextOut(pActiveEgg->hdc, X_CM2P(pActiveEgg->fPX), Y_CM2P(pActiveEgg->fPY), pString, _tcslen(pString));
pActiveEgg->fPX += GetStringWidth(pString);
MovePen(pActiveEgg->fPX, pActiveEgg->fPY);
UpdatePlate(&rcPlate);
}
double GetStringWidth(char* pString)
{
SIZE size;
InitCheck();
assert(pActiveEgg != NULL);
GetTextExtentPoint(pActiveEgg->hdc, pString, _tcslen(pString), &size);
return WidthP2CM(size.cx);
}
void DrawArc(double r, double dStart, double dSweep)
{
DrawEllipticalArc(r, r, dStart, dSweep);
}
void DrawEllipticalArc(double rx, double ry, double dStart, double dSweep)
{
double fCenterX, fCenterY;
double fDstX, fDstY;
InitCheck();
assert(pActiveEgg != NULL);
fCenterX = pActiveEgg->fPX + rx * cos(Deg2Rad(dStart + 180));
fCenterY = pActiveEgg->fPY + ry * sin(Deg2Rad(dStart + 180));
fDstX = fCenterX + rx * cos(Deg2Rad(dStart + dSweep));
fDstY = fCenterY + ry * sin(Deg2Rad(dStart + dSweep));
if (dSweep > 0)
{
Arc(pActiveEgg->hdc,
X_CM2P(fCenterX - rx),
Y_CM2P(fCenterY + ry),
X_CM2P(fCenterX + rx),
Y_CM2P(fCenterY - ry),
X_CM2P(pActiveEgg->fPX),
Y_CM2P(pActiveEgg->fPY),
X_CM2P(fDstX),
Y_CM2P(fDstY));
}
else
{
Arc(pActiveEgg->hdc,
X_CM2P(fCenterX - rx),
Y_CM2P(fCenterY + ry),
X_CM2P(fCenterX + rx),
Y_CM2P(fCenterY - ry),
X_CM2P(fDstX),
Y_CM2P(fDstY),
X_CM2P(pActiveEgg->fPX),
Y_CM2P(pActiveEgg->fPY));
}
pActiveEgg->fPX = fDstX;
pActiveEgg->fPY = fDstY;
MoveToEx(pActiveEgg->hdc, X_CM2P(pActiveEgg->fPX), Y_CM2P(pActiveEgg->fPY), NULL);
UpdatePlate(&rcPlate);
}
void DrawBitmap(char* lpszFilename)
{
HBITMAP hBitmap = NULL;
HDC hdcTemp;
HBITMAP hOldBitmap;
BITMAP bm;
InitCheck();
assert(pActiveEgg != NULL);
hBitmap = (HBITMAP)LoadImage(NULL, lpszFilename, IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION);
if (hBitmap == NULL)
{
char tmpStr[FILENAME_MAX];
_snprintf(tmpStr, FILENAME_MAX, _T("位图文件\"%s\"不存在。"), lpszFilename);
Error(tmpStr);
}
hdcTemp = CreateCompatibleDC(pActiveEgg->hdc);
hOldBitmap = SelectObject(hdcTemp, hBitmap);
GetObject( hBitmap, sizeof( bm ), &bm );
BitBlt(pActiveEgg->hdc, X_CM2P(pActiveEgg->fPX), Y_CM2P(pActiveEgg->fPY),
bm.bmWidth, bm.bmHeight, hdcTemp, 0, 0, SRCCOPY);
DeleteObject(SelectObject(hdcTemp, hOldBitmap));
DeleteDC(hdcTemp);
OffsetPen(X_P2CM(bm.bmWidth), 0);
UpdatePlate(&rcPlate);
}
HEGG LayEgg(void)
{
//TODO: 更好的异常处理
HBRUSH hbrTransparent;
egg* pEgg = NULL;
//建立egg
pEgg = (egg*)calloc(sizeof(egg), 1);
assert(pEgg != NULL);
EnterCriticalSection(&hCriticalSection);
pEgg->hdc = CreateCompatibleDC(ePlate.hdc);
if (pEgg->hdc == NULL)
{
Error(_T("CreateCompatibleDC Error!"));
}
pEgg->hbm = CreateCompatibleBitmap(ePlate.hdc,
rcPlate.right,
rcPlate.bottom);
LeaveCriticalSection(&hCriticalSection);
assert(pEgg->hbm != NULL);
SelectObject(pEgg->hdc, pEgg->hbm);
//用缺省颜色建立画笔
SetTextColor(pEgg->hdc, DEFAULT_PEN_COLOR);
pEgg->hPen = CreatePen(PS_SOLID, DEFAULT_PEN_WIDTH, DEFAULT_PEN_COLOR);
SelectObject(pEgg->hdc, pEgg->hPen);
//透明色绘制背景
pEgg->rgbTransparent = DEFAULT_TRANSPARENT_COLOR;
SetBkColor(pEgg->hdc, pEgg->rgbTransparent);
hbrTransparent = CreateSolidBrush(pEgg->rgbTransparent);
FillRect(pEgg->hdc, &rcPlate, hbrTransparent);
Dele