/*************************************************************************\
* "$RCSfile: CDlgPreviewSettings.cpp,v $"                                 *
***************************************************************************
* Information by CVS or VSS:                                              *
*     Last check in on: $Date: 2011/09/07 16:33:34 $                      *
*     by                $Author: goebel $
*     Revision        : $Revision: 1.26 $                                 *
\*************************************************************************/
/*! \file CDlgPreviewSettings.cpp
*	\brief Implementation CDlgPreviewSettings Class
**************************************************************************/

#include "VIC_PS.h"
#include "CRegion.h"
#include "CZoomFactor.hpp"
#include "CLog.hpp"
#include "CPSApp.hpp"
#include "CDlg.hpp"
#include "CDlgPreviewSettings.hpp"

CDlgPreviewSettings *CDlgPreviewSettings::m_pThis = NULL;	//!< The one and only CDlgPreviewSettings instance

/*************************************************************************/
CDlgPreviewSettings::CDlgPreviewSettings(int x, int y, int Width, int Height) :
	CDlg(x, y, Width, Height, DialogId::PREV)
/*************************************************************************/
/*! @brief Constructor
**************************************************************************/
{
	int iWidth, iHeight, tlWidth;

	GUI_DlgSetTitle(&m_Dlg, m_pStrings->getValue("DlgPrvTitle", "Preview Settings"));
	m_bDynamicUpdate = true;
	m_pROI = NULL;
	m_pCursor = NULL;

	VIB_ChDir(VIB_Drive[1], m_pApp->GetSkinPath());
	m_Icon[ICON(ID_UP)] = ReadIcon("B_UP.PNG", 64, 40);
	m_Icon[ICON(ID_DOWN)] = ReadIcon("B_DOWN.PNG", 64, 40);
	m_Icon[ICON(ID_LEFT)] = ReadIcon("B_LEFT.PNG", 64, 40);
	m_Icon[ICON(ID_RIGHT)] = ReadIcon("B_RIGHT.PNG", 64, 40);
	m_Icon[ICON(ID_ZOOMUP)] = ReadIcon("B_ZUP.PNG", 64, 40);
	m_Icon[ICON(ID_ZOOMDOWN)] = ReadIcon("B_ZDOWN.PNG", 64, 40);
	m_Icon[ICON(ID_OK_S)] = ReadIcon("B_OK_S.PNG", 98, 40);
	m_Icon[ICON(ID_INFO_S)] = ReadIcon("B_INFO_S.PNG", 98, 40);
	m_Icon[ICON(ID_ROI_TL)] = ReadIcon("B_TL.PNG", 64, 64);
	m_Icon[ICON(ID_ROI_BR)] = ReadIcon("B_BR.PNG", 64, 64);
	m_Icon[ICON(ID_ROI_CENTER)] = ReadIcon("B_CENTER.PNG", 64, 64);
	VIB_ChDir(VIB_Drive[1], "..");

	iWidth  = m_Icon[ICON(ID_UP)].Width;
	iHeight = m_Icon[ICON(ID_UP)].Height;

	m_OVImage = GUI_CImage(NULL, NULL, NULL, Width - 16, (Width - 16) * m_pApp->m_CamReg.m_Height / m_pApp->m_CamReg.m_Width);
	m_YOVImage = GUI_YImage(NULL, m_OVImage.Width, m_OVImage.Height);

	x = 8;
	y = 32;
	m_OVImagePosX = x;
	m_OVImagePosY = y;
	m_ROIXPos = 0;
	m_ROIYPos = 0;
	m_ROIWidth = 0;
	m_ROIHeight = 0;

	GUI_DlgAddIcon(&m_Dlg, x, y, &m_OVImage);
	GUI_DlgAddBorder(&m_Dlg, x - 2, y - 2, m_OVImage.Width + 4, m_OVImage.Height + 4, 5);

	y += m_OVImage.Height + 8;
	GUI_DlgAddIconButton(&m_Dlg, x,	y, iWidth, iHeight, NULL,
						 &m_Icon[ICON(ID_ZOOMDOWN)], ID_ZOOMDOWN);
	GUI_DlgAddAccel(&m_Dlg, '-', ID_ZOOMDOWN);
	GUI_DlgAddIconButton(&m_Dlg, x, y + iHeight + 4, iWidth, iHeight, NULL,
						 &m_Icon[ICON(ID_LEFT)], ID_LEFT);
	GUI_DlgAddIconButton(&m_Dlg, x + iWidth + 4, y, iWidth, iHeight, NULL,
						 &m_Icon[ICON(ID_UP)], ID_UP);
	GUI_DlgAddIconButton(&m_Dlg, x + iWidth + 4, y + iHeight + 4, iWidth, iHeight, NULL,
						 &m_Icon[ICON(ID_DOWN)], ID_DOWN);
	GUI_DlgAddIconButton(&m_Dlg, x + 2 * (iWidth + 4), y, iWidth, iHeight, NULL,
						 &m_Icon[ICON(ID_ZOOMUP)], ID_ZOOMUP);
	GUI_DlgAddAccel(&m_Dlg, '+', ID_ZOOMUP);
	GUI_DlgAddIconButton(&m_Dlg, x + 2 * (iWidth + 4), y + iHeight + 4, iWidth, iHeight, NULL,
						 &m_Icon[ICON(ID_RIGHT)], ID_RIGHT);
	y += 2*(iHeight+4);
	GUI_DlgAddIconButton(&m_Dlg, x, y, m_Icon[ICON(ID_OK_S)].Width, iHeight, NULL,
						 &m_Icon[ICON(ID_OK_S)], DLG_ABORT);
	GUI_DlgAddIconButton(&m_Dlg, x + m_Icon[ICON(ID_OK_S)].Width + 4,	y,
						 m_Icon[ICON(ID_INFO_S)].Width, iHeight, NULL,
						 &m_Icon[ICON(ID_INFO_S)], ID_INFO_S);

	UpdateScaleFactors();

	y += (iHeight + 8);
	GUI_DlgAddBorder(&m_Dlg, x, y - 2, Width - 16, 64, GUI_BSSINGLEINV);
	sprintf(m_ZoomText, "Zoom %s", m_pApp->GetZoomFactor()->GetName());
	GUI_DlgAddDynamicText(&m_Dlg, x + 6, y, m_ZoomText);
	y += 20;
	GUI_DlgAddText(&m_Dlg, x +  6, y, "x:");
	GUI_DlgAddText(&m_Dlg, x +  6, y + 20, "y:");
	GUI_DlgAddText(&m_Dlg, x + 98, y, "Width:");
	GUI_DlgAddText(&m_Dlg, x + 98, y + 20, "Height:");
	GUI_DlgAddDynamicText(&m_Dlg, x +  24, y, m_StrXPos);
	GUI_DlgAddDynamicText(&m_Dlg, x +  24, y + 20, m_StrYPos);
	GUI_DlgAddDynamicText(&m_Dlg, x + 164, y, m_StrWidth);
	GUI_DlgAddDynamicText(&m_Dlg, x + 164, y + 20, m_StrHeight);

	y += (iHeight + 8);
	m_pApp->SetTP(TextStyle::BOLD);
	m_pDlgSItem[INDEX(ID_ROI_NAME)] = GUI_DlgAddText(&m_Dlg, x, y, "ROI:");
	GUI_DlgAddDynamicText(&m_Dlg, x + 48, y, m_StrROIName);
	m_pApp->SetTP(TextStyle::NORMAL);

	y += 18;
	iHeight = m_Icon[ICON(ID_ROI_TL)].Height;
	tlWidth = m_Icon[ICON(ID_ROI_TL)].Width;
	m_pDlgItem[INDEX(ID_ROI_TL_ITEM)] =
		GUI_DlgAddIconButton(&m_Dlg, x, y, tlWidth, iHeight, NULL,
							 &m_Icon[ICON(ID_ROI_TL)], ID_ROI_TL);
	m_pDlgItem[INDEX(ID_ROI_CENTER_ITEM)] =
		GUI_DlgAddIconButton(&m_Dlg, x + tlWidth + 4, y,
							 m_Icon[ICON(ID_ROI_CENTER)].Width, iHeight, NULL,
							 &m_Icon[ICON(ID_ROI_CENTER)], ID_ROI_CENTER);
	m_pDlgItem[INDEX(ID_ROI_BR_ITEM)] =
		GUI_DlgAddIconButton(&m_Dlg, x + 2 * (tlWidth + 4), y,
							 m_Icon[ICON(ID_ROI_BR)].Width, iHeight, NULL,
							 &m_Icon[ICON(ID_ROI_BR)], ID_ROI_BR);
	GUI_DlgAddAccel(&m_Dlg, 't', ID_ROI_TL);
	GUI_DlgAddAccel(&m_Dlg, 'c', ID_ROI_CENTER);
	GUI_DlgAddAccel(&m_Dlg, 'b', ID_ROI_BR);

	y += (iHeight + 4);
	m_pDlgSItem[INDEX(ID_ROI_STRX)] = GUI_DlgAddLabel(&m_Dlg, x, y, "_x:", ID_ROI_X);
	m_pDlgItem[INDEX(ID_ROI_X)] =
		GUI_DlgAddVEditBox(&m_Dlg, x + 24, y, 48, &m_ROIXPos, 0, m_pApp->GetCamWidth(), ID_ROI_X);
	m_pDlgSItem[INDEX(ID_ROI_STRW)] = GUI_DlgAddLabel(&m_Dlg, x + 92, y, "_Width:", ID_ROI_W);
	m_pDlgItem[INDEX(ID_ROI_W)] =
		GUI_DlgAddVEditBox(&m_Dlg, x + 152, y, 48, &m_ROIWidth, 0, m_pApp->GetCamWidth(), ID_ROI_W);

	y += 24;
	m_pDlgSItem[INDEX(ID_ROI_STRY)] = GUI_DlgAddLabel(&m_Dlg, x, y, "_y:", ID_ROI_Y);
	m_pDlgItem[INDEX(ID_ROI_Y)] =
		GUI_DlgAddVEditBox(&m_Dlg, x + 24, y, 48, &m_ROIYPos, 0, m_pApp->GetCamHeight(), ID_ROI_Y);
	m_pDlgSItem[INDEX(ID_ROI_STRH)] = GUI_DlgAddLabel(&m_Dlg, x + 92, y, "_Height:", ID_ROI_H);
	m_pDlgItem[INDEX(ID_ROI_H)] =
		GUI_DlgAddVEditBox(&m_Dlg, x + 152, y, 48, &m_ROIHeight, 0, m_pApp->GetCamHeight(), ID_ROI_H);

	EnableROI_Items();
	UpdateROIValues();
	m_bForceRedrawEx = false;
}

