#include "stdafx.h"
#include "FormMain.h"

#include <QFileInfo>
#include <fstream>
#include <sstream>

#include <cassert>
#include <QSettings>

#include "FormVertexBuilder.h"
#include "FullScreenPanel.h"

#include <Qt5Utility/QGui.h>

#include <QMessageBox>
#include <QFileDialog>
#include <QPrintDialog>
#include <QPrintPreviewDialog>

#include "BuildInfo.h"
#include "PathInfo.h"
#include "PostprocLibrary.h"



QColor ToQColor(const lib_graph::color4f& c)
{
	int r = lm::clamp(0, (int)(c.r() * 255.0f), 255);
	int g = lm::clamp(0, (int)(c.g() * 255.0f), 255);
	int b = lm::clamp(0, (int)(c.b() * 255.0f), 255);
	int a = lm::clamp(0, (int)(c.a() * 255.0f), 255);

	return QColor(r, g, b, a);
}



FormMain::FormMain(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	m_EnableAllFeatures = false;

	setAcceptDrops(true);

	setWindowTitle("QtGeoViewer");

	InitializeGLView();
	InitializeStatusBar();
	InitializeMenu();
	InitializeCoordinateCombobox();
	InitializeEventFilter();
	InitContextMenu();

	InitDataBinding();

	SyncViewSettingsFromGUI();
	SyncUVViewSettingsFromGUI();
	SyncSceneSettingsFromGUI();
	ApplyGeomStateFromGUI();
	SyncShaderSettingsToGUI();

	ui.toolBar_View->setVisible( ui.actionWindow_ToolBarView->isChecked() );

	UpdateViewTypeFromMenu();

	CenteringSplitter();

	RebuildObjectList();

	InitializeSubDlg();

	InitializeAnimation();

	InitializeFromConfigFiles();

	HideFeatures();

	ResetHoleRange();

	this->show();

	ProcArguments();
}

FormMain::~FormMain()
{
}


void FormMain::HideFeatures(void)
{
	bool b = m_EnableAllFeatures;

	ui.actionVertexBuilder->setVisible(b);
	ui.menuPrintRoot->menuAction()->setVisible(b);
	ui.actionShadowmap->setVisible(b);
	ui.actionEnvmap->setVisible(b);
	ui.actionShaderCustom->setVisible(b);
	ui.actionWindowCustomShader->setVisible(b);
	ui.actionPyScript->setVisible(b);
	ui.actionConsole->setVisible(b);
}

void FormMain::InitializeEventFilter(void)
{
	ui.editEnvMap->installEventFilter(this);
	ui.editMatcap->installEventFilter(this);
	ui.editMatCapEachMaterial->installEventFilter(this);
}

void FormMain::InitDataBinding(void)
{
	InitializeVisiblStateMenu();
	InitializeUVStateMenu();
	InitializeSceneStateMenu();
	InitializeGeomStateMenu();
	InitializeCursorMenu();
}

void FormMain::InitializeVisiblStateMenu(void)
{
	DataBinderMap& dbmap = m_Binder_ViewConfig;

	View3DConfig& cfg_3d = m_View3d.m_Config;

	dbmap.AddBinder(new MenuBinder(ui.actionDrawBBox            , &cfg_3d.m_DrawBBox            ));
	dbmap.AddBinder(new MenuBinder(ui.actionFaceVBO             , &cfg_3d.m_EnableFaceVBO       ));
	dbmap.AddBinder(new MenuBinder(ui.actionVidTopMost          , &cfg_3d.m_ShowVidTopMost      ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawBBoxRange       , &cfg_3d.m_DrawBBoxRange       ));
	dbmap.AddBinder(new MenuBinder(ui.actionWireDispList        , &cfg_3d.m_EnableWireDispList  ));
	dbmap.AddBinder(new MenuBinder(ui.actionMultisample         , &cfg_3d.m_EnableMultisample   ));
	dbmap.AddBinder(new MenuBinder(ui.actionCoverageTransparent , &cfg_3d.m_EnableCoverageTrans ));
	dbmap.AddBinder(new MenuBinder(ui.actionShowSelVertCoord    , &cfg_3d.m_ShowSelVertCoord    ));
	dbmap.AddBinder(new MenuBinder(ui.actionHighlightSelected   , &cfg_3d.m_HighlightSelected   ));
	dbmap.AddBinder(new MenuBinder(ui.actionFixMaterialSilver   , &cfg_3d.m_UseFixMaterial      ));
	dbmap.AddBinder(new MenuBinder(ui.actionShadowmapBuffer     , &cfg_3d.m_DrawShadowmapBuf    ));
	dbmap.AddBinder(new MenuBinder(ui.actionEnableTexture3D     , &cfg_3d.m_EnableTexture       ));
	dbmap.AddBinder(new MenuBinder(ui.actionEnableLighting      , &cfg_3d.m_EnableLighting      ));
	dbmap.AddBinder(new MenuBinder(ui.actionEnableCulling       , &cfg_3d.m_EnableCullFace      ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawWire            , &cfg_3d.m_DrawWire            ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawVid             , &cfg_3d.m_DrawVid             ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawVertNormal      , &cfg_3d.m_DrawVertNormal      ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawVert            , &cfg_3d.m_DrawVert            ));
	dbmap.AddBinder(new MenuBinder(ui.actionWireVBO             , &cfg_3d.m_EnableWireVBO       ));
	dbmap.AddBinder(new MenuBinder(ui.actionIndexColorMode      , &cfg_3d.m_IndexMaterial       ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawMiniAxis        , &cfg_3d.m_DrawMiniAxis        ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawLookPos         , &cfg_3d.m_DrawLookPos         ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawLightPos        , &cfg_3d.m_DrawLightPosition   ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawGround          , &cfg_3d.m_DrawGround          ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawFid             , &cfg_3d.m_DrawFid             ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawFace            , &cfg_3d.m_DrawFace            ));
	dbmap.AddBinder(new MenuBinder(ui.actionCameraRecords       , &cfg_3d.m_DrawCameraRecord    ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawAxis            , &cfg_3d.m_DrawAxis            ));
	dbmap.AddBinder(new MenuBinder(ui.actionDoubleSideShading   , &cfg_3d.m_DoubleSideShading   ));
	dbmap.AddBinder(new MenuBinder(ui.actionDirectionalLight    , &cfg_3d.m_LightIsDirectional  ));
	dbmap.AddBinder(new MenuBinder(ui.actionCullFrontOrBack     , &cfg_3d.m_CullAngle_F         ));
	dbmap.AddBinder(new MenuBinder(ui.actionHighlightMaterial   , &cfg_3d.m_HighlightMaterial   ));
	dbmap.AddBinder(new MenuBinder(ui.actionCloseVert           , &cfg_3d.m_ShowCloseVertInfo   ));
	dbmap.AddBinder(new MenuBinder(ui.actionCameraRange         , &cfg_3d.m_DrawRenderRange     ));
	dbmap.AddBinder(new MenuBinder(ui.actionRenderTime          , &cfg_3d.m_ShowRenderTime      ));
	dbmap.AddBinder(new MenuBinder(ui.actionUseFixTexture       , &cfg_3d.m_UseFixTexture       ));
	dbmap.AddBinder(new MenuBinder(ui.actionShowSelVertIdx      , &cfg_3d.m_ShowSelVertIdx      ));
	dbmap.AddBinder(new MenuBinder(ui.actionPickTransparent     , &cfg_3d.m_PickTransparent     ));
	dbmap.AddBinder(new MenuBinder(ui.actionFlatShading         , &cfg_3d.m_EnableFlatShade     ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawPolylineLenWhl  , &cfg_3d.m_DrawPolylineLenWhl  ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawPolylineLen     , &cfg_3d.m_DrawPolylineLen     ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawPolyline        , &cfg_3d.m_DrawPolyline        ));
	dbmap.AddBinder(new MenuBinder(ui.actionShowMeasure         , &cfg_3d.m_DrawCameraMeasure   ));
	dbmap.AddBinder(new MenuBinder(ui.actionFlipMouseMR         , &cfg_3d.m_FlipMouseMR         ));

	for (GuiBinder& binder : dbmap.m_BinderMap)
	{
		MenuBinder* mb = dynamic_cast<MenuBinder*>(&binder);
		if (mb != NULL)
		{
			QAction* a = mb->GetMenu();
			connect(a, SIGNAL(triggered(bool)), this, SLOT(actionVisibleStates_Triggered(bool)));
		}
	}
}

void FormMain::InitializeUVStateMenu(void)
{
	DataBinderMap& dbmap = m_Binder_UVConfig;

	dbmap.AddBinder(new MenuBinder(ui.actionUVRepeat        , &m_View2d.m_RepeatTexture             ));
	dbmap.AddBinder(new MenuBinder(ui.actionUseFixTexture2D , &m_View2d.m_UseFixTexute              ));
	dbmap.AddBinder(new MenuBinder(ui.actionShowVertex2d    , &m_View2d.m_DrawVerts                 ));
	dbmap.AddBinder(new MenuBinder(ui.actionShowImage2d     , &m_View2d.m_EnableTexture             ));
	dbmap.AddBinder(new MenuBinder(ui.actionTextureMipmap   , &m_Scene.m_TexConfig.m_EnableMipmap   ));
	dbmap.AddBinder(new MenuBinder(ui.actionTextureCompress , &m_Scene.m_TexConfig.m_EnableCompress ));
	dbmap.AddBinder(new MenuBinder(ui.actionUVFlipY         , &m_Scene.m_TextureTransform.m_FlipY   ));

	for (GuiBinder& binder : dbmap.m_BinderMap)
	{
		MenuBinder* mb = dynamic_cast<MenuBinder*>(&binder);
		if (mb != NULL)
		{
			QAction* a = mb->GetMenu();
			connect(a, SIGNAL(triggered(bool)), this, SLOT(actionVisibleStatesUV_Triggered(bool)));
		}
	}
}

