0032308: Configuration - make Xlib dependency optional
[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(HAVE_XLIB)
49   #include <Xw_Window.hxx>
50 #elif defined(__APPLE__)
51   #include <Cocoa_Window.hxx>
52 #else
53
54 #endif
55
56 // =======================================================================
57 // function :  Constructor
58 // purpose :
59 // =======================================================================
60 View_Widget::View_Widget (QWidget* theParent,
61                           const Handle(AIS_InteractiveContext)& theContext,
62                           const bool isFitAllActive)
63 : QWidget (theParent), myFirst (true), myDefaultWidth (-1),
64   myDefaultHeight (-1), myViewIsEnabled (true),
65   myHasInitProj (Standard_False), myInitVx (0), myInitVy (0), myInitVz (0)
66 {
67   myViewer = new View_Viewer (View_Viewer::DefaultColor());
68   if (!theContext.IsNull())
69   {
70     myViewer->InitViewer (theContext);
71   }
72   else
73   {
74     myViewer->InitViewer (myViewer->CreateStandardViewer());
75   }
76   myController = new AIS_ViewController();
77
78   setAttribute (Qt::WA_PaintOnScreen);
79   setAttribute (Qt::WA_NoSystemBackground);
80
81   setMouseTracking (true);
82   setBackgroundRole (QPalette::NoRole);
83   // set focus policy to threat QContextMenuEvent from keyboard  
84   setFocusPolicy (Qt::StrongFocus);
85
86   initViewActions();
87   ((View_ToolButton*)myFitAllAction)->SetButtonChecked (isFitAllActive);
88 }
89
90 // =======================================================================
91 // function : SetPredefinedSize
92 // purpose :
93 // =======================================================================
94 void View_Widget::SetPredefinedSize (int theDefaultWidth, int theDefaultHeight)
95 {
96   myDefaultWidth = theDefaultWidth;
97   myDefaultHeight = theDefaultHeight;
98 }
99
100 // =======================================================================
101 // function : Init
102 // purpose :
103 // =======================================================================
104 void View_Widget::Init()
105 {
106   myViewer->CreateView();
107
108 #ifdef _WIN32
109   Aspect_Handle aWindowHandle = (Aspect_Handle)winId();
110   Handle(Aspect_Window) aWnd = new WNT_Window (aWindowHandle);
111 #elif defined (HAVE_XLIB)
112   Aspect_Drawable aWindowHandle = (Aspect_Drawable )winId();
113   Handle(Aspect_DisplayConnection) aDispConnection = myViewer->GetContext()->CurrentViewer()->Driver()->GetDisplayConnection();
114   Handle(Aspect_Window) aWnd = new Xw_Window (aDispConnection, aWindowHandle);
115 #elif defined (__APPLE__)
116   NSView* aViewHandle = (NSView*)winId();
117   Handle(Aspect_Window) aWnd = new Cocoa_Window (aViewHandle);
118 #else
119   //
120 #endif
121   myViewer->SetWindow (aWnd);
122
123   myViewer->GetView()->SetBackgroundColor (View_Viewer::DefaultColor());
124   myViewer->GetView()->MustBeResized();
125
126   if (myHasInitProj)
127     myViewer->GetView()->SetProj (myInitVx, myInitVy, myInitVz);
128 }
129
130 // =======================================================================
131 // function : DisplayMode
132 // purpose :
133 // =======================================================================
134 int View_Widget::DisplayMode() const
135 {
136   return myViewActions[View_ViewActionType_DisplayModeId]->isChecked() ? AIS_Shaded : AIS_WireFrame;
137 }
138
139 // =======================================================================
140 // function : SetDisplayMode
141 // purpose :
142 // =======================================================================
143 void View_Widget::SetDisplayMode (const int theMode)
144 {
145   myViewActions[View_ViewActionType_DisplayModeId]->setChecked ( theMode ? AIS_Shaded : AIS_WireFrame);
146 }
147
148 // =======================================================================
149 // function : paintEvent
150 // purpose :
151 // =======================================================================
152 void View_Widget::paintEvent (QPaintEvent* /*theEvent*/)
153 {
154 #if (QT_VERSION < 0x050000 || QT_VERSION >= 0x050700)
155   if (myFirst)
156   {
157     Init();
158     myFirst = false;
159   }
160 #endif
161
162   if (myViewer->GetView())
163     myViewer->GetView()->Redraw();
164 }
165
166 // =======================================================================
167 // function : resizeEvent
168 // purpose :
169 // =======================================================================
170 void View_Widget::resizeEvent (QResizeEvent* /*theEvent*/)
171 {
172 #if (QT_VERSION > 0x050000 && QT_VERSION < 0x050700)
173   if (myFirst)
174   {
175     Init();
176     myFirst = false;
177   }
178 #endif
179   if (myViewer->GetView())
180     myViewer->GetView()->MustBeResized();
181 }
182
183 // =======================================================================
184 // function : sizeHint
185 // purpose :
186 // =======================================================================
187 QSize View_Widget::sizeHint() const
188 {
189   if (myDefaultWidth > 0 && myDefaultHeight > 0)
190     return QSize (myDefaultWidth, myDefaultHeight);
191
192   return QWidget::sizeHint();
193 }
194
195 // =======================================================================
196 // function : SetEnabledView
197 // purpose :
198 // =======================================================================
199 void View_Widget::SetEnabledView (const bool theIsEnabled)
200 {
201   myViewIsEnabled = theIsEnabled;
202
203   if (myViewer->GetView())
204     myViewer->GetView()->SetBackgroundColor (theIsEnabled ? View_Viewer::DefaultColor()
205                                                           : View_Viewer::DisabledColor());
206   ViewAction (View_ViewActionType_DisplayModeId)->setEnabled (theIsEnabled);
207 }
208
209 // =======================================================================
210 // function : SaveState
211 // purpose :
212 // =======================================================================
213 void View_Widget::SaveState (View_Widget* theWidget,
214                              QMap<QString, QString>& theItems,
215                              const QString& thePrefix)
216 {
217   theItems[thePrefix + "fitall"] = theWidget->ViewAction (View_ViewActionType_FitAllId)->isChecked();
218   theItems[thePrefix + "dispmode"] = QString::number (theWidget->DisplayMode());
219 }
220
221 // =======================================================================
222 // function : RestoreState
223 // purpose :
224 // =======================================================================
225 bool View_Widget::RestoreState (View_Widget* theWidget,
226                                 const QString& theKey, const QString& theValue,
227                                 const QString& thePrefix)
228 {
229   if (theKey == thePrefix + "fitall")
230   {
231     theWidget->SetActionChecked (View_ViewActionType_FitAllId, theValue.toInt() > 0);
232   }
233   else if (theKey == thePrefix + "dispmode")
234   {
235     theWidget->SetDisplayMode (theValue.toInt());
236   }
237   else
238     return false;
239
240   return true;
241 }
242
243 // =======================================================================
244 // function : onCheckedStateChanged
245 // purpose :
246 // =======================================================================
247 void View_Widget::onCheckedStateChanged (bool isOn)
248 {
249   QWidget* aSentByAction = (QWidget*)sender();
250
251   if (aSentByAction == myFitAllAction)
252     emit checkedStateChanged(View_ViewActionType_FitAllId, isOn);
253 }
254
255 // =======================================================================
256 // function : initViewActions
257 // purpose :
258 // =======================================================================
259 void View_Widget::initViewActions()
260 {
261   if (!myViewActions.empty())
262     return;
263
264   myFitAllAction = new View_ToolButton (this); // action for automatic fit all
265   connect (myFitAllAction, SIGNAL (checkedStateChanged(bool)), this, SLOT (onCheckedStateChanged(bool)));
266   createAction (View_ViewActionType_FitAllId, ":/icons/view_fitall.png", tr ("Fit All"), SLOT (OnFitAll()));
267   myFitAllAction->setDefaultAction (ViewAction (View_ViewActionType_FitAllId));
268
269   createAction (View_ViewActionType_DisplayModeId, ":/icons/view_dm_shading.png", tr ("Display Mode"),
270                 SIGNAL (displayModeClicked()), true);
271 }
272
273 // =======================================================================
274 // function : mousePressEvent
275 // purpose :
276 // =======================================================================
277 void View_Widget::mousePressEvent (QMouseEvent* theEvent)
278 {
279   if (myController->PressMouseButton (Graphic3d_Vec2i (theEvent->x(), theEvent->y()),
280                                       keyMouse (theEvent->button()),
281                                       keyFlag (theEvent->modifiers()),
282                                       Standard_False))
283   {
284     myController->FlushViewEvents (myViewer->GetContext(), myViewer->GetView(), Standard_True);
285   }
286 }
287
288 // =======================================================================
289 // function : mouseReleaseEvent
290 // purpose :
291 // =======================================================================
292 void View_Widget::mouseReleaseEvent (QMouseEvent* theEvent)
293 {
294   if (myController->ReleaseMouseButton (Graphic3d_Vec2i (theEvent->x(), theEvent->y()),
295                                         keyMouse (theEvent->button()),
296                                         keyFlag (theEvent->modifiers()),
297                                         Standard_False))
298   {
299     myController->FlushViewEvents (myViewer->GetContext(), myViewer->GetView(), Standard_True);
300   }
301 }
302
303 // =======================================================================
304 // function : mouseMoveEvent
305 // purpose :
306 // =======================================================================
307 void View_Widget::mouseMoveEvent (QMouseEvent* theEvent)
308 {
309   myController->UpdateMousePosition (Graphic3d_Vec2i (theEvent->x(), theEvent->y()),
310                                      keyMouse (theEvent->button()),
311                                      keyFlag (theEvent->modifiers()), Standard_False);
312
313   myController->FlushViewEvents (myViewer->GetContext(), myViewer->GetView(), Standard_True);
314 }
315
316 // =======================================================================
317 // function : createAction
318 // purpose :
319 // =======================================================================
320 void View_Widget::createAction (const View_ViewActionType theActionId, const QString& theIcon, const QString& theText,
321                                 const char* theSlot, const bool isCheckable, const QString& theToolBar,
322                                 const QString& theStatusBar)
323 {
324   QAction* anAction = new QAction (QIcon (theIcon), theText, this);
325   anAction->setToolTip (!theToolBar.isEmpty() ? theToolBar : theText);
326   anAction->setStatusTip (!theStatusBar.isEmpty() ? theStatusBar : theText);
327   if (isCheckable)
328     anAction->setCheckable (true);
329   connect(anAction, SIGNAL (triggered()) , this, theSlot);
330   myViewActions[theActionId] = anAction;
331 }
332
333 // =======================================================================
334 // function : keyFlag
335 // purpose :
336 // =======================================================================
337 Aspect_VKeyFlags View_Widget::keyFlag (const int theModifierId)
338 {
339   switch (theModifierId)
340   {
341     case Qt::NoModifier:      return Aspect_VKeyFlags_NONE;
342     case Qt::ShiftModifier:   return Aspect_VKeyFlags_SHIFT;
343     case Qt::ControlModifier: return Aspect_VKeyFlags_CTRL;
344     default: break;
345   }
346   return Aspect_VKeyFlags_NONE;
347 }
348
349 // =======================================================================
350 // function : keyMouse
351 // purpose :
352 // =======================================================================
353 Aspect_VKeyMouse View_Widget::keyMouse (const int theButtonId)
354 {
355   switch (theButtonId)
356   {
357     case Qt::NoButton:    return Aspect_VKeyMouse_NONE;
358     case Qt::LeftButton:  return Aspect_VKeyMouse_LeftButton;
359     case Qt::RightButton: return Aspect_VKeyMouse_RightButton;
360     case Qt::MidButton:   return Aspect_VKeyMouse_MiddleButton;
361     default: break;
362   }
363   return Aspect_VKeyMouse_NONE;
364 }