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