void FormMain::InitializeSceneStateMenu(void)
{
	DataBinderMap& dbmap = m_Binder_Scene;

	dbmap.AddBinder(new CheckboxBinder( ui.checkEnvMap         , &m_Scene.m_EnvImg.m_VisibleEnvSphere       ));
	dbmap.AddBinder(new CheckboxBinder( ui.checkEnvReflection  , &m_Scene.m_EnvImg.m_IsEnableReflection     ));
	dbmap.AddBinder(new CheckboxBinder( ui.checkShadowEnabled  , &m_Scene.m_ShadowConfig.m_EnableShadow     ));
	dbmap.AddBinder(new CheckboxBinder( ui.checkSoftShadow     , &m_Scene.m_ShadowConfig.m_EnableSoftShadow ));

	for (GuiBinder& binder : dbmap.m_BinderMap)
	{
		CheckboxBinder* mb = dynamic_cast<CheckboxBinder*>(&binder);
		if (mb != NULL)
		{
			QCheckBox* c = mb->GetCheckBox();
			connect(c, SIGNAL(toggled(bool)), this, SLOT(actionSceneStates_Toggled(bool)));
		}
	}
}

void FormMain::InitializeCursorMenu(void)
{
	DataBinderMap& dbmap = m_Binder_Cursor;

	Cursor3D& cursor = m_Scene.m_Cursor3d;
	dbmap.AddBinder(new MenuBinder( ui.actionShowCursor     , &cursor.ShowCursor     ));
	dbmap.AddBinder(new MenuBinder( ui.actionCursorToDepth  , &cursor.CursorDepth    ));
	dbmap.AddBinder(new MenuBinder( ui.actionCursorCoord    , &cursor.ShowCoord      ));
	dbmap.AddBinder(new MenuBinder( ui.actionCheckBaryCoord , &cursor.CheckBaryCoord ));
	dbmap.AddBinder(new MenuBinder( ui.actionCursorAxis     , &cursor.ShowAxis       ));
	dbmap.AddBinder(new MenuBinder( ui.actionMeasure        , &cursor.ShowMeasure    ));
	dbmap.AddBinder(new MenuBinder( ui.actionMeasureLen     , &cursor.ShowMeasureLen ));
	dbmap.AddBinder(new MenuBinder( ui.actionMeasureXYZ     , &cursor.ShowMeasureXYZ ));

	for (GuiBinder& binder : dbmap.m_BinderMap)
	{
		MenuBinder* mb = dynamic_cast<MenuBinder*>(&binder);
		if (mb != NULL)
		{
			QAction* a = mb->GetMenu();
			connect(a, SIGNAL(triggered(bool)), this, SLOT(actionCursorMenuStates_Toggled(bool)));
		}
	}
}


void FormMain::InitializeGeomStateMenu(void)
{
	AddGeomStateAction( ui.actionCentering  );
	AddGeomStateAction( ui.actionAutoResize );
}

void FormMain::AddGeomStateAction(const QAction* action)
{
	connect(action, SIGNAL(triggered(bool)), this, SLOT(actionGeomStates_Triggered(bool)));
}


void FormMain::InitializeGLView(void)
{
	ui.GLWidgetMain->setMouseTracking(true);
	ui.GLWidgetUV->setMouseTracking(true);

	ui.GLWidgetMain->SetViewer(&m_View3d);
	m_View3d.InitializeView(ui.GLWidgetMain);

	ui.GLWidgetUV->SetViewer(&m_View2d);
	m_View2d.InitializeView(ui.GLWidgetUV);

	m_Widgets.AddWidget(ui.GLWidgetMain);
	m_Widgets.AddWidget(ui.GLWidgetUV);

	m_View2d.m_Widgets = &m_Widgets;
	m_View3d.m_Widgets = &m_Widgets;

	// OpenGLのリストの共有化
	SetContextShare();

	m_ContextShare.BeginDrawTop();

	m_Scene.Initialize();

	m_ContextShare.EndDrawTop();

	m_View3d.RegisterScene( &m_Scene );
	m_View2d.RegisterScene( &m_Scene );

	connect(&m_View3d, SIGNAL(SelectedObjectChanged(int)), SLOT(View3D_SelectedObjectChanged(int)));
	connect(&m_View3d, SIGNAL(CameraMoved(void)), SLOT(View3D_CameraMoved(void)));
}

// OpenGLのリストの共有化
void FormMain::SetContextShare(void)
{
	ui.GLWidgetUV->makeCurrent();
	m_ContextShare.AddContext( GetDC((HWND)ui.GLWidgetUV->winId()) , wglGetCurrentContext() );
	ui.GLWidgetUV->doneCurrent();

	ui.GLWidgetMain->makeCurrent();
	m_ContextShare.AddContext( GetDC((HWND)ui.GLWidgetUV->winId()) , wglGetCurrentContext() );
	ui.GLWidgetMain->doneCurrent();

	m_ContextShare.MakeShare();
}

void FormMain::InitializeCoordinateCombobox(void)
{
	ui.comboCoordinate->blockSignals(true);
	ui.comboCoordinate->addItem("Yup RH"); // RUF
	ui.comboCoordinate->addItem("Zup RH"); // FRU
	ui.comboCoordinate->addItem("Xup RH"); // UFR
	ui.comboCoordinate->addItem("Yup LH"); // RUB
	ui.comboCoordinate->addItem("Zup LH"); // BRU
	ui.comboCoordinate->addItem("Xup LH"); // UBR
	ui.comboCoordinate->blockSignals(false);
}

void FormMain::InitializeStatusBar(void)
{
	m_StatusBar0 = new QLabel(this);
	m_StatusBar1 = new QLabel(this);
	ui.statusBar->addWidget(m_StatusBar0, 1);
	ui.statusBar->addWidget(m_StatusBar1, 0);

	m_StatusBar0->setText("");

	m_StatusBar1->setMinimumWidth(290);
	m_StatusBar1->setText("");
}

void FormMain::InitializeFromConfigFiles(void)
{
	if (!InitializeConfig(PathInfo::GetGuiConfigFilePath()))
	{
		InitializeConfig(PathInfo::GetDefaultGuiConfigFilePath());
	}

	OpenCameraFile(PathInfo::GetCameraLogFilePath());

	LoadWindowLayout(PathInfo::GetWindowLayoutConfigFilePath());

	if (!QGui::LoadGUIState(this, PathInfo::GetLayoutConfigFilePath()))
	{
		QGui::LoadGUIState(this, PathInfo::GetDefaultLayoutConfigFilePath());
	}
}

void FormMain::LoadDefaultConfig(void)
{
	InitializeConfig(PathInfo::GetDefaultGuiConfigFilePath());

	QGui::LoadGUIState(this, PathInfo::GetDefaultLayoutConfigFilePath());
}

void FormMain::SaveConfig(void)
{
	PathInfo::CreateConfiDirIfNotExist();

	SaveConfigFile(PathInfo::GetGuiConfigFilePath());

	m_View3d.m_CameraRecord.SaveCamera(PathInfo::GetCameraLogFilePath().toLocal8Bit().data());

	QGui::SaveGUIState(this, PathInfo::GetLayoutConfigFilePath());

	SaveWindowLayout(PathInfo::GetWindowLayoutConfigFilePath());
}

bool FormMain::InitializeConfig(QString path)
{
	View3DConfig& config_3d = m_View3d.m_Config;

	GuiConfig cfg;
	cfg.m_Config3D = &config_3d;
	cfg.m_Scene    = &m_Scene;

	if (!cfg.LoadConfigT(path.toLocal8Bit().data()))
		return false;

	ui.actionUVAutoFit->setChecked(cfg.m_AutFitUVView);

	ui.comboCoordinate->setCurrentIndex(cfg.m_CoordType);

	CreateRecentFilesMenu(cfg.m_RecentFiles);

	m_Binder_ViewConfig.UpdateAllGUI(true);
	m_Binder_UVConfig.UpdateAllGUI(true);
	m_Binder_Scene.UpdateAllGUI(true);
	m_Binder_Cursor.UpdateAllGUI(true);

	ApplyGeomStateDataoToGUI();

	SyncViewSettingsFromGUI();
	SyncUVViewSettingsFromGUI();
	SyncShaderSettingsToGUI();

	m_EnableAllFeatures = cfg.m_EnableAllFeatures;

	return true;
}

void FormMain::SaveConfigFile(QString path)
{
	GuiConfig cfg;
	cfg.m_Config3D = &m_View3d.m_Config;
	cfg.m_Scene    = &m_Scene;

	cfg.m_EnableAllFeatures = m_EnableAllFeatures;

	cfg.m_AutFitUVView = ui.actionUVAutoFit ->isChecked();

	cfg.m_CoordType = ui.comboCoordinate->currentIndex();

	CreateRecentFilesFromMenu(cfg.m_RecentFiles);

	cfg.SaveConfigT(path.toLocal8Bit().data());
}


void FormMain::InitializeSubDlg(void)
{
	connect(&m_WireColorSelDlg, SIGNAL(currentColorChanged(const QColor &)), this, SLOT(WireOverlayColorChanged(const QColor &)));
	connect(&m_DiffuseColorSelDlg, SIGNAL(currentColorChanged(const QColor &)), this, SLOT(FaceDiffuseColorChanged(const QColor &)));
	connect(&m_BGColorSelDlg, SIGNAL(currentColorChanged(const QColor &)), this, SLOT(BGColorChanged(const QColor &)));
	connect(&m_SelDiffuseColorSelDlg, SIGNAL(currentColorChanged(const QColor &)), this, SLOT(SelFaceDiffuseColorChanged(const QColor &)));

	m_ViewConfigDlg.InitializeConfigDlg(&m_View3d.m_Config);
	connect(&m_ViewConfigDlg, SIGNAL(ConfigChanged()), this, SLOT(ConfigChangedDlg_ConfigChanged()));

	m_CrossSectionDlg.InitializeConfigDlg(&m_View3d);
	connect(&m_CrossSectionDlg, SIGNAL(ConfigChanged()), this, SLOT(CrossSectionDlg_ConfigChanged()));

	m_CustomShaderDlg.SetShaderLibrary(&m_View3d.m_ShaderLib);
	m_CustomShaderDlg.SetParentWidget(ui.GLWidgetMain);
	m_CustomShaderDlg.LoadOrSetDefaultCode();
	connect(&m_CustomShaderDlg, SIGNAL(ShaderBuild()), this, SLOT(CustomShaderDlg_ShaderBuild()));

	connect(&m_MatcapDlg, SIGNAL(ListSelectChanged()), this, SLOT(MatcapDlg_ListSelectChanged()));

	m_PyScriptDlg.m_Scene = &m_Scene;
	m_PyScriptDlg.m_View3d = &m_View3d;
	m_PyScriptDlg.m_View2d = &m_View2d;
}

