#include "PropViewFrame.h"
#include <string>
#include <wxPropGrid/Include/propgrid.h>
#include "wx/config.h"
#include <wx/spinctrl.h>
#include <wx/splitter.h>
#include "mvIcon.xpm"
#include "DevCtrl.h"
#include "CaptureThread.h"
#include "HistogramCanvas.h"
#include "ImageCanvas.h"
#include "Info.h"
#include "LineProfileCanvas.h"
#include "PropData.h"
#include <limits>
#include "icons.h"

using namespace mvIMPACT::acquire;
using namespace std;

DEFINE_EVENT_TYPE(imageReadyEvent)
DEFINE_EVENT_TYPE(imageSkippedEvent)
DEFINE_EVENT_TYPE(toggleDisplayArea)
DEFINE_EVENT_TYPE(liveModeAborted)

//-----------------------------------------------------------------------------
class MyApp : public wxApp
//-----------------------------------------------------------------------------
{
public:
	virtual bool OnInit( void )
	{
		//wxImage::AddHandler(new wxPNGHandler);
		// Create the main application window
		ostringstream cmdline;
		for( int i=1; i<argc; i++ )
		{
			cmdline << argv[i] << " ";
		}

		PropViewFrame *pFrame = new PropViewFrame( wxString::Format( wxT("wxPropView(%s)"), VERSION_STRING ), wxDefaultPosition, wxDefaultSize, cmdline.str() );
		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)

//-----------------------------------------------------------------------------
class FramePositionStorage
//-----------------------------------------------------------------------------
{
	wxConfigBase* m_pConfig;
	wxWindow* m_pWin;
public:
	FramePositionStorage( wxWindow* pWin ) : m_pWin(pWin), m_pConfig(wxConfigBase::Get()) {}
	void store( void ) const
	{
		int Height, Width, XPos, YPos;
		m_pWin->GetSize( &Width, &Height );
		m_pWin->GetPosition( &XPos, &YPos );
		m_pConfig->Write( wxT("/MainFrame/h"), Height );
		m_pConfig->Write( wxT("/MainFrame/w"), Width );
		m_pConfig->Write( wxT("/MainFrame/x"), XPos );
		m_pConfig->Write( wxT("/MainFrame/y"), YPos );
	}
	wxRect restore( const wxRect& defaultDimensions ) const
	{
		wxRect rect;
		rect.height = m_pConfig->Read( wxT("/MainFrame/h"), defaultDimensions.height );
		rect.width = m_pConfig->Read( wxT("/MainFrame/w"), defaultDimensions.width );
		rect.x = m_pConfig->Read( wxT("/MainFrame/x"), defaultDimensions.x );
		rect.y = m_pConfig->Read( wxT("/MainFrame/y"), 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;
	}
};

// ----------------------------------------------------------------------------
// 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(miActionSave_ToDefault, PropViewFrame::OnSaveToDefault)
	EVT_MENU(miActionSave_SystemToDefault, PropViewFrame::OnSaveSystemToDefault)
	EVT_MENU(miActionSave_ActiveDevice, PropViewFrame::OnSaveActiveDevice)
	EVT_MENU(miActionSave_ExportActiveDevice, PropViewFrame::OnExportActiveDevice)
	EVT_MENU(miActionLoad_FromDefault, PropViewFrame::OnLoadFromDefault)
	EVT_MENU(miActionLoad_ActiveDevice, PropViewFrame::OnLoadActiveDevice)
	EVT_MENU(miActionLoad_ImportActiveDevice, PropViewFrame::OnImportActiveDevice)
	EVT_MENU(miAction_SaveBitmap, PropViewFrame::OnSaveBitmap)
	EVT_MENU(miPopUpPropRestoreDefault, PropViewFrame::OnPopUpPropRestoreDefault)
	EVT_MENU(miPopUpPropAppendValue, PropViewFrame::OnPopUpPropAppendValue)
	EVT_MENU(miPopUpPropDeleteValue, PropViewFrame::OnPopUpPropDeleteValue)
	EVT_MENU(miPopUpMethExec, PropViewFrame::OnPopUpMethExec)
	EVT_MENU(miCapture_Live, PropViewFrame::OnBtnLive)
	EVT_MENU(miCapture_Snap, PropViewFrame::OnBtnSnap)
	EVT_MENU(miCapture_Stop, PropViewFrame::OnBtnStop)
	EVT_MENU(miCapture_Abort, PropViewFrame::OnBtnAbort)
	EVT_MENU(miSettingsDisplay_Scale, PropViewFrame::OnScaleDisplay)
	EVT_MENU(miSettingsDisplay_OverlayMessages, PropViewFrame::OnShowDisplayMessagesAsOverlay)
	EVT_MENU(miSettingsDisplay_Active, PropViewFrame::OnActivateDisplay)
	EVT_MENU(miSettings_ShowConnectedDevicesOnly, PropViewFrame::OnConnectedOnly)
	EVT_MENU(miSettings_ShowLogWindow, PropViewFrame::OnSettingsDisplayLogWindow)
	EVT_MENU(miSettingsPropGrid_Show, PropViewFrame::OnSettingsPropGrid_Show)
	EVT_MENU(miSettingsPropGrid_StandardView, PropViewFrame::OnSettingsPropGrid_StandardView)
	EVT_MENU(miSettingsPropGrid_DevelopersView, PropViewFrame::OnSettingsPropGrid_DevelopersView)
	EVT_SIZE(PropViewFrame::OnSize)
	EVT_TIMER(wxID_ANY, PropViewFrame::OnTimer)
	EVT_BUTTON(widBtnAbort, PropViewFrame::OnBtnAbort)
	EVT_BUTTON(widBtnLive, PropViewFrame::OnBtnLive)
	EVT_BUTTON(widUseDevice, PropViewFrame::OnUseDevice)
	EVT_BUTTON(widBtnSnap, PropViewFrame::OnBtnSnap)
	EVT_COMMAND(widMainFrame, imageReadyEvent, PropViewFrame::OnImageReady)
	EVT_COMMAND(widMainFrame, imageSkippedEvent, PropViewFrame::OnImageSkipped)
	EVT_COMMAND(widMainFrame, toggleDisplayArea, PropViewFrame::OnToggleDisplayWindowSize)
	EVT_COMMAND(widMainFrame, liveModeAborted, PropViewFrame::OnLiveModeAborted)
	EVT_PG_CHANGED(widPropGrid, PropViewFrame::OnPropertyChanged)
	EVT_PG_RIGHT_CLICK(widPropGrid, PropViewFrame::OnPropertyRightClicked)
	EVT_TEXT(widDevCombo, PropViewFrame::OnDevComboTextChanged)
	EVT_CLOSE(PropViewFrame::OnClose)
	EVT_SPLITTER_SASH_POS_CHANGED(widHorSplitter, PropViewFrame::OnSplitterSashPosChanged)
	EVT_SPLITTER_SASH_POS_CHANGED(widVerSplitter, PropViewFrame::OnSplitterSashPosChanged)
	EVT_CHECKBOX(widCBEnableLineProfile, PropViewFrame::OnCBEnableLineProfile)
	EVT_CHECKBOX(widCBEnableHistogram, PropViewFrame::OnCBEnableHistogram)
	EVT_TEXT(widSCLineProfileAOIx, PropViewFrame::OnLineProfileAOIxTextChanged)
	EVT_TEXT(widSCLineProfileAOIy, PropViewFrame::OnLineProfileAOIyTextChanged)
	EVT_TEXT(widSCLineProfileAOIw, PropViewFrame::OnLineProfileAOIwTextChanged)
	EVT_TEXT(widSCLineProfileAOIh, PropViewFrame::OnLineProfileAOIhTextChanged)
	EVT_TEXT(widSCHistogramAOIx, PropViewFrame::OnHistogramAOIxTextChanged)
	EVT_TEXT(widSCHistogramAOIy, PropViewFrame::OnHistogramAOIyTextChanged)
	EVT_TEXT(widSCHistogramAOIw, PropViewFrame::OnHistogramAOIwTextChanged)
	EVT_TEXT(widSCHistogramAOIh, PropViewFrame::OnHistogramAOIhTextChanged)
	EVT_TEXT(widSCHistogramUpdateSpeed, PropViewFrame::OnHistogramUpdateSpeedTextChanged)
	EVT_TEXT(widSCLineProfileUpdateSpeed, PropViewFrame::OnLineProfileUpdateSpeedTextChanged)
END_EVENT_TABLE()

//-----------------------------------------------------------------------------
PropViewFrame::PropViewFrame( const wxString& title, const wxPoint& pos, const wxSize& size, const string& cmdLine )
: wxFrame(0, widMainFrame, title, pos, size), m_boDisplayWindowMaximized(false), m_CurrentImage(1),
   m_CurrentPixelFormat("unknown"), m_DeviceListChangedCounter(numeric_limits<unsigned int>::max()),
   m_NoDevStr(wxT("no device")), m_pDevPropHandler(0), m_pDisplayArea(0), m_pHistogramArea(0), 
   m_pLineProfileArea(0), m_pLogWindow(0), m_pPropGrid(0)
//-----------------------------------------------------------------------------
{
	memset( &m_CurrentRequestInfo, 0, sizeof( RequestInfo ) );

	// create the menu
	// sub menu 'Action -> Save'
	wxMenu* pMenuActionSave = new wxMenu;
	m_pMISaveToDefault = pMenuActionSave->Append( miActionSave_ToDefault, wxT("to default") );
	m_pMISaveSystemToDefault = pMenuActionSave->Append( miActionSave_SystemToDefault, wxT("system settings to default") );
	m_pMISaveActiveDevice = pMenuActionSave->Append( miActionSave_ActiveDevice, wxT("Active device") );
	m_pMIExportActiveDevice = pMenuActionSave->Append( miActionSave_ExportActiveDevice, wxT("Export active device"), wxT("Stores the current settings for this device in a platform independent XML file") );

	// sub menu 'Action -> Load'
	wxMenu* pMenuActionLoad = new wxMenu;
	m_pMILoadFromDefault = pMenuActionLoad->Append( miActionLoad_FromDefault, wxT("from default") );
	m_pMILoadActiveDevice = pMenuActionLoad->Append( miActionLoad_ActiveDevice, wxT("Active device") );
	m_pMIImportActiveDevice = pMenuActionLoad->Append( miActionLoad_ImportActiveDevice, wxT("Import active device"), wxT("Tries to loads settings for this device from a platform independent XML file") );

	// menu 'Action'
	wxMenu* pMenuAction = new wxMenu;
	m_pMIUse = pMenuAction->Append( miAction_UseDevice, wxT("&Use device\tAlt-U"), wxT("Opens or closes the selected device"), wxITEM_CHECK );
	pMenuAction->Append( wxID_ANY, wxT("&Save..."), pMenuActionSave );
	pMenuAction->Append( wxID_ANY, wxT("&Load..."), pMenuActionLoad );
	pMenuAction->AppendSeparator();
	m_pMIActionSaveBitmap = pMenuAction->Append( miAction_SaveBitmap, wxT("Save bitmap") );
	pMenuAction->Append( miQuit, wxT("E&xit\tALT-X") );

	// menu 'Capture'
	wxMenu* pMenuCapture = new wxMenu;
	m_pMICaptureLive = pMenuCapture->Append( miCapture_Live, wxT("&Live\tCTRL-L"), wxT("Starts a continuous acquisition") );
	m_pMICaptureSnap = pMenuCapture->Append( miCapture_Snap, wxT("&Snap\tCTRL-S"), wxT("Captures a single image from the selected device") );
	m_pMICaptureStop = pMenuCapture->Append( miCapture_Stop, wxT("S&top\tCTRL-T"), wxT("Stops a running continuous acquisition") );
	m_pMICaptureAbort = pMenuCapture->Append( miCapture_Abort, wxT("A&bort\tCTRL-B"), wxT("Clears the request queue, but does NOT stop a running continuous acquisition") );

	// sub menu 'Settings -> Display'
	wxMenu* pMenuSettingsDisplay = new wxMenu;
	m_pMISettingsDisplayActive = pMenuSettingsDisplay->Append( miSettingsDisplay_Active, wxT("&Active"), wxT("If not active images will be captured, but NOT displayed"), wxITEM_CHECK );
	m_pMISettingsDisplayScale = pMenuSettingsDisplay->Append( miSettingsDisplay_Scale, wxT("&Scale"), wxT("If active the captured image will be scaled to fit into the display screen(slower)"), wxITEM_CHECK );
	m_pMISettingsDisplayShowMessagesAsOverlay = pMenuSettingsDisplay->Append( miSettingsDisplay_OverlayMessages, wxT("&Message overlay"), wxT("If active the various informations will be blitted on top of the image to inform e.g. about possible performance losses"), wxITEM_CHECK );
	
	// sub menu 'Settings -> Property grid'
	wxMenu* pMenuSettingsPropertyGrid = new wxMenu;
	m_pMISettingsPropGrid_Show = pMenuSettingsPropertyGrid->Append( miSettingsPropGrid_Show, wxT("Show &property grid"), wxT(""), wxITEM_CHECK );
	pMenuSettingsPropertyGrid->AppendSeparator();
	m_pMISettingsPropGrid_StandardView = pMenuSettingsPropertyGrid->Append( miSettingsPropGrid_StandardView, wxT("Standard view"), wxT(""), wxITEM_RADIO );
	m_pMISettingsPropGrid_DevelopersView = pMenuSettingsPropertyGrid->Append( miSettingsPropGrid_DevelopersView, wxT("Developers view"), wxT(""), wxITEM_RADIO );

	// menu 'Settings'
	wxMenu* pMenuSettings = new wxMenu;
	pMenuSettings->Append( wxID_ANY, wxT("&Image display..."), pMenuSettingsDisplay );
	pMenuSettings->AppendSeparator();
	m_pMISettingsConnectedOnly = pMenuSettings->Append( miSettings_ShowConnectedDevicesOnly, wxT("Display &connected devices only"), wxT(""), wxITEM_CHECK );
	pMenuSettings->AppendSeparator();
	m_pMISettingsDisplayLogWindow = pMenuSettings->Append( miSettings_ShowLogWindow, wxT("Show &log window"), wxT(""), wxITEM_CHECK );
	pMenuSettings->Append( wxID_ANY, wxT("Property grid..."), pMenuSettingsPropertyGrid );
		
	// menu 'About'
	wxMenu* pMenuAbout = new wxMenu;
	pMenuAbout->Append( miHelp_About, wxT("&About\tCTRL-A"));

	// 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 );
	wxPanel* pPanel = new wxPanel( this );

	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 );
	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_NORMAL,
		wxT("Starts continuous acquisition from the selected device"),
		wxT("Starts continuous acquisition from the selected device") );
	m_pToolBar->AddTool( miCapture_Stop, wxT("Stop"), stop_xpm, wxNullBitmap, wxITEM_NORMAL,
		wxT("Stops continuous acquisition from the selected device"),
		wxT("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( miSettingsDisplay_Active, wxT("Blit"), DisplayActive_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("turns the display on or off"),
		wxT("turns the display on or off") );
	m_pToolBar->AddTool( miSettingsDisplay_Scale, wxT("Scale"), Scale_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("toggle between scaled and unscaled display"),
		wxT("toggle between scaled and unscaled display") );
	m_pToolBar->AddTool( miSettingsDisplay_OverlayMessages, wxT("Msg."), DisplayMessages_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("turns display messages on or off"),
		wxT("turns display messages on or off") );
	m_pToolBar->AddSeparator();
	m_pToolBar->AddTool( miSettings_ShowLogWindow, wxT("Info"), LogWindow_xpm, wxNullBitmap, wxITEM_CHECK,
		wxT("displays or hides the lower set of controls"),
		wxT("displays or hides the lower set of controls") );
	m_pToolBar->AddTool( miSettingsPropGrid_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( pPanel, widVerSplitter, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER );

	// property grid on the left
	m_pPropGrid = new wxPropertyGrid( m_pVerticalSplitter, widPropGrid, wxDefaultPosition, wxDefaultSize,
		wxPG_BOLD_MODIFIED|
		//wxPG_SPLITTER_AUTO_CENTER|
		//wxPG_AUTO_SORT|
		//wxPG_HIDE_MARGIN|wxPG_STATIC_SPLITTER|
		//wxPG_TOOLTIPS| // Right now, a bit messy.
		//wxPG_NOCATEGORIES|
		wxTAB_TRAVERSAL |
		wxSUNKEN_BORDER
		);
	m_pPropGrid->SetExtraStyle(wxPG_EX_MODE_BUTTONS);
	m_pPropGrid->Compact(true);
	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 );
	// the window for the controls in the lower right corner of the image
	m_pLowerRightWindow = new wxNotebook( m_pHorizontalSplitter, wxID_ANY, 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 );
	
	// histogram window (page of lower right notebook)
	wxPanel* pPanelHistogram = new wxPanel( m_pLowerRightWindow );
	wxBoxSizer* pHistogramSizer = new wxBoxSizer( wxHORIZONTAL );
	wxBoxSizer* pHistogramControlsSizer = new wxBoxSizer( wxVERTICAL );
	m_pCBEnableHistogram = new wxCheckBox( pPanelHistogram, widCBEnableHistogram, wxT("Enable") );
	pHistogramControlsSizer->Add( m_pCBEnableHistogram, wxSizerFlags().Left() );

	wxFlexGridSizer* pHistogramGridSizer = new wxFlexGridSizer( 2, 5 );
	pHistogramGridSizer->Add( new wxStaticText( pPanelHistogram, wxID_ANY, wxT("update interval:") ) );
	m_pSCHistogramUpdateSpeed = new wxSpinCtrl( pPanelHistogram, widSCHistogramUpdateSpeed, wxT("3"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, PlotCanvas::ulMin, PlotCanvas::ulMax, 3 );
	pHistogramGridSizer->Add( m_pSCHistogramUpdateSpeed, wxSizerFlags().Left() );
	pHistogramGridSizer->Add( new wxStaticText( pPanelHistogram, wxID_ANY, wxT("AOI x-offset:") ) );
	m_pSCHistogramAOIx = new wxSpinCtrl( pPanelHistogram, widSCHistogramAOIx, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 640, 0 );
	pHistogramGridSizer->Add( m_pSCHistogramAOIx, wxSizerFlags().Left() );
	pHistogramGridSizer->Add( new wxStaticText( pPanelHistogram, wxID_ANY, wxT("AOI y-offset:") ) );
	m_pSCHistogramAOIy = new wxSpinCtrl( pPanelHistogram, widSCHistogramAOIy, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 480, 0 );
	pHistogramGridSizer->Add( m_pSCHistogramAOIy, wxSizerFlags().Left() );
	pHistogramGridSizer->Add( new wxStaticText( pPanelHistogram, wxID_ANY, wxT("AOI width:") ) );
	m_pSCHistogramAOIw = new wxSpinCtrl( pPanelHistogram, widSCHistogramAOIw, wxT("640"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 640, 640 );
	pHistogramGridSizer->Add( m_pSCHistogramAOIw, wxSizerFlags().Left() );
	pHistogramGridSizer->Add( new wxStaticText( pPanelHistogram, wxID_ANY, wxT("AOI height:") ) );
	m_pSCHistogramAOIh = new wxSpinCtrl( pPanelHistogram, widSCHistogramAOIh, wxT("480"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 480, 480 );
	pHistogramGridSizer->Add( m_pSCHistogramAOIh, wxSizerFlags().Left() );	
	pHistogramControlsSizer->Add( pHistogramGridSizer );
	pHistogramSizer->Add( pHistogramControlsSizer, wxSizerFlags().Left() );
	m_pHistogramArea = new HistogramCanvas( pPanelHistogram, wxID_ANY, wxDefaultPosition, wxDefaultSize );
	m_pHistogramArea->RegisterImageCanvas( m_pDisplayArea );
	m_pHistogramArea->SetAOIColour( *wxGREEN );
	pHistogramSizer->Add( m_pHistogramArea, wxSizerFlags(1).Expand() );
	pPanelHistogram->SetSizer( pHistogramSizer );
	m_pLowerRightWindow->AddPage( pPanelHistogram, wxT("Histogram"), false );

	// line profile window (page of lower right notebook)
	wxPanel* pPanelProfile = new wxPanel( m_pLowerRightWindow );
	wxBoxSizer* pProfilePanelSizer = new wxBoxSizer( wxHORIZONTAL );
	wxBoxSizer* pLineProfileControlsSizer = new wxBoxSizer( wxVERTICAL );
	m_pCBEnableLineProfile = new wxCheckBox( pPanelProfile, widCBEnableLineProfile, wxT("Enable") );
	pLineProfileControlsSizer->Add( m_pCBEnableLineProfile, wxSizerFlags().Left() );
	
	wxFlexGridSizer* pLineProfileControlsGridSizer = new wxFlexGridSizer( 2, 5 );
	pLineProfileControlsGridSizer->Add( new wxStaticText( pPanelProfile, wxID_ANY, wxT("update interval:") ) );
	m_pSCLineProfileUpdateSpeed = new wxSpinCtrl( pPanelProfile, widSCLineProfileUpdateSpeed, wxT("3"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, PlotCanvas::ulMin, PlotCanvas::ulMax, 3 );
	pLineProfileControlsGridSizer->Add( m_pSCLineProfileUpdateSpeed, wxSizerFlags().Left() );
	pLineProfileControlsGridSizer->Add( new wxStaticText( pPanelProfile, wxID_ANY, wxT("AOI x-offset:") ) );
	m_pSCLineProfileAOIx = new wxSpinCtrl( pPanelProfile, widSCLineProfileAOIx, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 640, 0 );
	pLineProfileControlsGridSizer->Add( m_pSCLineProfileAOIx, wxSizerFlags().Left() );
	pLineProfileControlsGridSizer->Add( new wxStaticText( pPanelProfile, wxID_ANY, wxT("AOI y-offset:") ) );
	m_pSCLineProfileAOIy = new wxSpinCtrl( pPanelProfile, widSCLineProfileAOIy, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 480, 0 );
	pLineProfileControlsGridSizer->Add( m_pSCLineProfileAOIy, wxSizerFlags().Left() );
	pLineProfileControlsGridSizer->Add( new wxStaticText( pPanelProfile, wxID_ANY, wxT("AOI width:") ) );
	m_pSCLineProfileAOIw = new wxSpinCtrl( pPanelProfile, widSCLineProfileAOIw, wxT("640"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 640, 640 );
	pLineProfileControlsGridSizer->Add( m_pSCLineProfileAOIw, wxSizerFlags().Left() );
	pLineProfileControlsGridSizer->Add( new wxStaticText( pPanelProfile, wxID_ANY, wxT("AOI height:") ) );
	m_pSCLineProfileAOIh = new wxSpinCtrl( pPanelProfile, widSCLineProfileAOIh, wxT("480"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 480, 480 );
	pLineProfileControlsGridSizer->Add( m_pSCLineProfileAOIh, wxSizerFlags().Left() );

	pLineProfileControlsSizer->Add( pLineProfileControlsGridSizer ); 
	pProfilePanelSizer->Add( pLineProfileControlsSizer, wxSizerFlags().Left() );
	m_pLineProfileArea = new LineProfileCanvas( pPanelProfile, wxID_ANY, wxDefaultPosition, wxDefaultSize );
	m_pLineProfileArea->RegisterImageCanvas( m_pDisplayArea );
	pProfilePanelSizer->Add( m_pLineProfileArea, wxSizerFlags(1).Expand() );
	pPanelProfile->SetSizer( pProfilePanelSizer );
	m_pLowerRightWindow->AddPage( pPanelProfile, wxT("Profile"), false );

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

	m_pStatusBar = new wxStatusBar( pPanel, widStatusBar );
	pTopDownSizer->Add( m_pStatusBar, wxSizerFlags().Expand() );
	pPanel->SetSizer( pTopDownSizer );
	pTopDownSizer->SetSizeHints( this );
	
	// restore previous state
	FramePositionStorage frameStorage(this);
	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_pMISettingsDisplayScale->Check( boActive );
	m_pToolBar->ToggleTool( miSettingsDisplay_Scale, boActive );
	m_pDisplayArea->SetScaling( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/overlayMessages"), 1l ) != 0;
	m_pMISettingsDisplayShowMessagesAsOverlay->Check( boActive );
	m_pDisplayArea->SetPerformanceWarningOutput( boActive );
	m_pToolBar->ToggleTool( miSettingsDisplay_OverlayMessages, boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/displayActive"), 1l ) != 0;
	m_pMISettingsDisplayActive->Check( boActive );
	m_pToolBar->ToggleTool( miSettingsDisplay_Active, boActive );
	m_pDisplayArea->SetActive( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/activeDevicesOnly"), 0l ) != 0;
	m_pMISettingsConnectedOnly->Check( boActive );
	boActive = pConfig->Read( wxT("/MainFrame/Settings/displayLogWindow"), 1l ) != 0;
	m_pMISettingsDisplayLogWindow->Check( boActive );
	m_pToolBar->ToggleTool( miSettings_ShowLogWindow, boActive );
	if( boActive )
	{
		m_pHorizontalSplitter->SplitHorizontally( m_pDisplayArea, m_pLowerRightWindow, 0 );
	}
	else
	{
		m_pHorizontalSplitter->Initialize( m_pDisplayArea );
	}
	boActive = pConfig->Read( wxT("/MainFrame/Settings/displayPropGrid"), 1l ) != 0;
	m_pMISettingsPropGrid_Show->Check( boActive );
	m_pToolBar->ToggleTool( miSettingsPropGrid_Show, boActive );
	if( boActive )
	{
		m_pVerticalSplitter->SplitVertically( m_pPropGrid, m_pHorizontalSplitter, 0 );
	}
	else
	{
		m_pVerticalSplitter->Initialize( m_pHorizontalSplitter );
	}
	int selectedPage = pConfig->Read( wxT("/MainFrame/selectedPage"), -1l );
	if( selectedPage != -1 )
	{
		m_pLowerRightWindow->SetSelection( selectedPage );
	}

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

	// histogram
	bool boHistogramActive = pConfig->Read( wxT("/Controls/Histogram/Enable"), 0l ) != 0;
	m_pCBEnableHistogram->SetValue( boHistogramActive );
	m_pHistogramArea->SetActive( boHistogramActive );
	m_pSCHistogramAOIh->SetValue( pConfig->Read( wxT("/Controls/Histogram/AOIh"), 480l ) );
	m_pSCHistogramAOIw->SetValue( pConfig->Read( wxT("/Controls/Histogram/AOIw"), 640l ) );
	m_pSCHistogramAOIx->SetValue( pConfig->Read( wxT("/Controls/Histogram/AOIx"), 0l ) );
	m_pSCHistogramAOIy->SetValue( pConfig->Read( wxT("/Controls/Histogram/AOIy"), 0l ) );
	m_pSCHistogramUpdateSpeed->SetValue( pConfig->Read( wxT("/Controls/Histogram/UpdateSpeed"), 3l ) );
	// line profile
	bool boLineProfileActive = pConfig->Read( wxT("/Controls/LineProfile/Enable"), 0l ) != 0;
	m_pCBEnableLineProfile->SetValue( boLineProfileActive );
	m_pLineProfileArea->SetActive( boLineProfileActive );
	m_pSCLineProfileAOIh->SetValue( pConfig->Read( wxT("/Controls/LineProfile/AOIh"), 480l ) );
	m_pSCLineProfileAOIw->SetValue( pConfig->Read( wxT("/Controls/LineProfile/AOIw"), 640l ) );
	m_pSCLineProfileAOIx->SetValue( pConfig->Read( wxT("/Controls/LineProfile/AOIx"), 0l ) );
	m_pSCLineProfileAOIy->SetValue( pConfig->Read( wxT("/Controls/LineProfile/AOIy"), 0l ) );
	m_pSCLineProfileUpdateSpeed->SetValue( pConfig->Read( wxT("/Controls/LineProfile/UpdateSpeed"), 3l ) );

	// scan command line
	bool boDisplayDebugInfo = false;
	bool boDisplayFullTree = false;
	bool boDisplayInvisibleComponents = false;
	bool boOpenDeviceInLiveMode = false;
	wxString processedParameters;
	wxString serialToOpen;
	if( !cmdLine.empty() )
	{
		string::size_type start = 0, end = 0, keyEnd = 0;
		string param, key, value;
		while( ( start = cmdLine.find_first_not_of( " ", start )) != string::npos )
		{
			end = cmdLine.find_first_of( " ", start );
			param = ( end == string::npos ) ? cmdLine.substr( start ) : cmdLine.substr( start, end - start );
			keyEnd = param.find_first_of( "=" );
			if( ( keyEnd == string::npos ) || ( keyEnd == param.length() - 1 ) )
			{
				WriteErrorMessage( wxString::Format( wxT("%s: Invalid command line parameter: '%s'.\n"), __FUNCTION__, param.c_str() ) );
			}
			else
			{
				key = param.substr( 0, keyEnd );
				value = param.substr( keyEnd + 1 );
				if( ( key == wxT("width") ) || ( key == wxT("w") ) )
				{
					rect.width = atoi( value.c_str() );
				}
				else if( ( key == wxT("height") ) || ( key == wxT("h") ) )
				{
					rect.height = atoi( value.c_str() );
				}
				else if( ( key == wxT("xpos") ) || ( key == wxT("x") ) )
				{
					rect.x = atoi( value.c_str() );
				}
				else if( ( key == wxT("ypos") ) || ( key == wxT("y") ) )
				{
					rect.y = atoi( value.c_str() );
				}
				else if( key == wxT("splitterratio") )
				{
					splitterratio = atof( value.c_str() );
				}
				else if( ( key == wxT("propgridwidth") ) || ( key == wxT("pgw") ) )
				{
					m_VerticalSplitterPos = atoi( value.c_str() );
				}
				else if( ( key == wxT("debuginfo") ) || ( key == wxT("di") ) )
				{
					boDisplayDebugInfo = ( atoi( value.c_str() ) != 0 );
				}
				else if( ( key == wxT("dic") ) )
				{
					boDisplayInvisibleComponents = ( atoi( value.c_str() ) != 0 );
				}
				else if( ( key == wxT("fulltree") ) || ( key == wxT("ft") ) )
				{
					boDisplayFullTree = ( atoi( value.c_str() ) != 0 );
				}
				else if( ( key == wxT("device") ) || ( key == wxT("d") ) )
				{
					serialToOpen = value.c_str();
				}
				else if( key == wxT("live") )
				{
					boOpenDeviceInLiveMode = ( atoi( value.c_str() ) != 0 );
				}
				else
				{
					WriteErrorMessage( wxString::Format( wxT("%s: Invalid command line parameter: '%s'.\n"), __FUNCTION__, param.c_str() ) );
				}
				processedParameters += param.c_str();
				processedParameters += " ";
			}
			start = end;
		}
	}

	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 );
	m_pLogWindow->WriteText( wxT("'width'         or 'w'   defines the startup width of the application\n") );
	m_pLogWindow->WriteText( wxT("'height'        or 'h'   defines the startup height of the application\n") );
	m_pLogWindow->WriteText( wxT("'xpos'          or 'x'   defines the startup x position of the application\n") );
	m_pLogWindow->WriteText( wxT("'ypos'          or 'y'   defines the startup y position of the application\n") );
	m_pLogWindow->WriteText( wxT("'splitterratio'          defines the startup ratio of the position of the property grids splitter\n") );
	m_pLogWindow->WriteText( wxT("'propgridwidth' or 'pgw' defines the startup width of the property grid\n") );
	m_pLogWindow->WriteText( wxT("'debuginfo'     or 'di'  to display debug information in the property grid\n") );
	m_pLogWindow->WriteText( wxT("'dic'                    to display invisible(currently shadowed) components in the property grid\n") );
	m_pLogWindow->WriteText( wxT("'fulltree'      or 'ft'  to display the complete property tree(including the data not meant to be accessed by the user\n") );
	m_pLogWindow->WriteText( wxT("'device'        or 'd'   to directly open a device with a particular serial number\n") );
	m_pLogWindow->WriteText( wxT("'live'                   to start live acquisition from the device openen via 'device' or 'd' directly\n") );
	m_pLogWindow->WriteText( wxT("\nUsage example: '<app name> di=1 h=340'\n") );

	WriteLogMessage( wxT( wxString::Format( "processed command line parameters: %s\n", ( processedParameters.length() > 0 ) ? processedParameters.c_str() : "none" ).c_str() ), boldStyle );
	wxTextAttr style( wxColour(0, 0, 255) );
	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 );
	
	style.SetTextColour( wxColour(255, 0, 0) );
	WriteLogMessage( wxT( "\nIn YUV422 mode no histogram or line profile will be displayed\n" ), style );

	m_pDevPropHandler = new DevicePropertyHandler( m_pPropGrid, boDisplayDebugInfo, boDisplayFullTree, boDisplayInvisibleComponents );
	m_pDevPropHandler->SetViewMode( m_ViewMode );
	switch( m_ViewMode )
	{
	case DevicePropertyHandler::vmDeveloper:
		m_pMISettingsPropGrid_DevelopersView->Check();
		break;
	default:
		m_pMISettingsPropGrid_StandardView->Check();
		break;
	}

	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 )
			{
				StartLive();
			}
		}
		else
		{
			style.SetTextColour( wxColour(255, 0, 0) );
			WriteLogMessage( wxT( wxString::Format( "\nCan't directly open device %s as it doesn't seem to be present or the serial number is incorrect\n", serialToOpen.c_str() ) ), style );
		}
	}
}

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

	// store the current state of the application
	wxConfigBase *pConfig = wxConfigBase::Get();
	// main frame
	FramePositionStorage frameStorage(this);
	frameStorage.store();
	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/overlayMessages"), m_pDisplayArea->OverlayMessagesActive() );
	pConfig->Write( wxT("/MainFrame/Settings/displayActive"), m_pDisplayArea->IsActive() );
	pConfig->Write( wxT("/MainFrame/Settings/activeDevicesOnly"), m_pMISettingsConnectedOnly->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/displayLogWindow"), m_pMISettingsDisplayLogWindow->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/displayPropGrid"), m_pMISettingsPropGrid_Show->IsChecked() );
	pConfig->Write( wxT("/MainFrame/Settings/propGridViewMode"), m_ViewMode );

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

	// histogram
	pConfig->Write( wxT("/Controls/Histogram/Enable"), m_pCBEnableHistogram->GetValue() );
	pConfig->Write( wxT("/Controls/Histogram/AOIh"), m_pSCHistogramAOIh->GetValue() );
	pConfig->Write( wxT("/Controls/Histogram/AOIw"), m_pSCHistogramAOIw->GetValue() );
	pConfig->Write( wxT("/Controls/Histogram/AOIx"), m_pSCHistogramAOIx->GetValue() );
	pConfig->Write( wxT("/Controls/Histogram/AOIy"), m_pSCHistogramAOIy->GetValue() );
	pConfig->Write( wxT("/Controls/Histogram/UpdateSpeed"), m_pSCHistogramUpdateSpeed->GetValue() );

	// line profile
	pConfig->Write( wxT("/Controls/LineProfile/Enable"), m_pCBEnableLineProfile->GetValue() );
	pConfig->Write( wxT("/Controls/LineProfile/AOIh"), m_pSCLineProfileAOIh->GetValue() );
	pConfig->Write( wxT("/Controls/LineProfile/AOIw"), m_pSCLineProfileAOIw->GetValue() );
	pConfig->Write( wxT("/Controls/LineProfile/AOIx"), m_pSCLineProfileAOIx->GetValue() );
	pConfig->Write( wxT("/Controls/LineProfile/AOIy"), m_pSCLineProfileAOIy->GetValue() );
	pConfig->Write( wxT("/Controls/LineProfile/UpdateSpeed"), m_pSCLineProfileUpdateSpeed->GetValue() );
}

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

	delete m_pDevPropHandler;
	m_pDevPropHandler = 0;	
	m_pDisplayArea->SetImage(0);
}

//-----------------------------------------------------------------------------
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 );
	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_pMISettingsDisplayActive->Check( e.IsChecked() );
	GetToolBar()->ToggleTool( miSettingsDisplay_Active, e.IsChecked() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnBtnAbort( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	FunctionInterface* p = 0;
	m_pDevPropHandler->GetActiveDevice( &p );
	if( p )
	{
		p->imageRequestReset( 0, 0 );
	}
}

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

	if( pThread )
	{
		pThread->SetLiveMode( true );
	}
	SetupDlgControls();
}

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

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

	if( pThread )
	{
		pThread->SetLiveMode( false );
	}
	SetupDlgControls();
}

