#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"
#include "SampleShapeBuilder.h"
#include "ShaderLibrary.h"
#include "QGVAboutDlg.h"

#include "FormCustomShader.h"
#include "FormPyScript.h"
#include "MatcapSelectDlg.h"
#include "EnvmapSelectDlg.h"
#include "FileDlgUtil.h"
#include "MaterialPresetDlg.h"



QColor ToQColor(const lgr::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)
	, m_MatcapDlg(NULL)
	, m_EnvmapDlg(NULL)
	, m_CustomShaderDlg(NULL)
	, m_PyScriptDlg(NULL)
	, m_MatPresetDlg(NULL)
{
	ui.setupUi(this);

	ui.widgetObjectList->setMainForm(this);
	ui.widgetCamera->setMainForm(this);

	m_EnableAllFeatures = false;
	m_LastFocusedDockDlg = NULL;

	setAcceptDrops(true);

	setWindowTitle("QtGeoViewer");

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

	InitDataBinding();

	ApplyGeomStateFromGUI();
	SyncShaderSettingsToGUI();
	updateView_All();

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

	UpdateViewTypeFromMenu();

	CenteringSplitter();

	ui.widgetObjectList->RebuildObjectList();

	InitializeSubDlg();

	InitializeAnimation();

	InitializeFromConfigFiles();

	HideFeatures();

	ResetHoleRange();

	this->show();

	m_InitRect = rect();
	m_InitRect.translate(pos());

	LoadLastWinPos();

	ProcArguments();
}

FormMain::~FormMain()
{
}


void FormMain::LoadLastWinPos(void)
{
	QString file = PathInfo::GetPosConfigFilePath();
	QSettings conf(file, QSettings::IniFormat);

	QVariant v;
	v = conf.value("main/WindowPos");
	if (v.isValid())
	{
		QRect r = v.toRect();
		int dl = r.left();
		int dt = r.top();
		int dw = r.width();
		int dh = r.height();

		resize(dw, dh);

		move(QPoint(dl, dt));
	}

	v = conf.value("main/WinState");
	if (v.isValid())
	{
		if (v.toBool())
			setWindowState(Qt::WindowMaximized);
	}
}

void FormMain::SaveWinPos(void)
{
	QString file = PathInfo::GetPosConfigFilePath();
	QSettings conf(file, QSettings::IniFormat);

	conf.setValue("main/WinState", isMaximized());

	if (isMaximized() || isMinimized())
	{
		setWindowState(Qt::WindowNoState);
		QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
	}

	QRect r = rect();
	r.translate(pos());

	conf.setValue("main/WindowPos", r);
}

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);
	ui.actionReleaseShader->setVisible(b);
}

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

	ui.editCurrentTexName->installEventFilter(this);
	ui.editCurrentMatNormalMap->installEventFilter(this);
	ui.editMatCapEachMaterial->installEventFilter(this);

	ui.colorAmbient->installEventFilter(this);
	ui.colorEmission->installEventFilter(this);
	ui.colorDiffuse->installEventFilter(this);
	ui.colorSpecular->installEventFilter(this);
}

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

	SyncViewSettingsFromGUI();
	m_Binder_Scene.UpdateAllData();
	m_Binder_UVConfig.UpdateAllData();
	m_Binder_TexConfig.UpdateAllData();
	SyncTexConfigToData();
}

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

	View3DConfig& cfg_3d = m_View3d.m_Config;

	dbmap.AddBinder(new MenuBinder(ui.actionDrawFace              , &cfg_3d.m_DrawFace              ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawWire              , &cfg_3d.m_DrawWire              ));
	dbmap.AddBinder(new MenuBinder(ui.actionFlatShading           , &cfg_3d.m_EnableFlatShade       ));
	dbmap.AddBinder(new MenuBinder(ui.actionVertexColor           , &cfg_3d.m_EnableVertexColor     ));
	dbmap.AddBinder(new MenuBinder(ui.actionVertexColor_0_1       , &cfg_3d.m_VertColorTo01         ));
	dbmap.AddBinder(new MenuBinder(ui.actionEnableTexture3D       , &cfg_3d.m_EnableTexture         ));
	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.actionSeparateSpecular      , &cfg_3d.m_SeparateSpecular      ));
	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.actionHighlightSelectedWire , &cfg_3d.m_HighlightSelectedWire ));
	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.actionEnableLighting        , &cfg_3d.m_EnableLighting        ));
	dbmap.AddBinder(new MenuBinder(ui.actionEnableCulling         , &cfg_3d.m_EnableCullFace        ));
	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.actionFBMaterial            , &cfg_3d.m_FBMaterial            ));
	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.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.actionShowMeshBound         , &cfg_3d.m_ShowMeshBound         ));
	dbmap.AddBinder(new MenuBinder(ui.actionPickTransparent       , &cfg_3d.m_PickTransparent       ));
	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.actionDrawPolylineIdx       , &cfg_3d.m_DrawPolylineIdx       ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawPolyline          , &cfg_3d.m_DrawPolyline          ));
	dbmap.AddBinder(new MenuBinder(ui.actionDrawBone              , &cfg_3d.m_DrawBone              ));
	dbmap.AddBinder(new MenuBinder(ui.actionShowMeasure           , &cfg_3d.m_DrawCameraMeasure     ));
	dbmap.AddBinder(new MenuBinder(ui.actionFlipMouseMR           , &cfg_3d.m_FlipMouseMR           ));
	dbmap.AddBinder(new MenuBinder(ui.actionSyncLightToCamera     , &cfg_3d.m_SyncLightTocamera     ));

	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             ));

	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::InitializeTexStateMenu(void)
{
	DataBinderMap& dbmap = m_Binder_TexConfig;

	static bool t = false;

	dbmap.AddBinder(new MenuBinder(ui.actionUVFlipY         , &m_Scene.m_TextureTransform.m_FlipY   ));
	dbmap.AddBinder(new MenuBinder(ui.actionTextureCompress , &m_Scene.m_TexConfig.m_EnableCompress ));

	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(actionVisibleStatesTex_Triggered(bool)));
		}
	}
}

void FormMain::on_actionTextureMipmap_toggled(bool b)
{
	m_Scene.m_TexConfig.m_SampleMode = gl::TexSampleMode::Mipmap;
	updateView_All();
}

void FormMain::on_actionTextureLinear_toggled(bool b)
{
	m_Scene.m_TexConfig.m_SampleMode = gl::TexSampleMode::Linear;
	updateView_All();
}

void FormMain::on_actionTextureNearest_toggled(bool b)
{
	m_Scene.m_TexConfig.m_SampleMode = gl::TexSampleMode::Nearest;
	updateView_All();
}