void FormMain::InitializeAnimation(void)
{
	connect(&m_RotationTimer, SIGNAL(timeout()), this, SLOT(OnRotateTimerUpdated()));
	m_RotationTimer.setInterval( 20 );
}

void FormMain::InitializeMenu(void)
{
	m_AGroup_Window = new QActionGroup(this);
	m_AGroup_Window->setExclusive(true);
	m_AGroup_Window->addAction( ui.actionWindow_3DView    );
	m_AGroup_Window->addAction( ui.actionWindow_UVView    );
	m_AGroup_Window->addAction( ui.actionWindows_DualView );

	m_AGroup_Shader = new QActionGroup(this);
	m_AGroup_Shader->setExclusive(true);
	m_AGroup_Shader->addAction( ui.actionShaderDefault   );
	m_AGroup_Shader->addAction( ui.actionShaderPhong     );
	m_AGroup_Shader->addAction( ui.actionShaderCustom    );
	m_AGroup_Shader->addAction( ui.actionNormalColor     );
	m_AGroup_Shader->addAction( ui.actionDepthColor      );
	m_AGroup_Shader->addAction( ui.actionShadowmap       );
	m_AGroup_Shader->addAction( ui.actionEnvmap          );
	m_AGroup_Shader->addAction( ui.actionIntegrateShader );
	m_AGroup_Shader->addAction( ui.actionMatcapShader    );

	m_AGroup_PProc = new QActionGroup(this);
	m_AGroup_PProc->addAction( ui.actionPostProcNone            );
	m_AGroup_PProc->addAction( ui.actionPostProcAntialias       );
	m_AGroup_PProc->addAction( ui.actionPostProcBorder          );
	m_AGroup_PProc->addAction( ui.actionPostProcDepthLayerColor );
	m_AGroup_PProc->addAction( ui.actionPostProcDepthColor      );
	m_AGroup_PProc->addAction( ui.actionPostProcDepthOfField    );
}

void FormMain::InitContextMenu(void)
{
	QList<QAction*> actions;
	actions
		<< ui.actionSelObjectVisible
		<< ui.actionSelObjectVertexOnlyMode
		<< ui.actionSelObjectDelete
		<< ui.actionSelObjectReload
		<< ui.actionSelObjectFlipFace
		<< ui.actionSelObjectOpenDir
		<< ui.actionActionSelObjectShowOnlyOnce
		<< ui.actionSelObjectTriangulate;

	ui.tableObject->addActions(actions);
}

void FormMain::ProcArguments(void)
{
	for (int i = 1; i < QApplication::arguments().size(); ++i)
	{
		QString s = QApplication::arguments()[i];
		OpenGeomFile(s);
	}
}

void FormMain::closeEvent(QCloseEvent *e)
{
	SaveConfig();

	e->accept();

	m_ViewConfigDlg.close();
	m_CrossSectionDlg.close();
	m_CustomShaderDlg.close();
	m_PyScriptDlg.close();
	m_FullscreenPanel.close();
	m_MatcapDlg.close();

	m_ContextShare.BeginDrawTop();
	m_Scene.FinalizeScene();
	m_ContextShare.EndDrawTop();
}


bool FormMain::eventFilter(QObject * filterobj, QEvent * filterevt)
{
	if (filterobj == ui.editEnvMap)
	{
		if (FilterEvent_editEnvMap(filterobj, filterevt))
			return true;
	}
	else if (filterobj == ui.editMatcap)
	{
		if (FilterEvent_editMatcap(filterobj, filterevt))
			return true;
	}
	else if (filterobj == ui.editMatCapEachMaterial)
	{
		if (FilterEvent_editMatcapEachMat(filterobj, filterevt))
			return true;
	}

	return QMainWindow::eventFilter(filterobj, filterevt);
}

bool FormMain::AcceptDropFilterIfUrl(QEvent * filterevt)
{
	QDragEnterEvent* e = dynamic_cast<QDragEnterEvent*>(filterevt);
	if (e == NULL)
		return false;

	if (e->mimeData()->hasUrls())
		e->acceptProposedAction();

	return true;
}

bool FormMain::IsURLDropFilterEvent(QEvent * filterevt)
{
	QDropEvent* e = dynamic_cast<QDropEvent*>(filterevt);
	if (e == NULL)
		return false;

	if (!e->mimeData()->hasUrls())
		return false;

	return true;
}

bool FormMain::FilterEvent_editEnvMap(QObject * filterobj, QEvent * filterevt)
{
	if (filterevt->type() == QEvent::DragEnter)
	{
		return AcceptDropFilterIfUrl(filterevt);
	}
	else if (filterevt->type() == QEvent::Drop)
	{
		if (!IsURLDropFilterEvent(filterevt))
			return false;

		QDropEvent* e = dynamic_cast<QDropEvent*>(filterevt);
		QList<QUrl> urls = e->mimeData()->urls();
		for (int i = 0; i < urls.size(); ++i)
		{
			QString path = urls[i].toLocalFile();
			if (!IsSupportedTextureExt(path))
				continue;

			LoadEnvMap(path);
			break;
		}

		return true;
	}

	return false;
}

bool FormMain::FilterEvent_editMatcap(QObject * filterobj, QEvent * filterevt)
{
	if (filterevt->type() == QEvent::DragEnter)
	{
		return AcceptDropFilterIfUrl(filterevt);
	}
	else if (filterevt->type() == QEvent::Drop)
	{
		if (!IsURLDropFilterEvent(filterevt))
			return false;

		QDropEvent* e = dynamic_cast<QDropEvent*>(filterevt);
		QList<QUrl> urls = e->mimeData()->urls();
		for (int i = 0; i < urls.size(); ++i)
		{
			QString path = urls[i].toLocalFile();
			if (!IsSupportedTextureExt(path))
				continue;

			LoadMatcapImage(path);
			break;
		}

		return true;
	}

	return false;
}

bool FormMain::FilterEvent_editMatcapEachMat(QObject * filterobj, QEvent * filterevt)
{
	if (filterevt->type() == QEvent::DragEnter)
	{
		return AcceptDropFilterIfUrl(filterevt);
	}
	else if (filterevt->type() == QEvent::Drop)
	{
		if (!IsURLDropFilterEvent(filterevt))
			return false;

		QDropEvent* e = dynamic_cast<QDropEvent*>(filterevt);
		QList<QUrl> urls = e->mimeData()->urls();
		for (int i = 0; i < urls.size(); ++i)
		{
			QString path = urls[i].toLocalFile();
			if (!IsSupportedTextureExt(path))
				continue;

			LoadMatcapImageForCurrentMat(path);
			break;
		}

		return true;
	}

	return false;
}

void FormMain::CenteringSplitter(void)
{
	int w = ui.splitter->width();
	QList<int> s;
	s.append(w/2);
	s.append(w/2);
	ui.splitter->setSizes(s);
}


void FormMain::updateView_All(void)
{
	updateView_3D();
	updateView_2D();
}

void FormMain::updateView_2D(void)
{
	ui.GLWidgetUV->update();
}

void FormMain::updateView_3D(void)
{
	ui.GLWidgetMain->update();
}

void FormMain::on_actionOpen_triggered()
{
	QString title = "Open file";
	QString filter = "Geometry(*.obj *.stl *.ply *.mqo *.pmd *.dae);;AllFiles(*.*)";
	QString fileName = GetFilePathFromOpenDlg(title, filter);

	if (fileName.isEmpty())
		return;

	if (IsResetSceneOnBeforeLoadFile())
		ClearAllObjects();

	if (OpenGeomFile(fileName))
		return;
}

void FormMain::on_actionExit_triggered()
{
	close();
}

void FormMain::actionVisibleStates_Triggered(bool)
{
	SyncViewSettingsFromGUI();
	updateView_All();
}

void FormMain::SyncViewSettingsFromGUI(void)
{
	m_Binder_ViewConfig.UpdateAllData();

	QAction* menu = GetMenuFromShader(m_View3d.m_Config.m_ShaderMode);
	if (menu != NULL)
		menu->setChecked(true);
}

QAction* FormMain::GetMenuFromShader(ShaderType type)
{
	switch(m_View3d.m_Config.m_ShaderMode)
	{
	case ShaderType::Phong      : return ui.actionShaderPhong;
	case ShaderType::Custom     : return ui.actionShaderCustom;
	case ShaderType::NormalColor: return ui.actionNormalColor;
	case ShaderType::DepthColor : return ui.actionDepthColor;
	case ShaderType::Shadowmap  : return ui.actionShadowmap;
	case ShaderType::Envmap     : return ui.actionEnvmap;
	case ShaderType::Integrate  : return ui.actionIntegrateShader;
	case ShaderType::Matcap     : return ui.actionMatcapShader;
	case ShaderType::Default    : return ui.actionShaderDefault;

	default:
		assert(false);
		return NULL;
	};
}

bool FormMain::SaveWindowLayout(const QString& filepath)
{
	WindowConfig config;

	config.m_MainWinLeft   = geometry().x();
	config.m_MainWinTop    = geometry().y();
	config.m_MainWinWidth  = geometry().width();
	config.m_MainWinHeight = geometry().height();
	config.m_IsMaximized   = isMaximized();

	return config.SaveConfig(filepath.toLocal8Bit().data());
}