/*************************************************************************/
CDlgPreviewSettings::~CDlgPreviewSettings()
/*************************************************************************/
/*! @brief Destructor.
**************************************************************************/
{
	GUI_FreeCImage(&m_OVImage);
	GUI_FreeYImage(&m_YOVImage);

	for (int i = 0; i < INDEX(ID_XXX); i++)
		GUI_FreeCImage(&m_Icon[i]);
}

/*************************************************************************/
CDlgPreviewSettings *CDlgPreviewSettings::CreateInstance(int x, int y, int Width, int Height)
/*************************************************************************/
/*! @brief Creates CDlgPreviewSettings instance.
	@param x Horizontal position of dialog
	@param y Vertical position of dialog
	@param Width Width of dialog
	@param Height Height of dialog
	@return Pointer to CDlgPreviewSettings instance
**************************************************************************/
{
	if (m_pThis == NULL)
		m_pThis = new CDlgPreviewSettings(x, y, Width, Height);
	return m_pThis;
}

/*************************************************************************/
void CDlgPreviewSettings::DisposeInstance()
/*************************************************************************/
/*! @brief Disposes CDlgPreviewSettings instance.
**************************************************************************/
{
	if (m_pThis)
		delete m_pThis;
	m_pThis = NULL;
}

/*************************************************************************/
void CDlgPreviewSettings::EnableROI_Items()
/*************************************************************************/
/*! @brief Enables Dialog Items associated with m_pROI.
**************************************************************************/
{
	const int State = (m_pROI != NULL) ? DLG_I_ENABLED: DLG_I_INVISIBLE;
	int i;

	for (i = INDEX(ID_ROI_TL_ITEM); i <= INDEX(ID_ROI_CENTER_ITEM); i++)
		GUI_DlgSetDItemState(m_pDlgItem[i], State);
	for (i = INDEX(ID_ROI_STRX); i <= INDEX(ID_ROI_STRH); i++)
		GUI_DlgSetSItemState(m_pDlgSItem[i], State);
	for (i = INDEX(ID_ROI_X); i <= INDEX(ID_ROI_H); i++)
		GUI_DlgSetDItemState(m_pDlgItem[i], State);
}

