Files
qwt/playground/plotmatrix/PlotMatrix.cpp
2023-10-31 09:22:42 +01:00

427 lines
11 KiB
C++

/*****************************************************************************
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "PlotMatrix.h"
#include <QwtPlot>
#include <QwtPlotCanvas>
#include <QwtScaleWidget>
#include <QwtScaleDraw>
#include <QLayout>
static void enablePlotAxis( QwtPlot* plot, int axis, bool on )
{
// when false we still enable the axis to have an effect
// of the minimal extent active. Instead we hide all visible
// parts and margins/spacings.
plot->setAxisVisible( axis, true );
QwtScaleDraw* sd = plot->axisScaleDraw( axis );
sd->enableComponent( QwtScaleDraw::Backbone, on );
sd->enableComponent( QwtScaleDraw::Ticks, on );
sd->enableComponent( QwtScaleDraw::Labels, on );
QwtScaleWidget* sw = plot->axisWidget( axis );
sw->setMargin( on ? 4 : 0 );
sw->setSpacing( on ? 20 : 0 );
}
namespace
{
class Plot : public QwtPlot
{
public:
Plot( QWidget* parent = NULL )
: QwtPlot( parent )
{
QwtPlotCanvas* canvas = new QwtPlotCanvas();
canvas->setLineWidth( 1 );
canvas->setFrameStyle( QFrame::Box | QFrame::Plain );
setCanvas( canvas );
}
virtual QSize sizeHint() const QWT_OVERRIDE
{
return minimumSizeHint();
}
};
}
class PlotMatrix::PrivateData
{
public:
PrivateData():
inScaleSync( false )
{
isAxisEnabled[QwtAxis::XBottom] = true;
isAxisEnabled[QwtAxis::XTop] = false;
isAxisEnabled[QwtAxis::YLeft] = true;
isAxisEnabled[QwtAxis::YRight] = false;
}
bool isAxisEnabled[QwtAxis::AxisPositions];
QVector< QwtPlot* > plotWidgets;
mutable bool inScaleSync;
};
PlotMatrix::PlotMatrix( int numRows, int numColumns, QWidget* parent )
: QFrame( parent )
{
m_data = new PrivateData();
m_data->plotWidgets.resize( numRows * numColumns );
QGridLayout* layout = new QGridLayout( this );
layout->setSpacing( 5 );
for ( int row = 0; row < numRows; row++ )
{
for ( int col = 0; col < numColumns; col++ )
{
QwtPlot* plot = new Plot( this );
layout->addWidget( plot, row, col );
for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
{
connect( plot->axisWidget( axisPos ),
SIGNAL(scaleDivChanged()), SLOT(scaleDivChanged()),
Qt::QueuedConnection );
}
m_data->plotWidgets[row * numColumns + col] = plot;
}
}
updateLayout();
}
PlotMatrix::~PlotMatrix()
{
delete m_data;
}
int PlotMatrix::numRows() const
{
const QGridLayout* l = qobject_cast< const QGridLayout* >( layout() );
if ( l )
return l->rowCount();
return 0;
}
int PlotMatrix::numColumns() const
{
const QGridLayout* l = qobject_cast< const QGridLayout* >( layout() );
if ( l )
return l->columnCount();
return 0;
}
QwtPlot* PlotMatrix::plotAt( int row, int column )
{
const int index = row * numColumns() + column;
if ( index < m_data->plotWidgets.size() )
return m_data->plotWidgets[index];
return NULL;
}
const QwtPlot* PlotMatrix::plotAt( int row, int column ) const
{
const int index = row * numColumns() + column;
if ( index < m_data->plotWidgets.size() )
return m_data->plotWidgets[index];
return NULL;
}
void PlotMatrix::setAxisVisible( int axis, bool tf )
{
if ( QwtAxis::isValid( axis ) )
{
if ( tf != m_data->isAxisEnabled[axis] )
{
m_data->isAxisEnabled[axis] = tf;
updateLayout();
}
}
}
bool PlotMatrix::isAxisVisible( int axis ) const
{
if ( QwtAxis::isValid( axis ) )
return m_data->isAxisEnabled[axis];
return false;
}
void PlotMatrix::setAxisScale( int axis, int rowOrColumn,
double min, double max, double step )
{
int row = 0;
int col = 0;
if ( QwtAxis::isXAxis( axis ) )
col = rowOrColumn;
else
row = rowOrColumn;
QwtPlot* plt = plotAt( row, col );
if ( plt )
{
plt->setAxisScale( axis, min, max, step );
plt->updateAxes();
}
}
void PlotMatrix::scaleDivChanged()
{
if ( m_data->inScaleSync )
return;
m_data->inScaleSync = true;
QwtPlot* plt = NULL;
int axisId = -1;
int rowOrColumn = -1;
// find the changed axis
for ( int row = 0; row < numRows(); row++ )
{
for ( int col = 0; col < numColumns(); col++ )
{
QwtPlot* p = plotAt( row, col );
if ( p )
{
for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
{
if ( p->axisWidget( axisPos ) == sender() )
{
plt = p;
axisId = axisPos;
rowOrColumn = QwtAxis::isXAxis( axisId ) ? col : row;
}
}
}
}
}
if ( plt )
{
const QwtScaleDiv scaleDiv = plt->axisScaleDiv( axisId );
// synchronize the axes
if ( QwtAxis::isXAxis( axisId ) )
{
for ( int row = 0; row < numRows(); row++ )
{
QwtPlot* p = plotAt( row, rowOrColumn );
if ( p != plt )
{
p->setAxisScaleDiv( axisId, scaleDiv );
}
}
}
else
{
for ( int col = 0; col < numColumns(); col++ )
{
QwtPlot* p = plotAt( rowOrColumn, col );
if ( p != plt )
{
p->setAxisScaleDiv( axisId, scaleDiv );
}
}
}
updateLayout();
}
m_data->inScaleSync = false;
}
void PlotMatrix::updateLayout()
{
using namespace QwtAxis;
for ( int row = 0; row < numRows(); row++ )
{
for ( int col = 0; col < numColumns(); col++ )
{
QwtPlot* p = plotAt( row, col );
if ( p )
{
bool showAxis[AxisPositions];
showAxis[XBottom] = isAxisVisible( XBottom ) && row == numRows() - 1;
showAxis[XTop] = isAxisVisible( XTop ) && row == 0;
showAxis[YLeft] = isAxisVisible( YLeft ) && col == 0;
showAxis[YRight] = isAxisVisible( YRight ) && col == numColumns() - 1;
for ( int axis = 0; axis < AxisPositions; axis++ )
{
enablePlotAxis( p, axis, showAxis[axis] );
}
}
}
}
for ( int row = 0; row < numRows(); row++ )
{
alignAxes( row, XTop );
alignAxes( row, XBottom );
alignScaleBorder( row, YLeft );
alignScaleBorder( row, YRight );
}
for ( int col = 0; col < numColumns(); col++ )
{
alignAxes( col, YLeft );
alignAxes( col, YRight );
alignScaleBorder( col, XBottom );
alignScaleBorder( col, XTop );
}
for ( int row = 0; row < numRows(); row++ )
{
for ( int col = 0; col < numColumns(); col++ )
{
QwtPlot* p = plotAt( row, col );
if ( p )
p->replot();
}
}
}
void PlotMatrix::alignAxes( int rowOrColumn, int axis )
{
if ( QwtAxis::isYAxis( axis ) )
{
double maxExtent = 0;
for ( int row = 0; row < numRows(); row++ )
{
QwtPlot* p = plotAt( row, rowOrColumn );
if ( p )
{
QwtScaleWidget* scaleWidget = p->axisWidget( axis );
QwtScaleDraw* sd = scaleWidget->scaleDraw();
sd->setMinimumExtent( 0.0 );
const double extent = sd->extent( scaleWidget->font() );
if ( extent > maxExtent )
maxExtent = extent;
}
}
for ( int row = 0; row < numRows(); row++ )
{
QwtPlot* p = plotAt( row, rowOrColumn );
if ( p )
{
QwtScaleWidget* scaleWidget = p->axisWidget( axis );
scaleWidget->scaleDraw()->setMinimumExtent( maxExtent );
}
}
}
else
{
double maxExtent = 0;
for ( int col = 0; col < numColumns(); col++ )
{
QwtPlot* p = plotAt( rowOrColumn, col );
if ( p )
{
QwtScaleWidget* scaleWidget = p->axisWidget( axis );
QwtScaleDraw* sd = scaleWidget->scaleDraw();
sd->setMinimumExtent( 0.0 );
const double extent = sd->extent( scaleWidget->font() );
if ( extent > maxExtent )
maxExtent = extent;
}
}
for ( int col = 0; col < numColumns(); col++ )
{
QwtPlot* p = plotAt( rowOrColumn, col );
if ( p )
{
QwtScaleWidget* scaleWidget = p->axisWidget( axis );
scaleWidget->scaleDraw()->setMinimumExtent( maxExtent );
}
}
}
}
void PlotMatrix::alignScaleBorder( int rowOrColumn, int axis )
{
int startDist = 0;
int endDist = 0;
if ( axis == QwtAxis::YLeft )
{
QwtPlot* plot = plotAt( rowOrColumn, 0 );
if ( plot )
plot->axisWidget( axis )->getBorderDistHint( startDist, endDist );
for ( int col = 1; col < numColumns(); col++ )
{
plot = plotAt( rowOrColumn, col );
if ( plot )
plot->axisWidget( axis )->setMinBorderDist( startDist, endDist );
}
}
else if ( axis == QwtAxis::YRight )
{
QwtPlot* plot = plotAt( rowOrColumn, numColumns() - 1 );
if ( plot )
plot->axisWidget( axis )->getBorderDistHint( startDist, endDist );
for ( int col = 0; col < numColumns() - 1; col++ )
{
plot = plotAt( rowOrColumn, col );
if ( plot )
plot->axisWidget( axis )->setMinBorderDist( startDist, endDist );
}
}
if ( axis == QwtAxis::XTop )
{
QwtPlot* plot = plotAt( rowOrColumn, 0 );
if ( plot )
plot->axisWidget( axis )->getBorderDistHint( startDist, endDist );
for ( int row = 1; row < numRows(); row++ )
{
plot = plotAt( row, rowOrColumn );
if ( plot )
plot->axisWidget( axis )->setMinBorderDist( startDist, endDist );
}
}
else if ( axis == QwtAxis::XBottom )
{
QwtPlot* plot = plotAt( numRows() - 1, rowOrColumn );
if ( plot )
plot->axisWidget( axis )->getBorderDistHint( startDist, endDist );
for ( int row = 0; row < numRows() - 1; row++ )
{
plot = plotAt( row, rowOrColumn );
if ( plot )
plot->axisWidget( axis )->setMinBorderDist( startDist, endDist );
}
}
}
#include "moc_PlotMatrix.cpp"