
// GUIComplexCalcView.cpp : CGUIComplexCalcView 類別的實作
//

#include "stdafx.h"
// SHARED_HANDLERS 可以定義在實作預覽、縮圖和搜尋篩選條件處理常式的
// ATL 專案中，並允許與該專案共用文件程式碼。
#ifndef SHARED_HANDLERS
#include "GUIComplexCalc.h"
#endif

#include "GUIComplexCalcDoc.h"
#include "GUIComplexCalcView.h"

#include <strstream>
using namespace std;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CGUIComplexCalcView

IMPLEMENT_DYNCREATE(CGUIComplexCalcView, CView)

BEGIN_MESSAGE_MAP(CGUIComplexCalcView, CView)
	// 標準列印命令
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CGUIComplexCalcView::OnFilePrintPreview)
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONUP()
    ON_WM_SETCURSOR()
    ON_WM_LBUTTONUP()
    ON_COMMAND(IDM_ADD, &CGUIComplexCalcView::OnAdd)
    ON_UPDATE_COMMAND_UI(IDM_ADD, &CGUIComplexCalcView::OnUpdateAdd)
    ON_COMMAND(IDM_DIVIDE, &CGUIComplexCalcView::OnDivide)
    ON_UPDATE_COMMAND_UI(IDM_DIVIDE, &CGUIComplexCalcView::OnUpdateDivide)
    ON_COMMAND(IDM_MULTIPLY, &CGUIComplexCalcView::OnMultiply)
    ON_UPDATE_COMMAND_UI(IDM_MULTIPLY, &CGUIComplexCalcView::OnUpdateMultiply)
    ON_COMMAND(IDM_SUBTRACT, &CGUIComplexCalcView::OnSubtract)
    ON_UPDATE_COMMAND_UI(IDM_SUBTRACT, &CGUIComplexCalcView::OnUpdateSubtract)
    ON_COMMAND(ID_APP_EXIT, &CGUIComplexCalcView::OnAppExit)
    ON_COMMAND(ID_APP_ABOUT, &CGUIComplexCalcView::OnAppAbout)
END_MESSAGE_MAP()

// CGUIComplexCalcView 建構/解構

CGUIComplexCalcView::CGUIComplexCalcView()
    : m_cxInch(0), m_cyInch(0),
      m_startPt(1,1),
      m_endPt(-1,-1),
      m_resultPt(0,0),
      m_typeOfOperation(0)
{
	// TODO: 在此加入建構程式碼

}

CGUIComplexCalcView::~CGUIComplexCalcView()
{
}

BOOL CGUIComplexCalcView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此經由修改 CREATESTRUCT cs 
	// 達到修改視窗類別或樣式的目的

	return CView::PreCreateWindow(cs);
}

// CGUIComplexCalcView 描繪

