/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
/********************************************************************/
/**
 * @file openglwindow.cpp
 * @brief fugenView.h の実装
 */
#include "stdafx.h"
#include "mgGL/Color.h"
#include "fugen.h"
#include "fugenView.h"
#include "MainFrm.h"

#include "Common/CommandBase.h"
#include "Misc/UserPreference.h"
#include "Undo/UndoManager.h"
#include "Undo/CameraAction.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// fugenView 診断

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

void fugenView::Dump(CDumpContext& dc) const{
	CView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// fugenView

IMPLEMENT_DYNCREATE(fugenView, CView)

fugenView::fugenView(bool is_perspective)
:MGOpenGLView(is_perspective),m_pDC(0),
m_locked(0), m_button_down_point(-1, -1), m_mousemove_old_point(-1,-1),
m_is_LButton_down(false), m_is_RButton_down(false),
m_viewop(ViewOpRotation),
m_spPlaneActionMgr(new CUndoManager), m_spCamActionMgr(new CUndoManager)
,m_idView(-1){
	m_printer.set_owner_COpenGLWindow(this);
	m_coordinateDrawer.set_no_display();

	UserPreference& pref = UserPreference::getInstance();
	int nHistSize = pref.GetIntValue(upv_Undo_Size);
	m_spPlaneActionMgr->RegisterTarget(static_cast<IPlaneActionTarget*>(this), nHistSize);
	m_spCamActionMgr->RegisterTarget(static_cast<ICameraActionTarget*>(this), nHistSize);
}

fugenView::~fugenView()
{
	release_dc();
}

BEGIN_MESSAGE_MAP(fugenView, CView)
	// Standard printing commands
	//{{AFX_MSG_MAP(fugenView)

	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)

	ON_WM_CONTEXTMENU()
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_ERASEBKGND()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MBUTTONDOWN()
	ON_WM_MBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_MOUSEWHEEL()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_SIZE()
	ON_WM_TIMER()

	ON_COMMAND(ID_VIEW_ZOOM_EXTENTS_ALL, OnViewZoomExtentsAll)
	ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOM_EXTENTS_ALL, OnUpdateViewZoomExtentsAll)
	ON_COMMAND(ID_VIEW_ZOOM_SELECTED_ALL, OnViewZoomSelectedAll)
	ON_UPDATE_COMMAND_UI(ID_VIEW_ZOOM_SELECTED_ALL, OnUpdateViewZoomSelectedAll)
	ON_WM_SETCURSOR()

	ON_UPDATE_COMMAND_UI(ID_CPLANE_GRID, OnUpdateCPlaneGrid)

	ON_COMMAND(ID_CPLANE_SWITCH, OnCPlaneSwitch)
	ON_UPDATE_COMMAND_UI(ID_CPLANE_SWITCH, OnCPlaneSwitchUpdateUI)

	ON_COMMAND(ID_CPLANE_UNDO, OnCPlaneUndo)
	ON_UPDATE_COMMAND_UI(ID_CPLANE_UNDO, OnUpdateCPlaneUndoUI)
	ON_COMMAND(ID_CPLANE_REDO, OnCPlaneRedo)
	ON_UPDATE_COMMAND_UI(ID_CPLANE_REDO, OnUpdateCPlaneRedoUI)

	ON_COMMAND(ID_VIEW_UNDO, OnViewUndo)
	ON_UPDATE_COMMAND_UI(ID_VIEW_UNDO, OnUpdateViewUndoUI)
	ON_COMMAND(ID_VIEW_REDO, OnViewRedo)
	ON_UPDATE_COMMAND_UI(ID_VIEW_REDO, OnUpdateViewRedoUI)