//-----------------------------------------------------------------------------
void PropViewFrame::ToggleCurrentDevice( void )
//-----------------------------------------------------------------------------
{
	int devIndex = m_pDevCombo->GetSelection();
	Device* pDev = m_pDevPropHandler->GetActiveDevice();
	if( pDev )
	{
		bool isOpen = pDev->isOpen();
		m_pLogWindow->WriteText( wxString::Format( wxT( "Trying to %s device %d(%s).\n" ), isOpen ? wxT("close"): wxT("open"), devIndex, pDev->serial.read().c_str() ) );

		try
		{
			if( isOpen )
			{
				m_pDevPropHandler->CloseDriver( m_pDevCombo->GetValue().c_str() );
				UpdateData();
			}
			else
			{
				m_pDevPropHandler->OpenDriver( m_pDevCombo->GetValue().c_str(), this );
			}
			m_pLogWindow->WriteText( wxT("Done...\n") );
		}
		catch( ImpactAcquireException& e )
		{
			WriteErrorMessage( wxString::Format( wxT("%s(%s)\n"), e.getErrorString().c_str(), e.getErrorCodeAsString().c_str() ) );
			WriteErrorMessage( wxString::Format( wxT("Error origin: %s.\n"), e.getErrorOrigin().c_str() ) );
		}
		SetupDlgControls();
	}
}

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

