From cc9689735156b654797bbcc29d135c11bb2543c1 Mon Sep 17 00:00:00 2001 From: Tobias Baumann Date: Tue, 24 May 2022 13:27:51 +0000 Subject: [PATCH] =?UTF-8?q?Dateien=20hochladen=20nach=20=E2=80=9Esrc/Tacti?= =?UTF-8?q?leVisualization=E2=80=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...pCBoxAlgorithmP300TactileVisualization.cpp | 1083 ++++++----------- ...ovpCBoxAlgorithmP300TactileVisualization.h | 292 ++--- 2 files changed, 485 insertions(+), 890 deletions(-) diff --git a/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.cpp b/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.cpp index ffba376..4ca66e2 100644 --- a/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.cpp +++ b/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.cpp @@ -1,32 +1,9 @@ -///------------------------------------------------------------------------------------------------- -/// -/// \file ovpCBoxAlgorithmP300TactileVisualization.cpp -/// \brief Functions of the Class P300TactileVisualization. !!This is a modification of the P300 Speller Visualization Box!! -/// \author Tobias Baumann (TH Nuernberg). -/// \version 1.0. -/// \date Mon Feb 04 12:43:53 2022. -/// \copyright GNU Affero General Public License v3.0 -/// -///------------------------------------------------------------------------------------------------- - -//includes #include "ovpCBoxAlgorithmP300TactileVisualization.h" -#include -#include -#include -#include -#include - -namespace OpenViBE { -namespace Plugins { -namespace Tactilebci { - -static void ToggleButtonShowHideCB(GtkToggleToolButton* button, gpointer data) -{ - if (gtk_toggle_tool_button_get_active(button)) { gtk_widget_show(GTK_WIDGET(data)); } - else { gtk_widget_hide(GTK_WIDGET(data)); } -} +using namespace OpenViBE; +using namespace /*OpenViBE::*/Kernel; +using namespace /*OpenViBE::*/Plugins; +using namespace /*OpenViBE::Plugins::*/Tactilebci; // This callback flushes all accumulated stimulations to the TCP Tagging // after the rendering has completed. @@ -39,790 +16,454 @@ static gboolean FlushCB(gpointer data) bool CBoxAlgorithmP300TactileVisualization::initialize() { - const Kernel::IBox& boxContext = this->getStaticBoxContext(); - - m_mainWidgetInterface = nullptr; - m_toolbarWidgetInterface = nullptr; - m_flashFontDesc = nullptr; - m_noFlashFontDesc = nullptr; - m_targetFontDesc = nullptr; - m_selectedFontDesc = nullptr; - - // ---------------------------------------------------------------------------------------------------------------------------------------------------------- - - m_interfaceFilename = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0); - m_rowStimulationBase = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1); - m_columnStimulationBase = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2); - - m_flashBgColor = CGdkcolorAutoCast(boxContext, this->getConfigurationManager(), 3); - m_flashFgColor = CGdkcolorAutoCast(boxContext, this->getConfigurationManager(), 4); - m_flashFontSize = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 5); - m_noFlashBgColor = CGdkcolorAutoCast(boxContext, this->getConfigurationManager(), 6); - m_noFlashFgColor = CGdkcolorAutoCast(boxContext, this->getConfigurationManager(), 7); - m_noFlashFontSize = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 8); - m_targetBgColor = CGdkcolorAutoCast(boxContext, this->getConfigurationManager(), 9); - m_targetFgColor = CGdkcolorAutoCast(boxContext, this->getConfigurationManager(), 10); - m_targetFontSize = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 11); - m_selectedBgColor = CGdkcolorAutoCast(boxContext, this->getConfigurationManager(), 12); - m_selectedFgColor = CGdkcolorAutoCast(boxContext, this->getConfigurationManager(), 13); - m_selectedFontSize = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 14); + // ------ Init decoder/encoder + m_SequenceInputDecoder.initialize(*this, 0); + m_TargetInputDecoder.initialize(*this, 1); + m_ResultInputDecoder.initialize(*this, 2); + m_ResultOutputEncoder.initialize(*this, 0); - m_nTactilos = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 15); - - //set m_nTactilos to 2 if lower than 2 + // ------ Get box settings + m_InterfaceFilename = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0); + m_RowBase = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1); + m_nTactilos = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2); + m_FreeSpelling = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 3); + + //set m_nTactilos minimum number of 2, if lower if(m_nTactilos < 2) { m_nTactilos = 2; } - //set m_nTactilos to MAX if greater than MAX_TACTILOS + + //set m_nTactilos maximum number of MAX_TACTILOS(10), if higher if(m_nTactilos > MAX_TACTILOS) { m_nTactilos = MAX_TACTILOS; } - - // ---------------------------------------------------------------------------------------------------------------------------------------------------------- - - m_sequenceStimulationDecoder = &this->getAlgorithmManager().getAlgorithm( - this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StimulationDecoder)); - m_sequenceStimulationDecoder->initialize(); - - m_targetStimulationDecoder = &this->getAlgorithmManager().getAlgorithm( - this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StimulationDecoder)); - m_targetStimulationDecoder->initialize(); - - m_targetFlaggingStimulationEncoder = &this->getAlgorithmManager().getAlgorithm( - this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StimulationEncoder)); - m_targetFlaggingStimulationEncoder->initialize(); - - m_rowSelectionStimulationDecoder = &this->getAlgorithmManager().getAlgorithm( - this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StimulationDecoder)); - m_rowSelectionStimulationDecoder->initialize(); - - m_columnSelectionStimulationDecoder = &this->getAlgorithmManager().getAlgorithm( - this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StimulationDecoder)); - m_columnSelectionStimulationDecoder->initialize(); - - m_sequenceMemoryBuffer.initialize( - m_sequenceStimulationDecoder->getInputParameter(OVP_GD_Algorithm_StimulationDecoder_InputParameterId_MemoryBufferToDecode)); - m_sequenceStimulationSet.initialize( - m_sequenceStimulationDecoder->getOutputParameter(OVP_GD_Algorithm_StimulationDecoder_OutputParameterId_StimulationSet)); - - m_targetMemoryBuffer.initialize( - m_targetStimulationDecoder->getInputParameter(OVP_GD_Algorithm_StimulationDecoder_InputParameterId_MemoryBufferToDecode)); - m_targetStimulationSet.initialize( - m_targetStimulationDecoder->getOutputParameter(OVP_GD_Algorithm_StimulationDecoder_OutputParameterId_StimulationSet)); - - m_targetFlaggingStimulationSet.initialize( - m_targetFlaggingStimulationEncoder->getInputParameter(OVP_GD_Algorithm_StimulationEncoder_InputParameterId_StimulationSet)); - m_targetFlaggingMemoryBuffer.initialize( - m_targetFlaggingStimulationEncoder->getOutputParameter(OVP_GD_Algorithm_StimulationEncoder_OutputParameterId_EncodedMemoryBuffer)); - - m_lastTime = 0; - - m_stimulusSender = nullptr; - - m_idleFuncTag = 0; - m_stimuliQueue.clear(); - - m_mainWidgetInterface = gtk_builder_new(); // glade_xml_new(m_interfaceFilename.toASCIIString(), "p300-speller-main", nullptr); - if (!gtk_builder_add_from_file(m_mainWidgetInterface, m_interfaceFilename.toASCIIString(), nullptr)) - { - this->getLogManager() << Kernel::LogLevel_ImportantWarning << "Could not load interface file [" << m_interfaceFilename << "]\n"; - this->getLogManager() << Kernel::LogLevel_ImportantWarning << - "The file may be missing. However, the interface files now use gtk-builder instead of glade. Did you update your files ?\n"; - return false; - } - - m_toolbarWidgetInterface = gtk_builder_new(); // glade_xml_new(m_interfaceFilename.toASCIIString(), "p300-speller-toolbar", nullptr); - gtk_builder_add_from_file(m_toolbarWidgetInterface, m_interfaceFilename.toASCIIString(), nullptr); - - m_mainWindow = GTK_WIDGET(gtk_builder_get_object(m_mainWidgetInterface, "p300-speller-main")); - m_toolbarWidget = GTK_WIDGET(gtk_builder_get_object(m_toolbarWidgetInterface, "p300-speller-toolbar")); - m_table = GTK_TABLE(gtk_builder_get_object(m_mainWidgetInterface, "p300-speller-table")); - m_result = GTK_LABEL(gtk_builder_get_object(m_mainWidgetInterface, "label-result")); - m_target = GTK_LABEL(gtk_builder_get_object(m_mainWidgetInterface, "label-target")); - //Begin Menu Initialization ------------------------------------------------------------------------------------- - if(m_nTactilos == 6) //Create Menus for m_nTactilos = 6 + // ------ Setup acquisition server TCP tagging + m_stimuliQueue.clear(); + m_stimulusSender = TCPTagging::CreateStimulusSender(); + if(!m_stimulusSender->connect("localhost", "15361")) { - m_Menu.push_back(TactileMenu(6)); - m_Menu[0].set_LabelText(0, "Ja"); - m_Menu[0].set_LabelText(1, "Nein"); - m_Menu[0].set_LabelText(2, "Pflege"); - m_Menu[0].set_LabelText(3, "Hilfe"); - m_Menu[0].set_LabelText(4, "Geräte"); - m_Menu[0].set_LabelText(5, "Funktionen"); - - m_Menu.push_back(TactileMenu(6)); - m_Menu[1].set_LabelText(0, "Ja"); - m_Menu[1].set_LabelText(1, "Nein"); - m_Menu[1].set_LabelText(2, "Hunger"); - m_Menu[1].set_LabelText(3, "Lage"); - m_Menu[1].set_LabelText(4, "Müdigkeit"); - m_Menu[1].set_LabelText(5, "Hauptmenü"); - - m_Menu.push_back(TactileMenu(6)); - m_Menu[2].set_LabelText(0, "Ja"); - m_Menu[2].set_LabelText(1, "Nein"); - m_Menu[2].set_LabelText(2, "Schmerzen"); - m_Menu[2].set_LabelText(3, "Atemnot"); - m_Menu[2].set_LabelText(4, "Anderes"); - m_Menu[2].set_LabelText(5, "Hauptmenü"); - - m_Menu.push_back(TactileMenu(6)); - m_Menu[3].set_LabelText(0, "Ja"); - m_Menu[3].set_LabelText(1, "Nein"); - m_Menu[3].set_LabelText(2, "Atemgerät"); - m_Menu[3].set_LabelText(3, "Rollstuhl"); - m_Menu[3].set_LabelText(4, "Computer"); - m_Menu[3].set_LabelText(5, "Hauptmenü"); - - //Set SubMenu ptr - m_Menu[0].set_SubMenu(2, &m_Menu[1]); - m_Menu[0].set_SubMenu(3, &m_Menu[2]); - m_Menu[0].set_SubMenu(4, &m_Menu[3]); - m_Menu[1].set_SubMenu(5, &m_Menu[0]); - m_Menu[2].set_SubMenu(5, &m_Menu[0]); - m_Menu[3].set_SubMenu(5, &m_Menu[0]); - - //Set current menu ptr to Mainmenu - m_currMenu = &m_Menu[0]; + this->getLogManager() << LogLevel_Warning << "Failed to connect to acquisition server TCP tagging.\n"; } - else //Create default menu for m_nTactilos != 6 + + // ------ Gtk variables + // Build main UI elements + m_MainWidgetInterface = gtk_builder_new(); + if(!gtk_builder_add_from_file(m_MainWidgetInterface, m_InterfaceFilename.toASCIIString(), nullptr))//error + { + this->getLogManager() << LogLevel_ImportantWarning << "Failed to load UI file [" << m_InterfaceFilename << "]\n"; + this->getLogManager() << LogLevel_ImportantWarning << "Make sure, that the given filename and path are correct\n"; + return(false); + } + m_MainWindow = GTK_WIDGET(gtk_builder_get_object(m_MainWidgetInterface, "p300-tactile-main")); + m_Table = GTK_TABLE(gtk_builder_get_object(m_MainWidgetInterface, "p300-tactile-table")); + m_ResultLabel = GTK_LABEL(gtk_builder_get_object(m_MainWidgetInterface, "label-result")); + m_TargetLabel = GTK_LABEL(gtk_builder_get_object(m_MainWidgetInterface, "label-target")); + + // Create font description + m_FontDesc = pango_font_description_copy(pango_context_get_font_description(gtk_widget_get_pango_context(m_MainWindow))); + pango_font_description_set_size(m_FontDesc, gint(FontSize*PANGO_SCALE)); + + // test if the UI-file fits the number of tactilos + guint nRow = 0; + g_object_get(m_Table, "n-rows", &nRow, nullptr); + if(m_nTactilos != nRow) + { + this->getLogManager() << LogLevel_ImportantWarning << "The number of tactilos " << m_nTactilos<<" used and the number of rows "<< nRow << " in the ui file must be the same.\n"; + this->getLogManager() << LogLevel_ImportantWarning << "Make sure to choose the right UI-File, e.g. p300-tactile-6.ui for 6 tactilos\n"; + return(false); + } + else + { + for(uint64_t i = 0; i < m_nTactilos; i++) + { + std::string eventbox_id = "eventbox-" + std::to_string(i+1); + + m_EventBox.push_back(GTK_WIDGET(gtk_builder_get_object(m_MainWidgetInterface, eventbox_id.c_str()))); + } + } + + // ------ Setup tactile UI + //Create UI for m_nTactilos = 6 + if(m_nTactilos == 6) + { + //create free spelling UI for 6 tactilos + if(m_FreeSpelling) + { + m_Menu.push_back(TactileMenu(6)); + m_Menu[0].set_LabelText(0, "Ja"); + m_Menu[0].set_LabelText(1, "Nein"); + m_Menu[0].set_LabelText(2, "Pflege"); + m_Menu[0].set_LabelText(3, "Hilfe"); + m_Menu[0].set_LabelText(4, "Geräte"); + m_Menu[0].set_LabelText(5, "Funktionen"); + + m_Menu.push_back(TactileMenu(6)); + m_Menu[1].set_LabelText(0, "Ja"); + m_Menu[1].set_LabelText(1, "Nein"); + m_Menu[1].set_LabelText(2, "Hunger"); + m_Menu[1].set_LabelText(3, "Lage"); + m_Menu[1].set_LabelText(4, "Müdigkeit"); + m_Menu[1].set_LabelText(5, "Hauptmenü"); + + m_Menu.push_back(TactileMenu(6)); + m_Menu[2].set_LabelText(0, "Ja"); + m_Menu[2].set_LabelText(1, "Nein"); + m_Menu[2].set_LabelText(2, "Schmerzen"); + m_Menu[2].set_LabelText(3, "Atemnot"); + m_Menu[2].set_LabelText(4, "Anderes"); + m_Menu[2].set_LabelText(5, "Hauptmenü"); + + m_Menu.push_back(TactileMenu(6)); + m_Menu[3].set_LabelText(0, "Ja"); + m_Menu[3].set_LabelText(1, "Nein"); + m_Menu[3].set_LabelText(2, "Atemgerät"); + m_Menu[3].set_LabelText(3, "Rollstuhl"); + m_Menu[3].set_LabelText(4, "Computer"); + m_Menu[3].set_LabelText(5, "Hauptmenü"); + + //set SubMenu ptr + m_Menu[0].set_SubMenu(2, &m_Menu[1]); + m_Menu[0].set_SubMenu(3, &m_Menu[2]); + m_Menu[0].set_SubMenu(4, &m_Menu[3]); + m_Menu[1].set_SubMenu(5, &m_Menu[0]); + m_Menu[2].set_SubMenu(5, &m_Menu[0]); + m_Menu[3].set_SubMenu(5, &m_Menu[0]); + + //set curr Menu ptr to main menu + m_CurrMenu = &m_Menu[0]; + } + //create copy spelling UI for 6 tactilos + else + { + m_Menu.push_back(TactileMenu(6)); + m_Menu[0].set_LabelText(0, "Hand links"); + m_Menu[0].set_LabelText(1, "Arm links"); + m_Menu[0].set_LabelText(2, "Brust links"); + m_Menu[0].set_LabelText(3, "Brust rechts"); + m_Menu[0].set_LabelText(4, "Arm rechts"); + m_Menu[0].set_LabelText(5, "Hand rechts"); + + m_CurrMenu = &m_Menu[0]; + } + } + //Create default UI for m_nTactilos != 6 + else { m_Menu.push_back(TactileMenu(m_nTactilos)); - m_currMenu = &m_Menu[0]; + m_CurrMenu = &m_Menu[0]; } - //Init Gtk Labels - for(int i = 0; i < m_nTactilos; i++) + // ------ Init UI + m_visualizationCtx = dynamic_cast(this->createPluginObject(OVP_ClassId_Plugin_VisualizationCtx)); + m_visualizationCtx->setWidget(*this, m_MainWindow); + + for(uint64_t i = 0; i < m_nTactilos; ++i) { - std::string label_id = "label-" + std::to_string(i+1); - std::string label_text = m_currMenu->get_LabelText(i); - - m_Label.push_back(GTK_LABEL(gtk_builder_get_object(m_mainWidgetInterface, label_id.c_str()))); - gtk_label_set_text(m_Label[i], label_text.c_str()); - } - - //End Menu Initialization --------------------------------------------------------------------------------------- - - gtk_builder_connect_signals(m_mainWidgetInterface, nullptr); - gtk_builder_connect_signals(m_toolbarWidgetInterface, nullptr); - - g_signal_connect(gtk_builder_get_object(m_toolbarWidgetInterface, "toolbutton-show_target_text"), "toggled", G_CALLBACK(ToggleButtonShowHideCB), - gtk_builder_get_object(m_mainWidgetInterface, "label-target")); - g_signal_connect(gtk_builder_get_object(m_toolbarWidgetInterface, "toolbutton-show_target_text"), "toggled", G_CALLBACK(ToggleButtonShowHideCB), - gtk_builder_get_object(m_mainWidgetInterface, "label-target-title")); - g_signal_connect(gtk_builder_get_object(m_toolbarWidgetInterface, "toolbutton-show_result_text"), "toggled", G_CALLBACK(ToggleButtonShowHideCB), - gtk_builder_get_object(m_mainWidgetInterface, "label-result")); - g_signal_connect(gtk_builder_get_object(m_toolbarWidgetInterface, "toolbutton-show_result_text"), "toggled", G_CALLBACK(ToggleButtonShowHideCB), - gtk_builder_get_object(m_mainWidgetInterface, "label-result-title")); - - m_visualizationCtx = dynamic_cast(this->createPluginObject( - OVP_ClassId_Plugin_VisualizationCtx)); - m_visualizationCtx->setWidget(*this, m_mainWindow); - m_visualizationCtx->setToolbar(*this, m_toolbarWidget); - - guint nRow = 0, nCol = 0; - g_object_get(m_table, "n-rows", &nRow, nullptr); - g_object_get(m_table, "n-columns", &nCol, nullptr); - - m_nRow = nRow; - m_nCol = nCol; - - PangoFontDescription* maxFontDesc = pango_font_description_copy(pango_context_get_font_description(gtk_widget_get_pango_context(m_mainWindow))); - m_flashFontDesc = pango_font_description_copy(pango_context_get_font_description(gtk_widget_get_pango_context(m_mainWindow))); - m_noFlashFontDesc = pango_font_description_copy(pango_context_get_font_description(gtk_widget_get_pango_context(m_mainWindow))); - m_targetFontDesc = pango_font_description_copy(pango_context_get_font_description(gtk_widget_get_pango_context(m_mainWindow))); - m_selectedFontDesc = pango_font_description_copy(pango_context_get_font_description(gtk_widget_get_pango_context(m_mainWindow))); - - uint64_t maxSize = 0; - maxSize = std::max(maxSize, m_flashFontSize); - maxSize = std::max(maxSize, m_noFlashFontSize); - maxSize = std::max(maxSize, m_targetFontSize); - maxSize = std::max(maxSize, m_selectedFontSize); - - pango_font_description_set_size(maxFontDesc, gint(maxSize * PANGO_SCALE)); - pango_font_description_set_size(m_flashFontDesc, gint(m_flashFontSize * PANGO_SCALE)); - pango_font_description_set_size(m_noFlashFontDesc, gint(m_noFlashFontSize * PANGO_SCALE)); - pango_font_description_set_size(m_targetFontDesc, gint(m_targetFontSize * PANGO_SCALE)); - pango_font_description_set_size(m_selectedFontDesc, gint(m_selectedFontSize * PANGO_SCALE)); - - this->cacheBuildFromTable(m_table); - this->cacheForEach(&CBoxAlgorithmP300TactileVisualization::cacheChangeBackgroundCB, &m_noFlashBgColor); - this->cacheForEach(&CBoxAlgorithmP300TactileVisualization::cacheChangeForegroundCB, &m_noFlashFgColor); - this->cacheForEach(&CBoxAlgorithmP300TactileVisualization::cacheChangeFontCB, maxFontDesc); - - pango_font_description_free(maxFontDesc); - - m_lastTargetRow = -1; - m_lastTargetCol = -1; - m_targetRow = -1; - m_targetCol = -1; - m_selectedRow = -1; - m_selectedCol = -1; - - m_stimulusSender = TCPTagging::CreateStimulusSender(); - - if (!m_stimulusSender->connect("localhost", "15361")) - { - this->getLogManager() << Kernel::LogLevel_Warning << "Unable to connect to AS TCP Tagging, stimuli wont be forwarded.\n"; + resetColor(); + gtk_widget_modify_font(gtk_bin_get_child(GTK_BIN(m_EventBox[i])), m_FontDesc); } - m_tableInitialized = false; - - return true; + toggleLabelText(); + + return(true); } +/*******************************************************************************/ bool CBoxAlgorithmP300TactileVisualization::uninitialize() -{ - if (m_idleFuncTag) +{ + // ------ uninitialize decoder/encoder + m_SequenceInputDecoder.uninitialize(); + m_TargetInputDecoder.uninitialize(); + m_ResultInputDecoder.uninitialize(); + m_ResultOutputEncoder.uninitialize(); + + // ------ uninitialize GTK UI + if (m_MainWidgetInterface) + { + g_object_unref(m_MainWidgetInterface); + m_MainWidgetInterface = nullptr; + } + if (m_visualizationCtx) + { + this->releasePluginObject(m_visualizationCtx); + } + + // ------ uinitialize TCP Tagging + if (m_idleFuncTag != 0) { m_stimuliQueue.clear(); g_source_remove(m_idleFuncTag); m_idleFuncTag = 0; } - if (m_stimulusSender) { delete m_stimulusSender; m_stimulusSender = nullptr; } - if (m_selectedFontDesc) - { - pango_font_description_free(m_selectedFontDesc); - m_selectedFontDesc = nullptr; - } - - if (m_targetFontDesc) - { - pango_font_description_free(m_targetFontDesc); - m_targetFontDesc = nullptr; - } - - if (m_noFlashFontDesc) - { - pango_font_description_free(m_noFlashFontDesc); - m_noFlashFontDesc = nullptr; - } - - if (m_flashFontDesc) - { - pango_font_description_free(m_flashFontDesc); - m_flashFontDesc = nullptr; - } - - if (m_toolbarWidgetInterface) - { - g_object_unref(m_toolbarWidgetInterface); - m_toolbarWidgetInterface = nullptr; - } - - if (m_mainWidgetInterface) - { - g_object_unref(m_mainWidgetInterface); - m_mainWidgetInterface = nullptr; - } - - m_targetFlaggingStimulationSet.uninitialize(); - m_targetFlaggingMemoryBuffer.uninitialize(); - - m_targetStimulationSet.uninitialize(); - m_targetMemoryBuffer.uninitialize(); - - m_sequenceStimulationSet.uninitialize(); - m_sequenceMemoryBuffer.uninitialize(); - - if (m_columnSelectionStimulationDecoder) - { - m_columnSelectionStimulationDecoder->uninitialize(); - this->getAlgorithmManager().releaseAlgorithm(*m_columnSelectionStimulationDecoder); - m_columnSelectionStimulationDecoder = nullptr; - } - - if (m_rowSelectionStimulationDecoder) - { - m_rowSelectionStimulationDecoder->uninitialize(); - this->getAlgorithmManager().releaseAlgorithm(*m_rowSelectionStimulationDecoder); - m_rowSelectionStimulationDecoder = nullptr; - } - - if (m_targetFlaggingStimulationEncoder) - { - m_targetFlaggingStimulationEncoder->uninitialize(); - this->getAlgorithmManager().releaseAlgorithm(*m_targetFlaggingStimulationEncoder); - m_targetFlaggingStimulationEncoder = nullptr; - - } - - if (m_targetStimulationDecoder) - { - m_targetStimulationDecoder->uninitialize(); - this->getAlgorithmManager().releaseAlgorithm(*m_targetStimulationDecoder); - m_targetStimulationDecoder = nullptr; - } - - if (m_sequenceStimulationDecoder) - { - m_sequenceStimulationDecoder->uninitialize(); - this->getAlgorithmManager().releaseAlgorithm(*m_sequenceStimulationDecoder); - m_sequenceStimulationDecoder = nullptr; - } - - if (m_visualizationCtx) - { - this->releasePluginObject(m_visualizationCtx); - m_sequenceStimulationDecoder = nullptr; - } - - return true; + return(true); } +/*******************************************************************************/ -bool CBoxAlgorithmP300TactileVisualization::processInput(const size_t /*index*/) + +bool CBoxAlgorithmP300TactileVisualization::processInput(const size_t index) { - this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess(); + // ------ ready to process + getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess(); - if (!m_tableInitialized) - { - this->cacheForEach(&CBoxAlgorithmP300TactileVisualization::cacheChangeBackgroundCB, &m_noFlashBgColor); - this->cacheForEach(&CBoxAlgorithmP300TactileVisualization::cacheChangeForegroundCB, &m_noFlashFgColor); - this->cacheForEach(&CBoxAlgorithmP300TactileVisualization::cacheChangeFontCB, m_noFlashFontDesc); - m_tableInitialized = true; - } - - return true; + return(true); } +/*******************************************************************************/ + + bool CBoxAlgorithmP300TactileVisualization::process() { - Kernel::IBoxIO& boxContext = this->getDynamicBoxContext(); + const IBox& staticBoxContext=this->getStaticBoxContext(); + IBoxIO& boxContext = this->getDynamicBoxContext(); + + //variables for processing of input chunks + uint64_t SequenceID = 0; + uint64_t TargetID = 0; + uint64_t ResultID = 0; + int Row = -1; + bool IsTarget = false; + bool TargetReceived = false; + bool ResultReceived = false; + + //variables for forwarding of target stimulations + uint64_t ChunkStartTime = 0; + uint64_t ChunkEndTime = 0; + uint64_t Size = 0; + const uint8_t* Buffer = nullptr; - // --- Sequence stimulations - - for (size_t i = 0; i < boxContext.getInputChunkCount(0); ++i) + + // ------ Sequence stimulation + for(uint64_t i = 0; i < boxContext.getInputChunkCount(0); ++i) { - CStimulationSet flaggingStimulationSet; - - m_sequenceMemoryBuffer = boxContext.getInputChunk(0, i); - m_targetFlaggingStimulationSet = &flaggingStimulationSet; - m_targetFlaggingMemoryBuffer = boxContext.getOutputChunk(0); - - m_sequenceStimulationDecoder->process(); - - m_lastTime = boxContext.getInputChunkEndTime(0, i); - - if (m_sequenceStimulationDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedHeader)) + m_SequenceInputDecoder.decode(i); + m_LastTime = boxContext.getInputChunkEndTime(0, i); + + // if header received + if(m_SequenceInputDecoder.isHeaderReceived()) + {} + + // if buffer received + if(m_SequenceInputDecoder.isBufferReceived()) { - m_targetFlaggingStimulationEncoder->process(OVP_GD_Algorithm_StimulationEncoder_InputTriggerId_EncodeHeader); - } - - if (m_sequenceStimulationDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedBuffer)) - { - CStimulationSet* stimulationSet = m_sequenceStimulationSet; - for (size_t j = 0; j < stimulationSet->size(); ++j) + //check received stimulations on sequence input + CStimulationSet* SequenceStimulationSet = m_SequenceInputDecoder.getOutputStimulationSet(); + for(uint64_t j = 0; j < SequenceStimulationSet->size(); ++j) { - uint64_t id = stimulationSet->getId(j); - bool flash = false; - int row = -1; - int col = -1; - bool isTarget = false; - - if (id >= m_rowStimulationBase && id < m_rowStimulationBase + m_nRow) + SequenceID = SequenceStimulationSet->getId(j); + + if(SequenceID >= m_RowBase && SequenceID < m_RowBase + m_nTactilos) { - row = int(id - m_rowStimulationBase); - flash = true; - isTarget = (row == m_lastTargetRow); + Row = SequenceID - m_RowBase; + IsTarget = (Row == (int)m_LastTarget); } - if (id >= m_columnStimulationBase && id < m_columnStimulationBase + m_nCol) + if(SequenceID == OVTK_StimulationId_VisualStimulationStart) { - col = int(id - m_columnStimulationBase); - flash = true; - isTarget = (col == m_lastTargetCol); - } - if (id == OVTK_StimulationId_VisualStimulationStop) - { - this->getLogManager() << Kernel::LogLevel_Debug << "Received OVTK_StimulationId_VisualStimulationStop - resets grid\n"; - this->cacheForEach(&CBoxAlgorithmP300TactileVisualization::cacheChangeBackgroundCB, &m_noFlashBgColor); - this->cacheForEach(&CBoxAlgorithmP300TactileVisualization::cacheChangeForegroundCB, &m_noFlashFgColor); - this->cacheForEach(&CBoxAlgorithmP300TactileVisualization::cacheChangeFontCB, m_noFlashFontDesc); - } - if (id == OVTK_StimulationId_Reset) - { - gtk_label_set_text(m_target, ""); - gtk_label_set_text(m_result, ""); - } - - if (flash) - { - this->cacheForEachIf(row, col, &CBoxAlgorithmP300TactileVisualization::cacheChangeBackgroundCB, - &CBoxAlgorithmP300TactileVisualization::cacheChangeBackgroundCB, &m_flashBgColor, &m_noFlashBgColor); - this->cacheForEachIf(row, col, &CBoxAlgorithmP300TactileVisualization::cacheChangeForegroundCB, - &CBoxAlgorithmP300TactileVisualization::cacheChangeForegroundCB, &m_flashFgColor, &m_noFlashFgColor); - this->cacheForEachIf(row, col, &CBoxAlgorithmP300TactileVisualization::cacheChangeFontCB, - &CBoxAlgorithmP300TactileVisualization::cacheChangeFontCB, m_flashFontDesc, m_noFlashFontDesc); - - // We now know if this flash corresponds to the current target or not, merge this to the outgoing stimulation stream - if (isTarget) + resetColor(); + toggleFlashColor(Row); + if (IsTarget) { m_stimuliQueue.push_back(OVTK_StimulationId_Target); - flaggingStimulationSet.push_back(OVTK_StimulationId_Target, stimulationSet->getDate(j), 0); } else { m_stimuliQueue.push_back(OVTK_StimulationId_NonTarget); - flaggingStimulationSet.push_back(OVTK_StimulationId_NonTarget, stimulationSet->getDate(j), 0); } } - - // Pass the stimulation to the server also as-is. If its a flash, it can be differentiated from a 'target' spec because - // its NOT between OVTK_StimulationId_RestStart and OVTK_StimulationId_RestStop stimuli in the generated P300 timeline. - m_stimuliQueue.push_back(id); - } - m_targetFlaggingStimulationEncoder->process(OVP_GD_Algorithm_StimulationEncoder_InputTriggerId_EncodeBuffer); - } - - if (m_sequenceStimulationDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedEnd)) - { - m_targetFlaggingStimulationEncoder->process(OVP_GD_Algorithm_StimulationEncoder_InputTriggerId_EncodeEnd); - } - - boxContext.markInputAsDeprecated(0, i); - boxContext.markOutputAsReadyToSend(0, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i)); - } - - // --- Target stimulations - - for (size_t i = 0; i < boxContext.getInputChunkCount(1); ++i) - { - if (m_lastTime >= boxContext.getInputChunkStartTime(1, i)) - { - m_targetMemoryBuffer = boxContext.getInputChunk(1, i); - m_targetStimulationDecoder->process(); - - if (m_targetStimulationDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedHeader)) { } - - if (m_targetStimulationDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedBuffer)) - { - CStimulationSet* stimulationSet = m_targetStimulationSet; - for (size_t j = 0; j < stimulationSet->size(); ++j) + if(SequenceID == OVTK_StimulationId_VisualStimulationStop) { - uint64_t id = stimulationSet->getId(j); - bool target = false; - if (id >= m_rowStimulationBase && id < m_rowStimulationBase + m_nRow) + resetColor(); + } + if(SequenceID == OVTK_StimulationId_SegmentStart) + { + toggleLabelText(); + } + + m_stimuliQueue.push_back(SequenceID); + } + } + + // if end received + if(m_SequenceInputDecoder.isEndReceived()) + {} + + boxContext.markInputAsDeprecated(0, i); + } + + // ------ Target stimulation + for(uint64_t i = 0; i < boxContext.getInputChunkCount(1); ++i) + { + if(m_LastTime >= boxContext.getInputChunkStartTime(1, i)) + { + m_TargetInputDecoder.decode(i); + + // if header received + if(m_SequenceInputDecoder.isHeaderReceived()) + {} + + // if buffer received + if(m_SequenceInputDecoder.isBufferReceived()) + { + // check received dtimulations on Target input + CStimulationSet* TargetStimulationSet = m_TargetInputDecoder.getOutputStimulationSet(); + for(uint64_t j = 0; j < TargetStimulationSet->size(); ++j) + { + TargetID = TargetStimulationSet->getId(j); + + if(TargetID >= m_RowBase && TargetID < m_RowBase + m_nTactilos) { - this->getLogManager() << Kernel::LogLevel_Debug << "Received Target Row " << id << "\n"; - m_targetRow = int(id - m_rowStimulationBase); - target = true; + Row = TargetID - m_RowBase; + TargetReceived = true; } - if (id >= m_columnStimulationBase && id < m_columnStimulationBase + m_nCol) + if(TargetReceived) { - this->getLogManager() << Kernel::LogLevel_Debug << "Received Target Column " << id << "\n"; - m_targetCol = int(id - m_columnStimulationBase); - target = true; - } - - if (target && m_targetRow != -1 && m_targetCol != -1) - { - this->getLogManager() << Kernel::LogLevel_Debug << "Displays Target Cell\n"; - this->cacheForEachIf(m_targetRow, m_targetCol, &CBoxAlgorithmP300TactileVisualization::cacheChangeBackgroundCB, - &CBoxAlgorithmP300TactileVisualization::cacheChangeNullCB, &m_targetBgColor, nullptr); - this->cacheForEachIf(m_targetRow, m_targetCol, &CBoxAlgorithmP300TactileVisualization::cacheChangeForegroundCB, - &CBoxAlgorithmP300TactileVisualization::cacheChangeNullCB, &m_targetFgColor, nullptr); - this->cacheForEachIf(m_targetRow, m_targetCol, &CBoxAlgorithmP300TactileVisualization::cacheChangeFontCB, - &CBoxAlgorithmP300TactileVisualization::cacheChangeNullCB, m_targetFontDesc, nullptr); - - std::vector widgets; - this->cacheForEachIf(m_targetRow, m_targetCol, &CBoxAlgorithmP300TactileVisualization::cacheCollectChildWidgetCB, - &CBoxAlgorithmP300TactileVisualization::cacheCollectChildWidgetCB, &widgets, nullptr); - - // Merge the current target into the stimulation stream. It can be differentiated - // from a 'flash' spec because it IS between OVTK_StimulationId_RestStart and - // OVTK_StimulationId_RestStop stimulations in the P300 timeline. - { - m_stimuliQueue.push_back(m_targetRow + m_rowStimulationBase); - m_stimuliQueue.push_back(m_targetCol + m_columnStimulationBase); - } - - if (widgets.size() == 1) - { - if (GTK_IS_LABEL(widgets[0])) - { - std::string label; - label = gtk_label_get_text(m_target); - label += gtk_label_get_text(GTK_LABEL(widgets[0])); - gtk_label_set_text(m_target, label.c_str()); - } - else - { - this->getLogManager() << Kernel::LogLevel_Warning << "Expected label class widget... could not find a valid text to append\n"; - } - } - else - { - this->getLogManager() << Kernel::LogLevel_Warning << "Did not find a unique widget at row:" << size_t(m_targetRow) << " column:" << - size_t(m_targetCol) << "\n"; - } - - m_targetHistory.emplace_back(m_targetRow, m_targetCol); - m_lastTargetRow = m_targetRow; - m_lastTargetCol = m_targetCol; - m_targetRow = -1; - m_targetCol = -1; + toggleTargetColor(Row); + m_stimuliQueue.push_back(TargetID); + + std::string TargetLabel = gtk_label_get_text(m_TargetLabel); + TargetLabel += gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(m_EventBox[Row])))); + gtk_label_set_text(m_TargetLabel, TargetLabel.c_str()); + + m_LastTarget = Row; } } } - - if (m_targetStimulationDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedEnd)) { } - + + // if end received + if(m_SequenceInputDecoder.isEndReceived()) + {} + boxContext.markInputAsDeprecated(1, i); } } - - // --- Selection stimulations - - for (size_t k = 2; k < 4; ++k) + + // ------ Result stimulation + for(uint64_t i = 0; i < boxContext.getInputChunkCount(2); ++i) { - Kernel::IAlgorithmProxy* decoder = (k == 2 ? m_rowSelectionStimulationDecoder : m_columnSelectionStimulationDecoder); - Kernel::TParameterHandler selectionMemoryBuffer( - decoder->getInputParameter(OVP_GD_Algorithm_StimulationDecoder_InputParameterId_MemoryBufferToDecode)); - Kernel::TParameterHandler selectionStimulationSet( - decoder->getOutputParameter(OVP_GD_Algorithm_StimulationDecoder_OutputParameterId_StimulationSet)); - - for (size_t i = 0; i < boxContext.getInputChunkCount(k); ++i) + if(m_LastTime >= boxContext.getInputChunkStartTime(2, i)) { - if (m_lastTime >= boxContext.getInputChunkStartTime(k, i)) + m_ResultInputDecoder.decode(i); + + // if header received + if(m_SequenceInputDecoder.isHeaderReceived()) + {} + + // if buffer received + if(m_SequenceInputDecoder.isBufferReceived()) { - selectionMemoryBuffer = boxContext.getInputChunk(k, i); - decoder->process(); - - if (decoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedHeader)) { } - - if (decoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedBuffer)) + // check received stimulations on result input + CStimulationSet* ResultStimulationSet = m_ResultInputDecoder.getOutputStimulationSet(); + for(uint64_t j = 0; j < ResultStimulationSet->size(); ++j) { - CStimulationSet* stimulationSet = selectionStimulationSet; - for (size_t j = 0; j < stimulationSet->size(); ++j) + ResultID = ResultStimulationSet->getId(j); + + if(ResultID >= m_RowBase && ResultID < m_RowBase + m_nTactilos) { - uint64_t id = stimulationSet->getId(j); - bool selected = false; - if (id >= m_rowStimulationBase && id < m_rowStimulationBase + m_nRow) - { - this->getLogManager() << Kernel::LogLevel_Debug << "Received Selected Row " << id << "\n"; - m_selectedRow = int(id - m_rowStimulationBase); - selected = true; - } - if (id >= m_columnStimulationBase && id < m_columnStimulationBase + m_nRow) - { - this->getLogManager() << Kernel::LogLevel_Debug << "Received Selected Column " << id << "\n"; - m_selectedCol = int(id - m_columnStimulationBase); - selected = true; - } - if (id == OVTK_StimulationId_Label_00) - { - if (k == 2) { m_selectedRow = -2; } - if (k == 3) { m_selectedCol = -2; } - selected = true; - } - if (selected && m_selectedRow != -1 && m_selectedCol != -1) - { - if (m_selectedRow >= 0 && m_selectedCol >= 0) - { - this->getLogManager() << Kernel::LogLevel_Debug << "Displays Selected Cell\n"; - this->cacheForEachIf(m_selectedRow, m_selectedCol, &CBoxAlgorithmP300TactileVisualization::cacheChangeBackgroundCB, - &CBoxAlgorithmP300TactileVisualization::cacheChangeNullCB, &m_selectedBgColor, nullptr); - this->cacheForEachIf(m_selectedRow, m_selectedCol, &CBoxAlgorithmP300TactileVisualization::cacheChangeForegroundCB, - &CBoxAlgorithmP300TactileVisualization::cacheChangeNullCB, &m_selectedFgColor, nullptr); - this->cacheForEachIf(m_selectedRow, m_selectedCol, &CBoxAlgorithmP300TactileVisualization::cacheChangeFontCB, - &CBoxAlgorithmP300TactileVisualization::cacheChangeNullCB, m_selectedFontDesc, nullptr); - - std::vector widgets; - this->cacheForEachIf(m_selectedRow, m_selectedCol, &CBoxAlgorithmP300TactileVisualization::cacheCollectChildWidgetCB, - &CBoxAlgorithmP300TactileVisualization::cacheCollectChildWidgetCB, &widgets, nullptr); - - if (widgets.size() == 1) - { - if (GTK_IS_LABEL(widgets[0])) - { - std::string label; - label = gtk_label_get_text(GTK_LABEL(widgets[0])); - if (!m_targetHistory.empty()) - { - auto it = m_targetHistory.begin(); - bool correct = (it->first == m_selectedRow && it->second == m_selectedCol); - bool halfCorrect = (it->first == m_selectedRow || it->second == m_selectedCol); - m_targetHistory.pop_front(); - std::string tmp; - if (correct) { tmp = ""; } - else if (halfCorrect) { tmp = ""; } - else { tmp = ""; } - label = tmp.append(label).append(""); - } - label = std::string(gtk_label_get_label(m_result)).append(label); - gtk_label_set_markup(m_result, label.c_str()); - } - else - { - this->getLogManager() << Kernel::LogLevel_Warning << - "Expected label class widget... could not find a valid text to append\n"; - } - } - else - { - this->getLogManager() << Kernel::LogLevel_Warning << "Did not find a unique widget at row : " << size_t(m_selectedRow) << - " column : " << size_t(m_selectedCol) << "\n"; - } - //Switch Menu - if(m_currMenu->get_SubMenu(m_selectedRow) != nullptr) - { - m_currMenu = m_currMenu->get_SubMenu(m_selectedRow); - for(uint64_t i = 0; i < m_nTactilos; i++) - { - std::string label_text = m_currMenu->get_LabelText(i); - - gtk_label_set_text(m_Label[i], label_text.c_str()); - } - } - } - else - { - this->getLogManager() << Kernel::LogLevel_Trace << "Selection Rejected !\n"; - std::string label; - label = gtk_label_get_text(m_result); - label += "*"; - gtk_label_set_text(m_result, label.c_str()); - } + Row = ResultID - m_RowBase; + ResultReceived = true; + } + if(ResultReceived) + { + toggleResultColor(Row); - m_selectedRow = -1; - m_selectedCol = -1; - } + std::string ResultLabel = gtk_label_get_text(m_ResultLabel); + ResultLabel += gtk_label_get_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(m_EventBox[Row])))); + gtk_label_set_text(m_ResultLabel, ResultLabel.c_str()); + + //switch current menu ptr to submenu + if(m_CurrMenu->get_SubMenu(Row) != nullptr) + { + m_CurrMenu = m_CurrMenu->get_SubMenu(Row); + } } } - - if (decoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedEnd)) { } - boxContext.markInputAsDeprecated(k, i); } - } + + // if end received + if(m_SequenceInputDecoder.isEndReceived()) + {} + + // forward target stimulations + boxContext.getInputChunk(2, i, ChunkStartTime, ChunkEndTime, Size, Buffer); + boxContext.appendOutputChunkData(0, Buffer, Size); + boxContext.markOutputAsReadyToSend(0, ChunkStartTime, ChunkEndTime); + boxContext.markInputAsDeprecated(2, i); + + } } - // After any possible rendering, we flush the accumulated stimuli. The default idle func is low priority, so it should be run after rendering by gtk. - if (m_idleFuncTag == 0) { m_idleFuncTag = g_idle_add(FlushCB, this); } - - return true; -} -// _________________________________________________________________________________________________________________________________________________________ -// - -void CBoxAlgorithmP300TactileVisualization::cacheBuildFromTable(GtkTable* table) -{ - if (table) + // ------ Send accumulated stimuli to the acquisition server + if(m_idleFuncTag == 0) { - const GdkColor white = InitGDKColor(65535, 65535, 65535, 65535); - - for (GList* list = table->children; list; list = list->next) - { - GtkTableChild* child = static_cast(list->data); - - for (size_t i = child->top_attach; i < child->bottom_attach; ++i) - { - for (size_t j = child->left_attach; j < child->right_attach; ++j) - { - widget_style_t& style = m_cache[i][j]; - style.widget = child->widget; - style.childWidget = gtk_bin_get_child(GTK_BIN(child->widget)); - style.bgColor = white; - style.fgColor = white; - style.fontDesc = nullptr; - } - } - } + m_idleFuncTag = g_idle_add(FlushCB, this); } + + return(true); } -void CBoxAlgorithmP300TactileVisualization::cacheForEach(const cache_callback callback, void* data) -{ - for (auto i = m_cache.begin(); i != m_cache.end(); ++i) - { - for (auto j = i->second.begin(); j != i->second.end(); ++j) { (this->*callback)(j->second, data); } - } -} -void CBoxAlgorithmP300TactileVisualization::cacheForEachIf(const int iLine, const int iColumn, const cache_callback ifCB, const cache_callback elseCB, - void* ifUserData, void* elseUserData) -{ - for (auto i = m_cache.begin(); i != m_cache.end(); ++i) - { - for (auto j = i->second.begin(); j != i->second.end(); ++j) - { - const bool line = (iLine != -1); - const bool column = (iColumn != -1); - bool inLine = false; - bool inCol = false; - bool first; - if (line && size_t(iLine) == i->first) { inLine = true; } - if (column && size_t(iColumn) == j->first) { inCol = true; } +// ------ Function Definitions - if (line && column) { first = inLine && inCol; } - else { first = inLine || inCol; } - if (first) { (this->*ifCB)(j->second, ifUserData); } - else { (this->*elseCB)(j->second, elseUserData); } - } - } -} - -void CBoxAlgorithmP300TactileVisualization::cacheChangeNullCB(widget_style_t& /*rWidgetStyle*/, void* /*data*/) { } - -void CBoxAlgorithmP300TactileVisualization::cacheChangeBackgroundCB(widget_style_t& style, void* data) -{ - GdkColor oColor = *static_cast(data); - if (memcmp(&style.bgColor, &oColor, sizeof(GdkColor)) != 0) - { - gtk_widget_modify_bg(style.widget, GTK_STATE_NORMAL, &oColor); - style.bgColor = oColor; - } -} - -void CBoxAlgorithmP300TactileVisualization::cacheChangeForegroundCB(widget_style_t& style, void* data) -{ - GdkColor oColor = *static_cast(data); - if (memcmp(&style.fgColor, &oColor, sizeof(GdkColor)) != 0) - { - gtk_widget_modify_fg(style.childWidget, GTK_STATE_NORMAL, &oColor); - style.fgColor = oColor; - } -} - -void CBoxAlgorithmP300TactileVisualization::cacheChangeFontCB(widget_style_t& style, void* data) -{ - auto* pFontDescription = static_cast(data); - if (style.fontDesc != pFontDescription) - { - gtk_widget_modify_font(style.childWidget, pFontDescription); - style.fontDesc = pFontDescription; - } -} - -void CBoxAlgorithmP300TactileVisualization::cacheCollectWidgetCB(widget_style_t& style, void* data) -{ - if (data) { (static_cast*>(data))->push_back(style.widget); } -} - -void CBoxAlgorithmP300TactileVisualization::cacheCollectChildWidgetCB(widget_style_t& style, void* data) -{ - if (data) { (static_cast*>(data))->push_back(style.childWidget); } -} - -// Note that we don't need concurrency control here as gtk callbacks run in the main thread +// Sends all accumulated stimuli to the TCP Tagging void CBoxAlgorithmP300TactileVisualization::flushQueue() { - for (const auto& stimulation : m_stimuliQueue) { m_stimulusSender->sendStimulation(stimulation); } + for (const auto& stimulation : m_stimuliQueue) + { + m_stimulusSender->sendStimulation(stimulation); + } m_stimuliQueue.clear(); // This function will be automatically removed after completion, so set to 0 m_idleFuncTag = 0; } -} // namespace Tactilebci -} // namespace Plugins -} // namespace OpenViBE + +// Change labels fore-/background +void CBoxAlgorithmP300TactileVisualization::toggleFlashColor(uint64_t id) +{ + gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[id])), GTK_STATE_NORMAL, &m_FlashFG); + gtk_widget_modify_bg(m_EventBox[id], GTK_STATE_NORMAL, &m_FlashBG); +} + +void CBoxAlgorithmP300TactileVisualization::toggleTargetColor(uint64_t id) +{ + gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[id])), GTK_STATE_NORMAL, &m_TargetFG); + gtk_widget_modify_bg(m_EventBox[id], GTK_STATE_NORMAL, &m_TargetBG); +} + +void CBoxAlgorithmP300TactileVisualization::toggleResultColor(uint64_t id) +{ + gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[id])), GTK_STATE_NORMAL, &m_ResultFG); + gtk_widget_modify_bg(m_EventBox[id], GTK_STATE_NORMAL, &m_ResultBG); +} + +void CBoxAlgorithmP300TactileVisualization::resetColor() +{ + for(uint64_t i = 0; i < m_nTactilos; i++) + { + gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(m_EventBox[i])), GTK_STATE_NORMAL, &m_NoFlashFG); + gtk_widget_modify_bg(m_EventBox[i], GTK_STATE_NORMAL, &m_NoFlashBG); + } +} + + +// Change label text +void CBoxAlgorithmP300TactileVisualization::toggleLabelText() +{ + for(uint64_t i = 0; i < m_nTactilos; i++) + { + std::string label_text = m_CurrMenu->get_LabelText(i); + + gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(m_EventBox[i]))), label_text.c_str()); + } +} \ No newline at end of file diff --git a/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.h b/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.h index 9ff0502..631b028 100644 --- a/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.h +++ b/src/TactileVisualization/ovpCBoxAlgorithmP300TactileVisualization.h @@ -1,208 +1,162 @@ ///------------------------------------------------------------------------------------------------- /// -/// \file ovpCBoxAlgorithmP300TactileVisualization.h -/// \brief Classes of the Box P300 Tactile Visualization. !!This is a modification of the P300 Speller Visualization Box!! +/// \file CBoxAlgorithmP300TactileVisualization.h +/// \brief Classes of the Box P300TactileVisualization. /// \author Tobias Baumann (TH Nuernberg). /// \version 1.0. -/// \date Mon Feb 04 12:43:53 2022. +/// \date Sat May 07 14:20:29 2022. /// \copyright GNU Affero General Public License v3.0. /// ///------------------------------------------------------------------------------------------------- -//includes #pragma once -#include "TactileMenu.h" +//You may have to change this path to match your folder organisation #include "../ovp_defines.h" +#include "TactileMenu.h" #include #include +#include #include #include #include #include #include +#include +#include #include "../utils.h" + namespace TCPTagging { class IStimulusSender; // fwd declare -} // namespace TCPTagging +} -namespace OpenViBE { -namespace Plugins { -namespace Tactilebci { - -class CBoxAlgorithmP300TactileVisualization final : public Toolkit::TBoxAlgorithm +namespace OpenViBE { -public: - - void release() override { delete this; } - - bool initialize() override; - bool uninitialize() override; - bool processInput(const size_t index) override; - bool process() override; - - _IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm, OVP_ClassId_BoxAlgorithm_P300TactileVisualization) - - // Sends all accumulated stimuli to the TCP Tagging - void flushQueue(); - -private: - - Kernel::IAlgorithmProxy* m_sequenceStimulationDecoder = nullptr; - Kernel::IAlgorithmProxy* m_targetStimulationDecoder = nullptr; - Kernel::IAlgorithmProxy* m_targetFlaggingStimulationEncoder = nullptr; - Kernel::IAlgorithmProxy* m_rowSelectionStimulationDecoder = nullptr; - Kernel::IAlgorithmProxy* m_columnSelectionStimulationDecoder = nullptr; - Kernel::TParameterHandler m_sequenceMemoryBuffer; - Kernel::TParameterHandler m_targetMemoryBuffer; - Kernel::TParameterHandler m_targetFlaggingStimulationSet; - Kernel::TParameterHandler m_sequenceStimulationSet; - Kernel::TParameterHandler m_targetStimulationSet; - Kernel::TParameterHandler m_targetFlaggingMemoryBuffer; - uint64_t m_lastTime = 0; - - GtkBuilder* m_mainWidgetInterface = nullptr; - GtkBuilder* m_toolbarWidgetInterface = nullptr; - GtkWidget* m_mainWindow = nullptr; - GtkWidget* m_toolbarWidget = nullptr; - GtkTable* m_table = nullptr; - GtkLabel* m_result = nullptr; - GtkLabel* m_target = nullptr; - - //Deklaration TactileMenu Variablen - std::vector m_Menu; - std::vector m_Label; - TactileMenu* m_currMenu; - - - uint64_t m_nRow = 0; - uint64_t m_nCol = 0; - - int m_lastTargetRow = 0; - int m_lastTargetCol = 0; - int m_targetRow = 0; - int m_targetCol = 0; - int m_selectedRow = 0; - int m_selectedCol = 0; - - bool m_tableInitialized = false; - - using widget_style_t = struct + namespace Plugins { - GtkWidget* widget; - GtkWidget* childWidget; - GdkColor bgColor; - GdkColor fgColor; - PangoFontDescription* fontDesc; - }; + namespace Tactilebci + { + /// The class CBoxAlgorithmP300TactileVisualization describes the box P300TactileVisualization. + class CBoxAlgorithmP300TactileVisualization final : virtual public Toolkit::TBoxAlgorithm + { + public: + // ------ OV base functions + void release() override { delete this; } - typedef void (CBoxAlgorithmP300TactileVisualization::*cache_callback)(widget_style_t& style, void* data); + bool initialize() override; + bool uninitialize() override; - void cacheBuildFromTable(GtkTable* table); - void cacheForEach(cache_callback callback, void* data); - void cacheForEachIf(int iLine, int iColumn, cache_callback ifCB, cache_callback elseCB, void* ifUserData, void* elseUserData); - void cacheChangeNullCB(widget_style_t& style, void* data); - void cacheChangeBackgroundCB(widget_style_t& style, void* data); - void cacheChangeForegroundCB(widget_style_t& style, void* data); - void cacheChangeFontCB(widget_style_t& style, void* data); - void cacheCollectWidgetCB(widget_style_t& style, void* data); - void cacheCollectChildWidgetCB(widget_style_t& style, void* data); - - // @todo refactor to std::pair ? - std::map> m_cache; - std::list> m_targetHistory; + //Process Callback on new input received (the most common behaviour for signal processing) : + bool processInput(const size_t index) override; - // TCP Tagging - std::vector m_stimuliQueue; - guint m_idleFuncTag = 0; - TCPTagging::IStimulusSender* m_stimulusSender = nullptr; + bool process() override; - VisualizationToolkit::IVisualizationContext* m_visualizationCtx = nullptr; - -protected: + // As we do with any class in openvibe, we use the macro below to associate this box to an unique identifier. + // The inheritance information is also made available, as we provide the superclass Toolkit::TBoxAlgorithm < IBoxAlgorithm > + _IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm, OVP_ClassId_BoxAlgorithm_P300TactileVisualization) + + // ------ TCP Tagging + void flushQueue(); + + // ------ UI Functions + void toggleFlashColor(uint64_t id); + void toggleTargetColor(uint64_t id); + void toggleResultColor(uint64_t id); + void resetColor(); + void toggleLabelText(); + + protected: + // ------ Input decoder: + Toolkit::TStimulationDecoder m_SequenceInputDecoder; + Toolkit::TStimulationDecoder m_TargetInputDecoder; + Toolkit::TStimulationDecoder m_ResultInputDecoder; + // ------ Output decoder: + Toolkit::TStimulationEncoder m_ResultOutputEncoder; + + private: + uint64_t m_LastTarget = 0; + uint64_t m_LastTime = 0; + + // ------ Box setting variables + CString m_InterfaceFilename; + uint64_t m_RowBase = 0; + uint64_t m_nTactilos = 6; + bool m_FreeSpelling = false; + + // ------TactileMenu variables + std::vector m_Menu; + TactileMenu* m_CurrMenu = nullptr; + + // ------ GTK variables + GtkBuilder* m_MainWidgetInterface = nullptr; + GtkWidget* m_MainWindow = nullptr; + GtkTable* m_Table = nullptr; + std::vector m_EventBox; + GtkLabel* m_ResultLabel = nullptr; + GtkLabel* m_TargetLabel = nullptr; + + GdkColor m_FlashBG = InitGDKColor(0, 3276, 3276, 3276); + GdkColor m_FlashFG = InitGDKColor(0, 65535, 65535, 65535); + GdkColor m_NoFlashBG = InitGDKColor(0, 0, 0, 0); + GdkColor m_NoFlashFG = InitGDKColor(0, 16383, 16383, 16383); + GdkColor m_TargetBG = InitGDKColor(0, 13107, 13107, 45874); + GdkColor m_TargetFG = InitGDKColor(0, 6553, 6553, 19660); + GdkColor m_ResultBG = InitGDKColor(0, 6553, 26214, 6553); + GdkColor m_ResultFG = InitGDKColor(0, 39321, 65535, 39321); + + uint64_t FontSize = 50; + PangoFontDescription* m_FontDesc = nullptr; + + // ------ TCP Tagging + std::vector m_stimuliQueue; + guint m_idleFuncTag = 0; + TCPTagging::IStimulusSender* m_stimulusSender = nullptr; + + // ------ Box visualization + VisualizationToolkit::IVisualizationContext* m_visualizationCtx = nullptr; + }; - CString m_interfaceFilename; - uint64_t m_rowStimulationBase = 0; - uint64_t m_columnStimulationBase = 0; + /// Descriptor of the box P300TactileVisualization. + class CBoxAlgorithmP300TactileVisualizationDesc final : virtual public IBoxAlgorithmDesc + { + public: - GdkColor m_flashBgColor = InitGDKColor(0, 6554, 6554, 6554); - GdkColor m_flashFgColor = InitGDKColor(0, 65535, 65535, 65535); - uint64_t m_flashFontSize = 100; - PangoFontDescription* m_flashFontDesc = nullptr; - GdkColor m_noFlashBgColor = InitGDKColor(0, 0, 0, 0); - GdkColor m_noFlashFgColor = InitGDKColor(0, 32768, 32768, 32768); - uint64_t m_noFlashFontSize = 75; - PangoFontDescription* m_noFlashFontDesc = nullptr; - GdkColor m_targetBgColor = InitGDKColor(0, 6554, 26214, 6554); - GdkColor m_targetFgColor = InitGDKColor(0, 39321, 65535, 39321); - uint64_t m_targetFontSize = 100; - PangoFontDescription* m_targetFontDesc = nullptr; - GdkColor m_selectedBgColor = InitGDKColor(0, 45875, 13107, 13107); - GdkColor m_selectedFgColor = InitGDKColor(0, 19661, 6554, 6554); - uint64_t m_selectedFontSize = 100; - PangoFontDescription* m_selectedFontDesc = nullptr; - - uint64_t m_nTactilos = 0; -}; + void release() override { } -class CBoxAlgorithmP300TactileVisualizationDesc final : public IBoxAlgorithmDesc -{ -public: + CString getName() const override { return CString("P300TactileVisualization"); } + CString getAuthorName() const override { return CString("Tobias Baumann"); } + CString getAuthorCompanyName() const override { return CString("TH Nuernberg"); } + CString getShortDescription() const override { return CString(""); } + CString getDetailedDescription() const override { return CString(""); } + CString getCategory() const override { return CString("TactileBCI"); } + CString getVersion() const override { return CString("1.0"); } + CString getStockItemName() const override { return CString("gtk-underline"); } - void release() override { } + CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_P300TactileVisualization; } + IPluginObject* create() override { return new CBoxAlgorithmP300TactileVisualization; } - CString getName() const override { return CString("P300 Tactile Visualization"); } - CString getAuthorName() const override { return CString("Tobias Baumann"); } - CString getAuthorCompanyName() const override { return CString("TH-Nürnberg"); } - CString getShortDescription() const override { return CString("Visualizes the Menus for a Tactile P300 BCI"); } - CString getDetailedDescription() const override { return CString(""); } - CString getCategory() const override { return CString("TactileBCI"); } - CString getVersion() const override { return CString("1.0"); } - CString getStockItemName() const override { return CString("gtk-select-font"); } + bool hasFunctionality(const EPluginFunctionality functionality) const override { return functionality == EPluginFunctionality::Visualization; } + + bool getBoxPrototype(Kernel::IBoxProto& prototype) const override + { + prototype.addInput("Sequence",OV_TypeId_Stimulations); + prototype.addInput("Target",OV_TypeId_Stimulations); + prototype.addInput("Result",OV_TypeId_Stimulations); - CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_P300TactileVisualization; } - IPluginObject* create() override { return new CBoxAlgorithmP300TactileVisualization; } + prototype.addOutput("Result",OV_TypeId_Stimulations); - bool hasFunctionality(const EPluginFunctionality functionality) const override { return functionality == EPluginFunctionality::Visualization; } + prototype.addSetting("Interface Filename",OV_TypeId_Filename,"/ui/p300-tactile-6.ui"); + prototype.addSetting("Row Stimulation Base",OV_TypeId_Stimulation,"OVTK_StimulationId_Label_01"); + prototype.addSetting("Number of Tactilos",OV_TypeId_Integer,"6"); + prototype.addSetting("Free Spelling",OV_TypeId_Boolean,"false"); - bool getBoxPrototype(Kernel::IBoxProto& prototype) const override - { - prototype.addInput("Sequence stimulations", OV_TypeId_Stimulations); - prototype.addInput("Target stimulations", OV_TypeId_Stimulations); - prototype.addInput("Row selection stimulations", OV_TypeId_Stimulations); - prototype.addInput("Column selection stimulations", OV_TypeId_Stimulations); + prototype.addFlag(OV_AttributeId_Box_FlagIsUnstable); - prototype.addOutput("Target / Non target flagging (deprecated)", OV_TypeId_Stimulations); - - prototype.addSetting("Interface filename", OV_TypeId_Filename, "${Path_Data}/plugins/simple-visualization/p300-speller.ui"); - prototype.addSetting("Row stimulation base", OV_TypeId_Stimulation, "OVTK_StimulationId_Label_01"); - prototype.addSetting("Column stimulation base", OV_TypeId_Stimulation, "OVTK_StimulationId_Label_07"); - - prototype.addSetting("Flash background color", OV_TypeId_Color, "10,10,10"); - prototype.addSetting("Flash foreground color", OV_TypeId_Color, "100,100,100"); - prototype.addSetting("Flash font size", OV_TypeId_Integer, "100"); - - prototype.addSetting("No flash background color", OV_TypeId_Color, "0,0,0"); - prototype.addSetting("No flash foreground color", OV_TypeId_Color, "50,50,50"); - prototype.addSetting("No flash font size", OV_TypeId_Integer, "75"); - - prototype.addSetting("Target background color", OV_TypeId_Color, "10,40,10"); - prototype.addSetting("Target foreground color", OV_TypeId_Color, "60,100,60"); - prototype.addSetting("Target font size", OV_TypeId_Integer, "100"); - - prototype.addSetting("Selected background color", OV_TypeId_Color, "70,20,20"); - prototype.addSetting("Selected foreground color", OV_TypeId_Color, "30,10,10"); - prototype.addSetting("Selected font size", OV_TypeId_Integer, "100"); - - prototype.addSetting("Number of Tactilos",OV_TypeId_Integer,"6"); - - return true; - } - - _IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_P300TactileVisualizationDesc) -}; - -} // namespace Tactilebci -} // namespace Plugins + return true; + } + _IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_P300TactileVisualizationDesc) + }; + } // namespace Tactilebci + } // namespace Plugins } // namespace OpenViBE