// 这段 MFC 示例源代码演示如何使用 MFC Microsoft Office Fluent 用户界面
// (“Fluent UI”)。该示例仅供参考，
// 用以补充《Microsoft 基础类参考》和
// MFC C++ 库软件随附的相关电子文档。
// 复制、使用或分发 Fluent UI 的许可条款是单独提供的。
// 若要了解有关 Fluent UI 许可计划的详细信息，请访问
// https://go.microsoft.com/fwlink/?LinkId=238214.
//
// 版权所有(C) Microsoft Corporation
// 保留所有权利。

// IDEView.cpp: CIDEView 类的实现
//

#include "stdafx.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义，并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "IDE.h"
#endif

#include "IDEDoc.h"
#include "IDEView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CIDEView

IMPLEMENT_DYNCREATE(CIDEView, CScrollView)

BEGIN_MESSAGE_MAP(CIDEView, CScrollView)
	// 标准打印命令
	ON_COMMAND(ID_FILE_PRINT, &CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CScrollView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CIDEView::OnFilePrintPreview)
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONUP()
END_MESSAGE_MAP()

// CIDEView 构造/析构

CIDEView::CIDEView() noexcept
{
	// TODO: 在此处添加构造代码

}

CIDEView::~CIDEView()
{
}

BOOL CIDEView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式

	return CScrollView::PreCreateWindow(cs);
}

// CIDEView 绘图

void CIDEView::OnDraw(CDC* pDC)
{
	CIDEDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

 	if (m_img.data != NULL)
 		DrawImage(m_img, pDC);
	//DrawGrid(pDC);
	// TODO: 在此处为本机数据添加绘制代码
}

void CIDEView::DrawMat(Mat & img, CDC *pDC)
{
	if (img.data == NULL)
		return;

	CRect rc;
	Mat imgTmp;
	// 获取控件大小;
	GetClientRect(rc);
	// 按控件大小，缩小或放大图片;
	cv::resize(img, imgTmp, cv::Size(rc.Width(), rc.Height()));
	//img.copyTo(imgTmp);

	// 转换格式;
	switch (imgTmp.channels())
	{
	case 1:
		cv::cvtColor(imgTmp, imgTmp, COLOR_GRAY2BGRA);
		break;
	case 3:
		cv::cvtColor(imgTmp, imgTmp, COLOR_BGR2BGRA);
		break;
	default:
		break;
	}

	int pixelBytes = imgTmp.channels()*(imgTmp.depth() + 1); // 计算一个像素多少个字节
	// 制作bitmapinfo(数据头);
	BITMAPINFO bitInfo;
	bitInfo.bmiHeader.biBitCount = 8 * pixelBytes;
	bitInfo.bmiHeader.biWidth = imgTmp.cols;
	bitInfo.bmiHeader.biHeight = -imgTmp.rows;
	bitInfo.bmiHeader.biPlanes = 1;
	bitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bitInfo.bmiHeader.biCompression = BI_RGB;
	bitInfo.bmiHeader.biClrImportant = 0;
	bitInfo.bmiHeader.biClrUsed = 0;
	bitInfo.bmiHeader.biSizeImage = 0;
	bitInfo.bmiHeader.biXPelsPerMeter = 0;
	bitInfo.bmiHeader.biYPelsPerMeter = 0;

	// 双缓存;
	CDC MemDC; //首先定义一个显示设备对象
	CBitmap MemBitmap;//定义一个位图对象

	//随后建立与屏幕显示兼容的内存显示设备
	MemDC.CreateCompatibleDC(NULL);
	//这时还不能绘图，因为没有地方画 ^_^
	//下面建立一个与屏幕显示兼容的位图，至于位图的大小嘛，可以用窗口的大小
	MemBitmap.CreateCompatibleBitmap(pDC, rc.Width(), rc.Height());

	//将位图选入到内存显示设备中
	//只有选入了位图的内存显示设备才有地方绘图，画到指定的位图上
	CBitmap *pOldBit = MemDC.SelectObject(&MemBitmap);

	//先用背景色将位图清除干净，这里我用的是白色作为背景
	//你也可以用自己应该用的颜色
	MemDC.FillSolidRect(0, 0, rc.Width(), rc.Height(), RGB(255, 255, 255));
	// Mat.data + bitmap数据头 -> MFC
	int nRet = ::StretchDIBits(
		MemDC,
		0, 0, rc.Width(), rc.Height(),
		0, 0, rc.Width(), rc.Height(),
		imgTmp.data,
		&bitInfo,
		DIB_RGB_COLORS,
		SRCCOPY
	);

	//将内存中的图拷贝到屏幕上进行显示
	pDC->BitBlt(0, 0, rc.Width(), rc.Height(), &MemDC, 0, 0, SRCCOPY);

	//绘图完成后的清理
	MemBitmap.DeleteObject();
	MemDC.DeleteDC();
}