bool FormMain::LoadWindowLayout(const QString& filepath)
{
	WindowConfig config;
	if (!config.LoadConfig(filepath.toLocal8Bit().data()))
		return false;

	if (config.m_IsMaximized)
		showMaximized();

	setGeometry(config.m_MainWinLeft, config.m_MainWinTop, config.m_MainWinWidth, config.m_MainWinHeight);

	return true;
}


void FormMain::actionVisibleStatesUV_Triggered(bool)
{
	SyncUVViewSettingsFromGUI();
}

void FormMain::SyncUVViewSettingsFromGUI(void)
{
	m_Binder_UVConfig.UpdateAllData();
	updateView_All();
}


void FormMain::actionSceneStates_Toggled(bool)
{
	SyncSceneSettingsFromGUI();
}

void FormMain::SyncSceneSettingsFromGUI(void)
{
	m_Binder_Scene.UpdateAllData();

	updateView_All();
}


void FormMain::on_actionWindow_ToolBarView_triggered(bool checked)
{
	ui.toolBar_View->setVisible( ui.actionWindow_ToolBarView->isChecked() );
}

void FormMain::on_actionToolBar_Options_toggled(bool checked)
{
	ui.toolBar_Option->setVisible(checked);
}

void FormMain::on_actionToolBar_Operation_toggled(bool checked)
{
	ui.toolBar_Operation->setVisible(checked);
}


void FormMain::on_actionCameraDist_triggered()
{
	m_View3d.AdjustCameraDistAuto();
}

void FormMain::on_actionCameraFront_triggered()
{
	m_View3d.MoveCaemraTo(ViewPoint::Front);
}

void FormMain::on_actionCameraBack_triggered()
{
	m_View3d.MoveCaemraTo(ViewPoint::Back);
}

void FormMain::on_actionCameraLeft_triggered()
{
	m_View3d.MoveCaemraTo(ViewPoint::Left);
}

void FormMain::on_actionCameraRight_triggered()
{
	m_View3d.MoveCaemraTo(ViewPoint::Right);
}

void FormMain::on_actionCameraTop_triggered()
{
	m_View3d.MoveCaemraTo(ViewPoint::Top);
}

void FormMain::on_actionCameraBottom_triggered()
{
	m_View3d.MoveCaemraTo(ViewPoint::Bottom);
}

void FormMain::on_actionCameraPers_triggered()
{
	m_View3d.MoveCaemraTo(ViewPoint::Perse);
}

void FormMain::on_actionCameraLookOrigin_triggered()
{
	m_View3d.MoveLookPosToOrigin();
}

void FormMain::on_actionCameraLookCenter_triggered()
{
	m_View3d.MoveLookPosToCenter();
}


void FormMain::on_actionWindow_3DView_triggered(bool checked)
{
	UpdateViewTypeFromMenu();
}

void FormMain::on_actionWindows_DualView_triggered(bool checked)
{
	UpdateViewTypeFromMenu();
}

void FormMain::on_actionWindow_UVView_triggered(bool checked)
{
	UpdateViewTypeFromMenu();
}

void FormMain::UpdateViewTypeFromMenu(void)
{
	if (ui.actionWindows_DualView->isChecked())
	{
		ui.GLWidgetMain->setVisible(true);
		ui.GLWidgetUV->setVisible(true);
	}
	if (ui.actionWindow_3DView->isChecked())
	{
		ui.GLWidgetMain->setVisible(true);
		ui.GLWidgetUV->setVisible(false);
	}
	if (ui.actionWindow_UVView->isChecked())
	{
		ui.GLWidgetMain->setVisible(false);
		ui.GLWidgetUV->setVisible(true);
	}
}


void FormMain::on_actionWindowMaterialList_triggered()
{
	ShowAndActivateAndRaise(ui.dockMaterial);
	ui.listMaterial->setFocus();
}

void FormMain::on_actionWindowObjectList_triggered()
{
	ShowAndActivateAndRaise(ui.dockObject);
	ui.tableObject->setFocus();
}

void FormMain::on_actionWindowCameraList_triggered()
{
	ShowAndActivateAndRaise(ui.dockCamera);
	ui.listCamera->setFocus();
}

void FormMain::on_actionWindowScenePanel_triggered()
{
	ShowAndActivateAndRaise(ui.dockScene);
}


void FormMain::on_listMaterial_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
	SetSelectedUVIdx2d(ui.listMaterial->currentRow());
	updateView_All();
}

void FormMain::ShowAndActivateAndRaise(QDockWidget* widget)
{
	widget->setVisible( true );
	widget->activateWindow();
	widget->raise();
}


void FormMain::on_tableObject_currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous)
{
	RefreshObjectSelectState();
}

void FormMain::RefreshObjectSelectState(void)
{
	m_Scene.m_SelectedObjectIdx = ui.tableObject->currentRow();

	QListWidget* list_mat = ui.listMaterial;

	list_mat->clear();

	const GeomObject* obj = m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	const lib_geo::BaseMesh& mesh = obj->m_Mesh;
	for (const lib_geo::BaseMaterial& mat : mesh.m_Materials)
	{
		const std::string& name = mat.m_Name;

		if( name.empty() )
			list_mat->addItem( "--" );
		else
			list_mat->addItem( QString::fromLocal8Bit( name.c_str() ) );
	}

	ui.actionSelObjectVisible->setChecked( obj->m_Visible );
	ui.actionSelObjectVertexOnlyMode->setChecked( obj->m_VertexOnlyMode );

	if (list_mat->count() > 0 && list_mat->currentRow() < 0)
	{
		list_mat->setCurrentRow(0);
		SetSelectedUVIdx2d(0);
	}

	updateView_All();
}


void FormMain::keyPressEvent(QKeyEvent *e)
{
}


void FormMain::dragEnterEvent(QDragEnterEvent* e)
{
	if (e->mimeData()->hasUrls())
		e->acceptProposedAction();
}

void FormMain::dropEvent(QDropEvent* e)
{
	if (e->mimeData()->hasUrls())
	{
		QList<QUrl> urls = e->mimeData()->urls();

		std::vector<QString> geom_files;

		for (int i = 0; i < urls.size(); ++i)
		{
			QString path = urls[i].toLocalFile();
			if (m_Scene.IsGeomFile(path))
				geom_files.push_back(path);
		}

		if (!geom_files.empty())
		{
			if (IsResetSceneOnBeforeLoadFile())
				ClearAllObjects();

			for (size_t i = 0; i < geom_files.size(); ++i)
			{
				if (OpenGeomFile(geom_files[i]))
					continue;
			}
		}

		for (int i = 0; i < urls.size(); ++i)
		{
			QString path = urls[i].toLocalFile();

			if (IsSupportedTextureExt(path))
			{
				OpenFixTextureFile(path);
				continue;
			}

			if (IsCameraFile(path))
			{
				OpenCameraFile(path);
				continue;
			}
		}
	}
}

bool FormMain::IsResetSceneOnBeforeLoadFile(void) const
{
	if (QApplication::keyboardModifiers() & Qt::ShiftModifier)
		return true;

	return false;
}

//! オブジェクトのマテリアルに設定されたものとは別のテクスチャを指定する.
void FormMain::OpenFixTextureFile(const QString& path)
{
	std::string fname = path.toLocal8Bit().data();

	m_ContextShare.BeginDrawTop();
	m_Scene.LoadDefaultMatTexture(fname);
	m_ContextShare.EndDrawTop();

	updateView_All();
}

bool FormMain::OpenGeomFile(const QString& path)
{
	if (ui.checkSplitObject->isChecked())
		m_Scene.m_ObjSplitMode = SceneMain::ObjSplit_Object;
	else if (ui.checkSplitGroup->isChecked())
		m_Scene.m_ObjSplitMode = SceneMain::ObjSplit_Group;
	else
		m_Scene.m_ObjSplitMode = SceneMain::ObjSplit_None;
	
	m_ContextShare.BeginDrawTop();

	bool suc = true;
	try
	{
		m_Scene.LoadFileAutoFmt(path);
	}
	catch(const FileLoadErrorException& ex)
	{
		QString msg;
		msg += "Failed Load ";
		msg += path + "\n\n";
		msg += QString::fromLocal8Bit(ex.what());

		QMessageBox::warning(this, "", msg);
		suc = false;
	}

	m_ContextShare.EndDrawTop();

	RebuildObjectList();

	updateView_All();

	if (!suc)
		return false;

	AddRecentFile(path);

	return true;
}

void FormMain::AdditionalInitializeOfGeom(int added_count)
{
	ui.tableObject->blockSignals(true);

	for (int i = 0; i < added_count; ++i)
	{
		int idx = (int)m_Scene.m_Objects.size() - added_count + i;
		GeomObject& added_obj = m_Scene.m_Objects.back();

		int new_idx = ui.tableObject->rowCount();
		ui.tableObject->setRowCount(new_idx + 1);
		SetObjectTableRow(new_idx, added_obj);
	}

	ui.tableObject->blockSignals(false);

	if (ui.tableObject->currentRow() < 0)
	{
		ui.tableObject->setCurrentCell(0, 0);

		if(IsAutUVFit())
		{
			m_View2d.FitView();
		}
	}

	updateView_All();
}

void FormMain::ClearAllObjects(void)
{
	m_ContextShare.BeginDrawTop();

	m_Scene.ClearObjects();

	m_ContextShare.EndDrawTop();

	RebuildObjectList();
	RefreshObjectSelectState();

	updateView_All();
}