//fugenViewからStart
	ON_COMMAND(ID_VIEW_VOLUME_PLAN, OnViewVolumePlan)
	ON_COMMAND(ID_VIEW_VOLUME_PERSPECTIVE, OnViewVolumePerspective)
	ON_UPDATE_COMMAND_UI(ID_VIEW_VOLUME_PLAN, OnUpdateViewVolumePlan)
	ON_UPDATE_COMMAND_UI(ID_VIEW_VOLUME_PERSPECTIVE, OnUpdateViewVolumePerspective)
	ON_COMMAND(ID_VIEW_VOLUME_TOP, OnViewVolumeTop)
	ON_COMMAND(ID_VIEW_VOLUME_BOTTOM, OnViewVolumeBottom)
	ON_COMMAND(ID_VIEW_VOLUME_LEFT, OnViewVolumeLeft)
	ON_COMMAND(ID_VIEW_VOLUME_RIGHT, OnViewVolumeRight)
	ON_COMMAND(ID_VIEW_VOLUME_BACK, OnViewVolumeBack)
	ON_UPDATE_COMMAND_UI(ID_VIEW_VOLUME_BACK, OnUpdateViewVolumeBack)
	ON_UPDATE_COMMAND_UI(ID_VIEW_VOLUME_BOTTOM, OnUpdateViewVolumeBottom)
	ON_UPDATE_COMMAND_UI(ID_VIEW_VOLUME_LEFT, OnUpdateViewVolumeLeft)
	ON_UPDATE_COMMAND_UI(ID_VIEW_VOLUME_RIGHT, OnUpdateViewVolumeRight)
	ON_UPDATE_COMMAND_UI(ID_VIEW_VOLUME_TOP, OnUpdateViewVolumeTop)
	ON_COMMAND(ID_VIEW_VOLUME_FRONT, OnViewVolumeFront)
	ON_UPDATE_COMMAND_UI(ID_VIEW_VOLUME_FRONT, OnUpdateViewVolumeFront)

	ON_COMMAND(ID_VIEW_CAMERA_CPLANE_TOP, OnViewCameraCPlaneTop)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CAMERA_CPLANE_TOP, OnUpdateViewCameraCPlaneTop)
	ON_COMMAND(ID_VIEW_CAMERA_CPLANE_BOTTOM, OnViewCameraCPlaneBottom)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CAMERA_CPLANE_BOTTOM, OnUpdateViewCameraCPlaneBottom)
	ON_COMMAND(ID_VIEW_CAMERA_CPLANE_LEFT, OnViewCameraCPlaneLeft)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CAMERA_CPLANE_LEFT, OnUpdateViewCameraCPlaneLeft)
	ON_COMMAND(ID_VIEW_CAMERA_CPLANE_RIGHT, OnViewCameraCPlaneRight)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CAMERA_CPLANE_RIGHT, OnUpdateViewCameraCPlaneRight)
	ON_COMMAND(ID_VIEW_CAMERA_CPLANE_FRONT, OnViewCameraCPlaneFront)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CAMERA_CPLANE_FRONT, OnUpdateViewCameraCPlaneFront)
	ON_COMMAND(ID_VIEW_CAMERA_CPLANE_BACK, OnViewCameraCPlaneBack)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CAMERA_CPLANE_BACK, OnUpdateViewCameraCPlaneBack)

	ON_COMMAND(ID_VIEW_CAMERA_TARGET, OnViewCameraTarget)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CAMERA_TARGET, OnUpdateViewCameraTarget)
	ON_COMMAND(ID_VIEW_CAMERA_CAMERA_AND_TARGET, OnViewCameraCameraAndTarget)
	ON_UPDATE_COMMAND_UI(ID_VIEW_CAMERA_CAMERA_AND_TARGET, OnUpdateViewCameraCameraAndTarget)
//fugenViewからEnd

	//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// fugenView メッセージ ハンドラ

void fugenView::OnActivateView(
	BOOL   bActivate,
	CView* pActivateView,
	CView* pDeactiveView
){
	CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
	if(bActivate){
		fugenDoc* pDoc = GetDocument();
		ASSERT_VALID(pDoc);
		MGContext* pCon = pDoc->context();
		ASSERT(pCon);
		pCon->exec_tolerance();

		fugenStatusBar& sbar = theStatusBar();
		sbar.SetDocument(pDoc);
	}
}

void fugenView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo){
	ASSERT_VALID(pDC);//pDCはPrinterのDC
	ASSERT(pInfo);

	// Do printing initialization here
	m_printer.OnBeginPrinting(this, pDC, pInfo);
}

