1 // Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // File: QtxRubberBand.cxx
21 // Author: Alexander A. BORODIN
23 #include "QtxRubberBand.h"
27 #include <QPaintEvent>
31 #include <QVectorIterator>
36 \class QtxAbstractRubberBand
37 \brief Analog of class QRubberBand with possibility of creation non-rectangular contour for selection.
39 Currently this class does not support Style functionality in full.
44 \param theParent parent widget
47 QtxAbstractRubberBand::QtxAbstractRubberBand( QWidget* theParent)
48 : QWidget( theParent/*,Qt::ToolTip*/ ),
52 setAttribute(Qt::WA_TransparentForMouseEvents);
54 setAttribute(Qt::WA_NoSystemBackground);
56 setAttribute(Qt::WA_WState_ExplicitShowHide);
58 theParent->installEventFilter(this);
59 setGeometry( QRect(QPoint(0,0), theParent->size() ) );
65 QtxAbstractRubberBand::~QtxAbstractRubberBand()
69 void QtxAbstractRubberBand::clearGeometry()
74 bool QtxAbstractRubberBand::isClosed()
79 void QtxAbstractRubberBand::paintEvent( QPaintEvent* theEvent )
81 if ( !myPoints.empty() )
83 QPixmap tiledPixmap(16, 16);
85 QPainter pixmapPainter(&tiledPixmap);
86 pixmapPainter.setPen(Qt::NoPen);
87 pixmapPainter.setBrush(QBrush( Qt::black, Qt::Dense4Pattern ));
88 pixmapPainter.setBackground(QBrush( Qt::white ));
89 pixmapPainter.setBackgroundMode(Qt::OpaqueMode);
90 pixmapPainter.drawRect(0, 0, tiledPixmap.width(), tiledPixmap.height());
92 // ### workaround for borked XRENDER
93 tiledPixmap = QPixmap::fromImage(tiledPixmap.toImage());
97 QPainter aPainter( this );
98 aPainter.setRenderHint( QPainter::Antialiasing );
99 QRect r = myPoints.boundingRect();
100 //aPainter.setClipRegion( r.normalized().adjusted( -1, -1, 2, 2 ) );
101 aPainter.drawTiledPixmap( 0, 0, width(), height(), tiledPixmap);
110 QPixmap anImage( size() );
112 QImage anImage( size(), QImage::Format_ARGB32_Premultiplied );
115 anImage.fill( Qt::transparent );
116 QPainter aImgPainter( &anImage );
117 aImgPainter.setRenderHint( QPainter::Antialiasing );
118 aImgPainter.setCompositionMode(QPainter::CompositionMode_Source);
120 QPen aPen( Qt::black );
122 aImgPainter.setPen( aPen );
124 aImgPainter.drawPolyline( myPoints );
125 if ( myIsClosed && myPoints.last() != myPoints.first() )
126 aImgPainter.drawLine( myPoints.last(), myPoints.first() );
128 //aImgPainter.setPen(Qt::NoPen);
129 //aImgPainter.setBrush(QBrush( Qt::white, Qt::Dense4Pattern));
130 //aImgPainter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
131 //aImgPainter.drawRect(0, 0, width(), height());
134 QPainter aPainter( this );
135 aPainter.drawPolyline( myPoints );
136 if ( myIsClosed && myPoints.last() != myPoints.first() )
137 aPainter.drawLine( myPoints.last(), myPoints.first() );
140 aPainter.drawPixmap( 0, 0, anImage );
142 aPainter.drawImage( 0, 0, anImage );
149 void QtxAbstractRubberBand::showEvent( QShowEvent* theEvent )
155 void QtxAbstractRubberBand::moveEvent( QMoveEvent* )
159 void QtxAbstractRubberBand::resizeEvent( QResizeEvent* )
163 bool QtxAbstractRubberBand::eventFilter( QObject* obj, QEvent* e )
165 if ( obj && obj == parent() && e->type() == QEvent::Resize )
167 QWidget* p = (QWidget*)parent();
168 setGeometry( QRect(QPoint(0,0), p->size() ) );
170 return QWidget::eventFilter( obj, e );
173 QRegion createRegion( const QPointF& p1, const QPointF& p2 )
178 QLineF n = QLineF( p1, p2 ).normalVector();//.unitVector();
180 n.translate( p1 * -1 );
181 QPointF nPoint = n.p2();
184 p << p1 + nPoint << p2 + nPoint << p2 - nPoint << p1 - nPoint << p1 + nPoint;
186 return QRegion( p.toPolygon() );
189 void QtxAbstractRubberBand::updateMask()
193 QVectorIterator<QPoint> it(myPoints);
194 while( it.hasNext() )
196 QPoint p = it.next();
200 QPoint np = it.peekNext();
202 if ( p == np ) continue;
204 r += createRegion( p, np );
208 r += createRegion( myPoints.last(), myPoints.first() );
215 QtxRectRubberBand::QtxRectRubberBand(QWidget* parent)
216 :QtxAbstractRubberBand( parent )
218 myPoints.resize( 4 );
222 QtxRectRubberBand::~QtxRectRubberBand()
226 void QtxRectRubberBand::initGeometry( const QRect& theRect )
229 myPoints << theRect.topLeft() << theRect.topRight() << theRect.bottomRight() << theRect.bottomLeft();
230 //setMask( QRegion( myPoints ) );
234 void QtxRectRubberBand::setStartPoint( const QPoint& thePoint )
236 myPoints[0] = thePoint;
237 myPoints[1].setY( thePoint.y() );
238 myPoints[3].setX( thePoint.x() );
242 void QtxRectRubberBand::setEndPoint( const QPoint& thePoint)
244 myPoints[2] = thePoint;
245 myPoints[1].setX( thePoint.x() );
246 myPoints[3].setY( thePoint.y() );
250 void QtxRectRubberBand::clearGeometry()
252 QMutableVectorIterator<QPoint> i(myPoints);
256 i.setValue( QPoint( -1, -1 ) );
261 QtxPolyRubberBand::QtxPolyRubberBand(QWidget* parent)
262 :QtxAbstractRubberBand( parent )
266 QtxPolyRubberBand::~QtxPolyRubberBand()
270 void QtxPolyRubberBand::initGeometry( const QPolygon& thePoints )
272 myPoints = thePoints;
276 void QtxPolyRubberBand::initGeometry( const QPoint& thePoint )
279 myPoints << thePoint;
283 void QtxPolyRubberBand::addNode( const QPoint& thePoint )
285 myPoints << thePoint;
289 void QtxPolyRubberBand::replaceLastNode( const QPoint& thePoint )
291 if ( !myPoints.empty() )
294 myPoints << thePoint;
299 void QtxPolyRubberBand::removeLastNode()
301 if ( !myPoints.empty() )
308 void QtxPolyRubberBand::setClosed( bool theFlag )
310 if (myIsClosed != theFlag )
312 myIsClosed = theFlag;
317 QtxCircleRubberBand::QtxCircleRubberBand(QWidget* parent)
318 :QtxAbstractRubberBand(parent), myHasCenter(false)
324 QtxCircleRubberBand::~QtxCircleRubberBand()
328 void QtxCircleRubberBand::initGeometry(const QPoint& thePoint)
333 myPoints << thePoint;
337 void QtxCircleRubberBand::setRadius(const QPoint& thePoint)
339 if (myPoints.size() == 1)
340 myPoints << thePoint;
342 myPoints.setPoint(1, thePoint);
347 void QtxCircleRubberBand::updateMask()
350 if (aLen > MIN_RADIUS) {
351 QRegion aReg1(myPoints[0].x() - aLen,
352 myPoints[0].y() - aLen, aLen * 2, aLen * 2, QRegion::Ellipse);
353 QRegion aReg2(myPoints[0].x() - aLen + 2,
354 myPoints[0].y() - aLen + 2, aLen * 2 - 4, aLen * 2 - 4, QRegion::Ellipse);
355 setMask(aReg1 - aReg2);
359 bool QtxCircleRubberBand::isCenterDefined() const
364 void QtxCircleRubberBand::clearGeometry()
366 QtxAbstractRubberBand::clearGeometry();
371 QPoint rotatePoint(const QPoint& theStart, const QPoint& theCenter, double theAngle)
373 double cosTheta = cos(theAngle);
374 double sinTheta = sin(theAngle);
375 int aX = (int)(cosTheta * (theStart.x() - theCenter.x()) -
376 sinTheta * (theStart.y() - theCenter.y()) + theCenter.x());
377 int aY = (int)(sinTheta * (theStart.x() - theCenter.x()) +
378 cosTheta * (theStart.y() - theCenter.y()) + theCenter.y());
379 return QPoint(aX, aY);
382 static double m_pi = 4 * atan(1);
383 static double angle_deg = 360. / CIRCLE_NB_POINTS;
384 static double angle_rad = angle_deg * (m_pi / 180.);
387 void QtxCircleRubberBand::getPoligon(QPolygon* thePoints) const
390 if (aLen > MIN_RADIUS) {
392 QPoint aCenter = myPoints[0];
393 QPoint aStart = myPoints[1];
394 for (int i = 0; i < CIRCLE_NB_POINTS; i++) {
395 thePoints->append(aStart);
396 aStart = rotatePoint(aStart, aCenter, angle_rad);
401 int QtxCircleRubberBand::radius() const
403 if (myPoints.size() < 2)
405 QPoint aDist = myPoints[1] - myPoints[0];
406 return (int)std::sqrt(std::pow(aDist.x(), 2) + std::pow(aDist.y(), 2));