Salome HOME
Update from BR_V5_DEV 13Feb2009
[modules/gui.git] / src / GLViewer / GLViewer_Context.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, 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.
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 //  Author : OPEN CASCADE
23 // File:      GLViewer_Context.cxx
24 // Created:   November, 2004
25 //
26 /*!
27   \class GLViewer_AspectLine
28   \brief Class for manage of presentations in GLViewer
29 */
30
31 #include "GLViewer_Context.h"
32
33 #include "GLViewer_Group.h"
34 #include "GLViewer_Object.h"
35 #include "GLViewer_Viewer2d.h"
36 #include "GLViewer_ViewPort2d.h"
37 #include "GLViewer_ViewFrame.h"
38
39 //QT includes
40 #include <QRect>
41
42 #include <TColStd_SequenceOfInteger.hxx>
43
44 #define TOLERANCE  12
45
46 /*!
47   Constructor
48 */
49 GLViewer_Context::GLViewer_Context( GLViewer_Viewer2d* v ) :
50        myGLViewer2d( v ),
51        myHighlightColor( Quantity_NOC_CYAN1 ),
52        mySelectionColor( Quantity_NOC_RED ),
53        myTolerance( TOLERANCE )
54 {
55   myUpdateAll = true;
56
57   myLastPicked = 0;
58   myLastPickedChanged = false;
59
60   myHFlag = GL_TRUE;
61   mySFlag = GL_TRUE;
62
63   mySelCurIndex = 0;
64 }
65
66 /*!
67   Destructor
68 */
69 GLViewer_Context::~GLViewer_Context()
70 {
71     myActiveObjects.clear();
72     myInactiveObjects.clear();
73     mySelectedObjects.clear();
74 }
75
76 /*!
77   Hiilights objects under cursor
78   \param x - X coord of mouse cursor
79   \param y - Y coord of mouse cursor
80   \param byCircle - true if needs round sensitive area around mouse cursor, else rectangle
81   function search object rectangle which intersect with sensitive area and call object highlight method
82 */
83 int GLViewer_Context::MoveTo( int xi, int yi, bool byCircle )
84 {
85     GLfloat x = (GLfloat)xi;
86     GLfloat y = (GLfloat)yi;
87     myGLViewer2d->transPoint( x, y );
88
89     myXhigh = x;
90     myYhigh = y;  
91
92     GLboolean isHigh = GL_FALSE;
93     GLboolean onObject = GL_FALSE;
94
95     GLViewer_Object* aPrevLastPicked = myLastPicked;
96     GLViewer_Object* lastPicked = 0;
97
98     ObjList anUpdatedObjects;
99   
100     if( myActiveObjects.isEmpty() )
101         return -1;
102
103     ObjList::iterator it = myActiveObjects.end();
104     ObjList::iterator itEnd = myActiveObjects.begin();
105     for( it--; ; --it )
106     {
107         GLViewer_Object* object = *it;
108
109         GLViewer_Rect* rect = object->getUpdateRect();
110         if( rect->contains( GLViewer_Pnt( x, y ) ) )
111         {
112             onObject = GL_TRUE;
113             object->highlight( x, y, myTolerance, GL_FALSE );
114             isHigh = object->isHighlighted();
115         }
116
117         if( isHigh )
118         {
119             lastPicked = object;
120             break;
121         }
122
123         if( it == itEnd )
124             break;
125     }
126
127     if( !myHFlag )
128     {
129         myLastPicked = lastPicked;
130         return -1;
131     }
132
133     if ( !onObject )
134     {
135         //cout << 0 << endl;
136         it = myActiveObjects.begin();
137         itEnd = myActiveObjects.end();
138
139         for( ; it != itEnd; ++it )
140             (*it)->unhighlight();
141
142         anUpdatedObjects.append( (*it) );
143
144         myLastPicked = 0;
145         myLastPickedChanged = aPrevLastPicked != myLastPicked;
146
147         if( myLastPickedChanged )
148             myGLViewer2d->updateAll();  
149
150         return 0;
151     }
152
153     if( !myLastPicked && isHigh )
154     {
155         //cout << 1 << endl;
156         myLastPicked = lastPicked;
157         anUpdatedObjects.append( myLastPicked );
158     }
159     else if( myLastPicked && !isHigh )
160     {
161         //cout << 2 << endl;
162         myLastPicked->unhighlight();
163         anUpdatedObjects.append( myLastPicked );
164         myLastPicked = 0;
165     }
166     else if( myLastPicked && isHigh )
167     {
168         //cout << 3 << endl;
169         myLastPicked->highlight( x, y, myTolerance, byCircle );
170         anUpdatedObjects.append( myLastPicked );
171         if( myLastPicked != lastPicked )
172         {
173             myLastPicked->unhighlight();
174             myLastPicked = lastPicked;
175             anUpdatedObjects.append( myLastPicked );
176         }
177     }
178
179     myLastPickedChanged = ( aPrevLastPicked != myLastPicked );
180
181     if( myLastPickedChanged || myUpdateAll )
182         myGLViewer2d->updateAll();
183     else
184         myGLViewer2d->activateDrawers( anUpdatedObjects, TRUE, TRUE );
185
186     return 0;
187 }
188
189 /*! Selects already highlighting object by calling object method select
190   \param Append - true if new selection will be append to existing selection, false - another
191   \param byCircle - true if needs round selection area in complex object
192 */
193 int GLViewer_Context::Select( bool Append, bool byCircle )
194 {
195     ObjList::Iterator it, itEnd, oit, oitEnd;
196     SelectionStatus status = SS_Invalid;
197
198     bool updateAll = false;
199
200     ObjList aList;
201
202     if ( !mySFlag )
203         return status;//invalid
204
205     if( myHFlag && myLastPicked )
206     {
207         if( mySelectedObjects.count() == 1 && mySelectedObjects.first() == myLastPicked )
208             status = SS_LocalChanged;
209
210         if ( !Append )
211         {
212             for( it = mySelectedObjects.begin(), itEnd = mySelectedObjects.end() ; it != itEnd; ++it )
213                     if( myLastPicked != *it )
214                 {
215                         updateAll = (*it)->unselect() || updateAll;
216                         aList.append( *it );
217                 }
218
219             if( updateAll || myUpdateAll )
220                 myGLViewer2d->updateAll();
221             else
222                 myGLViewer2d->activateDrawers( aList, TRUE, TRUE );
223
224             if( mySelectedObjects.count() != 0 && status == SS_Invalid )
225                 status = SS_GlobalChanged;
226             mySelectedObjects.clear();
227         } 
228         else if( myLastPicked->isSelected() && status != SS_LocalChanged )
229         {
230             mySelectedObjects.removeAll( myLastPicked );
231             myLastPicked->unselect();
232             myGLViewer2d->updateAll();
233
234             if( mySelectedObjects.count() != 0 && status == SS_Invalid )
235               status = SS_GlobalChanged;
236
237             return status;
238         }
239
240         if ( myLastPicked->select( myXhigh, myYhigh, myTolerance, GLViewer_Rect(), false, byCircle, Append )
241              && mySelectedObjects.indexOf( myLastPicked ) == -1 )
242         {
243             mySelectedObjects.append( myLastPicked );
244             myGLViewer2d->activateDrawer( myLastPicked, TRUE, TRUE );
245
246             if( status == SS_Invalid )
247                 status = SS_GlobalChanged;
248         }
249         else if( status == SS_LocalChanged )
250             status = SS_GlobalChanged;
251
252         return status;
253     }
254
255     if( myHFlag && !myLastPicked )
256     {
257         if ( !Append )
258         {
259             for( it = mySelectedObjects.begin(), itEnd = mySelectedObjects.end() ; it != itEnd; ++it )
260                     if ( myLastPicked != *it )
261                 {
262                         updateAll = (*it)->unselect() || updateAll;
263                         aList.append( *it );
264                 }
265
266             if( updateAll || myUpdateAll )
267                 myGLViewer2d->updateAll();
268             else
269                 myGLViewer2d->activateDrawers( aList, TRUE, TRUE );
270
271             if( mySelectedObjects.count() != 0 )
272                 status = SS_GlobalChanged;
273
274             mySelectedObjects.clear();
275         }
276         return status;
277     }
278
279     if( !myHFlag )
280     {
281         bool isSel = false;
282         GLfloat aXScale;
283         GLfloat aYScale;
284         GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )myGLViewer2d->getActiveView()->getViewPort();
285         vp->getScale( aXScale, aYScale );
286
287         if ( !Append )
288         {
289             for( it = mySelectedObjects.begin(), itEnd = mySelectedObjects.end() ; it != itEnd; ++it )
290                 if( myLastPicked != *it )
291                 {
292                     updateAll = (*it)->unselect() || updateAll;
293                     aList.append( *it );
294                 }
295
296             if( updateAll || myUpdateAll )
297                 myGLViewer2d->updateAll();
298             else
299                 myGLViewer2d->activateDrawers( aList, TRUE, TRUE );
300
301             if( mySelectedObjects.count() != 0 )
302                 status = SS_GlobalChanged;
303
304             mySelectedObjects.clear();
305         }        
306
307         for( oit = myActiveObjects.begin(), oitEnd = myActiveObjects.end(); oit != oitEnd; ++oit )
308         {
309             (*oit)->setScale( aXScale, aYScale );
310             GLViewer_Rect* rect = (*oit)->getUpdateRect();
311
312             if( rect->contains( GLViewer_Pnt( myXhigh, myXhigh ) ) )
313             {
314                 (*oit)->select( myXhigh, myYhigh, myTolerance, GLViewer_Rect(), false, byCircle, Append );
315                 isSel = (*oit)->isSelected();
316             }
317             if( isSel )
318             {
319                 myLastPicked = *oit;
320                 mySelectedObjects.append( myLastPicked );
321                 myGLViewer2d->activateDrawer( myLastPicked, TRUE, TRUE );
322                 status = SS_GlobalChanged;
323                 return status;
324             }
325         }
326     }
327         
328     return SS_NoChanged;
329 }
330
331 /*! Selects objects on scene by rectangle
332   \param theRect - rectangle of selection
333   \param Append - true if new selection will be append to existing selection, false - another
334   function search object rectangle which intersect with theRect and call object select method
335 */
336 int GLViewer_Context::SelectByRect( const QRect& theRect, bool Append )
337 {
338     GLfloat aXScale;
339     GLfloat aYScale;
340     GLViewer_ViewPort2d* vp = ( GLViewer_ViewPort2d* )myGLViewer2d->getActiveView()->getViewPort();
341     vp->getScale( aXScale, aYScale );
342
343     SelectionStatus status = SS_NoChanged;
344
345     ObjList aList;
346     ObjList::Iterator it, itEnd;
347
348     if ( !mySFlag || myActiveObjects.empty() )
349         return SS_Invalid;
350
351     bool updateAll = false;
352     if( !Append )
353     {
354         if( mySelectedObjects.count() != 0 )
355             status = SS_GlobalChanged;
356
357         for( it = mySelectedObjects.begin(), itEnd = mySelectedObjects.end(); it != itEnd; ++it )
358         {
359             updateAll = (*it)->unselect() || updateAll;
360             aList.append( *it );
361         }
362         mySelectedObjects.clear();
363     }
364
365     for( it = myActiveObjects.begin(), itEnd = myActiveObjects.end(); it != itEnd; ++it )
366     {
367         bool isSel = false;
368         (*it)->setScale( aXScale, aYScale );
369         QRect rect = myGLViewer2d->getQRect( *( (*it)->getRect() ) );
370
371         if( rect.intersects( theRect ) )
372         {
373             GLViewer_Rect aRect = myGLViewer2d->getGLVRect( theRect );
374             (*it)->select( myXhigh, myYhigh, myTolerance, aRect, false, false, Append );
375             isSel = (*it)->isSelected();
376         }
377
378         if( isSel && mySelectedObjects.indexOf( *it ) == -1 )
379         {
380             aList.append( *it );
381             mySelectedObjects.append( *it );
382             status = SS_GlobalChanged;
383         }
384     }
385
386     if( updateAll || myUpdateAll )
387         myGLViewer2d->updateAll();
388     else
389         myGLViewer2d->activateDrawers( aList, TRUE, TRUE );
390
391     return status;
392 }
393
394 /*!
395   Sets color of hilighting
396   \param aCol - new color of highlighting
397 */
398 void GLViewer_Context::SetHighlightColor( Quantity_NameOfColor aCol )
399 {
400   myHighlightColor = aCol;
401   
402   Quantity_Color colorH( aCol );
403   int redH = 255 * (int)colorH.Red();
404   int greenH = 255 * (int)colorH.Green();
405   int blueH = 255 * (int)colorH.Blue();
406   QColor colH = QColor( redH, greenH, blueH );
407
408   Quantity_Color colorS( mySelectionColor );
409   int redS = 255 * (int)colorS.Red();
410   int greenS = 255 * (int)colorS.Green();
411   int blueS = 255 * (int)colorS.Blue();
412   QColor colS = QColor( redS, greenS, blueS );
413
414   myGLViewer2d->updateColors( colH, colS);
415 }
416
417 /*!
418   Sets color of selection
419   \param aCol - new color of selection
420 */
421 void GLViewer_Context::SetSelectionColor( Quantity_NameOfColor aCol )
422 {
423   mySelectionColor = aCol;
424   
425   Quantity_Color colorH( myHighlightColor );
426   int redH = 255 * (int)colorH.Red();
427   int greenH = 255 * (int)colorH.Green();
428   int blueH = 255 * (int)colorH.Blue();
429   QColor colH = QColor( redH, greenH, blueH );
430
431   Quantity_Color colorS( aCol );
432   int redS = 255 * (int)colorS.Red();
433   int greenS = 255 * (int)colorS.Green();
434   int blueS = 255 * (int)colorS.Blue();
435   QColor colS = QColor( redS, greenS, blueS );
436
437   myGLViewer2d->updateColors( colH, colS);
438 }
439
440 /*!
441   \return number of selected objects
442 */
443 int GLViewer_Context::NbSelected()
444 {
445   return mySelectedObjects.count();
446 }
447
448 /*!
449   Inits iteration through selected objects
450 */
451 void GLViewer_Context::InitSelected()
452 {
453   mySelCurIndex = 0;
454 }
455
456 /*!
457   Checks if iteration through selected objects may be continued
458 */
459 bool GLViewer_Context::MoreSelected()
460 {
461   return ( mySelCurIndex < NbSelected() );
462 }
463
464 /*!
465   Iterates to next selected object
466 */
467 bool GLViewer_Context::NextSelected()
468 {
469   if ( mySelCurIndex >= 0 && mySelCurIndex < NbSelected() )
470   {
471     mySelCurIndex++;
472     return TRUE;
473   }
474
475   return FALSE;
476 }
477
478 /*!
479   \return current selected object (must be used only in cycle as "for( InitSelected(); MoreSelected(); NextSelected() ) {...}" )
480 */
481 GLViewer_Object* GLViewer_Context::SelectedObject()
482 {
483     return mySelectedObjects[ mySelCurIndex ];
484 }
485
486 /*!
487   \return true if object is selected
488   \param theObj - object to be checked
489 */
490 bool  GLViewer_Context::isSelected( GLViewer_Object* theObj )
491 {
492     return mySelectedObjects.contains( theObj );
493 }
494
495 /*! Inserts new object in context
496   \param theObject - object to be inserted
497   \param display - true if needs display object immediatly after inserting, else false
498   \param isActive - true if needs inserting object in active list
499 */
500 int GLViewer_Context::insertObject( GLViewer_Object* object, bool display, bool isActive )
501 {
502 //  cout << "GLViewer_Context::insertObject" << endl;
503
504     if( !object )
505         return -1;
506
507     if( isActive )
508     {
509         myActiveObjects.append( object );
510         if( display )
511         {
512             //QRect* rect = object->getRect()->toQRect();
513             //myGLViewer2d->updateBorders( *rect );
514             myGLViewer2d->activateDrawer( object, FALSE );
515         }
516     }
517     else
518         myInactiveObjects.append( object );
519
520     return myActiveObjects.count() + myInactiveObjects.count();
521 }
522
523 /*!
524   Replaces object in context
525   \param oldObject - object to be replaced
526   \param newObject - object for replacing
527 */
528 bool GLViewer_Context::replaceObject( GLViewer_Object* oldObject, GLViewer_Object* newObject )
529 {
530     if( !oldObject || !newObject )
531         return false;
532
533   if( myActiveObjects.contains( oldObject ) )
534   {
535     myActiveObjects.removeAll( oldObject );
536     myActiveObjects.append( newObject );
537     return true;
538   }
539
540   if( myInactiveObjects.contains( oldObject ) )
541   {
542     myInactiveObjects.removeAll( oldObject );
543     myInactiveObjects.append( newObject );
544     return true;
545   }
546
547   return false;
548 }
549
550 /*!
551   Updates scales of all objects in context
552 */
553 void GLViewer_Context::updateScales( GLfloat scX, GLfloat scY )
554 {
555   if( scX <= 0 || scY <= 0 )
556       return;
557
558   ObjList::iterator it, itEnd;
559
560   for( it = myActiveObjects.begin(), itEnd = myActiveObjects.end(); it != itEnd; ++it )
561       (*it)->setScale( scX, scY );
562
563   for( it = myInactiveObjects.begin(), itEnd = myInactiveObjects.end(); it != itEnd; ++it )
564       (*it)->setScale( scX, scY );
565 }
566
567 /*!
568   Clears hilighting of objects
569   \param updateViewer - if it is true, viewer must be updated
570 */
571 void GLViewer_Context::clearHighlighted( bool updateViewer )
572 {
573   if( myHFlag && myLastPicked )
574   {
575     myLastPicked->unhighlight();
576     myLastPicked = 0;
577     
578     if( updateViewer )
579       myGLViewer2d->updateAll();
580   }
581 }
582
583 /*!
584   Clears selection of objects
585   \param updateViewer - if it is true, viewer must be updated
586 */
587 void GLViewer_Context::clearSelected( bool updateViewer )
588 {
589   if( !mySFlag )
590     return;
591
592   ObjList::Iterator it, itEnd;
593   ObjList aList;
594
595   for( it = mySelectedObjects.begin(), itEnd = mySelectedObjects.end(); it != itEnd; ++it )
596   {
597     (*it)->unselect();
598     aList.append( *it );
599   }          
600         
601   if( updateViewer )
602     myGLViewer2d->activateDrawers( aList, TRUE );
603   mySelectedObjects.clear();    
604 }
605
606 /*!
607   Selects object, other selected objects are left as selected
608   \param updateViewer - if it is true, viewer must be updated
609 */
610 void GLViewer_Context::setSelected( GLViewer_Object* object, bool updateViewer )
611 {
612   if( !object )
613     return;
614
615   if( myActiveObjects.contains( object ) && !mySelectedObjects.contains( object ) )
616   {
617     object->setSelected( TRUE );
618     mySelectedObjects.append( object );
619   }
620      
621   if( updateViewer )
622     myGLViewer2d->activateDrawer( object, TRUE, TRUE );
623 }
624
625 /*!
626   Unselects object, other selected objects are left as selected
627   \param updateViewer - if it is true, viewer must be updated
628 */
629 void GLViewer_Context::remSelected( GLViewer_Object* object, bool updateViewer )
630 {
631   if( !object || !mySelectedObjects.contains( object ) )
632     return;
633   
634   mySelectedObjects.removeAll( object );
635   object->unselect();
636   
637   if( updateViewer )
638     myGLViewer2d->activateDrawer( object, TRUE, TRUE );
639 }
640
641 /*!
642   Erases object in viewer
643   \param theUpdateViewer - if it is true, viewer must be updated
644 */
645 void GLViewer_Context::eraseObject( GLViewer_Object* theObject, bool theUpdateViewer )
646 {
647     if( !theObject || !myActiveObjects.contains( theObject ) )
648         return;
649
650     theObject->unhighlight();
651     theObject->unselect();
652     theObject->setVisible( false );
653
654     if( theUpdateViewer )
655         myGLViewer2d->updateAll();
656 }
657
658 /*!
659   Deletes object in
660   \param updateViewer - if it is true, viewer must be updated
661 */
662 void GLViewer_Context::deleteObject( GLViewer_Object* theObject, bool updateViewer )
663 {
664     if( !theObject ||
665         ( !myActiveObjects.contains( theObject ) && !myInactiveObjects.contains( theObject ) ) )
666         return;
667
668     if( myActiveObjects.contains( theObject ) )      
669         myActiveObjects.removeAll( theObject );
670     else if( myInactiveObjects.contains( theObject ) )
671         myInactiveObjects.removeAll( theObject );
672     else 
673         return;
674      
675     if( mySelectedObjects.contains( theObject ) )
676         mySelectedObjects.removeAll( theObject );
677
678     GLViewer_Group* aGroup = theObject->getGroup();
679     if( aGroup )
680         aGroup->removeObject( theObject );
681
682     if( myLastPicked == theObject )
683         myLastPicked = 0;
684
685     if ( updateViewer )
686       myGLViewer2d->updateAll();
687 }
688
689 /*!
690   Installs active status to object
691   \param theObject
692 */
693 bool GLViewer_Context::setActive( GLViewer_Object* theObject )
694 {
695   if( !theObject || !myInactiveObjects.contains( theObject ) )
696     return false;
697
698   myInactiveObjects.removeAll( theObject );
699   myActiveObjects.append( theObject );
700   return true;
701 }
702
703 /*!
704   Installs inactive status to object
705   \param theObject
706 */
707 bool GLViewer_Context::setInactive( GLViewer_Object* theObject )
708 {
709   if( !theObject || !myActiveObjects.contains( theObject ) )
710     return false;
711
712   myActiveObjects.removeAll( theObject );
713   myInactiveObjects.append( theObject );
714   return true;
715 }