|
|
@@ -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 <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
|
|
|
///
|
|
|
|
///-------------------------------------------------------------------------------------------------
|
|
|
|
//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 <openvibe/ov_all.h>
|
|
|
|
#include <toolkit/ovtk_all.h>
|
|
|
|
#include <tcptagging/IStimulusSender.h>
|
|
|
|
#include <visualization-toolkit/ovviz_all.h>
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <list>
|
|
|
|
#include <map>
|
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <string>
|
|
|
|
#include "../utils.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace TCPTagging {
|
|
|
|
class IStimulusSender; // fwd declare
|
|
|
|
} // namespace TCPTagging
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace OpenViBE {
|
|
|
|
namespace Plugins {
|
|
|
|
namespace Tactilebci {
|
|
|
|
|
|
|
|
class CBoxAlgorithmP300TactileVisualization final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
|
|
|
{
|
|
|
|
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<IBoxAlgorithm>, 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<const IMemoryBuffer*> m_sequenceMemoryBuffer;
|
|
|
|
Kernel::TParameterHandler<const IMemoryBuffer*> m_targetMemoryBuffer;
|
|
|
|
Kernel::TParameterHandler<const CStimulationSet*> m_targetFlaggingStimulationSet;
|
|
|
|
Kernel::TParameterHandler<CStimulationSet*> m_sequenceStimulationSet;
|
|
|
|
Kernel::TParameterHandler<CStimulationSet*> m_targetStimulationSet;
|
|
|
|
Kernel::TParameterHandler<IMemoryBuffer*> 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<TactileMenu> m_Menu;
|
|
|
|
std::vector<GtkLabel*> 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
|
|
|
|
{
|
|
|
|
GtkWidget* widget;
|
|
|
|
GtkWidget* childWidget;
|
|
|
|
GdkColor bgColor;
|
|
|
|
GdkColor fgColor;
|
|
|
|
PangoFontDescription* fontDesc;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef void (CBoxAlgorithmP300TactileVisualization::*cache_callback)(widget_style_t& style, void* data);
|
|
|
|
|
|
|
|
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<long,long> ?
|
|
|
|
std::map<size_t, std::map<size_t, widget_style_t>> m_cache;
|
|
|
|
std::list<std::pair<int, int>> m_targetHistory;
|
|
|
|
|
|
|
|
// TCP Tagging
|
|
|
|
std::vector<uint64_t> m_stimuliQueue;
|
|
|
|
guint m_idleFuncTag = 0;
|
|
|
|
TCPTagging::IStimulusSender* m_stimulusSender = nullptr;
|
|
|
|
|
|
|
|
VisualizationToolkit::IVisualizationContext* m_visualizationCtx = nullptr;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
CString m_interfaceFilename;
|
|
|
|
uint64_t m_rowStimulationBase = 0;
|
|
|
|
uint64_t m_columnStimulationBase = 0;
|
|
|
|
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
|
|
|
class CBoxAlgorithmP300TactileVisualizationDesc final : public IBoxAlgorithmDesc
|
|
|
|
namespace OpenViBE
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
void release() override { }
|
|
|
|
|
|
|
|
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"); }
|
|
|
|
|
|
|
|
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_P300TactileVisualization; }
|
|
|
|
IPluginObject* create() override { return new CBoxAlgorithmP300TactileVisualization; }
|
|
|
|
|
|
|
|
bool hasFunctionality(const EPluginFunctionality functionality) const override { return functionality == EPluginFunctionality::Visualization; }
|
|
|
|
|
|
|
|
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
|
|
|
namespace Plugins
|
|
|
|
{
|
|
|
|
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.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
|
|
|
|
namespace Tactilebci
|
|
|
|
{
|
|
|
|
/// <summary> The class CBoxAlgorithmP300TactileVisualization describes the box P300TactileVisualization. </summary>
|
|
|
|
class CBoxAlgorithmP300TactileVisualization final : virtual public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// ------ OV base functions
|
|
|
|
void release() override { delete this; }
|
|
|
|
|
|
|
|
bool initialize() override;
|
|
|
|
bool uninitialize() override;
|
|
|
|
|
|
|
|
//Process Callback on new input received (the most common behaviour for signal processing) :
|
|
|
|
bool processInput(const size_t index) override;
|
|
|
|
|
|
|
|
bool process() override;
|
|
|
|
|
|
|
|
// 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<IBoxAlgorithm>, 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<CBoxAlgorithmP300TactileVisualization> m_SequenceInputDecoder;
|
|
|
|
Toolkit::TStimulationDecoder<CBoxAlgorithmP300TactileVisualization> m_TargetInputDecoder;
|
|
|
|
Toolkit::TStimulationDecoder<CBoxAlgorithmP300TactileVisualization> m_ResultInputDecoder;
|
|
|
|
// ------ Output decoder:
|
|
|
|
Toolkit::TStimulationEncoder<CBoxAlgorithmP300TactileVisualization> 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<TactileMenu> m_Menu;
|
|
|
|
TactileMenu* m_CurrMenu = nullptr;
|
|
|
|
|
|
|
|
// ------ GTK variables
|
|
|
|
GtkBuilder* m_MainWidgetInterface = nullptr;
|
|
|
|
GtkWidget* m_MainWindow = nullptr;
|
|
|
|
GtkTable* m_Table = nullptr;
|
|
|
|
std::vector<GtkWidget*> 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<uint64_t> m_stimuliQueue;
|
|
|
|
guint m_idleFuncTag = 0;
|
|
|
|
TCPTagging::IStimulusSender* m_stimulusSender = nullptr;
|
|
|
|
|
|
|
|
// ------ Box visualization
|
|
|
|
VisualizationToolkit::IVisualizationContext* m_visualizationCtx = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
/// <summary> Descriptor of the box P300TactileVisualization. </summary>
|
|
|
|
class CBoxAlgorithmP300TactileVisualizationDesc final : virtual public IBoxAlgorithmDesc
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
void release() override { }
|
|
|
|
|
|
|
|
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"); }
|
|
|
|
|
|
|
|
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_P300TactileVisualization; }
|
|
|
|
IPluginObject* create() override { return new CBoxAlgorithmP300TactileVisualization; }
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
prototype.addOutput("Result",OV_TypeId_Stimulations);
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
|
|
|
prototype.addFlag(OV_AttributeId_Box_FlagIsUnstable);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_P300TactileVisualizationDesc)
|
|
|
|
};
|
|
|
|
} // namespace Tactilebci
|
|
|
|
} // namespace Plugins
|
|
|
|
} // namespace OpenViBE
|