///pWndは右ボタンがおされたWindow.
void fugenView::OnContextMenu(CWnd* pWnd, CPoint pt){
	// OnContextMenu に来る pt はスクリーン座標 (see MSDN)
	CPoint ptClient(pt);
	ScreenToClient(&ptClient);

	// XXX: クリック地点からマウスが動いていなかったら、
	// コンテキストメニューを表示する。
	if(m_button_down_point != ptClient){
		// デフォルトのハンドラーは呼ばない。
		// MDI クライアントのコンテキストメニューがビュー上に出て格好悪い。
		//CView::OnContextMenu(pWnd, pt);
		return;
	}

	// 専用リソースで表示する。
	CMenu menu;
	VERIFY(menu.LoadMenu(IDR_DEFAULT_CONTEXT_MENU));

	CMenu* pPopup = menu.GetSubMenu(0);
	ASSERT(pPopup);

	// 現在のツールにコンテキストメニューを差分修正させる。
	MGCommandBase* cmd=current_command_tool();
	cmd->setEventView(this);
	cmd->ModifyContextMenu(*pPopup);

	// メニューに横棒が並んでいたら削除
	const int nItem = pPopup->GetMenuItemCount();
	for(int i = nItem - 1; i > 0; --i){
		if(!pPopup->GetMenuItemID(i) &&
		   !pPopup->GetMenuItemID(i - 1)){
			pPopup->RemoveMenu(i, MF_BYPOSITION);
		}
	}

	// ポップアップ。
	// コマンドルーティングのため、引数に親ウィンドウを指定する。
	pPopup->TrackPopupMenu(
		TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, ::AfxGetMainWnd());
	
}

int fugenView::OnCreate(LPCREATESTRUCT lpCreateStruct){
	if(CView::OnCreate(lpCreateStruct) == -1)
		return -1;
	return 0;
}

void fugenView::OnDestroy(){
	::wglMakeCurrent(NULL, NULL);
	release_dc();
	CView::OnDestroy();
}

void fugenView::OnDraw(CDC* pDC){
	CRect rct;
	GetClientRect(&rct);
	if(0<rct.bottom && 0<rct.right){
		set_window(rct.Width(),rct.Height());
		CWaitCursor sandglass;
		redrawOnlythis(pDC);
	}
}

void fugenView::OnEndPrinting(
	CDC* pDC,///<PrinterのDC
	CPrintInfo* pInfo
){
	ASSERT_VALID(pDC);
	ASSERT(pInfo);

	m_printer.OnEndPrinting(this, pDC, pInfo);
}

void fugenView::OnEndPrintPreview(CDC* pDC, CPrintInfo* pInfo, POINT point, CPreviewView* pView){
	m_printer.OnEndPrintPreview(this, pDC, pInfo, point, pView);
	CView::OnEndPrintPreview(pDC, pInfo, point, pView);
}

BOOL fugenView::OnEraseBkgnd(CDC* pDC){
	if(display_list()){
		// 画面リサイズ時のチラつき防止のため背景クリア
		CRect rct;
		GetClientRect(&rct);
		CBrush brush;

		brush.CreateSolidBrush(ARGBtoCOLORREF(GetDocument()->context()->Bcolor().get_colorAsUInt()));
		pDC->FillRect(&rct, &brush);
		return TRUE;
	}

	return CView::OnEraseBkgnd(pDC);
}

//Copy the enability of the parent's cplane.
void fugenView::copyCplaneEnability(fugenView* pParent){
	if(pParent){
		//If this has parent, set cplane status same as the parent's.
		const MGConstructionPlane& cplpar = pParent->cplane();
		if(cplpar.enabled()){
			cplane().set_enable();
		}else{
			cplane().set_disable();
		}
	}else{
		//If this has not parent, set enable.
		cplane().set_enable();
	}
}

