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