#include <algorithm>
#include <apps/Common/Info.h>
#include <apps/Common/mvIcon.xpm>
#include "CaptureThread.h"
#include "HistogramCanvas.h"
#include "icons.h"
#include "ImageCanvas.h"
#include "InfoPlotCanvas.h"
#include <limits>
#include "LineProfileCanvas.h"
#include <memory>
#include "PropData.h"
#include "PropViewFrame.h"
#include "ValuesFromUserDlg.h"
#include "VectorScopeCanvas.h"
#include <wx/choicdlg.h>
#include <wx/config.h>
#include <wx/dnd.h>
#include <wx/file.h>
#include <wx/filename.h>
#include <wx/numdlg.h>
#include <wx/slider.h>
#include <wx/spinctrl.h>
#include <wx/splitter.h>
#include <wx/tooltip.h>
#include <wxPropGrid/Include/propgrid.h>

#ifdef WIN32
#	define BUILD_WITH_TEXT_EVENTS_FOR_SPINCTRL
#endif // #ifdef WIN32

using namespace mvIMPACT::acquire;
using namespace std;

DEFINE_EVENT_TYPE(imageReadyEvent)
DEFINE_EVENT_TYPE(imageSkippedEvent)
DEFINE_EVENT_TYPE(toggleDisplayArea)
DEFINE_EVENT_TYPE(liveModeAborted)
DEFINE_EVENT_TYPE(eventNotified)
DEFINE_EVENT_TYPE(sequenceReadyEvent)
DEFINE_EVENT_TYPE(imageInfoEvent)
DEFINE_EVENT_TYPE(refreshAOIControls)
DEFINE_EVENT_TYPE(refreshCurrentPixelData)

//-----------------------------------------------------------------------------
template<class _Ty>
void DeleteElement( _Ty& data )
//-----------------------------------------------------------------------------
{
	delete data;
	data = 0;
}

//-----------------------------------------------------------------------------
struct SettingData
//-----------------------------------------------------------------------------
{
	TScope scope_;
	string name_;
	explicit SettingData( TScope scope, const string& name ) : scope_(scope), name_(name) {}
};

//=============================================================================
//================= Implementation RequestData ================================
//=============================================================================

const wxString RequestData::UNKNOWN_PIXEL_FORMAT_STRING_(wxT("unknown"));

//-----------------------------------------------------------------------------
RequestData::RequestData() : image_(1), pixelFormat_(UNKNOWN_PIXEL_FORMAT_STRING_)
//-----------------------------------------------------------------------------
{
	image_.getBuffer()->pixelFormat = ibpfMono8;
	memset( &requestInfo_, 0, sizeof(requestInfo_) );
}


//=============================================================================
//================= Implementation FramePositionStorage =======================
//=============================================================================
//-----------------------------------------------------------------------------
class FramePositionStorage
//-----------------------------------------------------------------------------
{
	wxConfigBase* m_pConfig;
	wxWindow* m_pWin;
	wxString m_windowName;
public:
	FramePositionStorage( wxWindow* pWin, const wxString& windowName ) : m_pConfig(wxConfigBase::Get()), m_pWin(pWin), m_windowName(windowName) {}
	void store( void ) const
	{
		int Height, Width, XPos, YPos;
		m_pWin->GetSize( &Width, &Height );
		m_pWin->GetPosition( &XPos, &YPos );
		m_pConfig->Write( wxString::Format( wxT("/%s/h"), m_windowName.c_str() ), Height );
		m_pConfig->Write( wxString::Format( wxT("/%s/w"), m_windowName.c_str() ), Width );
		m_pConfig->Write( wxString::Format( wxT("/%s/x"), m_windowName.c_str() ), XPos );
		m_pConfig->Write( wxString::Format( wxT("/%s/y"), m_windowName.c_str() ), YPos );
	}
	wxRect restore( const wxRect& defaultDimensions ) const
	{
		wxRect rect;
		rect.height = m_pConfig->Read( wxString::Format( wxT("/%s/h"), m_windowName.c_str() ), defaultDimensions.height );
		rect.width = m_pConfig->Read( wxString::Format( wxT("/%s/w"), m_windowName.c_str() ), defaultDimensions.width );
		rect.x = m_pConfig->Read( wxString::Format( wxT("/%s/x"), m_windowName.c_str() ), defaultDimensions.x );
		rect.y = m_pConfig->Read( wxString::Format( wxT("/%s/y"), m_windowName.c_str() ), defaultDimensions.y );
		int displayWidth = 0;
		int displayHeight = 0;
		wxDisplaySize( &displayWidth, &displayHeight );
		if( ( rect.x >= displayWidth ) || ( rect.x < 0 ) )
		{
			rect.x = 0;
		}
		if( ( rect.y >= displayHeight ) || ( rect.y < 0 ) )
		{
			rect.y = 0;
		}
		return rect;
	}
};

//-----------------------------------------------------------------------------
class DnDFile : public wxFileDropTarget
//-----------------------------------------------------------------------------
{
public:
	DnDFile(PropViewFrame *pOwner) { m_pOwner = pOwner; }
	virtual bool OnDropFiles( wxCoord, wxCoord, const wxArrayString& fileNames )
	{
		return ( fileNames.IsEmpty() ) ? false : m_pOwner->SetCurrentImage( fileNames.Item( 0 ) );
	}
private:
	PropViewFrame *m_pOwner;
};

