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