qt_demoe/qwtdemo/examples/itemeditor/editor.cpp

375 lines
9.3 KiB
C++

#include "editor.h"
#include <qwt_plot.h>
#include <qwt_plot_canvas.h>
#include <qwt_scale_map.h>
#include <qwt_plot_shapeitem.h>
#include <qevent.h>
class Overlay: public QwtWidgetOverlay
{
public:
Overlay( QWidget *parent, Editor *editor ):
QwtWidgetOverlay( parent ),
d_editor( editor )
{
switch( editor->mode() )
{
case Editor::NoMask:
{
setMaskMode( QwtWidgetOverlay::NoMask );
setRenderMode( QwtWidgetOverlay::AutoRenderMode );
break;
}
case Editor::Mask:
{
setMaskMode( QwtWidgetOverlay::MaskHint );
setRenderMode( QwtWidgetOverlay::AutoRenderMode );
break;
}
case Editor::AlphaMask:
{
setMaskMode( QwtWidgetOverlay::AlphaMask );
setRenderMode( QwtWidgetOverlay::AutoRenderMode );
break;
}
case Editor::AlphaMaskRedraw:
{
setMaskMode( QwtWidgetOverlay::AlphaMask );
setRenderMode( QwtWidgetOverlay::DrawOverlay );
break;
}
case Editor::AlphaMaskCopyMask:
{
setMaskMode( QwtWidgetOverlay::AlphaMask );
setRenderMode( QwtWidgetOverlay::CopyAlphaMask );
break;
}
}
}
protected:
virtual void drawOverlay( QPainter *painter ) const
{
d_editor->drawOverlay( painter );
}
virtual QRegion maskHint() const
{
return d_editor->maskHint();
}
private:
Editor *d_editor;
};
Editor::Editor( QwtPlot* plot ):
QObject( plot ),
d_isEnabled( false ),
d_overlay( NULL ),
d_mode( Mask )
{
setEnabled( true );
}
Editor::~Editor()
{
delete d_overlay;
}
QwtPlot *Editor::plot()
{
return qobject_cast<QwtPlot *>( parent() );
}
const QwtPlot *Editor::plot() const
{
return qobject_cast<const QwtPlot *>( parent() );
}
void Editor::setMode( Mode mode )
{
d_mode = mode;
}
Editor::Mode Editor::mode() const
{
return d_mode;
}
void Editor::setEnabled( bool on )
{
if ( on == d_isEnabled )
return;
QwtPlot *plot = qobject_cast<QwtPlot *>( parent() );
if ( plot )
{
d_isEnabled = on;
if ( on )
{
plot->canvas()->installEventFilter( this );
}
else
{
plot->canvas()->removeEventFilter( this );
delete d_overlay;
d_overlay = NULL;
}
}
}
bool Editor::isEnabled() const
{
return d_isEnabled;
}
bool Editor::eventFilter( QObject* object, QEvent* event )
{
QwtPlot *plot = qobject_cast<QwtPlot *>( parent() );
if ( plot && object == plot->canvas() )
{
switch( event->type() )
{
case QEvent::MouseButtonPress:
{
const QMouseEvent* mouseEvent =
dynamic_cast<QMouseEvent* >( event );
if ( d_overlay == NULL &&
mouseEvent->button() == Qt::LeftButton )
{
const bool accepted = pressed( mouseEvent->pos() );
if ( accepted )
{
d_overlay = new Overlay( plot->canvas(), this );
d_overlay->updateOverlay();
d_overlay->show();
}
}
break;
}
case QEvent::MouseMove:
{
if ( d_overlay )
{
const QMouseEvent* mouseEvent =
dynamic_cast< QMouseEvent* >( event );
const bool accepted = moved( mouseEvent->pos() );
if ( accepted )
d_overlay->updateOverlay();
}
break;
}
case QEvent::MouseButtonRelease:
{
const QMouseEvent* mouseEvent =
static_cast<QMouseEvent* >( event );
if ( d_overlay && mouseEvent->button() == Qt::LeftButton )
{
released( mouseEvent->pos() );
delete d_overlay;
d_overlay = NULL;
}
break;
}
default:
break;
}
return false;
}
return QObject::eventFilter( object, event );
}
bool Editor::pressed( const QPoint& pos )
{
d_editedItem = itemAt( pos );
if ( d_editedItem )
{
d_currentPos = pos;
setItemVisible( d_editedItem, false );
return true;
}
return false; // don't accept the position
}
bool Editor::moved( const QPoint& pos )
{
if ( plot() == NULL )
return false;
const QwtScaleMap xMap = plot()->canvasMap( d_editedItem->xAxis() );
const QwtScaleMap yMap = plot()->canvasMap( d_editedItem->yAxis() );
const QPointF p1 = QwtScaleMap::invTransform( xMap, yMap, d_currentPos );
const QPointF p2 = QwtScaleMap::invTransform( xMap, yMap, pos );
#if QT_VERSION >= 0x040600
const QPainterPath shape = d_editedItem->shape().translated( p2 - p1 );
#else
const double dx = p2.x() - p1.x();
const double dy = p2.y() - p1.y();
QPainterPath shape = d_editedItem->shape();
for ( int i = 0; i < shape.elementCount(); i++ )
{
const QPainterPath::Element &el = shape.elementAt( i );
shape.setElementPositionAt( i, el.x + dx, el.y + dy );
}
#endif
d_editedItem->setShape( shape );
d_currentPos = pos;
return true;
}
void Editor::released( const QPoint& pos )
{
Q_UNUSED( pos );
if ( d_editedItem )
{
raiseItem( d_editedItem );
setItemVisible( d_editedItem, true );
}
}
QwtPlotShapeItem* Editor::itemAt( const QPoint& pos ) const
{
const QwtPlot *plot = this->plot();
if ( plot == NULL )
return NULL;
// translate pos into the plot coordinates
double coords[ QwtPlot::axisCnt ];
coords[ QwtPlot::xBottom ] =
plot->canvasMap( QwtPlot::xBottom ).invTransform( pos.x() );
coords[ QwtPlot::xTop ] =
plot->canvasMap( QwtPlot::xTop ).invTransform( pos.x() );
coords[ QwtPlot::yLeft ] =
plot->canvasMap( QwtPlot::yLeft ).invTransform( pos.y() );
coords[ QwtPlot::yRight ] =
plot->canvasMap( QwtPlot::yRight ).invTransform( pos.y() );
QwtPlotItemList items = plot->itemList();
for ( int i = items.size() - 1; i >= 0; i-- )
{
QwtPlotItem *item = items[ i ];
if ( item->isVisible() &&
item->rtti() == QwtPlotItem::Rtti_PlotShape )
{
QwtPlotShapeItem *shapeItem = static_cast<QwtPlotShapeItem *>( item );
const QPointF p( coords[ item->xAxis() ], coords[ item->yAxis() ] );
if ( shapeItem->boundingRect().contains( p )
&& shapeItem->shape().contains( p ) )
{
return shapeItem;
}
}
}
return NULL;
}
QRegion Editor::maskHint() const
{
return maskHint( d_editedItem );
}
QRegion Editor::maskHint( QwtPlotShapeItem *shapeItem ) const
{
const QwtPlot *plot = this->plot();
if ( plot == NULL || shapeItem == NULL )
return QRegion();
const QwtScaleMap xMap = plot->canvasMap( shapeItem->xAxis() );
const QwtScaleMap yMap = plot->canvasMap( shapeItem->yAxis() );
QRect rect = QwtScaleMap::transform( xMap, yMap,
shapeItem->shape().boundingRect() ).toRect();
const int m = 5; // some margin for the pen
return rect.adjusted( -m, -m, m, m );
}
void Editor::drawOverlay( QPainter* painter ) const
{
const QwtPlot *plot = this->plot();
if ( plot == NULL || d_editedItem == NULL )
return;
const QwtScaleMap xMap = plot->canvasMap( d_editedItem->xAxis() );
const QwtScaleMap yMap = plot->canvasMap( d_editedItem->yAxis() );
painter->setRenderHint( QPainter::Antialiasing,
d_editedItem->testRenderHint( QwtPlotItem::RenderAntialiased ) );
d_editedItem->draw( painter, xMap, yMap,
plot->canvas()->contentsRect() );
}
void Editor::raiseItem( QwtPlotShapeItem *shapeItem )
{
const QwtPlot *plot = this->plot();
if ( plot == NULL || shapeItem == NULL )
return;
const QwtPlotItemList items = plot->itemList();
for ( int i = items.size() - 1; i >= 0; i-- )
{
QwtPlotItem *item = items[ i ];
if ( shapeItem == item )
return;
if ( item->isVisible() &&
item->rtti() == QwtPlotItem::Rtti_PlotShape )
{
shapeItem->setZ( item->z() + 1 );
return;
}
}
}
void Editor::setItemVisible( QwtPlotShapeItem *item, bool on )
{
if ( plot() == NULL || item == NULL || item->isVisible() == on )
return;
const bool doAutoReplot = plot()->autoReplot();
plot()->setAutoReplot( false );
item->setVisible( on );
plot()->setAutoReplot( doAutoReplot );
/*
Avoid replot with a full repaint of the canvas.
For special combinations - f.e. using the
raster paint engine on a remote display -
this makes a difference.
*/
QwtPlotCanvas *canvas =
qobject_cast<QwtPlotCanvas *>( plot()->canvas() );
if ( canvas )
canvas->invalidateBackingStore();
plot()->canvas()->update( maskHint( item ) );
}