void FormMain::RebuildObjectList(void)
{
	ui.tableObject->blockSignals(true);

	ui.tableObject->clear();

	ui.tableObject->setSelectionBehavior(QAbstractItemView::SelectRows);
	ui.tableObject->setSelectionMode(QAbstractItemView::SingleSelection);
	ui.tableObject->setEditTriggers(QAbstractItemView::NoEditTriggers);

	ui.tableObject->setRowCount(m_Scene.m_Objects.size());
	ui.tableObject->setColumnCount(4);

	QStringList qs;
	qs << "Name" << "Visible" << "Verts" << "Faces";
	ui.tableObject->setHorizontalHeaderLabels(qs);

	for(size_t i = 0; i < m_Scene.m_Objects.size(); ++i)
	{
		SetObjectTableRow((int)i, m_Scene.m_Objects[i]);
	}

	if(m_Scene.m_SelectedObjectIdx >= 0)
	{
		ui.tableObject->setCurrentCell(m_Scene.m_SelectedObjectIdx, 0);
	}

	ui.tableObject->blockSignals(false);

	if(ui.tableObject->currentRow() < 0)
	{
		if(!m_Scene.m_Objects.empty())
		{
			ui.tableObject->setCurrentCell(0, 0);
		}
	}

	{
		ui.tableObject->setVisible(false);
		ui.tableObject->resizeColumnsToContents();
		ui.tableObject->setVisible(true);
	}
}

bool FormMain::IsSupportedTextureExt(const QString& path) const
{
	QString ext = QFileInfo(path).suffix().toLower();

	std::map<QString, bool> types;
	types[ "bmp"  ] = true;
	types[ "jpg"  ] = true;
	types[ "jepg" ] = true;
	types[ "jpg"  ] = true;
	types[ "png"  ] = true;

	return types[ext];
}


bool FormMain::IsCameraFile(const QString& path) const
{
	QFileInfo fInfo( path );
	QString ext = fInfo.suffix().toLower();
	return (ext == "camera");
}

bool FormMain::OpenCameraFile(const QString& path)
{
	std::string fname = path.toLocal8Bit().data();

	if(!m_View3d.m_CameraRecord.LoadCamera(fname.c_str()))
		return false;

	ui.listCamera->blockSignals(true);
	ui.listCamera->clear();
	for (size_t i = 0; i < m_View3d.m_CameraRecord.m_Records.size(); ++i)
	{
		ui.listCamera->addItem( QString::number(i) );
	}
	ui.listCamera->blockSignals(false);

	return true;
}


void FormMain::actionGeomStates_Triggered(bool)
{
	ApplyGeomStateFromGUI();

	m_Scene.UpdateTransform();

	updateView_All();
}

void FormMain::ApplyGeomStateFromGUI(void)
{
	m_Scene.m_Config.m_EnableAutoCentering = ui.actionCentering->isChecked();
	m_Scene.m_Config.m_EnableAutoReisze    = ui.actionAutoResize->isChecked();
}

void FormMain::ApplyGeomStateDataoToGUI(void)
{
	ui.actionAutoResize ->setChecked( m_Scene.m_Config.m_EnableAutoReisze    );
	ui.actionCentering  ->setChecked( m_Scene.m_Config.m_EnableAutoCentering );

	ui.checkShowOnlySelect->setChecked(m_View3d.m_Config.m_ShowOnlySelect);
}

void FormMain::on_actionGeomClear_triggered()
{
	ClearAllObjects();
}


void FormMain::on_actionUVFitView_triggered()
{
	m_View2d.FitView();

	updateView_All();
}

void FormMain::on_actionSelObjectDelete_triggered()
{
	DeleteSelectedObject();
}

void FormMain::on_actionSelObjectReload_triggered()
{
	GeomObject* obj = m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	if (!obj->IsFileObject())
	{
		QMessageBox::information(this, "", "IsNotFileObject");
		return;
	}

	m_Scene.ReloadObject(obj);

	RebuildObjectList();

	updateView_All();
}

void FormMain::on_actionSelObjectVisible_triggered()
{
	FlipVisibleSelectedObject();
}

void FormMain::on_actionSelObjectVertexOnlyMode_triggered()
{
	GeomObject* obj = m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	obj->m_VertexOnlyMode = !obj->m_VertexOnlyMode;

	ui.actionSelObjectVertexOnlyMode->setChecked( obj->m_VertexOnlyMode );

	updateView_All();
}

void FormMain::on_actionSelObjectFlipFace_triggered()
{
	GeomObject* obj = m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	obj->FlipFace();

	ui.GLWidgetMain->makeCurrent();
	m_View3d.ReleaseRenderbuffer(obj);
	ui.GLWidgetMain->doneCurrent();

	updateView_All();
}

void FormMain::on_actionSelObjectOpenDir_triggered()
{
	GeomObject* obj = m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	if (!obj->IsFileObject())
		return;

	QString path = QString::fromLocal8Bit(obj->m_FilePath.c_str());
	QString dir = QFileInfo(path).dir().path();
	QGui::ShowDirectory(dir);
}

void FormMain::on_actionShowOnlySelected_triggered()
{
	ShowObjectOnlySelected();
}

void FormMain::on_actionSelObjectTriangulate_triggered()
{
	GeomObject* obj = m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	obj->Triangulate();

	m_View3d.ReleaseAllRenderBuffer();

	RebuildObjectList();
	updateView_All();
}


void FormMain::on_actionAddSample_triggered()
{
	m_Scene.AddSampleShape();

	AdditionalInitializeOfGeom(1);
}

void FormMain::on_actionAddGroundPlane_triggered()
{
	m_Scene.AddGroundPlane();

	AdditionalInitializeOfGeom(1);
}


void FormMain::on_actionShaderDefault_triggered(bool checked)
{
	ChangeShaderMenuMain(ShaderType::Default);
}

void FormMain::on_actionShaderPhong_triggered(bool checked)
{
	ChangeShaderMenuMain(ShaderType::Phong);
}

void FormMain::on_actionShaderCustom_triggered(bool checked)
{
	ChangeShaderMenuMain(ShaderType::Custom);
}

void FormMain::on_actionNormalColor_triggered(bool checked)
{
	ChangeShaderMenuMain(ShaderType::NormalColor);
}

void FormMain::on_actionDepthColor_triggered(bool checked)
{
	ChangeShaderMenuMain(ShaderType::DepthColor);
}

void FormMain::on_actionShadowmap_triggered(bool checked)
{
	ChangeShaderMenuMain(ShaderType::Shadowmap);
}

void FormMain::on_actionEnvmap_triggered(bool checked)
{
	ChangeShaderMenuMain(ShaderType::Envmap);
}

void FormMain::on_actionIntegrateShader_triggered(bool checked)
{
	ChangeShaderMenuMain(ShaderType::Integrate);
}

void FormMain::on_actionMatcapShader_triggered(bool checked)
{
	ChangeShaderMenuMain(ShaderType::Matcap);
}

void FormMain::SyncShaderSettingsToGUI(void)
{
	ChangeShaderMenuMain(m_View3d.m_Config.m_ShaderMode);
}

void FormMain::ChangeShaderMenuMain(ShaderType type)
{
	m_View3d.m_Config.m_ShaderMode = type;
	updateView_All();
}


void FormMain::on_actionCreate_Check_triggered()
{
	CreateSampleTextureMain(SampleTextureBuilder::TEX_CHECKER);
}

void FormMain::on_actionCreate_Stripe_V_triggered()
{
	CreateSampleTextureMain(SampleTextureBuilder::TEX_STRIPE_V);
}

void FormMain::on_actionCreate_Stripe_H_triggered()
{
	CreateSampleTextureMain(SampleTextureBuilder::TEX_STRIPE_H);
}

void FormMain::CreateSampleTextureMain(SampleTextureBuilder::TextureType tex_type)
{
	m_ContextShare.BeginDrawTop();
	m_Scene.CreateSampleTexture(tex_type);
	m_ContextShare.EndDrawTop();

	updateView_All();
}

bool FormMain::IsAutUVFit(void) const
{
	return ui.actionUVAutoFit->isChecked();
}


void FormMain::SetSelectedUVIdx2d(int idx)
{
	m_Scene.m_SelectedMaterialIdx = idx;

	if (IsAutUVFit())
	{
		m_View2d.FitView();
	}

	ui.editCurrentTexName->clear();

	GeomObject* obj = m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	if (!obj->IsValidMaterialIdx(idx))
		return;

	lib_geo::BaseMesh& ms = obj->m_Mesh;
	lib_geo::BaseMaterial& mat = ms.m_Materials[idx];
	geom::GeomTextureSet* ts = obj->GetTexture(idx);
	if (ts == NULL)
	{
		ui.editCurrentTexName->setText("");
		ui.editMatCapEachMaterial->setText("");
	}
	else
	{
		QString name;
		gl::GlTexture* tex = ts->TexColor;
		if (tex != NULL)
			name = QString::fromLocal8Bit(tex->GetName().c_str());

		ui.editCurrentTexName->setText(name);

		MatcapImage& matcap = ts->TexMatcap;
		ui.editMatCapEachMaterial->setText(matcap.GetName());
	}

	QColor dc = ToQColor(mat.m_Diffuse);
	SetWidgetColor(ui.colorWidget, dc);
}


void FormMain::on_pushDeleteSelectedObject_clicked()
{
	DeleteSelectedObject();
}

void FormMain::on_tableObject_cellChanged(int row, int column)
{
	if (column == 1)
	{
		QTableWidgetItem* item = ui.tableObject->item(row, column);

		m_Scene.m_Objects[row].m_Visible = (item->checkState() == Qt::Checked);
	}

	updateView_All();
}


void FormMain::DeleteSelectedObject()
{
	int sel_idx = ui.tableObject->currentRow();
	if (sel_idx < 0)
		return;

	m_ContextShare.BeginDrawTop();

	m_Scene.RemoveItem(sel_idx);

	m_ContextShare.EndDrawTop();

	DeleteTableRow(ui.tableObject, sel_idx);

	ui.tableObject->setVisible(false);
	ui.tableObject->resizeColumnsToContents();
	ui.tableObject->setVisible(true);

	m_Scene.m_SelectedObjectIdx = ui.tableObject->currentRow();

	m_Scene.UpdateTransform();

	updateView_All();
}

