File indexing completed on 2024-06-16 11:34:31

0001 /***************************************************************************
0002  *   Copyright (C) 2005 by David Saxton                                    *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "probepositioner.h"
0012 #include "oscilloscope.h"
0013 #include "oscilloscopedata.h"
0014 #include "oscilloscopeview.h"
0015 
0016 #include <QPaintEvent>
0017 #include <QPainter>
0018 // #include <q3pointarray.h> // 2018.08.14
0019 
0020 #include <algorithm>
0021 #include <cmath>
0022 
0023 #include <ktechlab_debug.h>
0024 
0025 ProbePositioner::ProbePositioner(QWidget *parent)
0026     : QWidget(parent /* , Qt::WNoAutoErase */)
0027 {
0028     m_probePosOffset = 0;
0029     p_draggedProbe = nullptr;
0030     setFixedWidth(int(probeArrowWidth));
0031     // setBackgroundMode(Qt::NoBackground); // 2018.12.07
0032     setBackgroundRole(QPalette::NoRole);
0033     b_needRedraw = true;
0034     m_pixmap = nullptr;
0035 }
0036 
0037 ProbePositioner::~ProbePositioner()
0038 {
0039     delete m_pixmap;
0040 }
0041 
0042 void ProbePositioner::forceRepaint()
0043 {
0044     b_needRedraw = true;
0045     repaint(/* false - 2018.12.07 */);
0046 }
0047 
0048 int ProbePositioner::probeOutputHeight() const
0049 {
0050     int height = int(Oscilloscope::self()->oscilloscopeView->height() - probeArrowHeight);
0051     int numProbes = Oscilloscope::self()->numberOfProbes();
0052     if (numProbes == 0)
0053         numProbes = 1;
0054     return height / numProbes;
0055 }
0056 
0057 int ProbePositioner::probePosition(ProbeData *probeData) const
0058 {
0059     if (!probeData)
0060         return -1;
0061 
0062     int spacing = probeOutputHeight();
0063     int probeNum = Oscilloscope::self()->probeNumber(probeData->id());
0064 
0065     return int(probeArrowHeight / 2 + spacing * (probeNum + probeData->drawPosition()));
0066 }
0067 
0068 void ProbePositioner::setProbePosition(ProbeData *probeData, int position)
0069 {
0070     if (!probeData)
0071         return;
0072 
0073     int height = int(Oscilloscope::self()->oscilloscopeView->height() - probeArrowHeight);
0074     int numProbes = Oscilloscope::self()->numberOfProbes();
0075     int spacing = height / numProbes;
0076     int probeNum = Oscilloscope::self()->probeNumber(probeData->id());
0077 
0078     int minPos = int(probeArrowHeight / 2);
0079     int maxPos = int(Oscilloscope::self()->oscilloscopeView->height() - (probeArrowHeight / 2)) - 1;
0080     if (position < minPos)
0081         position = minPos;
0082     else if (position > maxPos)
0083         position = maxPos;
0084 
0085     probeData->setDrawPosition(float(position - probeArrowHeight / 2) / float(spacing) - probeNum);
0086 
0087     forceRepaint();
0088     Oscilloscope::self()->oscilloscopeView->updateView();
0089 }
0090 
0091 ProbeData *ProbePositioner::probeAtPosition(const QPoint &pos)
0092 {
0093     int relativeArrowHeight = int(probeArrowHeight * (1. - float(pos.x() / probeArrowWidth)));
0094 
0095     const ProbeDataMap::const_iterator end = m_probeDataMap.end();
0096     for (ProbeDataMap::const_iterator it = m_probeDataMap.begin(); it != end; ++it) {
0097         ProbeData *probeData = it.value();
0098         int currentPos = probePosition(probeData);
0099         m_probePosOffset = pos.y() - currentPos;
0100         if (std::abs(m_probePosOffset) <= relativeArrowHeight)
0101             return probeData;
0102     }
0103     m_probePosOffset = 0;
0104     return nullptr;
0105 }
0106 
0107 void ProbePositioner::slotProbeDataRegistered(int id, ProbeData *probe)
0108 {
0109     m_probeDataMap[id] = probe;
0110     connect(probe, &ProbeData::displayAttributeChanged, this, &ProbePositioner::forceRepaint);
0111 
0112     // This connect doesn't really belong here, but it save a lot of code
0113     connect(probe, &ProbeData::displayAttributeChanged, Oscilloscope::self()->oscilloscopeView, &OscilloscopeView::updateView);
0114     forceRepaint();
0115     Oscilloscope::self()->oscilloscopeView->updateView();
0116 }
0117 
0118 void ProbePositioner::slotProbeDataUnregistered(int id)
0119 {
0120     m_probeDataMap.remove(id);
0121     // We "set" the position of each probe to force it into proper bounds
0122 
0123     const ProbeDataMap::const_iterator end = m_probeDataMap.end();
0124     for (ProbeDataMap::const_iterator it = m_probeDataMap.begin(); it != end; ++it)
0125         setProbePosition(it.value(), probePosition(it.value()));
0126 
0127     forceRepaint();
0128 }
0129 
0130 void ProbePositioner::resizeEvent(QResizeEvent *e)
0131 {
0132     delete m_pixmap;
0133     m_pixmap = new QPixmap(e->size());
0134     QWidget::resizeEvent(e);
0135     forceRepaint();
0136 }
0137 
0138 void ProbePositioner::mousePressEvent(QMouseEvent *e)
0139 {
0140     p_draggedProbe = probeAtPosition(e->pos());
0141     if (p_draggedProbe)
0142         e->accept();
0143     else
0144         e->ignore();
0145 }
0146 
0147 void ProbePositioner::mouseReleaseEvent(QMouseEvent *e)
0148 {
0149     if (p_draggedProbe)
0150         e->accept();
0151     else
0152         e->ignore();
0153 }
0154 
0155 void ProbePositioner::mouseMoveEvent(QMouseEvent *e)
0156 {
0157     if (!p_draggedProbe) {
0158         e->ignore();
0159         return;
0160     }
0161     e->accept();
0162 
0163     setProbePosition(p_draggedProbe, e->pos().y() - m_probePosOffset);
0164     forceRepaint();
0165 }
0166 
0167 void ProbePositioner::paintEvent(QPaintEvent *e)
0168 {
0169     QRect r = e->rect();
0170 
0171     if (b_needRedraw) {
0172         if (!m_pixmap) {
0173             qCWarning(KTL_LOG) << " unexpected null m_pixmap in " << this;
0174             return;
0175         }
0176 
0177         QPainter p;
0178         // m_pixmap->fill( paletteBackgroundColor() );
0179         m_pixmap->fill(palette().color(backgroundRole()));
0180         const bool startSuccess = p.begin(m_pixmap);
0181         if ((!startSuccess) || (!p.isActive())) {
0182             qCWarning(KTL_LOG) << " painter is not active";
0183         }
0184 
0185         p.setClipRegion(e->region());
0186 
0187         const ProbeDataMap::const_iterator end = m_probeDataMap.end();
0188         for (ProbeDataMap::const_iterator it = m_probeDataMap.begin(); it != end; ++it) {
0189             ProbeData *probeData = it.value();
0190             p.setBrush(probeData->color());
0191             int currentPos = probePosition(probeData);
0192 
0193             QPolygon pa(3);
0194             pa[0] = QPoint(0, int(currentPos - (probeArrowHeight / 2)));
0195             pa[1] = QPoint(int(probeArrowWidth), currentPos);
0196             pa[2] = QPoint(0, int(currentPos + (probeArrowHeight / 2)));
0197 
0198             p.drawPolygon(pa);
0199         }
0200         b_needRedraw = false;
0201     }
0202 
0203     // bitBlt( this, r.x(), r.y(), m_pixmap, r.x(), r.y(), r.width(), r.height() ); // 2018.12.07
0204     QPainter p;
0205     const bool paintStarted = p.begin(this);
0206     if (!paintStarted) {
0207         qCWarning(KTL_LOG) << " failed to start painting ";
0208     }
0209     p.drawImage(r, m_pixmap->toImage(), r);
0210 }
0211 
0212 #include "moc_probepositioner.cpp"