void FormMain::SyncTexConfigToGUI(bool silent)
{
	gl::TexSampleMode mode = m_Scene.m_TexConfig.m_SampleMode;

	if (silent)
	{
		SetActioncheck(ui.actionTextureMipmap, true, false);
		SetActioncheck(ui.actionTextureLinear, true, false);
		SetActioncheck(ui.actionTextureNearest, true, false);
	}

	QAction* a = NULL;
	if (mode == gl::TexSampleMode::Mipmap)
		a = ui.actionTextureMipmap;
	else if (mode == gl::TexSampleMode::Linear)
		a = ui.actionTextureLinear;
	else if (mode == gl::TexSampleMode::Nearest)
		a = ui.actionTextureNearest;

	SetActioncheck(a, silent, true);
}

void FormMain::SetActioncheck(QAction* a, bool silent, bool check)
{
	assert(a != NULL);
	if (silent)
		a->blockSignals(true);

	a->setChecked(check);

	if (silent)
		a->blockSignals(false);
}

void FormMain::SyncTexConfigToData(void)
{
	if (ui.actionTextureMipmap->isChecked())
		m_Scene.m_TexConfig.m_SampleMode = gl::TexSampleMode::Mipmap;
	else if (ui.actionTextureLinear->isChecked())
		m_Scene.m_TexConfig.m_SampleMode = gl::TexSampleMode::Linear;
	else if (ui.actionTextureNearest->isChecked())
		m_Scene.m_TexConfig.m_SampleMode = gl::TexSampleMode::Nearest;
}

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.actionSelectCloseMat    , &cursor.SelCloseMat    ));
	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 ));
	dbmap.AddBinder(new MenuBinder( ui.actionRecordStroke      , &cursor.RecordStroke   ));
	dbmap.AddBinder(new MenuBinder( ui.actionShowStrokeLength  , &cursor.ShowStrokeLen  ));
	dbmap.AddBinder(new MenuBinder( ui.actionTransparentStroke , &cursor.TranspStorke   ));

	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.m_Widgets = &m_Widgets;
	m_View3d.RegisterScene(&m_Scene);
	m_View3d.InitializeView(ui.GLWidgetMain);

	ui.GLWidgetUV->SetViewer(&m_View2d);
	m_View2d.m_Widgets = &m_Widgets;
	m_View2d.RegisterScene(&m_Scene);
	m_View2d.InitializeView(ui.GLWidgetUV);

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

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

	m_ContextShare.BeginDrawTop();

	m_Scene.Initialize();

	m_ContextShare.EndDrawTop();

	connect(
		&m_View3d,
		SIGNAL(SelectedObjectChanged(int, int)),
		SLOT(View3D_SelectedObjectChanged(int, int)));
	connect(
		&m_View3d,
		SIGNAL(SelectedMatChanged(int)),
		SLOT(View3D_SelectedMatChanged(int)));
	connect(
		&m_View3d,
		SIGNAL(CameraMoved(void)),
		SLOT(View3D_CameraMoved(void)));
	connect(
		&m_View3d,
		SIGNAL(StatusTipChanged(QString)),
		SLOT(View3D_StatusTipChanged(QString)));
	connect(
		&m_View3d,
		SIGNAL(SequenceStepped(int)),
		SLOT(View3D_SequenceStepped(int)));
	connect(
		&m_View3d,
		SIGNAL(CursorMoved()),
		SLOT(View3D_CursorMoved()));
}

// 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::Initialize2DViewSrcCombobox(void)
{
	ui.combo2DViewSrcType->blockSignals(true);
	ui.combo2DViewSrcType->addItem("Color");
	ui.combo2DViewSrcType->addItem("Normal");
	ui.combo2DViewSrcType->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());
	}

	ui.widgetCamera->OpenCameraFile(PathInfo::GetCameraLogFilePath());

	if (!LoadWindowLayout(PathInfo::GetWindowLayoutConfigFilePath()))
	{
		LoadWindowLayout(PathInfo::GetDefaultWindowLayoutConfigFilePath());
	}

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

void FormMain::LoadDefaultConfig(void)
{
	InitializeConfig(PathInfo::GetDefaultGuiConfigFilePath());
	QGui::LoadGUIState(this, PathInfo::GetDefaultLayoutConfigFilePath());
	LoadWindowLayout(PathInfo::GetDefaultWindowLayoutConfigFilePath());
}

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);
	m_Binder_TexConfig.UpdateAllGUI(true);
	SyncTexConfigToGUI(true);

	ApplyGeomStateDataoToGUI();

	SyncViewSettingsFromGUI();
	m_Binder_UVConfig.UpdateAllData();
	m_Binder_TexConfig.UpdateAllData();
	SyncTexConfigToData();
	SyncShaderSettingsToGUI();

	ui.widgetIOOption->setConfig(m_Scene.m_IOConfig);

	updateView_All();

	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;

	ui.widgetIOOption->getConfig(m_Scene.m_IOConfig);

	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_SelMatColorSelDlg,
		SIGNAL(currentColorChanged(const QColor &)),
		this,
		SLOT(SelMatColorChanged(const QColor &)));

	m_SelMatColorWidget = NULL;

	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()));
}

void FormMain::InitializeAnimation(void)
{
	connect(
		&m_AnimationTimer,
		SIGNAL(timeout()),
		this,
		SLOT(OnAnimationTimerUpdated()));
	m_AnimationTimer.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    );

	m_AGroup_Texture = new QActionGroup(this);
	m_AGroup_Texture->addAction( ui.actionTextureMipmap  );
	m_AGroup_Texture->addAction( ui.actionTextureNearest );
	m_AGroup_Texture->addAction( ui.actionTextureLinear  );
}

void FormMain::InitContextMenu(void)
{
	ui.widgetObjectList->RegisterContextMenu();
}

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

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

	SaveConfig();

	e->accept();

	m_ViewConfigDlg.close();
	m_CrossSectionDlg.close();
	m_FullscreenPanel.close();

	if (m_CustomShaderDlg != NULL)
		m_CustomShaderDlg->close();
	if (m_PyScriptDlg != NULL)
		m_PyScriptDlg->close();

	if (m_MatcapDlg != NULL)
		m_MatcapDlg->close();
	if (m_EnvmapDlg != NULL)
		m_EnvmapDlg->close();
	if (m_MatPresetDlg != NULL)
		m_MatPresetDlg->close();

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