/*************************************************************************/
int CDlgPreviewSettings::OnUserIO(int nKey)
/*************************************************************************/
/*! @brief Function processes the user inputs.
	@param nKey Last key code the user entered 
	@return CDlg::m_Activity (!= \p DLG_EOF if the user has made an input)
**************************************************************************/
{
	const int Width = m_pApp->m_YPVImage.Width;
	const int Height = m_pApp->m_YPVImage.Height;
	const int PVWidth = m_pApp->m_PVWidth;
	const int PVHeight = m_pApp->m_PVHeight;
	int txp, typ;
	CZoomFactor *pZoom = m_pApp->GetZoomFactor();

	m_Activity = 0;

	if (m_pApp->IsDlgGettingFocus(m_ID))
		UpdateScaleFactors();

	if (m_pApp->IsDlgInFocus(m_ID))
	{
		m_Activity = GUI_DlgWork(&m_Dlg, nKey);
		switch (m_Activity)
		{	
		case ID_RIGHT:
			if ((m_pApp->m_PVPosX + 4 + PVWidth) < m_pApp->GetCamWidth())
			{
				m_pApp->m_PVPosX += 4;
				m_pApp->m_PVPosX &= ~3;
				UpdateScaleFactors();
			}
			break;
		case ID_LEFT:
			m_pApp->m_PVPosX -= 4;
			m_pApp->m_PVPosX &= ~3;
			if (m_pApp->m_PVPosX < 0)
				m_pApp->m_PVPosX = 0;
			UpdateScaleFactors();
			break;
		case ID_UP:
			m_pApp->m_PVPosY -= 4;
			if (m_pApp->m_PVPosY < 0)
				m_pApp->m_PVPosY = 0;
			UpdateScaleFactors();
			break;
		case ID_DOWN:
			if ((m_pApp->m_PVPosY + 4 + PVHeight) < m_pApp->GetCamHeight())
			{
				m_pApp->m_PVPosY += 4;
				UpdateScaleFactors();
			}
			break;
		case ID_ZOOMUP:
			pZoom->Up();
			m_pApp->m_PVScale = pZoom->GetValue();
			m_pApp->m_PVPosX = 0;
			m_pApp->m_PVPosY = 0;
			UpdateScaleFactors();
			sprintf(m_ZoomText, "Zoom %s", pZoom->GetName());
			break;
		case ID_ZOOMDOWN:
			pZoom->Down();
			m_pApp->m_PVScale = pZoom->GetValue();
			m_pApp->m_PVPosX = 0;
			m_pApp->m_PVPosY = 0;
			UpdateScaleFactors();
			sprintf(m_ZoomText, "Zoom %s", pZoom->GetName());
			break;
		case ID_INFO_S:
			CLog::Print("Zoom: %s (X,Y): (%d,%d):(%d,%d)\n", pZoom->GetName(),
				m_pApp->m_PVPosX,	m_pApp->m_PVPosY, PVWidth, PVHeight);
			break;
		case ID_ROI_TL:
			if (m_pCursor == NULL)
				break;
			if ((m_pCursor->x < m_pROI->m_Right) && (m_pCursor->y < m_pROI->m_Bottom))
			{
				m_pROI->NewWH(m_pCursor->x, m_pCursor->y, m_pROI->m_Width, m_pROI->m_Height, m_pROI->m_Name);
				UpdateROIValues();
			}
			break;
		case ID_ROI_BR:
			if (m_pCursor == NULL)
				break;
			if ((m_pCursor->x > m_pROI->m_Left) && (m_pCursor->y > m_pROI->m_Top))
			{
				m_pROI->NewXY(m_pROI->m_Left, m_pROI->m_Top, m_pCursor->x, m_pCursor->y, m_pROI->m_Name);
				UpdateROIValues();
			}
			break;
		case ID_ROI_CENTER:
			if (m_pCursor == NULL)
				break;
			m_pROI->MoveCenter(m_pCursor->x, m_pCursor->y);
			UpdateROIValues();
			break;
		case DLG_MOUSE_PRESSED:
			txp = m_Dlg.PosX-m_OVImagePosX - m_Dlg.x;
			typ = m_Dlg.PosY-m_OVImagePosY - m_Dlg.y;
			if (txp > 0 && txp < m_OVImage.Width && typ > 0 && typ < m_OVImage.Height)
			{
				txp = txp / m_OVScaleX / m_pApp->GetScale();
				typ = typ / m_OVScaleY / m_pApp->GetScale();
				m_pApp->m_PVPosX = _max2(txp - PVWidth / 2, 0);
				m_pApp->m_PVPosX = _min2(m_pApp->m_PVPosX, m_pApp->GetCamWidth() - PVWidth);
				m_pApp->m_PVPosX = _max2(m_pApp->m_PVPosX, 0);
				m_pApp->m_PVPosY = _max2(typ - PVHeight / 2, 0);
				m_pApp->m_PVPosY = _min2(m_pApp->m_PVPosY, m_pApp->GetCamHeight() - PVHeight);
				m_pApp->m_PVPosY = _max2(m_pApp->m_PVPosY, 0);
				UpdateScaleFactors();
			}
			txp = m_Dlg.PosX - m_PVImageOffsetX;
			typ = m_Dlg.PosY - m_PVImageOffsetY;
			if (txp > 0 && txp < Width && typ > 0 && typ < Height)
			{
				if (m_pCursor != NULL)
				{
					const int x = (float)txp / m_pApp->GetScale() + m_pApp->m_PVPosX;
					const int y = (float)typ / m_pApp->GetScale() + m_pApp->m_PVPosY;
					m_pCursor->x = x;
					m_pCursor->y = y;
					UpdateROIValues();
				}
			}
			else
			{
				m_pApp->ChangeInfoArea(&m_Dlg);
			}
			break;
		case DLG_VALUE_CHANGED:
			if (m_pCursor != NULL)
			{
				m_pROI->NewWH(m_ROIXPos, m_ROIYPos, m_ROIWidth, m_ROIHeight, m_pROI->m_Name);
				UpdateROIValues();
				GUI_DlgUpdate(&m_Dlg, m_pApp->GetDispImage(), m_Dlg.x, m_Dlg.y);
			}
			break;
		case DLG_ABORT:
			m_pApp->SetDlgNewFocus(m_DlgOldFocus);
			m_bIsVisible = false;
			break;
		}
		EnableROI_Items();
	}
	return m_Activity;
}