void CGUIComplexCalcView::OnDraw(CDC* pDC)
{
    int i;
	CGUIComplexCalcDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此加入原生資料的描繪程式碼
    // reference circle
    CBrush *pOldBr = (CBrush*) pDC->SelectStockObject(NULL_BRUSH);
    CPen bPen2(PS_DASH, 1, RGB(200, 200, 200));
    CPen *pOldPen = (CPen*) pDC->SelectObject(&bPen2);
    pDC->Ellipse(-100, 100, 100, -100);
    pDC->Ellipse(-200, 200, 200, -200);

    // x-axis
    CPen bAxisPen(PS_SOLID, 2, RGB(255, 0, 0));
    pDC->SelectObject(&bAxisPen);
    pDC->MoveTo(-200, 0);
    pDC->LineTo(200, 0);
    pDC->MoveTo(190,5); pDC->LineTo(200, 0);pDC->LineTo(190,-5); 
    for (i=-200; i<=200; i+=100)
    {
        pDC->MoveTo(i, -6); 
        pDC->LineTo(i, 6);
    }

    // y-axis
    pDC->MoveTo(0, -200);
    pDC->LineTo(0, 200);
    pDC->MoveTo(-5,190); pDC->LineTo(0,200);pDC->LineTo(5,190); 
    for (i=-200; i<=200; i+=100)
    {
        pDC->MoveTo(-6, i); 
        pDC->LineTo(6, i);
    }

    // labels
    pDC->TextOut(5,-3, CString("(0+0i)"));
    pDC->TextOut(168,-5, CString("(2+0i)"));
    pDC->TextOut(5,198, CString("(0+2i)"));

    // end point
    pDC->MoveTo(m_endPt.convertPoint()+CPoint(-5,5));
    pDC->LineTo(m_endPt.convertPoint()+CPoint(5,-5));
    pDC->MoveTo(m_endPt.convertPoint()+CPoint(5,5));
    pDC->LineTo(m_endPt.convertPoint()+CPoint(-5,-5));

    // bounding rectangle
    CPen bPen(PS_SOLID, 3, RGB(0, 0, 255));
    pOldPen = (CPen*) pDC->SelectObject(&bPen);
    pDC->Rectangle(CRect(-204, 204, 204,-204));

    // start point
    pDC->MoveTo(m_startPt.convertPoint()+CPoint(-5,5));
    pDC->LineTo(m_startPt.convertPoint()+CPoint(5,-5));
    pDC->MoveTo(m_startPt.convertPoint()+CPoint(5,5));
    pDC->LineTo(m_startPt.convertPoint()+CPoint(-5,-5));

    // text descriptions
    pDC->TextOutW(-200, -210, 
        CString("請在上面複數平面中以滑鼠左鍵及右鍵選擇兩點"));

    ostrstream sstr; m_startPt.print(sstr); sstr<<ends;
    CString line("起點: "); line += sstr.str(); sstr.freeze(false);
    pDC->SetTextColor(RGB(0,0,255));
    pDC->TextOutW(-190, -240, line);
    
    ostrstream sstr2; m_endPt.print(sstr2); sstr2<<ends; 
    CString line2("終點: "); line2 += sstr2.str(); sstr2.freeze(false);
    pDC->SetTextColor(RGB(255,0,0));
    pDC->TextOutW(-190, -260, line2);

    CString line3;
    m_resultPt = m_startPt;
    switch (m_typeOfOperation)
    {
    case 0:
        line3 = "起點 + 終點 = ";
        m_resultPt.add(m_endPt);
        break;
    case 1:
        line3 = "起點 - 終點 = ";
        m_resultPt.subtract(m_endPt);
        break;
    case 2:
        line3 = "起點 * 終點 = ";
        m_resultPt.multiply(m_endPt);
        break;
    case 3:
        line3 = "起點 / 終點 = ";
        m_resultPt.divide(m_endPt);
    }
    CPoint pt = m_resultPt.convertPoint();
    pDC->LPtoDP(&pt);

    ostrstream sstr3; m_resultPt.print(sstr3); sstr3<<ends; 
    line3 += sstr3.str(); sstr3.freeze(false);
    pDC->SetTextColor(RGB(192,0,128));
    if (!m_rectHit.PtInRect(pt))
        line3 += "  (outside the box)";
    pDC->TextOutW(-190, -290, line3);

    // result point
    pt = m_resultPt.convertPoint();
    CPen bResultPen(PS_SOLID, 3, RGB(192, 0, 128));
    pDC->SelectObject(&bResultPen);
    pDC->MoveTo(pt+CPoint(-6,0));
    pDC->LineTo(pt+CPoint(6,0));
    pDC->MoveTo(pt+CPoint(0,6));
    pDC->LineTo(pt+CPoint(0,-6));
    CRect resultRect(pt.x-6, pt.y-6, pt.x+7, pt.y+7);
    pDC->Ellipse(&resultRect);

    pDC->SelectObject(pOldPen);
    pDC->SelectObject(pOldBr);
}


// CGUIComplexCalcView 列印


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

BOOL CGUIComplexCalcView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 預設的準備列印程式碼
	return DoPreparePrinting(pInfo);
}