bool FormMain::eventFilter(QObject * filterobj, QEvent * filterevt)
{
	if (filterobj == ui.editEnvMap)
	{
		if (filterevt->type() == QEvent::DragEnter)
			return AcceptDropFilterIfUrl(filterevt);

		if (filterevt->type() == QEvent::Drop)
			return OnDropFile_editEnvMap(filterevt);
	}
	else if (filterobj == ui.editMatcap)
	{
		if (filterevt->type() == QEvent::DragEnter)
			return AcceptDropFilterIfUrl(filterevt);

		if (filterevt->type() == QEvent::Drop)
			return OnDropFile_editMatcap(filterevt);
	}
	else if (filterobj == ui.editMatCapEachMaterial)
	{
		if (filterevt->type() == QEvent::DragEnter)
			return AcceptDropFilterIfUrl(filterevt);

		if (filterevt->type() == QEvent::Drop)
			return OnDropFile_editMatcapEachMat(filterevt);
	}
	else if (filterobj == ui.editCurrentTexName)
	{
		if (filterevt->type() == QEvent::DragEnter)
			return AcceptDropFilterIfUrl(filterevt);

		if (filterevt->type() == QEvent::Drop)
			return OnDropFile_editCurrentTexName(filterevt);
	}
	else if (filterobj == ui.editCurrentMatNormalMap)
	{
		if (filterevt->type() == QEvent::DragEnter)
			return AcceptDropFilterIfUrl(filterevt);

		if (filterevt->type() == QEvent::Drop)
			return OnDropFile_editCurrentMatNormalMap(filterevt);
	}
	else if (filterobj == ui.colorAmbient)
	{
		if (filterevt->type() == QEvent::MouseButtonPress)
			return colorAmbient_OnButtonDown(filterevt);
	}
	else if (filterobj == ui.colorEmission)
	{
		if (filterevt->type() == QEvent::MouseButtonPress)
			return colorEmission_OnButtonDown(filterevt);
	}
	else if (filterobj == ui.colorDiffuse)
	{
		if (filterevt->type() == QEvent::MouseButtonPress)
			return colorDiffuse_OnButtonDown(filterevt);
	}
	else if (filterobj == ui.colorSpecular)
	{
		if (filterevt->type() == QEvent::MouseButtonPress)
			return colorSpecular_OnButtonDown(filterevt);
	}

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

bool FormMain::OnDropFile_editEnvMap(QEvent * filterevt)
{
	QString path = GetFirstLoadableImagePathFromDragEvent(filterevt);
	if (!path.isEmpty())
		LoadEnvMap(path);

	return true;
}

bool FormMain::OnDropFile_editMatcap(QEvent * filterevt)
{
	QString path = GetFirstLoadableImagePathFromDragEvent(filterevt);
	if (!path.isEmpty())
		LoadMatcapImage(path);

	return true;
}

bool FormMain::OnDropFile_editMatcapEachMat(QEvent * filterevt)
{
	QString path = GetFirstLoadableImagePathFromDragEvent(filterevt);
	if (!path.isEmpty())
		LoadMatcapImageForCurrentMat(path);

	return true;
}

bool FormMain::OnDropFile_editCurrentTexName(QEvent * filterevt)
{
	QString path = GetFirstLoadableImagePathFromDragEvent(filterevt);
	if (!path.isEmpty())
		LoadCurSelMatTexture(TextureType::Color, path);

	return true;
}

bool FormMain::OnDropFile_editCurrentMatNormalMap(QEvent * filterevt)
{
	QString path = GetFirstLoadableImagePathFromDragEvent(filterevt);
	if (!path.isEmpty())
		LoadCurSelMatTexture(TextureType::Normal, path);

	return true;
}

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

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

	return true;
}

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

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

	QList<QUrl> urls = e->mimeData()->urls();
	for (QUrl& url : urls)
	{
		QString path = url.toLocalFile();
		if (IsSupportedTextureExt(path))
			return path;
	}

	return QString();
}

bool FormMain::colorAmbient_OnButtonDown(QEvent * filterevt)
{
	QMouseEvent * e = dynamic_cast<QMouseEvent *>(filterevt);
	if (e->buttons() == Qt::LeftButton)
		ChangeMatlemColor(ui.colorAmbient);
	return true;
}

bool FormMain::colorEmission_OnButtonDown(QEvent * filterevt)
{
	QMouseEvent * e = dynamic_cast<QMouseEvent *>(filterevt);
	if (e->buttons() == Qt::LeftButton)
		ChangeMatlemColor(ui.colorEmission);
	return true;
}

bool FormMain::colorDiffuse_OnButtonDown(QEvent * filterevt)
{
	QMouseEvent * e = dynamic_cast<QMouseEvent *>(filterevt);
	if (e->buttons() == Qt::LeftButton)
		ChangeMatlemColor(ui.colorDiffuse);
	return true;
}

bool FormMain::colorSpecular_OnButtonDown(QEvent * filterevt)
{
	QMouseEvent * e = dynamic_cast<QMouseEvent *>(filterevt);
	if (e->buttons() == Qt::LeftButton)
		ChangeMatlemColor(ui.colorSpecular);
	return true;
}

void FormMain::ChangeMatlemColor(QWidget* col_widget)
{
	lib_geo::BaseMaterial* mat = m_Scene.GetSelectedMaterial();
	if (mat == NULL)
		return;

	lgr::color4f* col = NULL;
	if (col_widget == ui.colorAmbient  ) col = &mat->m_Ambient  ;
	if (col_widget == ui.colorEmission ) col = &mat->m_Emission ;
	if (col_widget == ui.colorDiffuse  ) col = &mat->m_Diffuse  ;
	if (col_widget == ui.colorSpecular ) col = &mat->m_Specular ;

	lgr::color4f src = *col;

	QColor dc = ToQColor(*col);

	m_SelMatColorWidget = col_widget;

	m_SelMatColorSelDlg.setOption(QColorDialog::ShowAlphaChannel);
	m_SelMatColorSelDlg.setCurrentColor(dc);
	if (m_SelMatColorSelDlg.exec() == QDialog::Rejected)
	{
		*col = src;
		SetColorPalleteBG(col_widget, dc);
	}
}


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()
{
	FileDlgFilterList exts;
	exts.Add( "Wavefront"   , "obj" );
	exts.Add( "STL"         , "stl" );
	exts.Add( "PLY"         , "ply" );
	exts.Add( "Metasequoia" , "mqo" );
	exts.Add( "Pmd"         , "pmd" );
	exts.Add( "Collada"     , "dae" );
	exts.Add( "DirectX"     , "x"   );

	QString filter = FileDlgUtil::ExtListToDlgFilter("Geometry", exts);
	QString title = "Open file";
	QString fileName = GetFilePathFromOpenDlg(title, filter);

	if (fileName.isEmpty())
		return;

	if (IsResetSceneOnBeforeLoadFile())
		ClearAllObjects();

	if (OpenGeomFileToLast(fileName))
		return;
}

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

void FormMain::actionVisibleStates_Triggered(bool checked)
{
	QAction* a = dynamic_cast<QAction*>(QObject::sender());
	if (checked)
	{
		if (a == ui.actionIndexColorMode)
		{
			ui.actionFixMaterialSilver->setChecked(false);
			ui.actionFBMaterial->setChecked(false);
		}
		else if (a == ui.actionFixMaterialSilver)
		{
			ui.actionIndexColorMode->setChecked(false);
			ui.actionFBMaterial->setChecked(false);
		}
		else if (a == ui.actionFBMaterial)
		{
			ui.actionFixMaterialSilver->setChecked(false);
			ui.actionIndexColorMode->setChecked(false);
		}
	}

	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();

	int l = config.m_MainWinLeft;
	int t = config.m_MainWinTop;
	int w = config.m_MainWinWidth;
	int h = config.m_MainWinHeight;
	setGeometry(l, t, w, h);

	return true;
}

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