/*************************************************************************/
void CDlgPreviewSettings::DynamicRedraw()
/*************************************************************************/
/*! @brief Updates the down scaled live image.
**************************************************************************/
{
	m_pApp->DisplayImage(&m_OVImage, m_Dlg.x + m_OVImagePosX, m_Dlg.y + m_OVImagePosY);
	if (m_bForceRedrawEx)
	{
		UpdateROIValues();
		EnableROI_Items();
		GUI_DlgUpdate(&m_Dlg, m_pApp->GetDispImage(), m_Dlg.x, m_Dlg.y);
		m_bForceRedrawEx = false;
	}
}

/*************************************************************************/
void CDlgPreviewSettings::Prepare()
/*************************************************************************/
/*! @brief Draws the preview image as the user sees it.

	The color preview image contains the down scaled live image and the
	green rectangle which represents the region of interest.
**************************************************************************/
{
	if (m_pApp->m_pCamImage == NULL)
		return;

	sprintf(m_ZoomText, "Zoom %s", m_pApp->GetZoomFactor()->GetName());
	GUI_ScaleImageY(m_pApp->m_pCamImage, &m_YOVImage, 0);
	GUI_CopyYArea2RGB(&m_YOVImage, &m_OVImage, 0, 0,
		m_YOVImage.Width, m_YOVImage.Height, 0, 0);

	GUI_Rect(&m_OVImage, m_OVRectPosX, m_OVRectPosY,
		m_OVRectWidth, m_OVRectHeight, &rgbGreen);
	if (m_pROI != NULL)
	{
		GUI_Rect(&m_OVImage, m_OVROIRectPosX, m_OVROIRectPosY,
			m_OVROIRectWidth, m_OVROIRectHeight, &rgbRed);
	}
	if (m_pCursor != NULL)
	{
		GUI_Line(&m_OVImage, m_OVCursorPosX, 0, m_OVCursorPosX, m_OVImage.Height - 1, &rgbMagenta);
		GUI_Line(&m_OVImage, 0, m_OVCursorPosY, m_OVImage.Width - 1, m_OVCursorPosY, &rgbMagenta);
	}
}