void FormMain::DeleteTableRow(QTableWidget* table, int row)
{
	// TODO : もう少し簡単な方法がありそう

	table->blockSignals(true);

	for (int i = table->currentRow() + 1; i < table->rowCount(); ++i)
	{
		for (int j = 0; j < table->columnCount(); ++j)
		{
			table->setItem(i-1, j, table->takeItem(i, j));
		}
	}

	table->setRowCount(table->rowCount() - 1);

	table->blockSignals(false);

	RefreshObjectSelectState();
}

void FormMain::FlipVisibleSelectedObject()
{
	int r = ui.tableObject->currentRow();
	int c = 1;

	if(r < 0)
		return;

	QTableWidgetItem* item = ui.tableObject->item(r, c);

	item->setCheckState( FilpState(item->checkState()) );
}

void FormMain::ShowObjectOnlySelected(void)
{
	GeomObject* sel_obj = m_Scene.GetPrimaryObject();
	if (sel_obj == NULL)
		return;

	for (GeomObject& o : m_Scene.m_Objects)
	{
		o.m_Visible = (sel_obj == &o);
	}

	RebuildObjectList();
	updateView_All();
}

void FormMain::ShowAllObject(void)
{
	for (GeomObject& o : m_Scene.m_Objects)
	{
		o.m_Visible = true;
	}

	RebuildObjectList();
	updateView_All();
}

void FormMain::HideAllObject(void)
{
	m_Scene.ShowAllObjects();

	RebuildObjectList();
	updateView_All();
}

void FormMain::on_actionUVResetView_triggered()
{
	m_View2d.ResetView();

	updateView_All();
}


//! ワイヤーオーバーレイ表示時の色設定
void FormMain::on_actionWireColor_triggered()
{
	m_WireColorSelDlg.exec();
}

//! デフォルトマテリアルの色設定
void FormMain::on_actionFaceColor_triggered()
{
	const lib_graph::color4f& c = m_Scene.m_DefaultMaterial.m_Diffuse;

	m_DiffuseColorSelDlg.setOption(QColorDialog::ShowAlphaChannel);
	m_DiffuseColorSelDlg.setCurrentColor(ToQColor(c));
	m_DiffuseColorSelDlg.exec();
}

//! 背景色の設定
void FormMain::on_actionBackGroundColor_triggered()
{
	const lib_graph::color4f& c = m_View3d.m_BGColor;

	m_BGColorSelDlg.setCurrentColor(ToQColor(c));
	m_BGColorSelDlg.exec();
}

void FormMain::WireOverlayColorChanged(const QColor & color)
{
	lib_graph::color3b& c = m_View3d.m_Config.m_WireColor;
	c.set(color.red(), color.green(), color.blue());

	m_View3d.ReleaseAllRenderBuffer();

	updateView_All();
}

void FormMain::CopyRGB(lib_graph::color4f& c, const QColor & color)
{
	c.r() = (float)color.red()   / 255.0f;
	c.g() = (float)color.green() / 255.0f;
	c.b() = (float)color.blue()  / 255.0f;
}

void FormMain::CopyRGBA(lib_graph::color4f& c, const QColor & color)
{
	c.r() = (float)color.red()   / 255.0f;
	c.g() = (float)color.green() / 255.0f;
	c.b() = (float)color.blue()  / 255.0f;
	c.a() = (float)color.alpha() / 255.0f;
}

void FormMain::FaceDiffuseColorChanged(const QColor & color)
{
	lib_graph::color4f& c = m_Scene.m_DefaultMaterial.m_Diffuse;
	CopyRGB(c, color);

	m_View3d.ReleaseAllRenderBuffer();
	updateView_All();
}

void FormMain::BGColorChanged(const QColor & color)
{
	lib_graph::color4f& c = m_View3d.m_BGColor;
	CopyRGB(c, color);

	updateView_All();
}

void FormMain::SetSelectedMaterialColor(QColor col)
{
	GeomObject* obj = m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	int mat_idx = m_Scene.m_SelectedMaterialIdx;
	if (!obj->IsValidMaterialIdx(mat_idx))
		return;

	lib_geo::BaseMaterial& mat = obj->m_Mesh.m_Materials[mat_idx];

	CopyRGBA(mat.m_Diffuse, col);
	SetWidgetColor(ui.colorWidget, col);
}

void FormMain::SelFaceDiffuseColorChanged(const QColor & color)
{
	SetSelectedMaterialColor(color);
	m_View3d.ResetPrimaryObjectLists();
	updateView_All();
}


//! オブジェクトテーブルの指定行の状態をobjと一致させる.
void FormMain::SetObjectTableRow(int row, const GeomObject& obj)
{
	QString name = QString::fromLocal8Bit(obj.m_Name.c_str());
	ui.tableObject->setItem(row, 0, new QTableWidgetItem(name));

	SetObjectTableVisibleState(row, obj);

	QString s_verts = QString::number(obj.GetNumVerts());
	QString s_faces = QString::number(obj.GetNumFaces());
	ui.tableObject->setItem(row, 2, new QTableWidgetItem(s_verts));
	ui.tableObject->setItem(row, 3, new QTableWidgetItem(s_faces));
}

//! オブジェクトテーブルの指定行の表示状態をあらわすチェックボックスを更新.
void FormMain::SetObjectTableVisibleState(int row, const GeomObject& obj)
{
	QTableWidgetItem* item = new QTableWidgetItem();
	item->setCheckState(obj.m_Visible ? Qt::Checked : Qt::Unchecked);

	ui.tableObject->setItem(row, 1, item);
}


Qt::CheckState FormMain::FilpState(Qt::CheckState state) const
{
	if(state == Qt::Checked)
		return Qt::Unchecked;
	else
		return Qt::Checked;
}


void FormMain::on_actionWindowOptions_triggered()
{
	m_ViewConfigDlg.showNormal();
	m_ViewConfigDlg.show();
	m_ViewConfigDlg.activateWindow();
}

void FormMain::on_actionWindowCustomShader_triggered()
{
	m_CustomShaderDlg.showNormal();
	m_CustomShaderDlg.show();
	m_CustomShaderDlg.activateWindow();
}


void FormMain::ConfigChangedDlg_ConfigChanged()
{
	m_View3d.ReleaseAllRenderBuffer();

	updateView_All();
}

void FormMain::CrossSectionDlg_ConfigChanged()
{
	updateView_All();
}


void FormMain::OnPaintImage(QPrinter *printer)
{
	QPainter painter(printer);

	QRect rect = painter.viewport();
	QSize size = this->size();
	size.scale(rect.size(), Qt::KeepAspectRatio);//縦横比維持

	painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
	painter.setWindow(this->rect());

	this->render(&painter);
}

void FormMain::on_actionPrint_triggered()
{
	PrintImage(false);
}

void FormMain::on_actionPrintPreview_triggered()
{
	PrintImage(true);
}

void FormMain::PrintImage(bool WithPreview)
{
	//QPrinter printer(QPrinter::ScreenResolution);
	QPrinter printer(QPrinter::ScreenResolution);

	if(WithPreview)
	{
		QPrintPreviewDialog preview(&printer, this);
		preview.setWindowFlags( Qt::Window );
		connect(&preview, SIGNAL(paintRequested(QPrinter *)), SLOT(OnPaintImage(QPrinter *)));
		preview.showMaximized();
		preview.exec();
	}
	else
	{
		QPrintDialog printDialog(&printer, this);
		if(printDialog.exec() == QDialog::Accepted)
			OnPaintImage(&printer);
	}
}


void FormMain::on_pushButtonAddCameraRecord_clicked()
{
	m_View3d.RecordCamera();

	ui.listCamera->addItem( QString::number(ui.listCamera->count()) );

	updateView_3D();
}

void FormMain::on_pushButtonDeleteCameraRecord_clicked()
{
	int idx = ui.listCamera->currentRow();
	if(idx < 0)
		return;

	m_View3d.RemoveRecordedCamera(idx);

	for (int i = idx+1; i < ui.listCamera->count(); ++i)
	{
		ui.listCamera->item(i)->setText(QString::number(i - 1));
	}

	ui.listCamera->takeItem(idx);

	updateView_3D();
}

void FormMain::on_pushCameraRecordClear_clicked()
{
	m_View3d.ClearRecordedCamera();

	ui.listCamera->clear();

	updateView_3D();
}

void FormMain::on_listCamera_itemDoubleClicked(QListWidgetItem *item)
{
	int idx = ui.listCamera->currentRow();
	if(idx < 0)
		return;

	m_View3d.MoveToRecordedCamera(idx, ui.checkCameraAnimation->isChecked());
}

void FormMain::on_actionSaveCamera_triggered()
{
	QString title = "camera";
	QString filter = "Camera File(*.camera)";
	QString fileName = GetFilePathFromSaveDlg(title, filter);
	if (fileName.isEmpty())
		return;

	m_View3d.m_CameraRecord.SaveCamera(fileName.toLocal8Bit().data());
}

void FormMain::on_actionProjectionOrtho_triggered()
{
	ui.actionProjectionOrtho->setChecked(true);
	ui.actionProjectionPers->setChecked(false);

	m_View3d.m_Camera.m_ProjMode = gl::Camera::PROJ_ORTHO;

	updateView_All();
}

void FormMain::on_actionProjectionPers_triggered()
{
	ui.actionProjectionPers->setChecked(true);
	ui.actionProjectionOrtho->setChecked(false);

	m_View3d.m_Camera.m_ProjMode = gl::Camera::PROJ_PERS;

	updateView_All();
}


void FormMain::CustomShaderDlg_ShaderBuild()
{
	updateView_All();
}

void FormMain::OnRotateTimerUpdated()
{
	static const float rot_speed = 0.005f;

	if (ui.actionRotateCamera->isChecked())
	{
		m_View3d.m_Camera.m_Manip.Tumble(rot_speed, 0.0f);
		UpdateCameraStatus();
	}

	if (ui.actionRotateLight->isChecked())
		m_View3d.m_ControlLight.m_Position.rotate_y(rot_speed);

	updateView_3D();
}