void CGUIComplexCalcView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 加入列印前額外的初始設定
}

void CGUIComplexCalcView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 加入列印後的清除程式碼
}

void CGUIComplexCalcView::OnRButtonUp(UINT nFlags, CPoint point)
{
    // TODO: 在此加入您的訊息處理常式程式碼和 (或) 呼叫預設值
    if (m_rectHit.PtInRect(point))
    {
        m_endPt = pointToComplex(point);
        Invalidate();
        CView::OnRButtonUp(nFlags, point);
    }
    else
    {
        ClientToScreen(&point);
        OnContextMenu(this, point);
    }
}

void CGUIComplexCalcView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
    CPoint sPoint(point);
    ScreenToClient(&sPoint);
    if (!m_rectHit.PtInRect(sPoint))
        theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}


// CGUIComplexCalcView 診斷

#ifdef _DEBUG
void CGUIComplexCalcView::AssertValid() const
{
	CView::AssertValid();
}

void CGUIComplexCalcView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CGUIComplexCalcDoc* CGUIComplexCalcView::GetDocument() const // 內嵌非偵錯版本
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CGUIComplexCalcDoc)));
	return (CGUIComplexCalcDoc*)m_pDocument;
}
#endif //_DEBUG


// CGUIComplexCalcView 訊息處理常式


void CGUIComplexCalcView::OnInitialUpdate()
{
    CView::OnInitialUpdate();

    // TODO: 在此加入特定的程式碼和 (或) 呼叫基底類別
    CClientDC dc(this);
    dc.SetMapMode(MM_LOENGLISH);
    CSize squareInch(1000,1000);
    dc.LPtoDP(&squareInch);
    m_cxInch = squareInch.cx/10.0; // 邏輯上每一英吋的 pixel 數
    m_cyInch = squareInch.cy/10.0;
//    TRACE("%f %f\n", m_cxInch, m_cyInch); // 108.4 108.9

//    short cxInch = dc.GetDeviceCaps(LOGPIXELSX); // 傳回資料不正確
//    short cyInch = dc.GetDeviceCaps(LOGPIXELSY);
//    TRACE("%d %d\n", cxInch, cyInch); // 96,96

    CFrameWnd *pMainWnd = GetParentFrame(); // 視窗寬 4.4 英吋, 高 6 英吋 (含標題列, 選單)
    pMainWnd->SetWindowPos(0,0,0 , (int)(4.4*m_cxInch+0.5), 
                            (int)(6*m_cyInch+0.5), SWP_NOMOVE|SWP_NOZORDER);
    pMainWnd->ShowWindow(SW_SHOW);

    int cx_border = GetSystemMetrics(SM_CXFRAME);
    int cy_border = GetSystemMetrics(SM_CYFRAME);
    int cy_caption = GetSystemMetrics(SM_CYCAPTION);
    CRect window_rect;
    pMainWnd->GetWindowRect(&window_rect);
    CPoint client_top_left(0, 0);
    pMainWnd->ClientToScreen(&client_top_left);
    int menu_height = client_top_left.y - window_rect.top - cy_caption - cy_border;
//    TRACE("cy_caption=%d menu_height=%d client_top_left.y=%d cy_border=%d\n",
//           cy_caption, menu_height, client_top_left.y, cy_border);

    CRect rectClient; GetClientRect(&rectClient); //裝置座標
    int xmargin = (int)((4.4-4.12)*m_cxInch - 2*cx_border)/2;
    int ymargin = (int)(((6-4.12)*m_cyInch - 2*cy_border - 
                        cy_caption - menu_height)/2.0 - 0.55*m_cyInch) ;
//    TRACE("xmargin=%d ymargin=%d right=%d bottom=%d\n", 
//          xmargin, ymargin, rectClient.right, rectClient.bottom);
    m_rectHit = CRect(xmargin, ymargin, 
        xmargin+(int)(4.1*m_cxInch), ymargin+(int)(4.1*m_cyInch));
}