void fugenView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags){
	make_RC_current();
	
	UserPreference& pref = UserPreference::getInstance();
	double magPlus = pref.GetDoubleValue(upv_ViewOp_ScaleDelta);
	float magR = (float)pref.GetDoubleValue(upv_ViewOp_RotationDelta);
	double magT = pref.GetDoubleValue(upv_ViewOp_TranslationDelta) * diameter();

	bool ctrlKeyDown = (GetKeyState(VK_CONTROL) < 0); // 変位を大きくするか
	if(ctrlKeyDown){
		magPlus *= 2.0;
		magR *= 4.;
		magT *= 10.;
	}
	bool bRFlip = pref.GetBoolValue(upv_ViewOp_RotationFlip);
	if(bRFlip)
		magR = -magR;
	bool bTFlip = pref.GetBoolValue(upv_ViewOp_TranslationFlip);
	if(bTFlip)
		magT = -magT;
	bool bRotate = !is_2D() && (GetKeyState(VK_SHIFT) < 0); // 回転変換か

	switch(nChar){		
	case VK_HOME:	ctrlKeyDown ? home():cplaneHome(); break;
	case VK_ADD:	ExecZoom(magPlus); break;
	case VK_SUBTRACT:ExecZoom(1./magPlus); break;
	case VK_UP:	  bRotate ? ExecRotate(magR,1.,0.,0.) :ExecPan(0.,magT); break;
	case VK_DOWN: bRotate ? ExecRotate(-magR,1.,0.,0.):ExecPan(0.,-magT); break;
	case VK_RIGHT:bRotate ? ExecRotate(magR,0.,1.0,0.):ExecPan(magT,0.); break;
	case VK_LEFT: bRotate ? ExecRotate(-magR,0.,1.,0.):ExecPan(-magT,0.); break;
	default:;
	}

	MGCommandBase* cmd=current_command_tool();
	cmd->setEventView(this);
	if(cmd->OnKeyDown(this,nChar,nRepCnt,nFlags))
		terminate_current_command_tool();
	release_dc();

	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}

void fugenView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags){
	make_RC_current();
	MGCommandBase* cmd=current_command_tool();
	cmd->setEventView(this);
	if(cmd->OnKeyUp(this,nChar,nRepCnt,nFlags))
		terminate_current_command_tool();
	release_dc();
	
	CView::OnKeyUp(nChar, nRepCnt, nFlags);
}

void fugenView::OnLButtonDblClk(UINT nFlags, CPoint point){
	make_RC_current();
	MGCommandBase* cmd=current_command_tool();
	cmd->setEventView(this);
	if(cmd->OnLButtonDblClk(this,nFlags,point))
		terminate_current_command_tool();
	release_dc();
	
	CView::OnLButtonDblClk(nFlags, point);
}

void fugenView::OnLButtonDown(UINT nFlags, CPoint point){
	make_RC_current();
	// ピックイベント開始。
	BeginPick(point);

	if(is_standard_view()){
		CFrameWnd* frame=GetParentFrame();
		frame->SetActiveView(this);
	}

	MGCommandBase* cmd=current_command_tool();
	cmd->setEventView(this);
	if(cmd->OnLButtonDown(this,nFlags,point))
		terminate_current_command_tool();
	release_dc();

	CView::OnLButtonDown(nFlags, point);
}

void fugenView::OnLButtonUp(UINT nFlags, CPoint point){
	make_RC_current();

	if(!IsPicking()){
		clearAllLButtonDownStatus();
	}
	if(!m_locked){
		MGCommandBase* cmd=current_command_tool();
		cmd->setEventView(this);
		if(cmd->OnLButtonUp(this,m_button_down_point,nFlags,point))
			terminate_current_command_tool();

		EndPick();
		redraw();///必要か？->MGSelectState::selection()でのredrawをやめ
				///ここでやるとした2013/12/23水野
	}
	release_dc();

	CView::OnLButtonUp(nFlags, point);
}

void fugenView::OnMButtonDblClk(UINT nFlags, CPoint point){
	make_RC_current();
	release_dc();
	
	CView::OnMButtonDblClk(nFlags, point);
}

void fugenView::OnMButtonDown(UINT nFlags, CPoint point){
	if(IsTracking()){
		CView::OnMButtonDown(nFlags, point);
		return;
	}

	// Ctrl + RButton 押しをエミュレート
	BeginTracking(nFlags, point);
	m_viewop = ViewOpPan;//view operation is limitted to panning??

	int sx,sy;
	change_sc(point,sx,sy);
	set_center_current(sx,sy);

	// デフォルトのハンドリングを行う
	CView::OnMButtonDown(nFlags, point);
}

void fugenView::OnMButtonUp(UINT nFlags, CPoint point){
	// このケースはほとんどないはずだが、
	// デフォルトのハンドリングを行う
	if(!IsTracking()){
		CView::OnMButtonUp(nFlags, point);
		return;
	}

	// マウスイベント捕捉終了
	EndTracking();

	// 最後にデフォルトのハンドリングを行う
	CView::OnMButtonUp(nFlags, point);
}

