v2.0.0
Loading...
Searching...
No Matches
rtfiffrawview.cpp
Go to the documentation of this file.
1//=============================================================================================================
36
37//=============================================================================================================
38// INCLUDES
39//=============================================================================================================
40
41#include "rtfiffrawview.h"
42
45
46#include <dsp/filterkernel.h>
47#include <fiff/fiff_info.h>
48
49//=============================================================================================================
50// QT INCLUDES
51//=============================================================================================================
52
53#include <QGridLayout>
54#include <QHeaderView>
55#include <QTableView>
56#include <QMenu>
57#include <QSvgGenerator>
58#include <QSettings>
59#include <QScrollBar>
60#include <QMouseEvent>
61#include <QRhiWidget>
62
63
64
65//=============================================================================================================
66// USED NAMESPACES
67//=============================================================================================================
68
69using namespace DISPLIB;
70using namespace FIFFLIB;
71using namespace Eigen;
72using namespace RTPROCESSINGLIB;
73using namespace UTILSLIB;
74
75//=============================================================================================================
76// DEFINE MEMBER METHODS
77//=============================================================================================================
78
79RtFiffRawView::RtFiffRawView(const QString& sSettingsPath,
80 QWidget *parent,
81 Qt::WindowFlags f)
82: AbstractView(parent, f)
83, m_iT(10)
84, m_fSamplingRate(1024)
85, m_fZoomFactor(1.0f)
86, m_bHideBadChannels(false)
88, m_iClickPosX(0)
89{
90 m_sSettingsPath = sSettingsPath;
91 m_pTableView = new QTableView;
92
93 auto *rhiViewport = new QRhiWidget;
94#if defined(WASMBUILD) || defined(__EMSCRIPTEN__)
95 rhiViewport->setApi(QRhiWidget::Api::OpenGL);
96#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
97 rhiViewport->setApi(QRhiWidget::Api::Metal);
98#elif defined(Q_OS_WIN)
99 rhiViewport->setApi(QRhiWidget::Api::Direct3D11);
100#else
101 rhiViewport->setApi(QRhiWidget::Api::OpenGL);
102#endif
103 m_pTableView->setViewport(rhiViewport);
104
105 // Install event filter for tracking mouse movements
106 m_pTableView->viewport()->installEventFilter(this);
107 m_pTableView->setMouseTracking(true);
108
109 // Set layout
110 QVBoxLayout *neLayout = new QVBoxLayout(this);
111 neLayout->addWidget(m_pTableView);
112 neLayout->setContentsMargins(0,0,0,0);
113 this->setLayout(neLayout);
114
115 loadSettings();
116}
117
118//=============================================================================================================
119
124
125//=============================================================================================================
126
128{
129 if(m_pTableView) {
130 auto *rhiViewport = new QRhiWidget;
131#if defined(WASMBUILD) || defined(__EMSCRIPTEN__)
132 rhiViewport->setApi(QRhiWidget::Api::OpenGL);
133#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
134 rhiViewport->setApi(QRhiWidget::Api::Metal);
135#elif defined(Q_OS_WIN)
136 rhiViewport->setApi(QRhiWidget::Api::Direct3D11);
137#else
138 rhiViewport->setApi(QRhiWidget::Api::OpenGL);
139#endif
140 m_pTableView->setViewport(rhiViewport);
141 }
142}
143
144//=============================================================================================================
145
146void RtFiffRawView::setSettingsPath(const QString& sSettingsPath)
147{
148 m_sSettingsPath = sSettingsPath;
149 loadSettings();
150}
151
152//=============================================================================================================
153
154void RtFiffRawView::init(QSharedPointer<FIFFLIB::FiffInfo> &info)
155{
156 m_pFiffInfo = info;
158
159 //Init the model
160 m_pModel = new RtFiffRawViewModel(this);
161 m_pModel->setFiffInfo(m_pFiffInfo);
162 m_pModel->setSamplingInfo(m_fSamplingRate, m_iT, true);
165 connect(this, &RtFiffRawView::addSampleAsEvent,
166 m_pModel, &RtFiffRawViewModel::addEvent, Qt::UniqueConnection);
167
168 //Init bad channel list
169 m_qListBadChannels.clear();
170 for(int i = 0; i<m_pModel->rowCount(); i++) {
171 if(m_pModel->data(m_pModel->index(i,2)).toBool()) {
173 }
174 }
175
176 //Init the delegate
178 m_pDelegate->initPainterPaths(m_pModel);
179
180 connect(this, &RtFiffRawView::markerMoved,
182
183 //Init the view
184 m_pTableView->setModel(m_pModel);
185 m_pTableView->setItemDelegate(m_pDelegate);
186 m_pTableView->setContextMenuPolicy(Qt::CustomContextMenu);
187
188 connect(m_pTableView.data(), &QTableView::doubleClicked,
190
191 connect(m_pTableView.data(), &QTableView::customContextMenuRequested,
193
194 //set some size settings for m_pTableView
195 m_pTableView->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
196 m_pTableView->setShowGrid(false);
197 m_pTableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); //Stretch 2 column to maximal width
198 m_pTableView->horizontalHeader()->hide();
199 m_pTableView->verticalHeader()->setDefaultSectionSize(m_pTableView->height() / m_fZoomFactor);//Row Height
200 m_pTableView->setAutoScroll(false);
201 m_pTableView->setColumnHidden(0,true); //because content is plotted jointly with column=1
202 m_pTableView->setColumnHidden(2,true);
203 m_pTableView->resizeColumnsToContents();
204 m_pTableView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
205
206 connect(m_pTableView->verticalScrollBar(), &QScrollBar::valueChanged,
208}
209
210//=============================================================================================================
211
212void RtFiffRawView::addData(const QList<Eigen::MatrixXd> &data)
213{
214 if(!data.isEmpty()) {
215 m_pModel->addData(data);
216
217 if(m_qListBadChannels.size() != m_pFiffInfo->bads.size()) {
218 m_qListBadChannels.clear();
219 for(int i = 0; i<m_pModel->rowCount(); i++) {
220 if(m_pModel->data(m_pModel->index(i,2)).toBool()) {
222 }
223 }
224
225 //Hide non selected channels/rows in the data views
226 for(int i = 0; i<m_qListBadChannels.size(); i++) {
228 m_pTableView->hideRow(m_qListBadChannels.at(i));
229 } else {
230 m_pTableView->showRow(m_qListBadChannels.at(i));
231 }
232 }
233 }
234 } else {
235 qWarning() << "[RtFiffRawView::addData] Received data list is empty.";
236 }
237}
238
239//=============================================================================================================
240
242{
243 return m_pModel->getLastBlock();
244}
245
246//=============================================================================================================
247
248bool RtFiffRawView::eventFilter(QObject *object, QEvent *event)
249{
250// if (object == m_pTableView->viewport() && event->type() == QEvent::MouseMove) {
251// QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
252// emit markerMoved(mouseEvent->pos(), m_pTableView->rowAt(mouseEvent->pos().y()));
253// return true;
254// }
255
256 return QWidget::eventFilter(object, event);
257}
258
259//=============================================================================================================
260
261void RtFiffRawView::setBackgroundColor(const QColor& backgroundColor)
262{
263 m_backgroundColor = backgroundColor;
264
265 if(m_pModel) {
266 m_pModel->setBackgroundColor(m_backgroundColor);
267 }
268
269// QPalette pal;
270// pal.setColor(QPalette::Window, m_backgroundColor);
271// m_pTableView->viewport()->setPalette(pal);
272// m_pTableView->viewport()->setBackgroundRole(QPalette::Window);
273}
274
275//=============================================================================================================
276
281
282//=============================================================================================================
283
284QMap<qint32, float> RtFiffRawView::getScalingMap()
285{
286 return m_qMapChScaling;
287}
288
289//=============================================================================================================
290
291void RtFiffRawView::setScalingMap(const QMap<qint32, float>& scaleMap)
292{
293 m_qMapChScaling = scaleMap;
294 m_pModel->setScaling(scaleMap);
295}
296
297//=============================================================================================================
298
299void RtFiffRawView::setSignalColor(const QColor& signalColor)
300{
301 m_pDelegate->setSignalColor(signalColor);
302}
303
304//=============================================================================================================
305
307{
308 return m_pDelegate->getSignalColor();
309}
310
311//=============================================================================================================
312
314{
316 m_bHideBadChannels = false;
317 } else {
318 m_bHideBadChannels = true;
319 }
320
321 //Hide non selected channels/rows in the data views
322 for(int i = 0; i<m_qListBadChannels.size(); i++) {
324 m_pTableView->hideRow(m_qListBadChannels.at(i));
325 } else {
326 m_pTableView->showRow(m_qListBadChannels.at(i));
327 }
328 }
329
330 //Update the visible channel list which are to be filtered
332}
333
334//=============================================================================================================
335
340
341//=============================================================================================================
342
343void RtFiffRawView::showSelectedChannelsOnly(const QStringList &selectedChannels)
344{
345 m_slSelectedChannels = selectedChannels;
346
347 //Hide non selected channels/rows in the data views
348 for(int i = 0; i<m_pModel->rowCount(); i++) {
349 QString channel = m_pModel->data(m_pModel->index(i, 0), Qt::DisplayRole).toString();
350
351 //if channel is a bad channel and bad channels are to be hidden -> do not show
352 if(!selectedChannels.contains(channel) || (m_qListBadChannels.contains(i) && m_bHideBadChannels)) {
353 m_pTableView->hideRow(i);
354 } else {
355 m_pTableView->showRow(i);
356 }
357 }
358
359 //Update the visible channel list which are to be filtered
361}
362
363//=============================================================================================================
364
365void RtFiffRawView::setZoom(double zoomFac)
366{
367 m_fZoomFactor = zoomFac;
368
369 m_pTableView->verticalHeader()->setDefaultSectionSize(m_pTableView->height() / m_fZoomFactor);//Row Height
370}
371
372//=============================================================================================================
373
375{
376 return m_fZoomFactor;
377}
378
379//=============================================================================================================
380
382{
383 m_iT = T;
384
385 m_pModel->setSamplingInfo(m_fSamplingRate, T);
386}
387
388//=============================================================================================================
389
391{
392 return m_iT;
393}
394
395//=============================================================================================================
396
398{
399 return m_fSamplingRate;
400}
401
402//=============================================================================================================
403
404void RtFiffRawView::takeScreenshot(const QString& fileName)
405{
406 if(fileName.contains(".svg", Qt::CaseInsensitive)) {
407 // Generate screenshot
408 QSvgGenerator svgGen;
409 svgGen.setFileName(fileName);
410 svgGen.setSize(m_pTableView->size());
411 svgGen.setViewBox(m_pTableView->rect());
412
413 m_pTableView->render(&svgGen);
414 }
415
416 if(fileName.contains(".png", Qt::CaseInsensitive)) {
417 QPixmap pixMap(m_pTableView->grab());
418 pixMap.save(fileName);
419 }
420}
421
422//=============================================================================================================
423
424void RtFiffRawView::updateProjection(const QList<FIFFLIB::FiffProj>& projs)
425{
426 m_pModel->updateProjection(projs);
427}
428
429//=============================================================================================================
430
432{
433 m_pModel->updateCompensator(to);
434}
435
436//=============================================================================================================
437
439{
440 m_pModel->updateSpharaActivation(state);
441}
442
443//=============================================================================================================
444
445void RtFiffRawView::updateSpharaOptions(const QString& sSytemType, int nBaseFctsFirst, int nBaseFctsSecond)
446{
447 m_pModel->updateSpharaOptions(sSytemType, nBaseFctsFirst, nBaseFctsSecond);
448}
449
450//=============================================================================================================
451
453{
454 m_pModel->setFilter(QList<FilterKernel>() << filterData);
455}
456
457//=============================================================================================================
458
460{
461 m_pModel->setFilterActive(state);
462}
463
464//=============================================================================================================
465
466void RtFiffRawView::setFilterChannelType(const QString &channelType)
467{
468 m_pModel->setFilterChannelType(channelType);
469}
470
471//=============================================================================================================
472
473void RtFiffRawView::triggerInfoChanged(const QMap<double, QColor>& colorMap,
474 bool active,
475 const QString &triggerCh,
476 double threshold)
477{
478 m_pModel->triggerInfoChanged(colorMap, active, triggerCh, threshold);
479}
480
481//=============================================================================================================
482
484{
485 m_iDistanceTimeSpacer = value;
486 m_pModel->distanceTimeSpacerChanged(value);
487}
488
489//=============================================================================================================
490
495
496//=============================================================================================================
497
499{
500 m_pModel->resetTriggerCounter();
501}
502
503//=============================================================================================================
504
506{
507 if(m_sSettingsPath.isEmpty()) {
508 return;
509 }
510
511 QSettings settings("MNECPP");
512}
513
514//=============================================================================================================
515
517{
518 if(m_sSettingsPath.isEmpty()) {
519 return;
520 }
521
522 QSettings settings("MNECPP");
523}
524
525//=============================================================================================================
526
528{
529 switch(mode) {
531 break;
532 default: // default is research mode
533 break;
534 }
535}
536
537//=============================================================================================================
538
540{
541 switch(mode) {
543 break;
544 default: // default is realtime mode
545 break;
546 }
547}
548
549//=============================================================================================================
550
552{
553 m_iClickPosX = pos.x();
554
555 //obtain index where index was clicked
556 QModelIndex index = m_pTableView->indexAt(pos);
557
558 //get selected items
559 QModelIndexList selected = m_pTableView->selectionModel()->selectedIndexes();
560
561 //create custom context menu and actions
562 QMenu *menu = new QMenu(this);
563
564 menu->addSection("Events");
565
566 QAction* addEventMarker = menu->addAction(tr("Add event"));
567 connect(addEventMarker, &QAction::triggered,
569
570 //Marking
571
572 menu->addSection("Channel Marking");
573
574 if(!m_qListBadChannels.contains(index.row())) {
575 QAction* doMarkChBad = menu->addAction(tr("Mark as bad"));
576 connect(doMarkChBad, &QAction::triggered,
578 } else {
579 QAction* doMarkChGood = menu->addAction(tr("Mark as good"));
580 connect(doMarkChGood, &QAction::triggered,
582 }
583
584 // non C++11 alternative
586 for(qint32 i = 0; i < selected.size(); ++i)
587 if(selected[i].column() == 1)
588 m_qListCurrentSelection.append(m_pModel->getIdxSelMap()[selected[i].row()]);
589
590 menu->addSection("Selection");
591
592 QAction* doSelection = menu->addAction(tr("Only show selection"));
593 connect(doSelection, &QAction::triggered,
595
596 //select channels
597 QAction* hideSelection = menu->addAction(tr("Hide selection"));
598 connect(hideSelection, &QAction::triggered, this,
600
601 //undo selection
602 QAction* resetAppliedSelection = menu->addAction(tr("Reset selection"));
603 connect(resetAppliedSelection, &QAction::triggered,
605 connect(resetAppliedSelection, &QAction::triggered,
607
608 //show context menu
609 menu->popup(m_pTableView->viewport()->mapToGlobal(pos));
610}
611
612//=============================================================================================================
613
615{
616 //Hide non selected channels/rows in the data views
617 for(int i = 0; i<m_pModel->rowCount(); i++) {
618 //if channel is a bad channel and bad channels are to be hidden -> do not show
619 if(m_qListCurrentSelection.contains(i)) {
620 m_pTableView->showRow(i);
621 } else {
622 m_pTableView->hideRow(i);
623 }
624 }
625
626 //Update the visible channel list which are to be filtered
627 //visibleRowsChanged();
628
629 //m_pModel->selectRows(m_qListCurrentSelection);
630}
631
632//=============================================================================================================
633
635{
636 for(int i=0; i<m_qListCurrentSelection.size(); i++) {
638 }
639
640 //Update the visible channel list which are to be filtered
641 //visibleRowsChanged();
642}
643
644//=============================================================================================================
645
647{
648 // non C++11 alternative
649 for(qint32 i = 0; i < m_pFiffInfo->chs.size(); ++i) {
650 if(m_qListBadChannels.contains(i)) {
651 if(!m_bHideBadChannels) {
652 m_pTableView->showRow(i);
653 }
654 } else {
655 m_pTableView->showRow(i);
656 }
657 }
658
659 //Update the visible channel list which are to be filtered
660 //visibleRowsChanged();
661}
662
663//=============================================================================================================
664
666{
667 if(!m_pTableView || !m_pModel || !m_pDelegate) {
668 return;
669 }
670
671 int from = m_pTableView->rowAt(0);
672// if(from != 0){
673// from--;
674
675 int to = m_pTableView->rowAt(m_pTableView->height()-1);
676 if(to != m_pModel->rowCount()-1)
677 to++;
678
679 if(from > to)
680 to = m_pModel->rowCount()-1;
681
682// //Update visible rows in order to only filter the visible rows
683// QStringList channelNames;
684
685// for(int i = from; i<=to; i++) {
686// channelNames << m_pModel->data(m_pModel->index(i, 0), Qt::DisplayRole).toString();
687// }
688
689// m_pModel->createFilterChannelList(channelNames);
690
691 m_pDelegate->setUpperItemIndex(from/*+1*/);
692
693 //qDebug() <<"RtFiffRawView::visibleRowsChanged - from "<< from << " to" << to;
694}
695
696//=============================================================================================================
697
699{
700 QModelIndexList selected = m_pTableView->selectionModel()->selectedIndexes();
701
702 for(int i=0; i<selected.size(); i++) {
703 if(m_qListBadChannels.contains(selected[i].row())) { //mark as good
704 m_pModel->markChBad(selected[i], false);
705 m_qListBadChannels.removeAll(selected[i].row());
706 }
707 else {
708 m_pModel->markChBad(selected[i], true);
709 m_qListBadChannels.append(selected[i].row());
710 }
711 }
712
713 m_pModel->updateProjection(m_pFiffInfo->projs);
714
715 //Hide non selected channels/rows in the data views
716 for(int i = 0; i<m_qListBadChannels.size(); i++) {
718 m_pTableView->hideRow(m_qListBadChannels.at(i));
719 } else {
720 m_pTableView->showRow(m_qListBadChannels.at(i));
721 }
722 }
723
725}
726
727//=============================================================================================================
728
730{
731
732}
733
734//=============================================================================================================
735
736void RtFiffRawView::onAddEvent(bool bChecked)
737{
738 Q_UNUSED(bChecked)
739 double dDx = static_cast<double>(m_pTableView->columnWidth(1)) / static_cast<double>(m_pModel->getMaxSamples());
740 double dSample = static_cast<double>(m_iClickPosX) / dDx;
741
742 int iFirstSampleOffset = m_pModel->getFirstSampleOffset();
743
744 // Dont allow adding events to blank space in the beginning
745 if (dSample > m_pModel->getCurrentSampleIndex() && iFirstSampleOffset == 0){
746 return;
747 }
748
749 //Add offset
750 int iAbsoluteSample = static_cast<int>(dSample) + iFirstSampleOffset;
751
752 //Account for whether adding before or after draw point
753 if (dSample > m_pModel->getCurrentSampleIndex()){
754 iAbsoluteSample -= m_pModel->getMaxSamples();
755 }
756
757 qDebug() << "EVENT SAMPLE:" << iAbsoluteSample;
758
759 emit addSampleAsEvent(iAbsoluteSample);
760}
Declaration of the RtFiffRawViewModel Class.
Declaration of the RtFiffRawViewDelegate Class.
Declaration of the RtFiffRawView Class.
The FilterKernel class represents a filter object that generates the FIR filter coefficients using Pa...
FiffInfo class declaration.
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
2-D display widgets and visualisation helpers (charts, topography, colour maps).
DSPSHARED_EXPORT Eigen::MatrixXd filterData(const Eigen::MatrixXd &matData, int type, double dCenterfreq, double dBandwidth, double dTransition, double dSFreq, int iOrder=1024, int designMethod=UTILSLIB::FilterKernel::m_designMethods.indexOf(UTILSLIB::FilterParameter("Cosine")), const Eigen::RowVectorXi &vecPicks=Eigen::RowVectorXi(), bool bUseThreads=true, bool bKeepOverhead=false)
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
AbstractView(QWidget *parent=0, Qt::WindowFlags f=Qt::Widget)
The RtFiffRawViewDelegate class represents a RTMSA delegate which creates the plot paths.
void markerMoved(QPoint position, int activeRow)
The RtFiffRawViewModel class implements the data access model for a real-time multi sample array data...
void toggleFreeze(const QModelIndex &index)
void triggerDetected(int numberDetectedTriggers, const QMap< int, QList< QPair< int, double > > > &mapDetectedTriggers)
void setFilterChannelType(const QString &channelType)
QPointer< DISPLIB::RtFiffRawViewModel > m_pModel
QMap< qint32, float > m_qMapChScaling
void init(QSharedPointer< FIFFLIB::FiffInfo > &info)
QMap< qint32, float > getScalingMap()
RtFiffRawView(const QString &sSettingsPath="", QWidget *parent=0, Qt::WindowFlags f=Qt::Widget)
void takeScreenshot(const QString &fileName)
void updateGuiMode(GuiMode mode)
bool eventFilter(QObject *object, QEvent *event)
void triggerDetected(int numberDetectedTriggers, const QMap< int, QList< QPair< int, double > > > &mapDetectedTriggers)
void setBackgroundColor(const QColor &backgroundColor)
void addSampleAsEvent(int iSample)
void updateSpharaOptions(const QString &sSytemType, int nBaseFctsFirst, int nBaseFctsSecond)
void setDistanceTimeSpacer(int value)
QList< qint32 > m_qListBadChannels
float getSamplingFreq() const
QStringList m_slSelectedChannels
void channelContextMenu(QPoint pos)
Eigen::MatrixXd getLastBlock()
QPointer< QTableView > m_pTableView
void markerMoved(QPoint position, int activeRow)
void addData(const QList< Eigen::MatrixXd > &data)
void updateProcessingMode(ProcessingMode mode)
void showSelectedChannelsOnly(const QStringList &selectedChannels)
void updateSpharaActivation(bool state)
QSharedPointer< FIFFLIB::FiffInfo > m_pFiffInfo
void triggerInfoChanged(const QMap< double, QColor > &colorMap, bool active, const QString &triggerCh, double threshold)
void setSignalColor(const QColor &signalColor)
void setSettingsPath(const QString &sSettingsPath)
QPointer< DISPLIB::RtFiffRawViewDelegate > m_pDelegate
void onAddEvent(bool bChecked)
void setFilterActive(bool state)
void setFilter(const UTILSLIB::FilterKernel &filterData)
QList< qint32 > m_qListCurrentSelection
void updateProjection(const QList< FIFFLIB::FiffProj > &projs)
void setZoom(double zoomFac)
void setScalingMap(const QMap< qint32, float > &scaleMap)
The FilterKernel class provides methods to create/design a FIR filter kernel.