void CIDEView::DrawGrid(CDC * pDC)
{
	// 获取客户区域;
	CRect rect;
	GetClientRect(&rect);
	
	// 备份北背色;
	COLORREF oldBkColor = pDC->GetBkColor();
	COLORREF gridColor = RGB(200,200,200);
	// Center lines
	CPen penDash;
	penDash.CreatePen(PS_DASH, 1, gridColor);
	CPen* pOldPen = pDC->SelectObject(&penDash);

	pDC->MoveTo(0, rect.top);
	pDC->LineTo(0, rect.bottom);
	pDC->MoveTo(rect.left, 0);
	pDC->LineTo(rect.right, 0);

	// Major unit lines
	CPen penDot;
	penDot.CreatePen(PS_DOT, 1, gridColor);
	pDC->SelectObject(&penDot);

	//for (int x = rect.left / 100 * 100; x < rect.right; x += 100)
	for (int x = rect.left / 50 * 50; x < rect.right; x += 50)
	{
		if (x != 0)
		{
			pDC->MoveTo(x, rect.top);
			pDC->LineTo(x, rect.bottom);
		}
	}

	//for (int y = rect.top / 100 * 100; y < rect.bottom; y += 100)
	for (int y = rect.top / 50 * 50; y < rect.bottom; y += 50)
	{
		if (y != 0)
		{
			pDC->MoveTo(rect.left, y);
			pDC->LineTo(rect.right, y);
		}
	}

	// Outlines
	CPen penSolid;
	penSolid.CreatePen(PS_SOLID, 1, gridColor);
	pDC->SelectObject(&penSolid);
	pDC->MoveTo(rect.left, rect.top);
	pDC->LineTo(rect.right, rect.top);
	pDC->LineTo(rect.right, rect.bottom);
	pDC->LineTo(rect.left, rect.bottom);
	pDC->LineTo(rect.left, rect.top);

	pDC->SelectObject(pOldPen);
	pDC->SetBkColor(oldBkColor);
}

void CIDEView::DrawImage(Mat & img, CDC * pDC)
{
	if (img.data == NULL)
		return;

	CRect rc;
	Mat imgTmp;
	// 获取控件大小;
	GetClientRect(rc);
	// 按控件大小，缩小或放大图片;
	//cv::resize(img, imgTmp, cv::Size(rc.Width(), rc.Height()));
	img.copyTo(imgTmp);

	// 转换格式;
	switch (imgTmp.channels())
	{
	case 1:
		cv::cvtColor(imgTmp, imgTmp, COLOR_GRAY2BGRA);
		break;
	case 3:
		cv::cvtColor(imgTmp, imgTmp, COLOR_BGR2BGRA);
		break;
	default:
		break;
	}

	// gdi+双缓存;
#if 1
	Bitmap bmp(imgTmp.cols, imgTmp.rows, imgTmp.step1(), PixelFormat32bppARGB, imgTmp.data);

	Graphics bmpGraphics(&bmp);
	bmpGraphics.SetSmoothingMode(SmoothingModeAntiAlias);
	// 画布颜色;
	//SolidBrush bkBrush(Color(0, 0, 0));
	//bmpGraphics.FillRectangle(&bkBrush, 0, 0, rc.Width(), rc.Height());

	// 在DC上画;
	Graphics graphDC(pDC->GetSafeHdc());
	CachedBitmap cachedBmp(&bmp, &graphDC);
	graphDC.DrawCachedBitmap(&cachedBmp, 0, 0);
#else
	Graphics graphDC(pDC->GetSafeHdc());
	Gdiplus::Bitmap bitmap(imgTmp.cols, imgTmp.rows, imgTmp.step1(), PixelFormat32bppARGB, imgTmp.data);
	graphDC.DrawImage(&bitmap, Gdiplus::Rect(rc.left, rc.top, rc.Width(), rc.Height()));
#endif
}

void CIDEView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	m_img = imread(_T("IDE.png"), CV_LOAD_IMAGE_COLOR);

	// 设置滚动条出现时的范围;
	CSize sizeTotal = CSize(m_img.cols, m_img.rows);
	//sizeTotal.cx = sizeTotal.cy = 100;
	//CSize sizePage = CSize(m_img.cols, m_img.rows);
	CSize sizePage = CSize(200, 200);
	CSize sizeLine = CSize(10, 10);
	SetScrollSizes(MM_TEXT, sizeTotal, sizePage, sizeLine);//单伴：MM_TEXT像素;
}


// CIDEView 打印


void CIDEView::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
	AFXPrintPreview(this);
#endif
}

BOOL CIDEView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 默认准备
	return DoPreparePrinting(pInfo);
}

void CIDEView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加额外的打印前进行的初始化过程
}

void CIDEView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加打印后进行的清理过程
}

void CIDEView::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
	ClientToScreen(&point);
	OnContextMenu(this, point);
}

void CIDEView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}


// CIDEView 诊断

#ifdef _DEBUG
void CIDEView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CIDEView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CIDEDoc* CIDEView::GetDocument() const // 非调试版本是内联的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CIDEDoc)));
	return (CIDEDoc*)m_pDocument;
}
#endif //_DEBUG


// CIDEView 消息处理程序


void CIDEView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
	// TODO: 在此添加专用代码和/或调用基类
	CScrollView::OnPrepareDC(pDC, pInfo);
	// mapping mode is MM_ANISOTROPIC
	// these extents setup a mode similar to MM_LOENGLISH
	// MM_LOENGLISH is in .01 physical inches
	// these extents provide .01 logical inches

#if 0
	pDC->SetMapMode(MM_ANISOTROPIC);
	pDC->SetViewportExt(pDC->GetDeviceCaps(LOGPIXELSX),
		pDC->GetDeviceCaps(LOGPIXELSY));
	pDC->SetWindowExt(100, -100);

	// set the origin of the coordinate system to the center of the page
	CPoint ptOrg;
	
	ptOrg.x = GetDocument()->GetSize().cx / 2;
	ptOrg.y = GetDocument()->GetSize().cy / 2;

	// ptOrg is in logical coordinates
	pDC->OffsetWindowOrg(-ptOrg.x, ptOrg.y);
#endif
}