void CGUIComplexCalcView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
    // TODO: 在此加入特定的程式碼和 (或) 呼叫基底類別
    GetClientRect(&m_rectClient); //裝置座標
    pDC->SetViewportOrg(CPoint(m_rectClient.right/2, 
        m_rectClient.bottom/2-(int)(0.55*m_cyInch))); //裝置座標
    pDC->SetMapMode(MM_LOENGLISH);

    CView::OnPrepareDC(pDC, pInfo);
}


BOOL CGUIComplexCalcView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    // TODO: 在此加入您的訊息處理常式程式碼和 (或) 呼叫預設值
    CPoint point;
    GetCursorPos(&point);
    pWnd->ScreenToClient(&point);
//    TRACE("point=(%d,%d)\n", point.x, point.y);
    if (m_rectHit.PtInRect(point))
    {
        ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));
        return TRUE;
    }
    return CView::OnSetCursor(pWnd, nHitTest, message);
}


void CGUIComplexCalcView::OnLButtonUp(UINT nFlags, CPoint point)
{
    // TODO: 在此加入您的訊息處理常式程式碼和 (或) 呼叫預設值
//    TRACE("point.x=%d point.y=%d\n", point.x, point.y);
    if (m_rectHit.PtInRect(point))
    {
        m_startPt = pointToComplex(point);
        Invalidate();
    }
    CView::OnLButtonUp(nFlags, point);
}


// 將平面上一個 CPoint 點轉換為 Complex 複數
Complex CGUIComplexCalcView::pointToComplex(CPoint point)
{
    CPoint origin((int)((m_rectHit.left+m_rectHit.right+0.5)/2.0), 
                  (int)((m_rectHit.top+m_rectHit.bottom+0.5)/2.0));
    return Complex((point.x - origin.x) / m_cxInch,
                   -(point.y - origin.y) / m_cyInch);
}

void CGUIComplexCalcView::OnAdd()
{
    // TODO: 在此加入您的命令處理常式程式碼
    m_typeOfOperation = 0;
    Invalidate();
}


void CGUIComplexCalcView::OnUpdateAdd(CCmdUI *pCmdUI)
{
    // TODO: 在此加入您的命令更新 UI 處理常式程式碼
    pCmdUI->SetCheck(m_typeOfOperation == 0);
}


void CGUIComplexCalcView::OnDivide()
{
    // TODO: 在此加入您的命令處理常式程式碼
    m_typeOfOperation = 3;
    Invalidate();
}


void CGUIComplexCalcView::OnUpdateDivide(CCmdUI *pCmdUI)
{
    // TODO: 在此加入您的命令更新 UI 處理常式程式碼
    pCmdUI->SetCheck(m_typeOfOperation == 3);
}


void CGUIComplexCalcView::OnMultiply()
{
    // TODO: 在此加入您的命令處理常式程式碼
    m_typeOfOperation = 2;
    Invalidate();
}


void CGUIComplexCalcView::OnUpdateMultiply(CCmdUI *pCmdUI)
{
    // TODO: 在此加入您的命令更新 UI 處理常式程式碼
    pCmdUI->SetCheck(m_typeOfOperation == 2);

}


void CGUIComplexCalcView::OnSubtract()
{
    // TODO: 在此加入您的命令處理常式程式碼
    m_typeOfOperation = 1;
    Invalidate();
}


void CGUIComplexCalcView::OnUpdateSubtract(CCmdUI *pCmdUI)
{
    // TODO: 在此加入您的命令更新 UI 處理常式程式碼
    pCmdUI->SetCheck(m_typeOfOperation == 1);
}


void CGUIComplexCalcView::OnAppExit()
{
    // TODO: 在此加入您的命令處理常式程式碼
    AfxGetMainWnd()->PostMessageW(WM_CLOSE);
}


void CGUIComplexCalcView::OnAppAbout()
{
    // TODO: 在此加入您的命令處理常式程式碼
    ((CGUIComplexCalcApp*)AfxGetApp())->OnAppAbout();
}
