Salome HOME
Copyright update: 2016
[modules/gui.git] / src / Qtx / QtxRubberBand.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File:      QtxRubberBand.cxx
21 // Author:    Alexander A. BORODIN
22 //
23 #include "QtxRubberBand.h"
24
25 #include <QBitmap>
26 #include <QImage>
27 #include <QPaintEvent>
28 #include <QPainter>
29 #include <QPalette>
30 #include <QShowEvent>
31 #include <QVectorIterator>
32
33 /*!
34   \class QtxAbstractRubberBand
35   \brief Analog of class QRubberBand with possibility of creation non-rectangular contour for selection.
36   
37   Currently this class does not support Style functionality in full.
38 */
39
40 /*!
41   \brief Constructor
42   \param theParent parent widget
43  */
44
45 QtxAbstractRubberBand::QtxAbstractRubberBand( QWidget* theParent)
46   : QWidget( theParent/*,Qt::ToolTip*/ ),
47     myPoints(),
48     myIsClosed( false )
49 {
50   setAttribute(Qt::WA_TransparentForMouseEvents);
51 #ifndef WIN32
52   setAttribute(Qt::WA_NoSystemBackground);
53 #endif //WIN32
54   setAttribute(Qt::WA_WState_ExplicitShowHide);
55   setVisible(false);
56   theParent->installEventFilter(this);
57   setGeometry( QRect(QPoint(0,0), theParent->size() ) );
58 }
59
60 /*!
61   \brief Destructor
62  */
63 QtxAbstractRubberBand::~QtxAbstractRubberBand()
64 {
65 }
66
67 void QtxAbstractRubberBand::clearGeometry()
68 {
69   myPoints.clear();
70 }
71
72 bool QtxAbstractRubberBand::isClosed()
73 {
74   return myIsClosed;
75 }
76
77 void QtxAbstractRubberBand::paintEvent( QPaintEvent* theEvent )
78 {
79   if ( !myPoints.empty() )
80     {
81       QPixmap tiledPixmap(16, 16);
82      
83       QPainter pixmapPainter(&tiledPixmap);
84       pixmapPainter.setPen(Qt::NoPen);
85       pixmapPainter.setBrush(QBrush( Qt::black, Qt::Dense4Pattern ));
86       pixmapPainter.setBackground(QBrush( Qt::white ));
87       pixmapPainter.setBackgroundMode(Qt::OpaqueMode);
88       pixmapPainter.drawRect(0, 0, tiledPixmap.width(), tiledPixmap.height());
89       pixmapPainter.end();
90       // ### workaround for borked XRENDER
91       tiledPixmap = QPixmap::fromImage(tiledPixmap.toImage());
92
93
94       
95       QPainter aPainter( this );
96       aPainter.setRenderHint( QPainter::Antialiasing );
97       QRect r = myPoints.boundingRect();
98       aPainter.setClipRegion( r.normalized().adjusted( -1, -1, 2, 2 ) );
99       aPainter.drawTiledPixmap( 0, 0, width(), height(), tiledPixmap);
100
101       aPainter.end();
102
103     /*
104
105
106
107 #ifdef WIN32
108       QPixmap anImage( size() );
109 #else
110       QImage anImage( size(), QImage::Format_ARGB32_Premultiplied );
111 #endif
112
113       anImage.fill( Qt::transparent );
114       QPainter aImgPainter( &anImage );
115       aImgPainter.setRenderHint( QPainter::Antialiasing );
116       aImgPainter.setCompositionMode(QPainter::CompositionMode_Source);
117
118       QPen aPen( Qt::black );
119       aPen.setWidth( 2 );
120       aImgPainter.setPen( aPen );
121     
122       aImgPainter.drawPolyline( myPoints );
123       if ( myIsClosed && myPoints.last() != myPoints.first() )
124         aImgPainter.drawLine( myPoints.last(), myPoints.first() );
125
126       //aImgPainter.setPen(Qt::NoPen);
127       //aImgPainter.setBrush(QBrush( Qt::white, Qt::Dense4Pattern));
128       //aImgPainter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
129       //aImgPainter.drawRect(0, 0, width(), height());
130       aImgPainter.end();
131
132       QPainter aPainter( this );
133       aPainter.drawPolyline( myPoints );
134       if ( myIsClosed && myPoints.last() != myPoints.first() )
135         aPainter.drawLine( myPoints.last(), myPoints.first() );
136       
137 #ifdef WIN32
138       aPainter.drawPixmap( 0, 0, anImage );
139 #else
140       aPainter.drawImage( 0, 0, anImage );
141       #endif
142       aPainter.end();*/
143       
144     }
145 }
146
147 void QtxAbstractRubberBand::showEvent( QShowEvent* theEvent )
148 {
149   raise();
150   theEvent->ignore();
151 }
152
153 void QtxAbstractRubberBand::moveEvent( QMoveEvent* )
154 {
155 }
156
157 void QtxAbstractRubberBand::resizeEvent( QResizeEvent* )
158 {
159 }
160
161 bool QtxAbstractRubberBand::eventFilter( QObject* obj, QEvent* e )
162 {
163   if ( obj && obj == parent() && e->type() == QEvent::Resize )
164     {
165       QWidget* p = (QWidget*)parent();
166       setGeometry( QRect(QPoint(0,0), p->size() ) );
167     }
168   return QWidget::eventFilter( obj, e );
169 }
170
171 QRegion createRegion( const QPointF& p1, const QPointF& p2 )
172 {
173   if ( p1 == p2 )
174     return QRegion();
175
176   QLineF n = QLineF( p1, p2 ).normalVector();//.unitVector();
177   n.setLength( 1 );
178   n.translate( p1 * -1 );
179   QPointF nPoint = n.p2();
180
181   QPolygonF p;
182   p << p1 + nPoint << p2 + nPoint << p2 - nPoint << p1 - nPoint << p1 + nPoint;
183
184   return QRegion( p.toPolygon() );
185 }
186
187 void QtxAbstractRubberBand::updateMask()
188 {
189   QRegion r;
190
191   QVectorIterator<QPoint> it(myPoints);
192   while( it.hasNext() )
193     {
194       QPoint p = it.next();
195       if( !it.hasNext() )
196         break;
197
198       QPoint np = it.peekNext();
199       
200       if ( p == np ) continue;
201
202       r += createRegion( p, np );
203     }
204
205   if ( isClosed() )
206     r += createRegion( myPoints.last(), myPoints.first() );
207
208   if ( !r.isEmpty() )
209     setMask( r );
210 }
211
212
213 QtxRectRubberBand::QtxRectRubberBand(QWidget* parent)
214   :QtxAbstractRubberBand( parent )      
215 {
216   myPoints.resize( 4 );
217   myIsClosed = true;
218 }
219
220 QtxRectRubberBand::~QtxRectRubberBand()
221 {
222 }
223
224 void QtxRectRubberBand::initGeometry( const QRect& theRect )
225 {
226   myPoints.clear();
227   myPoints << theRect.topLeft() << theRect.topRight() << theRect.bottomRight() << theRect.bottomLeft();
228   //setMask( QRegion( myPoints ) );
229   updateMask();
230 }
231
232 void QtxRectRubberBand::setStartPoint( const QPoint& thePoint )
233 {
234   myPoints[0] = thePoint;
235   myPoints[1].setY( thePoint.y() );
236   myPoints[3].setX( thePoint.x() );
237   updateMask();
238 }
239
240 void QtxRectRubberBand::setEndPoint( const QPoint& thePoint)
241 {
242   myPoints[2] = thePoint;       
243   myPoints[1].setX( thePoint.x() );
244   myPoints[3].setY( thePoint.y() );
245   updateMask();
246 }
247
248 void QtxRectRubberBand::clearGeometry()
249 {
250   QMutableVectorIterator<QPoint> i(myPoints);
251   while (i.hasNext())
252     {
253       i.next();
254       i.setValue( QPoint( -1, -1 ) );
255     }
256 }
257
258
259 QtxPolyRubberBand::QtxPolyRubberBand(QWidget* parent)
260   :QtxAbstractRubberBand( parent )
261 {
262 }
263
264 QtxPolyRubberBand::~QtxPolyRubberBand()
265 {
266 }
267
268 void QtxPolyRubberBand::initGeometry( const QPolygon& thePoints )
269 {
270   myPoints = thePoints;
271   updateMask();
272 }
273
274 void QtxPolyRubberBand::initGeometry( const QPoint& thePoint )
275 {
276   myPoints.clear();  
277   myPoints << thePoint;
278   updateMask();
279 }
280
281 void QtxPolyRubberBand::addNode( const QPoint& thePoint )
282 {
283   myPoints << thePoint;
284   updateMask();
285 }
286
287 void QtxPolyRubberBand::replaceLastNode( const QPoint& thePoint )
288 {
289   if ( !myPoints.empty() )
290     {
291       myPoints.pop_back();
292       myPoints << thePoint;
293       updateMask();
294     }
295 }
296
297 void QtxPolyRubberBand::removeLastNode()
298 {
299   if ( !myPoints.empty() )
300     {
301       myPoints.pop_back();
302       updateMask();
303     }
304 }
305
306 void QtxPolyRubberBand::setClosed( bool theFlag )
307 {
308   if (myIsClosed != theFlag )
309     {
310       myIsClosed = theFlag;
311       updateMask();
312     }
313 }