void FormMain::actionVisibleStatesTex_Triggered(bool)
{
	m_Binder_TexConfig.UpdateAllData();
	updateView_All();
}

void FormMain::actionSceneStates_Toggled(bool)
{
	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.frameView3D->setVisible(true);
		ui.frameView2D->setVisible(true);

		// TODO: 仮. 起動時にビューを1:1に設定できない問題の仮対応.
		static bool firsttime = true;
		if (firsttime)
		{
			firsttime = false;
			CenteringSplitter();
		}
	}
	if (ui.actionWindow_3DView->isChecked())
	{
		ui.frameView3D->setVisible(true);
		ui.frameView2D->setVisible(false);
	}
	if (ui.actionWindow_UVView->isChecked())
	{
		ui.frameView3D->setVisible(false);
		ui.frameView2D->setVisible(true);
	}
}

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

void FormMain::on_actionWindowObjectList_triggered()
{
	ShowAndActivateAndRaise(ui.dockObject);
	ui.widgetObjectList->focusList();
}

void FormMain::on_actionWindowCameraList_triggered()
{
	ShowAndActivateAndRaise(ui.dockCamera);
	ui.widgetCamera->focusList();
}

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

void FormMain::on_actionCursorPanel_triggered()
{
	ShowAndActivateAndRaise(ui.dockCursor);
}

void FormMain::on_actionIOOptionPanel_triggered()
{
	ShowAndActivateAndRaise(ui.dockIOOption);
}

void FormMain::on_listMaterial_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
	MeshBuf* mbuf = m_Scene.GetSelOrFirstMeshbuf();
	if (mbuf == NULL)
		return;

	int idx = ui.listMaterial->currentRow();
	mbuf->SetSelMatIdx(idx);
	OnChangedSelectedMaterial();
	updateView_All();
}

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

void FormMain::OnChangedSelectedMaterial(void)
{
	if (IsAutUVFit())
	{
		m_View2d.FitView();
	}

	ui.editCurrentTexName->clear();

	GeomTextureSet* ts = m_Scene.GetSelectedTexture();
	if (ts == NULL)
	{
		ui.editCurrentTexName->setText("");
		ui.editMatCapEachMaterial->setText("");
	}
	else
	{
		QString name_c, name_n;

		gl::GlTexture* tex_c = ts->GetTexColor();
		if (tex_c != NULL)
			name_c = QString::fromLocal8Bit(tex_c->GetName().c_str());

		gl::GlTexture* tex_n = ts->GetTexNormal();
		if (tex_n != NULL)
			name_n = QString::fromLocal8Bit(tex_n->GetName().c_str());

		ui.editCurrentTexName->setText(name_c);
		ui.editCurrentMatNormalMap->setText(name_n);

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

	lib_geo::BaseMaterial* mat = m_Scene.GetSelectedMaterial();
	if (mat != NULL)
	{
		SetColorPalleteBG(ui.colorAmbient  , ToQColor(mat->m_Ambient));
		SetColorPalleteBG(ui.colorEmission , ToQColor(mat->m_Emission));
		SetColorPalleteBG(ui.colorDiffuse  , ToQColor(mat->m_Diffuse));
		SetColorPalleteBG(ui.colorSpecular , ToQColor(mat->m_Specular));
		SetMatShininessSliderPos(mat->m_Shininess);
	}
	else
	{
		QColor w(255, 255, 255);
		SetColorPalleteBG( ui.colorAmbient  , w );
		SetColorPalleteBG( ui.colorEmission , w );
		SetColorPalleteBG( ui.colorDiffuse  , w );
		SetColorPalleteBG( ui.colorSpecular , w );
		SetMatShininessSliderPos(0);
	}

	updateView_All();
}

void FormMain::SetMatShininessSliderPos(float shininess)
{
	int val_max = ui.sliderShininess->maximum();
	int slider_pos = (int)(shininess * (float)val_max / 200.0f);
	slider_pos = (lm::min)(val_max, slider_pos);
	ui.sliderShininess->blockSignals(true);
	ui.sliderShininess->setValue(slider_pos);
	ui.sliderShininess->blockSignals(false);
	ui.labelShininessVal->setText(QString::number(shininess, 'f', 2));
}

void FormMain::keyPressEvent(QKeyEvent *e)
{
	Modifier m(e);
	if (m.Flag_C() && e->key() == Qt::Key_Tab)
	{
		FocusNextSubDlg();
	}
}

void FormMain::FocusNextSubDlg(void)
{
	std::vector<QDockWidget*> widgets;

	if (ui.dockObject   ->isVisible()) widgets.push_back( ui.dockObject   );
	if (ui.dockCamera   ->isVisible()) widgets.push_back( ui.dockCamera   );
	if (ui.dockScene    ->isVisible()) widgets.push_back( ui.dockScene    );
	if (ui.dockMaterial ->isVisible()) widgets.push_back( ui.dockMaterial );

	if (widgets.empty())
		return;

	QDockWidget* next_widget = NULL;

	for (size_t i = 0; i < widgets.size(); ++i)
	{
		if (widgets[i] == m_LastFocusedDockDlg)
		{
			next_widget = widgets[(i + 1) % widgets.size()];
			break;
		}
	}

	if (next_widget == NULL)
		next_widget = widgets.front();

	m_LastFocusedDockDlg = next_widget;

	next_widget->activateWindow();
	next_widget->raise();
	next_widget->setFocus();
}

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 (QUrl& url : urls)
		{
			QString path = url.toLocalFile();
			if (FormatType::IsGeomFileExt(path))
				geom_files.push_back(path);
		}

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

			for (QString& f : geom_files)
			{
				if (OpenGeomFileToLast(f))
					continue;
			}
		}

		for (QUrl& url : urls)
		{
			QString path = url.toLocalFile();

			if (IsSupportedTextureExt(path))
			{
				DropTextureFile(path, e->pos());
				continue;
			}

			if (IsCameraFile(path))
			{
				ui.widgetCamera->OpenCameraFile(path);
				continue;
			}
		}
	}
}

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

	return false;
}