void fugenView::OnMouseMove(UINT nFlags, CPoint point){
	if(m_mousemove_new_point == point || point == m_button_down_point)
		return;
	m_mousemove_new_point=point;

	// マウス左ボタンがプレスされていなければ、ピックイベントを解除する。
	if(!(MK_LBUTTON & nFlags))
		EndPick();

	if(IsTracking()){ // tracking
		// マウスイベント捕捉開始

		if(!((MK_MBUTTON | MK_RBUTTON) & nFlags)){
			// TODO: プログラムがここに来ることがなかったら
			// この行を削除したい。
			EndTracking();
		}else{
			switch(m_viewop){
			case ViewOpRotation:
				// rotate(3D); pan(2D)
				mouse_move_transform(point);
				break;
			case ViewOpPan:
				// パン
				pan(m_mousemove_old_point, point);
				break;
			case ViewOpZoom:{// zoom			
				int diff = m_mousemove_old_point.y - point.y; // Windows 座標系
				if(diff){
					UserPreference& pref = UserPreference::getInstance();
					double ds = pref.GetDoubleValue(upv_ViewOp_ScaleDelta);
					if(0<ds && ds<1.){
						ds = 1./ds;
					}
					scale(diff>0 ? ds : 1./ds);
				}
				}
				break;
			default:
				ASSERT(false);
				break;
			}
			redrawOnlythis();//再描画
		}
	}else{
		MGCommandBase* cmd=current_command_tool();
		cmd->setEventView(this);
		if(cmd->OnMouseMove(this,nFlags,point))
			terminate_current_command_tool();
	}
	m_mousemove_old_point=point;
	CView::OnMouseMove(nFlags, point);
}

namespace
{
	const double MAX_FACTOR = 1.e+3;
	const double MIN_FACTOR = 1.e-3;
}

BOOL fugenView::OnMouseWheel(UINT nFlags, short zDelta, CPoint point){
	make_RC_current();

	if(!zDelta) return false;
	double delta=fabs(double(zDelta))/115.;
	UserPreference& pref = UserPreference::getInstance();
	float factor = float(pref.GetDoubleValue(upv_ViewOp_ScaleDelta) * delta);
	if (nFlags&MK_CONTROL) factor *= 2.;
	if(factor>=MAX_FACTOR)
		return false;
	if(factor<=MIN_FACTOR)
		return false;

	// 拡大・縮小
	if(zDelta>0)
		factor=float(1./factor);

	CRect rect;
	GetWindowRect(&rect);
	point.x -= rect.left;
	point.y -= rect.top;
	ExecZoom(factor,&point);

	MGCommandBase* cmd=current_command_tool();
	cmd->setEventView(this);
	if(cmd->OnMouseWheel(this,nFlags,zDelta,point))
		terminate_current_command_tool();
	release_dc();
	return CView::OnMouseWheel(nFlags, zDelta, point);
}

void fugenView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo){
	CView::OnPrepareDC(pDC, pInfo);
	if(pInfo){
		m_printer.OnPrepareDC(this, pDC, pInfo);
	}
}

BOOL fugenView::OnPreparePrinting(CPrintInfo* pInfo){
	ASSERT(pInfo);
	return m_printer.OnPreparePrinting(this, pInfo);
}

void fugenView::OnPrint(CDC* pDC, CPrintInfo* pInfo){
	ASSERT_VALID(pDC);
	ASSERT(pInfo);

	m_printer.OnPrint(this, pDC, pInfo);
}

void fugenView::OnRButtonDblClk(UINT nFlags, CPoint point){
	make_RC_current();
	MGCommandBase* cmd=current_command_tool();
	cmd->setEventView(this);
	if(cmd->OnRButtonDblClk(this,nFlags,point))
		terminate_current_command_tool();
	release_dc();

	CView::OnRButtonDblClk(nFlags, point);
}

void fugenView::OnRButtonDown(UINT nFlags, CPoint point){
	make_RC_current();
	//std::cout<<"***In RDown button="<<m_is_RButton_down<<std::endl;
	if(!IsTracking()){
		BeginTracking(nFlags, point);
		int sx,sy;
		change_sc(point,sx,sy);
		set_center_current(sx,sy);
	}

	// カレントコマンドにだけイベントを流す
	MGCommandBase* cmd=current_command_tool();
	cmd->setEventView(this);
	if(cmd->OnRButtonDown(this,nFlags,point)){
		terminate_current_command_tool();
	}
	release_dc();

	// デフォルトのハンドリングを行う
	redraw();
	CView::OnRButtonDown(nFlags, point);
}

