FSUDAQ_Qt6/CustomWidgets.h
2023-05-18 17:14:24 -04:00

266 lines
7.4 KiB
C++

#ifndef CustomWidgets_H
#define CustomWidgets_H
#include <QLabel>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QWheelEvent>
#include <QChart>
#include <QChartView>
#include <QValueAxis>
#include <QRubberBand>
#include <QMouseEvent>
#include <QGestureEvent>
#include <QLineSeries>
#include <QAreaSeries>
#include <QValueAxis>
//^====================================================
class RSpinBox : public QDoubleSpinBox{
Q_OBJECT
public :
RSpinBox(QWidget * parent = nullptr, int decimal = 0): QDoubleSpinBox(parent){
setFocusPolicy(Qt::StrongFocus);
setDecimals(decimal);
}
void SetToolTip(double min = -1){
if( min == -1 ){
setToolTip("(" + QString::number(minimum()) + " - " + QString::number(maximum()) + ", " + QString::number(singleStep()) + ")");
}else{
setToolTip("(" + QString::number(min) + " - " + QString::number(maximum()) + ", " + QString::number(singleStep()) + ")");
}
setToolTipDuration(-1);
}
signals:
void returnPressed();
protected:
void wheelEvent(QWheelEvent * event) override{ event->ignore(); }
void keyPressEvent(QKeyEvent * event) override{
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
emit returnPressed();
} else {
QDoubleSpinBox::keyPressEvent(event);
}
}
};
//^====================================================
class RComboBox : public QComboBox{
public :
RComboBox(QWidget * parent = nullptr): QComboBox(parent){
setFocusPolicy(Qt::StrongFocus);
}
protected:
void wheelEvent(QWheelEvent * event) override{ event->ignore(); }
};
//^====================================================
class Trace : public QChart{
public:
explicit Trace(QGraphicsItem *parent = nullptr, Qt::WindowFlags wFlags = {})
: QChart(QChart::ChartTypeCartesian, parent, wFlags){
grabGesture(Qt::PanGesture);
grabGesture(Qt::PinchGesture);
}
~Trace(){}
protected:
bool sceneEvent(QEvent *event){
if (event->type() == QEvent::Gesture) return gestureEvent(static_cast<QGestureEvent *>(event));
return QChart::event(event);
}
private:
bool gestureEvent(QGestureEvent *event){
if (QGesture *gesture = event->gesture(Qt::PanGesture)) {
QPanGesture *pan = static_cast<QPanGesture *>(gesture);
QChart::scroll(-(pan->delta().x()), pan->delta().y());
}
if (QGesture *gesture = event->gesture(Qt::PinchGesture)) {
QPinchGesture *pinch = static_cast<QPinchGesture *>(gesture);
if (pinch->changeFlags() & QPinchGesture::ScaleFactorChanged) QChart::zoom(pinch->scaleFactor());
}
return true;
}
private:
};
//^====================================================
class TraceView : public QChartView{
public:
TraceView(QChart * chart, QWidget * parent = nullptr): QChartView(chart, parent){
m_isTouching = false;
this->setRubberBand(QChartView::RectangleRubberBand);
m_coordinateLabel = new QLabel(this);
m_coordinateLabel->setStyleSheet("QLabel { color : black; }");
m_coordinateLabel->setVisible(false);
m_coordinateLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
setMouseTracking(true);
setRenderHints(QPainter::Antialiasing);
}
void SetHRange(int min, int max) {
this->hRangeMin = min;
this->hRangeMax = max;
}
protected:
bool viewportEvent(QEvent *event) override{
if (event->type() == QEvent::TouchBegin) {
m_isTouching = true;
chart()->setAnimationOptions(QChart::NoAnimation);
}
return QChartView::viewportEvent(event);
}
void mousePressEvent(QMouseEvent *event) override{
if (m_isTouching) return;
QChartView::mousePressEvent(event);
}
void mouseMoveEvent(QMouseEvent *event) override{
QPointF chartPoint = this->chart()->mapToValue(event->pos());
QString coordinateText = QString("x: %1, y: %2").arg(QString::number(chartPoint.x(), 'f', 0)).arg(QString::number(chartPoint.y(), 'f', 0));
m_coordinateLabel->setText(coordinateText);
m_coordinateLabel->move(event->pos() + QPoint(10, -10));
m_coordinateLabel->setVisible(true);
if (m_isTouching) return;
QChartView::mouseMoveEvent(event);
}
void mouseReleaseEvent(QMouseEvent *event) override{
if (m_isTouching) m_isTouching = false;
chart()->setAnimationOptions(QChart::SeriesAnimations);
QChartView::mouseReleaseEvent(event);
}
void leaveEvent(QEvent *event) override {
m_coordinateLabel->setVisible(false);
QChartView::leaveEvent(event);
}
void keyPressEvent(QKeyEvent *event) override{
switch (event->key()) {
case Qt::Key_Plus: chart()->zoomIn(); break;
case Qt::Key_Minus: chart()->zoomOut(); break;
case Qt::Key_Left: chart()->scroll(-10, 0); break;
case Qt::Key_Right: chart()->scroll(10, 0); break;
case Qt::Key_Up: chart()->scroll(0, 10); break;
case Qt::Key_Down: chart()->scroll(0, -10); break;
case Qt::Key_R :
chart()->axes(Qt::Vertical).first()->setRange(-(0x1FFF), 0x1FFF);
//chart()->axes(Qt::Horizontal).first()->setRange(hRangeMin, hRangeMax);
break;
default: QGraphicsView::keyPressEvent(event); break;
}
}
private:
bool m_isTouching;
int hRangeMin;
int hRangeMax;
QLabel * m_coordinateLabel;
};
//^====================================================
class Histogram {
public:
Histogram(QString title, double xMin, double xMax, int nBin){
plot = new Trace();
dataSeries = new QLineSeries();
this->xMin = xMin;
this->xMax = xMax;
this->nBin = nBin;
dX = (xMax-xMin)/nBin;
Clear();
maxBin = -1;
maxBinValue = 0;
//dataSeries->setPen(QPen(Qt::blue, 1));
areaSeries = new QAreaSeries(dataSeries);
areaSeries->setName(title);
areaSeries->setBrush(Qt::blue);
plot->addSeries(areaSeries);
plot->setAnimationDuration(1); // msec
plot->setAnimationOptions(QChart::NoAnimation);
plot->createDefaultAxes();
QValueAxis * xaxis = qobject_cast<QValueAxis*> (plot->axes(Qt::Horizontal).first());
xaxis->setRange(xMin, xMax);
xaxis->setTickCount( nBin + 1 > 11 ? 11 : nBin + 1);
//xaxis->setLabelFormat("%.1f");
//xaxis->setTitleText("Time [ns]");
}
~Histogram(){
delete areaSeries;
delete dataSeries;
delete plot;
}
Trace * GetTrace() { return plot;}
void Clear(){
for( int i = 0; i <= nBin; i++) {
dataSeries->append(xMin + i * dX, 0 );
dataSeries->append(xMin + i * dX, 0 );
}
}
void SetColor(Qt::GlobalColor color){ areaSeries->setBrush(color);}
void Fill(double value){
double bin = (value - xMin)/dX;
if( bin < 0 || bin >= nBin ) return;
int index1 = 2*qFloor(bin) + 1;
int index2 = index1 + 1;
QPointF point1 = dataSeries->at(index1);
dataSeries->replace(index1, point1.x(), point1.y() + 1);
QPointF point2 = dataSeries->at(index2);
dataSeries->replace(index2, point2.x(), point2.y() + 1);
if( point2.y() + 1 > maxBinValue ){
maxBinValue = point2.y() + 1;
maxBin = index2/2;
}
QValueAxis * yaxis = qobject_cast<QValueAxis*> (plot->axes(Qt::Vertical).first());
//yaxis->setTickInterval(1);
yaxis->setRange(0, ((double)maxBinValue) * 1.2 );
//yaxis->setTickCount(10);
//yaxis->setLabelFormat("%.0f");
}
private:
Trace * plot;
QLineSeries * dataSeries;
QAreaSeries * areaSeries;
double dX, xMin, xMax;
int nBin;
int maxBin;
int maxBinValue;
};
//^====================================================
#endif