//! オブジェクトに画像をドロップされた場合はそのマテリアルのカラーテクスチャをセット
//! 何も無い場所にドロップされるとデフォルトテクスチャをセット
void FormMain::DropTextureFile(const QString& path, const QPoint& pos)
{
	std::string fname = path.toLocal8Bit().data();

	QPoint pl = ui.GLWidgetMain->mapFrom(this, pos);

	PickedMeshSubface picked;
	m_View3d.BeginRender();
	bool suc = m_View3d.PickFace2D(picked, pl.x(), pl.y());
	m_View3d.EndRender();

	if (suc)
	{
		m_View3d.BeginRender();
		MeshBuf* mbuf = picked.mbuf;
		lib_geo::BaseFace& f = mbuf->m_Mesh.m_Faces[picked.subf.fid];
		GeomTextureSet* ts = mbuf->GetTexture(f.m_MatIdx);
		if (ts != NULL)
		{
			std::string fp = path.toLocal8Bit().data();

			QString name_qs = QFileInfo(path).fileName();
			std::string name = name_qs.toLocal8Bit().data();

			mbuf->ReleaseTextureUnit(ts, TextureType::Color);
			gl::GlTexture* tex = mbuf->GetInitTexture(fp, name, m_Scene.m_TexConfig);
			ts->SetTextureUnit(TextureType::Color, tex);
		}
		m_View3d.EndRender();
	}
	else
	{
		m_ContextShare.BeginDrawTop();
		m_Scene.LoadDefaultMatTexture(fname);
		m_ContextShare.EndDrawTop();
	}

	updateView_All();
}

bool FormMain::OpenGeomFileToLast(const QString& path)
{
	ui.widgetIOOption->getConfig(m_Scene.m_IOConfig);

	m_ContextShare.BeginDrawTop();

	bool suc = true;
	try
	{
		m_Scene.ImportFileAutoFmt(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();

	if (suc)
		ui.widgetObjectList->OnDoneAddGeom();

	ResetSequenceSliderRange();

	updateView_All();

	if (!suc)
		return false;

	AddRecentFile(path);

	return true;
}

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

	m_Scene.ClearObjects();

	m_ContextShare.EndDrawTop();

	m_View3d.ClearRenderMap();

	ui.widgetObjectList->ClearTree();
	RefreshObjectSelectState();

	updateView_All();
}


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


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.widgetObjectList->applyConfig();
}

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


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

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

void FormMain::RebuildAllGLBuf(void)
{
	ui.GLWidgetMain->makeCurrent();
	std::vector<MeshBuf*> mv = m_Scene.GetCurSelMeshes();
	for (MeshBuf* m : mv)
	{
		m_View3d.ReleaseRenderbuffer(m);
	}
	ui.GLWidgetMain->doneCurrent();

	updateView_All();
}

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


void FormMain::on_actionAddSample_triggered()
{
	SampleShapeBuilder::CreateSphere(m_Scene);
	ui.widgetObjectList->OnDoneAddGeom();

	ResetSequenceSliderRange();

	updateView_All();
}

void FormMain::on_actionAddGroundPlane_triggered()
{
	SampleShapeBuilder::CreateGroundPlane(m_Scene);
	ui.widgetObjectList->OnDoneAddGeom();

	ResetSequenceSliderRange();

	updateView_All();
}

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

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

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

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

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

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

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

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

void FormMain::on_actionMatcapShader_triggered(bool)
{
	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::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::RefreshObjectSelectState(void)
{
	ui.widgetObjectList->SetPrimayrSelectObjectToScene();

	RebuildMatList();

	updateView_All();
}

void FormMain::RebuildMatList(void)
{
	MeshBuf* mbuf = m_Scene.GetSelOrFirstMeshbuf();

	QListWidget* list_mat = ui.listMaterial;

	list_mat->blockSignals(true);
	list_mat->clear();

	if (mbuf != NULL)
	{
		const lib_geo::BaseMesh& mesh = mbuf->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()));
		}
	}

	list_mat->blockSignals(false);

	if (mbuf != NULL)
	{
		mbuf->SelectMatAuto();
		list_mat->setCurrentRow(mbuf->GetSelMatIdx());
	}
	else
	{
		list_mat->setCurrentRow(-1);
	}

	OnChangedSelectedMaterial();
}


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

	m_ContextShare.BeginDrawTop();

	m_Scene.RemoveItem(sel_idx);

	m_ContextShare.EndDrawTop();

	m_View3d.ClearRenderMap();

	ui.widgetObjectList->removeObject(sel_idx);

	int sel_idx2 = ui.widgetObjectList->getSelObjIdxWhenSelObjNode();

	m_Scene.m_Sels.SelectObject(sel_idx2);

	m_Scene.UpdateTransform();

	RefreshObjectSelectState();

	ResetSequenceSliderRange();

	updateView_All();
}

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);
	}

	ui.widgetObjectList->SyncViewMark();
	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 lgr::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 lgr::color4f& c = m_View3d.m_BGColor;

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

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

	m_View3d.ReleaseAllRenderBuffer();

	updateView_All();
}

void FormMain::CopyRGB(lgr::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(lgr::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)
{
	lgr::color4f& c = m_Scene.m_DefaultMaterial.m_Diffuse;
	CopyRGB(c, color);

	m_View3d.ReleaseAllRenderBuffer();
	updateView_All();
}

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

	updateView_All();
}

void FormMain::SetSelectedMaterialColor(QColor col)
{
	lib_geo::BaseMaterial* mat = m_Scene.GetSelectedMaterial();
	if (mat == NULL)
		return;

	if (m_SelMatColorWidget == ui.colorAmbient  ) CopyRGBA(mat->m_Ambient  , col);
	if (m_SelMatColorWidget == ui.colorEmission ) CopyRGBA(mat->m_Emission , col);
	if (m_SelMatColorWidget == ui.colorDiffuse  ) CopyRGBA(mat->m_Diffuse  , col);
	if (m_SelMatColorWidget == ui.colorSpecular ) CopyRGBA(mat->m_Specular , col);

	SetColorPalleteBG(m_SelMatColorWidget, col);
}

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


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

void FormMain::on_actionWindowCustomShader_triggered()
{
	if (m_CustomShaderDlg == NULL)
	{
		m_CustomShaderDlg = new FormCustomShader(this);
		m_CustomShaderDlg->SetShaderLibrary(&m_View3d.m_ShaderLib);
		m_CustomShaderDlg->SetParentWidget(ui.GLWidgetMain);
		m_CustomShaderDlg->LoadOrSetDefaultCode();
		connect(
			m_CustomShaderDlg,
			SIGNAL(ShaderBuild()),
			this,
			SLOT(CustomShaderDlg_ShaderBuild()));
	}

	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_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_Scene.m_Camera.m_ProjMode = gl::Camera::PROJ_ORTHO;

	updateView_All();
}

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

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

	updateView_All();
}


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

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

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

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

	if (ui.actionAnimation->isChecked())
	{
		StepSequence(1);
		if (IsLastSequence())
			ui.actionAnimation->setChecked(false);
	}
	else if (ui.actionAnimationRev->isChecked())
	{
		StepSequence(-1);
		if (IsTopSequence())
			ui.actionAnimationRev->setChecked(false);
	}

	updateView_3D();
}

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

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

