33#include <QPainterPath>
50: QAbstractItemDelegate(parent)
64 for(
int i = 0; i<model->rowCount(); i++)
65 m_painterPaths.append(QPainterPath());
68 QColor colorMarker(233,0,43);
69 colorMarker.setAlpha(160);
71 m_penMarker = QPen(colorMarker, 2, Qt::DashLine);
73 m_penGrid = QPen(Qt::black, 1, Qt::DashLine);
74 m_penTimeSpacers = QPen(Qt::black, 1, Qt::DashLine);
76 m_penFreeze = QPen(Qt::darkGray, 1, Qt::SolidLine);
77 m_penFreezeSelected = QPen(Qt::darkRed, 1, Qt::SolidLine);
79 m_penFreezeBad = QPen(Qt::darkGray, 0.1, Qt::SolidLine);
80 m_penFreezeSelectedBad = QPen(Qt::darkRed, 1, Qt::SolidLine);
82 m_penNormal = QPen(Qt::darkBlue, 1, Qt::SolidLine);
83 m_penNormalSelected = QPen(Qt::red, 1, Qt::SolidLine);
85 m_penNormalBad = QPen(Qt::darkBlue, 0.1, Qt::SolidLine);
86 m_penNormalSelectedBad = QPen(Qt::red, 1, Qt::SolidLine);
92 const QStyleOptionViewItem &option,
94 QPainterPath &lastPath,
96 QPointF &markerPosition,
98 const QVector<float> &data,
99 const QVector<float> &lastData)
104 qint32 kind = t_pModel->
getKind(index.row());
109 float dScaleY = option.rect.height()/(2*fMaxValue);
111 float y_base = path.currentPosition().y();
112 QPointF qSamplePosition;
114 float dDx = ((float)option.rect.width()) / t_pModel->
getMaxSamples();
122 float newY = y_base-dValue;
124 qSamplePosition.setY(newY);
125 qSamplePosition.setX(path.currentPosition().x());
127 path.moveTo(qSamplePosition);
132 for(i = 1; i < data.size(); ++i) {
133 float val = data[i] - data[0];
134 dValue = val*dScaleY;
137 float newY = y_base-dValue;
139 qSamplePosition.setY(newY);
140 qSamplePosition.setX(path.currentPosition().x()+dDx);
142 path.lineTo(qSamplePosition);
145 if(i == (qint32)(markerPosition.x()/dDx)) {
146 ellipsePos.setX(path.currentPosition().x()+dDx);
147 ellipsePos.setY(newY+(option.rect.height()/2));
149 amplitude = QString::number(data[i]);
154 qint32 sample_offset = t_pModel->
numVLines() + 1;
155 qSamplePosition.setX(qSamplePosition.x() + dDx*
static_cast<double>(sample_offset));
158 float val = lastData[i] - lastData[0];
159 dValue = val*dScaleY;
160 float newY = y_base-dValue;
161 qSamplePosition.setY(newY);
163 lastPath.moveTo(qSamplePosition);
165 for(i += sample_offset; i < lastData.size(); ++i) {
166 val = lastData[i] - lastData[0];
167 dValue = val*dScaleY;
169 newY = y_base-dValue;
171 qSamplePosition.setY(newY);
172 qSamplePosition.setX(lastPath.currentPosition().x()+dDx);
174 lastPath.lineTo(qSamplePosition);
177 if(i == (qint32)(markerPosition.x()/dDx)) {
178 ellipsePos.setX(lastPath.currentPosition().x()+dDx);
179 ellipsePos.setY(newY+(option.rect.height()/2));
181 amplitude = QString::number(lastData[i]);
189 const QStyleOptionViewItem &option,
190 const QModelIndex &index)
const
192 float t_fPlotHeight = option.rect.height();
193 painter->setRenderHint(QPainter::Antialiasing,
true);
195 switch(index.column()) {
199 painter->rotate(-90);
200 painter->drawText(QRectF(-option.rect.y()-t_fPlotHeight,0,t_fPlotHeight,20),Qt::AlignCenter,index.model()->data(index,Qt::DisplayRole).toString());
207 QBrush backgroundBrush = index.model()->data(index, Qt::BackgroundRole).value<QBrush>();
208 bool bIsBadChannel = index.model()->data(index.model()->index(index.row(), 2), Qt::DisplayRole).toBool();
212 if (index.row() == m_iUpperItemIndex) {
214 painter->setBrushOrigin(option.rect.topLeft());
215 QRect rect = option.rect;
216 rect.setHeight(2000);
217 painter->fillRect(rect, backgroundBrush);
224 QBrush brush(QColor(254,74,93,40));
225 painter->setBrushOrigin(option.rect.topLeft());
226 painter->fillRect(option.rect, brush);
239 QVariant variant = index.model()->data(index,Qt::DisplayRole);
244 if(data.second > 0) {
245 QPainterPath path(QPointF(option.rect.x(),option.rect.y()));
256 createGridPath(index, option, path, data);
259 painter->setPen(m_penGrid);
260 painter->drawPath(path);
264 createTimeSpacersPath(index, option, path, data);
267 painter->setPen(m_penTimeSpacers);
268 painter->drawPath(path);
272 path = QPainterPath(QPointF(option.rect.x(),option.rect.y()));
274 createTriggerPath(painter, index, option, path, data);
278 if(index.row() == t_pModel->getCurrentTriggerIndex() &&
279 t_pModel->triggerDetectionActive()) {
280 path = QPainterPath(QPointF(option.rect.x(),option.rect.y()));
281 QPointF textPosition;
282 createTriggerThresholdPath(index, option, path, data, textPosition);
285 painter->setPen(QPen(Qt::red, 1, Qt::DashLine));
286 painter->drawPath(path);
287 painter->drawText(textPosition, QString(
"%1 Threshold").arg(t_pModel->getTriggerName()));
291 path = QPainterPath(QPointF(option.rect.x(),option.rect.y()));
294 createPlotPath(index, option, path, data);
296 painter->setRenderHint(QPainter::Antialiasing,
true);
298 painter->translate(0, t_fPlotHeight/2);
301 if(t_pModel->isFreezed()) {
302 if(option.state & QStyle::State_Selected)
303 painter->setPen(m_penFreezeSelectedBad);
305 painter->setPen(m_penFreezeBad);
307 if(option.state & QStyle::State_Selected)
308 painter->setPen(m_penNormalSelectedBad);
310 painter->setPen(m_penNormalBad);
313 if(t_pModel->isFreezed()) {
314 if(option.state & QStyle::State_Selected)
315 painter->setPen(m_penFreezeSelected);
317 painter->setPen(m_penFreeze);
319 if(option.state & QStyle::State_Selected)
320 painter->setPen(m_penNormalSelected);
322 painter->setPen(m_penNormal);
326 painter->drawPath(path);
330 path = QPainterPath(QPointF(option.rect.x(),option.rect.y()));
331 createCurrentPositionMarkerPath(index, option, path);
334 painter->setPen(m_penMarker);
335 painter->drawPath(path);
338 path = QPainterPath(QPointF(option.rect.x(),option.rect.y()));
339 createMarkerPath(index, option, path);
342 painter->setPen(QPen(Qt::green, 1, Qt::SolidLine));
343 painter->drawPath(path);
354 const QModelIndex &index)
const
356 QSize size = option.rect.size();
358 switch(index.column()) {
360 size = QSize(20,option.rect.height());
363 QList< QVector<float> > data = index.model()->data(index).value< QList<QVector<float> > >();
378 m_markerPosition = position;
379 m_iActiveRow = activeRow;
386 m_penNormal.setColor(signalColor);
387 m_penNormalBad.setColor(signalColor);
394 return m_penNormal.color();
401 m_iUpperItemIndex = iUpperItemIndex;
406void RtFiffRawViewDelegate::createPlotPath(
const QModelIndex &index,
407 const QStyleOptionViewItem &option,
412 int iPlotSizePx = option.rect.width();
414 double dPixelsPerSample =
static_cast<double>(iPlotSizePx) /
static_cast<double>(iNumSamples);
422 double dScaleY = option.rect.height()/(2 * dMaxYValueEstimate);
423 double dChannelOffset = path.currentPosition().y();
437 path.moveTo(calcPoint(path, 0., 0., dChannelOffset, dScaleY));
447 for (
int j = 0; j < data.second; ++j) {
449 path.lineTo(calcPoint(path, dPixelsPerSample, dY,
450 dChannelOffset, dScaleY));
456void RtFiffRawViewDelegate::createCurrentPositionMarkerPath(
const QModelIndex &index,
const QStyleOptionViewItem &option, QPainterPath& path)
const
458 const RtFiffRawViewModel* t_pModel =
static_cast<const RtFiffRawViewModel*
>(index.model());
461 float dDx = ((float)option.rect.width()) / t_pModel->
getMaxSamples();
462 currentSampleIndex = currentSampleIndex*dDx;
464 float yStart = option.rect.topLeft().y();
465 float yEnd = option.rect.bottomRight().y();
467 path.moveTo(currentSampleIndex,yStart);
468 path.lineTo(currentSampleIndex,yEnd);
473void RtFiffRawViewDelegate::createGridPath(
const QModelIndex &index,
const QStyleOptionViewItem &option, QPainterPath& path,
RowVectorPair &data)
const
477 const RtFiffRawViewModel* t_pModel =
static_cast<const RtFiffRawViewModel*
>(index.model());
482 float distance = float (option.rect.width())/(t_pModel->
numVLines()+1);
484 float yStart = option.rect.topLeft().y();
486 float yEnd = option.rect.bottomRight().y();
488 for(qint32 i = 0; i < t_pModel->
numVLines(); ++i) {
489 float x = distance*(i+1);
490 path.moveTo(x,yStart);
498void RtFiffRawViewDelegate::createTimeSpacersPath(
const QModelIndex &index,
const QStyleOptionViewItem &option, QPainterPath& path,
RowVectorPair &data)
const
502 const RtFiffRawViewModel* t_pModel =
static_cast<const RtFiffRawViewModel*
>(index.model());
507 float distanceSec = float (option.rect.width())/(t_pModel->
numVLines()+1);
510 float yStart = option.rect.topLeft().y();
512 float yEnd = option.rect.bottomRight().y();
514 for(qint32 t = 0; t < t_pModel->
numVLines()+1; ++t) {
516 float x = (distanceSec*t)+(distanceSpacers*(i+1));
517 path.moveTo(x,yStart);
526void RtFiffRawViewDelegate::createTriggerPath(QPainter *painter,
527 const QModelIndex &index,
528 const QStyleOptionViewItem &option,
535 const RtFiffRawViewModel* t_pModel =
static_cast<const RtFiffRawViewModel*
>(index.model());
539 QMap<double, QColor> mapTriggerTypeColors = t_pModel->
getTriggerColor();
541 float yStart = option.rect.topLeft().y();
542 float yEnd = option.rect.bottomRight().y();
543 float dDx = ((float)option.rect.width()) / t_pModel->
getMaxSamples();
548 for(
int u = 0; u < detectedTriggers.size(); ++u) {
551 int triggerPos = detectedTriggers[u].first;
554 if(mapTriggerTypeColors.contains(detectedTriggers[u].second)) {
555 painter->setPen(QPen(mapTriggerTypeColors[detectedTriggers[u].second], 1.5, Qt::SolidLine));
558 if(triggerPos <= currentSampleIndex + t_pModel->getCurrentOverlapAddDelay()) {
559 path.moveTo(
static_cast<qreal
>(triggerPos)*dDx,yStart);
560 path.lineTo(
static_cast<qreal
>(triggerPos)*dDx,yEnd);
563 painter->drawPath(path);
568 for(
int u = 0; u < detectedTriggersOld.size(); ++u) {
571 int triggerPos = detectedTriggersOld[u].first;
576 if(mapTriggerTypeColors.contains(detectedTriggersOld[u].second)) {
577 painter->setPen(QPen(mapTriggerTypeColors[detectedTriggersOld[u].second], 1.5, Qt::SolidLine));
580 path.moveTo(
static_cast<qreal
>(triggerPos)*dDx,yStart);
581 path.lineTo(
static_cast<qreal
>(triggerPos)*dDx,yEnd);
583 painter->drawPath(path);
591void RtFiffRawViewDelegate::createTriggerThresholdPath(
const QModelIndex &index,
592 const QStyleOptionViewItem &option,
595 QPointF &textPosition)
const
599 const RtFiffRawViewModel* t_pModel =
static_cast<const RtFiffRawViewModel*
>(index.model());
602 qint32 kind = t_pModel->
getKind(index.row());
603 double dMaxValue = 1e-9f;
614 double dScaleY = option.rect.height()/(2*dMaxValue);
617 path.moveTo(option.rect.topLeft().x(), option.rect.topLeft().y()+option.rect.height()/2+dScaleY*triggerThreshold);
618 path.lineTo(option.rect.topRight().x(), option.rect.topLeft().y()+option.rect.height()/2+dScaleY*triggerThreshold);
620 textPosition = QPointF(option.rect.topLeft().x()+5, option.rect.topLeft().y()+option.rect.height()/2+dScaleY*triggerThreshold-5);
625void RtFiffRawViewDelegate::createMarkerPath(
const QModelIndex &index,
626 const QStyleOptionViewItem &option,
627 QPainterPath& path)
const
629 const RtFiffRawViewModel* t_pModel =
static_cast<const RtFiffRawViewModel*
>(index.model());
635 double dDx =
static_cast<double>(option.rect.width()) /
static_cast<double>(iMaxSample);
637 float yStart = option.rect.topLeft().y();
638 float yEnd = option.rect.bottomRight().y();
640 int iEarliestDrawnSample = iOffset - iMaxSample + iTimeCursorSample;
641 int iLatestDrawnSample = iOffset + iTimeCursorSample;
643 auto eventSamples = t_pModel->
getEventsToDisplay(iEarliestDrawnSample, iLatestDrawnSample);
645 for(
int iEventSample : eventSamples)
647 int iLastStartingSample = iOffset - iMaxSample;
648 int iDrawPositionInSamples = (iEventSample - iLastStartingSample) % iMaxSample;
650 float iPositionInPixels =
static_cast<float>(iDrawPositionInSamples) * dDx;
652 path.moveTo(iPositionInPixels,yStart);
653 path.lineTo(iPositionInPixels,yEnd);
659QPointF RtFiffRawViewDelegate::calcPoint(QPainterPath& path,
663 const double yScale)
const
665 double x = path.currentPosition().x() + dx;
666 double yScaled = -((yScale * y) - yBase);
671 return QPointF(x, yScaled);
Per-modality vertical-scale spinbox panel (one spin per channel type).
Real-time FIFF raw-data table browser backed by RtFiffRawViewModel + RtFiffRawViewDelegate.
QAbstractItemDelegate painting one FIFF channel's signal trace inside RtFiffRawView.
void createPaths(const QModelIndex &index, const QStyleOptionViewItem &option, QPainterPath &path, QPainterPath &lastPath, QPointF &ellipsePos, QPointF &markerPosition, QString &litude, const QVector< float > &data, const QVector< float > &lastData)
Circular-buffer QAbstractTableModel feeding the real-time FIFF raw browser.
2-D display widgets and visualisation helpers (charts, topography, colour maps).
float getScalingValue(const QMap< qint32, float > &qMapChScaling, int iChannelKind, int iChannelUnit)
QPair< const double *, qint32 > RowVectorPair
void setUpperItemIndex(int iUpperItemIndex)
RtFiffRawViewDelegate(RtFiffRawView *parent=0)
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
void initPainterPaths(const QAbstractTableModel *model)
void setSignalColor(const QColor &signalColor)
void markerMoved(QPoint position, int activeRow)
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
Circular-buffer QAbstractTableModel feeding the real-time FIFF raw browser.
double getTriggerThreshold() const
int getNumberOfTimeSpacers() const
double getLastBlockFirstValue(int row) const
const QMap< qint32, float > & getScaling() const
int getCurrentOverlapAddDelay() const
FIFFLIB::fiff_int_t getKind(qint32 row) const
qint32 getMaxSamples() const
QList< QPair< int, double > > getDetectedTriggers() const
int getFirstSampleOffset() const
QMap< double, QColor > getTriggerColor() const
FIFFLIB::fiff_int_t getUnit(qint32 row) const
std::vector< int > getEventsToDisplay(int iBegin, int iEnd) const
qint32 getCurrentSampleIndex() const
QList< QPair< int, double > > getDetectedTriggersOld() const
double getMaxValueFromRawViewModel(int row) const
QTableView-based real-time FIFF raw-data browser host.