1 // Copyright (C) 2007-2023 CEA, EDF, 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());
95 QPainter aPainter( this );
96 aPainter.setRenderHint( QPainter::Antialiasing );
97 aPainter.drawTiledPixmap( 0, 0, width(), height(), tiledPixmap);
102 void QtxAbstractRubberBand::showEvent( QShowEvent* theEvent )
108 void QtxAbstractRubberBand::moveEvent( QMoveEvent* )
112 void QtxAbstractRubberBand::resizeEvent( QResizeEvent* )
116 bool QtxAbstractRubberBand::eventFilter( QObject* obj, QEvent* e )
118 if ( obj && obj == parent() && e->type() == QEvent::Resize )
120 QWidget* p = (QWidget*)parent();
121 setGeometry( QRect(QPoint(0,0), p->size() ) );
123 return QWidget::eventFilter( obj, e );
126 QRegion createRegion( const QPointF& p1, const QPointF& p2 )
131 QLineF n = QLineF( p1, p2 ).normalVector();//.unitVector();
133 n.translate( p1 * -1 );
134 QPointF nPoint = n.p2();
137 p << p1 + nPoint << p2 + nPoint << p2 - nPoint << p1 - nPoint << p1 + nPoint;
139 return QRegion( p.toPolygon() );
142 void QtxAbstractRubberBand::updateMask()
146 QVectorIterator<QPoint> it(myPoints);
147 while( it.hasNext() )
149 QPoint p = it.next();
153 QPoint np = it.peekNext();
155 if ( p == np ) continue;
157 r += createRegion( p, np );
161 r += createRegion( myPoints.last(), myPoints.first() );
168 QtxRectRubberBand::QtxRectRubberBand(QWidget* parent)
169 :QtxAbstractRubberBand( parent )
171 myPoints.resize( 4 );
175 QtxRectRubberBand::~QtxRectRubberBand()
179 void QtxRectRubberBand::initGeometry( const QRect& theRect )
182 myPoints << theRect.topLeft() << theRect.topRight() << theRect.bottomRight() << theRect.bottomLeft();
183 //setMask( QRegion( myPoints ) );
187 void QtxRectRubberBand::setStartPoint( const QPoint& thePoint )
189 myPoints[0] = thePoint;
190 myPoints[1].setY( thePoint.y() );
191 myPoints[3].setX( thePoint.x() );
195 void QtxRectRubberBand::setEndPoint( const QPoint& thePoint)
197 myPoints[2] = thePoint;
198 myPoints[1].setX( thePoint.x() );
199 myPoints[3].setY( thePoint.y() );
203 void QtxRectRubberBand::clearGeometry()
205 QMutableVectorIterator<QPoint> i(myPoints);
209 i.setValue( QPoint( -1, -1 ) );
214 QtxPolyRubberBand::QtxPolyRubberBand(QWidget* parent)
215 :QtxAbstractRubberBand( parent )
219 QtxPolyRubberBand::~QtxPolyRubberBand()
223 void QtxPolyRubberBand::initGeometry( const QPolygon& thePoints )
225 myPoints = thePoints;
229 void QtxPolyRubberBand::initGeometry( const QPoint& thePoint )
232 myPoints << thePoint;
236 void QtxPolyRubberBand::addNode( const QPoint& thePoint )
238 myPoints << thePoint;
242 void QtxPolyRubberBand::replaceLastNode( const QPoint& thePoint )
244 if ( !myPoints.empty() )
247 myPoints << thePoint;
252 void QtxPolyRubberBand::removeLastNode()
254 if ( !myPoints.empty() )
261 void QtxPolyRubberBand::setClosed( bool theFlag )
263 if (myIsClosed != theFlag )
265 myIsClosed = theFlag;
270 QtxCircleRubberBand::QtxCircleRubberBand(QWidget* parent)
271 :QtxAbstractRubberBand(parent), myHasCenter(false)
277 QtxCircleRubberBand::~QtxCircleRubberBand()
281 void QtxCircleRubberBand::initGeometry(const QPoint& thePoint)
286 myPoints << thePoint;
290 void QtxCircleRubberBand::setRadius(const QPoint& thePoint)
292 if (myPoints.size() == 1)
293 myPoints << thePoint;
295 myPoints.setPoint(1, thePoint);
300 void QtxCircleRubberBand::updateMask()
303 if (aLen > MIN_RADIUS) {
304 QRegion aReg1(myPoints[0].x() - aLen,
305 myPoints[0].y() - aLen, aLen * 2, aLen * 2, QRegion::Ellipse);
306 QRegion aReg2(myPoints[0].x() - aLen + 2,
307 myPoints[0].y() - aLen + 2, aLen * 2 - 4, aLen * 2 - 4, QRegion::Ellipse);
308 setMask(aReg1 - aReg2);
312 bool QtxCircleRubberBand::isCenterDefined() const
317 void QtxCircleRubberBand::clearGeometry()
319 QtxAbstractRubberBand::clearGeometry();
324 QPoint rotatePoint(const QPoint& theStart, const QPoint& theCenter, double theAngle)
326 double cosTheta = cos(theAngle);
327 double sinTheta = sin(theAngle);
328 int aX = (int)(cosTheta * (theStart.x() - theCenter.x()) -
329 sinTheta * (theStart.y() - theCenter.y()) + theCenter.x());
330 int aY = (int)(sinTheta * (theStart.x() - theCenter.x()) +
331 cosTheta * (theStart.y() - theCenter.y()) + theCenter.y());
332 return QPoint(aX, aY);
335 static double m_pi = 4 * atan(1);
336 static double angle_deg = 360. / CIRCLE_NB_POINTS;
337 static double angle_rad = angle_deg * (m_pi / 180.);
340 void QtxCircleRubberBand::getPoligon(QPolygon* thePoints) const
343 if (aLen > MIN_RADIUS) {
345 QPoint aCenter = myPoints[0];
346 QPoint aStart = myPoints[1];
347 for (int i = 0; i < CIRCLE_NB_POINTS; i++) {
348 thePoints->append(aStart);
349 aStart = rotatePoint(aStart, aCenter, angle_rad);
354 int QtxCircleRubberBand::radius() const
356 if (myPoints.size() < 2)
358 QPoint aDist = myPoints[1] - myPoints[0];
359 return (int)std::sqrt(std::pow(aDist.x(), 2) + std::pow(aDist.y(), 2));