void FormMain::on_actionAnimation_toggled(bool checked)
{
	if (checked)
	{
		ui.actionAnimationRev->setChecked(false);
		if (IsLastSequence())
		{
			QSlider* s = ui.sliderSequence;
			s->setValue(0);
		}
	}

	ui.butonAnimationFwd->blockSignals(true);
	ui.butonAnimationFwd->setChecked(checked);
	ui.butonAnimationFwd->blockSignals(false);

	UpdateAnimState();
}

void FormMain::on_actionAnimationRev_toggled(bool checked)
{
	if (checked)
	{
		ui.actionAnimation->setChecked(false);
		if (IsTopSequence())
		{
			QSlider* s = ui.sliderSequence;
			s->setValue(s->maximum());
		}
	}

	ui.butonAnimationRev->blockSignals(true);
	ui.butonAnimationRev->setChecked(checked);
	ui.butonAnimationRev->blockSignals(false);

	UpdateAnimState();
}

void FormMain::on_butonAnimationFwd_toggled(bool checked)
{
	ui.actionAnimation->setChecked(checked);
}

void FormMain::on_butonAnimationRev_toggled(bool checked)
{
	ui.actionAnimationRev->setChecked(checked);
}

void FormMain::UpdateAnimState(void)
{
	if (IsEnableAnimation())
		m_AnimationTimer.start();
	else
		m_AnimationTimer.stop();
}

bool FormMain::IsEnableAnimation(void)
{
	if (ui.actionRotateCamera->isChecked())
		return true;
	if (ui.actionRotateLight->isChecked())
		return true;
	if (ui.actionAnimation->isChecked())
		return true;
	if (ui.actionAnimationRev->isChecked())
		return true;

	return false;
}

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

void FormMain::on_actionSelectNext_triggered()
{
	ui.widgetObjectList->AddSelectObjectIdx(1);
}

void FormMain::on_actionSelectPrev_triggered()
{
	ui.widgetObjectList->AddSelectObjectIdx(-1);
}

void FormMain::on_actionSwitchVisible_triggered()
{
	ui.widgetObjectList->FlipVisibleSelectedObject();
}

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

	ui.widgetObjectList->SyncViewMark();
	updateView_All();
}

void FormMain::on_actionShowAll_triggered()
{
	m_Scene.ShowAllObject();

	ui.widgetObjectList->SyncViewMark();
	updateView_All();
}

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

	ui.widgetObjectList->RebuildObjectList();
	updateView_All();
}

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

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

	setGeometry(m_InitRect);

	LoadDefaultConfig();

	SyncViewSettingsFromGUI();
	m_Binder_UVConfig.UpdateAllData();
	m_Binder_TexConfig.UpdateAllData();
	SyncTexConfigToData();
	ApplyGeomStateFromGUI();
	SyncShaderSettingsToGUI();

	updateView_All();
}

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;
}

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

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

	return types[ext];
}

QString FormMain::GetSupportedImageFilePathFromDlg(const QString& title)
{
	FileDlgFilterList exts;
	exts.Add( "Png" , "png"  );
	exts.Add( "Jpg" , "jpg"  );
	exts.Add( "Jpg" , "jpeg" );
	exts.Add( "Bmp" , "bmp"  );
	exts.Add( "Tif" , "tif"  );
	exts.Add( "Tif" , "tiff" );

	QString filter = FileDlgUtil::ExtListToDlgFilter("Image", exts);
	return GetFilePathFromOpenDlg(title, filter);
}


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

	return m_LastFileDialogDir;
}


void FormMain::on_toolLoadEnvMap_clicked()
{
	QString fileName = GetSupportedImageFilePathFromDlg("Open envmap");
	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_buttonPresetEnvMap_clicked()
{
	if (m_EnvmapDlg == NULL)
	{
		m_EnvmapDlg = new EnvmapSelectDlg(this);
		connect(
			m_EnvmapDlg,
			SIGNAL(ListSelectChanged()),
			this,
			SLOT(EnvmapDlg_ListSelectChanged()));
	}

	m_EnvmapDlg->show();
}

void FormMain::EnvmapDlg_ListSelectChanged()
{
	QString p = m_EnvmapDlg->GetSelectedItemPath();
	if (p.isEmpty())
		return;

	LoadEnvMap(p);
}

void FormMain::on_toolLoadMatcap_clicked()
{
	QString fileName = GetSupportedImageFilePathFromDlg("Open matcap");
	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()
{
	if (m_MatcapDlg == NULL)
	{
		m_MatcapDlg = new MatcapSelectDlg(this);
		connect(
			m_MatcapDlg,
			SIGNAL(ListSelectChanged()),
			this,
			SLOT(MatcapDlg_ListSelectChanged()));
	}

	m_MatcapDlg->show();
}

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

	LoadMatcapImage(p);
}

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

	ui.labelEnvReflection->setText(QString::number(r, 'f', 2));

	updateView_All();
}