//-----------------------------------------------------------------------------
class MonitorDisplay : public wxFrame
//-----------------------------------------------------------------------------
{
	ImageCanvas* m_pDisplayArea;
public:
	explicit MonitorDisplay( wxWindow* pParent ) : wxFrame(pParent, wxID_ANY, wxT("Monitor display"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT)
	{
		wxBoxSizer* pTopDownSizer = new wxBoxSizer(wxHORIZONTAL);
		wxPanel* pPanel = new wxPanel(this);
		m_pDisplayArea = new ImageCanvas(this, pPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN, wxEmptyString);
		m_pDisplayArea->SetScaling( true );
		m_pDisplayArea->HandleMouseAndKeyboardEvents( false );
		pTopDownSizer->Add( m_pDisplayArea, wxSizerFlags(1).Expand() );
		pPanel->SetSizer( pTopDownSizer );
		pTopDownSizer->SetSizeHints( this );
		SetSizeHints( 100, 66 );
		wxRect defaultRect(0, 0, 150, 100);
		FramePositionStorage frameStorage(this, wxString(wxT("MonitorDisplay")));
		SetSize( frameStorage.restore( defaultRect ) );
	}
	~MonitorDisplay()
	{
		FramePositionStorage frameStorage(this, wxString(wxT("MonitorDisplay")));
		frameStorage.store();
	}
	ImageCanvas* GetDisplayArea( void ) { return m_pDisplayArea; }
};

//=============================================================================
//================= Implementation MyApp ======================================
//=============================================================================
//-----------------------------------------------------------------------------
class MyApp : public wxApp
//-----------------------------------------------------------------------------
{
public:
	virtual bool OnInit( void )
	{
		wxImage::AddHandler( new wxGIFHandler );
		wxImage::AddHandler( new wxJPEGHandler );
		wxImage::AddHandler( new wxPNGHandler );
		wxImage::AddHandler( new wxTIFFHandler );
		// Create the main application window
		PropViewFrame *pFrame = new PropViewFrame( wxString::Format( wxT("wxPropView(%s)"), VERSION_STRING ), wxDefaultPosition, wxDefaultSize, argc, argv );
		pFrame->Show( true );
		SetTopWindow( pFrame );
		// success: wxApp::OnRun() will be called which will enter the main message
		// loop and the application will run. If we returned false here, the
		// application would exit immediately.
		return true;
	}
};

// Create a new application object: this macro will allow wxWidgets to create
// the application object during program execution (it's better than using a
// static object for many reasons) and also declares the accessor function
// wxGetApp() which will return the reference of the right type (i.e. MyApp and
// not wxApp)
IMPLEMENT_APP(MyApp)

//=============================================================================
//================= Implementation ImageAnalysisPlotControls ==================
//=============================================================================
//-----------------------------------------------------------------------------
void ImageAnalysisPlotControls::Load( wxConfigBase* pConfig )
//-----------------------------------------------------------------------------
{
	bool boEnable = pConfig->Read( wxString::Format(wxT("/Controls/%s/AOIFullMode"), m_pPlotCanvas->GetConfigName().c_str()), 0l ) != 0;
	m_pCBAOIFullMode->SetValue( boEnable );
	m_pPlotCanvas->SetAOIFullMode( boEnable );
	m_pSCAOIh->SetValue( pConfig->Read( wxString::Format(wxT("/Controls/%s/AOIh"), m_pPlotCanvas->GetConfigName().c_str()), 480l ) );
	m_pSCAOIw->SetValue( pConfig->Read( wxString::Format(wxT("/Controls/%s/AOIw"), m_pPlotCanvas->GetConfigName().c_str()), 640l ) );
	m_pSCAOIx->SetValue( pConfig->Read( wxString::Format(wxT("/Controls/%s/AOIx"), m_pPlotCanvas->GetConfigName().c_str()), 0l ) );
	m_pSCAOIy->SetValue( pConfig->Read( wxString::Format(wxT("/Controls/%s/AOIy"), m_pPlotCanvas->GetConfigName().c_str()), 0l ) );
	if( m_pSCDrawStart_percent )
	{
		m_pSCDrawStart_percent->SetValue( pConfig->Read( wxString::Format(wxT("/Controls/%s/DrawStartPercent"), m_pPlotCanvas->GetConfigName().c_str()), 0l ) );
	}
	if( m_pSCDrawWindow_percent )
	{
		m_pSCDrawWindow_percent->SetValue( pConfig->Read( wxString::Format(wxT("/Controls/%s/DrawWindowPercent"), m_pPlotCanvas->GetConfigName().c_str()), 100l ) );
	}
	if( m_pSCDrawStepWidth )
	{
		m_pSCDrawStepWidth->SetValue( pConfig->Read( wxString::Format(wxT("/Controls/%s/DrawStepWidth"), m_pPlotCanvas->GetConfigName().c_str()), 0l ) );
	}
	if( m_pSCGridStepsX )
	{
		m_pSCGridStepsX->SetValue( pConfig->Read( wxString::Format(wxT("/Controls/%s/GridStepsX"), m_pPlotCanvas->GetConfigName().c_str()), 1l ) );
	}
	if( m_pSCGridStepsY )
	{
		m_pSCGridStepsY->SetValue( pConfig->Read( wxString::Format(wxT("/Controls/%s/GridStepsY"), m_pPlotCanvas->GetConfigName().c_str()), 1l ) );
	}
	m_pSCUpdateSpeed->SetValue( pConfig->Read( wxString::Format(wxT("/Controls/%s/UpdateSpeed"), m_pPlotCanvas->GetConfigName().c_str()), 3l ) );
	ImageAnalysisPlotCanvas::TDisplayMethod displayMethod = static_cast<ImageAnalysisPlotCanvas::TDisplayMethod>(pConfig->Read( wxString::Format(wxT("/Controls/%s/DisplayMethod"), m_pPlotCanvas->GetConfigName().c_str()), 0l ));
	m_pNBDisplayMethod->SetSelection( displayMethod );
	m_pPlotCanvas->SetDisplayMethod( displayMethod );
	UpdateControls();
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotControls::Save( wxConfigBase* pConfig )
//-----------------------------------------------------------------------------
{
	pConfig->Write( wxString::Format(wxT("/Controls/%s/AOIFullMode"), m_pPlotCanvas->GetConfigName().c_str()), m_pCBAOIFullMode->GetValue() );
	pConfig->Write( wxString::Format(wxT("/Controls/%s/AOIh"), m_pPlotCanvas->GetConfigName().c_str()), m_pSCAOIh->GetValue() );
	pConfig->Write( wxString::Format(wxT("/Controls/%s/AOIw"), m_pPlotCanvas->GetConfigName().c_str()), m_pSCAOIw->GetValue() );
	pConfig->Write( wxString::Format(wxT("/Controls/%s/AOIx"), m_pPlotCanvas->GetConfigName().c_str()), m_pSCAOIx->GetValue() );
	pConfig->Write( wxString::Format(wxT("/Controls/%s/AOIy"), m_pPlotCanvas->GetConfigName().c_str()), m_pSCAOIy->GetValue() );
	if( m_pSCDrawStart_percent )
	{
		pConfig->Write( wxString::Format(wxT("/Controls/%s/DrawStartPercent"), m_pPlotCanvas->GetConfigName().c_str()), m_pSCDrawStart_percent->GetValue() );
	}
	if( m_pSCDrawWindow_percent )
	{
		pConfig->Write( wxString::Format(wxT("/Controls/%s/DrawWindowPercent"), m_pPlotCanvas->GetConfigName().c_str()), m_pSCDrawWindow_percent->GetValue() );
	}
	if( m_pSCDrawStepWidth )
	{
		pConfig->Write( wxString::Format(wxT("/Controls/%s/DrawStepWidth"), m_pPlotCanvas->GetConfigName().c_str()), m_pSCDrawStepWidth->GetValue() );
	}
	if( m_pSCGridStepsX )
	{
		pConfig->Write( wxString::Format(wxT("/Controls/%s/GridStepsX"), m_pPlotCanvas->GetConfigName().c_str()), m_pSCGridStepsX->GetValue() );
	}
	if( m_pSCGridStepsY )
	{
		pConfig->Write( wxString::Format(wxT("/Controls/%s/GridStepsY"), m_pPlotCanvas->GetConfigName().c_str()), m_pSCGridStepsY->GetValue() );
	}
	pConfig->Write( wxString::Format(wxT("/Controls/%s/UpdateSpeed"), m_pPlotCanvas->GetConfigName().c_str()), m_pSCUpdateSpeed->GetValue() );
	pConfig->Write( wxString::Format(wxT("/Controls/%s/DisplayMethod"), m_pPlotCanvas->GetConfigName().c_str()), m_pNBDisplayMethod->GetSelection() );
}

//-----------------------------------------------------------------------------
void ImageAnalysisPlotControls::UpdateControls( void )
//-----------------------------------------------------------------------------
{
	bool boFullAOIMode = m_pCBAOIFullMode->IsChecked();
	m_pSCAOIx->Enable( !boFullAOIMode );
	m_pSCAOIy->Enable( !boFullAOIMode );
	m_pSCAOIw->Enable( !boFullAOIMode );
	m_pSCAOIh->Enable( !boFullAOIMode );
}

//=============================================================================
//================= Implementation PropViewFrame ==============================
//=============================================================================
// ----------------------------------------------------------------------------
// event tables and other macros for wxWidgets
// ----------------------------------------------------------------------------

// the event tables connect the wxWidgets events with the functions (event
// handlers) which process them. It can be also done at run-time, but for the
// simple menu events like this the static method is much simpler.
BEGIN_EVENT_TABLE(PropViewFrame, wxFrame)
	EVT_MENU(miHelp_About, PropViewFrame::OnAbout)
	EVT_MENU(miQuit, PropViewFrame::OnQuit)
	EVT_MENU(miAction_UseDevice, PropViewFrame::OnUseDevice)
	EVT_MENU(miAction_Settings_Save_ToDefault, PropViewFrame::OnSaveToDefault)
	EVT_MENU(miAction_Settings_Save_SystemToDefault, PropViewFrame::OnSaveSystemToDefault)
	EVT_MENU(miAction_Settings_Save_CurrentProduct, PropViewFrame::OnSaveCurrentProduct)
	EVT_MENU(miAction_Settings_Save_ActiveDevice, PropViewFrame::OnSaveActiveDevice)
	EVT_MENU(miAction_Settings_Save_ExportActiveDevice, PropViewFrame::OnExportActiveDevice)
	EVT_MENU(miAction_Settings_Load_FromDefault, PropViewFrame::OnLoadFromDefault)
	EVT_MENU(miAction_Settings_Load_CurrentProduct, PropViewFrame::OnLoadCurrentProduct)
	EVT_MENU(miAction_Settings_Load_ActiveDevice, PropViewFrame::OnLoadActiveDevice)
	EVT_MENU(miAction_Settings_Load_ImportActiveDevice, PropViewFrame::OnImportActiveDevice)
	EVT_MENU(miAction_Settings_Manage, PropViewFrame::OnManageSettings)
	EVT_MENU(miAction_LoadImage, PropViewFrame::OnLoadImage)
	EVT_MENU(miAction_SaveImage, PropViewFrame::OnSaveImage)
	EVT_MENU(miAction_SaveImageSequence, PropViewFrame::OnSaveImageSequence)
	EVT_MENU(miAction_UpdateDeviceList, PropViewFrame::OnUpdateDeviceList)
	EVT_MENU(miPopUpPropRestoreDefault, PropViewFrame::OnPopUpPropRestoreDefault)
	EVT_MENU(miPopUpPropAppendValue, PropViewFrame::OnPopUpPropAppendValue)
	EVT_MENU(miPopUpPropDeleteValue, PropViewFrame::OnPopUpPropDeleteValue)
	EVT_MENU(miPopUpPropSetMultiple_FixedValue, PropViewFrame::OnPopUpPropSetMultiple_FixedValue)
	EVT_MENU(miPopUpPropSetMultiple_FromToRange, PropViewFrame::OnPopUpPropSetMultiple_FromToRange)
	EVT_MENU(miPopUpMethExec, PropViewFrame::OnPopUpMethExec)
	EVT_MENU(miCapture_Live, PropViewFrame::OnBtnLive)
	EVT_MENU(miCapture_Snap, PropViewFrame::OnBtnSnap)
	EVT_MENU(miCapture_Abort, PropViewFrame::OnBtnAbort)
	EVT_MENU(miCapture_Record, PropViewFrame::OnBtnRecord)
	EVT_MENU(miCapture_Backward, PropViewFrame::OnIncDecRecordDisplay)
	EVT_MENU(miCapture_Forward, PropViewFrame::OnIncDecRecordDisplay)
	EVT_MENU(miCapture_SetupCaptureQueueDepth, PropViewFrame::OnSetupCaptureQueueDepth)
	EVT_MENU(miSettings_Display_Active, PropViewFrame::OnActivateDisplay)
	EVT_MENU(miSettings_Display_FitToScreen, PropViewFrame::OnFitToDisplay)
	EVT_MENU(miSettings_Display_ShowMonitorImage, PropViewFrame::OnShowMonitorDisplay)
	EVT_MENU(miSettings_Display_ShowOverlayMessages, PropViewFrame::OnShowDisplayMessagesAsOverlay)
	EVT_MENU(miSettings_Display_ShowRequestInfoAsOverlay, PropViewFrame::OnShowRequestInfosAsOverlay)
	EVT_MENU(miSettings_Display_ShowIncompleteFrames, PropViewFrame::OnShowIncompleteFrames)
	EVT_MENU(miSettings_Recording_Continuous, PropViewFrame::OnContinuousRecording)
	EVT_MENU(miSettings_Recording_SetupSequenceSize, PropViewFrame::OnSetupRecordSequenceSize)
	EVT_MENU(miSettings_ShowStatusBar, PropViewFrame::OnShowStatusBar)
	EVT_MENU(miSettings_ShowToolBar, PropViewFrame::OnShowToolBar)
	EVT_MENU(miSettings_ShowConnectedDevicesOnly, PropViewFrame::OnConnectedOnly)
	EVT_MENU(miSettings_Analysis_ShowControls, PropViewFrame::OnSettings_Analysis_ShowControls)
	EVT_MENU(miSettings_PropGrid_Show, PropViewFrame::OnSettingsPropGrid_Show)
	EVT_MENU(miSettings_PropGrid_DisplayPropIndicesAsHex, PropViewFrame::OnSettingsPropGrid_DisplayPropIndicesAsHex)
	EVT_MENU(miSettings_PropGrid_StandardView, PropViewFrame::OnSettingsPropGrid_StandardView)
	EVT_MENU(miSettings_PropGrid_DevelopersView, PropViewFrame::OnSettingsPropGrid_DevelopersView)
	EVT_COMMAND_SCROLL_THUMBTRACK(widSLRecordDisplay, PropViewFrame::OnSLRecordDisplay)
	EVT_SIZE(PropViewFrame::OnSize)
	EVT_TIMER(wxID_ANY, PropViewFrame::OnTimer)
	EVT_BUTTON(widBtnAbort, PropViewFrame::OnBtnAbort)
	EVT_BUTTON(widBtnLive, PropViewFrame::OnBtnLive)
	EVT_BUTTON(widBtnUseDevice, PropViewFrame::OnUseDevice)
	EVT_BUTTON(widBtnSnap, PropViewFrame::OnBtnSnap)
	EVT_COMMAND(widMainFrame, imageReadyEvent, PropViewFrame::OnImageReady)
	EVT_COMMAND(widMainFrame, sequenceReadyEvent, PropViewFrame::OnSequenceReady)
	EVT_COMMAND(widMainFrame, imageSkippedEvent, PropViewFrame::OnImageSkipped)
	EVT_COMMAND(widMainFrame, toggleDisplayArea, PropViewFrame::OnToggleDisplayWindowSize)
	EVT_COMMAND(widMainFrame, liveModeAborted, PropViewFrame::OnLiveModeAborted)
	EVT_COMMAND(widMainFrame, eventNotified, PropViewFrame::OnEventNotified)
	EVT_COMMAND(widMainFrame, imageInfoEvent, PropViewFrame::OnImageInfo)
	EVT_COMMAND(widMainFrame, refreshAOIControls, PropViewFrame::OnRefreshAOIControls)
	EVT_COMMAND(widMainFrame, refreshCurrentPixelData, PropViewFrame::OnRefreshCurrentPixelData)
	EVT_PG_CHANGED(widPropGrid, PropViewFrame::OnPropertyChanged)
	EVT_PG_RIGHT_CLICK(widPropGrid, PropViewFrame::OnPropertyRightClicked)
	EVT_NOTEBOOK_PAGE_CHANGED(widNotebook, PropViewFrame::OnNotebookPageChanged)
	EVT_TEXT(widDevCombo, PropViewFrame::OnDevComboTextChanged)
	EVT_TEXT(widInfoPlot_PlotSelectionCombo, PropViewFrame::OnInfoPlot_PlotSelectionComboTextChanged)
	EVT_CLOSE(PropViewFrame::OnClose)
	EVT_SPLITTER_SASH_POS_CHANGED(widHorSplitter, PropViewFrame::OnSplitterSashPosChanged)
	EVT_SPLITTER_SASH_POS_CHANGED(widVerSplitter, PropViewFrame::OnSplitterSashPosChanged)
	EVT_CHECKBOX(widPixelHistogram | iapidCBAOIFullMode, PropViewFrame::OnAnalysisPlotCBAOIFullMode)
	EVT_CHECKBOX(widNoiseHistogram | iapidCBAOIFullMode, PropViewFrame::OnAnalysisPlotCBAOIFullMode)
	EVT_CHECKBOX(widLineProfile | iapidCBAOIFullMode, PropViewFrame::OnAnalysisPlotCBAOIFullMode)
	EVT_CHECKBOX(widVectorScope | iapidCBAOIFullMode, PropViewFrame::OnAnalysisPlotCBAOIFullMode)
	EVT_CHECKBOX(widCBEnableInfoPlot, PropViewFrame::OnCBEnableInfoPlot)
	EVT_SPINCTRL(widPixelHistogram | iapidSCAOIx, PropViewFrame::OnAnalysisPlotAOIxChanged)
	EVT_SPINCTRL(widNoiseHistogram | iapidSCAOIx, PropViewFrame::OnAnalysisPlotAOIxChanged)
	EVT_SPINCTRL(widLineProfile | iapidSCAOIx, PropViewFrame::OnAnalysisPlotAOIxChanged)
	EVT_SPINCTRL(widVectorScope | iapidSCAOIx, PropViewFrame::OnAnalysisPlotAOIxChanged)
	EVT_SPINCTRL(widPixelHistogram | iapidSCAOIy, PropViewFrame::OnAnalysisPlotAOIyChanged)
	EVT_SPINCTRL(widNoiseHistogram | iapidSCAOIy, PropViewFrame::OnAnalysisPlotAOIyChanged)
	EVT_SPINCTRL(widLineProfile | iapidSCAOIy, PropViewFrame::OnAnalysisPlotAOIyChanged)
	EVT_SPINCTRL(widVectorScope | iapidSCAOIy, PropViewFrame::OnAnalysisPlotAOIyChanged)
	EVT_SPINCTRL(widPixelHistogram | iapidSCAOIw, PropViewFrame::OnAnalysisPlotAOIwChanged)
	EVT_SPINCTRL(widNoiseHistogram | iapidSCAOIw, PropViewFrame::OnAnalysisPlotAOIwChanged)
	EVT_SPINCTRL(widLineProfile | iapidSCAOIw, PropViewFrame::OnAnalysisPlotAOIwChanged)
	EVT_SPINCTRL(widVectorScope | iapidSCAOIw, PropViewFrame::OnAnalysisPlotAOIwChanged)
	EVT_SPINCTRL(widPixelHistogram | iapidSCAOIh, PropViewFrame::OnAnalysisPlotAOIhChanged)
	EVT_SPINCTRL(widNoiseHistogram | iapidSCAOIh, PropViewFrame::OnAnalysisPlotAOIhChanged)
	EVT_SPINCTRL(widLineProfile | iapidSCAOIh, PropViewFrame::OnAnalysisPlotAOIhChanged)
	EVT_SPINCTRL(widVectorScope | iapidSCAOIh, PropViewFrame::OnAnalysisPlotAOIhChanged)
	EVT_SPINCTRL(widPixelHistogram | iapidSCDrawStart_percent, PropViewFrame::OnAnalysisPlotDrawStartChanged)
	EVT_SPINCTRL(widNoiseHistogram | iapidSCDrawStart_percent, PropViewFrame::OnAnalysisPlotDrawStartChanged)
	EVT_SPINCTRL(widLineProfile | iapidSCDrawStart_percent, PropViewFrame::OnAnalysisPlotDrawStartChanged)
	EVT_SPINCTRL(widPixelHistogram | iapidSCDrawWindow_percent, PropViewFrame::OnAnalysisPlotDrawWindowChanged)
	EVT_SPINCTRL(widNoiseHistogram | iapidSCDrawWindow_percent, PropViewFrame::OnAnalysisPlotDrawWindowChanged)
	EVT_SPINCTRL(widLineProfile | iapidSCDrawWindow_percent, PropViewFrame::OnAnalysisPlotDrawWindowChanged)
	EVT_SPINCTRL(widPixelHistogram | iapidSCDrawStepWidth, PropViewFrame::OnAnalysisPlotDrawStepWidthChanged)
	EVT_SPINCTRL(widNoiseHistogram | iapidSCDrawStepWidth, PropViewFrame::OnAnalysisPlotDrawStepWidthChanged)
	EVT_SPINCTRL(widVectorScope | iapidSCGridStepsX, PropViewFrame::OnAnalysisPlotGridXStepsChanged)
	EVT_SPINCTRL(widVectorScope | iapidSCGridStepsY, PropViewFrame::OnAnalysisPlotGridYStepsChanged)
	EVT_SPINCTRL(widPixelHistogram | iapidSCUpdateSpeed, PropViewFrame::OnAnalysisPlotUpdateSpeedChanged)
	EVT_SPINCTRL(widNoiseHistogram | iapidSCUpdateSpeed, PropViewFrame::OnAnalysisPlotUpdateSpeedChanged)
	EVT_SPINCTRL(widLineProfile | iapidSCUpdateSpeed, PropViewFrame::OnAnalysisPlotUpdateSpeedChanged)
	EVT_SPINCTRL(widVectorScope | iapidSCUpdateSpeed, PropViewFrame::OnAnalysisPlotUpdateSpeedChanged)
	EVT_SPINCTRL(widSCInfoPlotHistoryDepth, PropViewFrame::OnInfoPlotUpdateHistoryDepthChanged)
	EVT_SPINCTRL(widSCInfoPlotUpdateSpeed, PropViewFrame::OnInfoPlotUpdateSpeedChanged)
#ifdef BUILD_WITH_TEXT_EVENTS_FOR_SPINCTRL // BAT: Unfortunately on linux wxWidgets 2.6.x - ??? handling these messages will cause problems, while on Windows not doing so will not always update the GUI as desired :-(
	EVT_TEXT(widPixelHistogram | iapidSCAOIx, PropViewFrame::OnAnalysisPlotAOIxTextChanged)
	EVT_TEXT(widNoiseHistogram | iapidSCAOIx, PropViewFrame::OnAnalysisPlotAOIxTextChanged)
	EVT_TEXT(widLineProfile | iapidSCAOIx, PropViewFrame::OnAnalysisPlotAOIxTextChanged)
	EVT_TEXT(widVectorScope | iapidSCAOIx, PropViewFrame::OnAnalysisPlotAOIxTextChanged)
	EVT_TEXT(widPixelHistogram | iapidSCAOIy, PropViewFrame::OnAnalysisPlotAOIyTextChanged)
	EVT_TEXT(widNoiseHistogram | iapidSCAOIy, PropViewFrame::OnAnalysisPlotAOIyTextChanged)
	EVT_TEXT(widLineProfile | iapidSCAOIy, PropViewFrame::OnAnalysisPlotAOIyTextChanged)
	EVT_TEXT(widVectorScope | iapidSCAOIy, PropViewFrame::OnAnalysisPlotAOIyTextChanged)
	EVT_TEXT(widPixelHistogram | iapidSCAOIw, PropViewFrame::OnAnalysisPlotAOIwTextChanged)
	EVT_TEXT(widNoiseHistogram | iapidSCAOIw, PropViewFrame::OnAnalysisPlotAOIwTextChanged)
	EVT_TEXT(widLineProfile | iapidSCAOIw, PropViewFrame::OnAnalysisPlotAOIwTextChanged)
	EVT_TEXT(widVectorScope | iapidSCAOIw, PropViewFrame::OnAnalysisPlotAOIwTextChanged)
	EVT_TEXT(widPixelHistogram | iapidSCAOIh, PropViewFrame::OnAnalysisPlotAOIhTextChanged)
	EVT_TEXT(widNoiseHistogram | iapidSCAOIh, PropViewFrame::OnAnalysisPlotAOIhTextChanged)
	EVT_TEXT(widLineProfile | iapidSCAOIh, PropViewFrame::OnAnalysisPlotAOIhTextChanged)
	EVT_TEXT(widVectorScope | iapidSCAOIh, PropViewFrame::OnAnalysisPlotAOIhTextChanged)
	EVT_TEXT(widPixelHistogram | iapidSCDrawStart_percent, PropViewFrame::OnAnalysisPlotDrawStartTextChanged)
	EVT_TEXT(widNoiseHistogram | iapidSCDrawStart_percent, PropViewFrame::OnAnalysisPlotDrawStartTextChanged)
	EVT_TEXT(widLineProfile | iapidSCDrawStart_percent, PropViewFrame::OnAnalysisPlotDrawStartTextChanged)
	EVT_TEXT(widPixelHistogram | iapidSCDrawWindow_percent, PropViewFrame::OnAnalysisPlotDrawWindowTextChanged)
	EVT_TEXT(widNoiseHistogram | iapidSCDrawWindow_percent, PropViewFrame::OnAnalysisPlotDrawWindowTextChanged)
	EVT_TEXT(widLineProfile | iapidSCDrawWindow_percent, PropViewFrame::OnAnalysisPlotDrawWindowTextChanged)
	EVT_TEXT(widPixelHistogram | iapidSCDrawStepWidth, PropViewFrame::OnAnalysisPlotDrawStepWidthTextChanged)
	EVT_TEXT(widNoiseHistogram | iapidSCDrawStepWidth, PropViewFrame::OnAnalysisPlotDrawStepWidthTextChanged)
	EVT_TEXT(widVectorScope | iapidSCGridStepsX, PropViewFrame::OnAnalysisPlotGridXStepsTextChanged)
	EVT_TEXT(widVectorScope | iapidSCGridStepsY, PropViewFrame::OnAnalysisPlotGridYStepsTextChanged)
	EVT_TEXT(widPixelHistogram | iapidSCUpdateSpeed, PropViewFrame::OnAnalysisPlotUpdateSpeedTextChanged)
	EVT_TEXT(widNoiseHistogram | iapidSCUpdateSpeed, PropViewFrame::OnAnalysisPlotUpdateSpeedTextChanged)
	EVT_TEXT(widLineProfile | iapidSCUpdateSpeed, PropViewFrame::OnAnalysisPlotUpdateSpeedTextChanged)
	EVT_TEXT(widVectorScope | iapidSCUpdateSpeed, PropViewFrame::OnAnalysisPlotUpdateSpeedTextChanged)
	EVT_TEXT(widSCInfoPlotHistoryDepth, PropViewFrame::OnInfoPlotUpdateHistoryDepthTextChanged)
	EVT_TEXT(widSCInfoPlotUpdateSpeed, PropViewFrame::OnInfoPlotUpdateSpeedTextChanged)
#endif
	EVT_NOTEBOOK_PAGE_CHANGED(widPixelHistogram | iapidNBDisplayMethod, PropViewFrame::OnNBDisplayMethodPageChanged)
	EVT_NOTEBOOK_PAGE_CHANGED(widNoiseHistogram | iapidNBDisplayMethod, PropViewFrame::OnNBDisplayMethodPageChanged)
	EVT_NOTEBOOK_PAGE_CHANGED(widLineProfile | iapidNBDisplayMethod, PropViewFrame::OnNBDisplayMethodPageChanged)
	EVT_NOTEBOOK_PAGE_CHANGED(widVectorScope | iapidNBDisplayMethod, PropViewFrame::OnNBDisplayMethodPageChanged)
END_EVENT_TABLE()

//-----------------------------------------------------------------------------
PropViewFrame::PropViewFrame( const wxString& title, const wxPoint& pos, const wxSize& size, int argc, wxChar** argv )
: wxFrame(0, widMainFrame, title, pos, size), m_boCloseDeviceInProgress(false), m_boDisplayWindowMaximized(false), m_boShutdownInProgress(false),
   m_boUpdateAOIInProgress(false), m_boCurrentImageIsFromFile(false), m_CurrentImageAnalysisControlIndex(-1),
   m_DeviceListChangedCounter(numeric_limits<unsigned int>::max()),
   m_NoDevStr(wxT("no device")), m_pDevPropHandler(0), m_pDisplayArea(0), m_pLogWindow(0), m_pPropGrid(0)
//-----------------------------------------------------------------------------
{
	// create the menu
	/* Keyboard shortcuts:
			CTRL+A : imageRequestReset
		ALT+CTRL+A : Analysis tab on/off
			CTRL+B : Blit on/off
		ALT+CTRL+B : Backward in captured sequence
		ALT+CTRL+D : Show connected devices only on/off
			CTRL+F : Fit to screen mode on/off
		ALT+CTRL+F : Forward in captured sequence
		ALT+CTRL+H : Array property indices will be displayed as HEX on/off
			CTRL+I : Single snap
		ALT+CTRL+I : Display incomplete image on/off
			CTRL+L : Live
		ALT+CTRL+M : Messages as overlay on/off
			CTRL+O : Load device settings from default location
		ALT+CTRL+O : Load device settings from file
		ALT+CTRL+P : Property grid on/off
			CTRL+R : Record mode on/off
		ALT+CTRL+R : Request info as overlay on/off
			CTRL+S : Save active device settings to default location
		ALT+CTRL+S : Save to file
			CTRL+T : Show tool bar on/off
		ALT+CTRL+T : Show status bar on/off
			CTRL+U : Open/Close Device
		ALT+CTRL+U : Update device list
			CTRL+Q : Set capture queue depth
		ALT+     X : Exit
	*/

	// sub menu 'Action -> Settings -> Save'
	wxMenu* pMenuActionSettingsSave = new wxMenu;
	m_pMIAction_Settings_Save_ToDefault = pMenuActionSettingsSave->Append( miAction_Settings_Save_ToDefault, wxT("Device Settings To Default(user specific, for this product family)") );
	m_pMIAction_Settings_Save_SystemToDefault = pMenuActionSettingsSave->Append( miAction_Settings_Save_SystemToDefault, wxT("System Settings To Default(user specific, for this product family)") );
	m_pMIAction_Settings_Save_CurrentProduct = pMenuActionSettingsSave->Append( miAction_Settings_Save_CurrentProduct, wxT("Current Product Settings") );
	m_pMIAction_Settings_Save_ActiveDevice = pMenuActionSettingsSave->Append( miAction_Settings_Save_ActiveDevice, wxT("Active Device Settings\tCTRL+S") );
	m_pMIAction_Settings_Save_ExportActiveDevice = pMenuActionSettingsSave->Append( miAction_Settings_Save_ExportActiveDevice, wxT("Active Device Settings To File\tALT+CTRL+S"), wxT("Stores the current settings for this device in a platform independent XML file") );

	// sub menu 'Action -> Settings -> Load'
	wxMenu* pMenuActionSettingsLoad = new wxMenu;
	m_pMIAction_Settings_Load_FromDefault = pMenuActionSettingsLoad->Append( miAction_Settings_Load_FromDefault, wxT("Default(user specific, for this product family)") );
	m_pMIAction_Settings_Load_CurrentProduct = pMenuActionSettingsLoad->Append( miAction_Settings_Load_CurrentProduct, wxT("Current Product Settings") );
	m_pMIAction_Settings_Load_ActiveDevice = pMenuActionSettingsLoad->Append( miAction_Settings_Load_ActiveDevice, wxT("Active Device Settings\tCTRL+O") );
	m_pMIAction_Settings_Load_ImportActiveDevice = pMenuActionSettingsLoad->Append( miAction_Settings_Load_ImportActiveDevice, wxT("Active Device Settings From File\tALT+CTRL+O"), wxT("Tries to loads settings for this device from a platform independent XML file") );

	// sub menu 'Action -> Settings'
	wxMenu* pMenuActionSettings = new wxMenu;
	pMenuActionSettings->Append( wxID_ANY, wxT("Save..."), pMenuActionSettingsSave );
	pMenuActionSettings->Append( wxID_ANY, wxT("Load..."), pMenuActionSettingsLoad );
	m_pMIAction_Settings_Manage = pMenuActionSettings->Append( miAction_Settings_Manage, wxT("Manage..." ) );

	// menu 'Action'
	wxMenu* pMenuAction = new wxMenu;
	m_pMIAction_Use = pMenuAction->Append( miAction_UseDevice, wxT("&Use Device\tCTRL+U"), wxT("Opens or closes the selected device"), wxITEM_CHECK );
	pMenuAction->Append( wxID_ANY, wxT("Settings..."), pMenuActionSettings );
	pMenuAction->AppendSeparator();
	m_pMIAction_LoadImage = pMenuAction->Append( miAction_LoadImage, wxT("Load Image...") );
	m_pMIAction_SaveImage = pMenuAction->Append( miAction_SaveImage, wxT("Save Image...") );
	m_pMIAction_SaveImageSequence = pMenuAction->Append( miAction_SaveImageSequence, wxT("Save All Recorded Images...") );
	pMenuAction->AppendSeparator();
	m_pMIAction_UpdateDeviceList = pMenuAction->Append( miAction_UpdateDeviceList, wxT("&Update Device List\tALT+CTRL+U") );
	pMenuAction->AppendSeparator();
	pMenuAction->Append( miQuit, wxT("E&xit\tALT+X") );

	// menu 'Capture'
	wxMenu* pMenuCapture = new wxMenu;
	m_pMICapture_Live = pMenuCapture->Append( miCapture_Live, wxT("&Live\tCTRL+L"), wxT("Starts or stops a continuous acquisition"), wxITEM_CHECK );
	m_pMICapture_Snap = pMenuCapture->Append( miCapture_Snap, wxT("S&ingle Snap\tCTRL+I"), wxT("Captures a single image from the selected device") );
	m_pMICapture_Abort = pMenuCapture->Append( miCapture_Abort, wxT("&Abort\tCTRL+A"), wxT("Clears the request queue, but does NOT stop a running continuous acquisition") );
	m_pMICapture_Record = pMenuCapture->Append( miCapture_Record, wxT("&Record\tCTRL+R"), wxT("Records the next 'RequestCount'(System Settings) images"), wxITEM_CHECK  );
	m_pMICapture_Forward = pMenuCapture->Append( miCapture_Forward, wxT("&Forward\tALT+CTRL+F"), wxT("Displays the next recorded image") );
	m_pMICapture_Backward = pMenuCapture->Append( miCapture_Backward, wxT("&Backward\tALT+CTRL+B"), wxT("Displays the previous recorded image") );
	m_pMICapture_SetupCaptureQueueDepth = pMenuCapture->Append( miCapture_SetupCaptureQueueDepth, wxT("Setup Capture Queue Depth\tCTRL+Q"), wxT("Sets the number of buffers that will be used to prefill the capture queue") );

	// sub menu 'Settings -> Property grid'
	wxMenu* pMenuSettingsPropertyGrid = new wxMenu;
	m_pMISettings_PropGrid_Show = pMenuSettingsPropertyGrid->Append( miSettings_PropGrid_Show, wxT("Show &Property Grid\tALT+CTRL+P"), wxT(""), wxITEM_CHECK );
	m_pMISettings_PropGrid_DisplayPropIndicesAsHex = pMenuSettingsPropertyGrid->Append( miSettings_PropGrid_DisplayPropIndicesAsHex, wxT("Display Property Indices As &Hex\tALT+CTRL+H"), wxT(""), wxITEM_CHECK );
	pMenuSettingsPropertyGrid->AppendSeparator();
	m_pMISettings_PropGrid_StandardView = pMenuSettingsPropertyGrid->Append( miSettings_PropGrid_StandardView, wxT("Standard View"), wxT(""), wxITEM_RADIO );
	m_pMISettings_PropGrid_DevelopersView = pMenuSettingsPropertyGrid->Append( miSettings_PropGrid_DevelopersView, wxT("Developers View"), wxT(""), wxITEM_RADIO );

	// sub menu 'Settings -> Display'
	wxMenu* pMenuSettingsDisplay = new wxMenu;
	m_pMISettings_Display_Active = pMenuSettingsDisplay->Append( miSettings_Display_Active, wxT("&Blit Active\tCTRL+B"), wxT("If not active images will be captured, but will NOT displayed"), wxITEM_CHECK );
	m_pMISettings_Display_FitToScreen = pMenuSettingsDisplay->Append( miSettings_Display_FitToScreen, wxT("&Fit To Screen\tCTRL+F"), wxT("If active the captured image will be scaled to fit into the main display area(slower)"), wxITEM_CHECK );
	m_pMISettings_Display_ShowMessagesAsOverlay = pMenuSettingsDisplay->Append( miSettings_Display_ShowOverlayMessages, wxT("&Message Overlay\tALT+CTRL+M"), wxT("If active the various informations will be blitted on top of the image in the main display area to inform e.g. about possible performance losses"), wxITEM_CHECK );
	m_pMISettings_Display_ShowRequestInfoAsOverlay = pMenuSettingsDisplay->Append( miSettings_Display_ShowRequestInfoAsOverlay, wxT("&Request Info Overlay\tALT+CTRL+R"), wxT("If active the various informations returned together with the image will be displayed as an overlay in the main display area(This will cost some additional CPU time)"), wxITEM_CHECK );
	m_pMISettings_Display_ShowIncompleteFrames = pMenuSettingsDisplay->Append( miSettings_Display_ShowIncompleteFrames, wxT("Show &Incomplete Frames\tALT+CTRL+I"), wxT("If active incomplete frames are displayed as well"), wxITEM_CHECK );
	pMenuSettingsDisplay->AppendSeparator();
	m_pMISettings_Display_ShowMonitorImage = pMenuSettingsDisplay->Append( miSettings_Display_ShowMonitorImage, wxT("Show Monitor Image"), wxT("") , wxITEM_CHECK );

	// sub menu 'Settings -> Analysis'
	wxMenu* pMenuSettingsAnalysis = new wxMenu;
	m_pMISettings_Analysis_ShowControls = pMenuSettingsAnalysis->Append( miSettings_Analysis_ShowControls, wxT("Show &Analysis Tabs\tALT+CTRL+A"), wxT(""), wxITEM_CHECK );
	m_pMISettings_Analysis_SynchroniseAOIs = pMenuSettingsAnalysis->Append( wxID_ANY, wxT("Synchronise AOIs"), wxT(""), wxITEM_CHECK );

	// sub menu 'Settings -> Recording'
	wxMenu* pMenuSettingsRecording = new wxMenu;
	m_pMISettings_Recording_SlientMode = pMenuSettingsRecording->AppendCheckItem( miSettings_Recording_SilentMode, wxT("Silent Mode"), wxT("Check this to disable all recording related dialogs") );
	m_pMISettings_Recording_Continuous = pMenuSettingsRecording->AppendCheckItem( miSettings_Recording_Continuous, wxT("Continuous"), wxT("Check this to enable continuous recording") );
	m_pMISettings_Recording_SetupSequenceSize = pMenuSettingsRecording->Append( miSettings_Recording_SetupSequenceSize, wxT("Setup Sequence Size"), wxT("Sets the number of buffers that will be recorded during a recording session that stops automatically") );

	// menu 'Settings'
	wxMenu* pMenuSettings = new wxMenu;
	pMenuSettings->Append( wxID_ANY, wxT("Property Grid..."), pMenuSettingsPropertyGrid );
	pMenuSettings->Append( wxID_ANY, wxT("Image Display..."), pMenuSettingsDisplay );
	pMenuSettings->Append( wxID_ANY, wxT("Analysis..."), pMenuSettingsAnalysis );
	m_pMISettings_ShowToolBar = pMenuSettings->Append( miSettings_ShowToolBar, wxT("Show &Tool Bar\tCTRL+T"), wxT(""), wxITEM_CHECK );
	m_pMISettings_ShowStatusBar = pMenuSettings->Append( miSettings_ShowStatusBar, wxT("Show S&tatus Bar\tALT+CTRL+T"), wxT(""), wxITEM_CHECK );
	pMenuSettings->AppendSeparator();
	m_pMISettings_ShowConnectedOnly = pMenuSettings->Append( miSettings_ShowConnectedDevicesOnly, wxT("Display &Connected Devices Only\tALT+CTRL+D"), wxT(""), wxITEM_CHECK );
	pMenuSettings->Append( wxID_ANY, wxT("&Recording..."), pMenuSettingsRecording );

	// menu 'About'
	wxMenu* pMenuAbout = new wxMenu;
	pMenuAbout->Append( miHelp_About, wxT("&About"));

	// add all menus to the menu bar
	wxMenuBar* pMenuBar = new wxMenuBar;
	pMenuBar->Append( pMenuAction, wxT("&Action") );
	pMenuBar->Append( pMenuCapture, wxT("&Capture") );
	pMenuBar->Append( pMenuSettings, wxT("&Settings") );
	pMenuBar->Append( pMenuAbout, wxT("&Help") );
	// ... and attach this menu bar to the frame
	SetMenuBar(pMenuBar);

	// define the applications icon
	wxIcon icon(mvIcon_xpm);
	SetIcon( icon );

	// create all GUI elements
	/*
		|-------------------|
		|buttons            |
		|-------------------|
		|prop-  | display   |
		|grid   |           |
		|       |           |
		|       |-----------|
		|       | output    |
		|       |           |
		|-------------------|
	*/
	wxBoxSizer* pTopDownSizer = new wxBoxSizer(wxVERTICAL);
	m_pPanel = new wxPanel(this);

	// the toolbar
	m_pToolBar = CreateToolBar( wxNO_BORDER | wxHORIZONTAL | wxTB_FLAT | wxTB_TEXT );
	m_pToolBar->SetMargins( 5, 5 );
	m_pToolBar->SetToolBitmapSize( wxSize(32, 16) );
	m_pToolBar->SetToolSeparation( 10 );

	wxStaticText *pStaticText = new wxStaticText(m_pToolBar, -1, wxT(" Serial No. "));
	m_pToolBar->AddControl( pStaticText );
	m_pDevCombo = new wxComboBox(m_pToolBar, widDevCombo, wxT(" Serial "), wxDefaultPosition, wxSize(120,wxDefaultCoord), 0, NULL, wxCB_DROPDOWN | wxCB_READONLY);
	m_pDevCombo->Select(0);
	m_pDevCombo->SetToolTip( wxT("Contains a list of serial numbers of every device detected. If devices seem to miss make sure these are connected AND a driver for the corresponding device family has been installed") );
	m_pToolBar->AddControl( m_pDevCombo );

	pStaticText = new wxStaticText(m_pToolBar, -1, wxT("  "));
	m_pToolBar->AddControl( pStaticText );
	m_pToolBar->AddTool( miAction_UseDevice, wxT("Use"), Use_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("Opens or closes the selected device"),
		wxT("Opens or closes the selected device") );
	m_pToolBar->AddSeparator();
	m_pToolBar->AddTool( miCapture_Live, wxT("Live"), live_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("Starts or stops continuous acquisition from the selected device"),
		wxT("Starts or stops continuous acquisition from the selected device") );
	m_pToolBar->AddTool( miCapture_Snap, wxT("Snap"), photo_xpm, wxNullBitmap, wxITEM_NORMAL,
		wxT("Captures a single image from the selected device"),
		wxT("Captures a single image from the selected device") );
	m_pToolBar->AddTool( miCapture_Abort, wxT("Abort"), abort_xpm, wxNullBitmap, wxITEM_NORMAL,
		wxT("Empties the image request queue for the selected device but does NOT stop a running continuous acquisition"),
		wxT("Empties the image request queue for the selected device but does NOT stop a running continuous acquisition") );
	m_pToolBar->AddSeparator();
	m_pToolBar->AddTool( miCapture_Record, wxT("Rec."), record_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("Records the next 'RequestCount'(System Settings) images"),
		wxT("Records the next 'RequestCount'(System Settings) images") );
	m_pToolBar->AddTool( miCapture_Backward, wxT("Prev."), back_xpm, wxNullBitmap, wxITEM_NORMAL,
		wxT("Displays the previous recorded image"),
		wxT("Displays the previous recorded image") );
	m_pToolBar->AddTool( miCapture_Forward, wxT("Next"), forward_xpm, wxNullBitmap, wxITEM_NORMAL,
		wxT("Displays the next recorded image"),
		wxT("Displays the next recorded image") );
	m_pRecordDisplaySlider = new wxSlider(m_pToolBar, widSLRecordDisplay, 0, 0, 1000, wxDefaultPosition, wxSize(150, -1), wxSL_HORIZONTAL | wxSL_LABELS);
	m_pRecordDisplaySlider->SetToolTip( wxT("Can be used to quickly move within a recorded sequence of images") );
	m_pToolBar->AddControl( m_pRecordDisplaySlider );
	m_pToolBar->AddSeparator();
	m_pToolBar->AddTool( miSettings_Display_Active, wxT("Blit"), DisplayActive_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("Turns the main display on or off"),
		wxT("Turns the main display on or off") );
	m_pToolBar->AddTool( miSettings_Display_FitToScreen, wxT("Fit"), Scale_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("If active the captured image will be scaled to fit into the main display area(needs additional CPU time)"),
		wxT("If active the captured image will be scaled to fit into the main display area(needs additional CPU time)") );
	m_pToolBar->AddTool( miSettings_Display_ShowOverlayMessages, wxT("Msg."), DisplayMessages_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("Turns display messages on top of the main display on or off"),
		wxT("Turns display messages on top of the main display on or off") );
	m_pToolBar->AddTool( miSettings_Display_ShowRequestInfoAsOverlay, wxT("Info"), DisplayMessages_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("Turns request info overlay messages on top of the main display on or off"),
		wxT("If active the various informations returned together with the image will be displayed as an overlay on top of the main display(This will cost some additional CPU time)") );
	m_pToolBar->AddSeparator();
	m_pToolBar->AddTool( miSettings_Display_ShowMonitorImage, wxT("Blit"), DisplayActive_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("Displays or hides the scaled image to monitor the visible part of the main display(NOTE: This feature can only be used when the main display is active!)"),
		wxT("Displays or hides the scaled image to monitor the visible part of the main display(NOTE: This feature can only be used when the main display is active!)") );
	m_pToolBar->AddSeparator();
	m_pToolBar->AddTool( miSettings_Analysis_ShowControls, wxT("Analysis"), LogWindow_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("Displays or hides the analysis tabs"),
		wxT("Displays or hides the analysis tabs") );
	m_pToolBar->AddTool( miSettings_PropGrid_Show, wxT("Grid"), PropertyGrid_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("Displays or hides the device property grid"),
		wxT("Displays or hides the device property grid") );
	m_pToolBar->AddSeparator();
	m_pToolBar->AddTool( miHelp_About, wxT("About"), help_xpm, wxNullBitmap, wxITEM_NORMAL,
		wxT("Displays the about dialog"),
		wxT("Displays the about dialog") );
	m_pToolBar->Realize();

	// splitter for property grid and the windows on the right
	m_pVerticalSplitter = new wxSplitterWindow(m_pPanel, widVerSplitter, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);

	// property grid on the left
	m_pPropGrid = new wxPropertyGrid(m_pVerticalSplitter, widPropGrid, wxDefaultPosition, wxDefaultSize, wxPG_SPLITTER_AUTO_CENTER | wxPG_TOOLTIPS | wxTAB_TRAVERSAL | wxSUNKEN_BORDER);
	m_pPropGrid->SetExtraStyle( wxPG_EX_MODE_BUTTONS );
	m_pPropGrid->SetExtraStyle( wxPG_EX_HELP_AS_TOOLTIPS );
	//m_pPropGrid->SetExtraStyle( wxPG_EX_GREY_LABEL_WHEN_DISABLED ); // this will display lists as disabled as well...
#if wxPROPGRID_MINOR < 3
	m_pPropGrid->Compact( true );
#endif
	m_pPropGrid->SetLineColour( wxColour(128, 128, 128) );

	// splitter between the image display window and the notebook window in the lower right corner of the window
	m_pHorizontalSplitter = new wxSplitterWindow(m_pVerticalSplitter, widHorSplitter, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);

	// the window for displaying the images
	m_pDisplayArea = new ImageCanvas(this, m_pHorizontalSplitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_SUNKEN | wxHSCROLL | wxVSCROLL, wxEmptyString);
	m_pDisplayArea->EnableScrolling( true, true );
	m_pDisplayArea->SetDropTarget( new DnDFile(this) ); // this will allow to drop image files into the display area
	// A separate window that displays the full, scaled image with an AOI on top showing the part of the image currently visible in the main display window
	m_pMonitorImage = new MonitorDisplay(this);

	// the window for the controls in the lower right corner of the application
	m_pLowerRightWindow = new wxNotebook(m_pHorizontalSplitter, widNotebook, wxDefaultPosition, wxDefaultSize);

	// log window (page of lower right notebook)
	m_pLogWindow = new wxTextCtrl(m_pLowerRightWindow, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxSUNKEN_BORDER | wxTE_RICH | wxTE_READONLY);
	m_pLowerRightWindow->AddPage( m_pLogWindow, wxT("Output"), true );
	
	wxScrolledWindow* pAnalysisPanel = 0;
	pAnalysisPanel = CreateImageAnalysisPlotControls( m_pLowerRightWindow, widPixelHistogram );
	m_pLowerRightWindow->AddPage( pAnalysisPanel, m_ImageAnalysisPlots[GetAnalysisControlIndex( widPixelHistogram )].m_pPlotCanvas->GetName(), false );
	pAnalysisPanel = CreateImageAnalysisPlotControls( m_pLowerRightWindow, widNoiseHistogram );
	m_pLowerRightWindow->AddPage( pAnalysisPanel , m_ImageAnalysisPlots[GetAnalysisControlIndex( widNoiseHistogram )].m_pPlotCanvas->GetName(), false );
	pAnalysisPanel = CreateImageAnalysisPlotControls( m_pLowerRightWindow, widLineProfile );
	m_pLowerRightWindow->AddPage( pAnalysisPanel , m_ImageAnalysisPlots[GetAnalysisControlIndex( widLineProfile )].m_pPlotCanvas->GetName(), false );
	pAnalysisPanel = CreateImageAnalysisPlotControls( m_pLowerRightWindow, widVectorScope );
	m_pLowerRightWindow->AddPage( pAnalysisPanel , m_ImageAnalysisPlots[GetAnalysisControlIndex( widVectorScope )].m_pPlotCanvas->GetName(), false );

	// info plot window (page of lower right notebook)
	wxPanel* pPanelInfoPlot = new wxPanel(m_pLowerRightWindow);
	wxBoxSizer* pInfoPlotPanelSizer = new wxBoxSizer(wxHORIZONTAL);
	wxBoxSizer* pInfoPlotControlsSizer = new wxBoxSizer(wxVERTICAL);
	m_pCBEnableInfoPlot = new wxCheckBox(pPanelInfoPlot, widCBEnableInfoPlot, wxT("Enable"));
	pInfoPlotControlsSizer->Add( m_pCBEnableInfoPlot, wxSizerFlags().Left() );
	pInfoPlotControlsSizer->AddSpacer( 5 );

	wxFlexGridSizer* pInfoPlotControlsGridSizer = new wxFlexGridSizer(2, 0);
	pInfoPlotControlsGridSizer->Add( new wxStaticText(pPanelInfoPlot, wxID_ANY, wxT("Update interval:")) );
	m_pSCInfoPlotUpdateSpeed = new wxSpinCtrl( pPanelInfoPlot, widSCInfoPlotUpdateSpeed, wxT("3"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, PlotCanvas::ulMin, PlotCanvas::ulMax, 3 );
	pInfoPlotControlsGridSizer->Add( m_pSCInfoPlotUpdateSpeed, wxSizerFlags().Left() );
	pInfoPlotControlsGridSizer->Add( new wxStaticText(pPanelInfoPlot, wxID_ANY, wxT("History depth:")) );
	m_pSCInfoPlotHistoryDepth = new wxSpinCtrl( pPanelInfoPlot, widSCInfoPlotHistoryDepth, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 5, 10000, 20 );
	pInfoPlotControlsGridSizer->Add( m_pSCInfoPlotHistoryDepth, wxSizerFlags().Left() );
	pInfoPlotControlsGridSizer->Add( new wxStaticText(pPanelInfoPlot, wxID_ANY, wxT("Plot selection:")) );
	m_pInfoPlotSelectionCombo = new wxComboBox(pPanelInfoPlot, widInfoPlot_PlotSelectionCombo, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN);
	pInfoPlotControlsGridSizer->Add( m_pInfoPlotSelectionCombo, wxSizerFlags().Left() );
	m_pInfoPlotSelectionCombo->Select(0);
	m_pInfoPlotSelectionCombo->SetToolTip( wxT("Contains a list of possible plots that can be displayed on this page") );
	wxStaticText* pSTTimestampAsTime = new wxStaticText(pPanelInfoPlot, wxID_ANY, wxT("Timestamp as time:"));
	pSTTimestampAsTime->SetToolTip( wxT("This is the device timestamp converted into local time. This value only makes sense for devices that create a timestamp in us since 01.01.1970") );
	pInfoPlotControlsGridSizer->Add( pSTTimestampAsTime );
	m_pTCTimestampAsTime = new wxTextCtrl(pPanelInfoPlot, wxID_ANY, wxT("00:00:00:000") );
	m_pTCTimestampAsTime->SetToolTip( wxT("This is the device timestamp converted into local time. This value only makes sense for devices that create a timestamp in us since 01.01.1970") );
	m_pTCTimestampAsTime->Enable( false );
	pInfoPlotControlsGridSizer->Add( m_pTCTimestampAsTime );

	pInfoPlotControlsSizer->Add( pInfoPlotControlsGridSizer );
	pInfoPlotPanelSizer->Add( pInfoPlotControlsSizer, wxSizerFlags().Left() );
	m_pInfoPlotArea = new InfoPlotCanvas( pPanelInfoPlot, wxID_ANY, wxDefaultPosition, wxDefaultSize );
	for( unsigned int i=0; i<InfoPlotCanvas::psLAST; i++ )
	{
		int item = m_pInfoPlotSelectionCombo->Append( m_pInfoPlotArea->GetPlotSelectionName( static_cast<InfoPlotCanvas::TPlotSelection>(i) ) );
		m_pInfoPlotSelectionCombo->SetClientData( item, reinterpret_cast<void*>(i) );
	}
	pInfoPlotPanelSizer->Add( m_pInfoPlotArea, wxSizerFlags(1).Expand() );
	pPanelInfoPlot->SetSizer( pInfoPlotPanelSizer );
	m_pLowerRightWindow->AddPage( pPanelInfoPlot, wxT("Info plot"), false );

	// configure splitters
	m_pHorizontalSplitter->SetMinimumPaneSize( 175 );
	m_pHorizontalSplitter->SetSashGravity( 0.9 );
	m_pVerticalSplitter->SetMinimumPaneSize( 50 );
	pTopDownSizer->Add( m_pVerticalSplitter, wxSizerFlags(6).Expand() );

	m_pStatusBar = new wxStatusBar(m_pPanel, widStatusBar);
	pTopDownSizer->Add( m_pStatusBar, wxSizerFlags().Expand() );
	m_pPanel->SetSizer( pTopDownSizer );
	pTopDownSizer->SetSizeHints( this );

	// restore previous state
	FramePositionStorage frameStorage(this, wxString(wxT("MainFrame")));
	wxRect defaultRect(0, 0, 1024, 700);
	wxRect rect = frameStorage.restore( defaultRect );
	wxConfigBase *pConfig = wxConfigBase::Get();
	m_VerticalSplitterPos = pConfig->Read( wxT("/MainFrame/verticalSplitter"), -1l );
	m_HorizontalSplitterPos = pConfig->Read( wxT("/MainFrame/horizontalSplitter"), -1l );

	bool boActive = pConfig->Read( wxT("/MainFrame/Settings/scaleDisplay"), 0l ) != 0;
	m_pMISettings_Display_FitToScreen->Check( boActive );
	m_pToolBar->ToggleTool( miSettings_Display_FitToScreen, boActive );
	m_pDisplayArea->SetScaling( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/monitorDisplay"), 0l ) != 0;
	m_pMISettings_Display_ShowMonitorImage->Check( boActive );
	m_pToolBar->ToggleTool( miSettings_Display_ShowMonitorImage, boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/overlayMessages"), 0l ) != 0;
	m_pMISettings_Display_ShowMessagesAsOverlay->Check( boActive );
	m_pDisplayArea->SetPerformanceWarningOutput( boActive );
	m_pToolBar->ToggleTool( miSettings_Display_ShowOverlayMessages, boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/requestInfoOverlay"), 0l ) != 0;
	m_pMISettings_Display_ShowRequestInfoAsOverlay->Check( boActive );
	m_pDisplayArea->SetInfoOverlayMode( boActive );
	m_pToolBar->ToggleTool( miSettings_Display_ShowRequestInfoAsOverlay, boActive );
	bool boLowerRightControlsActive = pConfig->Read( wxT("/MainFrame/Settings/displayLogWindow"), 0l ) != 0;
	bool boDisplayActive = pConfig->Read( wxT("/MainFrame/Settings/displayActive"), 1l ) != 0;
	// either the display or the controls MUST be active!
	m_pMISettings_Analysis_ShowControls->Check( boLowerRightControlsActive );
	m_pToolBar->ToggleTool( miSettings_Analysis_ShowControls, boLowerRightControlsActive );
	m_pMISettings_Display_Active->Check( boDisplayActive );
	m_pToolBar->ToggleTool( miSettings_Display_Active, boDisplayActive );
	m_pDisplayArea->SetActive( boDisplayActive );
	SetupDisplayLogSplitter( true ); // needed as otherwise the initial view might not be correct when display and propgrid are switched off!!!
	SetupDisplayLogSplitter();
	boActive = pConfig->Read( wxT("/MainFrame/Settings/displayIncompleteFrames"), 0l ) != 0;
	m_pMISettings_Display_ShowIncompleteFrames->Check( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/silentRecording"), 0l ) != 0;
	m_pMISettings_Recording_SlientMode->Check( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/continuousRecording"), 0l ) != 0;
	m_pMISettings_Recording_Continuous->Check( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/activeDevicesOnly"), 0l ) != 0;
	m_pMISettings_ShowConnectedOnly->Check( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/synchroniseAOIs"), 0l ) != 0;
	m_pMISettings_Analysis_SynchroniseAOIs->Check( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/displayPropGrid"), 1l ) != 0;
	m_pMISettings_PropGrid_Show->Check( boActive );
	m_pToolBar->ToggleTool( miSettings_PropGrid_Show, boActive );
	SetupVerSplitter( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/showToolBar"), 1l ) != 0;
	m_pMISettings_ShowToolBar->Check( boActive );
	ConfigureToolBar( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/showStatusBar"), 1l ) != 0;
	m_pMISettings_ShowStatusBar->Check( boActive );
	ConfigureStatusBar( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/displayPropsWithHexIndices"), 0l ) != 0;
	m_pMISettings_PropGrid_DisplayPropIndicesAsHex->Check( boActive );
	int selectedPage = pConfig->Read( wxT("/MainFrame/selectedPage"), -1l );
	if( selectedPage != -1 )
	{
		m_pLowerRightWindow->SetSelection( selectedPage );
		m_CurrentImageAnalysisControlIndex = GetAnalysisControlIndex();
		if( m_CurrentImageAnalysisControlIndex >= 0 )
		{
			m_pDisplayArea->SetActiveAnalysisPlot( m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pPlotCanvas );
			m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pPlotCanvas->SetActive( true );
		}
	}

	// previous view mode
	m_ViewMode = static_cast<DevicePropertyHandler::TViewMode>(pConfig->Read( wxT("/MainFrame/Settings/propGridViewMode"), DevicePropertyHandler::vmStandard ));

	// property grid
	double splitterratio;
	pConfig->Read( wxT("/PropGrid/splitterRatio"), &splitterratio, 0.5 );

	for( unsigned int i=0; i<iapLAST; i++ )
	{
		m_ImageAnalysisPlots[i].Load( pConfig );
	}

	// info plot
	bool boInfoPlotActive = pConfig->Read( wxT("/Controls/InfoPlot/Enable"), 0l ) != 0;
	m_pCBEnableInfoPlot->SetValue( boInfoPlotActive );
	m_pInfoPlotArea->SetActive( boInfoPlotActive );
	m_pSCInfoPlotHistoryDepth->SetValue( pConfig->Read( wxT("/Controls/InfoPlot/HistoryDepth"), 20l ) );
	m_pSCInfoPlotUpdateSpeed->SetValue( pConfig->Read( wxT("/Controls/InfoPlot/UpdateSpeed"), 3l ) );
	m_pInfoPlotSelectionCombo->Select( pConfig->Read( wxT("/Controls/InfoPlot/PlotSelection"), 0l ) );
	InfoPlotCanvas::TPlotSelection plotSelection = static_cast<InfoPlotCanvas::TPlotSelection>(wxPtrToUInt( m_pInfoPlotSelectionCombo->GetClientData( m_pInfoPlotSelectionCombo->GetSelection() ) ));
	m_pInfoPlotArea->SetPlotSelection( plotSelection );

	// scan command line
	bool boDisplayDebugInfo = false;
	bool boDisplayFullTree = false;
	bool boDisplayInvisibleComponents = false;
	bool boOpenDeviceInLiveMode = false;
	bool boShowEvents = false;
	wxString processedParameters;
	wxString serialToOpen;
	wxString fileToOpen;
	for( int i=1; i<argc; i++ )
	{
		wxString key, value;
		wxString param(argv[i]);
		key = param.BeforeFirst( wxT('=') );
		value = param.AfterFirst( wxT('=') );
		if( key.IsEmpty() )
		{
			WriteErrorMessage( wxString::Format( wxT("%s: Invalid command line parameter: '%s'.\n"), ConvertedString(__FUNCTION__).c_str(), param.c_str() ) );
		}
		else
		{
			if( value.IsEmpty() )
			{
				fileToOpen = param;
			}
			else
			{
				if( ( key == wxT("width") ) || ( key == wxT("w") ) )
				{
					rect.width = atoi( value.mb_str() );
				}
				else if( ( key == wxT("height") ) || ( key == wxT("h") ) )
				{
					rect.height = atoi( value.mb_str() );
				}
				else if( ( key == wxT("xpos") ) || ( key == wxT("x") ) )
				{
					rect.x = atoi( value.mb_str() );
				}
				else if( ( key == wxT("ypos") ) || ( key == wxT("y") ) )
				{
					rect.y = atoi( value.mb_str() );
				}
				else if( key == wxT("splitterratio") )
				{
					splitterratio = atof( value.mb_str() );
				}
				else if( ( key == wxT("propgridwidth") ) || ( key == wxT("pgw") ) )
				{
					m_VerticalSplitterPos = atoi( value.mb_str() );
				}
				else if( ( key == wxT("debuginfo") ) || ( key == wxT("di") ) )
				{
					boDisplayDebugInfo = ( atoi( value.mb_str() ) != 0 );
				}
				else if( ( key == wxT("dic") ) )
				{
					boDisplayInvisibleComponents = ( atoi( value.mb_str() ) != 0 );
				}
				else if( ( key == wxT("fulltree") ) || ( key == wxT("ft") ) )
				{
					boDisplayFullTree = ( atoi( value.mb_str() ) != 0 );
				}
				else if( ( key == wxT("device") ) || ( key == wxT("d") ) )
				{
					serialToOpen = value;
				}
				else if( key == wxT("live") )
				{
					boOpenDeviceInLiveMode = ( atoi( value.mb_str() ) != 0 );
				}
				else if( ( key == wxT("showEvents") ) || ( key == wxT("se") ) )
				{
					boShowEvents = ( atoi( value.mb_str() ) != 0 );
				}
				else
				{
					WriteErrorMessage( wxString::Format( wxT("%s: Invalid command line parameter: '%s'.\n"), ConvertedString(__FUNCTION__).c_str(), param.c_str() ) );
				}
			}
			processedParameters += param;
			processedParameters.Append( wxT(' ') );
		}
	}

	wxTextAttr boldStyle;
	m_pLogWindow->GetStyle( m_pLogWindow->GetLastPosition(), boldStyle );
	wxFont boldFont(boldStyle.GetFont());
	boldFont.SetWeight( wxFONTWEIGHT_BOLD );
	boldFont.SetPointSize( 10 );
	boldFont.SetUnderlined( true );
	boldStyle.SetFont( boldFont );
	WriteLogMessage( wxT("Available command line options:\n" ), boldStyle );
	WriteLogMessage( wxT("'width'         or 'w'   defines the startup width of the application\n") );
	WriteLogMessage( wxT("'height'        or 'h'   defines the startup height of the application\n") );
	WriteLogMessage( wxT("'xpos'          or 'x'   defines the startup x position of the application\n") );
	WriteLogMessage( wxT("'ypos'          or 'y'   defines the startup y position of the application\n") );
	WriteLogMessage( wxT("'splitterratio'          defines the startup ratio of the position of the property grids splitter\n") );
	WriteLogMessage( wxT("'propgridwidth' or 'pgw' defines the startup width of the property grid\n") );
	WriteLogMessage( wxT("'debuginfo'     or 'di'  to display debug information in the property grid\n") );
	WriteLogMessage( wxT("'dic'                    to display invisible(currently shadowed) components in the property grid\n") );
	WriteLogMessage( wxT("'fulltree'      or 'ft'  to display the complete property tree(including the data not meant to be accessed by the user\n") );
	WriteLogMessage( wxT("'device'        or 'd'   to directly open a device with a particular serial number\n") );
	WriteLogMessage( wxT("'live'                   to start live acquisition from the device openen via 'device' or 'd' directly\n") );
	WriteLogMessage( wxT("'showEvents'    or 'se'  to display occuring events in the log output window (this will cause additional CPU load)\n") );
	WriteLogMessage( wxT("\nUsage example: '<app name> di=1 h=340'\n") );

	WriteLogMessage( wxT("processed command line parameters: "), boldStyle );
	WriteLogMessage( ( processedParameters.length() > 0 ) ? processedParameters : wxT("none"), boldStyle );
	WriteLogMessage( wxT('\n'), boldStyle );

	wxTextAttr style(*wxBLUE);
	WriteLogMessage( wxT("\nRight-click on a method object to execute it.\n"), style );
	WriteLogMessage( wxT("Parameters must be separated by whitespaces, empty strings can be passed as a single underscore.\n"), style );
	WriteLogMessage( wxT("To find out what the parameters please have a look in the manuals interface reference.\n"), style );
	WriteLogMessage( wxT("Right-click on a list or property to restore its default.\n"), style );
	WriteLogMessage( wxT("\n") );
	WriteLogMessage( wxT("Left-click in the display area and press '+' or '-' or use the mouse wheel for zooming in and out of the image(this will only be active when the 'fit to screen mode is switched off).\n"), style );
	WriteLogMessage( wxT("Double-left-click in the display area to toggle full screen display mode.\n"), style );
	WriteLogMessage( wxT("Right-click in the display an drag the mouse to select a new AOI for the selected analysis page.\n"), style );
	WriteLogMessage( wxT("Left-click into the AOI of the selected analysis page to drag it to a new location.\n"), style );
	WriteLogMessage( wxT("Drop any supported image file type onto the display area to open that file for analysis.\n"), style );
	WriteLogMessage( wxT("\n") );
	WriteLogMessage( wxT("Pixel histogram:\n") );
	WriteLogMessage( wxT("Read: Channel (Mean value, most frequent value count / most frequent value)\n") );
	WriteLogMessage( wxT("\n") );
	WriteLogMessage( wxT("Noise histogram:\n") );
	WriteLogMessage( wxT("Read: Channel#Direction (Mean difference, most frequent value count/  value, Standard deviation)\n") );
	WriteLogMessage( wxT("EXAMPLE: For a single channel(Mono) image the output of 'C0Hor(3.43, 5086/  0, 9.25), C0Ver(3.26, 4840/  0, 7.30) will") );
	WriteLogMessage( wxT("indicate that the mean difference between pixels in horizontal direction is 3.43, the most frequent difference is 0 and this difference is present 5086 times") );
	WriteLogMessage( wxT("in the current AOI. The standard deviation in horizontal direction is 9.25. The C0Ver value list contains the same data but in vertical direction.\n") );

#ifdef BUILD_WITH_PLUGIN_SUPPORT
	WriteLogMessage( wxString::Format( wxT("Deteced plugins: %d.\n"), m_pluginManager.getCount() ), style );
#endif // #ifdef BUILD_WITH_PLUGIN_SUPPORT

	m_pDevPropHandler = new DevicePropertyHandler( m_pPropGrid, boDisplayDebugInfo, boDisplayFullTree, boDisplayInvisibleComponents, boShowEvents );
	m_pDevPropHandler->SetViewMode( m_ViewMode, m_pMISettings_PropGrid_DisplayPropIndicesAsHex->IsChecked() );
	switch( m_ViewMode )
	{
	case DevicePropertyHandler::vmDeveloper:
		m_pMISettings_PropGrid_DevelopersView->Check();
		break;
	default:
		m_pMISettings_PropGrid_StandardView->Check();
		break;
	}

	m_pMonitorImage->Show( m_pMISettings_Display_ShowMonitorImage->IsChecked() && m_pDisplayArea->IsActive() );
	m_pDisplayArea->RegisterMonitorDisplay( m_pMISettings_Display_ShowMonitorImage->IsChecked() ? m_pMonitorImage->GetDisplayArea() : 0 );

	SetSizeHints( 720, 400 );
	SetSize( rect );

	m_pHorizontalSplitter->SetSashPosition( ( m_HorizontalSplitterPos != -1 ) ? m_HorizontalSplitterPos : 3*rect.height/4, true );
	m_pVerticalSplitter->SetSashPosition( ( m_VerticalSplitterPos != -1 ) ? m_VerticalSplitterPos : rect.width/3, true );

	SetupDlgControls();
	UpdateTitle();

	if( ( splitterratio <= 0 ) || ( splitterratio >= 1 ) )
	{
		splitterratio = 0.5;
	}
	m_pPropGrid->SetSplitterRatio( splitterratio );
	UpdatePropGridSplitter();
	wxToolTip::Enable( true );

	m_ListUpdateTimer.SetOwner( this, teListUpdate );
	m_ListUpdateTimer.Start( TIMER_PERIOD );

	if( serialToOpen.length() > 0 )
	{
		int selection = m_pDevCombo->FindString( serialToOpen );
		if( selection != wxNOT_FOUND )
		{
			m_pDevCombo->Select( selection );
			UpdateDeviceFromComboBox();
			ToggleCurrentDevice();
			if( boOpenDeviceInLiveMode )
			{
				ConfigureLive();
			}
		}
		else
		{
			wxString msg(wxT("\nCan't directly open device "));
			msg.Append(ConvertedString(serialToOpen));
			msg.Append( wxT(" as it doesn't seem to be present or the serial number is incorrect\n"));
			WriteErrorMessage( msg );
		}
	}
	else
	{
		SetCurrentImage( fileToOpen );
	}
}

//-----------------------------------------------------------------------------
PropViewFrame::~PropViewFrame()
//-----------------------------------------------------------------------------
{
	Deinit();

	// store the current state of the application
	// main frame
	FramePositionStorage frameStorage(this, wxString(wxT("MainFrame")));
	frameStorage.store();
	wxConfigBase *pConfig = wxConfigBase::Get();
	pConfig->Write( wxT("/MainFrame/verticalSplitter"), ( m_pVerticalSplitter->IsSplit() ) ? m_pVerticalSplitter->GetSashPosition() : m_VerticalSplitterPos );
	pConfig->Write( wxT("/MainFrame/horizontalSplitter"), ( m_pHorizontalSplitter->IsSplit() ) ? m_pHorizontalSplitter->GetSashPosition() : m_HorizontalSplitterPos );
	pConfig->Write( wxT("/MainFrame/selectedPage"), m_pLowerRightWindow->GetSelection() );
	pConfig->Write( wxT("/MainFrame/Settings/scaleDisplay"), m_pDisplayArea->IsScaled() );
	pConfig->Write( wxT("/MainFrame/Settings/monitorDisplay"), m_pMISettings_Display_ShowMonitorImage->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/overlayMessages"), m_pDisplayArea->OverlayMessagesActive() );
	pConfig->Write( wxT("/MainFrame/Settings/requestInfoOverlay"), m_pDisplayArea->InfoOverlayActive() );
	pConfig->Write( wxT("/MainFrame/Settings/displayActive"), m_pMISettings_Display_Active->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/displayIncompleteFrames"), m_pMISettings_Display_ShowIncompleteFrames->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/silentRecording"), m_pMISettings_Recording_SlientMode->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/continuousRecording"), m_pMISettings_Recording_Continuous->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/activeDevicesOnly"), m_pMISettings_ShowConnectedOnly->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/displayLogWindow"), m_pMISettings_Analysis_ShowControls->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/synchroniseAOIs"), m_pMISettings_Analysis_SynchroniseAOIs->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/displayPropGrid"), m_pMISettings_PropGrid_Show->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/showToolBar"), m_pMISettings_ShowToolBar->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/showStatusBar"), m_pMISettings_ShowStatusBar->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/displayPropsWithHexIndices"), m_pMISettings_PropGrid_DisplayPropIndicesAsHex->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/propGridViewMode"), int(m_ViewMode) );

	// property grid
	pConfig->Write( wxT("/PropGrid/splitterRatio"), m_pPropGrid->GetSplitterRatio() );

	for( unsigned int i=0; i<iapLAST; i++ )
	{
		m_ImageAnalysisPlots[i].Save( pConfig );
	}

	// info plot
	pConfig->Write( wxT("/Controls/InfoPlot/Enable"), m_pCBEnableInfoPlot->GetValue() );
	pConfig->Write( wxT("/Controls/InfoPlot/HistoryDepth"), m_pSCInfoPlotHistoryDepth->GetValue() );
	pConfig->Write( wxT("/Controls/InfoPlot/UpdateSpeed"), m_pSCInfoPlotUpdateSpeed->GetValue() );
	pConfig->Write( wxT("/Controls/InfoPlot/PlotSelection"), m_pInfoPlotSelectionCombo->GetSelection() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::Abort( void )
//-----------------------------------------------------------------------------
{
	FunctionInterface* p = 0;
	m_pDevPropHandler->GetActiveDevice( &p );
	if( p )
	{
		int result = p->imageRequestReset( 0, 0 );
		if( result != DMR_NO_ERROR )
		{
			WriteErrorMessage( wxString::Format( wxT("FunctionInterface::imageRequestReset( 0, 0 ) returned an error: %s.\n"), ConvertedString(ImpactAcquireException::getErrorCodeAsString( result )).c_str() ) );
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::ConfigureAnalysisPlot( const wxRect* pAOI /* = 0 */ )
//-----------------------------------------------------------------------------
{
	if( m_CurrentImageAnalysisControlIndex >= 0 )
	{
		m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pPlotCanvas->SetActive( true );
		m_pDisplayArea->SetActiveAnalysisPlot( m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pPlotCanvas );
		ConfigureAOIControlLimits( m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex] );
		if( pAOI )
		{
			ConfigureAOI( m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex], *pAOI );
		}

		m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pPlotCanvas->RefreshData( m_CurrentRequestData,
			m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pSCAOIx->GetValue(),
			m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pSCAOIy->GetValue(),
			m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pSCAOIw->GetValue(),
			m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pSCAOIh->GetValue(),
			true );
	}
	else
	{
		m_pDisplayArea->SetActiveAnalysisPlot( 0 );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::ConfigureAOI( ImageAnalysisPlotControls& controls, const wxRect& rect )
//-----------------------------------------------------------------------------
{
	m_boUpdateAOIInProgress = true;
	controls.m_pSCAOIx->SetValue( rect.GetLeft() );
	controls.m_pSCAOIy->SetValue( rect.GetTop() );
	controls.m_pSCAOIw->SetValue( rect.GetWidth() );
	controls.m_pSCAOIh->SetValue( rect.GetHeight() );
	m_boUpdateAOIInProgress = false;
}

//-----------------------------------------------------------------------------
void PropViewFrame::ConfigureAOIControlLimits( ImageAnalysisPlotControls& controls )
//-----------------------------------------------------------------------------
{
	ImageBuffer* p = m_CurrentRequestData.image_.getBuffer();
	if( p && p->vpData )
	{
		m_boUpdateAOIInProgress = true;
		if( ( p->iHeight > 0 ) && ( p->iHeight != controls.m_pSCAOIh->GetMax() ) )
		{
			controls.m_pSCAOIh->SetRange( 1, p->iHeight );
			controls.m_pSCAOIy->SetRange( 0, p->iHeight - 1 );
			// otherwise the limits are correct, but the displayed value might be incorrect
			controls.m_pSCAOIh->SetValue( controls.m_pSCAOIh->GetValue() );
			controls.m_pSCAOIy->SetValue( controls.m_pSCAOIy->GetValue() );
		}
		if( ( p->iWidth > 0 ) && ( p->iWidth != controls.m_pSCAOIw->GetMax() ) )
		{
			controls.m_pSCAOIw->SetRange( 1, p->iWidth );
			controls.m_pSCAOIx->SetRange( 0, p->iWidth - 1 );
			// otherwise the limits are correct, but the displayed value might be incorrect
			controls.m_pSCAOIw->SetValue( controls.m_pSCAOIw->GetValue() );
			controls.m_pSCAOIx->SetValue( controls.m_pSCAOIx->GetValue() );
		}
		m_boUpdateAOIInProgress = false;
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::ConfigureLive( void )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );

	if( pThread )
	{
		if( !pThread->GetLiveMode() )
		{
			SetupUpdateFrequencies( true );
			pThread->SetContinuousRecording( m_pMISettings_Recording_Continuous->IsChecked() );
			pThread->SetLiveMode( true, !m_pMISettings_Recording_SlientMode->IsChecked() );
		}
		else
		{
			pThread->SetLiveMode( false );
		}
		SetupDlgControls();
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::ConfigureSplitter( wxSplitterWindow* pSplitter, wxWindow* pWindowToRemove, wxWindow* pWindowToShow )
//-----------------------------------------------------------------------------
{
	if( pSplitter )
	{
		if( pSplitter->IsSplit() )
		{
			pSplitter->Unsplit( pWindowToRemove );
		}
		else if( pSplitter->GetWindow1() != pWindowToShow )
		{
			if( pSplitter->GetWindow1() == pWindowToRemove )
			{
				// switch current window. Therefore we first need to split the window again and then
				// the 'old' window can be removed
				pSplitter->SplitHorizontally( pWindowToShow, pWindowToRemove, 0 );
				pSplitter->Unsplit( pWindowToRemove );
			}
			else
			{
				pSplitter->Initialize( pWindowToShow );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::ConfigureStatusBar( bool boShow )
//-----------------------------------------------------------------------------
{
	if( boShow )
	{
		m_pPanel->GetSizer()->Show( m_pStatusBar );
	}
	else
	{
		m_pPanel->GetSizer()->Hide( m_pStatusBar );
	}
	m_pPanel->GetSizer()->Layout();
}

//-----------------------------------------------------------------------------
void PropViewFrame::ConfigureToolBar( bool boShow )
//-----------------------------------------------------------------------------
{
	if( boShow )
	{
		m_pToolBar->Show();
	}
	else
	{
		m_pToolBar->Hide();
	}
	SendSizeEvent();
}

//-----------------------------------------------------------------------------
wxScrolledWindow* PropViewFrame::CreateImageAnalysisPlotControls( wxWindow* pParent, int windowIDOffset )
//-----------------------------------------------------------------------------
{
	int index = GetAnalysisControlIndex( windowIDOffset );
	wxScrolledWindow* pPanel = new wxScrolledWindow(pParent);
	pPanel->SetScrollRate( 10, 10 );
	wxBoxSizer* pSizer = new wxBoxSizer(wxHORIZONTAL);
	wxBoxSizer* pControlsSizer = new wxBoxSizer(wxVERTICAL);
	m_ImageAnalysisPlots[index].m_pNBDisplayMethod = new wxNotebook(pPanel, windowIDOffset + iapidNBDisplayMethod, wxDefaultPosition, wxDefaultSize);
	switch( windowIDOffset )
	{
	case widPixelHistogram:
		RegisterAnalysisPlot<PixelHistogramCanvas>( index, wxColour(128, 0, 255) );
		break;
	case widNoiseHistogram:
		RegisterAnalysisPlot<NoiseHistogramCanvas>( index, wxColour(255, 0, 128) );
		break;
	case widLineProfile:
		RegisterAnalysisPlot<LineProfileCanvas>( index, *wxBLUE );
		break;
	case widVectorScope:
		RegisterAnalysisPlot<VectorScopeCanvas>( index, wxColour(0, 128, 255) );
		break;
	default:
		wxASSERT( false && "Invalid window ID offset for this function" );
		return 0;
	}
	m_ImageAnalysisPlots[index].m_pNBDisplayMethod->InsertPage( 0, m_ImageAnalysisPlots[index].m_pPlotCanvas, wxT("Graphical"), true );
	m_ImageAnalysisPlots[index].m_pCBAOIFullMode = new wxCheckBox(pPanel, windowIDOffset + iapidCBAOIFullMode, wxT("Full AOI mode"));
	pControlsSizer->Add( m_ImageAnalysisPlots[index].m_pCBAOIFullMode, wxSizerFlags().Left() );
	pControlsSizer->AddSpacer( 5 );

	wxFlexGridSizer* pGridSizer = new wxFlexGridSizer(2, 0);
	pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("AOI x-offset:")) );
	m_ImageAnalysisPlots[index].m_pSCAOIx = new wxSpinCtrl(pPanel, windowIDOffset + iapidSCAOIx, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 639, 0);
	pGridSizer->Add( m_ImageAnalysisPlots[index].m_pSCAOIx, wxSizerFlags().Left() );
	pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("AOI y-offset:")) );
	m_ImageAnalysisPlots[index].m_pSCAOIy = new wxSpinCtrl(pPanel, windowIDOffset + iapidSCAOIy, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 479, 0);
	pGridSizer->Add( m_ImageAnalysisPlots[index].m_pSCAOIy, wxSizerFlags().Left() );
	pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("AOI width:")) );
	m_ImageAnalysisPlots[index].m_pSCAOIw = new wxSpinCtrl(pPanel, windowIDOffset + iapidSCAOIw, wxT("640"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 640, 640);
	pGridSizer->Add( m_ImageAnalysisPlots[index].m_pSCAOIw, wxSizerFlags().Left() );
	pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("AOI height:")) );
	m_ImageAnalysisPlots[index].m_pSCAOIh = new wxSpinCtrl(pPanel, windowIDOffset + iapidSCAOIh, wxT("480"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 480, 480);
	pGridSizer->Add( m_ImageAnalysisPlots[index].m_pSCAOIh, wxSizerFlags().Left() );
	if( m_ImageAnalysisPlots[index].m_pPlotCanvas->HasPercentageWindow() )
	{
		pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("Draw start(%):")) );
		m_ImageAnalysisPlots[index].m_pSCDrawStart_percent = new wxSpinCtrl(pPanel, windowIDOffset + iapidSCDrawStart_percent, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 99, 0);
		pGridSizer->Add( m_ImageAnalysisPlots[index].m_pSCDrawStart_percent, wxSizerFlags().Left() );
		pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("Draw window(%):")) );
		m_ImageAnalysisPlots[index].m_pSCDrawWindow_percent = new wxSpinCtrl(pPanel, windowIDOffset + iapidSCDrawWindow_percent, wxT("100"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 100, 100);
		pGridSizer->Add( m_ImageAnalysisPlots[index].m_pSCDrawWindow_percent, wxSizerFlags().Left() );
	}
	if( m_ImageAnalysisPlots[index].m_pPlotCanvas->HasStepWidthParameter() )
	{
		pGridSizer->Add( new wxStaticText( pPanel, wxID_ANY, wxT("Draw step width:") ) );
		m_ImageAnalysisPlots[index].m_pSCDrawStepWidth = new wxSpinCtrl(pPanel, windowIDOffset + iapidSCDrawStepWidth, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, HistogramCanvas::GetDrawStepWidthMax(), 0);
		pGridSizer->Add( m_ImageAnalysisPlots[index].m_pSCDrawStepWidth, wxSizerFlags().Left() );
	}
	if( m_ImageAnalysisPlots[index].m_pPlotCanvas->HasGridSteps() )
	{
		pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("Grid steps X:")) );
		m_ImageAnalysisPlots[index].m_pSCGridStepsX = new wxSpinCtrl(pPanel, windowIDOffset + iapidSCGridStepsX, wxT("1"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 100, 1);
		pGridSizer->Add( m_ImageAnalysisPlots[index].m_pSCGridStepsX, wxSizerFlags().Left() );
		pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("Grid steps Y:")) );
		m_ImageAnalysisPlots[index].m_pSCGridStepsY = new wxSpinCtrl(pPanel, windowIDOffset + iapidSCGridStepsY, wxT("1"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 100, 1);
		pGridSizer->Add( m_ImageAnalysisPlots[index].m_pSCGridStepsY, wxSizerFlags().Left() );
	}
	pGridSizer->Add( new wxStaticText(pPanel, wxID_ANY, wxT("Update interval:")) );
	m_ImageAnalysisPlots[index].m_pSCUpdateSpeed = new wxSpinCtrl(pPanel, windowIDOffset + iapidSCUpdateSpeed, wxT("3"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, PlotCanvas::ulMin, PlotCanvas::ulMax, 3);
	pGridSizer->Add( m_ImageAnalysisPlots[index].m_pSCUpdateSpeed, wxSizerFlags().Left() );
	pControlsSizer->Add( pGridSizer );
	pSizer->Add( pControlsSizer, wxSizerFlags().Left() );
	m_ImageAnalysisPlots[index].m_pPlotCanvas->RegisterImageCanvas( m_pDisplayArea );
	m_ImageAnalysisPlots[index].m_pNBDisplayMethod->SetMinSize( wxSize(100, 50) );
	pSizer->Add( m_ImageAnalysisPlots[index].m_pNBDisplayMethod, wxSizerFlags(1).Expand() );
	pPanel->SetSizer( pSizer );
	return pPanel;
}

//-----------------------------------------------------------------------------
void PropViewFrame::Deinit( void )
//-----------------------------------------------------------------------------
{
	if( m_ListUpdateTimer.IsRunning() )
	{
		m_ListUpdateTimer.Stop();
	}

	m_boShutdownInProgress = true;
	m_pDisplayArea->SetActive( false );
	m_CurrentRequestData = RequestData();
	delete m_pDevPropHandler;
	m_pDevPropHandler = 0;
}

//-----------------------------------------------------------------------------
ImageAnalysisPlotCanvas* PropViewFrame::DeselectAnalysisPlot( void )
//-----------------------------------------------------------------------------
{
	ImageAnalysisPlotCanvas* pCurrentAnalysisPlot = const_cast<ImageAnalysisPlotCanvas*>(m_pDisplayArea->GetActiveAnalysisPlot());
	if( pCurrentAnalysisPlot )
	{
		pCurrentAnalysisPlot->SetActive( false );
	}
	return pCurrentAnalysisPlot;
}

//-----------------------------------------------------------------------------
int PropViewFrame::GetAnalysisControlIndex( void ) const
//-----------------------------------------------------------------------------
{
	wxString selectedPageName = m_pLowerRightWindow->GetPageText( m_pLowerRightWindow->GetSelection() );
	for( int i=0; i<iapLAST; i++ )
	{
		if( m_ImageAnalysisPlots[i].m_pPlotCanvas && ( m_ImageAnalysisPlots[i].m_pPlotCanvas->GetName() == selectedPageName ) )
		{
			return i;
		}
	}
	return -1;
}

//-----------------------------------------------------------------------------
int PropViewFrame::GetAnalysisControlIndex( int windowID ) const
//-----------------------------------------------------------------------------
{
	return ( windowID >> 8 ) - 1;
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAbout(wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxBoxSizer* pTopDownSizer;
	wxDialog dlg(this, wxID_ANY, wxString(wxT("About wxPropView")));
	wxIcon icon(mvIcon_xpm);
	dlg.SetIcon( icon );
	pTopDownSizer = new wxBoxSizer(wxVERTICAL);
	wxStaticText *pText = new wxStaticText(&dlg, wxID_ANY, wxString::Format( wxT("configure tool for %s devices"), COMPANY_NAME ));
	pTopDownSizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5);
	pText = new wxStaticText(&dlg, wxID_ANY, wxString::Format( wxT("(C) 2005 - %s by %s"), CURRENT_YEAR, COMPANY_NAME ));
	pTopDownSizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5);
	pText = new wxStaticText(&dlg, wxID_ANY, wxString::Format( wxT("Version %s"), VERSION_STRING ));
	pTopDownSizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5);
	pText = new wxStaticText(&dlg, wxID_ANY, wxT("Support contact: www.matrix-vision.de") );
	pTopDownSizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5);
	pText = new wxStaticText(&dlg, wxID_ANY, wxString::Format( wxT("This tool has been written using wxWidgets (www.wxwidgets.org) and was compiled with version %d.%d.%d of this library"), wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER ));
	pTopDownSizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5);
	pText = new wxStaticText(&dlg, wxID_ANY, wxT("The property grid control is based on code written by Jaakko Salli"));
	pTopDownSizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5);
	pText = new wxStaticText(&dlg, wxID_ANY, wxT("The latest stable version can be obtained from http://wxpropgrid.sourceforge.net/cgi-bin/index"));
	pTopDownSizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5);
	pText = new wxStaticText(&dlg, wxID_ANY, wxString::Format( wxT("The complete source of this application can be obtained by contacting %s"), COMPANY_NAME ));
	pTopDownSizer->Add( pText, 0, wxALL | wxALIGN_CENTER, 5);
	wxButton* pBtnOK = new wxButton(&dlg, wxID_OK, wxT("OK"));
	pBtnOK->SetDefault();
	pTopDownSizer->Add( pBtnOK, 0, wxALL | wxALIGN_RIGHT, 15);
	dlg.SetSizer( pTopDownSizer );
	pTopDownSizer->Fit( &dlg );
	dlg.ShowModal();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnActivateDisplay( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_pDisplayArea->SetActive( e.IsChecked() );
	m_pMISettings_Display_Active->Check( e.IsChecked() );
	bool boShowMonitorDisplay = e.IsChecked() && m_pMISettings_Display_ShowMonitorImage->IsChecked();
	m_pMonitorImage->GetDisplayArea()->SetActive( boShowMonitorDisplay );
	m_pMonitorImage->Show( boShowMonitorDisplay );
	GetToolBar()->ToggleTool( miSettings_Display_Active, e.IsChecked() );
	SetupDisplayLogSplitter();
	SetupDlgControls();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnBtnAbort( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	Abort();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnBtnRecord( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );

	if( pThread )
	{
		pThread->SetRecordMode( e.IsChecked() );
		m_pMICapture_Record->Check( e.IsChecked() );
		GetToolBar()->ToggleTool( miCapture_Record, e.IsChecked() );
		SetupUpdateFrequencies( true );
	}
	SetupDlgControls();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnBtnLive( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	ConfigureLive();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnIncDecRecordDisplay( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );

	if( pThread )
	{
		SetupUpdateFrequencies( false );
		unsigned long int currentImage = static_cast<unsigned long int>(( e.GetId() == miCapture_Forward ) ? pThread->DisplaySequenceRequestNext() : pThread->DisplaySequenceRequestPrev());
		WriteLogMessage( wxString::Format( wxT("Recorded image %lu: "), currentImage ) );
		m_pRecordDisplaySlider->SetValue( currentImage );
		m_boCurrentImageIsFromFile = false;
		UpdateData( true );
	}
	SetupDlgControls();
}

//-----------------------------------------------------------------------------
void PropViewFrame::ToggleCurrentDevice( void )
//-----------------------------------------------------------------------------
{
	int devIndex = m_pDevCombo->GetSelection();
	Device* pDev = m_pDevPropHandler->GetActiveDevice();
	if( pDev )
	{
		bool isOpen = pDev->isOpen();
		WriteLogMessage( wxT("Trying to ") );
		WriteLogMessage( isOpen ? wxT("close"): wxT("open") );
		WriteLogMessage( wxString::Format( wxT(" device %d ("), devIndex ) );
		WriteLogMessage( ConvertedString(pDev->serial.read()) );
		WriteLogMessage( wxT(")\n") );
		try
		{
			if( isOpen )
			{
				if( !m_boCloseDeviceInProgress )
				{
					m_boCloseDeviceInProgress = true;
					if( !m_boCurrentImageIsFromFile )
					{
						m_CurrentRequestData = RequestData();
						m_pMonitorImage->GetDisplayArea()->SetImage( 0 );
						m_pDisplayArea->SetImage( 0 );
					}
					m_pDevPropHandler->CloseDriver( m_pDevCombo->GetValue() );
					UpdateData();
					m_boCloseDeviceInProgress = false;
				}
			}
			else
			{
				m_pDevPropHandler->OpenDriver( m_pDevCombo->GetValue(), this );
			}
			WriteLogMessage( wxT(" Done...\n") );
		}
		catch( const ImpactAcquireException& e )
		{
			WriteErrorMessage( wxString::Format( wxT("\n%s(%s)\n"), ConvertedString(e.getErrorString()).c_str(), ConvertedString(e.getErrorCodeAsString()).c_str() ) );
			WriteErrorMessage( wxString::Format( wxT("Error origin: %s.\n"), ConvertedString(e.getErrorOrigin()).c_str() ) );
		}
		SetupDlgControls();
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnUseDevice( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	ToggleCurrentDevice();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnBtnSnap(wxCommandEvent& )
//-----------------------------------------------------------------------------
{

	CaptureThread* pThread = 0;
	m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );
	if( pThread )
	{
		SetupUpdateFrequencies( false );
		int result = pThread->RequestSingle( !m_pMISettings_Recording_SlientMode->IsChecked() );
		if( result != DMR_NO_ERROR )
		{
			WriteErrorMessage( wxString::Format( wxT("Image request failed(Reason: %s)! More information can be found in the *.log-file or the debug output.\n"), ConvertedString(ImpactAcquireException::getErrorCodeAsString( result )).c_str() ) );
		}
		SetupDlgControls();
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotCBAOIFullMode( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	int plotIndex = GetAnalysisControlIndex( e.GetId() );
	m_ImageAnalysisPlots[plotIndex].m_pPlotCanvas->SetAOIFullMode( e.IsChecked() );
	if( m_ImageAnalysisPlots[plotIndex].m_pPlotCanvas->IsActive() )
	{
		m_ImageAnalysisPlots[plotIndex].m_pPlotCanvas->RefreshData( m_CurrentRequestData,
			m_ImageAnalysisPlots[plotIndex].m_pSCAOIx->GetValue(),
			m_ImageAnalysisPlots[plotIndex].m_pSCAOIy->GetValue(),
			m_ImageAnalysisPlots[plotIndex].m_pSCAOIw->GetValue(),
			m_ImageAnalysisPlots[plotIndex].m_pSCAOIh->GetValue(),
			true );
		m_pDisplayArea->Refresh( false );
	}
	m_ImageAnalysisPlots[plotIndex].UpdateControls();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnCBEnableInfoPlot( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pInfoPlotArea->SetActive( m_pCBEnableInfoPlot->IsChecked() );
	if( m_pCBEnableInfoPlot->IsChecked() )
	{
		m_pInfoPlotArea->RefreshData( m_CurrentRequestData.requestInfo_, true );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnClose( wxCloseEvent& )
//-----------------------------------------------------------------------------
{
	Deinit();
	Destroy();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnConnectedOnly( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	UpdateDeviceComboBox();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnContinuousRecording( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	if( m_pDevPropHandler )
	{
		m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );
		if( pThread )
		{
			pThread->SetContinuousRecording( e.IsChecked() );
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnDevComboTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	UpdateDeviceFromComboBox();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnEventNotified( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	Device* pDevice = static_cast<Device*>(e.GetClientData());
	if( pDevice )
	{
		WriteLogMessage( wxString::Format( wxT("There has been a %s event reported by device %s.\n"), e.GetString().c_str(), ConvertedString(pDevice->serial.read()).c_str() ), wxTextAttr(wxColour(0, 150, 50)) );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnExportActiveDevice( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxFileDialog fileDlg( this, wxT("Select a filename"), wxT(""), wxT(""), wxT("mv-settings Files (*.xml)|*.xml"), wxSAVE | wxOVERWRITE_PROMPT );
	if( fileDlg.ShowModal() == wxID_OK )
	{
		wxString pathName = fileDlg.GetPath();
		FunctionInterface* p = 0;
		m_pDevPropHandler->GetActiveDevice( &p );
		if( p )
		{
			string pathANSI(pathName.mb_str());
			int result = p->saveSetting( pathANSI, sfDefault, sGlobal );
			if( result == DMR_NO_ERROR )
			{
				WriteLogMessage( wxString::Format( wxT("Storing of data to %s successful.\n"), pathName.c_str() ) );
			}
			else
			{
				WriteErrorMessage( wxString::Format( wxT("Storing of data to %s failed(error code: %d(%s)).\n"), pathName.c_str(), result, ConvertedString(ImpactAcquireException::getErrorCodeAsString(result)).c_str() ) );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnFitToDisplay( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_pDisplayArea->SetScaling( e.IsChecked() );
	m_pMISettings_Display_FitToScreen->Check( e.IsChecked() );
	GetToolBar()->ToggleTool( miSettings_Display_FitToScreen, e.IsChecked() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotDrawStartChanged( wxSpinEvent& e )
//-----------------------------------------------------------------------------
{
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->SetDrawStartPercent( e.GetPosition() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotDrawStartTextChanged( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->SetDrawStartPercent( e.GetInt() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotDrawWindowChanged( wxSpinEvent& e )
//-----------------------------------------------------------------------------
{
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->SetDrawWindowWidthPercent( e.GetPosition() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotDrawWindowTextChanged( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->SetDrawWindowWidthPercent( e.GetInt() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotDrawStepWidthChanged( wxSpinEvent& e )
//-----------------------------------------------------------------------------
{
	dynamic_cast<HistogramCanvas*>(m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas)->SetDrawStepWidth( e.GetPosition() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotDrawStepWidthTextChanged( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	dynamic_cast<HistogramCanvas*>(m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas)->SetDrawStepWidth( e.GetInt() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotGridXStepsChanged( wxSpinEvent& e )
//-----------------------------------------------------------------------------
{
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->SetGridSteps( e.GetPosition(), -1 );
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, -1, -1, -1, -1, true );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotGridXStepsTextChanged( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->SetGridSteps( e.GetInt(), -1 );
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, -1, -1, -1, -1, true );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotGridYStepsChanged( wxSpinEvent& e )
//-----------------------------------------------------------------------------
{
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->SetGridSteps( -1, e.GetPosition() );
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, -1, -1, -1, -1, true );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotGridYStepsTextChanged( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->SetGridSteps( -1, e.GetInt() );
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, -1, -1, -1, -1, true );
}

//-----------------------------------------------------------------------------
void PropViewFrame::AnalysisPlotUpdateSpeedChanged( void )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	if( m_pDevPropHandler )
	{
		m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );
		if( pThread )
		{
			if( pThread->GetLiveMode() )
			{
				SetupUpdateFrequencies( true );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotUpdateSpeedChanged( wxSpinEvent& )
//-----------------------------------------------------------------------------
{
	AnalysisPlotUpdateSpeedChanged();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotUpdateSpeedTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	AnalysisPlotUpdateSpeedChanged();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnRefreshAOIControls( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	if( m_CurrentImageAnalysisControlIndex < 0 )
	{
		return;
	}

	// this will reconstruct an AOI for the selected image analysis page as a result of rectangle being dragged with the right mouse button pressed down
	const AOI* const pAOI = m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pPlotCanvas->GetAOI();
	if( pAOI )
	{
		ConfigureAOI( m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex], pAOI->m_rect );
		m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pPlotCanvas->RefreshData( m_CurrentRequestData, pAOI->m_rect.GetLeft(), pAOI->m_rect.GetTop(), pAOI->m_rect.GetWidth(), pAOI->m_rect.GetHeight() );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnRefreshCurrentPixelData( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	RefreshCurrentPixelData();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnImageInfo( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	auto_ptr<RequestInfoData> p(reinterpret_cast<RequestInfoData*>(e.GetClientData()));
	if( m_pInfoPlotArea )
	{
		m_pInfoPlotArea->RefreshData( *p );
		if( m_pInfoPlotArea->IsActive() )
		{
			time_t t = static_cast<time_t>(p->timeStamp_us / 1000000);
			wxDateTime dt(t);
			dt.SetMillisecond( static_cast<wxDateTime::wxDateTime_t>(( p->timeStamp_us % 1000000 ) / 1000) );
			m_pTCTimestampAsTime->SetValue( wxString::Format( wxT("%02d:%02d:%02d:%03d"), dt.GetHour(), dt.GetMinute(), dt.GetSecond(), dt.GetMillisecond() ) );
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnImageReady( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_boCurrentImageIsFromFile = false;
	UpdateData();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnImageSkipped( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );
	size_t cnt = 1;
	if( pThread )
	{
		cnt = pThread->GetSkippedImageCount();
	}
	if( m_pLogWindow && m_pDisplayArea && m_pDisplayArea->IsActive() )
	{
		m_pDisplayArea->IncreaseSkippedCounter( cnt );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSequenceReady( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );

	if( pThread )
	{
		wxString msg(wxString::Format( wxT("All %lu ('RequestCount') images recorded.\n"), static_cast<unsigned long int>(pThread->GetRecordedSequence().size()) ));
		if( m_pLogWindow )
		{
			WriteLogMessage( msg );
		}
		if( !m_pMISettings_Recording_SlientMode->IsChecked() )
		{
			wxMessageDialog dlg( NULL, msg, wxT("Info"), wxOK | wxICON_WARNING );
			dlg.ShowModal();
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnImportActiveDevice( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxFileDialog fileDlg( this, wxT("Select a filename"), wxT(""), wxT(""), wxT("mv-settings Files (*.xml)|*.xml"), wxOPEN | wxFILE_MUST_EXIST );
	if( fileDlg.ShowModal() == wxID_OK )
	{
		wxString pathName = fileDlg.GetPath();
		FunctionInterface* p = 0;
		m_pDevPropHandler->GetActiveDevice( &p );
		if( p )
		{
			string pathANSI(pathName.mb_str());
			int result = p->loadSetting( pathANSI, sfDefault, sGlobal );
			if( result == DMR_NO_ERROR )
			{
				WriteLogMessage( wxString::Format( wxT("Importing data from %s successful.\n"), pathName.c_str() ) );
			}
			else
			{
				WriteLogMessage( wxString::Format( wxT("Importing data from %s failed(error code: %d(%s)).\n"), pathName.c_str(), result, ConvertedString(ImpactAcquireException::getErrorCodeAsString( result )).c_str() ) );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnManageSettings( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	if( m_pDevPropHandler )
	{
		Device* pDev = m_pDevPropHandler->GetActiveDevice();
		if( pDev && pDev->autoLoadSettingsOrder.isValid() )
		{
			map<int, SettingData> data;
			wxArrayString choices;
			const unsigned int valCount = pDev->autoLoadSettingsOrder.valCount();
			for( unsigned int i=0; i<valCount; i++ )
			{
				const string setting(pDev->autoLoadSettingsOrder.read( i ));
				if( OBJ_IsSettingAvailable( setting.c_str(), sfNative, sUser ) == PROPHANDLING_NO_ERROR )
				{
					data.insert( make_pair( choices.GetCount(), SettingData(sUser, setting) ) );
					choices.Add( ConvertedString(setting) );
				}
				if( OBJ_IsSettingAvailable( setting.c_str(), sfNative, sGlobal ) == PROPHANDLING_NO_ERROR )
				{
					data.insert( make_pair( choices.GetCount(), SettingData(sGlobal, setting) ) );
					choices.Add( ConvertedString(setting) + wxString(wxT("(global storage)")) );
				}
			}
			if( choices.IsEmpty() )
			{
				wxMessageDialog dlg(this, wxT("There are no settings available for configuration for this device!"));
				dlg.ShowModal();
			}
			else
			{
				wxMultiChoiceDialog dlg(this, wxT("Please select the settings, that shall be deleted.\nPlease note, that settings, that have a name different from the serial\nnumber of the current device might affect the behaviour of other devices as well."), wxT("Select settings"), choices);
				if( dlg.ShowModal() == wxID_OK )
				{
					wxArrayInt selections = dlg.GetSelections();
					const size_t selectionCount = selections.GetCount();
					for( size_t j=0; j<selectionCount; j++ )
					{
						map<int, SettingData>::const_iterator it = data.find( selections[j] );
						if( it == data.end() )
						{
							WriteErrorMessage( wxT("INTERNAL ERROR! Setting can't be deleted as it can't be located in the internal hash table.\n") );
							continue;
						}
						TPROPHANDLING_ERROR result = OBJ_DeleteSetting( it->second.name_.c_str(), sfNative, it->second.scope_ );
						if( result != PROPHANDLING_NO_ERROR )
						{
							WriteErrorMessage( wxString::Format( wxT("Failed to delete setting %s(scope: %d). Error code: %s.\n"),
								ConvertedString(it->second.name_).c_str(),
								it->second.scope_,
								ConvertedString(ImpactAcquireException::getErrorCodeAsString( result )).c_str() ) );
						}
					}
				}
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnNotebookPageChanged( wxNotebookEvent& )
//-----------------------------------------------------------------------------
{
	ImageAnalysisPlotCanvas* p = DeselectAnalysisPlot();
	m_CurrentImageAnalysisControlIndex = GetAnalysisControlIndex();
	if( p && m_pMISettings_Analysis_SynchroniseAOIs->IsChecked() )
	{
		wxRect activeAOI = p->GetAOIRect();
		ConfigureAnalysisPlot( &activeAOI );
	}
	else
	{
		ConfigureAnalysisPlot();
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnNBDisplayMethodPageChanged( wxNotebookEvent& )
//-----------------------------------------------------------------------------
{
	if( m_CurrentImageAnalysisControlIndex >= 0 )
	{
		m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pPlotCanvas->SetDisplayMethod( static_cast<ImageAnalysisPlotCanvas::TDisplayMethod>(m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pNBDisplayMethod->GetSelection()) );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnPopUpMethExec( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxPGId id = m_pPropGrid->GetSelectedProperty();
	if( wxPGIdIsOk(id) )
	{
		WriteLogMessage( static_cast<MethodObject*>(wxPGIdToPtr(id)->GetClientData())->Call() );
		WriteLogMessage( wxT('\n') );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotAOIxChanged( wxSpinEvent& e )
//-----------------------------------------------------------------------------
{
	if( m_boUpdateAOIInProgress )
	{
		return;
	}
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, e.GetPosition() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotAOIxTextChanged( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	if( m_boUpdateAOIInProgress )
	{
		return;
	}
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, e.GetInt() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotAOIyChanged( wxSpinEvent& e )
//-----------------------------------------------------------------------------
{
	if( m_boUpdateAOIInProgress )
	{
		return;
	}
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, -1, e.GetPosition() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotAOIyTextChanged( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	if( m_boUpdateAOIInProgress )
	{
		return;
	}
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, -1, e.GetInt() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotAOIwChanged( wxSpinEvent& e )
//-----------------------------------------------------------------------------
{
	if( m_boUpdateAOIInProgress )
	{
		return;
	}
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, -1, -1, e.GetPosition() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotAOIwTextChanged( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	if( m_boUpdateAOIInProgress )
	{
		return;
	}
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, -1, -1, e.GetInt() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotAOIhChanged( wxSpinEvent& e )
//-----------------------------------------------------------------------------
{
	if( m_boUpdateAOIInProgress )
	{
		return;
	}
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, -1, -1, -1, e.GetPosition() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnAnalysisPlotAOIhTextChanged( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	if( m_boUpdateAOIInProgress )
	{
		return;
	}
	m_ImageAnalysisPlots[GetAnalysisControlIndex( e.GetId() )].m_pPlotCanvas->RefreshData( m_CurrentRequestData, -1, -1, -1, e.GetInt() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnInfoPlot_PlotSelectionComboTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	InfoPlotCanvas::TPlotSelection plotSelection = static_cast<InfoPlotCanvas::TPlotSelection>(wxPtrToUInt( m_pInfoPlotSelectionCombo->GetClientData( m_pInfoPlotSelectionCombo->GetSelection() ) ));
	m_pInfoPlotArea->SetPlotSelection( plotSelection );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnInfoPlotUpdateHistoryDepthChanged( wxSpinEvent& e )
//-----------------------------------------------------------------------------
{
	m_pInfoPlotArea->SetHistoryDepth( e.GetPosition() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnInfoPlotUpdateHistoryDepthTextChanged( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_pInfoPlotArea->SetHistoryDepth( e.GetInt() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnInfoPlotUpdateSpeedChanged( wxSpinEvent& e )
//-----------------------------------------------------------------------------
{
	m_pInfoPlotArea->SetUpdateFrequency( e.GetPosition() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnInfoPlotUpdateSpeedTextChanged( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_pInfoPlotArea->SetUpdateFrequency( e.GetInt() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnLiveModeAborted( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	wxString msg(wxString::Format( wxT("The live mode has been aborted because of the following error: '%s'.\n"), e.GetString().c_str() ));
	wxMessageDialog dlg( NULL, msg, wxT("Information"), wxOK | wxICON_INFORMATION );
	dlg.ShowModal();
	WriteErrorMessage( msg );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnLoadActiveDevice( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	if( m_pDevPropHandler )
	{
		FunctionInterface* p = 0;
		m_pDevPropHandler->GetActiveDevice( &p );
		if( p )
		{
			wxArrayString choices;
			choices.Add( wxString(wxT("user specific(default)")) );
			choices.Add( wxString(wxT("system wide")) );
			wxSingleChoiceDialog dlg(this, wxT("Please select the scope from where for this setting shall be imported.\nSystem wide settings can be used by every user logged on to this system,\nbut only certain users might be able to modify them."), wxT("Select the settings scope"), choices);
			if( dlg.ShowModal() == wxID_OK )
			{
				string serialANSI(m_pDevCombo->GetValue().mb_str());
				int result = p->loadSetting( serialANSI, sfNative, ( dlg.GetSelection() == 0 ) ? sUser : sGlobal );
				if( result != DMR_NO_ERROR )
				{
					WriteErrorMessage( wxString::Format( wxT("Loading settings for the current device failed. Result: %s.\n"), ConvertedString(ImpactAcquireException::getErrorCodeAsString( result )).c_str() ) );
				}
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnLoadCurrentProduct( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	if( m_pDevPropHandler )
	{
		FunctionInterface* p = 0;
		Device* pDev = m_pDevPropHandler->GetActiveDevice( &p );
		if( p && pDev )
		{
			wxArrayString choices;
			choices.Add( wxString(wxT("user specific(default)")) );
			choices.Add( wxString(wxT("system wide")) );
			wxSingleChoiceDialog dlg(this, wxT("Please select the scope from where for this setting shall be imported.\nSystem wide settings can be used by every user logged on to this system,\nbut only certain users might be able to modify them."), wxT("Select the settings scope"), choices);
			if( dlg.ShowModal() == wxID_OK )
			{
				int result = p->loadSetting( pDev->product.read(), sfNative, ( dlg.GetSelection() == 0 ) ? sUser : sGlobal );
				if( result != DMR_NO_ERROR )
				{
					WriteErrorMessage( wxString::Format( wxT("Loading settings for the current product type failed. Result: %s.\n"), ConvertedString(ImpactAcquireException::getErrorCodeAsString( result )).c_str() ) );
				}
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnLoadFromDefault( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	if( m_pDevPropHandler )
	{
		FunctionInterface* p = 0;
		m_pDevPropHandler->GetActiveDevice( &p );
		if( p )
		{
			int result = p->loadSettingFromDefault();
			if( result != DMR_NO_ERROR )
			{
				WriteErrorMessage( wxString::Format( wxT("Loading settings for the current device from the default location failed. Result: %s.\n"), ConvertedString(ImpactAcquireException::getErrorCodeAsString( result )).c_str() ) );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnPopUpPropAppendValue( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxPGId id = m_pPropGrid->GetSelectedProperty();
	if( wxPGIdIsOk(id) )
	{
		PropData* pData = static_cast<PropData*>(wxPGIdToPtr(id)->GetClientData());
		if( pData )
		{
			VectorPropertyObject* pProp = dynamic_cast<VectorPropertyObject*>(pData);
			if( pProp )
			{
				Property prop(pProp->Component().hObj());
				prop.resizeValArray( prop.valCount() + 1 );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnPopUpPropDeleteValue( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxPGId id = m_pPropGrid->GetSelectedProperty();
	if( wxPGIdIsOk(id) )
	{
		PropData* pData = static_cast<PropData*>(wxPGIdToPtr(id)->GetClientData());
		if( pData )
		{
			VectorPropertyObject* pProp = dynamic_cast<VectorPropertyObject*>(pData);
			if( pProp )
			{
				Property prop(pProp->Component().hObj());
				pProp->RemoveValue( prop.valCount() - 1 );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnPopUpPropRestoreDefault( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxPGId id = m_pPropGrid->GetSelectedProperty();
	if( wxPGIdIsOk(id) )
	{
		Component comp = static_cast<PropData*>(wxPGIdToPtr(id)->GetClientData())->Component();
		if( comp.type() == ctList )
		{
			wxMessageDialog AreYouSureDlg( NULL,
				wxString::Format( wxT("All properties in the list '%s' will be set to default.\n"), ConvertedString(comp.name()).c_str() ),
				wxT("Warning"),
				wxNO_DEFAULT | wxYES_NO | wxICON_INFORMATION );

			if( AreYouSureDlg.ShowModal() != wxID_YES )
			{
				return;
			}
		}
		if( comp.isDefault() )
		{
			WriteLogMessage( wxString::Format( wxT("Element '%s' is already set to the default value.\n"), ConvertedString(comp.name()).c_str() ) );
		}
		else
		{
			comp.restoreDefault();
		}
		m_pPropGrid->ClearModifiedStatus( id );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnPopUpPropSetMultiple_FixedValue( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxPGId id = m_pPropGrid->GetSelectedProperty();
	if( wxPGIdIsOk(id) )
	{
		PropData* pData = static_cast<PropData*>(wxPGIdToPtr(id)->GetClientData());
		if( pData )
		{
			VectorPropertyObject* pProp = dynamic_cast<VectorPropertyObject*>(pData);
			if( pProp && ( pProp->Component().type() == ctPropInt ) )
			{
				vector<ValueData*> v;
				try
				{
					PropertyI prop(pProp->Component());
					v.push_back( new ValueRangeData(wxString(wxT("First value to set")), 0, prop.valCount() - 1, 1, 0) );
					v.push_back( new ValueRangeData(wxString(wxT("Last value to set")), 0, prop.valCount() - 1, 1, prop.valCount() - 1) );
					if( prop.hasDict() )
					{
						wxArrayString stringArray;
						vector<pair<string, int> > translationDict;
						prop.getTranslationDict( translationDict );
						vector<pair<string, int> >::size_type vSize = translationDict.size();
						for( vector<pair<string, int> >::size_type i=0; i<vSize; i++ )
						{
							stringArray.push_back( ConvertedString(translationDict[i].first) );
						}
						v.push_back( new ValueChoiceData(wxString(wxT("Value")), stringArray) );
					}
					else
					{
						v.push_back( new ValueRangeData(wxString(wxT("Value")),
							prop.isConstDefined( plMinValue ) ? prop.read( plMinValue ) : numeric_limits<int>::min(),
							prop.isConstDefined( plMaxValue ) ? prop.read( plMaxValue ) : numeric_limits<int>::max(),
							prop.isConstDefined( plStepWidth ) ? prop.read( plStepWidth ) : 1,
							prop.isConstDefined( plMinValue ) ? prop.read( plMinValue ) : numeric_limits<int>::min()) );
					}
					ValuesFromUserDlg dlg(this, wxString(wxT("Select the value and range to apply")), v);
					if( dlg.ShowModal() == wxID_OK )
					{
						const vector<wxControl*>& resultData = dlg.GetUserInputControls();
						wxASSERT( dynamic_cast<wxSpinCtrl*>(resultData[0]) && dynamic_cast<wxSpinCtrl*>(resultData[1]) );
						int first = dynamic_cast<wxSpinCtrl*>(resultData[0])->GetValue();
						int last = dynamic_cast<wxSpinCtrl*>(resultData[1])->GetValue();
						if( first <= last )
						{
							try
							{
								if( prop.hasDict() )
								{
									vector<string> sequence( last - first + 1, string(dynamic_cast<wxComboBox*>(resultData[2])->GetValue().mb_str()) );
									prop.writeS( sequence, first );
								}
								else
								{
									vector<int> sequence(last - first + 1, dynamic_cast<wxSpinCtrl*>(resultData[2])->GetValue());
									prop.write( sequence, first );
								}
							}
							catch( const ImpactAcquireException& e )
							{
								wxMessageDialog errorDlg( NULL, wxString::Format(wxT("Couldn't set value range(Error: %s)"), ConvertedString(e.getErrorCodeAsString()).c_str()), wxT("Error"), wxOK | wxICON_INFORMATION );
								errorDlg.ShowModal();
							}
						}
						else
						{
							WriteErrorMessage( wxString::Format( wxT("%s(%d): Invalid input data!\n"), ConvertedString(__FUNCTION__).c_str(), __LINE__ ) );
						}
					}
				}
				catch( const ImpactAcquireException& e )
				{
					wxMessageDialog errorDlg( NULL, wxString::Format(wxT("Internal problem(Error: %s)"), ConvertedString(e.getErrorCodeAsString()).c_str()), wxT("Error"), wxOK | wxICON_INFORMATION );
					errorDlg.ShowModal();
				}
				for_each( v.begin(), v.end(), ptr_fun(DeleteElement<ValueData*>) );
			}
			else
			{
				WriteErrorMessage( wxString::Format( wxT("%s(%d): Element '%s' doesn't seem to be a vector property!\n"), ConvertedString(__FUNCTION__).c_str(), __LINE__, ConvertedString(pProp->Component().name()).c_str() ) );
			}
		}
		else
		{
			WriteErrorMessage( wxString::Format( wxT("%s(%d): Invalid client data detected!\n"), ConvertedString(__FUNCTION__).c_str(), __LINE__ ) );
		}
	}
	else
	{
		WriteErrorMessage( wxString::Format( wxT("%s(%d): No item selected!\n"), ConvertedString(__FUNCTION__).c_str(), __LINE__ ) );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnPopUpPropSetMultiple_FromToRange( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxPGId id = m_pPropGrid->GetSelectedProperty();
	if( wxPGIdIsOk(id) )
	{
		PropData* pData = static_cast<PropData*>(wxPGIdToPtr(id)->GetClientData());
		if( pData )
		{
			VectorPropertyObject* pProp = dynamic_cast<VectorPropertyObject*>(pData);
			if( pProp && ( pProp->Component().type() == ctPropInt ) )
			{
				vector<ValueData*> v;
				try
				{
					PropertyI prop(pProp->Component());
					v.push_back( new ValueRangeData(wxString(wxT("First value to set")), 0, prop.valCount() - 1, 1, 0) );
					v.push_back( new ValueRangeData(wxString(wxT("Last value to set")), 0, prop.valCount() - 1, 1, prop.valCount() - 1) );
					wxASSERT( !prop.hasDict() );
					v.push_back( new ValueRangeData(wxString(wxT("Start value")),
						prop.isConstDefined( plMinValue ) ? prop.read( plMinValue ) : numeric_limits<int>::min(),
						prop.isConstDefined( plMaxValue ) ? prop.read( plMaxValue ) : numeric_limits<int>::max(),
						prop.isConstDefined( plStepWidth ) ? prop.read( plStepWidth ) : 1,
						prop.isConstDefined( plMinValue ) ? prop.read( plMinValue ) : numeric_limits<int>::min()) );
					v.push_back( new ValueRangeData(wxString(wxT("End value")),
						prop.isConstDefined( plMinValue ) ? prop.read( plMinValue ) : numeric_limits<int>::min(),
						prop.isConstDefined( plMaxValue ) ? prop.read( plMaxValue ) : numeric_limits<int>::max(),
						prop.isConstDefined( plStepWidth ) ? prop.read( plStepWidth ) : 1,
						prop.isConstDefined( plMinValue ) ? prop.read( plMaxValue ) : numeric_limits<int>::max()) );
					ValuesFromUserDlg dlg(this, wxString(wxT("Select the value and range to apply")), v);
					if( dlg.ShowModal() == wxID_OK )
					{
						const vector<wxControl*>& resultData = dlg.GetUserInputControls();
						wxASSERT( dynamic_cast<wxSpinCtrl*>(resultData[0]) && dynamic_cast<wxSpinCtrl*>(resultData[1]) &&
							dynamic_cast<wxSpinCtrl*>(resultData[2]) && dynamic_cast<wxSpinCtrl*>(resultData[3]));
						int first = dynamic_cast<wxSpinCtrl*>(resultData[0])->GetValue();
						int last = dynamic_cast<wxSpinCtrl*>(resultData[1])->GetValue();
						int startVal = dynamic_cast<wxSpinCtrl*>(resultData[2])->GetValue();
						int endVal = dynamic_cast<wxSpinCtrl*>(resultData[3])->GetValue();
						if( first <= last )
						{
							try
							{
								vector<int> sequence;
								int valuesToProcess = last - first + 1;
								double increment = static_cast<double>( endVal - startVal ) / static_cast<double>( valuesToProcess - 1 );
								for( int i=0; i<valuesToProcess; i++ )
								{
									int offset = static_cast<int>(i*increment);
									if( i*increment - offset > 0.5 )
									{
										++offset;
									}
									sequence.push_back( startVal + offset );
								}
								prop.write( sequence, first );
							}
							catch( const ImpactAcquireException& e )
							{
								wxMessageDialog errorDlg( NULL, wxString::Format(wxT("Couldn't set value range(Error: %s)"), ConvertedString(e.getErrorCodeAsString()).c_str()), wxT("Error"), wxOK | wxICON_INFORMATION );
								errorDlg.ShowModal();
							}
						}
						else
						{
							WriteErrorMessage( wxString::Format( wxT("%s(%d): Invalid input data!\n"), ConvertedString(__FUNCTION__).c_str(), __LINE__ ) );
						}
					}
				}
				catch( const ImpactAcquireException& e )
				{
					wxMessageDialog errorDlg( NULL, wxString::Format(wxT("Internal problem(Error: %s)"), ConvertedString(e.getErrorCodeAsString()).c_str()), wxT("Error"), wxOK | wxICON_INFORMATION );
					errorDlg.ShowModal();
				}
				for_each( v.begin(), v.end(), ptr_fun(DeleteElement<ValueData*>) );
			}
			else
			{
				WriteErrorMessage( wxString::Format( wxT("%s(%d): Element '%s' doesn't seem to be a vector property!\n"), ConvertedString(__FUNCTION__).c_str(), __LINE__, ConvertedString(pProp->Component().name()).c_str() ) );
			}
		}
		else
		{
			WriteErrorMessage( wxString::Format( wxT("%s(%d): Invalid client data detected!\n"), ConvertedString(__FUNCTION__).c_str(), __LINE__ ) );
		}
	}
	else
	{
		WriteErrorMessage( wxString::Format( wxT("%s(%d): No item selected!\n"), ConvertedString(__FUNCTION__).c_str(), __LINE__ ) );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnPropertyChanged( wxPropertyGridEvent& e )
//-----------------------------------------------------------------------------
{
	PropData* prop_data = static_cast<PropData*>(wxPGIdToPtr(e.GetProperty())->GetClientData());

	if( prop_data )
	{
		prop_data->UpdatePropData();
	}
	m_pDevPropHandler->SetActiveDevice( m_pDevCombo->GetValue() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnPropertyRightClicked( wxPropertyGridEvent& e )
//-----------------------------------------------------------------------------
{
	PropData* prop_data = static_cast<PropData*>(wxPGIdToPtr(e.GetProperty())->GetClientData());

	if( prop_data )
	{
		TComponentType type = prop_data->Component().type();
		if( ( ( type & ctProp ) || ( type & ctList ) ) && prop_data->Component().isWriteable() )
		{
			wxMenu menu(wxT(""));
			menu.Append( miPopUpPropRestoreDefault, wxT("&Restore default") );
			TComponentFlag flags = prop_data->Component().flags();
			wxPGId id = m_pPropGrid->GetSelectedProperty();
			if( wxPGIdIsOk(id) )
			{
				PropData* pData = static_cast<PropData*>(wxPGIdToPtr(id)->GetClientData());
				if( pData )
				{
					VectorPropertyObject* pProp = dynamic_cast<VectorPropertyObject*>(pData);
					if( pProp )
					{
						Property driverProp(pProp->Component());
						if( !( flags & cfFixedSize ) )
						{
							unsigned int valCount = driverProp.valCount();
							unsigned int maxValCount = driverProp.maxValCount();
							wxMenuItem* pMI = menu.Append( miPopUpPropAppendValue, wxT("&Append value") );
							if( maxValCount <= valCount )
							{
								pMI->Enable( false );
							}
							pMI = menu.Append( miPopUpPropDeleteValue, wxT("&Delete last value") );
							if( valCount <= 1 )
							{
								pMI->Enable( false );
							}
						}
						if( driverProp.type() == ctPropInt )
						{
							wxMenu* pSubMenu = new wxMenu(wxT(""));
							pSubMenu->Append( miPopUpPropSetMultiple_FixedValue, wxT("&to a constant value") );
							if( !driverProp.hasDict() )
							{
								pSubMenu->Append( miPopUpPropSetMultiple_FromToRange, wxT("via a user defined &value range") );
							}
							menu.Append( wxID_ANY, wxT("Set multiple elements..."), pSubMenu );
						}
					}
				}
			}
			PopupMenu( &menu );
		}
		/// \todo disable read-only methods later?
		else if( ( type & ctMeth ) /* && prop_data->Component().isWriteable()*/ )
		{
			wxMenu menu(wxT(""));
			menu.Append(miPopUpMethExec, wxT("&Execute"));
			PopupMenu(&menu);
		}
	}
	m_pDevPropHandler->SetActiveDevice( m_pDevCombo->GetValue() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnQuit( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	// true is to force the frame to close
	Close( true );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSaveActiveDevice( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	FunctionInterface* p = 0;
	m_pDevPropHandler->GetActiveDevice( &p );
	if( p )
	{
		wxArrayString choices;
		choices.Add( wxString(wxT("user specific(default)")) );
		choices.Add( wxString(wxT("system wide")) );
		wxSingleChoiceDialog dlg(this, wxT("Please select the scope to which this setting shall be exported.\nPlease note, that storing a setting for system wide usage might\nrequire certain user privileges not available to every user.\nSystem wide settings can be used by every user logged on to this system."), wxT("Select the settings scope"), choices);
		if( dlg.ShowModal() == wxID_OK )
		{
			string pathANSI(m_pDevCombo->GetValue().mb_str());
			int result = p->saveSetting( pathANSI, sfNative, ( dlg.GetSelection() == 0 ) ? sUser : sGlobal );
			if( result != DMR_NO_ERROR )
			{
				WriteErrorMessage( wxString::Format( wxT("Storing settings for the current device failed. Result: %s.\n"), ConvertedString(ImpactAcquireException::getErrorCodeAsString( result )).c_str() ) );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSaveCurrentProduct( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	FunctionInterface* p = 0;
	Device* pDev = m_pDevPropHandler->GetActiveDevice( &p );
	if( p && pDev )
	{
		wxArrayString choices;
		choices.Add( wxString(wxT("user specific(default)")) );
		choices.Add( wxString(wxT("system wide")) );
		wxSingleChoiceDialog dlg(this, wxT("Please select the scope to which this setting shall be exported.\nPlease note, that storing a setting for system wide usage might\nrequire certain user privileges not available to every user.\nSystem wide settings can be used by every user logged on to this system."), wxT("Select the settings scope"), choices);
		if( dlg.ShowModal() == wxID_OK )
		{
			int result = p->saveSetting( pDev->product.read(), sfNative, ( dlg.GetSelection() == 0 ) ? sUser : sGlobal );
			if( result != DMR_NO_ERROR )
			{
				WriteErrorMessage( wxString::Format( wxT("Storing settings for the current product type failed. Result: %s.\n"), ConvertedString(ImpactAcquireException::getErrorCodeAsString( result )).c_str() ) );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::SaveImage( const wxString& filenameAndPath, int fileFilterIndex )
//-----------------------------------------------------------------------------
{
	wxString extension;
	switch( fileFilterIndex )
	{
	case 0:
		extension = wxT("bmp");
		break;
	case 1:
		extension = wxT("png");
		break;
	case 2:
	default:
		extension = wxT("raw");
		break;
	}

	if( extension == wxT("raw") )
	{
		wxFileName tmpFilename(filenameAndPath);
		wxString name(tmpFilename.GetName());
		tmpFilename.SetName( wxString::Format( wxT("%s_%dx%d_%s"), name.c_str(), m_CurrentRequestData.image_.getBuffer()->iWidth, m_CurrentRequestData.image_.getBuffer()->iHeight, m_CurrentRequestData.pixelFormat_.c_str() ) );
		tmpFilename.SetExt( extension );
		wxFile file(tmpFilename.GetFullPath().c_str(), wxFile::write);
		if( !file.IsOpened() )
		{
			WriteErrorMessage( wxString::Format( wxT("Storing of %s failed. Could not open file.\n"), tmpFilename.GetFullPath().c_str() ) );
			return;
		}
		size_t bytesWritten = file.Write( m_CurrentRequestData.image_.getBuffer()->vpData, m_CurrentRequestData.image_.getBuffer()->iSize );
		if( bytesWritten < static_cast<size_t>(m_CurrentRequestData.image_.getBuffer()->iSize) )
		{
			WriteErrorMessage( wxString::Format( wxT("Storing of %s failed. Could not write all data.\n"), tmpFilename.GetFullPath().c_str() ) );
			return;
		}
		WriteLogMessage( wxString::Format( wxT("Storing of %s successful.\n"), tmpFilename.GetFullPath().c_str() ) );
	}
	else
	{
		wxFileName tmp(filenameAndPath);
		tmp.SetExt( extension );
		ImageCanvas::TSaveResult result = m_pDisplayArea->SaveCurrentImage( tmp.GetFullPath(), extension );
		switch( result )
		{
		case ImageCanvas::srOK:
			WriteLogMessage( wxString::Format( wxT("Storing of %s successful.\n"), tmp.GetFullPath().c_str() ) );
			break;
		case ImageCanvas::srNoImage:
			{
				wxMessageDialog errorDlg( NULL, wxT("There is no valid image to store!"), wxT("Error"), wxOK | wxICON_INFORMATION );
				errorDlg.ShowModal();
			}
			break;
		case ImageCanvas::srFailedToSave:
			WriteErrorMessage( wxString::Format( wxT("Storing of %s failed.\n"), tmp.GetFullPath().c_str() ) );
			break;
		default:
			WriteLogMessage( wxString::Format( wxT("Storing of %s return unexpected value: %d.\n"), tmp.GetFullPath().c_str(), result ) );
			break;
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnLoadImage( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxFileDialog fileDlg( this, wxT("Select a file"), wxT(""), wxT(""), wxT("Supported image files (*.bmp;*.gif;*.jpeg;*.jpg;*.png;*.tif)|*.bmp;*.gif;*.jpeg;*.jpg;*.png;*.tif"), wxOPEN | wxFILE_MUST_EXIST );
	if( fileDlg.ShowModal() == wxID_OK )
	{
		SetCurrentImage( fileDlg.GetPath() );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSaveImageSequence( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );

	if( pThread )
	{
		wxFileDialog fileDlg( this, wxT("Select a filename"), wxT(""), wxT(""), wxT("BMP files (*.bmp)|*.bmp|PNG files (*.png)|*.png|RAW files (*.raw)|*.raw"), wxSAVE );
		if( fileDlg.ShowModal() == wxID_OK )
		{
			wxString fileName = fileDlg.GetPath();
			if( fileName.IsEmpty() )
			{
				return;
			}
			wxFileName tmpFilename(fileName);
			wxString name;
			wxFileName::SplitPath( fileName, 0, &name, 0 );

			// remove number
			if( name.Len() > 3 )
			{
				wxString numstr = name.Right( 3 );
				if( numstr.IsNumber() )
				{
					name.RemoveLast( 3 );
				}
			}

			const RequestContainer &seq = pThread->GetRecordedSequence();
			RequestContainer::size_type size = seq.size();
			m_boCurrentImageIsFromFile = false;
			for( RequestContainer::size_type i=0; i<size; i++ )
			{
				pThread->DisplaySequenceRequest( i );
				UpdateData();
				tmpFilename.SetName( wxString::Format( wxT("%s%03lu"), name.c_str(), static_cast<unsigned long int>(i) ) );
				SaveImage( tmpFilename.GetFullPath(), fileDlg.GetFilterIndex() );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSaveImage( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxFileDialog fileDlg( this, wxT("Select a filename"), wxT(""), wxT(""), wxT("BMP files (*.bmp)|*.bmp|PNG files (*.png)|*.png|RAW files (*.raw)|*.raw"), wxSAVE | wxOVERWRITE_PROMPT );
	if( fileDlg.ShowModal() == wxID_OK )
	{
		wxString fileName = fileDlg.GetPath();
		if( fileName.IsEmpty() )
		{
			return;
		}

		wxFileName::SplitPath( fileName, 0, 0, 0 );
		SaveImage( fileName, fileDlg.GetFilterIndex() );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSaveToDefault( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	FunctionInterface* p = 0;
	m_pDevPropHandler->GetActiveDevice( &p );
	if( p )
	{
		int result = p->saveSettingToDefault();
		if( result != DMR_NO_ERROR )
		{
			WriteErrorMessage( wxString::Format( wxT("Storing settings for the current device to the default location failed. Result: %s.\n"), ConvertedString(ImpactAcquireException::getErrorCodeAsString( result )).c_str() ) );
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSaveSystemToDefault( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	FunctionInterface* p = 0;
	m_pDevPropHandler->GetActiveDevice( &p );
	if( p )
	{
		int result = p->saveSystemToDefault();
		if( result != DMR_NO_ERROR )
		{
			WriteErrorMessage( wxString::Format( wxT("Storing system settings to the default location failed. Result: %s.\n"), ConvertedString(ImpactAcquireException::getErrorCodeAsString( result )).c_str() ) );
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnShowDisplayMessagesAsOverlay(wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_pDisplayArea->SetPerformanceWarningOutput( e.IsChecked() );
	m_pMISettings_Display_ShowMessagesAsOverlay->Check( e.IsChecked() );
	GetToolBar()->ToggleTool( miSettings_Display_ShowOverlayMessages, e.IsChecked() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnShowIncompleteFrames( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );
	if( pThread )
	{
		pThread->SetCaptureMode( e.IsChecked() );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnShowRequestInfosAsOverlay( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_pDisplayArea->SetInfoOverlayMode( e.IsChecked() );
	m_pMISettings_Display_ShowRequestInfoAsOverlay->Check( e.IsChecked() );
	GetToolBar()->ToggleTool( miSettings_Display_ShowRequestInfoAsOverlay, e.IsChecked() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnShowMonitorDisplay( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_pMonitorImage->GetDisplayArea()->SetActive( e.IsChecked() );
	m_pMonitorImage->Show( e.IsChecked() );
	m_pMISettings_Display_ShowMonitorImage->Check( e.IsChecked() );
	GetToolBar()->ToggleTool( miSettings_Display_ShowMonitorImage, e.IsChecked() );
	m_pDisplayArea->RegisterMonitorDisplay( e.IsChecked() ? m_pMonitorImage->GetDisplayArea() : 0 );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnShowStatusBar( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	ConfigureStatusBar( e.IsChecked() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnShowToolBar( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	ConfigureToolBar( e.IsChecked() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSettings_Analysis_ShowControls( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_pMISettings_Analysis_ShowControls->Check( e.IsChecked() );
	GetToolBar()->ToggleTool( miSettings_Analysis_ShowControls, e.IsChecked() );
	m_pDisplayArea->Refresh( true );
	SetupDisplayLogSplitter();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSettingsPropGrid_Show( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	SetupVerSplitter( e.IsChecked() );
	m_pMISettings_PropGrid_Show->Check( e.IsChecked() );
	GetToolBar()->ToggleTool( miSettings_PropGrid_Show, e.IsChecked() );
	m_pDisplayArea->Refresh( true );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSettingsPropGrid_DisplayPropIndicesAsHex( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_pDevPropHandler->SetViewMode( m_pDevPropHandler->GetViewMode(), e.IsChecked() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSettingsPropGrid_StandardView( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pDevPropHandler->SetViewMode( DevicePropertyHandler::vmStandard, m_pMISettings_PropGrid_DisplayPropIndicesAsHex->IsChecked() );
	m_ViewMode = m_pDevPropHandler->GetViewMode();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSettingsPropGrid_DevelopersView( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pDevPropHandler->SetViewMode( DevicePropertyHandler::vmDeveloper, m_pMISettings_PropGrid_DisplayPropIndicesAsHex->IsChecked() );
	m_ViewMode = m_pDevPropHandler->GetViewMode();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSetupCaptureQueueDepth( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	FunctionInterface* pFI = 0;
	Device* pDev = m_pDevPropHandler->GetActiveDevice( &pFI, 0, &pThread );

	if( pDev && pFI && pThread )
	{
		const int maxCaptureQueueDepth = pFI->requestCount() - 1;
		long newValue = ::wxGetNumberFromUser( wxString::Format( wxT("Enter the new capture queue depth for device %s.\nNote that this can't be larger then the number of request buffers currently allocated - 1 buffer that is currently displayed and/or analysed.\n'0' will restore the internal default behaviour."), ConvertedString(pDev->serial.read().c_str()).c_str() ),
			wxT("New capture queue depth"),
			wxT("Setup capture queue depth"),
			pThread->GetCaptureQueueDepth(),
			0,
			maxCaptureQueueDepth,
			this );
		if( newValue >= 0 )
		{
			pThread->SetCaptureQueueDepth( newValue );
		}
		else
		{
			WriteLogMessage( wxT("Operation canceled by the user.") );
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSetupRecordSequenceSize( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	FunctionInterface* pFI = 0;
	Device* pDev = m_pDevPropHandler->GetActiveDevice( &pFI, 0, &pThread );

	if( pDev && pFI && pThread )
	{
		const int maxCaptureQueueDepth = pFI->requestCount();
		long newValue = ::wxGetNumberFromUser( wxString::Format( wxT("Enter the new record sequence length for device %s.\nNote that this can't be larger then the number of request buffers currently allocated.\n'0' will restore the internal default behaviour."), ConvertedString(pDev->serial.read().c_str()).c_str() ),
			wxT("New record sequence length"),
			wxT("Setup record sequence length"),
			pThread->GetRecordSequenceSize(),
			0,
			maxCaptureQueueDepth,
			this );
		if( newValue >= 0 )
		{
			pThread->SetRecordSequenceSize( newValue );
		}
		else
		{
			WriteLogMessage( wxT("Operation canceled by the user.") );
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSize( wxSizeEvent& e )
//-----------------------------------------------------------------------------
{
	if( m_pDisplayArea )
	{
		m_pDisplayArea->Refresh( false );
	}
	for( unsigned int i=0; i<iapLAST; i++ )
	{
		if( m_ImageAnalysisPlots[i].m_pPlotCanvas )
		{
			m_ImageAnalysisPlots[i].m_pPlotCanvas->Refresh( false );
		}
	}
	e.Skip();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSLRecordDisplay( wxScrollEvent& e )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );

	if( pThread )
	{
		SetupUpdateFrequencies( false );
		pThread->DisplaySequenceRequest( static_cast<size_t>(e.GetPosition()) );
		WriteLogMessage( wxString::Format( wxT("Recorded image %lu: "), static_cast<unsigned long int>(e.GetPosition()) ) );
		m_boCurrentImageIsFromFile = false;
		UpdateData( true );
	}
	SetupDlgControls();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnUpdateDeviceList( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pDevPropHandler->GetDevMgr().updateDeviceList();
}

//-----------------------------------------------------------------------------
void PropViewFrame::UpdatePropGridSplitter( void )
//-----------------------------------------------------------------------------
{
	double ratio = m_pPropGrid->GetSplitterRatio();
	if( ratio != -1 )
	{
		m_pVerticalSplitter->UpdateSize();
		wxRect rect = m_pPropGrid->GetRect();
		m_pPropGrid->SetSplitterPosition( (int)( rect.GetWidth()* ratio ), true );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSplitterSashPosChanged( wxSplitterEvent& )
//-----------------------------------------------------------------------------
{
	UpdatePropGridSplitter();
	m_pDisplayArea->Refresh( true );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnTimer( wxTimerEvent& e )
//-----------------------------------------------------------------------------
{
	switch( e.GetId() )
	{
	case teListUpdate:
		if( m_pPropGrid->IsShown() )
		{
			// while the propgrid is not displayed we don't need to update it
			m_pDevPropHandler->ValidateTrees();
		}
		SetupDlgControls();
		UpdateStatusBar();
		break;
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnToggleDisplayWindowSize( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	if( !m_pHorizontalSplitter->IsSplit() && !m_pVerticalSplitter->IsSplit() )
	{
		// if all hideable windows are hidden already restore them
		m_boDisplayWindowMaximized = false;
	}
	else
	{
		// else toggle current status
		m_boDisplayWindowMaximized = !m_boDisplayWindowMaximized;
	}

	m_pMISettings_PropGrid_Show->Check( !m_boDisplayWindowMaximized );
	m_pMISettings_Analysis_ShowControls->Check( !m_boDisplayWindowMaximized );
	GetToolBar()->ToggleTool( miSettings_Analysis_ShowControls, !m_boDisplayWindowMaximized );
	GetToolBar()->ToggleTool( miSettings_PropGrid_Show, !m_boDisplayWindowMaximized );
	SetupDisplayLogSplitter( !m_boDisplayWindowMaximized );
	SetupVerSplitter( !m_boDisplayWindowMaximized );
	m_pDisplayArea->RefreshScrollbars();
	m_pDisplayArea->Refresh( true );
}

//-----------------------------------------------------------------------------
void PropViewFrame::RefreshCurrentPixelData( void )
//-----------------------------------------------------------------------------
{
	if( ( m_pStatusBar->GetFieldsCount() != NO_OF_STATUSBAR_FIELDS ) || m_boShutdownInProgress )
	{
		return;
	}

	double scale = 0.;
	wxPoint pixel;
	m_pDisplayArea->GetCurrentPixel( &scale, &pixel );
	const ImageBuffer* pIB = m_CurrentRequestData.image_.getBuffer();
	wxString pixelInfo;

	if( pIB && pIB->vpData && ( scale > 0. ) )
	{
		if( ( pixel.x < 0 ) || ( pixel.x >= pIB->iWidth ) || ( pIB->iWidth < 1 ) )
		{
			pixel.x = -1;
		}

		if( ( pixel.y < 0 ) || ( pixel.y >= pIB->iHeight ) || ( pIB->iHeight < 1 ) )
		{
			pixel.y = -1;
		}

		pixelInfo.append( wxString::Format(wxT("(%d, %d): "), pixel.x, pixel.y ) );

		if( ( pixel.x >= 0 ) && ( pixel.y >= 0 ) )
		{
			switch( pIB->pixelFormat )
			{
			case ibpfMono10:
			case ibpfMono12:
			case ibpfMono14:
			case ibpfMono16:
				{
					unsigned short* p = reinterpret_cast<unsigned short*>(reinterpret_cast<unsigned char*>(pIB->vpData) + ( pixel.y * pIB->pChannels[0].iLinePitch )) + pixel.x;
					pixelInfo.append( wxString::Format( wxT("%d"), *p ) );
				}
				break;
			case ibpfRGB101010Packed:
			case ibpfRGB121212Packed:
			case ibpfRGB141414Packed:
			case ibpfRGB161616Packed:
				{
					unsigned short* p = reinterpret_cast<unsigned short*>(reinterpret_cast<unsigned char*>(pIB->vpData) + ( pixel.y * pIB->pChannels[0].iLinePitch ) + ( pixel.x * pIB->iBytesPerPixel ));
					pixelInfo.append( wxString::Format( wxT("%d(R), %d(G), %d(B)"), p[0], p[1], p[2] ) );
				}
				break;
			case ibpfRGBx888Packed:
			case ibpfRGB888Packed:
				{
					unsigned char* p = reinterpret_cast<unsigned char*>(pIB->vpData) + ( pixel.y * pIB->pChannels[0].iLinePitch ) + ( pixel.x * pIB->iBytesPerPixel );
					pixelInfo.append( wxString::Format( wxT("%d(R), %d(G), %d(B)"), p[2], p[1], p[0] ) );
				}
				break;
			case ibpfRGBx888Planar:
				{
					unsigned char* r = reinterpret_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[0].iChannelOffset + ( pixel.y * pIB->pChannels[0].iLinePitch ) + pixel.x;
					unsigned char* g = reinterpret_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[1].iChannelOffset + ( pixel.y * pIB->pChannels[1].iLinePitch ) + pixel.x;
					unsigned char* b = reinterpret_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[2].iChannelOffset + ( pixel.y * pIB->pChannels[2].iLinePitch ) + pixel.x;
					pixelInfo.append( wxString::Format( wxT("%d(R), %d(G), %d(B)"), *r, *g, *b ) );
				}
				break;
			case ibpfMono8:
				{
					unsigned char* p = reinterpret_cast<unsigned char*>(pIB->vpData) + ( pixel.y * pIB->pChannels[0].iLinePitch ) + pixel.x;
					pixelInfo.append( wxString::Format( wxT("%d"), *p ) );
				}
				break;
			case ibpfYUV422Packed:
				{
					unsigned char* p = reinterpret_cast<unsigned char*>(pIB->vpData) + ( pixel.y * pIB->pChannels[0].iLinePitch ) + ( pixel.x * pIB->iBytesPerPixel );
					if( ( pixel.x & 1 ) || ( pixel.x == pIB->iWidth - 1 ) )
					{
						pixelInfo.append( wxString::Format( wxT("%d(Y), %d(U), %d(V)"), p[0], p[-1], p[1] ) );
					}
					else
					{
						pixelInfo.append( wxString::Format( wxT("%d(Y), %d(U), %d(V)"), p[0], p[1], p[3] ) );
					}
				}
				break;
			case ibpfYUV422_UYVYPacked:
				{
					unsigned char* p = reinterpret_cast<unsigned char*>(pIB->vpData) + ( pixel.y * pIB->pChannels[0].iLinePitch ) + ( pixel.x * pIB->iBytesPerPixel );
					if( ( pixel.x & 1 ) || ( pixel.x == pIB->iWidth - 1 ) )
					{
						pixelInfo.append( wxString::Format( wxT("%d(Y), %d(U), %d(V)"), p[1], p[0], p[-2] ) );
					}
					else
					{
						pixelInfo.append( wxString::Format( wxT("%d(Y), %d(U), %d(V)"), p[1], p[0], p[2] ) );
					}
				}
				break;
			case ibpfYUV422Planar:
				{
					unsigned char* y = reinterpret_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[0].iChannelOffset + ( pixel.y * pIB->pChannels[0].iLinePitch ) + pixel.x;
					unsigned char* u = reinterpret_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[1].iChannelOffset + ( pixel.y * pIB->pChannels[1].iLinePitch ) + pixel.x / 2;
					unsigned char* v = reinterpret_cast<unsigned char*>(pIB->vpData) + pIB->pChannels[2].iChannelOffset + ( pixel.y * pIB->pChannels[2].iLinePitch ) + pixel.x / 2;
					pixelInfo.append( wxString::Format( wxT("%d(Y), %d(U), %d(V)"), *y, *u, *v ) );
				}
				break;
			default:
				pixelInfo.append( wxT("Unsupported format") );
				break;
			}
		}
		else
		{
			pixelInfo.append( wxT("-") );
		}
	}
	else
	{
		pixelInfo = wxString(wxT("-"));
	}

	m_pStatusBar->SetStatusText( pixelInfo, sbfPixelData );
}

//-----------------------------------------------------------------------------
template<class _Ty>
void PropViewFrame::RegisterAnalysisPlot( int index, const wxColour& AOIColour )
//-----------------------------------------------------------------------------
{
	m_ImageAnalysisPlots[index].m_pPlotCanvas = new _Ty( m_ImageAnalysisPlots[index].m_pNBDisplayMethod, wxID_ANY, wxDefaultPosition, wxDefaultSize );
	m_ImageAnalysisPlots[index].m_pPlotCanvas->SetAOIColour( AOIColour );
	m_ImageAnalysisPlots[index].m_pPlotCanvas->CreateGrid( m_ImageAnalysisPlots[index].m_pNBDisplayMethod );
	m_ImageAnalysisPlots[index].m_pNBDisplayMethod->AddPage( m_ImageAnalysisPlots[index].m_pPlotCanvas->GetGrid(), wxT("Numerical") );
}

//-----------------------------------------------------------------------------
bool PropViewFrame::SetCurrentImage( const wxString& fileName )
//-----------------------------------------------------------------------------
{
	if( fileName.IsEmpty() )
	{
		return false;
	}

	wxImage image;
	bool boLoadedSuccessfully = image.LoadFile( fileName );
	if( !boLoadedSuccessfully )
	{
		WriteErrorMessage( wxString::Format( wxT("Failed to load file %s.\n"), fileName.c_str() ) );
		return false;
	}

	int inc = ( image.HasAlpha() ) ? 4 : 3;
	m_CurrentRequestData.image_ = mvIMPACT::acquire::ImageBufferDesc(ibpfRGB888Packed, image.GetWidth(), image.GetHeight());
	m_CurrentRequestData.pixelFormat_ = wxString(wxT("RGB888Packed"));
	const int PIXEL_COUNT = m_CurrentRequestData.image_.getBuffer()->iWidth * m_CurrentRequestData.image_.getBuffer()->iHeight;
	unsigned char* pDst = static_cast<unsigned char*>(m_CurrentRequestData.image_.getBuffer()->vpData);
	unsigned char* pSrc = image.GetData();
	for( int i=0; i<PIXEL_COUNT; i++ )
	{
		*pDst++ = pSrc[2];
		*pDst++ = pSrc[1];
		*pDst++ = pSrc[0];
		pSrc += inc;
	}
	m_boCurrentImageIsFromFile = true;
	UpdateData();
	return true;
}

//-----------------------------------------------------------------------------
void PropViewFrame::SetupDlgControls( void )
//-----------------------------------------------------------------------------
{
	CaptureThread* pThread = 0;
	const Device* pDev = m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );
	bool boDevOpen = false;
	bool boDevPresent = false;
	bool boDevLive = false;
	bool boSequenceBegin = true;
	bool boSequenceEnd = true;
	bool boDevRecord = false;
	RequestContainer::size_type recordedSequenceLength = 0;
	if( pDev )
	{
		boDevOpen = pDev->isOpen();
		boDevPresent = ( pDev->state.read() == dsPresent );
		if( pThread )
		{
			boDevRecord = pThread->GetRecordMode();
			boDevLive = pThread->GetLiveMode();
			pThread->SetCaptureMode( m_pMISettings_Display_ShowIncompleteFrames->IsChecked() );
			recordedSequenceLength = pThread->GetRecordedSequence().size();
			if( recordedSequenceLength > 1 )
			{
				boSequenceBegin = pThread->GetCurrentSequenceIndex() == 0;
				boSequenceEnd = pThread->GetCurrentSequenceIndex() == recordedSequenceLength - 1;
			}
		}
	}

	const DeviceManager& devMgr = m_pDevPropHandler->GetDevMgr();
	if( m_DeviceListChangedCounter != devMgr.changedCount() )
	{
		UpdateDeviceComboBox();
	}

	bool isDeviceSelected = m_pDevCombo->GetValue() != m_NoDevStr;
	m_pMIAction_Use->Enable( isDeviceSelected );
	m_pMIAction_Use->Check( boDevOpen );
	m_pMICapture_Record->Check( boDevRecord );

	m_pMIAction_Settings_Save_ToDefault->Enable( boDevOpen );
	m_pMIAction_Settings_Save_SystemToDefault->Enable( boDevOpen );
	m_pMIAction_Settings_Save_CurrentProduct->Enable( boDevOpen );
	m_pMIAction_Settings_Save_ActiveDevice->Enable( boDevOpen );
	m_pMIAction_Settings_Save_ExportActiveDevice->Enable( boDevOpen );
	m_pMIAction_Settings_Load_FromDefault->Enable( boDevOpen );
	m_pMIAction_Settings_Load_CurrentProduct->Enable( boDevOpen );
	m_pMIAction_Settings_Load_ActiveDevice->Enable( boDevOpen );
	m_pMIAction_Settings_Load_ImportActiveDevice->Enable( boDevOpen );
	m_pMIAction_Settings_Manage->Enable( isDeviceSelected && pDev && pDev->autoLoadSettingsOrder.isValid() );
	m_pMIAction_LoadImage->Enable( !boDevLive );
	m_pMIAction_SaveImage->Enable( boDevOpen && !boDevLive );
	m_pMIAction_SaveImageSequence->Enable( boDevOpen && !boDevLive && ( !boSequenceEnd || !boSequenceBegin ) );
	m_pMICapture_Live->Enable( boDevOpen && boDevPresent );
	m_pMICapture_Live->Check( boDevLive );
	m_pMICapture_Snap->Enable( boDevOpen && boDevPresent && !boDevLive );
	m_pMICapture_Abort->Enable( boDevOpen && boDevPresent );
	m_pMICapture_Record->Enable( boDevOpen && boDevPresent && !boDevLive );
	m_pMICapture_Forward->Enable( boDevOpen && boDevPresent && !boDevLive && !boSequenceEnd );
	m_pMICapture_Backward->Enable( boDevOpen && boDevPresent && !boDevLive && !boSequenceBegin );
	m_pMICapture_SetupCaptureQueueDepth->Enable( boDevOpen && !boDevLive );
	m_pMISettings_Recording_Continuous->Enable( boDevOpen );
	m_pMISettings_Recording_SlientMode->Enable( boDevOpen && !boDevLive );
	m_pMISettings_Recording_SetupSequenceSize->Enable( boDevOpen && !boDevLive );
	m_pRecordDisplaySlider->Enable( boDevOpen && boDevPresent && !boDevLive && ( recordedSequenceLength > 0 ) );
	if( m_pRecordDisplaySlider->IsEnabled() )
	{
		if( static_cast<size_t>(m_pRecordDisplaySlider->GetMax()) != recordedSequenceLength - 1 )
		{
			m_pRecordDisplaySlider->SetRange( 0, recordedSequenceLength - 1 );
		}
	}

	m_pToolBar->EnableTool( miAction_UseDevice, isDeviceSelected );
	m_pToolBar->ToggleTool( miAction_UseDevice, boDevOpen );
	m_pToolBar->EnableTool( miCapture_Abort, m_pMICapture_Abort->IsEnabled() );
	m_pToolBar->EnableTool( miCapture_Live, m_pMICapture_Live->IsEnabled() );
	m_pToolBar->ToggleTool( miCapture_Live, boDevLive );
	m_pToolBar->EnableTool( miCapture_Snap, m_pMICapture_Snap->IsEnabled() );
	m_pToolBar->EnableTool( miCapture_Record, m_pMICapture_Record->IsEnabled() );
	m_pToolBar->ToggleTool( miCapture_Record, boDevRecord );
	m_pToolBar->EnableTool( miCapture_Forward, m_pMICapture_Forward->IsEnabled() );
	m_pToolBar->EnableTool( miCapture_Backward, m_pMICapture_Backward->IsEnabled() );
	m_pToolBar->EnableTool( miSettings_Display_ShowMonitorImage, m_pMISettings_Display_Active->IsChecked() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::SetupDisplayLogSplitter( bool boForceSplit /* = false */ )
//-----------------------------------------------------------------------------
{
	if( ( m_pMISettings_Display_Active->IsChecked() && m_pMISettings_Analysis_ShowControls->IsChecked() ) || boForceSplit )
	{
		m_pHorizontalSplitter->SplitHorizontally( m_pDisplayArea, m_pLowerRightWindow, 0 );
		m_pHorizontalSplitter->SetSashPosition( m_HorizontalSplitterPos );
		ConfigureAnalysisPlot();
	}
	else
	{
		m_HorizontalSplitterPos = m_pHorizontalSplitter->GetSashPosition();
		if( m_pMISettings_Analysis_ShowControls->IsChecked() )
		{
			ConfigureSplitter( m_pHorizontalSplitter, m_pDisplayArea, m_pLowerRightWindow );
			ConfigureAnalysisPlot();
		}
		else
		{
			ConfigureSplitter( m_pHorizontalSplitter, m_pLowerRightWindow, m_pDisplayArea );
			DeselectAnalysisPlot();
		}
	}
	UpdateData();
}

//-----------------------------------------------------------------------------
void PropViewFrame::SetupUpdateFrequencies( bool boCurrentValue )
//-----------------------------------------------------------------------------
{
	for( unsigned int i=0; i<iapLAST; i++ )
	{
		if( m_ImageAnalysisPlots[i].m_pPlotCanvas )
		{
			m_ImageAnalysisPlots[i].m_pPlotCanvas->SetUpdateFrequency( ( boCurrentValue ) ? m_ImageAnalysisPlots[i].m_pSCUpdateSpeed->GetValue() : 1 );
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::SetupVerSplitter( bool boSplit )
//-----------------------------------------------------------------------------
{
	if( boSplit )
	{
		m_pVerticalSplitter->SplitVertically( m_pPropGrid, m_pHorizontalSplitter, 0 );
		m_pVerticalSplitter->SetSashPosition( m_VerticalSplitterPos );
	}
	else if( m_pVerticalSplitter->IsSplit() )
	{
		m_VerticalSplitterPos = m_pVerticalSplitter->GetSashPosition();
		m_pVerticalSplitter->Unsplit( m_pPropGrid );
	}
	else
	{
		m_pVerticalSplitter->Initialize( m_pHorizontalSplitter );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::UpdateData( bool boShowInfo /* = false */ )
//-----------------------------------------------------------------------------
{
	CaptureThread* pCT = 0;

	// To prevent a crash when the handler OnImageReady() is called and m_pDevPropHandler is already deleted.
	if( !m_pDevPropHandler )
	{
		return;
	}

	bool boShowRequestInfoAsOverlay = m_pMISettings_Display_ShowRequestInfoAsOverlay->IsChecked();
	bool boFillInfoStringVector = boShowRequestInfoAsOverlay || boShowInfo;
	TImageBufferPixelFormat lastPixelFormat = m_CurrentRequestData.image_.getBuffer()->pixelFormat;
	vector<wxString> requestInfoStrings;

	if( !m_boCurrentImageIsFromFile )
	{
		Device* pDev = m_pDevPropHandler->GetActiveDevice( 0, 0, &pCT );
		if( pCT && pDev && !m_boCloseDeviceInProgress && pDev->isOpen() )
		{
			pCT->GetImageData( m_CurrentRequestData, boFillInfoStringVector , requestInfoStrings );
			if( boShowInfo )
			{
				wxString msg;
				vector<wxString>::size_type vSize = requestInfoStrings.size();
				for( vector<wxString>::size_type i=0; i<vSize; i++ )
				{
					msg.append( requestInfoStrings[i] );
					msg.append( ( i < vSize - 1 ) ? wxT(", ") : wxT("\n") );
				}
				WriteLogMessage( msg );
			}
		}
		else
		{
			m_CurrentRequestData = RequestData();
		}
	}

	if( boShowRequestInfoAsOverlay )
	{
		m_pDisplayArea->SetInfoOverlay( requestInfoStrings );
	}
	ImageBuffer* p = m_CurrentRequestData.image_.getBuffer();
	m_pMonitorImage->GetDisplayArea()->SetImage( p );
	if( !m_pDisplayArea->SetImage( p ) && ( lastPixelFormat != p->pixelFormat ) )
	{
		WriteErrorMessage( wxString::Format( wxT("%s: ERROR!!! Don't know how to display format %s.\n"), ConvertedString(__FUNCTION__).c_str(), m_CurrentRequestData.pixelFormat_.c_str() ) );
	}
	if( p && p->vpData )
	{
#ifdef BUILD_WITH_PLUGIN_SUPPORT
		m_pluginManager.forwardImage( p );
#endif // #ifdef BUILD_WITH_PLUGIN_SUPPORT
		if( m_CurrentImageAnalysisControlIndex >= 0 )
		{
			ConfigureAOIControlLimits( m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex] );
			m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pPlotCanvas->RefreshData( m_CurrentRequestData,
				m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pSCAOIx->GetValue(),
				m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pSCAOIy->GetValue(),
				m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pSCAOIw->GetValue(),
				m_ImageAnalysisPlots[m_CurrentImageAnalysisControlIndex].m_pSCAOIh->GetValue() );
		}
		if( lastPixelFormat != p->pixelFormat )
		{
			switch( p->pixelFormat )
			{
			case ibpfMono10:
			case ibpfMono12:
			case ibpfMono14:
			case ibpfMono16:
			case ibpfRGB101010Packed:
			case ibpfRGB121212Packed:
			case ibpfRGB141414Packed:
			case ibpfRGB161616Packed:
			case ibpfRGBx888Planar:
			case ibpfYUV422Packed:
			case ibpfYUV422_UYVYPacked:
			case ibpfYUV422Planar:
				WriteLogMessage( wxString::Format( wxT("%s: Please note that pixel format %s will require additional CPU time as it needs to be converted for displaying.\n"), ConvertedString(__FUNCTION__).c_str(), m_CurrentRequestData.pixelFormat_.c_str() ) );
				break;
			default:
				break;
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::UpdateDeviceComboBox( void )
//-----------------------------------------------------------------------------
{
	const DeviceManager& devMgr = m_pDevPropHandler->GetDevMgr();
	bool boDisplayConnectedOnly = m_pMISettings_ShowConnectedOnly->IsChecked();
	m_DeviceListChangedCounter = devMgr.changedCount();
	int oldIndex = m_pDevCombo->GetSelection();
	wxString oldSelection = ( oldIndex == wxNOT_FOUND ) ? m_NoDevStr : m_pDevCombo->GetString( oldIndex );
	// delete all entries
	m_pDevCombo->Clear();
	// refill the combo box with up to date data
	unsigned int devCnt = devMgr.deviceCount();
	if( devCnt > 0 )
	{
		for( unsigned int i=0; i<devCnt; i++ )
		{
			if( !boDisplayConnectedOnly || ( devMgr[i]->state.read() == dsPresent ) )
			{
				m_pDevCombo->Append(ConvertedString(devMgr[i]->serial.read()));
			}
		}
		if( oldSelection == m_NoDevStr )
		{
			m_pDevCombo->Select(0);
		}
		else
		{
			int selection = m_pDevCombo->FindString( oldSelection );
			m_pDevCombo->Select( ( selection == wxNOT_FOUND ) ? 0 : selection );
		}
	}
	else
	{
		m_pDevCombo->Append(m_NoDevStr);
		m_pDevCombo->Select(0);
	}

	if( m_pDevCombo->GetString(0) != m_NoDevStr )
	{
		m_pDevPropHandler->SetActiveDevice( m_pDevCombo->GetValue() );
	}
	UpdateTitle();
	UpdateData();
}


//-----------------------------------------------------------------------------
void PropViewFrame::UpdateDeviceFromComboBox( void )
//-----------------------------------------------------------------------------
{
	m_pDevPropHandler->SetActiveDevice( m_pDevCombo->GetValue() );
	UpdateTitle();
	UpdateData();
}

//-----------------------------------------------------------------------------
void PropViewFrame::UpdateStatusBar( void )
//-----------------------------------------------------------------------------
{
	const Statistics* pS = 0;
	FunctionInterface* pFI = 0;
	CaptureThread* pCT = 0;
	m_pDevPropHandler->GetActiveDevice( &pFI, &pS, &pCT );
	bool boValidDevice = pFI && pS && pCT;
	bool boValidImage = m_CurrentRequestData.image_.getBuffer() && m_CurrentRequestData.image_.getBuffer()->vpData;
	if( boValidDevice || boValidImage )
	{
		if( m_pStatusBar->GetFieldsCount() != NO_OF_STATUSBAR_FIELDS )
		{
			int statusBarFieldWidths[NO_OF_STATUSBAR_FIELDS];
			statusBarFieldWidths[sbfFPS] = -1;
			statusBarFieldWidths[sbfFrameCount] = -1;
			statusBarFieldWidths[sbfImageFormat] = -3;
			statusBarFieldWidths[sbfErrorCount] = -1;
			statusBarFieldWidths[sbfExposeTime] = -1;
			statusBarFieldWidths[sbfGain] = -1;
			statusBarFieldWidths[sbfPixelData] = -2;
			m_pStatusBar->SetFieldsCount( NO_OF_STATUSBAR_FIELDS, &statusBarFieldWidths[0] );
		}

		bool boSlowDisplay = ( m_CurrentRequestData.image_.getBuffer()->pixelFormat != ibpfMono8 ) &&
							 ( m_CurrentRequestData.image_.getBuffer()->pixelFormat != ibpfRGBx888Packed ) &&
							 ( m_CurrentRequestData.pixelFormat_ != RequestData::UNKNOWN_PIXEL_FORMAT_STRING_ );
		if( pS )
		{
			m_pStatusBar->SetStatusText( wxString::Format(wxT("Frames/sec.: %.1f"), pS->framesPerSecond.read() ), sbfFPS );
			m_pStatusBar->SetStatusText( wxString::Format(wxT("Requests: %d"), pS->frameCount.read() ), sbfFrameCount );
			m_pStatusBar->SetStatusText( wxString::Format(wxT("Errors: %d"), pS->errorCount.read() ), sbfErrorCount );
			m_pStatusBar->SetStatusText( wxString::Format(wxT("Exposure(us): %d"), m_CurrentRequestData.requestInfo_.exposeTime_us ), sbfExposeTime );
			m_pStatusBar->SetStatusText( wxString::Format(wxT("Gain(dB): %.4f"), m_CurrentRequestData.requestInfo_.gain_dB ), sbfGain );
		}
		else
		{
			m_pStatusBar->SetStatusText( wxT("Frames/sec.: -"), sbfFPS );
			m_pStatusBar->SetStatusText( wxT("Requests: -"), sbfFrameCount );
			m_pStatusBar->SetStatusText( wxT("Errors: -"), sbfErrorCount );
			m_pStatusBar->SetStatusText( wxT("Exposure(us): -"), sbfExposeTime );
			m_pStatusBar->SetStatusText( wxT("Gain(dB): -"), sbfGain );
		}
		wxString imageFormatMsg(wxString::Format( wxT("Image format %dx%d, %s%s (%s)"),
			m_CurrentRequestData.image_.getBuffer()->iWidth,
			m_CurrentRequestData.image_.getBuffer()->iHeight,
			m_CurrentRequestData.pixelFormat_.c_str(),
			( boSlowDisplay ? wxT("(slow display because of conversion)"): wxT("") ),
			pCT ? pCT->GetLastRequestResult().c_str() : wxT("loaded from disc") ));
		m_pStatusBar->SetStatusText( imageFormatMsg, sbfImageFormat );
		RefreshCurrentPixelData();
	}
	else
	{
		if( m_pStatusBar->GetFieldsCount() != 1 )
		{
			m_pStatusBar->SetFieldsCount( 1, 0 );
		}
		m_pStatusBar->SetStatusText( wxT("no statistics available"), 0 );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::UpdateTitle( void )
//-----------------------------------------------------------------------------
{
	wxString title(wxString::Format( wxT("wxPropView(%s) [%s]"), VERSION_STRING, m_pDevCombo->GetValue().c_str() ));
	if( m_pDevPropHandler )
	{
		string serialANSI(m_pDevCombo->GetValue().mb_str());
		Device* p = m_pDevPropHandler->GetDevMgr().getDeviceBySerial( serialANSI );
		if( p )
		{
			title.append( wxString::Format( wxT(", %s"), ConvertedString(p->product.read()).c_str() ) );
			if( p->isOpen() )
			{
				mvIMPACT::acquire::Info info(p);
				title.append( wxString::Format( wxT("(driver version: %s)"), ConvertedString(info.driverVersion.readS()).c_str() ) );
			}
		}
	}
	SetTitle( title );
}

//-----------------------------------------------------------------------------
void PropViewFrame::WriteLogMessage( const wxString& msg, const wxTextAttr& style /* = wxTextAttr(*wxBLACK) */ )
//-----------------------------------------------------------------------------
{
	if( m_pLogWindow )
	{
		// If you want the control to show the last line of text at the bottom, you can add "ScrollLines(1)" 
		// right after the AppendText call. AppendText will ensure the new line is visible, and ScrollLines 
		// will ensure the scroll bar is at the real end of the range, not further.
		long posBefore = m_pLogWindow->GetLastPosition();
		m_pLogWindow->AppendText( msg );
		long posAfter = m_pLogWindow->GetLastPosition();
		m_pLogWindow->SetStyle( posBefore, posAfter, style );
		m_pLogWindow->ScrollLines( 1 );
		m_pLogWindow->ShowPosition( m_pLogWindow->GetLastPosition() ); // ensure ! that this position is really visible
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::WriteErrorMessage( const wxString& msg )
//-----------------------------------------------------------------------------
{
	wxTextAttr errorStyle(*wxRED);
	WriteLogMessage( msg, errorStyle );
}