/*************************************************************************/
void CDlgPreviewSettings::UpdateScaleFactors()
/*************************************************************************/
/*! @brief Calculates the new scale coefficients when zoomed in or out.
**************************************************************************/
{
	m_pApp->UpdateScaleFactors();
	m_OVScaleX = 1.0 / (m_pApp->GetScale() * m_pApp->GetCamWidth()) * m_OVImage.Width;
	m_OVScaleY = 1.0 / (m_pApp->GetScale() * m_pApp->GetCamHeight()) * m_OVImage.Height;
	m_OVRectPosX = _max2(m_OVScaleX * m_pApp->m_VCamPosX, 0);
	m_OVRectPosY = _max2(m_OVScaleY * m_pApp->m_VCamPosY, 0);
	m_OVRectWidth  = m_OVScaleX * m_pApp->m_YPVImage.Width;
	m_OVRectHeight = m_OVScaleY * m_pApp->m_YPVImage.Height;
	m_OVRectWidth  = _min2(m_OVRectWidth, m_OVImage.Width - m_OVRectPosX);
	m_OVRectHeight = _min2(m_OVRectHeight, m_OVImage.Height - m_OVRectPosY);

	sprintf(m_StrXPos, "%d", m_pApp->m_PVPosX);
	sprintf(m_StrYPos, "%d", m_pApp->m_PVPosY);
	sprintf(m_StrWidth, "%d", m_pApp->m_PVWidth);
	sprintf(m_StrHeight, "%d", m_pApp->m_PVHeight);
}