//-----------------------------------------------------------------------------
void PropViewFrame::OnBtnSnap(wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	FunctionInterface* p = 0;
	m_pDevPropHandler->GetActiveDevice( &p );
	if( p )
	{
		p->imageRequestSingle(0);
		SetupDlgControls();
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnCBEnableHistogram( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pHistogramArea->SetActive( m_pCBEnableHistogram->IsChecked() );
	if( m_pCBEnableHistogram->IsChecked() )
	{
		if( m_CurrentImage.getBuffer() )
		{
			m_pSCHistogramAOIh->SetRange( 1, m_CurrentImage.getBuffer()->iHeight );
			m_pSCHistogramAOIw->SetRange( 1, m_CurrentImage.getBuffer()->iWidth );
		}
		m_pHistogramArea->RefreshData( m_CurrentImage.getBuffer(), m_pSCHistogramAOIx->GetValue(), m_pSCHistogramAOIy->GetValue(), m_pSCHistogramAOIw->GetValue(), m_pSCHistogramAOIh->GetValue(), true );
	}
	m_pDisplayArea->Refresh( false );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnCBEnableLineProfile( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pLineProfileArea->SetActive( m_pCBEnableLineProfile->IsChecked() );
	if( m_pCBEnableLineProfile->IsChecked() )
	{
		if( m_CurrentImage.getBuffer() )
		{
			m_pSCLineProfileAOIh->SetRange( 1, m_CurrentImage.getBuffer()->iHeight );
			m_pSCLineProfileAOIw->SetRange( 1, m_CurrentImage.getBuffer()->iWidth );
		}
		m_pLineProfileArea->RefreshData( m_CurrentImage.getBuffer(), m_pSCLineProfileAOIx->GetValue(), m_pSCLineProfileAOIy->GetValue(), m_pSCLineProfileAOIw->GetValue(), m_pSCLineProfileAOIh->GetValue(), true );
	}
	m_pDisplayArea->Refresh( false );
}

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

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

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

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

	m_pDevPropHandler->GetActiveDevice( 0, 0, &pCT );
	TImageBufferPixelFormat lastPixelFormat = m_CurrentImage.getBuffer()->pixelFormat;

	if( pCT )
	{
		pCT->GetImageData( &m_CurrentImage, &m_CurrentRequestInfo, m_CurrentPixelFormat );
	}
	else
	{
		ImageBufferDesc nbd(1);
		m_CurrentImage = nbd;
		m_CurrentImage.getBuffer()->pixelFormat = ibpfMono8;
		//m_CurrentImage = ImageBufferDesc(ib); // doesn't work with GCC...
		m_CurrentPixelFormat = "unknown";
		memset( &m_CurrentRequestInfo, 0, sizeof(RequestInfo) );
	}

	ImageBuffer* p = m_CurrentImage.getBuffer();
	if( !m_pDisplayArea->SetImage( p ) && ( lastPixelFormat != p->pixelFormat ) )
	{
		WriteErrorMessage( wxString::Format(wxT("%s: ERROR!!! Don't know how to display this format: %s.\n"), __FUNCTION__, m_CurrentPixelFormat.c_str() ) );
	}
	if( p && p->vpData )
	{
		switch( p->pixelFormat )
		{
		case ibpfMono8:
		case ibpfMono10:
		case ibpfMono12:
		case ibpfMono14:
		case ibpfMono16:
		case ibpfRGBx888Packed:
		case ibpfRGBx888Planar:
		case ibpfRGB888Packed:
			if( m_pSCHistogramAOIw->GetMax() != p->iWidth )
			{
				m_pSCHistogramAOIw->SetRange( 1, p->iWidth );
				m_pSCLineProfileAOIw->SetRange( 1, p->iWidth );
				// otherwise the limits are correct, but the displayed value might be incorrect
				m_pSCHistogramAOIw->SetValue( m_pSCHistogramAOIw->GetValue() );
				m_pSCLineProfileAOIw->SetValue( m_pSCLineProfileAOIw->GetValue() );
			}
			if( m_pSCHistogramAOIh->GetMax() != p->iHeight )
			{
				m_pSCHistogramAOIh->SetRange( 1, p->iHeight );
				m_pSCLineProfileAOIh->SetRange( 1, p->iHeight );
				// otherwise the limits are correct, but the displayed value might be incorrect
				m_pSCHistogramAOIh->SetValue( m_pSCHistogramAOIh->GetValue() );
				m_pSCLineProfileAOIh->SetValue( m_pSCLineProfileAOIh->GetValue() );
			}
			if( m_pHistogramArea->IsActive() )
			{
				m_pHistogramArea->RefreshData( p, m_pSCHistogramAOIx->GetValue(), m_pSCHistogramAOIy->GetValue(), m_pSCHistogramAOIw->GetValue(), m_pSCHistogramAOIh->GetValue() );
			}
			if( m_pLineProfileArea->IsActive() )
			{
				m_pLineProfileArea->RefreshData( p, m_pSCLineProfileAOIx->GetValue(), m_pSCLineProfileAOIy->GetValue(), m_pSCLineProfileAOIw->GetValue(), m_pSCLineProfileAOIh->GetValue() );
			}
			break;
		case ibpfYUV422Packed:
			if( ( m_pHistogramArea->IsActive() || m_pLineProfileArea->IsActive() ) &&
				( lastPixelFormat != p->pixelFormat ) )
			{
				m_pLogWindow->WriteText( wxString::Format(wxT("%s: Can't display enhanced image information (e.g. line profile)in this format: %s.\n"), __FUNCTION__, m_CurrentPixelFormat.c_str() ) );
			}
			break;
		default:
			if( lastPixelFormat != p->pixelFormat )
			{
				WriteErrorMessage( wxString::Format(wxT("%s: ERROR!!! Don't know how to display this format: %s.\n"), __FUNCTION__, m_CurrentPixelFormat.c_str() ) );
			}
			break;
		}
		if( lastPixelFormat != p->pixelFormat )
		{
			switch( p->pixelFormat )
			{
			case ibpfMono10:
			case ibpfMono12:
			case ibpfMono14:
			case ibpfMono16:
			case ibpfRGBx888Planar:
			case ibpfYUV422Packed:
				m_pLogWindow->WriteText( wxString::Format(wxT("%s: Please note that this pixel format will require additional CPU time as it needs to be converted for displaying: %s.\n"), __FUNCTION__, m_CurrentPixelFormat.c_str() ) );
				break;
			default:
				break;
			}
		}
	}
}

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

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

//-----------------------------------------------------------------------------
void PropViewFrame::OnExportActiveDevice( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxFileDialog fileDlg( this, wxT("Select a filename"), wxT(""), wxT(""), wxT("mv-settings Files (*.xml)|*.xml"), wxSAVE | wxHIDE_READONLY | wxFILE_MUST_EXIST | wxOVERWRITE_PROMPT );
	if( fileDlg.ShowModal() == wxID_OK )
	{
		wxString pathName = fileDlg.GetPath();
		FunctionInterface* p = 0;
		m_pDevPropHandler->GetActiveDevice( &p );
		if( p )
		{
			int result = p->saveSetting( pathName.c_str(),
										 static_cast<TStorageFlag>(0),	// not Native -> to xml file
										 sGlobal );
			if( result == 0 )
			{
				m_pLogWindow->WriteText( 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, ImpactAcquireException::getErrorCodeAsString(result).c_str() ) );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnHistogramUpdateSpeedTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pHistogramArea->SetUpdateFrequency( m_pSCHistogramUpdateSpeed->GetValue() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnImageReady( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	UpdateData();
	e.Skip();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnImageSkipped( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	if( m_pLogWindow && m_pDisplayArea && m_pDisplayArea->IsActive() )
	{
		m_pLogWindow->WriteText( wxT("Skipped an image as the display is still busy.\n") );
	}
	e.Skip();
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnImportActiveDevice( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxFileDialog fileDlg( this, wxT("Select a filename"), wxT(""), wxT(""), wxT("mv-settings Files (*.xml)|*.xml"), wxOPEN |wxHIDE_READONLY | wxFILE_MUST_EXIST | wxOVERWRITE_PROMPT );
	if( fileDlg.ShowModal() == wxID_OK )
	{
		wxString pathName = fileDlg.GetPath();
		FunctionInterface* p = 0;
		m_pDevPropHandler->GetActiveDevice( &p );
		if( p )
		{
			int result = p->loadSetting( pathName.c_str(),
										 static_cast<TStorageFlag>(0),	// not Native -> to xml file
										 sGlobal );
			if( result == 0 )
			{
				m_pLogWindow->WriteText( wxString::Format( wxT("Importing data from %s successful.\n"), pathName.c_str() ) );
			}
			else
			{
				m_pLogWindow->WriteText( wxString::Format( wxT("Importing data from %s failed(error code: %d(%s)).\n"), pathName.c_str(), result, ImpactAcquireException::getErrorCodeAsString( result ).c_str() ) );
			}
		}
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnPopUpMethExec( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxPGId id = m_pPropGrid->GetSelectedProperty();
	if( id.GetPropertyPtr() )
	{
		string result = (static_cast<MethodObject*>(id.GetPropertyPtr()->GetClientData()))->Call();
		m_pLogWindow->WriteText( wxT(result.c_str()) );
		m_pLogWindow->WriteText( wxT("\n") );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnHistogramAOIxTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pHistogramArea->RefreshData( m_CurrentImage.getBuffer(), m_pSCHistogramAOIx->GetValue() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnHistogramAOIyTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pHistogramArea->RefreshData( m_CurrentImage.getBuffer(), -1, m_pSCHistogramAOIy->GetValue() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnHistogramAOIwTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pHistogramArea->RefreshData( m_CurrentImage.getBuffer(), -1, -1, m_pSCHistogramAOIw->GetValue() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnHistogramAOIhTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pHistogramArea->RefreshData( m_CurrentImage.getBuffer(), -1, -1, -1, m_pSCHistogramAOIh->GetValue() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnLineProfileAOIxTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pLineProfileArea->RefreshData( m_CurrentImage.getBuffer(), m_pSCLineProfileAOIx->GetValue() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnLineProfileAOIyTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pLineProfileArea->RefreshData( m_CurrentImage.getBuffer(), -1, m_pSCLineProfileAOIy->GetValue() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnLineProfileAOIwTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pLineProfileArea->RefreshData( m_CurrentImage.getBuffer(), -1, -1, m_pSCLineProfileAOIw->GetValue() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnLineProfileAOIhTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pLineProfileArea->RefreshData( m_CurrentImage.getBuffer(), -1, -1, -1, m_pSCLineProfileAOIh->GetValue() );
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnLineProfileUpdateSpeedTextChanged( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	m_pLineProfileArea->SetUpdateFrequency( m_pSCLineProfileUpdateSpeed->GetValue() );
}

//-----------------------------------------------------------------------------
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& )
//-----------------------------------------------------------------------------
{
	FunctionInterface* p = 0;
	m_pDevPropHandler->GetActiveDevice( &p );
	if( p )
	{
		p->loadSetting( m_pDevCombo->GetValue().c_str(), sfNative, sUser );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnLoadFromDefault( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	FunctionInterface* p = 0;
	m_pDevPropHandler->GetActiveDevice( &p );
	if( p )
	{
		p->loadSettingFromDefault();
	}
}

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

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

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

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

//-----------------------------------------------------------------------------
void PropViewFrame::OnPropertyRightClicked( wxPropertyGridEvent& e )
//-----------------------------------------------------------------------------
{
	PropData* prop_data = (PropData*)e.GetProperty().GetPropertyPtr()->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( id.GetPropertyPtr() )
			{
				PropData* pData = static_cast<PropData*>(id.GetPropertyPtr()->GetClientData());
				if( pData )
				{
					VectorPropertyObject* pProp = dynamic_cast<VectorPropertyObject*>(pData);
					if( pProp )
					{
						if( !( flags & cfFixedSize ) )
						{
							Property driverProp(pProp->Component());
							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 );
							}
						}
					}
				}
			}
			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().c_str() );
}

//-----------------------------------------------------------------------------
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 )
	{
		p->saveSetting( m_pDevCombo->GetValue().c_str(), sfNative, sUser );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSaveBitmap( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	wxFileDialog fileDlg( this, wxT("Select a filename"), wxT(""), wxT(""), wxT("bitmap files (*.bmp)|*.bmp"), wxSAVE | wxHIDE_READONLY | wxFILE_MUST_EXIST | wxOVERWRITE_PROMPT );
	if( fileDlg.ShowModal() == wxID_OK )
	{
		ImageCanvas::TSaveResult result = m_pDisplayArea->SaveCurrentImageAsBitmap( fileDlg.GetPath() );
		switch( result )
		{
		case ImageCanvas::srOK:
			m_pLogWindow->WriteText( wxString::Format( wxT("Storing of %s successful.\n"), fileDlg.GetPath().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"), fileDlg.GetPath().c_str() ) );
			break;
		default:
			m_pLogWindow->WriteText( wxString::Format( wxT("Storing of %s return unexpected value: %d.\n"), fileDlg.GetPath().c_str(), result ) );
			break;
		}	
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSaveToDefault( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	FunctionInterface* p = 0;
	m_pDevPropHandler->GetActiveDevice( &p );
	if( p )
	{
		p->saveSettingToDefault();
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnSaveSystemToDefault( wxCommandEvent& )
//-----------------------------------------------------------------------------
{
	FunctionInterface* p = 0;
	m_pDevPropHandler->GetActiveDevice( &p );
	if( p )
	{
		p->saveSystemToDefault();
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::OnScaleDisplay( wxCommandEvent& e )
//-----------------------------------------------------------------------------
{
	m_pDisplayArea->SetScaling( e.IsChecked() );
	m_pMISettingsDisplayScale->Check( e.IsChecked() );
	GetToolBar()->ToggleTool( miSettingsDisplay_Scale, e.IsChecked() );
}

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

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

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

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

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

//-----------------------------------------------------------------------------
void PropViewFrame::OnSize(wxSizeEvent& e)
//-----------------------------------------------------------------------------
{
	if( m_pDisplayArea )
	{
		m_pDisplayArea->Refresh( false );
	}
	if( m_pHistogramArea )
	{
		m_pHistogramArea->Refresh( false );
	}
	if( m_pLineProfileArea )
	{
		m_pLineProfileArea->Refresh( false );
	}
	e.Skip();
}

//-----------------------------------------------------------------------------
void PropViewFrame::UpdatePropGridSplitter( )
//-----------------------------------------------------------------------------
{
	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;
	}

	if( m_pMISettingsDisplayLogWindow->IsChecked() || !m_boDisplayWindowMaximized )
	{
		SetupDisplayLogSplitter( !m_boDisplayWindowMaximized );
	}

	if( m_pMISettingsPropGrid_Show->IsChecked() || !m_boDisplayWindowMaximized )
	{
		SetupVerSplitter( !m_boDisplayWindowMaximized );
	}
	m_pMISettingsPropGrid_Show->Check( !m_boDisplayWindowMaximized );
	m_pMISettingsDisplayLogWindow->Check( !m_boDisplayWindowMaximized );
	GetToolBar()->ToggleTool( miSettings_ShowLogWindow, !m_boDisplayWindowMaximized );
	GetToolBar()->ToggleTool( miSettingsPropGrid_Show, !m_boDisplayWindowMaximized );
	m_pDisplayArea->Refresh( true );
}

//-----------------------------------------------------------------------------
void PropViewFrame::SetupDlgControls( void )
//-----------------------------------------------------------------------------
{
	const Device* pDev = m_pDevPropHandler->GetActiveDevice();
	bool boDevOpen = false;
	bool boDevPresent = false;
	bool boDevLive = false;
	if( pDev )
	{
		boDevOpen = pDev->isOpen();
		boDevPresent = ( pDev->state.read() == 1 );
		CaptureThread* pThread = 0;
		m_pDevPropHandler->GetActiveDevice( 0, 0, &pThread );
		if( pThread )
		{
			boDevLive = pThread->GetLiveMode();
		}
	}

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

	bool isDeviceSelected = m_pDevCombo->GetValue() != m_NoDevStr;
	m_pMIUse->Enable( isDeviceSelected );
	GetToolBar()->EnableTool( miAction_UseDevice, isDeviceSelected );
	m_pMIUse->Check( boDevOpen );
	GetToolBar()->ToggleTool( miAction_UseDevice, boDevOpen );
	m_pMISaveToDefault->Enable( boDevOpen );
	m_pMISaveSystemToDefault->Enable( boDevOpen );
	m_pMISaveActiveDevice->Enable( boDevOpen );
	m_pMIExportActiveDevice->Enable( boDevOpen );
	m_pMILoadFromDefault->Enable( boDevOpen );
	m_pMILoadActiveDevice->Enable( boDevOpen );
	m_pMIImportActiveDevice->Enable( boDevOpen );
	m_pMIActionSaveBitmap->Enable( boDevOpen && !boDevLive );
	m_pMICaptureLive->Enable( boDevOpen && boDevPresent && !boDevLive );
	m_pMICaptureSnap->Enable( boDevOpen && boDevPresent && !boDevLive );
	m_pMICaptureStop->Enable( boDevOpen && boDevPresent && boDevLive );
	m_pMICaptureAbort->Enable( boDevOpen && boDevPresent );
	
	m_pToolBar->EnableTool(miCapture_Abort, m_pMICaptureAbort->IsEnabled());
	m_pToolBar->EnableTool(miCapture_Live, m_pMICaptureLive->IsEnabled());
	m_pToolBar->EnableTool(miCapture_Stop, m_pMICaptureStop->IsEnabled());
	m_pToolBar->EnableTool(miCapture_Snap, m_pMICaptureSnap->IsEnabled());
}

//-----------------------------------------------------------------------------
void PropViewFrame::SetupDisplayLogSplitter( bool boSplit )
//-----------------------------------------------------------------------------
{
	if( boSplit )
	{
		m_pHorizontalSplitter->SplitHorizontally( m_pDisplayArea, m_pLowerRightWindow, 0 );
		m_pHorizontalSplitter->SetSashPosition( m_HorizontalSplitterPos );		
	}
	else
	{
		m_HorizontalSplitterPos = m_pHorizontalSplitter->GetSashPosition();
		m_pHorizontalSplitter->Unsplit(m_pLowerRightWindow);
	}
}

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

//-----------------------------------------------------------------------------
void PropViewFrame::UpdateDeviceComboBox( void )
//-----------------------------------------------------------------------------
{
	const DeviceManager& devMgr = m_pDevPropHandler->GetDevMgr();
	bool boDisplayConnectedOnly = m_pMISettingsConnectedOnly->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(devMgr[i]->serial.read().c_str());
			}
		}
		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().c_str() );
	}
	UpdateTitle();
	UpdateData();
}

//-----------------------------------------------------------------------------
void PropViewFrame::UpdateStatusBar( void )
//-----------------------------------------------------------------------------
{
	const Statistics* pS = 0;
	FunctionInterface* pFI = 0;
	m_pDevPropHandler->GetActiveDevice( &pFI, &pS );

	if( pFI && pS )
	{
		if( m_pStatusBar->GetFieldsCount() != NO_OF_STATUSBAR_FIELDS )
		{
			int	statusBarFieldWidths[NO_OF_STATUSBAR_FIELDS];
			statusBarFieldWidths[sbfFPS] = -2;
			statusBarFieldWidths[sbfFrameCount] = -2;
			statusBarFieldWidths[sbfImageFormat] = -5;
			statusBarFieldWidths[sbfErrorCount] = -2;
			statusBarFieldWidths[sbfExposeTime] = -3;
			statusBarFieldWidths[sbfGain] = -3;
			m_pStatusBar->SetFieldsCount( NO_OF_STATUSBAR_FIELDS, &statusBarFieldWidths[0] );
		}

		bool boSlowDisplay = ( m_CurrentImage.getBuffer()->pixelFormat != ibpfMono8 ) && ( m_CurrentImage.getBuffer()->pixelFormat != ibpfRGBx888Packed ) && ( m_CurrentImage.getBuffer()->pixelFormat != ibpfRGB888Packed ); 
		m_pStatusBar->SetStatusText( wxString::Format(wxT("Frames/sec.: %.1f"), pS->framesPerSecond.read() ), sbfFPS );
		m_pStatusBar->SetStatusText( wxString::Format(wxT("Frame count: %d"), pS->frameCount.read() ), sbfFrameCount );
		m_pStatusBar->SetStatusText( wxString::Format(wxT("ImageFormat %dx%d, %s%s"), m_CurrentImage.getBuffer()->iWidth, m_CurrentImage.getBuffer()->iHeight, m_CurrentPixelFormat.c_str(), boSlowDisplay ? wxT("(slow display because of conversion)"): "" ), sbfImageFormat );
		m_pStatusBar->SetStatusText( wxString::Format(wxT("Error count: %d"), pS->errorCount.read() ), sbfErrorCount );
		m_pStatusBar->SetStatusText( wxString::Format(wxT("Expose time(us): %d"), m_CurrentRequestInfo.exposeTime_us ), sbfExposeTime );
		m_pStatusBar->SetStatusText( wxString::Format(wxT("Gain(dB): %.4f"), m_CurrentRequestInfo.gain_dB ), sbfGain );
	}
	else
	{
		if( m_pStatusBar->GetFieldsCount() != 1 )
		{
			m_pStatusBar->SetFieldsCount( 1, 0 );
		}
		m_pStatusBar->SetStatusText( wxT("no statistics available"), 0 );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::UpdateTitle( void )
//-----------------------------------------------------------------------------
{
	SetTitle( wxString::Format( wxT("wxPropView(%s) [%s]"), VERSION_STRING, m_pDevCombo->GetValue().c_str() ) );
}

//-----------------------------------------------------------------------------
void PropViewFrame::WriteLogMessage( const wxString& msg, const wxTextAttr& style )
//-----------------------------------------------------------------------------
{
	if( m_pLogWindow )
	{
		long posBefore = m_pLogWindow->GetLastPosition();
		m_pLogWindow->WriteText( msg );
		long posAfter = m_pLogWindow->GetLastPosition();
		m_pLogWindow->SetStyle( posBefore, posAfter, style );
	}
}

//-----------------------------------------------------------------------------
void PropViewFrame::WriteErrorMessage( const wxString& msg )
//-----------------------------------------------------------------------------
{
	wxTextAttr errorStyle( wxColour(255, 0, 0) );
	WriteLogMessage( msg, errorStyle );
}
