Salome HOME
Task #30 - Sketch base GUI: create, draw lines
[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
10 #include <V3d_View.hxx>
11
12 #include <Aspect_DisplayConnection.hxx>
13 #include <Graphic3d.hxx>
14 #include <Graphic3d_GraphicDriver.hxx>
15 #include <Geom_Axis2Placement.hxx>
16 #include <AIS_Drawer.hxx>
17 #include <Prs3d_DatumAspect.hxx>
18 #include <Prs3d_LineAspect.hxx>
19 #include <V3d_View.hxx>
20 #include <Visual3d_View.hxx>
21 #include <AIS_ListOfInteractive.hxx>
22
23 #include <QMouseEvent>
24
25 #ifdef WIN32
26 #include <WNT_Window.hxx>
27 #else
28 #include <Xw_Window.hxx>
29 #endif
30
31 XGUI_Viewer::InteractionStyle2StatesMap XGUI_Viewer::myStateMap;
32 XGUI_Viewer::InteractionStyle2ButtonsMap XGUI_Viewer::myButtonMap;
33 static bool isInitialized = false;
34
35 /*!
36  Creates viewer 3d [ static ]
37  */
38 Handle(V3d_Viewer) CreateViewer(const Standard_ExtString name, const Standard_CString displayName,
39                                 const Standard_CString domain, const Standard_Real viewSize,
40                                 const V3d_TypeOfOrientation viewProjection,
41                                 const Standard_Boolean computedMode,
42                                 const Standard_Boolean defaultComputedMode)
43 {
44   static Handle(Graphic3d_GraphicDriver) aGraphicDriver;
45   if (aGraphicDriver.IsNull()) {
46     Handle(Aspect_DisplayConnection) aDisplayConnection;
47 #ifndef WIN32
48     aDisplayConnection = new Aspect_DisplayConnection( displayName );
49 #else
50     aDisplayConnection = new Aspect_DisplayConnection();
51 #endif
52     aGraphicDriver = Graphic3d::InitGraphicDriver(aDisplayConnection);
53   }
54
55   return new V3d_Viewer(aGraphicDriver, name, domain, viewSize, viewProjection, Quantity_NOC_GRAY30,
56                         V3d_ZBUFFER, V3d_GOURAUD, V3d_WAIT, computedMode, defaultComputedMode,
57                         V3d_TEX_NONE);
58 }
59
60 // VSR: Uncomment below line to allow texture background support in OCC viewer
61 #define OCC_ENABLE_TEXTURED_BACKGROUND
62
63 /*!
64  Get data for supported background modes: gradient types, identifiers and supported image formats
65  */
66 QString XGUI_Viewer::backgroundData(QStringList& gradList, QIntList& idList, QIntList& txtList)
67 {
68   gradList << tr("Horizontal gradient") << tr("Vertical gradient")
69       << tr("First diagonal gradient") << tr("Second diagonal gradient")
70       << tr("First corner gradient") << tr("Second corner gradient")
71       << tr("Third corner gradient") << tr("Fourth corner gradient");
72   idList << XGUI::HorizontalGradient << XGUI::VerticalGradient << XGUI::Diagonal1Gradient
73       << XGUI::Diagonal2Gradient << XGUI::Corner1Gradient << XGUI::Corner2Gradient
74       << XGUI::Corner3Gradient << XGUI::Corner4Gradient;
75 #ifdef OCC_ENABLE_TEXTURED_BACKGROUND
76   txtList << XGUI::CenterTexture << XGUI::TileTexture << XGUI::StretchTexture;
77 #endif
78   return tr("Image files (*.bmp *.gif *.pix *.xwd *.rgb *.rs)");
79 }
80
81 XGUI_Viewer::XGUI_Viewer(XGUI_MainWindow* theParent, bool DisplayTrihedron)
82     : QObject(theParent), 
83     myMainWindow(theParent), 
84     myPreselectionEnabled(true), 
85     mySelectionEnabled(true), 
86     myMultiSelectionEnabled(true), 
87     myIsRelative(true), 
88     myInteractionStyle(XGUI::STANDARD), 
89     myTrihedronSize(100),
90     myActiveView(0)
91 {
92   if (!isInitialized) {
93     isInitialized = true;
94
95     // standard interaction style
96     XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::ZOOM] = Qt::ControlModifier;
97     XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::ZOOM] = Qt::LeftButton;
98
99     XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::PAN] = Qt::ControlModifier;
100     XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::PAN] = Qt::MidButton;
101
102     XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::ROTATE] = Qt::ControlModifier;
103     XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::ROTATE] = Qt::RightButton;
104
105     XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::FIT_AREA] = Qt::ControlModifier;
106     XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::FIT_AREA] = Qt::RightButton;
107
108     // "key free" interaction style
109     XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::ZOOM] = Qt::NoModifier;
110     XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::ZOOM] = Qt::RightButton;
111
112     XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::PAN] = Qt::NoModifier;
113     XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::PAN] = Qt::MidButton;
114
115     XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::ROTATE] = Qt::NoModifier;
116     XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::ROTATE] = Qt::LeftButton;
117
118     XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::FIT_AREA] = Qt::NoModifier; // unused
119     XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::FIT_AREA] = Qt::NoButton; // unused
120   }
121
122   // init CasCade viewers
123   myV3dViewer = CreateViewer(TCollection_ExtendedString("Viewer3d").ToExtString(), "", "", 1000.0,
124                              V3d_XposYnegZpos, Standard_True, Standard_True);
125   myV3dViewer->SetDefaultLights();
126
127   // init selector
128   myAISContext = new AIS_InteractiveContext(myV3dViewer);
129   myAISContext->SelectionColor(Quantity_NOC_WHITE);
130
131   // display isoline on planar faces (box for ex.)
132   myAISContext->IsoOnPlane(true);
133
134   if (DisplayTrihedron) {
135     Handle(Geom_Axis2Placement) anAxis = new Geom_Axis2Placement(gp::XOY());
136     myTrihedron = new AIS_Trihedron(anAxis);
137     myTrihedron->SetInfiniteState( Standard_True);
138
139     Quantity_Color Col(193 / 255., 205 / 255., 193 / 255., Quantity_TOC_RGB);
140     myTrihedron->SetArrowColor(Col.Name());
141     myTrihedron->SetSize(myTrihedronSize);
142     Handle(AIS_Drawer) drawer = myTrihedron->Attributes();
143     if (drawer->HasDatumAspect()) {
144       Handle(Prs3d_DatumAspect) daspect = drawer->DatumAspect();
145       daspect->FirstAxisAspect()->SetColor(Quantity_Color(1.0, 0.0, 0.0, Quantity_TOC_RGB));
146       daspect->SecondAxisAspect()->SetColor(Quantity_Color(0.0, 1.0, 0.0, Quantity_TOC_RGB));
147       daspect->ThirdAxisAspect()->SetColor(Quantity_Color(0.0, 0.0, 1.0, Quantity_TOC_RGB));
148     }
149   }
150   // set zooming style to standard
151   //myZoomingStyle = 0;
152
153   QMdiArea* aMDI = myMainWindow->mdiArea();
154   connect(aMDI, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(onWindowActivated(QMdiSubWindow*)));
155
156 }
157
158 XGUI_Viewer::~XGUI_Viewer(void)
159 {
160   myAISContext.Nullify();
161   myV3dViewer.Nullify();
162 }
163
164 QMdiSubWindow* XGUI_Viewer::createView(V3d_TypeOfView theType)
165 {
166   // create view frame
167   XGUI_ViewWindow* view = new XGUI_ViewWindow(this, theType);
168   // get main view window (created by view frame)
169   //OCCViewer_ViewWindow* vw = view->getView(OCCViewer_ViewFrame::MAIN_VIEW);
170   // initialize main view window
171   //initView( vw );
172   // set default background for view window
173   //vw->setBackground( background(0) ); // 0 means MAIN_VIEW (other views are not yet created here)
174   //// connect signal from viewport
175     //connect(view->viewPort(), SIGNAL(vpClosed()), this, SLOT(onViewClosed()));
176     //connect(view->viewPort(), SIGNAL(vpMapped()), this, SLOT(onViewMapped()));
177     if (myViews.size() == 0) 
178         setTrihedronShown(true);
179
180     view->setBackground(XGUI_ViewBackground(XGUI::VerticalGradient, Qt::white, QColor(Qt::blue).lighter()));
181   //view->setBackground(XGUI_ViewBackground(Qt::black));
182
183   QMdiArea* aMDI = myMainWindow->mdiArea();
184   QMdiSubWindow* aWnd = aMDI->addSubWindow(view, Qt::FramelessWindowHint);
185     addView(aWnd);
186   aWnd->setGeometry(0, 0, aMDI->width() / 2, aMDI->height() / 2);
187   aWnd->show();
188   return aWnd;
189 }
190
191 /*! Sets hot button
192  *\param theOper - hot operation
193  *\param theState - adding state to state map operations.
194  *\param theButton - adding state to button map operations.
195  */
196 void XGUI_Viewer::setHotButton(XGUI::InteractionStyle theInteractionStyle,
197                                XGUI::HotOperation theOper, Qt::KeyboardModifiers theState,
198                                Qt::MouseButtons theButton)
199 {
200   myStateMap[theInteractionStyle][theOper] = theState;
201   myButtonMap[theInteractionStyle][theOper] = theButton;
202 }
203
204 /*! Gets hot button for operation \a theOper.
205  *\param theOper - input hot operation
206  *\param theState - output state from state map operations.
207  *\param theButton - output state from button map operations.
208  */
209 void XGUI_Viewer::getHotButton(XGUI::InteractionStyle theInteractionStyle,
210                                XGUI::HotOperation theOper, Qt::KeyboardModifiers& theState,
211                                Qt::MouseButtons& theButton)
212 {
213   theState = myStateMap[theInteractionStyle][theOper];
214   theButton = myButtonMap[theInteractionStyle][theOper];
215 }
216
217 /*!
218  Changes visibility of trihedron to opposite
219  */
220 void XGUI_Viewer::toggleTrihedron()
221 {
222   setTrihedronShown(!isTrihedronVisible());
223 }
224
225 /*!
226  \return true if trihedron is visible
227  */
228 bool XGUI_Viewer::isTrihedronVisible() const
229 {
230   return !myTrihedron.IsNull() && !myAISContext.IsNull() && myAISContext->IsDisplayed(myTrihedron);
231 }
232
233 /*!
234  Sets visibility state of trihedron
235  \param on - new state
236  */
237
238 void XGUI_Viewer::setTrihedronShown(bool on)
239 {
240   if (myTrihedron.IsNull())
241     return;
242
243   if (on) {
244     myAISContext->Display(myTrihedron);
245     myAISContext->Deactivate(myTrihedron);
246   } else {
247     myAISContext->Erase(myTrihedron);
248   }
249 }
250
251 /*!
252  \return trihedron size
253  */
254 double XGUI_Viewer::trihedronSize() const
255 {
256   double sz = 0;
257   if (!myTrihedron.IsNull())
258     sz = myTrihedron->Size();
259   return sz;
260 }
261
262 /*!
263  Changes trihedron size
264  \param sz - new size
265  */
266 void XGUI_Viewer::setTrihedronSize(const double sz, bool isRelative)
267 {
268   if (myTrihedronSize != sz || isRelative != myIsRelative) {
269     myTrihedronSize = sz;
270     myIsRelative = isRelative;
271     updateTrihedron();
272   }
273 }
274
275 /*! 
276  * Update the size of the trihedron
277  */
278 void XGUI_Viewer::updateTrihedron()
279 {
280   if (myTrihedron.IsNull())
281     return;
282
283   if (myIsRelative) {
284     double newSz, oldSz;
285
286     if (computeTrihedronSize(newSz, oldSz))
287       myTrihedron->SetSize(newSz);
288
289   } else if (myTrihedron->Size() != myTrihedronSize) {
290     myTrihedron->SetSize(myTrihedronSize);
291   }
292 }
293
294 /*!
295  Get new and current trihedron size corresponding to the current model size
296  */
297 bool XGUI_Viewer::computeTrihedronSize(double& theNewSize, double& theSize)
298 {
299   theNewSize = 100;
300   theSize = 100;
301
302   //SRN: BUG IPAL8996, a usage of method ActiveView without an initialization
303   Handle(V3d_Viewer) viewer = v3dViewer();
304   viewer->InitActiveViews();
305   if (!viewer->MoreActiveViews())
306     return false;
307
308   Handle(V3d_View) view3d = viewer->ActiveView();
309   //SRN: END of fix
310
311   if (view3d.IsNull())
312     return false;
313
314   double Xmin = 0, Ymin = 0, Zmin = 0, Xmax = 0, Ymax = 0, Zmax = 0;
315   double aMaxSide;
316
317   view3d->View()->MinMaxValues(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
318
319   if (Xmin == RealFirst() || Ymin == RealFirst() || Zmin == RealFirst() || Xmax == RealLast()
320       || Ymax == RealLast() || Zmax == RealLast())
321     return false;
322
323   aMaxSide = Xmax - Xmin;
324   if (aMaxSide < Ymax - Ymin)
325     aMaxSide = Ymax - Ymin;
326   if (aMaxSide < Zmax - Zmin)
327     aMaxSide = Zmax - Zmin;
328
329   // IPAL21687
330   // The boundary box of the view may be initialized but nullified
331   // (case of infinite objects)
332   if (aMaxSide < Precision::Confusion())
333     return false;
334
335   static float EPS = (float)5.0E-3;
336   theSize = trihedron()->Size();
337   //theNewSize = aMaxSide*aSizeInPercents / 100.0;
338
339   return fabs(theNewSize - theSize) > theSize * EPS || fabs(theNewSize - theSize) > theNewSize * EPS;
340 }
341
342 void XGUI_Viewer::onViewClosed(QMdiSubWindow* theView)
343 {
344     if ( !theView )
345         return;
346
347     emit deleteView( static_cast<XGUI_ViewWindow*>(theView->widget()) );
348     removeView( theView );
349
350     // if this is last view
351     if (myViews.size() == 0) {
352         Standard_Integer aViewsNb = 0;
353         for ( myV3dViewer->InitActiveViews(); myV3dViewer->MoreActiveViews(); myV3dViewer->NextActiveViews())
354             ++aViewsNb;
355         if ( aViewsNb < 2 ) {
356             //clean up presentations before last view is closed
357             myAISContext->RemoveAll(Standard_False);
358         }
359     }
360 }
361
362 /*!Remove view window \a theView from view manager.
363  *And close the last view, if it has \a theView.
364 */
365 void XGUI_Viewer::removeView( QMdiSubWindow* theView )
366 {
367     XGUI_ViewWindow* aWindow = static_cast<XGUI_ViewWindow*>(theView->widget());
368
369     aWindow->disconnect( this );
370     myViews.removeAt( myViews.indexOf( theView ) );
371     if ( myActiveView == theView )
372         myActiveView = 0;
373     if ( myViews.size() == 0 )
374         emit lastViewClosed();
375 }
376
377
378 /*void XGUI_Viewer::onViewMapped()
379 {
380   setTrihedronShown(true);
381 }*/
382
383
384 void XGUI_Viewer::addView(QMdiSubWindow* theView)
385 {
386     XGUI_ViewWindow* aWindow = dynamic_cast<XGUI_ViewWindow*>(theView->widget());
387
388     connect(aWindow, SIGNAL(closed(QMdiSubWindow*)),
389             this,    SLOT(onViewClosed(QMdiSubWindow*)));
390
391     connect(aWindow, SIGNAL(tryClosing(XGUI_ViewWindow*)),
392             this,    SIGNAL(tryCloseView(XGUI_ViewWindow*)));
393
394     connect(aWindow, SIGNAL(mousePressed(XGUI_ViewWindow*, QMouseEvent*)),
395             this,    SLOT(onMousePressed(XGUI_ViewWindow*, QMouseEvent*)));
396
397     connect(aWindow, SIGNAL(mouseReleased(XGUI_ViewWindow*, QMouseEvent*)),
398             this,    SIGNAL(mouseRelease(XGUI_ViewWindow*, QMouseEvent*)));
399
400     connect(aWindow, SIGNAL(mouseDoubleClicked(XGUI_ViewWindow*, QMouseEvent*)),
401             this,    SIGNAL(mouseDoubleClick(XGUI_ViewWindow*, QMouseEvent*)));
402
403     connect(aWindow, SIGNAL(mouseMoving(XGUI_ViewWindow*, QMouseEvent*)),
404             this,    SIGNAL(mouseMove(XGUI_ViewWindow*, QMouseEvent*)));
405
406     connect(aWindow, SIGNAL(keyPressed(XGUI_ViewWindow*, QKeyEvent*)),
407             this,    SIGNAL(keyPress(XGUI_ViewWindow*, QKeyEvent*)));
408
409     connect(aWindow, SIGNAL(keyReleased(XGUI_ViewWindow*, QKeyEvent*)),
410             this,    SIGNAL(keyRelease(XGUI_ViewWindow*, QKeyEvent*)));
411
412 //    connect(aWindow, SIGNAL(contextMenuRequested( QContextMenuEvent* )),
413 //            this,    SLOT  (onContextMenuRequested( QContextMenuEvent* )));
414
415     connect(aWindow, SIGNAL(mouseMoving(XGUI_ViewWindow*, QMouseEvent*)),
416             this, SLOT(onMouseMove(XGUI_ViewWindow*, QMouseEvent*)));
417
418     connect(aWindow, SIGNAL(mouseReleased(XGUI_ViewWindow*, QMouseEvent*)),
419             this, SLOT(onMouseReleased(XGUI_ViewWindow*, QMouseEvent*)));
420
421     myViews.append(theView);
422 }
423
424 /*!
425     Emit activated for view \a view.
426 */
427 void XGUI_Viewer::onWindowActivated(QMdiSubWindow* view)
428 {
429   if (view && (view != myActiveView) && (!view->isMinimized())) {
430     myActiveView = view;
431     ((XGUI_ViewWindow*)myActiveView->widget())->windowActivated();
432     QList<QMdiSubWindow*>::iterator aIt;
433     for (aIt = myViews.begin(); aIt != myViews.end(); ++aIt) {
434       if ((*aIt) != myActiveView) {
435         ((XGUI_ViewWindow*)(*aIt)->widget())->windowDeactivated();
436       }
437     }
438   }
439 }
440
441
442 void XGUI_Viewer::onWindowMinimized(QMdiSubWindow* theWnd)
443 {
444   if (myActiveView == theWnd) {
445     myActiveView = 0;
446     QList<QMdiSubWindow*>::iterator aIt;
447     for (aIt = myViews.begin(); aIt != myViews.end(); ++aIt) {
448       if (!(*aIt)->widget()->isMinimized()) {
449         (*aIt)->raise();
450         onWindowActivated(*aIt);
451         break;
452       }
453     }
454   }
455 }
456
457 /*!
458   SLOT: called on mouse move, processes hilighting
459 */
460 void XGUI_Viewer::onMouseMove(XGUI_ViewWindow* theWindow, QMouseEvent* theEvent)
461 {
462   XGUI_ViewPort* aViewPort = theWindow->viewPort();
463   Handle(V3d_View) aView3d = aViewPort->getView();
464
465   if ( !aView3d.IsNull() )
466     myAISContext->MoveTo(theEvent->x(), theEvent->y(), aView3d);
467 }
468
469 /*!
470   SLOT: called on mouse button release, finishes selection
471 */
472 void XGUI_Viewer::onMouseReleased(XGUI_ViewWindow* theWindow, QMouseEvent* theEvent)
473 {
474   myAISContext->Select();
475
476   emit selectionChanged();
477 }