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