/*************************************************************************/
void CDlgPreviewSettings::UpdateROIValues()
/*************************************************************************/
/*! @brief Updates the strings associated with \p m_pROI.
**************************************************************************/
{
	const int Width  = m_pApp->GetCamWidth();
	const int Height = m_pApp->GetCamHeight();

	if (m_pROI != NULL)
	{
		m_ROIXPos = m_pROI->m_Left;
		m_ROIYPos = m_pROI->m_Top;
		m_ROIWidth = m_pROI->m_Width;
		m_ROIHeight = m_pROI->m_Height;
		m_OVROIRectPosX = (float)m_OVImage.Width / (float)Width * (float) m_pROI->m_Left;
		m_OVROIRectPosY = (float)m_OVImage.Height / (float)Height * (float) m_pROI->m_Top;
		m_OVROIRectWidth = m_OVScaleX * (m_pROI->m_Right - m_pROI->m_Left);
		m_OVROIRectHeight = m_OVScaleY * (m_pROI->m_Bottom - m_pROI->m_Top);

		m_StrROIName[20] = '\0';
		m_pROI->SetAutoClip(Width, Height);
	}
	else
	{
		m_StrROIName[0] = '\0';
	}
	if (m_pCursor != NULL)
	{
		m_OVCursorPosX = (float)m_OVImage.Width / (float)Width * m_pCursor->x;
		m_OVCursorPosY = (float)m_OVImage.Height / (float)Height * m_pCursor->y;
	}
}

/**************************************************************************/
