Salome HOME
Merge branch 'master' of newgeom:newgeom
[modules/shaper.git] / src / XGUI / XGUI_Viewer.cpp
1 #include "XGUI_Viewer.h"
2 #include "XGUI_MainWindow.h"
3 #include "XGUI_ViewWindow.h"
4 #include "XGUI_ViewPort.h"
5
6 #include <QMdiArea>
7 #include <QMdiSubWindow>
8 #include <QApplication>
9 #include <QMouseEvent>
10 #include <QMenu>
11
12 #include <V3d_View.hxx>
13
14 #include <Aspect_DisplayConnection.hxx>
15 #include <Graphic3d.hxx>
16 #include <Graphic3d_GraphicDriver.hxx>
17 #include <Geom_Axis2Placement.hxx>
18 #include <AIS_Drawer.hxx>
19 #include <Prs3d_DatumAspect.hxx>
20 #include <Prs3d_LineAspect.hxx>
21 #include <V3d_View.hxx>
22 #include <Visual3d_View.hxx>
23 #include <AIS_ListOfInteractive.hxx>
24 #include <AIS_ListIteratorOfListOfInteractive.hxx>
25 #include <AIS_Shape.hxx>
26
27
28 #ifdef WIN32
29 #include <WNT_Window.hxx>
30 #else
31 #include <Xw_Window.hxx>
32 #endif
33
34 XGUI_Viewer::InteractionStyle2StatesMap XGUI_Viewer::myStateMap;
35 XGUI_Viewer::InteractionStyle2ButtonsMap XGUI_Viewer::myButtonMap;
36 static bool isInitialized = false;
37
38 /*!
39  Creates viewer 3d [ static ]
40  */
41 Handle(V3d_Viewer) CreateViewer(const Standard_ExtString name, const Standard_CString displayName,
42                                 const Standard_CString domain, const Standard_Real viewSize,
43                                 const V3d_TypeOfOrientation viewProjection,
44                                 const Standard_Boolean computedMode,
45                                 const Standard_Boolean defaultComputedMode)
46 {
47   static Handle(Graphic3d_GraphicDriver) aGraphicDriver;
48   if (aGraphicDriver.IsNull()) {
49     Handle(Aspect_DisplayConnection) aDisplayConnection;
50 #ifndef WIN32
51     aDisplayConnection = new Aspect_DisplayConnection( displayName );
52 #else
53     aDisplayConnection = new Aspect_DisplayConnection();
54 #endif
55     aGraphicDriver = Graphic3d::InitGraphicDriver(aDisplayConnection);
56   }
57
58   return new V3d_Viewer(aGraphicDriver, name, domain, viewSize, viewProjection, Quantity_NOC_GRAY30,
59                         V3d_ZBUFFER, V3d_GOURAUD, V3d_WAIT, computedMode, defaultComputedMode,
60                         V3d_TEX_NONE);
61 }
62
63 // VSR: Uncomment below line to allow texture background support in OCC viewer
64 #define OCC_ENABLE_TEXTURED_BACKGROUND
65
66 /*!
67  Get data for supported background modes: gradient types, identifiers and supported image formats
68  */
69 QString XGUI_Viewer::backgroundData(QStringList& gradList, QIntList& idList, QIntList& txtList)
70 {
71   gradList << tr("Horizontal gradient") << tr("Vertical gradient")
72       << tr("First diagonal gradient") << tr("Second diagonal gradient")
73       << tr("First corner gradient") << tr("Second corner gradient")
74       << tr("Third corner gradient") << tr("Fourth corner gradient");
75   idList << XGUI::HorizontalGradient << XGUI::VerticalGradient << XGUI::Diagonal1Gradient
76       << XGUI::Diagonal2Gradient << XGUI::Corner1Gradient << XGUI::Corner2Gradient
77       << XGUI::Corner3Gradient << XGUI::Corner4Gradient;
78 #ifdef OCC_ENABLE_TEXTURED_BACKGROUND
79   txtList << XGUI::CenterTexture << XGUI::TileTexture << XGUI::StretchTexture;
80 #endif
81   return tr("Image files (*.bmp *.gif *.pix *.xwd *.rgb *.rs)");
82 }
83
84 XGUI_Viewer::XGUI_Viewer(XGUI_MainWindow* theParent, bool DisplayTrihedron)
85     : QObject(theParent), 
86     myMainWindow(theParent), 
87     myPreselectionEnabled(true), 
88     mySelectionEnabled(true), 
89     myMultiSelectionEnabled(true), 
90     myIsRelative(true), 
91     myInteractionStyle(XGUI::STANDARD), 
92     myTrihedronSize(100),
93     myActiveView(0),
94     myWndIdCount(0)
95 {
96   if (!isInitialized) {
97     isInitialized = true;
98
99     // standard interaction style
100     XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::ZOOM] = Qt::ControlModifier;
101     XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::ZOOM] = Qt::LeftButton;
102
103     XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::PAN] = Qt::ControlModifier;
104     XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::PAN] = Qt::MidButton;
105
106     XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::ROTATE] = Qt::ControlModifier;
107     XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::ROTATE] = Qt::RightButton;
108
109     XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::FIT_AREA] = Qt::ControlModifier;
110     XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::FIT_AREA] = Qt::RightButton;
111
112     // "key free" interaction style
113     XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::ZOOM] = Qt::NoModifier;
114     XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::ZOOM] = Qt::RightButton;
115
116     XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::PAN] = Qt::NoModifier;
117     XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::PAN] = Qt::MidButton;
118
119     XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::ROTATE] = Qt::NoModifier;
120     XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::ROTATE] = Qt::LeftButton;
121
122     XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::FIT_AREA] = Qt::NoModifier; // unused
123     XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::FIT_AREA] = Qt::NoButton; // unused
124   }
125
126   // init CasCade viewers
127   myV3dViewer = CreateViewer(TCollection_ExtendedString("Viewer3d").ToExtString(), "", "", 1000.0,
128                              V3d_XposYnegZpos, Standard_True, Standard_True);
129   myV3dViewer->SetDefaultLights();
130
131   // init selector
132   myAISContext = new AIS_InteractiveContext(myV3dViewer);
133   myAISContext->SelectionColor(Quantity_NOC_WHITE);
134
135   // display isoline on planar faces (box for ex.)
136   myAISContext->IsoOnPlane(true);
137
138   if (DisplayTrihedron) {
139     Handle(Geom_Axis2Placement) anAxis = new Geom_Axis2Placement(gp::XOY());
140     myTrihedron = new AIS_Trihedron(anAxis);
141     myTrihedron->SetInfiniteState( Standard_True);
142
143     Quantity_Color Col(193 / 255., 205 / 255., 193 / 255., Quantity_TOC_RGB);
144     myTrihedron->SetArrowColor(Col.Name());
145     myTrihedron->SetSize(myTrihedronSize);
146     Handle(AIS_Drawer) drawer = myTrihedron->Attributes();
147     if (drawer->HasDatumAspect()) {
148       Handle(Prs3d_DatumAspect) daspect = drawer->DatumAspect();
149       daspect->FirstAxisAspect()->SetColor(Quantity_Color(1.0, 0.0, 0.0, Quantity_TOC_RGB));
150       daspect->SecondAxisAspect()->SetColor(Quantity_Color(0.0, 1.0, 0.0, Quantity_TOC_RGB));
151       daspect->ThirdAxisAspect()->SetColor(Quantity_Color(0.0, 0.0, 1.0, Quantity_TOC_RGB));
152     }
153   }
154   // set zooming style to standard
155   //myZoomingStyle = 0;
156
157   QMdiArea* aMDI = myMainWindow->mdiArea();
158   connect(aMDI, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(onWindowActivated(QMdiSubWindow*)));
159
160 }
161
162 XGUI_Viewer::~XGUI_Viewer(void)
163 {
164   myAISContext.Nullify();
165   myV3dViewer.Nullify();
166 }
167
168 QMdiSubWindow* XGUI_Viewer::createView(V3d_TypeOfView theType)
169 {
170   // create view frame
171   XGUI_ViewWindow* view = new XGUI_ViewWindow(this, theType);
172   // get main view window (created by view frame)
173   //OCCViewer_ViewWindow* vw = view->getView(OCCViewer_ViewFrame::MAIN_VIEW);
174   // initialize main view window
175   //initView( vw );
176   // set default background for view window
177   //vw->setBackground( background(0) ); // 0 means MAIN_VIEW (other views are not yet created here)
178   // connect signal from viewport
179   //connect(view->viewPort(), SIGNAL(vpClosed()), this, SLOT(onViewClosed()));
180     //connect(view->viewPort(), SIGNAL(vpMapped()), this, SLOT(onViewMapped()));
181   if (myViews.size() == 0) 
182     setTrihedronShown(true);
183
184   view->setBackground(XGUI_ViewBackground(XGUI::VerticalGradient, Qt::white, QColor(Qt::blue).lighter()));
185   //view->setBackground(XGUI_ViewBackground(Qt::black));
186   view->updateEnabledDrawMode();
187
188   QMdiArea* aMDI = myMainWindow->mdiArea();
189   QMdiSubWindow* aWnd = aMDI->addSubWindow(view, Qt::FramelessWindowHint);
190   addView(aWnd);
191   aWnd->setGeometry(0, 0, aMDI->width() / 2, aMDI->height() / 2);
192   aWnd->show();
193   aWnd->setWindowTitle(QString("Viewer #%1").arg(++myWndIdCount));
194   emit viewCreated(view);
195   return aWnd;
196 }
197
198 XGUI_ViewWindow* XGUI_Viewer::activeViewWindow() const
199 {
200   return dynamic_cast<XGUI_ViewWindow*>(myActiveView->widget());
201 }
202
203 void XGUI_Viewer::getSelectedObjects(AIS_ListOfInteractive& theList)
204 {
205   theList.Clear();
206   for (myAISContext->InitSelected(); myAISContext->MoreSelected(); myAISContext->NextSelected())
207     theList.Append(myAISContext->SelectedInteractive());
208 }
209
210 void XGUI_Viewer::getSelectedShapes(NCollection_List<TopoDS_Shape>& theList)
211 {
212   Handle(AIS_InteractiveContext) ic = AISContext();
213
214   for (ic->InitSelected(); ic->MoreSelected(); ic->NextSelected()) {
215     TopoDS_Shape aShape = ic->SelectedShape();
216     if (!aShape.IsNull())
217       theList.Append(aShape);
218   }
219 }
220
221 void XGUI_Viewer::setObjectsSelected(const AIS_ListOfInteractive& theList)
222 {
223   AIS_ListIteratorOfListOfInteractive aIt;
224   for (aIt.Initialize(theList); aIt.More(); aIt.Next())
225     myAISContext->AddOrRemoveSelected(aIt.Value(), false);
226   myAISContext->UpdateCurrentViewer();
227 }
228
229 /*! Sets hot button
230  *\param theOper - hot operation
231  *\param theState - adding state to state map operations.
232  *\param theButton - adding state to button map operations.
233  */
234 void XGUI_Viewer::setHotButton(XGUI::InteractionStyle theInteractionStyle,
235                                XGUI::HotOperation theOper, Qt::KeyboardModifiers theState,
236                                Qt::MouseButtons theButton)
237 {
238   myStateMap[theInteractionStyle][theOper] = theState;
239   myButtonMap[theInteractionStyle][theOper] = theButton;
240 }
241
242 /*! Gets hot button for operation \a theOper.
243  *\param theOper - input hot operation
244  *\param theState - output state from state map operations.
245  *\param theButton - output state from button map operations.
246  */
247 void XGUI_Viewer::getHotButton(XGUI::InteractionStyle theInteractionStyle,
248                                XGUI::HotOperation theOper, Qt::KeyboardModifiers& theState,
249                                Qt::MouseButtons& theButton)
250 {
251   theState = myStateMap[theInteractionStyle][theOper];
252   theButton = myButtonMap[theInteractionStyle][theOper];
253 }
254
255 /*!
256  Changes visibility of trihedron to opposite
257  */
258 void XGUI_Viewer::toggleTrihedron()
259 {
260   setTrihedronShown(!isTrihedronVisible());
261 }
262
263 /*!
264  \return true if trihedron is visible
265  */
266 bool XGUI_Viewer::isTrihedronVisible() const
267 {
268   return !myTrihedron.IsNull() && !myAISContext.IsNull() && myAISContext->IsDisplayed(myTrihedron);
269 }
270
271 /*!
272  Sets visibility state of trihedron
273  \param on - new state
274  */
275
276 void XGUI_Viewer::setTrihedronShown(bool on)
277 {
278   if (myTrihedron.IsNull())
279     return;
280
281   if (on) {
282     myAISContext->Display(myTrihedron);
283     myAISContext->Deactivate(myTrihedron);
284   } else {
285     myAISContext->Erase(myTrihedron);
286   }
287 }
288
289 /*!
290  \return trihedron size
291  */
292 double XGUI_Viewer::trihedronSize() const
293 {
294   double sz = 0;
295   if (!myTrihedron.IsNull())
296     sz = myTrihedron->Size();
297   return sz;
298 }
299
300 /*!
301  Changes trihedron size
302  \param sz - new size
303  */
304 void XGUI_Viewer::setTrihedronSize(const double sz, bool isRelative)
305 {
306   if (myTrihedronSize != sz || isRelative != myIsRelative) {
307     myTrihedronSize = sz;
308     myIsRelative = isRelative;
309     updateTrihedron();
310   }
311 }
312
313 /*! 
314  * Update the size of the trihedron
315  */
316 void XGUI_Viewer::updateTrihedron()
317 {
318   if (myTrihedron.IsNull())
319     return;
320
321   if (myIsRelative) {
322     double newSz, oldSz;
323
324     if (computeTrihedronSize(newSz, oldSz))
325       myTrihedron->SetSize(newSz);
326
327   } else if (myTrihedron->Size() != myTrihedronSize) {
328     myTrihedron->SetSize(myTrihedronSize);
329   }
330 }
331
332 /*!
333  Get new and current trihedron size corresponding to the current model size
334  */
335 bool XGUI_Viewer::computeTrihedronSize(double& theNewSize, double& theSize)
336 {
337   theNewSize = 100;
338   theSize = 100;
339
340   //SRN: BUG IPAL8996, a usage of method ActiveView without an initialization
341   Handle(V3d_Viewer) viewer = v3dViewer();
342   viewer->InitActiveViews();
343   if (!viewer->MoreActiveViews())
344     return false;
345
346   Handle(V3d_View) view3d = viewer->ActiveView();
347   //SRN: END of fix
348
349   if (view3d.IsNull())
350     return false;
351
352   double Xmin = 0, Ymin = 0, Zmin = 0, Xmax = 0, Ymax = 0, Zmax = 0;
353   double aMaxSide;
354
355   view3d->View()->MinMaxValues(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
356
357   if (Xmin == RealFirst() || Ymin == RealFirst() || Zmin == RealFirst() || Xmax == RealLast()
358       || Ymax == RealLast() || Zmax == RealLast())
359     return false;
360
361   aMaxSide = Xmax - Xmin;
362   if (aMaxSide < Ymax - Ymin)
363     aMaxSide = Ymax - Ymin;
364   if (aMaxSide < Zmax - Zmin)
365     aMaxSide = Zmax - Zmin;
366
367   // IPAL21687
368   // The boundary box of the view may be initialized but nullified
369   // (case of infinite objects)
370   if (aMaxSide < Precision::Confusion())
371     return false;
372
373   static float EPS = (float)5.0E-3;
374   theSize = trihedron()->Size();
375   //theNewSize = aMaxSide*aSizeInPercents / 100.0;
376
377   return fabs(theNewSize - theSize) > theSize * EPS || fabs(theNewSize - theSize) > theNewSize * EPS;
378 }
379
380 void XGUI_Viewer::onViewClosed(QMdiSubWindow* theView)
381 {
382   if ( !theView )
383     return;
384
385   emit deleteView( static_cast<XGUI_ViewWindow*>(theView->widget()) );
386   removeView( theView );
387
388   // if this is last view
389   if (myViews.size() == 0) {
390     Standard_Integer aViewsNb = 0;
391     for ( myV3dViewer->InitActiveViews(); myV3dViewer->MoreActiveViews(); myV3dViewer->NextActiveViews())
392       ++aViewsNb;
393     if ( aViewsNb < 2 ) {
394       //clean up presentations before last view is closed
395       myAISContext->RemoveAll(Standard_False);
396     }
397   }
398 }
399
400 /*!Remove view window \a theView from view manager.
401  *And close the last view, if it has \a theView.
402 */
403 void XGUI_Viewer::removeView( QMdiSubWindow* theView )
404 {
405     XGUI_ViewWindow* aWindow = static_cast<XGUI_ViewWindow*>(theView->widget());
406
407     aWindow->disconnect( this );
408     myViews.removeAt( myViews.indexOf( theView ) );
409     if ( myActiveView == theView )
410         myActiveView = 0;
411     if ( myViews.size() == 0 )
412         emit lastViewClosed();
413 }
414
415
416 /*void XGUI_Viewer::onViewMapped()
417 {
418   setTrihedronShown(true);
419 }*/
420
421
422 void XGUI_Viewer::addView(QMdiSubWindow* theView)
423 {
424     XGUI_ViewWindow* aWindow = dynamic_cast<XGUI_ViewWindow*>(theView->widget());
425
426     connect(aWindow, SIGNAL(closed(QMdiSubWindow*)),
427             this,    SLOT(onViewClosed(QMdiSubWindow*)));
428
429     connect(aWindow, SIGNAL(tryClosing(XGUI_ViewWindow*)),
430             this,    SIGNAL(tryCloseView(XGUI_ViewWindow*)));
431
432     connect(aWindow, SIGNAL(mousePressed(XGUI_ViewWindow*, QMouseEvent*)),
433             this,    SLOT(onMousePressed(XGUI_ViewWindow*, QMouseEvent*)));
434
435     connect(aWindow, SIGNAL(mouseDoubleClicked(XGUI_ViewWindow*, QMouseEvent*)),
436             this,    SIGNAL(mouseDoubleClick(XGUI_ViewWindow*, QMouseEvent*)));
437
438     connect(aWindow, SIGNAL(mouseMoving(XGUI_ViewWindow*, QMouseEvent*)),
439             this,    SIGNAL(mouseMove(XGUI_ViewWindow*, QMouseEvent*)));
440
441     connect(aWindow, SIGNAL(keyPressed(XGUI_ViewWindow*, QKeyEvent*)),
442             this,    SIGNAL(keyPress(XGUI_ViewWindow*, QKeyEvent*)));
443
444     connect(aWindow, SIGNAL(keyReleased(XGUI_ViewWindow*, QKeyEvent*)),
445             this,    SIGNAL(keyRelease(XGUI_ViewWindow*, QKeyEvent*)));
446
447     connect(aWindow, SIGNAL(contextMenuRequested( QContextMenuEvent* )),
448             this,    SLOT  (onContextMenuRequested( QContextMenuEvent* )));
449     //connect(aWindow, SIGNAL( contextMenuRequested(QContextMenuEvent*) ), 
450     //        this, SIGNAL( contextMenuRequested(QContextMenuEvent*) ) );
451
452     connect(aWindow, SIGNAL(mouseMoving(XGUI_ViewWindow*, QMouseEvent*)),
453             this, SLOT(onMouseMove(XGUI_ViewWindow*, QMouseEvent*)));
454
455     connect(aWindow, SIGNAL(mouseReleased(XGUI_ViewWindow*, QMouseEvent*)),
456             this, SLOT(onMouseReleased(XGUI_ViewWindow*, QMouseEvent*)));
457
458     myViews.append(theView);
459 }
460
461 /*!
462     Emit activated for view \a view.
463 */
464 void XGUI_Viewer::onWindowActivated(QMdiSubWindow* view)
465 {
466   if (view && (view != myActiveView) && (!view->isMinimized())) {
467     qDebug("onWindowActivated");
468     myActiveView = view;
469     ((XGUI_ViewWindow*)myActiveView->widget())->windowActivated();
470     QList<QMdiSubWindow*>::iterator aIt;
471     for (aIt = myViews.begin(); aIt != myViews.end(); ++aIt) {
472       if ((*aIt) != myActiveView) {
473         ((XGUI_ViewWindow*)(*aIt)->widget())->windowDeactivated();
474       }
475     }
476   }
477 }
478
479
480 void XGUI_Viewer::onWindowMinimized(QMdiSubWindow* theWnd)
481 {
482   if (myActiveView == theWnd) {
483     myActiveView = 0;
484     QList<QMdiSubWindow*>::iterator aIt;
485     for (aIt = myViews.begin(); aIt != myViews.end(); ++aIt) {
486       if (!(*aIt)->widget()->isMinimized()) {
487         (*aIt)->raise();
488         onWindowActivated(*aIt);
489         break;
490       }
491     }
492   }
493 }
494
495 /*!
496   SLOT: called on mouse button press, stores current mouse position as start point for transformations
497 */
498 void XGUI_Viewer::onMousePressed(XGUI_ViewWindow* theWindow, QMouseEvent* theEvent)
499 {
500   myStartPnt.setX(theEvent->x()); myStartPnt.setY(theEvent->y());
501   emit mousePress(theWindow, theEvent);
502 }
503
504 /*!
505   SLOT: called on mouse move, processes hilighting
506 */
507 void XGUI_Viewer::onMouseMove(XGUI_ViewWindow* theWindow, QMouseEvent* theEvent)
508 {
509   myCurPnt.setX(theEvent->x()); myCurPnt.setY(theEvent->y());
510   if (!mySelectionEnabled) return;
511
512   Handle(V3d_View) aView3d = theWindow->viewPort()->getView();
513   if ( !aView3d.IsNull() ) {
514     myAISContext->MoveTo(theEvent->x(), theEvent->y(), aView3d);
515   }
516 }
517
518 /*!
519   SLOT: called on mouse button release, finishes selection
520 */
521 void XGUI_Viewer::onMouseReleased(XGUI_ViewWindow* theWindow, QMouseEvent* theEvent)
522 {
523   if (!mySelectionEnabled || theEvent->button() != Qt::LeftButton) {
524     emit mouseRelease(theWindow, theEvent);
525     return;
526   }
527
528   myEndPnt.setX(theEvent->x()); myEndPnt.setY(theEvent->y());
529   bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
530   
531   //if (!aHasShift) 
532   //  emit deselection();
533
534   if (myStartPnt == myEndPnt) {
535     // the MoveTo is necessary for the second click in the same point. Otherwise the selection is lost.
536     Handle(V3d_View) aView3d = theWindow->viewPort()->getView();
537     if ( !aView3d.IsNull() ) {
538       myAISContext->MoveTo(theEvent->x(), theEvent->y(), aView3d);
539     }
540     if (aHasShift && myMultiSelectionEnabled)
541       myAISContext->ShiftSelect();
542     else
543       myAISContext->Select();
544   } else {
545     if (aHasShift && myMultiSelectionEnabled)
546       myAISContext->ShiftSelect(myStartPnt.x(), myStartPnt.y(),
547                                 myEndPnt.x(), myEndPnt.y(),
548                                 theWindow->viewPort()->getView(), false );
549     else
550       myAISContext->Select(myStartPnt.x(), myStartPnt.y(),
551                            myEndPnt.x(), myEndPnt.y(),
552                            theWindow->viewPort()->getView(), false );
553
554     int Nb = myAISContext->NbSelected();
555     if( Nb>1 && !myMultiSelectionEnabled ) {
556       myAISContext->InitSelected();
557       Handle( SelectMgr_EntityOwner ) anOwner = myAISContext->SelectedOwner();
558       if( !anOwner.IsNull() ) {
559         myAISContext->ClearSelected( Standard_False );
560         myAISContext->AddOrRemoveSelected( anOwner, Standard_False );
561       }
562     }
563
564     myAISContext->UpdateCurrentViewer();
565   }
566   emit mouseRelease(theWindow, theEvent);
567   emit selectionChanged();
568 }
569
570 //******************************************************
571 void XGUI_Viewer::setMultiSelectionEnabled(bool toEnable) 
572
573   myMultiSelectionEnabled = toEnable; 
574   updateViewsDrawMode();
575 }
576
577 //******************************************************
578 void XGUI_Viewer::setSelectionEnabled(bool toEnable) 
579
580   mySelectionEnabled = toEnable; 
581   updateViewsDrawMode();
582 }
583
584 //******************************************************
585 void XGUI_Viewer::updateViewsDrawMode() const
586 {
587   foreach(QMdiSubWindow* aWnd, myViews){
588     XGUI_ViewWindow* aView = static_cast<XGUI_ViewWindow*>(aWnd->widget());
589     aView->updateEnabledDrawMode();
590   }
591 }
592
593 //******************************************************
594 void XGUI_Viewer::onContextMenuRequested(QContextMenuEvent* theEvent)
595 {
596   XGUI_ViewWindow* aWnd = dynamic_cast<XGUI_ViewWindow*>(sender());
597   if (!aWnd) return;
598
599   QMenu aMenu;
600
601   // Include Viewer actions
602   if (myActions.size() > 0) {
603     aMenu.addActions(myActions);
604     aMenu.addSeparator();
605   }
606   if (aWnd->actions().size() > 0) {
607     aMenu.addActions(aWnd->actions());
608     aMenu.addSeparator();
609   }
610
611   QMdiArea* aMDI = myMainWindow->mdiArea();
612   if (aMenu.actions().size() > 0) {
613     QMenu* aSubMenu = aMenu.addMenu(tr("Windows"));
614     aSubMenu->addActions(aMDI->actions());
615   } else {
616     aMenu.addActions(aMDI->actions());
617   }
618   aMenu.exec(theEvent->globalPos());
619 }