Salome HOME
b55eea2be320d4e07be17b64e733ba52d39e1515
[modules/gui.git] / src / GLViewer / GLViewer_Viewer2d.cxx
1 // Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  Author : OPEN CASCADE
24 // File:      GLViewer_Viewer2d.cxx
25 // Created:   November, 2004
26 //#include <GLViewerAfx.h>
27 //
28 #include "GLViewer_Viewer2d.h"
29 #include "GLViewer_Object.h"
30 #include "GLViewer_ViewFrame.h"
31 #include "GLViewer_BaseObjects.h"
32 #include "GLViewer_CoordSystem.h"
33 #include "GLViewer_Context.h"
34 #include "GLViewer_Drawer.h"
35 #include "GLViewer_Selector2d.h"
36 #include "GLViewer_ViewPort2d.h"
37
38 #include "SUIT_Desktop.h"
39 #include "SUIT_ViewWindow.h"
40 #include "SUIT_ViewManager.h"
41
42 #include <QMenu>
43 #include <QRect>
44 #include <QFile>
45 #include <QPolygon>
46 #include <QMouseEvent>
47 #include <QColorDialog>
48
49 /*!
50   Constructor
51   \param title - viewer title
52 */
53 GLViewer_Viewer2d::GLViewer_Viewer2d( const QString& title) :
54 GLViewer_Viewer( title )
55 {
56   myGLContext = new GLViewer_Context( this );
57
58   createSelector();
59
60   mySelMode = GLViewer_Viewer::Multiple;
61
62   myDrawers.clear();
63 }
64
65 /*!
66   Destructor
67 */
68 GLViewer_Viewer2d::~GLViewer_Viewer2d()
69 {    
70     //myGLSketcher = 0;
71     //delete myGLSketcher;
72
73   qDeleteAll(myDrawers);
74   myDrawers.clear();
75
76   delete myGLContext;
77   myGLContext = nullptr;
78
79   GLViewer_TexFont::clearTextBases();
80 }
81
82 /*!Create new instance of view window on desktop \a theDesktop.
83  *\retval SUIT_ViewWindow* - created view window pointer.
84  */
85 SUIT_ViewWindow* GLViewer_Viewer2d::createView( SUIT_Desktop* theDesktop )
86 {
87     return new GLViewer_ViewFrame( theDesktop, this );
88 }
89
90 /*!
91   Adds item for change background color
92   \param thePopup - menu
93 */
94 void GLViewer_Viewer2d::addPopupItems( QMenu* thePopup )
95 {
96   // CTH8434. "Change background color" menu item is available if there are no selected objects
97   if ( getSelector() == 0 || getSelector()->numSelected() == 0 )
98   {
99     if( thePopup->actions().count() > 0 )
100         thePopup->addSeparator();
101     thePopup->addAction( tr( "CHANGE_BGCOLOR" ), this, SLOT( onChangeBgColor() ) );
102   }
103 }
104
105 /*!
106   Changes background color
107 */
108 void GLViewer_Viewer2d::onChangeBgColor()
109 {
110   if( !getActiveView() )
111     return;
112   GLViewer_ViewPort2d* vp = ( ( GLViewer_ViewPort2d* )getActiveView()->getViewPort() );
113
114   QColor selColor = QColorDialog::getColor( vp->backgroundColor(), vp );        
115   if ( selColor.isValid() ) {
116     vp->setBackgroundColor( selColor );
117   }
118 }
119
120 /*!
121   Updates colors for all drawers (does not work)
122 */
123 void GLViewer_Viewer2d::updateColors( QColor /*colorH*/, QColor /*colorS*/ )
124 {
125   activateAllDrawers( true );
126 }
127
128 /*!
129   Updates rect of global scene by adding new rectangle
130   \param theRect - rectangle
131 */
132 void GLViewer_Viewer2d::updateBorders( GLViewer_Rect* theRect )
133 {
134   QVector<SUIT_ViewWindow*> views = getViewManager()->getViews();
135   for ( int i = 0, n = views.count(); i < n; i++ )
136   {
137     GLViewer_Rect* border = ( ( GLViewer_ViewPort2d* )((GLViewer_ViewFrame*)views[i])->getViewPort() )->getBorder();
138
139     border->setLeft( qMin( border->left(), theRect->left() ) );
140     border->setRight( qMax( border->right(), theRect->right() ) );
141     border->setBottom( qMin( border->bottom(), theRect->bottom() ) );
142     border->setTop( qMax( border->top(), theRect->top() ) );
143   }
144 }
145
146 /*!
147   Recomputes global scene rect
148 */
149 void GLViewer_Viewer2d::updateBorders()
150 {
151     QVector<SUIT_ViewWindow*> views = getViewManager()->getViews();
152
153     ObjList anObjects = myGLContext->getObjects();
154     ObjList::Iterator beginIt = anObjects.begin();
155     ObjList::Iterator endIt = anObjects.end();
156     for ( int i = 0, n = views.count(); i < n; i++ )
157     {
158         GLViewer_Rect* border = ( ( GLViewer_ViewPort2d* )((GLViewer_ViewFrame*)views[i])->getViewPort() )->getBorder();
159         if ( !border )
160           continue;
161         border->setIsEmpty( true );
162         // initialise border by default values to avoid old values
163         border->setCoords( 0, 0, 0, 0 );
164         for ( ObjList::Iterator it = beginIt; it != endIt; ++it )
165         {
166             GLViewer_Object* anObject = *it;
167             GLViewer_Rect* aRect = anObject->getRect();
168             if( !anObject->isSelectable() || !anObject->getVisible() )
169                 continue;
170
171             if( border->isEmpty() )
172             {
173                 border->setIsEmpty( false );
174                 border->setCoords( aRect->left(), aRect->right(), aRect->bottom(), aRect->top() );
175             }
176             else
177             {
178                 border->setLeft( qMin( border->left(), aRect->left() ) );
179                 border->setRight( qMax( border->right(), aRect->right() ) );
180                 border->setBottom( qMin( border->bottom(), aRect->bottom() ) );
181                 border->setTop( qMax( border->top(), aRect->top() ) );
182             }
183         }
184     }
185 }
186
187 /*!
188   Redraws all active objects by updating all drawers in all views
189 */
190 void GLViewer_Viewer2d::updateAll()
191 {
192   if ( !getActiveView() )
193     return;
194
195   QVector<SUIT_ViewWindow*> views = getViewManager()->getViews();
196   for ( int i = 0, n = views.count(); i < n; i++ )
197     ( ( GLViewer_ViewPort2d* )( ( GLViewer_ViewFrame* )views[i] )->getViewPort() )->getGLWidget()->updateGL();
198 }
199
200 /*!
201    \param onlyUpdate is passed to method activateAllDrawers drawers
202 */
203 void GLViewer_Viewer2d::updateDrawers( GLboolean update, GLfloat /*scX*/, GLfloat /*scY*/ )
204 {
205     activateAllDrawers( update );
206 }
207
208 /*!
209   Activates drawers for objects from list \param theObjects only
210 */
211 void GLViewer_Viewer2d::activateDrawers( QList<GLViewer_Object*>& theObjects, bool onlyUpdate, GLboolean swap )
212 {
213     //cout << "GLViewer_Viewer2d::activateDrawers " << (int)onlyUpdate << " " << (int)swap << endl;
214     QList<GLViewer_Drawer*>::Iterator anIt = myDrawers.begin();
215     QList<GLViewer_Drawer*>::Iterator endDIt = myDrawers.end();
216     for( ; anIt != endDIt; anIt++ )
217         (*anIt)->clear();
218
219     QList<GLViewer_Drawer*> anActiveDrawers;
220     QList<GLViewer_Object*>::Iterator endOIt = theObjects.end();
221
222     for( QList<GLViewer_Object*>::Iterator oit = theObjects.begin(); oit != endOIt; ++oit )
223     {
224         GLViewer_Drawer* aDrawer = (*oit)->getDrawer();
225         if( !aDrawer )
226         {
227             anIt = myDrawers.begin();
228             endDIt = myDrawers.end();
229
230             for( ; anIt != endDIt; anIt++ )
231                 if( (*anIt)->getObjectType() == (*oit)->getObjectType() )
232                 {
233                     (*oit)->setDrawer( *anIt );
234                     aDrawer = *anIt;
235                     break;
236                 }
237
238             if( !aDrawer )
239             {
240                 myDrawers.append( (*oit)->createDrawer() );
241                 aDrawer = (*oit)->getDrawer();
242             }
243         }
244         if ( !aDrawer )
245           continue;
246         aDrawer->addObject( (*oit) );
247
248         int aPriority = aDrawer->getPriority();
249
250         if( anActiveDrawers.indexOf( aDrawer ) != -1 )
251             continue;
252
253         QList<GLViewer_Drawer*>::Iterator aDIt = anActiveDrawers.begin();
254         QList<GLViewer_Drawer*>::Iterator aDEndIt = anActiveDrawers.end();
255         for( ; aDIt != aDEndIt; ++aDIt )
256             if( (*aDIt)->getPriority() > aPriority )
257                 break;
258
259         anActiveDrawers.insert( aDIt, aDrawer );
260     } 
261
262     QList<GLViewer_Drawer*>::Iterator aDIt = anActiveDrawers.begin();
263     QList<GLViewer_Drawer*>::Iterator aDEndIt = anActiveDrawers.end();
264
265     QVector<SUIT_ViewWindow*> views = getViewManager()->getViews();
266     for ( int i = 0, n = views.count(); i < n; i++ )
267     {
268         float xScale, yScale;
269         GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )((GLViewer_ViewFrame*)views[i])->getViewPort();
270         vp->getScale( xScale, yScale );
271         vp->getGLWidget()->makeCurrent();
272
273         for( ; aDIt != aDEndIt; aDIt++ )
274         {
275             GLViewer_Drawer* aDrawer = *aDIt;
276             if( aDrawer )
277                 aDrawer->create( xScale, yScale, onlyUpdate );
278         }
279 /*
280         // draw border
281         GLViewer_Rect* border = ( ( GLViewer_ViewPort2d* )((GLViewer_ViewFrame*)views[i])->getViewPort() )->getBorder();
282         (*aDIt)->drawRectangle( border, Qt::blue );
283
284         QString coords = QString::number( border->left() ) + " " + QString::number( border->right() ) + " " +
285                          QString::number( border->bottom() ) + " " + QString::number( border->top() );
286         (*aDIt)->drawText( "Border : " + coords, border->left(), border->top() + 10 / yScale,
287                            Qt::blue, &QFont( "Courier", 8, QFont::Normal ), 2 );
288 */
289         if ( swap )
290            vp->getGLWidget()->swapBuffers();
291     }
292
293     ( ( GLViewer_ViewPort2d* )getActiveView()->getViewPort() )->getGLWidget()->makeCurrent();
294 }
295
296 /*!
297   Activates drawer for \param theObject
298 */
299 void GLViewer_Viewer2d::activateDrawer( GLViewer_Object* theObject, bool onlyUpdate, GLboolean swap )
300 {
301   ObjList aList;
302   aList.append( theObject );
303   activateDrawers( aList, onlyUpdate, swap );
304 }
305
306 /*!
307    \param onlyUpdate is passed to drawers
308 */
309 void GLViewer_Viewer2d::activateAllDrawers( bool onlyUpdate, GLboolean swap )
310 {
311     if ( !getActiveView() )
312       return;
313
314     ObjList anActiveObjs;
315     const ObjList& objs = myGLContext->getObjects();
316     for( ObjList::const_iterator it = objs.begin(); it != objs.end(); ++it )
317     {
318       GLViewer_Object* obj = (GLViewer_Object*)(*it);
319       if( obj->getVisible() )
320           anActiveObjs.append( obj );
321     }
322
323     activateDrawers( anActiveObjs, onlyUpdate, swap );
324 }
325
326 /*!
327   Creates set of marker
328   \param theMarkersNum - number of markers 
329   \param theMarkersRad - radius of markers
330 */
331 void GLViewer_Viewer2d::onCreateGLMarkers( int theMarkersNum, int theMarkersRad )
332 {
333     if ( !getActiveView() )
334       return;
335
336     GLViewer_MarkerSet* aMarkerSet = new GLViewer_MarkerSet( theMarkersNum, theMarkersRad );
337     getGLContext()->insertObject( aMarkerSet );
338
339     GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )getActiveView()->getViewPort();
340     int vpWidth = vp->getWidth();
341     int vpHeight = vp->getHeight();
342
343     float* aXCoord = new float[ theMarkersNum ];
344     float* anYCoord = new float[ theMarkersNum ];
345
346     srand( 1 );
347     for ( long i = 0; i < theMarkersNum; i++ )  
348     {
349         aXCoord[i] = cos( PI * (rand() / (GLfloat)RAND_MAX) ) * ((GLfloat)vpWidth / 2.);
350         anYCoord[i] = cos( PI * (rand() / (GLfloat)RAND_MAX) ) * ((GLfloat)vpHeight / 2.);
351     }
352
353     aMarkerSet->setXCoord( aXCoord, theMarkersNum );
354     aMarkerSet->setYCoord( anYCoord, theMarkersNum );
355     aMarkerSet->compute();
356
357     updateBorders( aMarkerSet->getRect() );
358     
359     activateAllDrawers( false );
360     activateTransform( GLViewer_Viewer::FitAll );
361
362     delete[] aXCoord;
363     delete[] anYCoord;
364 }
365
366 /*!
367   Creates GL polyline
368   \param theAnglesNum - number of angles
369   \param theRadius - radius
370   \param thePolylineNumber - number
371 */
372 void GLViewer_Viewer2d::onCreateGLPolyline( int theAnglesNum, int theRadius, int thePolylineNumber )
373 {
374     if ( !getActiveView() )
375       return;
376
377     GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )getActiveView()->getViewPort();
378     int vpWidth = vp->getWidth();
379     int vpHeight = vp->getHeight();
380
381     float* aXCoord = new float[ theAnglesNum ];
382     float* anYCoord = new float[ theAnglesNum ];
383
384     //srand( ( unsigned )time( NULL ) );
385     srand( 1 );
386     for( int j = 0; j < thePolylineNumber; j++)
387     {
388         GLViewer_Polyline* aPolyline = new GLViewer_Polyline( theAnglesNum, theRadius );
389         getGLContext()->insertObject( aPolyline );
390
391         float aXOffset = cos( PI * (rand() / (GLfloat)RAND_MAX) ) * ((GLfloat)vpWidth / 2.);
392         float anYOffset = cos( PI * (rand() / (GLfloat)RAND_MAX) ) * ((GLfloat)vpHeight / 2.);
393         for( int i = 0; i < theAnglesNum; i++ )  
394         {
395             aXCoord[i] = cos( 2. * PI * i / theAnglesNum ) * theRadius + aXOffset;
396             anYCoord[i] = sin( 2. * PI * i / theAnglesNum ) * theRadius + anYOffset;
397         }
398
399         aPolyline->setHighSelAll( true );
400         aPolyline->setClosed( true );
401         aPolyline->setXCoord( aXCoord, theAnglesNum );
402         aPolyline->setYCoord( anYCoord, theAnglesNum );
403         aPolyline->compute();
404
405         updateBorders( aPolyline->getRect() );
406     }
407     
408     activateAllDrawers( false );
409     activateTransform( GLViewer_Viewer::FitAll );
410
411     delete[] aXCoord;
412     delete[] anYCoord;
413 }
414
415 /*!
416   Creates text
417   \param theStr - text string
418   \param theTextNumber - number
419 */
420 void GLViewer_Viewer2d::onCreateGLText( QString theStr, int theTextNumber )
421 {
422     if ( !getActiveView() )
423       return;
424
425     if( theTextNumber <= 0 )
426         return;
427     
428     GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )getActiveView()->getViewPort();
429     int vpWidth = vp->getWidth();
430     int vpHeight = vp->getHeight();
431
432     //srand( ( unsigned )time( NULL ) );
433     srand( 1 );
434     for( int j = 0; j < theTextNumber; j++)
435     {
436         float aXPos = cos( PI * (rand() / (GLfloat)RAND_MAX) ) * ((GLfloat)vpWidth / 2.);
437         float anYPos = cos( PI * (rand() / (GLfloat)RAND_MAX) ) * ((GLfloat)vpHeight / 2.);
438         QColor aColor( 255, 0, 255 );
439
440         GLViewer_TextObject* aText = new GLViewer_TextObject( theStr, aXPos, anYPos, aColor  );
441         aText->compute();
442         getGLContext()->insertObject( aText );
443
444         updateBorders( aText->getRect() );
445     }
446
447     activateAllDrawers( false );
448 }
449
450 /*!
451   Translates point from global CS to curreent viewer CS
452   \param x, y - co-ordinates to be translated
453 */
454 void GLViewer_Viewer2d::transPoint( GLfloat& x, GLfloat& y )
455 {
456     if ( !getActiveView() )
457       return;
458
459     GLfloat xScale, yScale;
460     GLfloat xPan, yPan;
461
462     GLViewer_ViewPort2d* curvp = ( GLViewer_ViewPort2d* )getActiveView()->getViewPort();
463
464     curvp->getScale( xScale, yScale );
465     curvp->getPan( xPan, yPan );
466
467     GLfloat a = curvp->getGLWidget()->getRotationAngle() * PI / 180.;
468     
469     x = (  x - ( GLfloat )curvp->getWidth()  / 2 ) / xScale;
470     y = ( -y + ( GLfloat )curvp->getHeight() / 2 ) / yScale;
471
472     GLfloat x1 = x;
473     GLfloat y1 = y;
474
475     x = x1 * cos(a) + y1 * sin(a);
476     y = -x1 * sin(a) + y1 * cos(a);
477
478     x -= xPan;
479     y -= yPan;
480 }
481
482 /*!
483   \return object rect in window CS
484   \param theObject - object
485 */
486 QRect* GLViewer_Viewer2d::getWinObjectRect( GLViewer_Object* theObject )
487 {
488     if ( !getActiveView() )
489       return 0;
490
491     GLfloat xScale, yScale;
492     GLfloat xPan, yPan;
493
494     GLViewer_ViewPort2d* curvp = ( GLViewer_ViewPort2d* )getActiveView()->getViewPort();
495     GLfloat aWidth = curvp->getWidth();
496     GLfloat aHeight = curvp->getHeight();
497
498
499     curvp->getScale( xScale, yScale );
500     curvp->getPan( xPan, yPan );
501
502     QRect aObjRect = theObject->getRect()->toQRect();
503     float aLeft = aObjRect.left() + xPan, aRight = aObjRect.right() + xPan;
504     float aTop = aObjRect.top() + yPan, aBot = aObjRect.bottom() + yPan;
505
506     GLfloat anAngle = curvp->getGLWidget()->getRotationAngle() * PI / 180.;
507
508     QPolygon aPointArray(4);
509     aPointArray[0] = QPoint( (int)(aLeft*cos(anAngle) - aTop*sin(anAngle)),
510                              (int)(aLeft*sin(anAngle) + aTop*cos(anAngle)) );
511     aPointArray[1] = QPoint( (int)(aRight*cos(anAngle) - aTop*sin(anAngle)),
512                              (int)(aRight*sin(anAngle) + aTop*cos(anAngle)) );
513     aPointArray[2] = QPoint( (int)(aRight*cos(anAngle) - aBot*sin(anAngle)),
514                              (int)(aRight*sin(anAngle) + aBot*cos(anAngle)) );
515     aPointArray[3] = QPoint( (int)(aLeft*cos(anAngle) - aBot*sin(anAngle)),
516                              (int)(aLeft*sin(anAngle) + aBot*cos(anAngle)) );
517
518     int aMinLeft = aPointArray[0].x(), aMaxRight = aPointArray[0].x(), 
519         aMinTop = aPointArray[0].y(), aMaxBottom = aPointArray[0].y();
520     for( int i = 1; i < 4; i++ )
521     {
522         int x = aPointArray[i].x();
523         int y = aPointArray[i].y();
524         aMinLeft = qMin( aMinLeft,x );
525         aMaxRight = qMax( aMaxRight, x );
526         aMinTop = qMin( aMinTop, y );
527         aMaxBottom = qMax( aMaxBottom, y );
528     }
529
530     aLeft = (aMinLeft/* + xPan*/)*xScale + aWidth / 2;
531     aRight = (aMaxRight/* + xPan*/)*xScale + aWidth / 2;
532
533     aTop = -( (aMaxBottom/* + yPan*/)*yScale - aHeight / 2 );
534     aBot = -( (aMinTop/* + yPan*/)*yScale - aHeight / 2 );    
535
536     QRect* newRect = new QRect( (int)aLeft, (int)aTop, (int)(aRight-aLeft), (int)(aBot-aTop) );
537     
538     return newRect;
539 }
540
541 /*!
542   Translates rect in window CS to rect in global CS
543   \param theRect - rectangle to be translated
544   \return transformed rect
545 */
546 GLViewer_Rect GLViewer_Viewer2d::getGLVRect( const QRect& theRect ) const
547 {
548   if ( !getActiveView() )
549       return GLViewer_Rect();
550
551   GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )getActiveView()->getViewPort();
552
553   if( !vp )
554     return GLViewer_Rect();
555
556   return vp->win2GLV( theRect );
557 }
558
559 /*!
560   Translates rect in global CS to rect in window CS
561   \param theRect - rectangle to be translated
562   \return transformed rect
563 */
564 QRect GLViewer_Viewer2d::getQRect( const GLViewer_Rect& theRect ) const
565 {
566   if ( !getActiveView() )
567       return QRect();
568
569   GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )getActiveView()->getViewPort();
570
571   if( !vp )
572     return QRect();
573
574   return vp->GLV2win( theRect );
575 }
576
577 /*!
578   \return new selector
579 */
580 GLViewer_Selector* GLViewer_Viewer2d::createSelector()
581 {
582   return new GLViewer_Selector2d( this, getGLContext() );
583 }
584
585 /*!
586   \return new Transformer 
587   \param type - type of new transformer
588 */
589 GLViewer_ViewTransformer* GLViewer_Viewer2d::createTransformer( int type )
590 {
591     return new GLViewer_View2dTransformer( this, type );
592 }
593
594 /*!
595   Custom mouse event handler
596 */
597 void GLViewer_Viewer2d::onMouseEvent( SUIT_ViewWindow*, QMouseEvent* e )
598 {
599     if ( !getActiveView() )
600         return;
601
602     //if ( testRotation( e ) )
603     //    return;
604
605     switch( e->type() )
606     {
607         case QEvent::MouseButtonPress :
608         case QEvent::MouseMove :
609         case QEvent::MouseButtonRelease :
610             //if( myGLSketcher->getType() != None )
611             //    myGLSketcher->sketch( e );
612         default: break;
613     }
614
615     GLViewer_Viewer::onMouseEvent( 0, e );
616 }
617
618 /*!
619   Rotation transformation
620 */
621 bool GLViewer_Viewer2d::testRotation( QMouseEvent* e )
622 {
623   if ( ( (int)e->button() == GLViewer_View2dTransformer::rotateButton() ) && // todo Qt::MouseButton is unsigned int: comparison of int with uint
624          ( e->type() == QEvent::MouseButtonPress ) &&
625          ( e->modifiers() & GLViewer_ViewTransformer::accelKey() ) )
626     {
627         activateTransform( GLViewer_Viewer::Rotate );
628         return true;
629     }
630     return false;
631 }
632
633 /*!
634   Inserts text lines as header for file
635   \param aType - file type
636   \param hFile - file instance
637 */
638 void GLViewer_Viewer2d::insertHeader( VectorFileType aType, QFile& hFile )
639 {
640     if( aType == POST_SCRIPT )
641     {
642         QString header = "%!PS-Adobe-3.0\n";
643         header += "%%Creator: OpenCascade 2004\n";
644         header += "%%Title: Our document\n";        
645         header += "%%PageOrder: Ascend\n";      
646         header += "%%Orientation: Portrait\n";
647         header += "%%LanguageLevel: 2\n";
648
649         header += "%%Pages: 1\n";
650         header += "%%Page: 1\n\n";
651         
652         hFile.write( header.toLatin1() );
653     }
654     else if( aType == HPGL )
655     {
656         QString header = "[Esc].(;\n";
657         header += "[Esc].I81;;17:\n";
658         header += "[Esc].N;19:\n";
659         header += "IN;\n";
660         header += "SC;\n";
661         header += "PU;\n";
662         header += "SP1;\n";
663         header += "LT;\n";
664         header += "VS36;\n";
665         
666         hFile.write( header.toLatin1() );
667     }
668 }
669
670 /*!
671   Inserts text lines as ending for file
672   \param aType - file type
673   \param hFile - file instance
674 */
675 void GLViewer_Viewer2d::insertEnding( VectorFileType aType, QFile& hFile )
676 {
677     if( aType == POST_SCRIPT )
678     {
679         QString ending = "showpage\n\n%%EOF";
680         hFile.write( ending.toLatin1() );
681     }
682     else if( aType == HPGL )
683     {
684         QString ending = "PU;PA0,0;SP;EC;PG1;EC1;OE\n"; 
685         hFile.write( ending.toLatin1() );
686     }
687 }
688
689 inline void mm2custom( GLViewer_Viewer2d::VectorFileType aType, double& value )
690 {
691     if( aType==GLViewer_Viewer2d::POST_SCRIPT )
692         value*=2.8346; //mm to pt
693
694     else if( aType==GLViewer_Viewer2d::HPGL )
695         value*=40;     //mm to plu (there are 40 plues in mm)
696 #ifdef WIN32
697     else if( aType==GLViewer_Viewer2d::ENH_METAFILE )
698         value*=100;    //this unit is 1/100 mm
699 #endif 
700 }
701
702 /*!
703   Translates current view content to vector file
704   \param aType - type of file
705   \param FileName - name of file,
706   \param aPType - paper size type
707   \param mmLeft, mmRight, mmTop, mmBottom - margins
708 */
709 bool GLViewer_Viewer2d::translateTo( VectorFileType aType, QString FileName, PaperType aPType, 
710                                   double mmLeft, double mmRight, double mmTop, double mmBottom )
711 {
712     if ( !getActiveView() )
713       return false;
714
715         QFile hFile( FileName.toUtf8() );
716
717 #ifdef WIN32
718     HDC hMetaFileDC;
719 #endif
720
721     GLViewer_ViewPort2d* aCurVP = (GLViewer_ViewPort2d*) getActiveView()->getViewPort();
722
723     GLfloat xPan, yPan;
724     aCurVP->getPan( xPan, yPan );
725     GLfloat aRotation = aCurVP->getGLWidget()->getRotationAngle() * 3.14159265 / 180.0;
726
727     GLViewer_CoordSystem aViewerCS( GLViewer_CoordSystem::Cartesian, xPan, yPan, 1.0, 1.0, aRotation );
728
729     double AW = Sizes[2*int(aPType)], 
730            AH = Sizes[2*int(aPType)+1]; //size of Axx paper in mm
731
732     mm2custom( aType, mmLeft ); //we translate mm to custom units
733     mm2custom( aType, mmRight );
734     mm2custom( aType, mmTop );
735     mm2custom( aType, mmBottom );
736     mm2custom( aType, AW );
737     mm2custom( aType, AH );
738
739     float xScale, yScale;
740     aCurVP->getScale( xScale, yScale );
741
742     double VPWidth = aCurVP->getWidth()/xScale,   //the width in reference units
743            VPHeight = aCurVP->getHeight()/yScale;
744
745     double k1 = ( AW-mmLeft-mmRight ) / VPWidth,
746            k2 = ( AH-mmTop-mmBottom ) / VPHeight;
747
748     if( k1>k2 )
749         k1 = k2; //We select the minimum
750
751     double hdelta = ( AW-mmLeft-mmRight - VPWidth * k1 )/2.0, //addition in horizontal
752            vdelta = ( AH-mmTop-mmBottom - VPHeight * k1 )/2.0; //addition in vertical
753
754     mmLeft   += hdelta; //The real free space on the left and right borders
755     mmRight  += hdelta;
756     mmTop    += vdelta;
757     mmBottom += vdelta;
758
759     GLViewer_CoordSystem aPaperCS( GLViewer_CoordSystem::Cartesian, 
760         -(mmLeft/k1+VPWidth/2.0), -(mmBottom/k1+VPHeight/2.0), 1/k1, 1/k1 );
761
762     if( aType==POST_SCRIPT || aType==HPGL )
763     {
764         hFile.open( QIODevice::ReadWrite | QIODevice::Truncate );
765         hFile.seek( 0 );
766         insertHeader( aType, hFile );
767     }
768 #ifdef WIN32
769     else if( aType==ENH_METAFILE )
770     {
771         RECT r; 
772         r.left = 0; r.right = AW; 
773         r.top = 0; r.bottom = AH; 
774         HDC screen_dc = GetDC( 0 ); //The screen device context
775         HDC bitDC = CreateCompatibleDC ( screen_dc ); //The context compatible with screen
776
777 #ifdef UNICODE
778         LPTSTR str = new TCHAR[FileName.length() + 1];
779         str[FileName.toWCharArray(str)] = '\0';
780         LPTSTR empty = L"";
781 #else  
782         QByteArray arr = FileName.toLatin1();
783         LPTSTR str = arr.constData();
784         LPTSTR empty = "";
785 #endif
786
787         hMetaFileDC = CreateEnhMetaFile( bitDC, str, &r, empty );
788 #ifdef UNICODE
789         delete str;
790 #endif 
791         SetMapMode( hMetaFileDC, MM_HIMETRIC );
792         SetWindowOrgEx( hMetaFileDC, 0, r.bottom, NULL );
793         HRGN ClipRgn = CreateRectRgn( 0, 0, AW, AH );
794         SelectClipRgn( hMetaFileDC, ClipRgn );
795
796         LOGBRUSH aBrushData;
797         aBrushData.lbColor = RGB( 255, 255, 255 );      
798         aBrushData.lbStyle = BS_SOLID;
799
800         FillRect( hMetaFileDC, &r, CreateBrushIndirect( &aBrushData ) );
801
802         ReleaseDC( 0, screen_dc );
803         DeleteDC( bitDC );
804
805         aCurVP->getGLWidget()->translateBackgroundToEMF( hMetaFileDC, &aViewerCS, &aPaperCS );  
806     }
807 #endif
808
809     if( aType==POST_SCRIPT )
810     {
811         QString temp = "%1 %2 %3 %4 rectclip\n\n",
812                 aBuffer = temp.arg( mmLeft ).arg( mmBottom ).
813                                arg( AW-mmLeft-mmRight ).arg( AH-mmBottom-mmTop );
814         //It is set clipping path
815
816         hFile.write( aBuffer.toLatin1() );
817
818         aCurVP->getGLWidget()->translateBackgroundToPS( hFile, &aViewerCS, &aPaperCS );
819     }
820
821     bool result = true;
822     for( int i=0, n=myDrawers.count(); i<n; i++ )
823         if( aType==POST_SCRIPT )
824             result &= myDrawers[ i ]->translateToPS( hFile, &aViewerCS, &aPaperCS );
825         else if( aType==HPGL )
826             result &= myDrawers[ i ]->translateToHPGL( hFile, &aViewerCS, &aPaperCS );
827 #ifdef WIN32
828         else if( aType==ENH_METAFILE )
829             result &= myDrawers[ i ]->translateToEMF( hMetaFileDC, &aViewerCS, &aPaperCS );
830 #endif
831
832     if( aType==POST_SCRIPT || aType==HPGL )
833     {
834         insertEnding( aType, hFile);
835         hFile.close();
836     }
837 #ifdef WIN32
838     else if( aType==ENH_METAFILE )  
839         DeleteEnhMetaFile( CloseEnhMetaFile( hMetaFileDC ) );
840 #endif
841
842     return true;
843 }
844
845 /*!
846   Repaints view
847   \param theView - view to be repainted. If it is NULL then all views will be repainted
848 */
849 void GLViewer_Viewer2d::repaintView( GLViewer_ViewFrame* theView, bool makeCurrent )
850 {
851     GLViewer_ViewFrame* aCurView;
852     if( !theView )
853         aCurView = (GLViewer_ViewFrame*)getActiveView();
854     else
855         aCurView = theView;
856     
857     if ( !aCurView )
858       return;
859
860     ObjList anActiveObjs;
861     const ObjList& objs = myGLContext->getObjects();
862     for( ObjList::const_iterator it = objs.begin(); it != objs.end(); ++it )
863     {
864       GLViewer_Object* obj = (GLViewer_Object*)(*it);
865       if( obj->getVisible() )
866           anActiveObjs.append( obj );
867     }
868
869     float xScale;
870     float yScale;
871
872     QList<GLViewer_Drawer*>::Iterator anIt = myDrawers.begin();
873     QList<GLViewer_Drawer*>::Iterator endDIt = myDrawers.end();
874     for( ; anIt != endDIt; anIt++ )
875             (*anIt)->clear();
876
877     QList<GLViewer_Drawer*> anActiveDrawers;
878     QList<GLViewer_Object*>::Iterator endOIt = anActiveObjs.end();
879
880     for( QList<GLViewer_Object*>::Iterator oit = anActiveObjs.begin(); oit != endOIt; ++oit )
881     {
882         GLViewer_Drawer* aDrawer = (*oit)->getDrawer();
883         if( !aDrawer )
884         {
885             anIt = myDrawers.begin();            
886
887             for( ; anIt != endDIt; anIt++ )
888                 if( (*anIt)->getObjectType() == (*oit)->getObjectType() )
889                 {
890                     (*oit)->setDrawer( *anIt );
891                     aDrawer = *anIt;
892                     break;
893                 }
894
895             if( !aDrawer ) //are not exists
896             {
897                 myDrawers.append( (*oit)->createDrawer() );
898                 aDrawer = (*oit)->getDrawer();
899             }
900         }
901         aDrawer->addObject( (*oit) );
902         if( anActiveDrawers.indexOf( aDrawer ) == -1 )
903             anActiveDrawers.append( aDrawer );
904     } 
905
906     QList<GLViewer_Drawer*>::Iterator aDIt = anActiveDrawers.begin();
907     QList<GLViewer_Drawer*>::Iterator aDEndIt = anActiveDrawers.end();
908
909     GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )aCurView->getViewPort();
910     vp->getScale( xScale, yScale );
911
912     if( makeCurrent )
913         vp->getGLWidget()->makeCurrent();
914
915     for( ; aDIt != aDEndIt; aDIt++ )
916         (*aDIt)->create( xScale, yScale, false );
917     
918 //    if ( swap )
919     vp->getGLWidget()->swapBuffers();
920
921 //    ( ( GLViewer_ViewPort2d* )getActiveView()->getViewPort() )->getGLWidget()->makeCurrent();
922 }
923
924 /*!
925   Starts some operation on mouse event
926 */
927 void GLViewer_Viewer2d::startOperations( QMouseEvent* e )
928 {
929     GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )((GLViewer_ViewFrame*)getActiveView())->getViewPort();
930
931     float x = e->pos().x();
932     float y = e->pos().y();
933     transPoint( x, y );
934     GLViewer_Pnt point( x, y );
935
936     if( e->button() == Qt::LeftButton && !myGLContext->getCurrentObject() && vp->startPulling( point ) )
937         return;
938
939     if( e->button() == Qt::LeftButton && !(vp->currentBlock() & BS_Selection) && !myGLContext->getCurrentObject() )
940         vp->startSelectByRect( e->x(), e->y() );
941 }
942
943 /*!
944   Updates started operation on mouse event
945 */
946 bool GLViewer_Viewer2d::updateOperations( QMouseEvent* e )
947 {
948     GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )((GLViewer_ViewFrame*)getActiveView())->getViewPort();
949
950     if( vp->isPulling() )
951     {
952         float x = e->pos().x();
953         float y = e->pos().y();
954         transPoint( x, y );
955
956         vp->drawPulling( GLViewer_Pnt( x, y ) );
957         updateAll();
958         return true;
959     }
960
961     if( !myGLContext->getCurrentObject() )
962     {
963         vp->drawSelectByRect( e->x(), e->y() );
964         return true;
965     }
966     return false;
967 }
968
969 /*!
970   Completes started operation on mouse event
971 */
972 void GLViewer_Viewer2d::finishOperations( QMouseEvent* e )
973 {
974     GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )((GLViewer_ViewFrame*)getActiveView())->getViewPort();
975
976     if( vp->isPulling() )
977     {
978         vp->finishPulling();
979         updateAll();
980         return;
981     }
982
983     if( !myGLContext->getCurrentObject() )
984     {
985         QRect aSelRect = vp->selectionRect();
986         vp->finishSelectByRect();
987         if ( getSelector() && !aSelRect.isNull() )
988         {            
989             bool append = bool ( e->modifiers() & GLViewer_Selector::appendKey() );
990             getSelector()->select( aSelRect, append );
991         }
992     }
993 }
994
995 /*!
996   Starts some operation on mouse wheel event
997 */
998 void GLViewer_Viewer2d::startOperations( QWheelEvent* e )
999 {
1000     bool zoomIn = e->delta() > 0;
1001     bool update = false;
1002     for( myGLContext->InitSelected(); myGLContext->MoreSelected(); myGLContext->NextSelected() )
1003     {
1004         GLViewer_Object* anObject = myGLContext->SelectedObject();
1005         update = anObject->updateZoom( zoomIn ) || update;
1006     }
1007
1008     emit wheelZoomChange( zoomIn );
1009
1010     if( update )
1011         updateAll();
1012 }
1013
1014
1015 int GLViewer_View2dTransformer::rotateBtn = Qt::RightButton;
1016
1017 /*!
1018   Constructor
1019 */
1020 GLViewer_View2dTransformer::GLViewer_View2dTransformer( GLViewer_Viewer* viewer, int typ )
1021 : GLViewer_ViewTransformer( viewer, typ )
1022 {
1023     if ( type() == GLViewer_Viewer::Rotate )
1024         initTransform( true );
1025 }
1026
1027 /*!
1028   Destructor
1029 */
1030 GLViewer_View2dTransformer::~GLViewer_View2dTransformer()
1031 {
1032     if ( type() == GLViewer_Viewer::Rotate )
1033         initTransform( false );
1034 }
1035
1036 /*!
1037     Redefined to provide specific 3D transfomations. [ virtual public ]
1038 */
1039 void GLViewer_View2dTransformer::exec()
1040 {
1041     if ( !myViewer->getActiveView() )
1042       return;
1043
1044     /* additional transforms */
1045     GLViewer_ViewPort* vp = myViewer->getActiveView()->getViewPort();
1046     GLViewer_ViewPort2d* avp = (GLViewer_ViewPort2d*)vp;
1047     switch ( myType )
1048     {
1049         case GLViewer_Viewer::Rotate:
1050             myMajorBtn = rotateButton();
1051             avp->setCursor( *avp->getRotCursor() );
1052             break;
1053         default:
1054             GLViewer_ViewTransformer::exec();
1055     }
1056 }
1057
1058 /*!
1059     Handles rotation. [ protected virtual ]
1060 */
1061 void GLViewer_View2dTransformer::onTransform( TransformState state )
1062 {
1063     if ( !myViewer->getActiveView() )
1064       return;
1065
1066     GLViewer_ViewPort* vp = myViewer->getActiveView()->getViewPort();
1067     GLViewer_ViewPort2d* avp = (GLViewer_ViewPort2d*)vp;
1068     if ( type() == GLViewer_Viewer::Rotate )
1069     {
1070         switch ( state )
1071         {
1072             case Debut:
1073                 if ( myButtonState & myMajorBtn )
1074                     avp->startRotation( myStart.x(), myStart.y() );
1075                 break;
1076             case EnTrain:
1077                 if ( myButtonState & myMajorBtn )
1078                     avp->rotate( myCurr.x(), myCurr.y() );
1079                 break;
1080             case Fin:
1081                 avp->endRotation();
1082                 break;
1083             default: break;
1084         }
1085     }
1086     GLViewer_ViewTransformer::onTransform( state );
1087 }