///////////////////////////////////////////////////////////////////////////// // Name: viacamcontroller.cpp // Purpose: // Author: Cesar Mauri Loba (cesar at crea-si dot com) // Modified by: // Created: // Copyright: (C) 2008-14 Cesar Mauri Loba - CREA Software Systems // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . ///////////////////////////////////////////////////////////////////////////// #include "viacamcontroller.h" #include "wviacam.h" #include "crvcamera_enum.h" #include "crvcamera.h" #include "pointeraction.h" #include "camwindow.h" #include "wconfiguration.h" #include "cmotioncalibration.h" #include "wcameradialog.h" #include "eviacamdefs.h" #include "configmanager.h" #include "cautostart.h" #include "hotkeymanager.h" #include "simplelog.h" #include "newtrackerinformationdlg.h" #include "checkupdates_manager.h" #include #include #include using namespace eviacam; CViacamController::CViacamController(void) : m_pMainWindow(NULL) , m_pCamera(NULL) , m_pCaptureThread(NULL) , m_pointerAction(NULL) , m_visionPipeline() , m_hotKeyManager(NULL) , m_configManager(NULL) , m_locale(NULL) , m_pAutostart(NULL) , m_pConfiguration(NULL) , m_pMotionCalibration(NULL) , m_wizardManager() , m_pCameraDialog(NULL) , m_wConfigurationListener(*this) , m_wCameraDialogListener(*this) , m_pCheckUpdateManager(NULL) , m_cameraName() , m_enabled(false) , m_enabledAtStartup(false) , m_languageId(wxLANGUAGE_DEFAULT) , m_onScreenKeyboardCommand() , m_frameRate(0) , m_motionCalibrationEnabled(false) , m_runWizardAtStartup(false) , m_newTrackerDialogAtStartup(true) , m_checkUpdatesAtStartup(true) { m_locale= new wxLocale (); m_configManager= new CConfigManager(this); InitDefaults(); } void CViacamController::InitDefaults() { m_runWizardAtStartup= true; m_languageId= wxLANGUAGE_DEFAULT; m_enabledAtStartup= false; #if defined(__WXMSW__) m_onScreenKeyboardCommand= _T("osk.exe"); #endif } CViacamController::~CViacamController(void) { assert (!m_pCaptureThread && !m_pCamera && !m_pCaptureThread); delete m_pointerAction; #if defined(__WXGTK__) delete m_pAutostart; #endif delete m_locale; delete m_configManager; delete m_pMotionCalibration; delete m_hotKeyManager; } void CViacamController::SetUpLanguage () { assert (m_locale); m_languageId= m_configManager->ReadLanguage (); m_locale->AddCatalogLookupPathPrefix(wxT(".")); #if defined(__WXGTK__) m_locale->AddCatalogLookupPathPrefix(wxT("/usr/local/share/locale/")); #endif if (!m_locale->Init(m_languageId)) slog_write (SLOG_PRIO_WARNING, "Cannot load locale. Switching to default locale.\n"); m_locale->AddCatalog(wxT("wxstd")); m_locale->AddCatalog(wxT("eviacam")); } void CViacamController::SetLanguage (const int id) { // Simply store new language id if (id!= m_languageId) { // Check if valid const wxLanguageInfo *info= wxLocale::GetLanguageInfo (id); if (info) { m_languageId= id; } else { assert (false); } } } CCamera* CViacamController::SetUpCamera() { CCamera* cam; int numDevices; int camId= -1; // Load app local data ReadAppData(wxConfigBase::Get()); numDevices= CCameraEnum::GetNumDevices (); if (numDevices== 0) { wxMessageDialog errorMsg (NULL, _("Not detected any camera. Aborting"), _T("Enable Viacam"), wxOK | wxICON_ERROR); errorMsg.ShowModal(); return NULL; } // Try to find previously used camera if (m_cameraName.Length()> 0) { for (camId= 0; camId< numDevices; camId++) if (wxString(CCameraEnum::GetDeviceName (camId), wxConvLibc)== m_cameraName) break; if (camId== numDevices) camId= -1; // Not found } // Show selection dialog when needed if (camId== -1) { if(numDevices > 1) { wxArrayString strArray; for (camId= 0; camId< numDevices; camId++) strArray.Add (wxString(CCameraEnum::GetDeviceName (camId), wxConvLibc)); wxSingleChoiceDialog choiceDlg(NULL, _("Choose the camera to use"), _T("Enable Viacam"), strArray, (char**)NULL, wxDEFAULT_DIALOG_STYLE | wxOK | wxCANCEL | wxCENTRE); if (choiceDlg.ShowModal ()!= wxID_OK) return NULL; camId= choiceDlg.GetSelection(); m_cameraName= choiceDlg.GetStringSelection (); } else { camId= 0; m_cameraName= wxString(CCameraEnum::GetDeviceName (camId), wxConvLibc); } } cam= CCameraEnum::GetCamera(camId); if (!cam) return NULL; cam->SetHorizontalFlip (true); // Try to open the camera to ensure it works if (!cam->Open ()) { wxMessageDialog errorMsg (NULL, _("Can not initialize the camera.\nPerhaps is being used by other application."), _T("Enable Viacam"), wxOK | wxICON_ERROR); errorMsg.ShowModal(); delete cam; cam= NULL; ChangeCamera(); } else cam->Close(); WriteAppData(wxConfigBase::Get()); wxConfigBase::Get()->Flush(); return cam; } bool CViacamController::Initialize () { bool retval= true; assert (!m_pMainWindow && !m_pCamera && !m_pCaptureThread); SetUpLanguage (); // Is the first time eviacam is executed on this computer? if (!wxConfigBase::Get()->Exists(_T("/settings/default"))) m_newTrackerDialogAtStartup = false; // Create camera object m_pCamera= SetUpCamera(); if (m_pCamera== NULL) retval= false; if (retval) { // TODO: check this!!! assert (!m_pMotionCalibration); m_pMotionCalibration= new CMotionCalibration(); //this); #if defined(__WXGTK__) assert (!m_pAutostart); m_pAutostart = new CAutostart(wxT("eviacam.desktop")); #endif } // Create main window if (retval) { m_pMainWindow = new WViacam( NULL, ID_WVIACAM ); assert (m_pMainWindow); m_pMainWindow->Show (true); } // Create hotkey manager if (retval) { assert (!m_hotKeyManager); m_hotKeyManager= new CHotkeyManager(); } // Create pointer action object if (retval) { assert (!m_pointerAction); m_pointerAction= new CPointerAction(); } // Create and start worker thread if (retval) { m_pCaptureThread = new CCaptureThread (m_pCamera, m_pMainWindow->GetCamWindow(), this, wxTHREAD_JOINABLE ); assert (m_pCaptureThread); if (m_pCaptureThread->Create()!= wxTHREAD_NO_ERROR) retval= false; if (retval) { // Fire thread m_pCaptureThread->SetPriority (WXTHREAD_MAX_PRIORITY); if (m_pCaptureThread->Run() != wxTHREAD_NO_ERROR) retval= false; } } // Register track area if (retval) m_pMainWindow->GetCamWindow()->RegisterControl (m_visionPipeline.GetTrackAreaControl()); // Load configuration if (retval) m_configManager->ReadAll (); // Enable pointeraction object if (retval && m_enabledAtStartup) SetEnabled(true); if (retval) m_pointerAction->SetEnabled(true); // Check for updates if (retval && m_checkUpdatesAtStartup) { assert(m_pCheckUpdateManager == NULL); m_pCheckUpdateManager = new CheckUpdatesManager(m_pMainWindow); m_pCheckUpdateManager->LaunchBackground(); } // Show new tracker information dialog when needed if (retval && m_newTrackerDialogAtStartup) { NewTrackerInformationDlg dlg(m_pMainWindow); dlg.ShowModal(); } // Run the wizard at startup if (retval && m_runWizardAtStartup) StartWizard(); return retval; } void CViacamController::Finalize () { SetEnabled (false, true); if (m_pCaptureThread) { // Save config m_configManager->WriteAll(); m_pCaptureThread->Finish(); m_pCaptureThread->Wait(); delete m_pCaptureThread; m_pCaptureThread= NULL; } if (m_pCamera) { delete m_pCamera; m_pCamera= NULL; } if (m_pointerAction) { m_pointerAction->SetEnabled(false); delete m_pointerAction; m_pointerAction= NULL; } if (m_hotKeyManager) { delete m_hotKeyManager; m_hotKeyManager= NULL; } if (m_pCheckUpdateManager) { delete m_pCheckUpdateManager; m_pCheckUpdateManager = NULL; } if (m_pMainWindow) { WViacam* mainWin= m_pMainWindow; m_pMainWindow= NULL; mainWin->GetCamWindow()->UnregisterControl (m_visionPipeline.GetTrackAreaControl()); mainWin->Close (true); // Main window is self-destroyed } } void CViacamController::WriteAppData(wxConfigBase* pConfObj) { // General options m_configManager->WriteLanguage (m_languageId); pConfObj->Write(_T("cameraName"), m_cameraName); pConfObj->Write(_T("newTrackerDialogAtStartup"), m_newTrackerDialogAtStartup); pConfObj->Write(_T("checkUpdatesAtStartup"), m_checkUpdatesAtStartup); } void CViacamController::WriteProfileData(wxConfigBase* pConfObj) { pConfObj->Write(_T("enabledAtStartup"), m_enabledAtStartup); pConfObj->Write(_T("onScreenKeyboardCommand"), m_onScreenKeyboardCommand); pConfObj->Write(_T("runWizardAtStartup"), m_runWizardAtStartup); // Propagates calls m_pointerAction->WriteProfileData (pConfObj); m_visionPipeline.WriteProfileData (pConfObj); m_hotKeyManager->WriteProfileData (pConfObj); } void CViacamController::ReadAppData(wxConfigBase* pConfObj) { // General options SetLanguage (m_configManager->ReadLanguage()); // Only load, dont't apply pConfObj->Read(_T("cameraName"), &m_cameraName); pConfObj->Read(_T("newTrackerDialogAtStartup"), &m_newTrackerDialogAtStartup); pConfObj->Read(_T("checkUpdatesAtStartup"), &m_checkUpdatesAtStartup); } void CViacamController::ReadProfileData(wxConfigBase* pConfObj) { pConfObj->Read(_T("enabledAtStartup"), &m_enabledAtStartup); pConfObj->Read(_T("onScreenKeyboardCommand"), &m_onScreenKeyboardCommand); pConfObj->Read(_T("runWizardAtStartup"), &m_runWizardAtStartup); // Propagates calls m_pointerAction->ReadProfileData (pConfObj); m_visionPipeline.ReadProfileData (pConfObj); m_hotKeyManager->ReadProfileData (pConfObj); } void CViacamController::SetEnabled (bool value, bool silent, wxWindow* parent) { if (value!= m_enabled) { if (value== false && !silent) { wxMessageDialog dlg (parent, _("This action will disable eViacam.\nAre you sure?"), _("eViacam warning"), wxICON_EXCLAMATION | wxYES_NO ); if (dlg.ShowModal()== wxID_NO) return; } if (value) { // Enable, reset counters m_pointerAction->ResetCounters(); } m_enabled= value; } } void CViacamController::OpenConfiguration() { if (!m_pConfiguration) { m_pConfiguration = new WConfiguration(m_pMainWindow); //, this); m_pConfiguration->Connect ( wxEVT_DESTROY, wxWindowDestroyEventHandler(CViacamController::WConfigurationListener::OnDestroy), NULL, &m_wConfigurationListener); } m_pConfiguration->Show(true); } void CViacamController::OpenOnScreenKeyboard() { if (m_onScreenKeyboardCommand.IsEmpty()) { wxMessageDialog dlg (NULL, _("On-screen keyboard command not set.\nPlease, configure it through options dialog."), _("eViacam error"), wxOK | wxICON_ERROR); dlg.ShowModal(); } else { if (wxExecute (m_onScreenKeyboardCommand)== 0) { wxString errMsg; errMsg.Printf (_("Can't execute on-screen keyboard program.\nCommand %s failed.\nPlease, configure it through options dialog."), m_onScreenKeyboardCommand.c_str()); #if defined(__WXMSW__) errMsg.Append (_("\n\nOn Windows Vista/7 several problems have been reported\nwith the system's default on-screen keyboard (osk). These\nissues are under investigation. Meanwhile you might want\nto disable User Account Control (UAC) to avoid such problems\nor try another osk, e.g. Click-N-Type.")); #endif wxMessageDialog dlg (NULL, errMsg, _("eViacam error"), wxOK | wxICON_ERROR); dlg.ShowModal(); } } } void CViacamController::ProcessImage (IplImage *pImage) { WViacam::EFPSCondition cond; long iFrameRate; float vx, vy; CIplImage image(pImage); bool allowedByFaceLocalizationSystem; // Refresh fps meter m_frameRate= 0.5f * m_pCamera->GetRealFrameRate() + 0.5f * m_frameRate; iFrameRate= (long) (m_frameRate + 0.5f); if (iFrameRate< 20) cond= WViacam::POOR; else if (iFrameRate< 25) cond= WViacam::FAIR; else cond= WViacam::GOOD; m_pMainWindow->SetFPS (iFrameRate, cond); // Proces frame allowedByFaceLocalizationSystem = m_visionPipeline.ProcessImage (image, vx, vy); if ((m_enabled && allowedByFaceLocalizationSystem) || m_motionCalibrationEnabled) { // Send mouse motion BEGIN_GUI_CALL_MUTEX() if (m_motionCalibrationEnabled) m_pMotionCalibration->ComputeMotionRange (-vx, vy, !(m_visionPipeline.GetTrackFace() && !m_visionPipeline.IsFaceDetected())); else m_pointerAction->ProcessMotion (-vx, vy); END_GUI_CALL_MUTEX() } m_hotKeyManager->CheckKeyboardStatus(); } bool CViacamController::StartMotionCalibration (void) { return m_pMotionCalibration->InitMotionCalibration(); } void CViacamController::StartWizard() { m_wizardManager.Open (m_pMainWindow); } const wxString& CViacamController::GetCameraName () const { return m_cameraName; } const bool CViacamController::CameraHasSettingsDialog () const { return (m_pCamera->HasSettingsDialog() || m_pCamera->HasCameraControls()); } void CViacamController::ChangeCamera () { m_cameraName.Clear(); } void CViacamController::ShowCameraSettingsDialog () { if (m_enabled && !m_pCameraDialog) { wxMessageDialog dlg ( NULL, _("Note that adjusting the camera controls while eViacam\nis enabled may cause loss of pointer control.\nAre you sure you want to continue?"), _T("Enable Viacam"), wxICON_EXCLAMATION | wxYES_NO ); if (dlg.ShowModal()== wxID_NO) return; } if (m_pCamera->HasSettingsDialog()) m_pCamera->ShowSettingsDialog (); if (m_pCamera->HasCameraControls()) { if (!m_pCameraDialog) { m_pCameraDialog = new WCameraDialog(m_pMainWindow, m_pCamera); m_pCameraDialog->Connect ( wxEVT_DESTROY, wxWindowDestroyEventHandler(CViacamController::WCameraDialogListener::OnDestroy), NULL, &m_wCameraDialogListener); m_pCameraDialog->Show(true); } m_pCameraDialog->Raise(); } }