void fugenView::OnRButtonUp(UINT nFlags, CPoint point){
	// このケースはほとんどないはずだが、
	// デフォルトのハンドリングを行う
	if(!IsTracking()){
		CView::OnRButtonUp(nFlags, point);
		return;
	}
	make_RC_current();

	// カレントコマンドにだけイベントを流す
	MGCommandBase* cmd=current_command_tool();
	cmd->setEventView(this);
	if(cmd->OnRButtonUp(this,m_button_down_point,nFlags,point)){
		terminate_current_command_tool();
	}
	release_dc();

	// マウスイベント捕捉終了
	EndTracking();

	// 最後にデフォルトのハンドリングを行う
	CView::OnRButtonUp(nFlags, point);
}

BOOL fugenView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message){
	// カレントコマンドがカーソルを変更したいならば、そうさせる。
	if(current_command_tool()->OnSetCursor(this, pWnd, nHitTest, message)){
		// 以降のカーソル処理を中断する。
		return TRUE;
	}

	// トラッキング中ならば
	//std::cout<<m_is_RButton_down<<std::endl;
	if(IsTracking()){
		UINT nIDR = 0;
		HCURSOR hCursor = 0;

		switch(m_viewop){
		case ViewOpRotation:
			// rotate(3D); pan(2D)
			nIDR = is_perspective() ? IDC_CURSOR_ROTATE : IDC_CURSOR_PAN;
			break;
		case ViewOpPan:
			nIDR = IDC_CURSOR_PAN;
			break;
		case ViewOpZoom:
			nIDR = IDC_CURSOR_ZOOM;
			break;
		default:
			ASSERT(false);
			break;
		}

		if(nIDR){
			VERIFY(hCursor = theApp.LoadCursor(nIDR));
			::SetCursor(hCursor);
		}

		// 以降のカーソル処理を中断する。
		return TRUE;
	}

	// デフォルトの処理。矢印カーソルか何か。
	return CView::OnSetCursor(pWnd, nHitTest, message);
}

void fugenView::OnSize(UINT nType, int cx, int cy){
	CView::OnSize(nType, cx, cy);
	set_window(cx,cy);
}

void fugenView::OnTimer(UINT_PTR nIDEvent){
}

// lHint=00000000 : Invalidate();
void fugenView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint){
	Invalidate(FALSE);
}

//Get the original view direction vector.
MGUnit_vector fugenView::view_direction_original()const{
	return MGUnit_vector(-eye_position());
}

void fugenView::OnCPlaneSwitch(){
	MGConstructionPlane& plane = cplane();
	plane.enabled() ? plane.set_disable() : plane.set_enable();
	Invalidate(FALSE);
}

void fugenView::OnCPlaneSwitchUpdateUI(CCmdUI* pCmdUI){
	pCmdUI->SetCheck(cplane().enabled() ? 1 : 0);
}

void fugenView::OnViewZoomExtentsAll(){
	ZoomToAllExtents();
}

void fugenView::OnUpdateViewZoomExtentsAll(CCmdUI* pCmdUI){
	pCmdUI->Enable(!GetDocument()->get_main_group().empty());
}

void fugenView::OnViewZoomSelectedAll(){
	ZoomToAllSelections();
}

void fugenView::OnUpdateViewZoomSelectedAll(CCmdUI* pCmdUI){
	pCmdUI->Enable(!current_objects().empty());
}

/// シーン内に存在するすべてのモデルがビューにフィットするようにズーム
void fugenView::ZoomToAllExtents(){
	fugenDoc* pDoc = GetDocument();
	if(pDoc->get_main_group().empty()){
		return;
	}
	const MGBox& box=pDoc->box();
	ExecPanZoom(box);
}

/// 選択モデルがビューにフィットするようにズーム
void fugenView::ZoomToAllSelections(){
	const MGPickObjects& picked = current_objects();
	if(picked.empty()){
		return;
	}

	MGBox box(MGDefault::empty_box());
	MGPickObjects::const_iterator first = picked.begin(), last = picked.end();
	for(; first != last; ++first){
		if((*first)->top_object()){
			box |= (*first)->top_object()->box();
		}
	}

	if(box.empty()){
		return;
	}

	ExecPanZoom(box);
}
