v2.0.0
Loading...
Searching...
No Matches
rtfiffrawview.cpp
Go to the documentation of this file.
1//=============================================================================================================
15
16//=============================================================================================================
17// INCLUDES
18//=============================================================================================================
19
20#include "rtfiffrawview.h"
21
24
25#include <dsp/filterkernel.h>
26#include <fiff/fiff_info.h>
27
28//=============================================================================================================
29// QT INCLUDES
30//=============================================================================================================
31
32#include <QGridLayout>
33#include <QHeaderView>
34#include <QTableView>
35#include <QMenu>
36#include <QSvgGenerator>
37#include <QSettings>
38#include <QScrollBar>
39#include <QMouseEvent>
40#include <QRhiWidget>
41
42
43
44//=============================================================================================================
45// USED NAMESPACES
46//=============================================================================================================
47
48using namespace DISPLIB;
49using namespace FIFFLIB;
50using namespace Eigen;
51using namespace RTPROCESSINGLIB;
52using namespace UTILSLIB;
53
54//=============================================================================================================
55// DEFINE MEMBER METHODS
56//=============================================================================================================
57
58RtFiffRawView::RtFiffRawView(const QString& sSettingsPath,
59 QWidget *parent,
60 Qt::WindowFlags f)
61: AbstractView(parent, f)
62, m_iT(10)
63, m_fSamplingRate(1024)
64, m_fZoomFactor(1.0f)
65, m_bHideBadChannels(false)
67, m_iClickPosX(0)
68{
69 m_sSettingsPath = sSettingsPath;
70 m_pTableView = new QTableView;
71
72 auto *rhiViewport = new QRhiWidget;
73#if defined(WASMBUILD) || defined(__EMSCRIPTEN__)
74 rhiViewport->setApi(QRhiWidget::Api::OpenGL);
75#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
76 rhiViewport->setApi(QRhiWidget::Api::Metal);
77#elif defined(Q_OS_WIN)
78 rhiViewport->setApi(QRhiWidget::Api::Direct3D11);
79#else
80 rhiViewport->setApi(QRhiWidget::Api::OpenGL);
81#endif
82 m_pTableView->setViewport(rhiViewport);
83
84 // Install event filter for tracking mouse movements
85 m_pTableView->viewport()->installEventFilter(this);
86 m_pTableView->setMouseTracking(true);
87
88 // Set layout
89 QVBoxLayout *neLayout = new QVBoxLayout(this);
90 neLayout->addWidget(m_pTableView);
91 neLayout->setContentsMargins(0,0,0,0);
92 this->setLayout(neLayout);
93
95}
96
97//=============================================================================================================
98
103
104//=============================================================================================================
105
107{
108 if(m_pTableView) {
109 auto *rhiViewport = new QRhiWidget;
110#if defined(WASMBUILD) || defined(__EMSCRIPTEN__)
111 rhiViewport->setApi(QRhiWidget::Api::OpenGL);
112#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
113 rhiViewport->setApi(QRhiWidget::Api::Metal);
114#elif defined(Q_OS_WIN)
115 rhiViewport->setApi(QRhiWidget::Api::Direct3D11);
116#else
117 rhiViewport->setApi(QRhiWidget::Api::OpenGL);
118#endif
119 m_pTableView->setViewport(rhiViewport);
120 }
121}
122
123//=============================================================================================================
124
125void RtFiffRawView::setSettingsPath(const QString& sSettingsPath)
126{
127 m_sSettingsPath = sSettingsPath;
128 loadSettings();
129}
130
131//=============================================================================================================
132
133void RtFiffRawView::init(QSharedPointer<FIFFLIB::FiffInfo> &info)
134{
135 m_pFiffInfo = info;
137
138 //Init the model
139 m_pModel = new RtFiffRawViewModel(this);
140 m_pModel->setFiffInfo(m_pFiffInfo);
141 m_pModel->setSamplingInfo(m_fSamplingRate, m_iT, true);
144 connect(this, &RtFiffRawView::addSampleAsEvent,
145 m_pModel, &RtFiffRawViewModel::addEvent, Qt::UniqueConnection);
146
147 //Init bad channel list
148 m_qListBadChannels.clear();
149 for(int i = 0; i<m_pModel->rowCount(); i++) {
150 if(m_pModel->data(m_pModel->index(i,2)).toBool()) {
152 }
153 }
154
155 //Init the delegate
157 m_pDelegate->initPainterPaths(m_pModel);
158
159 connect(this, &RtFiffRawView::markerMoved,
161
162 //Init the view
163 m_pTableView->setModel(m_pModel);
164 m_pTableView->setItemDelegate(m_pDelegate);
165 m_pTableView->setContextMenuPolicy(Qt::CustomContextMenu);
166
167 connect(m_pTableView.data(), &QTableView::doubleClicked,
169
170 connect(m_pTableView.data(), &QTableView::customContextMenuRequested,
172
173 //set some size settings for m_pTableView
174 m_pTableView->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
175 m_pTableView->setShowGrid(false);
176 m_pTableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); //Stretch 2 column to maximal width
177 m_pTableView->horizontalHeader()->hide();
178 m_pTableView->verticalHeader()->setDefaultSectionSize(m_pTableView->height() / m_fZoomFactor);//Row Height
179 m_pTableView->setAutoScroll(false);
180 m_pTableView->setColumnHidden(0,true); //because content is plotted jointly with column=1
181 m_pTableView->setColumnHidden(2,true);
182 m_pTableView->resizeColumnsToContents();
183 m_pTableView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
184
185 connect(m_pTableView->verticalScrollBar(), &QScrollBar::valueChanged,
187}
188
189//=============================================================================================================
190
191void RtFiffRawView::addData(const QList<Eigen::MatrixXd> &data)
192{
193 if(!data.isEmpty()) {
194 m_pModel->addData(data);
195
196 if(m_qListBadChannels.size() != m_pFiffInfo->bads.size()) {
197 m_qListBadChannels.clear();
198 for(int i = 0; i<m_pModel->rowCount(); i++) {
199 if(m_pModel->data(m_pModel->index(i,2)).toBool()) {
201 }
202 }
203
204 //Hide non selected channels/rows in the data views
205 for(int i = 0; i<m_qListBadChannels.size(); i++) {
207 m_pTableView->hideRow(m_qListBadChannels.at(i));
208 } else {
209 m_pTableView->showRow(m_qListBadChannels.at(i));
210 }
211 }
212 }
213 } else {
214 qWarning() << "[RtFiffRawView::addData] Received data list is empty.";
215 }
216}
217
218//=============================================================================================================
219
221{
222 return m_pModel->getLastBlock();
223}
224
225//=============================================================================================================
226
227bool RtFiffRawView::eventFilter(QObject *object, QEvent *event)
228{
229// if (object == m_pTableView->viewport() && event->type() == QEvent::MouseMove) {
230// QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
231// emit markerMoved(mouseEvent->pos(), m_pTableView->rowAt(mouseEvent->pos().y()));
232// return true;
233// }
234
235 return QWidget::eventFilter(object, event);
236}
237
238//=============================================================================================================
239
240void RtFiffRawView::setBackgroundColor(const QColor& backgroundColor)
241{
242 m_backgroundColor = backgroundColor;
243
244 if(m_pModel) {
245 m_pModel->setBackgroundColor(m_backgroundColor);
246 }
247
248// QPalette pal;
249// pal.setColor(QPalette::Window, m_backgroundColor);
250// m_pTableView->viewport()->setPalette(pal);
251// m_pTableView->viewport()->setBackgroundRole(QPalette::Window);
252}
253
254//=============================================================================================================
255
260
261//=============================================================================================================
262
263QMap<qint32, float> RtFiffRawView::getScalingMap()
264{
265 return m_qMapChScaling;
266}
267
268//=============================================================================================================
269
270void RtFiffRawView::setScalingMap(const QMap<qint32, float>& scaleMap)
271{
272 m_qMapChScaling = scaleMap;
273 m_pModel->setScaling(scaleMap);
274}
275
276//=============================================================================================================
277
278void RtFiffRawView::setSignalColor(const QColor& signalColor)
279{
280 m_pDelegate->setSignalColor(signalColor);
281}
282
283//=============================================================================================================
284
286{
287 return m_pDelegate->getSignalColor();
288}
289
290//=============================================================================================================
291
293{
295 m_bHideBadChannels = false;
296 } else {
297 m_bHideBadChannels = true;
298 }
299
300 //Hide non selected channels/rows in the data views
301 for(int i = 0; i<m_qListBadChannels.size(); i++) {
303 m_pTableView->hideRow(m_qListBadChannels.at(i));
304 } else {
305 m_pTableView->showRow(m_qListBadChannels.at(i));
306 }
307 }
308
309 //Update the visible channel list which are to be filtered
311}
312
313//=============================================================================================================
314
319
320//=============================================================================================================
321
322void RtFiffRawView::showSelectedChannelsOnly(const QStringList &selectedChannels)
323{
324 m_slSelectedChannels = selectedChannels;
325
326 //Hide non selected channels/rows in the data views
327 for(int i = 0; i<m_pModel->rowCount(); i++) {
328 QString channel = m_pModel->data(m_pModel->index(i, 0), Qt::DisplayRole).toString();
329
330 //if channel is a bad channel and bad channels are to be hidden -> do not show
331 if(!selectedChannels.contains(channel) || (m_qListBadChannels.contains(i) && m_bHideBadChannels)) {
332 m_pTableView->hideRow(i);
333 } else {
334 m_pTableView->showRow(i);
335 }
336 }
337
338 //Update the visible channel list which are to be filtered
340}
341
342//=============================================================================================================
343
344void RtFiffRawView::setZoom(double zoomFac)
345{
346 m_fZoomFactor = zoomFac;
347
348 m_pTableView->verticalHeader()->setDefaultSectionSize(m_pTableView->height() / m_fZoomFactor);//Row Height
349}
350
351//=============================================================================================================
352
354{
355 return m_fZoomFactor;
356}
357
358//=============================================================================================================
359
361{
362 m_iT = T;
363
364 m_pModel->setSamplingInfo(m_fSamplingRate, T);
365}
366
367//=============================================================================================================
368
370{
371 return m_iT;
372}
373
374//=============================================================================================================
375
377{
378 return m_fSamplingRate;
379}
380
381//=============================================================================================================
382
383void RtFiffRawView::takeScreenshot(const QString& fileName)
384{
385 if(fileName.contains(".svg", Qt::CaseInsensitive)) {
386 // Generate screenshot
387 QSvgGenerator svgGen;
388 svgGen.setFileName(fileName);
389 svgGen.setSize(m_pTableView->size());
390 svgGen.setViewBox(m_pTableView->rect());
391
392 m_pTableView->render(&svgGen);
393 }
394
395 if(fileName.contains(".png", Qt::CaseInsensitive)) {
396 QPixmap pixMap(m_pTableView->grab());
397 pixMap.save(fileName);
398 }
399}
400
401//=============================================================================================================
402
403void RtFiffRawView::updateProjection(const QList<FIFFLIB::FiffProj>& projs)
404{
405 m_pModel->updateProjection(projs);
406}
407
408//=============================================================================================================
409
411{
412 m_pModel->updateCompensator(to);
413}
414
415//=============================================================================================================
416
418{
419 m_pModel->updateSpharaActivation(state);
420}
421
422//=============================================================================================================
423
424void RtFiffRawView::updateSpharaOptions(const QString& sSytemType, int nBaseFctsFirst, int nBaseFctsSecond)
425{
426 m_pModel->updateSpharaOptions(sSytemType, nBaseFctsFirst, nBaseFctsSecond);
427}
428
429//=============================================================================================================
430
432{
433 m_pModel->setFilter(QList<FilterKernel>() << filterData);
434}
435
436//=============================================================================================================
437
439{
440 m_pModel->setFilterActive(state);
441}
442
443//=============================================================================================================
444
445void RtFiffRawView::setFilterChannelType(const QString &channelType)
446{
447 m_pModel->setFilterChannelType(channelType);
448}
449
450//=============================================================================================================
451
452void RtFiffRawView::triggerInfoChanged(const QMap<double, QColor>& colorMap,
453 bool active,
454 const QString &triggerCh,
455 double threshold)
456{
457 m_pModel->triggerInfoChanged(colorMap, active, triggerCh, threshold);
458}
459
460//=============================================================================================================
461
463{
464 m_iDistanceTimeSpacer = value;
465 m_pModel->distanceTimeSpacerChanged(value);
466}
467
468//=============================================================================================================
469
474
475//=============================================================================================================
476
478{
479 m_pModel->resetTriggerCounter();
480}
481
482//=============================================================================================================
483
485{
486 if(m_sSettingsPath.isEmpty()) {
487 return;
488 }
489
490 QSettings settings("MNECPP");
491}
492
493//=============================================================================================================
494
496{
497 if(m_sSettingsPath.isEmpty()) {
498 return;
499 }
500
501 QSettings settings("MNECPP");
502}
503
504//=============================================================================================================
505
507{
508 switch(mode) {
510 break;
511 default: // default is research mode
512 break;
513 }
514}
515
516//=============================================================================================================
517
519{
520 switch(mode) {
522 break;
523 default: // default is realtime mode
524 break;
525 }
526}
527
528//=============================================================================================================
529
531{
532 m_iClickPosX = pos.x();
533
534 //obtain index where index was clicked
535 QModelIndex index = m_pTableView->indexAt(pos);
536
537 //get selected items
538 QModelIndexList selected = m_pTableView->selectionModel()->selectedIndexes();
539
540 //create custom context menu and actions
541 QMenu *menu = new QMenu(this);
542
543 menu->addSection("Events");
544
545 QAction* addEventMarker = menu->addAction(tr("Add event"));
546 connect(addEventMarker, &QAction::triggered,
548
549 //Marking
550
551 menu->addSection("Channel Marking");
552
553 if(!m_qListBadChannels.contains(index.row())) {
554 QAction* doMarkChBad = menu->addAction(tr("Mark as bad"));
555 connect(doMarkChBad, &QAction::triggered,
557 } else {
558 QAction* doMarkChGood = menu->addAction(tr("Mark as good"));
559 connect(doMarkChGood, &QAction::triggered,
561 }
562
563 // non C++11 alternative
565 for(qint32 i = 0; i < selected.size(); ++i)
566 if(selected[i].column() == 1)
567 m_qListCurrentSelection.append(m_pModel->getIdxSelMap()[selected[i].row()]);
568
569 menu->addSection("Selection");
570
571 QAction* doSelection = menu->addAction(tr("Only show selection"));
572 connect(doSelection, &QAction::triggered,
574
575 //select channels
576 QAction* hideSelection = menu->addAction(tr("Hide selection"));
577 connect(hideSelection, &QAction::triggered, this,
579
580 //undo selection
581 QAction* resetAppliedSelection = menu->addAction(tr("Reset selection"));
582 connect(resetAppliedSelection, &QAction::triggered,
584 connect(resetAppliedSelection, &QAction::triggered,
586
587 //show context menu
588 menu->popup(m_pTableView->viewport()->mapToGlobal(pos));
589}
590
591//=============================================================================================================
592
594{
595 //Hide non selected channels/rows in the data views
596 for(int i = 0; i<m_pModel->rowCount(); i++) {
597 //if channel is a bad channel and bad channels are to be hidden -> do not show
598 if(m_qListCurrentSelection.contains(i)) {
599 m_pTableView->showRow(i);
600 } else {
601 m_pTableView->hideRow(i);
602 }
603 }
604
605 //Update the visible channel list which are to be filtered
606 //visibleRowsChanged();
607
608 //m_pModel->selectRows(m_qListCurrentSelection);
609}
610
611//=============================================================================================================
612
614{
615 for(int i=0; i<m_qListCurrentSelection.size(); i++) {
617 }
618
619 //Update the visible channel list which are to be filtered
620 //visibleRowsChanged();
621}
622
623//=============================================================================================================
624
626{
627 // non C++11 alternative
628 for(qint32 i = 0; i < m_pFiffInfo->chs.size(); ++i) {
629 if(m_qListBadChannels.contains(i)) {
630 if(!m_bHideBadChannels) {
631 m_pTableView->showRow(i);
632 }
633 } else {
634 m_pTableView->showRow(i);
635 }
636 }
637
638 //Update the visible channel list which are to be filtered
639 //visibleRowsChanged();
640}
641
642//=============================================================================================================
643
645{
646 if(!m_pTableView || !m_pModel || !m_pDelegate) {
647 return;
648 }
649
650 int from = m_pTableView->rowAt(0);
651// if(from != 0){
652// from--;
653
654 int to = m_pTableView->rowAt(m_pTableView->height()-1);
655 if(to != m_pModel->rowCount()-1)
656 to++;
657
658 if(from > to)
659 to = m_pModel->rowCount()-1;
660
661// //Update visible rows in order to only filter the visible rows
662// QStringList channelNames;
663
664// for(int i = from; i<=to; i++) {
665// channelNames << m_pModel->data(m_pModel->index(i, 0), Qt::DisplayRole).toString();
666// }
667
668// m_pModel->createFilterChannelList(channelNames);
669
670 m_pDelegate->setUpperItemIndex(from/*+1*/);
671
672 //qDebug() <<"RtFiffRawView::visibleRowsChanged - from "<< from << " to" << to;
673}
674
675//=============================================================================================================
676
678{
679 QModelIndexList selected = m_pTableView->selectionModel()->selectedIndexes();
680
681 for(int i=0; i<selected.size(); i++) {
682 if(m_qListBadChannels.contains(selected[i].row())) { //mark as good
683 m_pModel->markChBad(selected[i], false);
684 m_qListBadChannels.removeAll(selected[i].row());
685 }
686 else {
687 m_pModel->markChBad(selected[i], true);
688 m_qListBadChannels.append(selected[i].row());
689 }
690 }
691
692 m_pModel->updateProjection(m_pFiffInfo->projs);
693
694 //Hide non selected channels/rows in the data views
695 for(int i = 0; i<m_qListBadChannels.size(); i++) {
697 m_pTableView->hideRow(m_qListBadChannels.at(i));
698 } else {
699 m_pTableView->showRow(m_qListBadChannels.at(i));
700 }
701 }
702
704}
705
706//=============================================================================================================
707
709{
710
711}
712
713//=============================================================================================================
714
715void RtFiffRawView::onAddEvent(bool bChecked)
716{
717 Q_UNUSED(bChecked)
718 double dDx = static_cast<double>(m_pTableView->columnWidth(1)) / static_cast<double>(m_pModel->getMaxSamples());
719 double dSample = static_cast<double>(m_iClickPosX) / dDx;
720
721 int iFirstSampleOffset = m_pModel->getFirstSampleOffset();
722
723 // Dont allow adding events to blank space in the beginning
724 if (dSample > m_pModel->getCurrentSampleIndex() && iFirstSampleOffset == 0){
725 return;
726 }
727
728 //Add offset
729 int iAbsoluteSample = static_cast<int>(dSample) + iFirstSampleOffset;
730
731 //Account for whether adding before or after draw point
732 if (dSample > m_pModel->getCurrentSampleIndex()){
733 iAbsoluteSample -= m_pModel->getMaxSamples();
734 }
735
736 qDebug() << "EVENT SAMPLE:" << iAbsoluteSample;
737
738 emit addSampleAsEvent(iAbsoluteSample);
739}
Real-time FIFF raw-data table browser backed by RtFiffRawViewModel + RtFiffRawViewDelegate.
QAbstractItemDelegate painting one FIFF channel's signal trace inside RtFiffRawView.
Circular-buffer QAbstractTableModel feeding the real-time FIFF raw browser.
Full FIFF measurement metadata: everything from FIFFB_MEAS / FIFFB_MEAS_INFO needed to interpret a re...
Linear-phase FIR filter kernel with overlap-add FFT convolution back-end.
FIFF file I/O, in-memory data structures and high-level readers/writers.
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)
QAbstractItemDelegate painting one FIFF channel's signal trace inside RtFiffRawView.
void markerMoved(QPoint position, int activeRow)
Circular-buffer QAbstractTableModel feeding the real-time FIFF raw browser.
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.