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