Salome HOME
17d9d68daa868bf07098ccc402492434499ea710
[modules/gui.git] / src / GLViewer / GLViewer_ViewPort2d.cxx
1 //  Copyright (C) 2005 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.
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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
18 //
19 //  Author : OPEN CASCADE
20 //
21
22 // File:      GLViewer_ViewPort2d.cxx
23 // Created:   November, 2004
24
25 /* GLViewer_ViewPort2d Source File */
26
27 //#include <GLViewerAfx.h>
28 #include "GLViewer_ViewPort2d.h"
29 #include "GLViewer_Viewer2d.h"
30 #include "GLViewer_ViewFrame.h"
31 #include "GLViewer_MimeSource.h"
32 #include "GLViewer_Context.h"
33 #include "GLViewer_Compass.h"
34 #include "GLViewer_Grid.h"
35
36 #include <QtxToolTip.h>
37
38 #include <qlayout.h>
39 #include <qevent.h>
40 #include <qrect.h>
41 #include <qpopupmenu.h>
42 #include <qtooltip.h>
43 #include <qapplication.h>
44 #include <qclipboard.h>
45 #include <qpainter.h>
46 #include <qbitmap.h>
47 #include <qlabel.h>
48
49 #define WIDTH       640
50 #define HEIGHT      480
51 #define MARGIN      100
52
53 #define GRID_XSIZE  100
54 #define GRID_YSIZE  100
55
56 int static aLastViewPostId = 0;
57
58 void rotate_point( float& theX, float& theY, float theAngle )
59 {
60     float aTempX = theX * cos(theAngle) - theY * sin(theAngle);
61     float aTempY = theX * sin(theAngle) + theY * cos(theAngle);
62     theX = aTempX;
63     theY = aTempY;
64 }
65
66 GLViewer_ViewPort2d::GLViewer_ViewPort2d( QWidget* parent, GLViewer_ViewFrame* theViewFrame ) :
67        GLViewer_ViewPort( parent ),
68        myMargin( MARGIN ), myWidth( WIDTH ), myHeight( HEIGHT ),
69        myXScale( 1.0 ), myYScale( 1.0 ), myXOldScale( 1.0 ), myYOldScale( 1.0 ),
70        myXPan( 0.0 ), myYPan( 0.0 ),
71        myIsMouseReleaseBlock( false )
72 {
73     if( theViewFrame == NULL )
74         myViewFrame = ( GLViewer_ViewFrame* )parent;
75     else
76         myViewFrame = theViewFrame;
77
78     myGrid = 0;
79     myCompass = 0;
80     myBorder = new GLViewer_Rect();
81
82     QBoxLayout* qbl = new QHBoxLayout( this );
83     myGLWidget = new GLViewer_Widget( this, 0 ) ;
84     qbl->addWidget( myGLWidget );
85     myGLWidget->setFocusProxy( this );
86     setMouseTracking( TRUE );
87
88     myIsDragProcess = noDrag;
89     //myCurDragMousePos = QPoint();
90     myCurDragPosX = NULL;
91     myCurDragPosY = NULL;
92
93     myIsPulling = false;
94
95     myViewPortId = aLastViewPostId;
96     aLastViewPostId++;
97
98     mypFirstPoint = NULL;
99     mypLastPoint = NULL;
100
101     myObjectTip = new QtxToolTip( myGLWidget );///GLViewer_ObjectTip( this );
102     myObjectTip->setShowDelayTime( 60000 );
103     connect( myObjectTip, SIGNAL( maybeTip( QPoint, QString&, QFont&, QRect&, QRect& ) ),
104              this, SLOT( onMaybeTip( QPoint, QString&, QFont&, QRect&, QRect& ) ) );
105 //    myGLWidget->installEventFilter( myObjectTip );
106 }
107
108 GLViewer_ViewPort2d::~GLViewer_ViewPort2d()
109 {
110     if( myCompass )
111         delete myCompass;
112
113     if( myGrid )
114         delete myGrid;
115
116     delete myBorder;
117     delete myGLWidget;
118 }
119
120 void GLViewer_ViewPort2d::onStartDragObject( )
121 {
122     if( myIsDragProcess == noDrag )
123     {
124         myIsDragProcess = initDrag;
125         QCursor::setPos( (int)(*myCurDragPosX), (int)(*myCurDragPosY) );
126         //myCurDragMousePos = QPoint( 0, 0 );
127         delete myCurDragPosX;
128         delete myCurDragPosY;
129         myCurDragPosX = NULL;
130         myCurDragPosY = NULL;
131         return;
132     } 
133 }
134
135 void GLViewer_ViewPort2d::onCutObject()
136
137     /*GLViewer_Object* aMovingObject = ((GLViewer_Viewer2d*)getViewFrame()->getViewer())->getGLContext()->getCurrentObject();
138     if( aMovingObject )    
139     {        
140         GLViewer_MimeSource* aMimeSource = new GLViewer_MimeSource();
141         aMimeSource->setObject( aMovingObject );
142         
143         QClipboard *aClipboard = QApplication::clipboard();
144         aClipboard->clear();
145         aClipboard->setData( aMimeSource );
146
147         ((GLViewer_Viewer2d*)getViewFrame()->getViewer())->getGLContext()->deleteObject( aMovingObject );
148     }*/
149     GLViewer_Context* aContext = ((GLViewer_Viewer2d*)getViewFrame()->getViewer())->getGLContext();
150     int aObjNum = aContext->NbSelected();
151     if( aObjNum > 0 )
152     {
153         QValueList<GLViewer_Object*> aObjects;
154         GLViewer_MimeSource* aMimeSource = new GLViewer_MimeSource();
155         aContext->InitSelected();
156         for( ; aContext->MoreSelected(); aContext->NextSelected() )
157             aObjects.append( aContext->SelectedObject() );
158
159         //aMimeSource->setObjects( aObjects ); ouv 6.05.04
160
161         QClipboard *aClipboard = QApplication::clipboard();
162         aClipboard->clear();
163         aClipboard->setData( aMimeSource );
164
165         for( int i = 0; i < aObjNum; i++ )
166             aContext->deleteObject( aObjects[i] );
167     }
168 }
169
170 void GLViewer_ViewPort2d::onCopyObject()
171 {
172     /*GLViewer_Object* aMovingObject = ((GLViewer_Viewer2d*)getViewFrame()->getViewer())->getGLContext()->getCurrentObject();
173     if( aMovingObject )    
174     {        
175         GLViewer_MimeSource* aMimeSource = new GLViewer_MimeSource();
176         aMimeSource->setObject( aMovingObject );
177         
178         QClipboard *aClipboard = QApplication::clipboard();
179         aClipboard->clear();
180         aClipboard->setData( aMimeSource );
181     }
182     */
183     GLViewer_Context* aContext = ((GLViewer_Viewer2d*)getViewFrame()->getViewer())->getGLContext();
184     int aObjNum = aContext->NbSelected();
185     if( aObjNum > 0 )
186     {
187         QValueList<GLViewer_Object*> aObjects;
188         GLViewer_MimeSource* aMimeSource = new GLViewer_MimeSource();
189         aContext->InitSelected();
190         for( ; aContext->MoreSelected(); aContext->NextSelected() )
191             aObjects.append( aContext->SelectedObject() );
192
193         //aMimeSource->setObjects( aObjects ); ouv 6.05.04
194
195         QClipboard *aClipboard = QApplication::clipboard();
196         aClipboard->clear();
197         aClipboard->setData( aMimeSource );
198     }
199 }
200
201 void GLViewer_ViewPort2d::onPasteObject()
202 {
203     /*QClipboard *aClipboard = QApplication::clipboard();
204     QMimeSource* aMimeSource = aClipboard->data();
205     if( aMimeSource->provides( "GLViewer_Object" ) )
206     {
207         const char* aType;
208         int i = 1;
209         QByteArray anArray;
210         do
211         {
212             aType = aMimeSource->format( i );
213             anArray = aMimeSource->encodedData( aType );
214             if( anArray.size() != 0 )
215                 break;
216             i++;
217         }
218         while( aType != 0 );
219         if( anArray.size() == 0 )
220             return;
221
222         GLViewer_Object* aObject = GLViewer_MimeSource::getObject( anArray, aType );
223         if( !aObject )
224             return;
225         
226         ((GLViewer_Viewer2d*)getViewFrame()->getViewer())->getGLContext()->insertObject( aObject, true );
227     }
228     */
229     /* ouv 6.05.04
230     QClipboard *aClipboard = QApplication::clipboard();
231
232     QMimeSource* aMimeSource = aClipboard->data();
233     if( aMimeSource->provides( "GLViewer_Objects" ) )
234     {
235         QByteArray anArray = aMimeSource->encodedData( "GLViewer_Objects" );
236         QValueList<GLViewer_Object*> aObjects = GLViewer_MimeSource::getObjects( anArray, "GLViewer_Objects" );
237         if( aObjects.empty() )
238             return;
239         GLViewer_Context* aContext = ((GLViewer_Viewer2d*)getViewFrame()->getViewer())->getGLContext();
240         for( int i = 0; i < aObjects.count(); i++ )
241             aContext->insertObject( aObjects[i], true );
242     }
243     */
244 }
245
246 void GLViewer_ViewPort2d::onDragObject( QMouseEvent* e )
247 {
248   //cout << "---GLViewer_ViewPort2d::onDragObject()---" << endl;
249   GLViewer_Viewer2d* aViewer = (GLViewer_Viewer2d*)getViewFrame()->getViewer();
250   GLViewer_Context* aContext = aViewer->getGLContext();
251   GLViewer_Object* anObject = aContext->getCurrentObject();
252   
253   if( !aContext )
254     return;
255
256   float aX = e->pos().x();
257   float anY = e->pos().y();
258   aViewer->transPoint( aX, anY );
259     
260   if( myCurDragPosX == NULL && myCurDragPosY == NULL )
261   {
262     myCurDragPosX = new float(aX);
263     myCurDragPosY = new float(anY);
264     return;
265   }
266
267   //QPoint aNewPos = e->pos();
268   //GLViewer_Viewer2d* aViewer = (GLViewer_Viewer2d*)getViewFrame()->getViewer();
269   
270   if( anObject && (e->state() & LeftButton ) )
271   {
272     if( aContext->isSelected( anObject ) )
273     {
274       for( aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected() )
275       {
276         GLViewer_Object* aMovingObject = aContext->SelectedObject();
277         if( aMovingObject )
278           aMovingObject->moveObject( aX - *myCurDragPosX, anY - *myCurDragPosY);
279       }
280     }
281     else
282       anObject->moveObject( aX - *myCurDragPosX, anY - *myCurDragPosY);
283   }
284   else if( aContext->NbSelected() && (e->state() & MidButton ) )
285     for( aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected() )
286         (aContext->SelectedObject())->moveObject( aX - *myCurDragPosX, anY - *myCurDragPosY);
287   
288   delete myCurDragPosX;
289   delete myCurDragPosY;
290   myCurDragPosX = new float(aX);
291   myCurDragPosY = new float(anY);    
292
293   myGLWidget->updateGL();
294 }
295
296 /*!
297     Emits 'mouseEvent' signal. [ virtual protected ]
298 */
299 void GLViewer_ViewPort2d::mousePressEvent( QMouseEvent* e )
300 {    
301     emit vpMouseEvent( e );
302     
303     GLViewer_Viewer2d* aViewer = (GLViewer_Viewer2d*)getViewFrame()->getViewer();   
304     GLViewer_Context* aContext = aViewer->getGLContext();
305
306     GLViewer_Object* anObject = NULL;
307     if( aContext )
308         anObject = aContext->getCurrentObject();
309     
310     bool accel = e->state() & GLViewer_ViewTransformer::accelKey();
311     if( ( anObject && !( accel || e->button() == Qt::RightButton ) ) ||
312         ( aContext->NbSelected() && !accel && e->button() == Qt::MidButton )  )
313     {       
314         myIsDragProcess = inDrag;
315     }
316 }
317
318 /*!
319     Emits 'mouseEvent' signal. [ virtual protected ]
320 */
321 void GLViewer_ViewPort2d::mouseMoveEvent( QMouseEvent* e )
322 {
323     emit vpMouseEvent( e );
324     
325     if( myIsDragProcess == inDrag )
326         onDragObject( e );
327
328     /*GLViewer_Viewer2d* aViewer = (GLViewer_Viewer2d*)getViewFrame()->getViewer();   
329     GLViewer_Context* aContext = aViewer->getGLContext();
330
331     GLViewer_Object* anObj = aContext->getCurrentObject();
332     if( anObj && aContext->currentObjectIsChanged() )
333     {
334         //cout << "GLViewer_ViewPort2d::mouseMoveEvent{QToolTip::add}" << endl;
335         //QToolTip::remove( myGLWidget );
336         QRect* aRect = (aViewer->getWinObjectRect(anObj));
337         //QToolTip::add( myGLWidget, *aRect, anObj->getToolTipText() );
338         myGLWidget->addToolTip( anObj->getToolTipText(), *aRect );
339     }
340     if(!anObj)
341     {
342         //cout << "GLViewer_ViewPort2d::mouseMoveEvent{QToolTip::remove}" << endl;
343         //QRect* aRect = (aViewer->getWinObjectRect(anObj));
344         //QToolTip::remove( myGLWidget, *aRect );
345         myGLWidget->removeToolTip();
346     }*/
347 }
348
349 /*!
350     Emits 'mouseEvent' signal. [ virtual protected ]
351 */
352 void GLViewer_ViewPort2d::mouseReleaseEvent( QMouseEvent* e )
353 {    
354     if ( myIsMouseReleaseBlock )
355     {
356       // skip mouse release after double click
357       myIsMouseReleaseBlock = false;
358       return;
359     }
360
361     /* show popup menu */
362     if ( e->button() == Qt::RightButton )
363     {
364         //QPopupMenu* popup = createPopup();
365         //if ( popup && popup->count() )
366         //    popup->exec( QCursor::pos() );
367         //destroyPopup( /*popup*/ );
368     }
369     emit vpMouseEvent( e );
370     
371     if( myIsDragProcess == inDrag )
372     {
373       bool isAnyMoved = false;
374       GLViewer_Viewer2d* aViewer = (GLViewer_Viewer2d*)getViewFrame()->getViewer();
375       GLViewer_Context* aContext = aViewer->getGLContext();
376       GLViewer_Object* aMovingObject;
377       for( aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected() )
378       {
379         aMovingObject = aContext->SelectedObject();
380         if( aMovingObject )
381           isAnyMoved = aMovingObject->finishMove() || isAnyMoved;
382       }
383       
384       aMovingObject = aContext->getCurrentObject();
385       if( aMovingObject )
386         isAnyMoved = aMovingObject->finishMove() || isAnyMoved;
387       
388       myIsDragProcess = noDrag;
389       //myCurDragMousePos.setX( 0 );
390       //myCurDragMousePos.setY( 0 );
391       delete myCurDragPosX;
392       delete myCurDragPosY;
393       myCurDragPosX = NULL;
394       myCurDragPosY = NULL;
395
396       if( isAnyMoved )
397       {
398         emit objectMoved();
399         aViewer->updateBorders();
400       }
401     }
402 }
403
404 void GLViewer_ViewPort2d::mouseDoubleClickEvent( QMouseEvent * e )
405 {
406   //redefined to block mouse release after mouse double click
407   myIsMouseReleaseBlock = true;
408   // invoke base implementation
409   GLViewer_ViewPort::mouseDoubleClickEvent( e );
410 }
411
412 void GLViewer_ViewPort2d::turnCompass( GLboolean on )
413 {
414     if( on )
415         myCompass = new GLViewer_Compass( Qt::green, 30, GLViewer_Compass::TopRight, 10, 5, 12, 3 );
416     else if( myCompass )
417         delete myCompass;
418 }
419
420 void GLViewer_ViewPort2d::turnGrid( GLboolean on )
421 {
422     if( on )
423     {
424         myGrid = new GLViewer_Grid( 2*WIDTH, 2*HEIGHT,
425                                     2*WIDTH, 2*HEIGHT, 
426                                     GRID_XSIZE, GRID_YSIZE,
427                                     myXPan, myYPan,
428                                     myXScale, myYScale );
429     }
430     else if( myGrid )
431         delete myGrid;
432 }
433
434 void GLViewer_ViewPort2d::setGridColor( const QColor gridColor, const QColor axisColor )
435 {
436     if( myGrid )
437     {
438         myGrid->setGridColor( ( GLfloat )gridColor.red() / 255,
439                   ( GLfloat )gridColor.green() / 255,
440                   ( GLfloat )gridColor.blue() / 255 );
441         myGrid->setAxisColor( ( GLfloat )axisColor.red() / 255,
442                   ( GLfloat )axisColor.green() / 255,
443                   ( GLfloat )axisColor.blue() / 255 );
444     }
445 }
446
447 void GLViewer_ViewPort2d::setBackgroundColor( const QColor& color )
448 {
449     GLViewer_ViewPort::setBackgroundColor( color );
450     myGLWidget->makeCurrent();
451     glClearColor( ( GLfloat )color.red() / 255,
452             ( GLfloat )color.green() / 255,
453             ( GLfloat )color.blue() / 255, 1.0 );
454     myGLWidget->repaint();
455 }
456
457 QColor GLViewer_ViewPort2d::backgroundColor() const
458 {
459     return GLViewer_ViewPort::backgroundColor();
460 }
461
462 void GLViewer_ViewPort2d::initResize( int x, int y )
463 {
464     float xa, xb, ya, yb;
465     xa = myBorder->left() - myMargin;
466     xb = myBorder->right() + myMargin;
467     ya = myBorder->top() - myMargin;
468     yb = myBorder->bottom() + myMargin;
469
470     GLfloat zoom, xzoom, yzoom;
471     GLfloat w = x;
472     GLfloat h = y;
473     bool max = FALSE;
474
475     xzoom = (GLfloat)x / myWidth; 
476     yzoom = (GLfloat)y / myHeight; 
477
478     if ( ( xzoom < yzoom ) && ( xzoom < 1 ) ) 
479         zoom = xzoom; 
480     else if ( ( yzoom < xzoom ) && ( yzoom < 1 ) ) 
481         zoom = yzoom; 
482     else 
483     { 
484         max = TRUE; 
485         zoom = xzoom > yzoom ? xzoom : yzoom; 
486     } 
487
488     if ( !max && ( ! ( ( ( myXPan + w/2 ) < xb * myXScale * zoom ) ||
489              ( ( myXPan - w/2 ) > xa * myXScale * zoom ) || 
490              ( ( myYPan + h/2 ) < yb * myYScale * zoom ) ||
491              ( ( myYPan - h/2 ) > ya * myYScale * zoom ) ) ) ) 
492         zoom = 1; 
493
494     if ( max && ( ( ( myXPan + w/2 ) < xb * myXScale * zoom ) ||
495             ( ( myXPan - w/2 ) > xa * myXScale * zoom ) || 
496             ( ( myYPan + h/2 ) < yb * myYScale * zoom ) || 
497             ( ( myYPan - h/2 ) > ya * myYScale * zoom ) ) ) 
498         zoom = 1; 
499  
500     myWidth = x;
501     myHeight = y; 
502
503     myXScale *= zoom; 
504     myYScale = myXScale; 
505
506     if ( myGrid )
507         myGrid->setResize( 2*x, 2*y, zoom );
508
509     myGLWidget->setScale( myXScale, myYScale, 1.0 );
510 }
511
512 void GLViewer_ViewPort2d::paintEvent( QPaintEvent* e )
513 {
514     //cout << "GLViewer_ViewPort2d::paintEvent" << endl;
515     myGLWidget->updateGL();
516     GLViewer_ViewPort::paintEvent( e );
517 }
518
519 void GLViewer_ViewPort2d::resizeEvent( QResizeEvent* e )
520 {
521     //cout << "GLViewer_ViewPort2d::resizeEvent" << endl;
522     GLViewer_ViewPort::resizeEvent( e );
523 }
524
525 void GLViewer_ViewPort2d::reset()
526 {
527     //cout << "GLViewer_ViewPort2d::reset" << endl;
528
529     GLint val[4]; 
530     GLint vpWidth, vpHeight; 
531
532     myGLWidget->makeCurrent();
533     glGetIntegerv( GL_VIEWPORT, val );
534     vpWidth = val[2]; 
535     vpHeight = val[3]; 
536
537     GLint w = myGLWidget->getWidth();
538     GLint h = myGLWidget->getHeight();
539     GLfloat zoom = vpWidth / ( GLfloat )w < vpHeight / ( GLfloat )h ? 
540                  vpWidth / ( GLfloat )w : vpHeight / ( GLfloat )h; 
541
542     if( myGrid )
543     {
544         myGrid->setPan( 0.0, 0.0 );
545         myGrid->setZoom( zoom / myXScale );
546     }
547
548     myXPan = 0.0;
549     myYPan = 0.0;
550     myXScale = zoom;
551     myYScale = zoom;
552
553     myGLWidget->setPan( myXPan, myYPan, 0.0 );
554     myGLWidget->setScale( myXScale, myYScale, 1.0 );
555     myGLWidget->setRotationAngle( 0.0 );
556     myGLWidget->setRotation( 0.0, 0.0, 0.0, 1.0 );
557     myGLWidget->updateGL();
558 }
559
560 void GLViewer_ViewPort2d::pan( int dx, int dy )
561 {
562     //cout << "GLViewer_ViewPort2d::pan " << dx << " " << dy << endl;
563
564     /*myXPan += dx / myXScale;
565     myYPan += dy / myYScale;
566
567     float ra, rx, ry, rz;
568     myGLWidget->getRotation( ra, rx, ry, rz );
569     GLfloat angle = ra * PI / 180.;
570
571     if( myGrid )
572         myGrid->setPan( myXPan*cos(angle) + myYPan*sin(angle),
573                         -myXPan*sin(angle) + myYPan*cos(angle) );
574
575     */
576     float ra, rx, ry, rz;
577     myGLWidget->getRotation( ra, rx, ry, rz );
578     GLfloat angle = ra * PI / 180.;
579
580     myXPan += (dx*cos(angle) + dy*sin(angle)) / myXScale;
581     myYPan += (-dx*sin(angle) + dy*cos(angle)) / myXScale;
582
583     if( myGrid )
584         myGrid->setPan( myXPan, myYPan );
585
586     myGLWidget->setPan( myXPan, myYPan, 0.0 );
587     myGLWidget->setScale( myXScale, myYScale, 1.0 );
588     myGLWidget->updateGL();
589 }
590
591 void GLViewer_ViewPort2d::setCenter( int x, int y )
592 {
593     //cout << "GLViewer_ViewPort2d::setCenter" << endl;
594
595     GLint val[4]; 
596     GLint vpWidth, vpHeight; 
597
598     myGLWidget->makeCurrent();
599     glGetIntegerv( GL_VIEWPORT, val );
600     vpWidth = val[2]; 
601     vpHeight = val[3]; 
602
603     myXPan -= ( x - vpWidth/2 ) / myXScale;
604     myYPan += ( y - vpHeight/2 ) / myYScale;
605
606     if( myGrid )
607     {
608         myGrid->setPan( myXPan, myYPan );
609         myGrid->setZoom( myXOldScale / myXScale );
610     }
611
612     myXScale = myXOldScale;
613     myYScale = myYOldScale;
614
615     myGLWidget->setPan( myXPan, myYPan, 0.0 );
616     myGLWidget->setScale( myXScale, myYScale, 1.0 );
617     myGLWidget->updateGL();
618 }
619
620 void GLViewer_ViewPort2d::zoom( int x0, int y0, int x, int y )
621 {
622     //cout << "GLViewer_ViewPort2d::zoom" << endl;
623   
624     float dx, dy, zm;
625     dx = x - x0;
626     dy = y - y0;
627
628     if ( dx == 0. && dy == 0. )
629         return;
630
631     zm = sqrt(dx * dx + dy * dy) / 100. + 1; 
632     zm = (dx > 0.) ?  zm : 1. / zm; 
633
634     //backup values
635     float bX = myXScale;
636     float bY = myYScale;
637     myXScale *= zm; 
638     myYScale *= zm; 
639
640     if( myGrid )
641     {
642         if( myGrid->setZoom( zm ) )
643         {
644             myGLWidget->setPan( myXPan, myYPan, 0.0 );
645             myGLWidget->setScale( myXScale, myYScale, 1.0 );
646             myGLWidget->updateGL();
647         }
648         else
649         {// undo
650             myXScale = bX;
651             myYScale = bY;
652         } 
653     }
654     else
655     {
656         myGLWidget->setPan( myXPan, myYPan, 0.0 );
657         myGLWidget->setScale( myXScale, myYScale, 1.0 );
658         myGLWidget->updateGL();
659     }
660 }
661
662 void GLViewer_ViewPort2d::fitRect( const QRect& rect )
663 {
664     float x0, x1, y0, y1;
665     float dx, dy, zm, centerX, centerY; 
666
667     GLint val[4]; 
668     GLint vpWidth, vpHeight; 
669
670     myGLWidget->makeCurrent();
671     glGetIntegerv( GL_VIEWPORT, val );
672     vpWidth = val[2]; 
673     vpHeight = val[3]; 
674
675     x0 = rect.left();
676     x1 = rect.right();
677     y0 = rect.top();
678     y1 = rect.bottom();
679
680     dx = fabs( x1 - x0 ); 
681     dy = fabs( y1 - y0 ); 
682     centerX = ( x0 + x1 ) / 2.; 
683     centerY = ( y0 + y1 ) / 2.; 
684
685     if ( dx == 0. || dy == 0. )
686         return;
687
688     zm = vpWidth / dx < vpHeight / dy ? vpWidth / dx : vpHeight / dy; 
689
690     float aDX = ( vpWidth / 2. - centerX ) / myXScale;
691     float aDY = ( vpHeight / 2. - centerY ) / myYScale;
692
693     float ra, rx, ry, rz;
694     myGLWidget->getRotation( ra, rx, ry, rz );
695     GLfloat angle = ra * PI / 180.;
696
697     myXPan += (aDX*cos(angle) - aDY*sin(angle));
698     myYPan -= (aDX*sin(angle) + aDY*cos(angle));
699
700     if( myGrid )
701         myGrid->setPan( myXPan, myYPan );
702
703     myXScale *= zm;
704     myYScale = myXScale;
705
706     if( myGrid )
707         myGrid->setZoom( zm );
708
709     myGLWidget->setPan( myXPan, myYPan, 0.0 );
710     myGLWidget->setScale( myXScale, myYScale, 1.0 );
711     myGLWidget->updateGL();
712 }
713
714 void GLViewer_ViewPort2d::fitSelect()
715 {
716   GLViewer_Viewer2d* aViewer = (GLViewer_Viewer2d*)getViewFrame()->getViewer();
717   GLViewer_Context* aContext = aViewer->getGLContext();
718   if( !aContext )
719     return;
720   
721   QRect aSelRect;
722   for( aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected() )
723     aSelRect |= *(aViewer->getWinObjectRect( aContext->SelectedObject() ));
724
725   if( aSelRect.isValid() )
726   {
727     aSelRect.setTop( aSelRect.top() - SELECTION_RECT_GAP );
728     aSelRect.setBottom( aSelRect.bottom() + SELECTION_RECT_GAP );
729     aSelRect.setLeft( aSelRect.left() - SELECTION_RECT_GAP );
730     aSelRect.setRight( aSelRect.right() + SELECTION_RECT_GAP );
731     fitRect( aSelRect );
732   }
733 }
734
735 void GLViewer_ViewPort2d::fitAll( bool keepScale, bool withZ )
736 {
737     //cout << "GLViewer_ViewPort2d::fitAll" << endl;
738
739     float xa, xb, ya, yb;
740     float dx, dy, zm;
741     float xScale, yScale;
742
743     myMargin = QMAX( myBorder->width(), myBorder->height() ) / 5;
744
745     xa = myBorder->left() - myMargin;
746     xb = myBorder->right() + myMargin;
747     ya = myBorder->bottom() - myMargin;
748     yb = myBorder->top() + myMargin;
749
750     float aPoints[8] = { xa, ya, xb, ya, xa, yb, xb, yb };
751
752     float ra, rx, ry, rz;
753     myGLWidget->getRotation( ra, rx, ry, rz );
754     float angle = ra * PI / 180.;
755
756     int i;
757     for( i = 0; i < 7; i = i + 2 )
758         rotate_point( aPoints[i], aPoints[i+1], angle );
759
760     float aBorders[4] = { aPoints[0], aPoints[0], aPoints[1], aPoints[1] };
761
762     for( i = 2; i < 7; i = i + 2 )
763     {
764         if( aBorders[0] < aPoints[i] )
765             aBorders[0] = aPoints[i];
766         if( aBorders[1] > aPoints[i] )
767             aBorders[1] = aPoints[i];
768
769         if( aBorders[2] < aPoints[i+1] )
770             aBorders[2] = aPoints[i+1];
771         if( aBorders[3] > aPoints[i+1] )
772             aBorders[3] = aPoints[i+1];
773     }
774
775     GLint val[4];
776     GLint vpWidth, vpHeight;
777
778     myGLWidget->makeCurrent();
779     glGetIntegerv( GL_VIEWPORT, val );
780     vpWidth = val[2];
781     vpHeight = val[3];
782
783     dx = fabs( aBorders[1] - aBorders[0] );
784     dy = fabs( aBorders[3] - aBorders[2] );
785
786     myXPan = -( aBorders[0] + aBorders[1] ) / 2; 
787     myYPan = -( aBorders[2] + aBorders[3] ) / 2;
788     
789
790     if( keepScale )
791     {
792         myXOldScale = myXScale;
793         myYOldScale = myYScale;
794     }
795
796     xScale = myXScale;
797     yScale = myYScale;
798     if( dx && dy )
799         zm = vpWidth / dx < vpHeight / dy ? vpWidth / dx : vpHeight / dy; 
800     else
801         zm = 1.0;
802     myXScale = zm; 
803     myYScale = zm;    
804     
805
806     if( myGrid )
807     {
808         myGrid->setPan( myXPan, myYPan );
809         if( dx > dy )
810             myGrid->setZoom(  zm / xScale );
811         else  
812             myGrid->setZoom( zm / yScale );
813     }
814
815     myGLWidget->setPan( myXPan, myYPan, 0.0 );
816     myGLWidget->setScale( myXScale, myYScale, 1.0 );
817     myGLWidget->updateGL();
818
819     if( keepScale )
820         emit vpUpdateValues();
821 }
822
823 void GLViewer_ViewPort2d::startRotation( int x, int y )
824 {
825     myGLWidget->setRotationStart( x, y, 1.0 );
826 }
827
828 void GLViewer_ViewPort2d::rotate( int intX, int intY )
829 {
830     GLint val[4];
831     GLint vpWidth, vpHeight;
832
833     myGLWidget->makeCurrent();
834     glGetIntegerv( GL_VIEWPORT, val );
835     vpWidth = val[2];
836     vpHeight = val[3];
837
838     float x = intX, y = intY;
839     float x0 = vpWidth/2;
840     float y0 = vpHeight/2;
841
842     float xs, ys, zs, dx, dy;
843     myGLWidget->getRotationStart( xs, ys, zs );
844
845     xs = xs - x0;
846     x = x - x0;
847     dx = x - xs;
848     ys = y0 - ys;
849     y = y0 - y;
850     dy = y - ys;
851
852     float l1 = pow( double( xs*xs + ys*ys ), 0.5 );
853     float l2 = pow( double( x*x + y*y ), 0.5 );
854     float l = pow( double( dx*dx + dy*dy ), 0.5 );
855
856     double mult = xs * y - x * ys;
857     short sign;
858     if( mult > 0 ) sign = 1;
859     else if( mult < 0 ) sign = -1;
860     else sign = 0;
861
862     float anglePrev = myGLWidget->getRotationAngle();
863     float angleNew = sign * acos( ( l1*l1 + l2*l2 - l*l ) / ( 2 * l1 * l2 )) * 180. / PI;
864     float angle = anglePrev + angleNew;
865
866     // GLfloat anAngle = angle * PI / 180.; unused
867
868     float ra, rx, ry, rz;
869     myGLWidget->getRotation( ra, rx, ry, rz );
870     myGLWidget->setRotation( angle, rx, ry, rz );
871     myGLWidget->updateGL();
872 }
873
874 void GLViewer_ViewPort2d::endRotation()
875 {
876     float ra, rx, ry, rz;
877     myGLWidget->getRotation( ra, rx, ry, rz );
878     myGLWidget->setRotationAngle( ra );
879 }
880
881 void GLViewer_ViewPort2d::drawCompass()
882 {
883     if( !myCompass->getVisible() )
884         return;
885
886     GLfloat xScale, yScale, xPan, yPan;
887
888     int xPos = getWidth();
889     int yPos = getHeight();
890
891     int cPos = myCompass->getPos();
892     int cSize = myCompass->getSize();
893     QColor cCol = myCompass->getColor();
894     int cWidthTop = myCompass->getArrowWidthTop();
895     int cWidthBot = myCompass->getArrowWidthBottom();
896     int cHeightTop = myCompass->getArrowHeightTop();
897     int cHeightBot = myCompass->getArrowHeightBottom();
898
899     GLfloat colorR = (cCol.red())/255;
900     GLfloat colorG = (cCol.green())/255;
901     GLfloat colorB = (cCol.blue())/255;
902
903     float delX = cSize * 0.5;
904     float delY = cSize * 0.5;
905
906     getScale( xScale, yScale );
907     getPan( xPan, yPan);
908
909     float centerX = (xPos/2 - delX - cSize)/xScale;
910     float centerY = (yPos/2 - delY - cSize)/yScale;
911     
912     switch ( cPos )
913     {
914     case GLViewer_Compass::TopLeft:
915             centerX = -centerX;
916             break;
917         case GLViewer_Compass::BottomLeft:
918             centerX = -centerX;
919             centerY = -centerY;
920             break;
921         case GLViewer_Compass::BottomRight:
922             centerY = -centerY;
923             break;
924         default: break;
925     }
926     
927     float ra, rx, ry, rz;
928     myGLWidget->getRotation( ra, rx, ry, rz );
929     GLfloat angle = ra * PI / 180.;
930     GLfloat /*r = 0.0,*/ x = 0.0 , y = 0.0;
931
932     rotate_point( centerX, centerY, -angle );
933
934     centerX -= xPan;
935     centerY -= yPan;
936
937     glColor3f( colorR, colorG, colorB );
938     glBegin( GL_POLYGON );     
939     //arrow
940         x = centerX;                      y = centerY + cSize / yScale;    
941         glVertex2f( x, y );
942         //point #2
943         x = centerX + cWidthTop / xScale; y = centerY + ( cSize - cHeightTop ) / yScale ;
944         glVertex2f( x, y );
945         //point #3    
946         x = centerX + cWidthBot / xScale; y = centerY + ( cSize - cHeightTop ) / yScale ;
947         glVertex2f( x, y );
948         //point #4
949         x = centerX + cWidthBot / xScale; y = centerY - cSize/yScale;
950         glVertex2f( x, y );
951         //point #5
952         x = centerX;                      y = centerY - (cSize - cHeightBot) / yScale ;
953         glVertex2f( x, y ); 
954         //point #6
955         x = centerX - cWidthBot / xScale; y = centerY - cSize/yScale;
956         glVertex2f( x, y );
957         //point #7
958         x = centerX - cWidthBot / xScale; y = centerY + ( cSize - cHeightTop ) / yScale ;
959         glVertex2f( x, y );
960         //point #8
961         x = centerX - cWidthTop / xScale; y = centerY + ( cSize - cHeightTop ) / yScale ;
962         glVertex2f( x, y );
963     glEnd();
964     glLineWidth( 2.0 );
965     glEnable( GL_LINE_SMOOTH );
966     glBegin(GL_LINE_LOOP);
967     //circle
968         float aCircAngle = 0;
969         for ( int i = 0; i < 20 * SEGMENTS + 1; i++ )
970         {
971             x = centerX + cos(aCircAngle) * cSize / xScale;
972             y = centerY + sin(aCircAngle) * cSize / yScale;
973             glVertex2f( x, y );    
974             aCircAngle += float( STEP ) / 2;
975         }        
976     glEnd(); 
977     
978     GLdouble        modelMatrix[16], projMatrix[16];
979     GLint           viewport[4];
980     GLdouble        winxN, winyN, winz;
981     GLdouble        winxE, winyE;
982     GLdouble        winxS, winyS;
983     GLdouble        winxW, winyW;
984     GLuint          aTextList;    
985
986     GLViewer_TexFont* aFont = myCompass->getFont();
987     float widN = (float)aFont->getStringWidth( "N" );
988     float widW = (float)aFont->getStringWidth( "W" );
989     float widS = (float)aFont->getStringWidth( "S" );
990     float widE = (float)aFont->getStringWidth( "E" );
991     float heightL = (float)aFont->getStringHeight();
992
993     float xGapN = - widN/2 *( 1.0 + sin(angle) );
994     float xGapS = - widS/2 *( 1.0 - sin(angle) );
995     float xGapW = - widW/2 *( 1.0 + cos(angle) );
996     float xGapE = - widE/2 *( 1.0 - cos(angle) );
997
998     float yGapN = - heightL/2 *( 1.0 - cos(angle) ) * 0.75;
999     float yGapS = - heightL/2 *( 1.0 + cos(angle) ) * 0.75;
1000     float yGapW = - heightL/2 *( 1.0 + sin(angle) ) * 0.75;
1001     float yGapE = - heightL/2 *( 1.0 - sin(angle) ) * 0.75;
1002
1003     glGetIntegerv (GL_VIEWPORT, viewport);
1004     glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
1005     glGetDoublev (GL_PROJECTION_MATRIX, projMatrix);
1006     
1007     gluProject (centerX, centerY + cSize / yScale, 0, modelMatrix, projMatrix, viewport, &winxN, &winyN, &winz);
1008     gluProject (centerX + cSize / xScale, centerY, 0, modelMatrix, projMatrix, viewport, &winxE, &winyE, &winz);
1009     gluProject (centerX, centerY - cSize / yScale, 0, modelMatrix, projMatrix, viewport, &winxS, &winyS, &winz);
1010     gluProject (centerX - cSize / xScale, centerY, 0, modelMatrix, projMatrix, viewport, &winxW, &winyW, &winz);
1011
1012     glColor3f( 1.0, 1.0, 1.0 );    
1013
1014     aTextList = glGenLists( 1 );
1015     glNewList( aTextList, GL_COMPILE );
1016
1017     glMatrixMode(GL_PROJECTION);
1018     glPushMatrix();
1019     glLoadIdentity();
1020     glOrtho(0,viewport[2],0,viewport[3],-100,100);
1021     glMatrixMode(GL_MODELVIEW);
1022     glPushMatrix();
1023     glLoadIdentity();    
1024
1025     aFont->drawString( "N", winxN + xGapN, winyN + yGapN );
1026     aFont->drawString( "E", winxE + xGapE, winyE + yGapE );
1027     aFont->drawString( "S", winxS + xGapS, winyS + yGapS );
1028     aFont->drawString( "W", winxW + xGapW, winyW + yGapW );
1029
1030     glMatrixMode(GL_PROJECTION);
1031     glPopMatrix();
1032     glMatrixMode(GL_MODELVIEW);
1033     glPopMatrix();
1034
1035     glEndList();
1036
1037     if ( aTextList != -1 ) 
1038         glCallList( aTextList );
1039 }
1040
1041 BlockStatus GLViewer_ViewPort2d::currentBlock()
1042 {
1043     if( myIsDragProcess == inDrag && myCurDragPosX != NULL && myCurDragPosY != NULL)
1044         return BlockStatus(BS_Highlighting | BS_Selection);
1045     
1046     if( mypFirstPoint && mypLastPoint )
1047         return BlockStatus(BS_Highlighting | BS_Selection);
1048     
1049     return BS_NoBlock;
1050 }
1051
1052 void GLViewer_ViewPort2d::startSelectByRect( int x, int y )
1053 {
1054     if( !mypFirstPoint && !mypLastPoint )
1055     {
1056         mypFirstPoint = new QPoint( x, y );
1057         mypLastPoint = new QPoint( x, y );
1058     }
1059 }
1060 void GLViewer_ViewPort2d::drawSelectByRect( int x, int y )
1061 {
1062     if( mypFirstPoint && mypLastPoint )
1063     {
1064
1065         QPainter p( getPaintDevice() );
1066         p.setPen( Qt::white );
1067         p.setRasterOp( Qt::XorROP );
1068
1069         p.drawRect( selectionRect() );    /* erase */
1070
1071         mypLastPoint->setX( x );
1072         mypLastPoint->setY( y );
1073         
1074         p.drawRect( selectionRect() );    /* draw */
1075     }
1076
1077 }
1078 void GLViewer_ViewPort2d::finishSelectByRect()
1079 {
1080     if( mypFirstPoint && mypLastPoint )
1081     {
1082
1083         QPainter p( getPaintDevice() );
1084         p.setPen( Qt::white );
1085         p.setRasterOp( Qt::XorROP );
1086
1087         p.drawRect( selectionRect() );    /* erase */
1088
1089         delete mypFirstPoint;
1090         delete mypLastPoint;
1091
1092         mypFirstPoint = NULL;
1093         mypLastPoint = NULL;
1094     }
1095 }
1096
1097 QRect GLViewer_ViewPort2d::selectionRect()
1098 {
1099     QRect aRect;
1100     if( mypFirstPoint && mypLastPoint )
1101     {
1102         aRect.setLeft( QMIN( mypFirstPoint->x(), mypLastPoint->x() ) );
1103         aRect.setTop( QMIN( mypFirstPoint->y(), mypLastPoint->y() ) );
1104         aRect.setRight( QMAX( mypFirstPoint->x(), mypLastPoint->x() ) );
1105         aRect.setBottom( QMAX( mypFirstPoint->y(), mypLastPoint->y() ) );
1106     }
1107
1108     return aRect;
1109 }
1110
1111 bool GLViewer_ViewPort2d::startPulling( GLViewer_Pnt point )
1112 {
1113     GLViewer_Viewer2d* aViewer = (GLViewer_Viewer2d*)getViewFrame()->getViewer();
1114     GLViewer_Context* aContext = aViewer->getGLContext();
1115     ObjList anObjects = aContext->getObjects();
1116
1117     for( ObjList::Iterator it = anObjects.begin(); it != anObjects.end(); ++it )
1118     {
1119         GLViewer_Object* anObject = *it;
1120         GLViewer_Rect aRect = anObject->getPullingRect();
1121
1122         if( aRect.contains( point ) && anObject->startPulling( point ) )
1123         {
1124             myIsPulling = true;
1125             myPullingObject = anObject;
1126             setCursor( *getHandCursor() );
1127             return true;
1128         }
1129     }
1130
1131     return false;
1132 }
1133
1134 void GLViewer_ViewPort2d::drawPulling( GLViewer_Pnt point )
1135 {
1136     GLViewer_Viewer2d* aViewer = (GLViewer_Viewer2d*)getViewFrame()->getViewer();
1137     GLViewer_Context* aContext = aViewer->getGLContext();
1138     ObjList anObjects = aContext->getObjects();
1139
1140     GLViewer_Object* aLockedObject = 0;
1141     for( ObjList::Iterator it = anObjects.begin(); it != anObjects.end(); ++it )
1142     {
1143         GLViewer_Object* anObject = *it;
1144         if( !anObject->getVisible() )
1145             continue;
1146
1147         GLViewer_Rect aRect = anObject->getPullingRect();
1148
1149         if( aRect.contains( point ) && anObject->portContains( point ) )
1150         {
1151             aLockedObject = anObject;
1152             break;
1153         }
1154     }
1155
1156     myPullingObject->pull( point, aLockedObject );
1157 }
1158
1159 void GLViewer_ViewPort2d::finishPulling()
1160 {
1161     myIsPulling = false;
1162     myPullingObject->finishPulling();
1163     setCursor( *getDefaultCursor() );
1164 }
1165
1166 GLViewer_Rect GLViewer_ViewPort2d::win2GLV( const QRect& theRect ) const
1167 {
1168   GLViewer_Rect aRect;
1169
1170   GLdouble        modelMatrix[16], projMatrix[16];
1171   GLint           viewport[4];
1172
1173   GLdouble        objx1, objy1;
1174   GLdouble        objx2, objy2;
1175   GLdouble        objz;
1176
1177   glGetIntegerv (GL_VIEWPORT, viewport);
1178   glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
1179   glGetDoublev (GL_PROJECTION_MATRIX, projMatrix);
1180
1181   gluUnProject( theRect.left(), viewport[3] - theRect.top(), 0, modelMatrix, projMatrix, viewport, &objx1, &objy1, &objz );
1182   gluUnProject( theRect.right(), viewport[3] - theRect.bottom(), 0, modelMatrix, projMatrix, viewport, &objx2, &objy2, &objz );
1183   
1184   aRect.setLeft( objx1 );
1185   aRect.setTop( objy1 );
1186   aRect.setRight( objx2 );
1187   aRect.setBottom( objy2 );
1188
1189   return aRect;
1190 }
1191
1192 QRect GLViewer_ViewPort2d::GLV2win( const GLViewer_Rect& theRect ) const
1193 {
1194   QRect aRect;
1195
1196   GLdouble        modelMatrix[16], projMatrix[16];
1197   GLint           viewport[4];
1198
1199   GLdouble        winx1, winy1;
1200   GLdouble        winx2, winy2;
1201   GLdouble        winz;
1202
1203   glGetIntegerv (GL_VIEWPORT, viewport);
1204   glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
1205   glGetDoublev (GL_PROJECTION_MATRIX, projMatrix);
1206
1207   gluProject( theRect.left(), theRect.top(), 0, modelMatrix, projMatrix, viewport, &winx1, &winy1, &winz );
1208   gluProject( theRect.right(), theRect.bottom(), 0, modelMatrix, projMatrix, viewport, &winx2, &winy2, &winz );
1209   
1210   aRect.setLeft( (int)winx1 );
1211   aRect.setTop( viewport[3] - (int)winy1 );
1212   aRect.setRight( (int)winx2 );
1213   aRect.setBottom( viewport[3] - (int)winy2 );
1214
1215   return aRect;
1216 }
1217
1218 void GLViewer_ViewPort2d::onMaybeTip( QPoint thePoint, QString& theText, QFont& theFont, QRect& theTextReg, QRect& theRegion )
1219 {
1220   GLViewer_Context* aContext = ((GLViewer_Viewer2d*)getViewFrame()->getViewer())->getGLContext();
1221
1222   GLViewer_Object* anObj = aContext->getCurrentObject();
1223   if( anObj )
1224   {
1225     theText = anObj->getToolTipText();
1226     if( theText.isEmpty() )
1227       theText = anObj->getName();
1228
1229     QStringList aList;
1230     if( anObj->isTooTipHTML() )
1231       aList = QStringList::split( "<br>", theText );
1232     else
1233       aList = QStringList::split( "\n", theText );
1234
1235     if( !aList.isEmpty() )
1236     {
1237       int index = 0;
1238       int str_size = aList.first().length();
1239       for( int i = 1, size = aList.count(); i < size; i++ )
1240       {
1241         if( str_size < aList[i].length() )
1242         {
1243           index = i;
1244           str_size = aList[i].length();
1245         }
1246       }
1247       theFont = font();
1248       int cur_height = 24;
1249       QCursor* aCursor = QApplication::overrideCursor();
1250       if( aCursor )
1251       {
1252         const QBitmap* aBitmap = aCursor->bitmap();
1253         if( aBitmap )
1254           cur_height = aBitmap->height();
1255       }
1256
1257       //temp
1258       QSize aSize = QLabel( theText, 0 ).sizeHint();
1259       theTextReg = QRect( thePoint.x(), thePoint.y() + cur_height,
1260                           aSize.width(), aSize.height() );
1261       theRegion = QRect( thePoint.x(), thePoint.y(), 1, 1 );
1262     }
1263   }
1264 }