void FormMain::on_actionRotateCamera_toggled(bool checked)
{
	ToggleLightCamera();
}

void FormMain::on_actionRotateLight_toggled(bool checked)
{
	ToggleLightCamera();
}

void FormMain::ToggleLightCamera(void)
{
	bool camera_rotate = ui.actionRotateCamera->isChecked();
	bool light_rotate  = ui.actionRotateLight->isChecked();

	if (camera_rotate || light_rotate)
		m_RotationTimer.start();
	else
		m_RotationTimer.stop();
}

void FormMain::on_actionCrossSectionDlg_triggered()
{
	m_CrossSectionDlg.showNormal();
	m_CrossSectionDlg.show();
	m_CrossSectionDlg.activateWindow();
}


void FormMain::on_actionSelectNext_triggered()
{
	int sel_idx = ui.tableObject->currentRow();
	int cnt = ui.tableObject->rowCount();
	if (sel_idx+1 < cnt)
	{
		ui.tableObject->setCurrentCell(sel_idx + 1, 0);
	}
}

void FormMain::on_actionSelectPrev_triggered()
{
	int sel_idx = ui.tableObject->currentRow();
	if (sel_idx > 0)
	{
		ui.tableObject->setCurrentCell(sel_idx - 1, 0);
	}
}

void FormMain::on_actionSwitchVisible_triggered()
{
	FlipVisibleSelectedObject();
}

void FormMain::on_actionActionSelObjectShowOnlyOnce_triggered()
{
	ShowObjectOnlySelected();
}

void FormMain::on_actionHideAll_triggered()
{
	HideAllObject();
}

void FormMain::on_actionShowAll_triggered()
{
	ShowAllObject();
}


void FormMain::on_actionVertexBuilder_triggered()
{
	FormVertexBuilder builder;
	builder.CreateVertex(m_Scene);

	RebuildObjectList();
	updateView_All();
}

void FormMain::on_actionFullScreen_triggered()
{
	m_FullscreenPanel.ShowWidgetAsFullscreen(ui.splitter, ui.gridLayout_3);
}

void FormMain::on_actionResetConfig_triggered()
{
	QString msg = QString::fromLocal8Bit("設定をリセットします");
	if (QMessageBox::question(this, "", msg, QMessageBox::Ok|QMessageBox::Cancel) != QMessageBox::Ok)
		return;

	LoadDefaultConfig();

	SyncViewSettingsFromGUI();
	SyncUVViewSettingsFromGUI();
	ApplyGeomStateFromGUI();
	SyncShaderSettingsToGUI();
}


QString FormMain::GetFilePathFromOpenDlg(const QString& title, const QString& filter)
{
	QString default_path = GetNextDefaultPathForFileDlg();
	QString s = QFileDialog::getOpenFileName(this, title, default_path, filter);

	if (!s.isEmpty())
		m_LastFileDialogDir = QFileInfo(s).absolutePath();

	return s;
}

QString FormMain::GetFilePathFromSaveDlg(const QString& title, const QString& filter)
{
	QString default_path = GetNextDefaultPathForFileDlg();
	QString s = QFileDialog::getSaveFileName(this, title, default_path, filter);

	if (!s.isEmpty())
		m_LastFileDialogDir = QFileInfo(s).absolutePath();

	return s;
}

QString FormMain::GetNextDefaultPathForFileDlg(void)
{
	if (m_LastFileDialogDir.isEmpty())
		return PathInfo::GetMyDocDirPath();

	return m_LastFileDialogDir;
}


void FormMain::on_toolLoadEnvMap_clicked()
{
	QString title = "Open envmap";
	QString filter = "Image(*.png *.jpeg *.jpg *.bmp);;AllFiles(*.*)";
	QString fileName = GetFilePathFromOpenDlg(title, filter);
	if (fileName.isEmpty())
		return;

	LoadEnvMap(fileName);
}

void FormMain::LoadEnvMap(QString& path)
{
	m_ContextShare.BeginDrawTop();
	m_Scene.m_EnvImg.LoadTexture(path.toLocal8Bit().data());
	m_ContextShare.EndDrawTop();

	QString title = QFileInfo(path).fileName();
	ui.editEnvMap->setText(title);

	updateView_All();
}

void FormMain::on_buttonReleaseEnvImg_clicked()
{
	m_ContextShare.BeginDrawTop();
	m_Scene.m_EnvImg.ClearEnv();
	m_ContextShare.EndDrawTop();

	ui.editEnvMap->clear();

	updateView_All();
}

void FormMain::on_sliderEnvReflection_valueChanged(int value)
{
	float r = GetSliderNormalizedPos(ui.sliderEnvReflection);
	m_Scene.m_EnvImg.m_EnvReflection = r;

	updateView_All();
}


void FormMain::on_comboCoordinate_currentIndexChanged(int index)
{
	SceneTransform& transform = m_Scene.m_WorldTransform;

	int idx = ui.comboCoordinate->currentIndex();
	switch (idx)
	{
	case 0: transform.SetCoordType(geom::SceneTransform::COORD_RUF); break;
	case 1: transform.SetCoordType(geom::SceneTransform::COORD_FRU); break;
	case 2: transform.SetCoordType(geom::SceneTransform::COORD_UFR); break;
	case 3: transform.SetCoordType(geom::SceneTransform::COORD_RUB); break;
	case 4: transform.SetCoordType(geom::SceneTransform::COORD_BRU); break;
	case 5: transform.SetCoordType(geom::SceneTransform::COORD_UBR); break;
	default:
		break;
	}

	updateView_All();
}

void FormMain::on_sliderShadowDarkness_valueChanged(int value)
{
	int b = ui.sliderShadowDarkness->minimum();
	int t = ui.sliderShadowDarkness->maximum();

	float r = (float)(value - b) / (float)(t - b);
	m_Scene.m_ShadowConfig.m_ShadowDarkness = r;

	updateView_All();
}

void FormMain::on_buttonClearAllGeoms_clicked()
{
	ClearAllObjects();
}

//! カメラ位置復元機能使用時のアニメーション有無
void FormMain::on_checkCameraAnimation_toggled(bool checked)
{
}


void FormMain::on_toolLoadMatcap_clicked()
{
	QString title = "Open matcap";
	QString filter = "Image(*.png *.jpeg *.jpg *.bmp);;AllFiles(*.*)";
	QString fileName = GetFilePathFromOpenDlg(title, filter);
	if (fileName.isEmpty())
		return;

	LoadMatcapImage(fileName);
}

void FormMain::on_buttonReleaseMatcap_clicked()
{
	m_ContextShare.BeginDrawTop();
	m_Scene.m_MatcapImg.ClearEnv();
	m_ContextShare.EndDrawTop();

	ui.editMatcap->clear();

	updateView_All();
}

void FormMain::on_buttonLoadMatcapPreset_clicked()
{
	m_MatcapDlg.show();
}

void FormMain::MatcapDlg_ListSelectChanged()
{
	QString p = m_MatcapDlg.GetSelectedItemPath();
	if(p.isEmpty())
		return;

	LoadMatcapImage(p);
}

void FormMain::LoadMatcapImage(QString& path)
{
	MatcapImage& mc = m_Scene.m_MatcapImg;

	m_ContextShare.BeginDrawTop();
	mc.LoadTexture(path.toLocal8Bit().data());
	m_ContextShare.EndDrawTop();

	QString title = QFileInfo(path).fileName();
	mc.SetName(title);
	ui.editMatcap->setText(mc.GetName());

	updateView_All();
}

void FormMain::LoadMatcapImageForCurrentMat(QString& path)
{
	geom::GeomObject* obj = m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	int sel_mat = m_Scene.m_SelectedMaterialIdx;
	if (!obj->IsValidMaterialIdx(sel_mat))
		return;

	geom::GeomTextureSet* tex = obj->GetTexture(sel_mat);

	m_ContextShare.BeginDrawTop();
	tex->TexMatcap.LoadTexture(path.toLocal8Bit().data());
	m_ContextShare.EndDrawTop();

	QString title = QFileInfo(path).fileName();
	tex->TexMatcap.SetName(title);

	SetSelectedUVIdx2d(sel_mat);

	updateView_All();
}

void FormMain::on_actionOpenAppdir_triggered()
{
	PathInfo::OpenAppDir();
}

void FormMain::on_actionOpenConfigDir_triggered()
{
	PathInfo::OpenConfigDir();
}

void FormMain::on_buttonDecGridAxis_clicked()
{
	m_View3d.m_GridAxisScale /= 10.0f;
	updateView_3D();
}

void FormMain::on_buttonIncGridAxis_clicked()
{
	m_View3d.m_GridAxisScale *= 10.0f;
	updateView_3D();
}

void FormMain::on_buttonResetGridAxis_clicked()
{
	m_View3d.m_GridAxisScale = 1.0f;
	updateView_3D();
}


void FormMain::SetPrimaryObjectIdx(int idx)
{
	ui.tableObject->setCurrentCell(idx, 0);
}


void FormMain::View3D_SelectedObjectChanged(int sel_idx)
{
	SetPrimaryObjectIdx(sel_idx);
}

void FormMain::View3D_CameraMoved(void)
{
	UpdateCameraStatus();
}

void FormMain::UpdateCameraStatus(void)
{
	const Camera& camera = m_View3d.m_Camera;
	const lib_gl::CameraManipulator& manip = camera.m_Manip;
	const lm::vec3f& vp = manip.m_ViewPos;

	float a, b;
	manip.GetViewAngles(a, b);
	a = a * 180.0f / M_PI;
	b = b * 180.0f / M_PI;

	QString msg;
	msg += "(";
	msg += QString::number(vp.x, 'f', 2) + " ";
	msg += QString::number(vp.y, 'f', 2) + " ";
	msg += QString::number(vp.z, 'f', 2);
	msg += ")";

	msg += "(";
	msg += QString::number(a, 'f', 2) + " ";
	msg += QString::number(b, 'f', 2);
	msg += ")";

	msg += "(";
	msg += QString::number(camera.m_Projection.m_Near, 'f', 2) + " ";
	msg += QString::number(camera.m_Projection.m_Far, 'f', 2);
	msg += ")";

	m_StatusBar1->setText(msg);
}

