e0c88e05a726856bda4f15ae5a26d91b21b313af
[occt.git] / tools / View / View_Widget.cxx
1 // Created on: 2017-06-16
2 // Created by: Natalia ERMOLAEVA
3 // Copyright (c) 2017 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement. 
15
16 #if !defined _WIN32
17 #define QT_CLEAN_NAMESPACE         /* avoid definition of INT32 and INT8 */
18 #endif
19
20 #include <inspector/View_Widget.hxx>
21
22 #include <AIS_ViewController.hxx>
23 #include <Geom_Axis2Placement.hxx>
24 #include <Graphic3d_GraphicDriver.hxx>
25
26 #include <inspector/View_ToolButton.hxx>
27 #include <inspector/View_ViewActionType.hxx>
28 #include <inspector/View_Viewer.hxx>
29
30 #include <Standard_WarningsDisable.hxx>
31 #include <QColorDialog>
32 #include <QCursor>
33 #include <QFileInfo>
34 #include <QMdiSubWindow>
35 #include <QMenu>
36 #include <QMessageBox>
37 #include <QMouseEvent>
38 #include <QPainter>
39 #include <QRubberBand>
40 #include <QStatusBar>
41 #include <QStyleFactory>
42 #include <Standard_WarningsRestore.hxx>
43
44 #include <stdio.h>
45
46 #ifdef _WIN32
47 #include <WNT_Window.hxx>
48 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
49 #include <Cocoa_Window.hxx>
50 #else
51 #include <Xw_Window.hxx>
52 #endif
53
54 // =======================================================================
55 // function :  Constructor
56 // purpose :
57 // =======================================================================
58 View_Widget::View_Widget (QWidget* theParent,
59                           const Handle(AIS_InteractiveContext)& theContext,
60                           const bool isFitAllActive)
61 : QWidget (theParent), myFirst (true), myDefaultWidth (-1),
62   myDefaultHeight (-1), myViewIsEnabled (true),
63   myHasInitProj (Standard_False), myInitVx (0), myInitVy (0), myInitVz (0)
64 {
65   myViewer = new View_Viewer (View_Viewer::DefaultColor());
66   if (!theContext.IsNull())
67   {
68     myViewer->InitViewer (theContext);
69   }
70   else
71   {
72     myViewer->InitViewer (myViewer->CreateStandardViewer());
73   }
74   myController = new AIS_ViewController();
75
76   setAttribute (Qt::WA_PaintOnScreen);
77   setAttribute (Qt::WA_NoSystemBackground);
78
79   setMouseTracking (true);
80   setBackgroundRole (QPalette::NoRole);
81   // set focus policy to threat QContextMenuEvent from keyboard  
82   setFocusPolicy (Qt::StrongFocus);
83
84   initViewActions();
85   ((View_ToolButton*)myFitAllAction)->SetButtonChecked (isFitAllActive);
86 }
87
88 // =======================================================================
89 // function : SetPredefinedSize
90 // purpose :
91 // =======================================================================
92 void View_Widget::SetPredefinedSize (int theDefaultWidth, int theDefaultHeight)
93 {
94   myDefaultWidth = theDefaultWidth;
95   myDefaultHeight = theDefaultHeight;
96 }
97
98 // =======================================================================
99 // function : Init
100 // purpose :
101 // =======================================================================
102 void View_Widget::Init()
103 {
104   myViewer->CreateView();
105
106 #ifdef _WIN32
107   Aspect_Handle aWindowHandle = (Aspect_Handle)winId();
108   Handle(Aspect_Window) aWnd = new WNT_Window (aWindowHandle);
109 #elif defined (__APPLE__) && !defined (MACOSX_USE_GLX)
110   NSView* aViewHandle = (NSView*)winId();
111   Handle(Aspect_Window) aWnd = new Cocoa_Window (aViewHandle);
112 #else
113   Window aWindowHandle = (Window)winId();
114   Handle(Aspect_DisplayConnection) aDispConnection = myViewer->GetContext()->CurrentViewer()->Driver()->GetDisplayConnection();
115   Handle(Aspect_Window) aWnd = new Xw_Window (aDispConnection, aWindowHandle);
116 #endif
117   myViewer->SetWindow (aWnd);
118
119   myViewer->GetView()->SetBackgroundColor (View_Viewer::DefaultColor());
120   myViewer->GetView()->MustBeResized();
121
122   if (myHasInitProj)
123     myViewer->GetView()->SetProj (myInitVx, myInitVy, myInitVz);
124 }
125
126 // =======================================================================
127 // function : DisplayMode
128 // purpose :
129 // =======================================================================
130 int View_Widget::DisplayMode() const
131 {
132   return myViewActions[View_ViewActionType_DisplayModeId]->isChecked() ? AIS_Shaded : AIS_WireFrame;
133 }
134
135 // =======================================================================
136 // function : SetDisplayMode
137 // purpose :
138 // =======================================================================
139 void View_Widget::SetDisplayMode (const int theMode)
140 {
141   myViewActions[View_ViewActionType_DisplayModeId]->setChecked ( theMode ? AIS_Shaded : AIS_WireFrame);
142 }
143
144 // =======================================================================
145 // function : paintEvent
146 // purpose :
147 // =======================================================================
148 void View_Widget::paintEvent (QPaintEvent* /*theEvent*/)
149 {
150 #if (QT_VERSION < 0x050000 || QT_VERSION >= 0x050700)
151   if (myFirst)
152   {
153     Init();
154     myFirst = false;
155   }
156 #endif
157
158   if (myViewer->GetView())
159     myViewer->GetView()->Redraw();
160 }
161
162 // =======================================================================
163 // function : resizeEvent
164 // purpose :
165 // =======================================================================
166 void View_Widget::resizeEvent (QResizeEvent* /*theEvent*/)
167 {
168 #if (QT_VERSION > 0x050000 && QT_VERSION < 0x050700)
169   if (myFirst)
170   {
171     Init();
172     myFirst = false;
173   }
174 #endif
175   if (myViewer->GetView())
176     myViewer->GetView()->MustBeResized();
177 }
178
179 // =======================================================================
180 // function : sizeHint
181 // purpose :
182 // =======================================================================
183 QSize View_Widget::sizeHint() const
184 {
185   if (myDefaultWidth > 0 && myDefaultHeight > 0)
186     return QSize (myDefaultWidth, myDefaultHeight);
187
188   return QWidget::sizeHint();
189 }
190
191 // =======================================================================
192 // function : SetEnabledView
193 // purpose :
194 // =======================================================================
195 void View_Widget::SetEnabledView (const bool theIsEnabled)
196 {
197   myViewIsEnabled = theIsEnabled;
198
199   if (myViewer->GetView())
200     myViewer->GetView()->SetBackgroundColor (theIsEnabled ? View_Viewer::DefaultColor()
201                                                           : View_Viewer::DisabledColor());
202   ViewAction (View_ViewActionType_DisplayModeId)->setEnabled (theIsEnabled);
203 }
204
205 // =======================================================================
206 // function : SaveState
207 // purpose :
208 // =======================================================================
209 void View_Widget::SaveState (View_Widget* theWidget,
210                              QMap<QString, QString>& theItems,
211                              const QString& thePrefix)
212 {
213   theItems[thePrefix + "fitall"] = theWidget->ViewAction (View_ViewActionType_FitAllId)->isChecked();
214   theItems[thePrefix + "dispmode"] = QString::number (theWidget->DisplayMode());
215 }
216
217 // =======================================================================
218 // function : RestoreState
219 // purpose :
220 // =======================================================================
221 bool View_Widget::RestoreState (View_Widget* theWidget,
222                                 const QString& theKey, const QString& theValue,
223                                 const QString& thePrefix)
224 {
225   if (theKey == thePrefix + "fitall")
226   {
227     theWidget->SetActionChecked (View_ViewActionType_FitAllId, theValue.toInt() > 0);
228   }
229   else if (theKey == thePrefix + "dispmode")
230   {
231     theWidget->SetDisplayMode (theValue.toInt());
232   }
233   else
234     return false;
235
236   return true;
237 }
238
239 // =======================================================================
240 // function : onCheckedStateChanged
241 // purpose :
242 // =======================================================================
243 void View_Widget::onCheckedStateChanged (bool isOn)
244 {
245   QWidget* aSentByAction = (QWidget*)sender();
246
247   if (aSentByAction == myFitAllAction)
248     emit checkedStateChanged(View_ViewActionType_FitAllId, isOn);
249 }
250
251 // =======================================================================
252 // function : initViewActions
253 // purpose :
254 // =======================================================================
255 void View_Widget::initViewActions()
256 {
257   if (!myViewActions.empty())
258     return;
259
260   myFitAllAction = new View_ToolButton (this); // action for automatic fit all
261   connect (myFitAllAction, SIGNAL (checkedStateChanged(bool)), this, SLOT (onCheckedStateChanged(bool)));
262   createAction (View_ViewActionType_FitAllId, ":/icons/view_fitall.png", tr ("Fit All"), SLOT (OnFitAll()));
263   myFitAllAction->setDefaultAction (ViewAction (View_ViewActionType_FitAllId));
264
265   createAction (View_ViewActionType_DisplayModeId, ":/icons/view_dm_shading.png", tr ("Display Mode"),
266                 SIGNAL (displayModeClicked()), true);
267 }
268
269 // =======================================================================
270 // function : mousePressEvent
271 // purpose :
272 // =======================================================================
273 void View_Widget::mousePressEvent (QMouseEvent* theEvent)
274 {
275   if (myController->PressMouseButton (Graphic3d_Vec2i (theEvent->x(), theEvent->y()),
276                                       keyMouse (theEvent->button()),
277                                       keyFlag (theEvent->modifiers()),
278                                       Standard_False))
279   {
280     myController->FlushViewEvents (myViewer->GetContext(), myViewer->GetView(), Standard_True);
281   }
282 }
283
284 // =======================================================================
285 // function : mouseReleaseEvent
286 // purpose :
287 // =======================================================================
288 void View_Widget::mouseReleaseEvent (QMouseEvent* theEvent)
289 {
290   if (myController->ReleaseMouseButton (Graphic3d_Vec2i (theEvent->x(), theEvent->y()),
291                                         keyMouse (theEvent->button()),
292                                         keyFlag (theEvent->modifiers()),
293                                         Standard_False))
294   {
295     myController->FlushViewEvents (myViewer->GetContext(), myViewer->GetView(), Standard_True);
296   }
297 }
298
299 // =======================================================================
300 // function : mouseMoveEvent
301 // purpose :
302 // =======================================================================
303 void View_Widget::mouseMoveEvent (QMouseEvent* theEvent)
304 {
305   myController->UpdateMousePosition (Graphic3d_Vec2i (theEvent->x(), theEvent->y()),
306                                      keyMouse (theEvent->button()),
307                                      keyFlag (theEvent->modifiers()), Standard_False);
308
309   myController->FlushViewEvents (myViewer->GetContext(), myViewer->GetView(), Standard_True);
310 }
311
312 // =======================================================================
313 // function : createAction
314 // purpose :
315 // =======================================================================
316 void View_Widget::createAction (const View_ViewActionType theActionId, const QString& theIcon, const QString& theText,
317                                 const char* theSlot, const bool isCheckable, const QString& theToolBar,
318                                 const QString& theStatusBar)
319 {
320   QAction* anAction = new QAction (QIcon (theIcon), theText, this);
321   anAction->setToolTip (!theToolBar.isEmpty() ? theToolBar : theText);
322   anAction->setStatusTip (!theStatusBar.isEmpty() ? theStatusBar : theText);
323   if (isCheckable)
324     anAction->setCheckable (true);
325   connect(anAction, SIGNAL (triggered()) , this, theSlot);
326   myViewActions[theActionId] = anAction;
327 }
328
329 // =======================================================================
330 // function : keyFlag
331 // purpose :
332 // =======================================================================
333 Aspect_VKeyFlags View_Widget::keyFlag (const int theModifierId)
334 {
335   switch (theModifierId)
336   {
337     case Qt::NoModifier:      return Aspect_VKeyFlags_NONE;
338     case Qt::ShiftModifier:   return Aspect_VKeyFlags_SHIFT;
339     case Qt::ControlModifier: return Aspect_VKeyFlags_CTRL;
340     default: break;
341   }
342   return Aspect_VKeyFlags_NONE;
343 }
344
345 // =======================================================================
346 // function : keyMouse
347 // purpose :
348 // =======================================================================
349 Aspect_VKeyMouse View_Widget::keyMouse (const int theButtonId)
350 {
351   switch (theButtonId)
352   {
353     case Qt::NoButton:    return Aspect_VKeyMouse_NONE;
354     case Qt::LeftButton:  return Aspect_VKeyMouse_LeftButton;
355     case Qt::RightButton: return Aspect_VKeyMouse_RightButton;
356     case Qt::MidButton:   return Aspect_VKeyMouse_MiddleButton;
357     default: break;
358   }
359   return Aspect_VKeyMouse_NONE;
360 }