void FormMain::on_sliderEnvRefract_valueChanged(int value)
{
	float r = ui.sliderEnvRefract->value() / 1000.0;
	m_Scene.m_EnvImg.m_EnvRefract = r;

	ui.labelEnvRefract->setText(QString::number(r, 'f', 2));
	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_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::View3D_SelectedObjectChanged(int sel_obj, int sel_mesh)
{
	ui.widgetObjectList->OnSelectedObjectChanged(sel_obj, sel_mesh);
}

void FormMain::View3D_SelectedMatChanged(int sel_idx)
{
	ui.listMaterial->setCurrentRow(sel_idx);
}

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

void FormMain::View3D_StatusTipChanged(QString msg)
{
	//ui.statusBar->showMessage(msg, 1500);
}

void FormMain::View3D_SequenceStepped(int step)
{
	StepSequence(step);
}

void FormMain::View3D_CursorMoved()
{
	Cursor3D& c = m_Scene.m_Cursor3d;
	QString x = QString::number(c.CursorPos.x, 'f', 4);
	QString y = QString::number(c.CursorPos.y, 'f', 4);
	QString z = QString::number(c.CursorPos.z, 'f', 4);
	QString s;
	if (x.at(0) != '-')
		s += " ";
	s += x;
	if (y.at(0) != '-')
		s += " ";
	s += " ";
	s += y;
	if (z.at(0) != '-')
		s += " ";
	s += " ";
	s += z;

	ui.editCursorPos->setText(s);
}

void FormMain::StepSequence(int step)
{
	QSlider* s = ui.sliderSequence;
	s->setValue(s->value() + step);
}

bool FormMain::IsLastSequence(void)
{
	QSlider* s = ui.sliderSequence;
	return s->value() == s->maximum();
}

bool FormMain::IsTopSequence(void)
{
	QSlider* s = ui.sliderSequence;
	return s->value() == 0;
}

void FormMain::UpdateCameraStatus(void)
{
	const Camera& camera = m_Scene.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();

	if (QObject::sender() == ui.actionRecordStroke)
	{
		m_Scene.m_Cursor3d.CutStroke();
	}

	updateView_3D();
}

void FormMain::on_actionResetCursor_triggered()
{
	m_Scene.m_Cursor3d.ResetCursorPos();
	updateView_3D();
}

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


void FormMain::on_actionPyScript_triggered()
{
	if (m_PyScriptDlg == NULL)
	{
		m_PyScriptDlg = new FormPyScript(this);
		m_PyScriptDlg->m_Scene = &m_Scene;
		m_PyScriptDlg->m_View3d = &m_View3d;
		m_PyScriptDlg->m_View2d = &m_View2d;
	}

	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()
{
	QGVAboutDlg dlg;
	dlg.exec();
}

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_sliderLightPowerDS_valueChanged(int value)
{
	float n = 2.0f * GetSliderNormalizedPos(ui.sliderLightPowerDS);
	m_View3d.SetDfSpLightPower(n);

	UpdateLightPowerText();

	updateView_All();
}

void FormMain::on_buttonResetLightPowerDS_clicked()
{
	ui.sliderLightPowerDS->setValue(1000);
}

void FormMain::on_sliderLightPowerA_valueChanged(int value)
{
	float n = 2.0f * GetSliderNormalizedPos(ui.sliderLightPowerA);
	m_View3d.SetAmbientLightPower(n);

	UpdateLightPowerText();

	updateView_All();
}

void FormMain::on_buttonResetLightPowerA_clicked()
{
	ui.sliderLightPowerA->setValue(1000);
}

void FormMain::UpdateLightPowerText(void)
{
	float ld = 2.0f * GetSliderNormalizedPos(ui.sliderLightPowerDS);
	float la = 2.0f * GetSliderNormalizedPos(ui.sliderLightPowerA);

	QString s = "";
	s += QString("Light");
	s += QString(" DS=") + QString::number(ld, 'f', 2);
	s += QString(" A=") + QString::number(la, 'f', 2);
	ui.labelLightPower->setText(s);
}

void FormMain::on_checkHoleAroundCursor_clicked(bool checked)
{
	if (checked)
		ui.checkShowOnlyAroundCursor->setChecked(false);

	if (checked)
		m_Scene.m_Cursor3d.SphereClip = SphereClipType::Hole;
	else
		m_Scene.m_Cursor3d.SphereClip = SphereClipType::None;

	updateView_All();
}

void FormMain::on_checkShowOnlyAroundCursor_toggled(bool checked)
{
	if (checked)
		ui.checkHoleAroundCursor->setChecked(false);

	if (checked)
		m_Scene.m_Cursor3d.SphereClip = SphereClipType::ShowAround;
	else
		m_Scene.m_Cursor3d.SphereClip = SphereClipType::None;

	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::LoadCurSelMatTexture(TextureType type)
{
	QString path = GetSupportedImageFilePathFromDlg("Load Texture");
	if (path.isEmpty())
		return;

	LoadCurSelMatTexture(type, path);
}

void FormMain::LoadCurSelMatTexture(TextureType type, QString filepath)
{
	GeomTextureSet* ts = m_Scene.GetSelectedTexture();
	if (ts == NULL)
		return;

	MeshBuf* mbuf = ts->GetParent();
	std::string fp = filepath.toLocal8Bit().data();

	QString name_qs = QFileInfo(filepath).fileName();
	std::string name = name_qs.toLocal8Bit().data();

	m_ContextShare.BeginDrawTop();

	mbuf->ReleaseTextureUnit(ts, type);
	gl::GlTexture* tex = mbuf->GetInitTexture(fp, name, m_Scene.m_TexConfig);
	ts->SetTextureUnit(type, tex);

	if (type == TextureType::Normal)
		m_View3d.ReleaseAllRenderBuffer();

	m_ContextShare.EndDrawTop();

	OnChangedSelectedMaterial();
	updateView_All();
}

void FormMain::ReleaseCurSelTexture(TextureType type)
{
	GeomTextureSet* ts = m_Scene.GetSelectedTexture();
	if (ts == NULL)
		return;

	MeshBuf* mbuf = ts->GetParent();
	int mat_idx = mbuf->GetSelMatIdx();

	m_ContextShare.BeginDrawTop();
	mbuf->ReleaseTextureUnit(mat_idx, type);
	m_ContextShare.EndDrawTop();

	OnChangedSelectedMaterial();
	updateView_All();
}

void FormMain::LoadMatcapImageForCurrentMat(QString& path)
{
	GeomTextureSet* ts = m_Scene.GetSelectedTexture();
	if (ts == NULL)
		return;

	QString title = QFileInfo(path).fileName();

	m_ContextShare.BeginDrawTop();
	ts->TexMatcap.LoadTexture(path.toLocal8Bit().data());
	ts->TexMatcap.SetName(title);
	m_ContextShare.EndDrawTop();

	OnChangedSelectedMaterial();
	updateView_All();
}

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

	QString title = QFileInfo(path).fileName();

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

	ui.editMatcap->setText(mc.GetName());

	updateView_All();
}

void FormMain::on_buttonOpenMatCapEachMaterial_clicked()
{
	QString path = GetSupportedImageFilePathFromDlg("Load Texture");
	if (path.isEmpty())
		return;

	LoadMatcapImage(path);
}

void FormMain::on_buttonClearMatCapEachMaterial_clicked()
{
	geom::GeomTextureSet* tex = m_Scene.GetSelectedTexture();
	if (tex == NULL)
		return;

	m_ContextShare.BeginDrawTop();
	tex->TexMatcap.ClearEnv();
	m_ContextShare.EndDrawTop();

	ui.editMatCapEachMaterial->clear();

	updateView_All();
}

void FormMain::on_buttonOpenCurrentMatColorMap_clicked()
{
	LoadCurSelMatTexture(TextureType::Color);
}

void FormMain::on_buttonClearCurrentMatColorMap_clicked()
{
	ReleaseCurSelTexture(TextureType::Color);
}

void FormMain::on_buttonOpenCurrentMatNormalMap_clicked()
{
	LoadCurSelMatTexture(TextureType::Normal);
}

void FormMain::on_buttonClearCurrentMatNormalMap_clicked()
{
	ReleaseCurSelTexture(TextureType::Normal);
}

void FormMain::SetColorPalleteBG(QWidget* w, QColor col)
{
	QColor border(0, 0, 0);
	SetWidgetColor(w, col, border);
}

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

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

void FormMain::on_sliderShininess_valueChanged(int value)
{
	lib_geo::BaseMaterial* mat = m_Scene.GetSelectedMaterial();
	if (mat == NULL)
		return;

	float val = (float)ui.sliderShininess->value();
	float val_max = (float)ui.sliderShininess->maximum();

	float real_val = 200.0f * val / val_max;

	mat->m_Shininess = real_val;

	ui.labelShininessVal->setText(QString::number(real_val, 'f', 2));

	updateView_All();
}

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 (QAction* a : recents->actions())
	{
		path.push_back(a->text());
	}
}

void FormMain::AddRecentFile(const QString& path)
{
	QString path_local = QDir::toNativeSeparators(path);

	static const int max_files = 10;

	QMenu* recents = ui.menuOpenRecent;

	for (QAction* a : recents->actions())
	{
		if (a->text() == path_local)
		{
			recents->removeAction(a);
			break;
		}
	}

	QAction* new_path = new QAction(path_local, 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 (OpenGeomFileToLast(path))
		return;
}

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

	m_View3d.m_ShaderLib.ReleaseAllShaders();

	m_ContextShare.EndDrawTop();

	updateView_All();
}

void FormMain::on_combo2DViewSrcType_currentIndexChanged(int index)
{
	switch (index)
	{
	case 0 : return m_View2d.ChangeTextureSource(View2DTexSrc::Color);
	case 1 : return m_View2d.ChangeTextureSource(View2DTexSrc::Normal);
	default:
		assert(false);
		break;
	}
}

void FormMain::on_sliderSequence_valueChanged(int value)
{
	UpdateSequence();
}

void FormMain::ResetSequenceSliderRange(void)
{
	int m = m_Scene.GetKeyframeMax();
	ui.sliderSequence->setMaximum(m);
	UpdateSequence();
}

void FormMain::UpdateSequence(void)
{
	int v = ui.sliderSequence->value();
	int m = ui.sliderSequence->maximum();

	QString s = QString("%1 / %2").arg(v).arg(m);
	ui.labelSequencePos->setText(s);

	m_Scene.SetFrame(v);

	m_View3d.ReleaseAllRenderBuffer();
	updateView_All();
}

void FormMain::on_actionNewStroke_triggered()
{
	m_Scene.m_Cursor3d.CutStroke();
	updateView_All();
}

void FormMain::on_actionClearStroke_triggered()
{
	m_Scene.m_Cursor3d.ClearStroke();
	updateView_All();
}

void FormMain::on_buttonMatPreset_clicked()
{
	lib_geo::BaseMaterial* mat = m_Scene.GetSelectedMaterial();
	if (mat == NULL)
		return;

	lib_geo::BaseMaterial mat_backup = (*mat);

	if (m_MatPresetDlg == NULL)
	{
		m_MatPresetDlg = new MaterialPresetDlg(this);
		connect(
			m_MatPresetDlg,
			SIGNAL(OnMatChanged()),
			this,
			SLOT(MatPresetDlg_OnMatChanged()));
	}

	MatPresetDlg_OnMatChanged();

	if (m_MatPresetDlg->exec() != QDialog::Accepted)
	{
		(*mat) = mat_backup;
		OnChangedSelectedMaterial();
		updateView_All();
		return;
	}

	lgr::MaterialSamples::MaterialSampleType t = m_MatPresetDlg->GetSelectedType();

	if (t != lgr::MaterialSamples::MAT_NONE)
		(*mat) = lgr::MaterialSamples::GetMaterial(t);
	else
		(*mat) = mat_backup;

	OnChangedSelectedMaterial();
	updateView_All();
}

void FormMain::MatPresetDlg_OnMatChanged()
{
	lib_geo::BaseMaterial* mat = m_Scene.GetSelectedMaterial();
	if (mat == NULL)
		return;

	lgr::MaterialSamples::MaterialSampleType t = m_MatPresetDlg->GetSelectedType();
	if (t == lgr::MaterialSamples::MAT_NONE)
		return;

	(*mat) = lgr::MaterialSamples::GetMaterial(t);

	OnChangedSelectedMaterial();
	updateView_All();
}

void FormMain::on_checkEnableIndexRange_toggled(bool checked)
{
	IndexRangeConfig& ir = m_Scene.m_IndexVisrange;
	ir.enableRange = checked;

	m_View3d.ReleaseAllIndexList();
	updateView_All();
}

void FormMain::on_editIndexLimitOffset_textChanged(const QString &arg1)
{
	IndexRangeConfig& ir = m_Scene.m_IndexVisrange;

	bool b;
	int i = arg1.toInt(&b);
	if (!b)
		return;

	ir.beginIdx = i;

	if (ir.enableRange)
	{
		m_View3d.ReleaseAllIndexList();
		updateView_All();
	}
}

void FormMain::on_editIndexLimitLen_textChanged(const QString &arg1)
{
	IndexRangeConfig& ir = m_Scene.m_IndexVisrange;

	bool b;
	int i = arg1.toInt(&b);
	if (!b)
		return;

	ir.idxLen = i;

	if (ir.enableRange)
	{
		m_View3d.ReleaseAllIndexList();
		updateView_All();
	}
}

void FormMain::on_fscrollIndexLimitOffset_onScroll(int step)
{
	IndexRangeConfig& ir = m_Scene.m_IndexVisrange;

	int n = ir.beginIdx + step;
	n = (std::max)(n, 0);
	ui.editIndexLimitOffset->setText(QString::number(n));
}

void FormMain::on_fscrollIndexLimitOffset_onReset()
{
	ui.editIndexLimitOffset->setText("0");
}

void FormMain::on_fscrollIndexLimitLen_onScroll(int step)
{
	IndexRangeConfig& ir = m_Scene.m_IndexVisrange;

	int n = ir.idxLen + step;
	n = (std::max)(n, 1);
	ui.editIndexLimitLen->setText(QString::number(n));
}

void FormMain::on_fscrollIndexLimitLen_onReset()
{
	ui.editIndexLimitLen->setText("1");
}

void FormMain::on_buttonTextureScaleDiv10_clicked()
{
	MulTexScaleMain(1.0 / 10.0);
}

void FormMain::on_buttonTextureScaleMul10_clicked()
{
	MulTexScaleMain(10.0);
}

void FormMain::on_fscrollTextureScale_onScroll(int step)
{
	double s = pow(2.0, (double)step / 100.0);
	MulTexScaleMain(s);
}

void FormMain::MulTexScaleMain(double s)
{
	m_Scene.m_TextureTransform.m_TexScale *= s;
	float ts = m_Scene.m_TextureTransform.m_TexScale;
	SetTextSilent(ui.editTextureScale, QString::number(ts));
	updateView_All();
}

void FormMain::on_fscrollTextureScale_onReset()
{
	ui.editTextureScale->setText("1.0");
}

void FormMain::on_editTextureScale_textChanged(const QString &arg1)
{
	bool b;
	double d = arg1.toDouble(&b);
	if (!b)
		return;

	m_Scene.m_TextureTransform.m_TexScale = d;

	updateView_All();
}

void FormMain::SetTextSilent(QLineEdit* edit, const QString& text)
{
	edit->blockSignals(true);
	edit->setText(text);
	edit->blockSignals(false);
}

void FormMain::on_sliderMatcapRate_valueChanged(int value)
{
	float r = GetSliderNormalizedPos(ui.sliderMatcapRate);
	m_Scene.m_MatcapImg.m_BlendRate = r;

	ui.labelMatcapRate->setText(QString::number(r, 'f', 2));

	updateView_All();
}