void FormMain::on_actionCameraFPSMode_toggled(bool arg1)
{
	m_View3d.m_FpsMode = arg1;
}


void FormMain::actionCursorMenuStates_Toggled(bool)
{
	m_Binder_Cursor.UpdateAllData();
	updateView_3D();
}

void FormMain::on_actionResetCursor_triggered()
{
	m_Scene.m_Cursor3d.ResetCursorPos();
	m_Scene.m_Cursor3d.UpdateNormal(m_View3d.m_Camera.m_Manip.GetFront());
	updateView_3D();
}

void FormMain::on_actionResetMeasure_triggered()
{
	m_View3d.ResetCursorMeasure();
	updateView_3D();
}


void FormMain::on_actionPyScript_triggered()
{
	m_PyScriptDlg.showNormal();
	m_PyScriptDlg.show();
	m_PyScriptDlg.activateWindow();
}

void FormMain::on_actionConsole_triggered()
{
	::AllocConsole();
	freopen( "CON", "r", stdin  );
	freopen( "CON", "w", stdout );
}


void FormMain::on_actionClearVertSelect_triggered()
{
	m_Scene.ClearAllVertSelect();
	updateView_All();
}


void FormMain::on_action_About_triggered()
{
	std::ostringstream ss;
	ss << "QtGeoViewer" << std::endl;
	ss << std::endl;
	ss << "VERSION : " << VERSION_MAJOR << "." << VERSION_MINOR << "." << BUILD_NUMBER << "." << SVN_REVISION << std::endl;
	ss << "BUILD_ID : " << BUILD_ID << std::endl;

	QMessageBox::information(this, "", QString::fromLocal8Bit(ss.str().c_str()));
}

void FormMain::on_action_Association_triggered()
{
	m_AssociationDlg.exec();
}

void FormMain::on_actionLookDepth_triggered()
{
	m_View3d.LookDepth();
}

void FormMain::on_actionLook3DCursor_triggered()
{
	m_View3d.Look3DCursor();
}

void FormMain::on_sliderLightPower_valueChanged(int value)
{
	float n = (float)ui.sliderLightPower->value() / (float)ui.sliderLightPower->maximum();

	m_View3d.SetLightStrengthByStdRatio(n);

	ui.labelLightPower->setText(QString("LightPower ") + QString::number(n, 'f', 2));

	updateView_All();
}

void FormMain::on_buttonResetLightPower_clicked()
{
	ui.sliderLightPower->setValue(1000);
}

void FormMain::on_checkHoleAroundCursor_clicked(bool checked)
{
	m_Scene.m_Cursor3d.MakeHole = checked;
	updateView_All();
}

void FormMain::on_sliderCursorHoleRange_valueChanged(int value)
{
	float val = (float)ui.sliderCursorHoleRange->value();
	float maxval = (float)ui.sliderCursorHoleRange->maximum();
	float n = val / maxval;

	m_Scene.m_Cursor3d.HoleRangeRatio = n;
	updateView_All();
}

void FormMain::on_buttonResetCursorHoleRange_clicked()
{
	ResetHoleRange();
}

void FormMain::ResetHoleRange(void)
{
	ui.sliderCursorHoleRange->setValue(500);
}

void FormMain::on_actionSaveImageToMydoc_triggered()
{
	QString path = PathInfo::GetMyDocDirPath();
	QString basename = path + "/" + "qgv_snap_";

	QDateTime dt = QDateTime::currentDateTime();

	QString dst;
	for(;;)
	{
		QString tp = dt.toString("yyyyMMdd_hhmmss_zzz");
		dst = basename + tp + ".png";
		if (!QFile(dst).exists())
			break;
	}

	ui.GLWidgetMain->grabFrameBuffer().save(dst);
}

void FormMain::on_actionPostProcNone_triggered()
{
	ChangePostprocMode(PostProcType::None);
}

void FormMain::on_actionPostProcAntialias_triggered()
{
	ChangePostprocMode(PostProcType::Antialias);
}

void FormMain::on_actionPostProcBorder_triggered()
{
	ChangePostprocMode(PostProcType::Border);
}

void FormMain::on_actionPostProcDepthLayerColor_triggered()
{
	ChangePostprocMode(PostProcType::DepthLayerColor);
}

void FormMain::on_actionPostProcDepthColor_triggered()
{
	ChangePostprocMode(PostProcType::DepthColor);
}

void FormMain::on_actionPostProcDepthOfField_triggered()
{
	ChangePostprocMode(PostProcType::DepthOfField);
}

void FormMain::ChangePostprocMode(PostProcType type)
{
	m_View3d.m_Config.m_PPMode = type;
	updateView_3D();
}

void FormMain::on_sliderDOFPint_valueChanged(int value)
{
	float n = GetSliderNormalizedPos(ui.sliderDOFPint);
	m_View3d.m_PPContext.m_DOFPintPos = n;

	updateView_3D();
}

void FormMain::on_sliderDOFRange_valueChanged(int value)
{
	float n = GetSliderNormalizedPos(ui.sliderDOFRange);
	m_View3d.m_PPContext.m_DOFRange = 10.0f * n;

	updateView_3D();
}

float FormMain::GetSliderNormalizedPos(const QSlider* slider) const
{
	float t = (float)slider->maximum();
	float b = (float)slider->minimum();
	float v = (float)slider->value();

	return (v - b) / (t - b);
}

void FormMain::on_buttonResetDOFPint_clicked()
{
	ui.sliderDOFPint->setValue(1000);
}

void FormMain::on_buttonResetDOFRange_clicked()
{
	ui.sliderDOFRange->setValue(1000);
}

void FormMain::on_actionAddCrossSectionRecord_triggered()
{
	m_Scene.AddCrossSectionRecord();
	updateView_All();
}

void FormMain::on_actionClearCrossSectionRecord_triggered()
{
	m_Scene.ClearCrossSectionRecord();
	updateView_All();
}

void FormMain::on_buttonClearMatCapEachMaterial_clicked()
{
	GeomObject* obj = m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	if (obj->m_Mesh.m_Materials.empty())
		return;

	int mat_idx = m_Scene.m_SelectedMaterialIdx;
	if (!obj->IsValidMaterialIdx(mat_idx))
		return;

	m_ContextShare.BeginDrawTop();
	obj->GetTexture(mat_idx)->TexMatcap.ClearEnv();
	m_ContextShare.EndDrawTop();

	ui.editMatCapEachMaterial->clear();

	updateView_All();
}

void FormMain::on_buttonClearCurrentMatNormalMap_clicked()
{

}

void FormMain::on_buttonDiffuse_clicked()
{
	GeomObject* obj = m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	if (obj->m_Mesh.m_Materials.empty())
	{
		QMessageBox::warning(this, "", "No materials");
		return;
	}

	int mat_idx = m_Scene.m_SelectedMaterialIdx;
	if (!obj->IsValidMaterialIdx(mat_idx))
		return;

	lib_geo::BaseMesh& ms = obj->m_Mesh;
	lib_geo::BaseMaterial& mat = ms.m_Materials[mat_idx];

	lib_graph::color4f src = mat.m_Diffuse;
	QColor dc = ToQColor(src);

	m_SelDiffuseColorSelDlg.setOption(QColorDialog::ShowAlphaChannel);
	m_SelDiffuseColorSelDlg.setCurrentColor(dc);
	if (m_SelDiffuseColorSelDlg.exec() == QDialog::Rejected)
	{
		mat.m_Diffuse = src;
		SetWidgetColor(ui.colorWidget, dc);
	}
}


void FormMain::SetWidgetColor(QWidget* w, QColor col)
{
	QString ss = QString("background-color: %1").arg(col.name());
	w->setStyleSheet(ss);
}

void FormMain::CreateRecentFilesMenu(const std::vector<QString>& path)
{
	QMenu* recents = ui.menuOpenRecent;
	recents->actions().clear();

	for (size_t i = 0; i < path.size(); ++i)
	{
		AddRecentFile(path[path.size() - i - 1]);
	}
}

void FormMain::CreateRecentFilesFromMenu(std::vector<QString>& path)
{
	QMenu* recents = ui.menuOpenRecent;
	for (int i = 0; i < recents->actions().size(); ++i)
	{
		QAction* a = recents->actions().at(i);
		path.push_back(a->text());
	}
}

void FormMain::AddRecentFile(const QString& path)
{
	static const int max_files = 5;

	QMenu* recents = ui.menuOpenRecent;

	for (int i = 0; i < recents->actions().size(); ++i)
	{
		QAction* a = recents->actions().at(i);
		if (a->text() == path)
		{
			recents->removeAction(a);
			break;
		}
	}

	QAction* new_path = new QAction(path, this);
	connect(new_path, SIGNAL(triggered()), this, SLOT(OnOpenRecent()));

	if (recents->actions().empty())
		recents->addAction(new_path);
	else
		recents->insertAction(recents->actions().front(), new_path);

	if (recents->actions().size() > max_files)
	{
		QAction* a = recents->actions().back();
		recents->removeAction(a);
	}
}

void FormMain::OnOpenRecent()
{
	QAction* a = dynamic_cast<QAction*>(QObject::sender());
	assert(a != NULL);
	if (a == NULL)
		return;

	QString path = a->text();

	if (IsResetSceneOnBeforeLoadFile())
		ClearAllObjects();

	if (OpenGeomFile(path))
		return;
}

void FormMain::on_checkShowOnlySelect_toggled(bool checked)
{
	m_View3d.m_Config.m_ShowOnlySelect = checked;
	updateView_All();
}
