PythonOcc: qtDisplay.py

File qtDisplay.py, 9.9 KB (added by mprotic, 5 years ago)
Line 
1#!/usr/bin/env python
2
3##Copyright 2009-2014 Thomas Paviot (tpaviot@gmail.com)
4##
5##This file is part of pythonOCC.
6##
7##pythonOCC is free software: you can redistribute it and/or modify
8##it under the terms of the GNU Lesser General Public License as published by
9##the Free Software Foundation, either version 3 of the License, or
10##(at your option) any later version.
11##
12##pythonOCC is distributed in the hope that it will be useful,
13##but WITHOUT ANY WARRANTY; without even the implied warranty of
14##MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15##GNU Lesser General Public License for more details.
16##
17##You should have received a copy of the GNU Lesser General Public License
18##along with pythonOCC.  If not, see <http://www.gnu.org/licenses/>.
19
20from __future__ import print_function
21
22import sys
23from OCC.Display import OCCViewer
24
25HAVE_PYQT4 = False
26HAVE_PYSIDE = False
27try:
28    from PyQt4 import QtCore, QtGui, QtOpenGL
29    HAVE_PYQT4 = True
30    print("Using PyQt4")
31except ImportError:
32    from PySide import QtCore, QtGui, QtOpenGL
33    HAVE_PYSIDE = True
34    print("PyQt4 not found - using PySide")
35
36
37def get_qt_modules():
38    return QtCore, QtGui, QtOpenGL
39
40
41class point(object):
42    def __init__(self, obj=None):
43        self.x = 0
44        self.y = 0
45        if obj is not None:
46            self.set(obj)
47
48    def set(self, obj):
49        self.x = obj.x()
50        self.y = obj.y()
51
52
53class qtBaseViewer(QtOpenGL.QGLWidget):
54    ''' The base Qt Widget for an OCC viewer
55    '''
56    def __init__(self, parent=None):
57        QtOpenGL.QGLWidget.__init__(self, parent)
58        self._display = None
59        self._inited = False
60
61        # enable Mouse Tracking
62        self.setMouseTracking(True)
63        # Strong focus
64        self.setFocusPolicy(QtCore.Qt.WheelFocus)
65
66        # required for overpainting the widget
67        self.setAttribute(QtCore.Qt.WA_PaintOnScreen)
68        self.setAttribute(QtCore.Qt.WA_NoSystemBackground)
69        self.setAutoFillBackground(False)
70
71    def GetHandle(self):
72        ''' returns an the identifier of the GUI widget.
73        It must be an integer
74        '''
75        win_id = self.winId()  ## this returns either an int or voitptr
76        if HAVE_PYSIDE:
77            ### with PySide, self.winId() does not return an integer
78            if sys.platform == "win32":
79                pycobject_hwnd = self.winId()
80                import ctypes
81                ctypes.pythonapi.PyCObject_AsVoidPtr.restype = ctypes.c_void_p
82                ctypes.pythonapi.PyCObject_AsVoidPtr.argtypes = [ctypes.py_object]
83                win_id = ctypes.pythonapi.PyCObject_AsVoidPtr(pycobject_hwnd)
84            else:
85                win_id = self.winId()
86        elif HAVE_PYQT4:
87            #win_id = self.winId()
88            ## below integer cast may be required because self.winId() can
89            ## returns a sip.voitptr according to the PyQt version used
90            ## as well as the python version
91            if type(win_id) is not int:  # cast to int using the int() funtion
92                win_id = int(win_id)
93        return win_id
94
95    def resizeEvent(self, event):
96        if self._inited:
97            self._display.OnResize()
98
99
100class qtViewer3d(qtBaseViewer):
101    def __init__(self, *kargs):
102        qtBaseViewer.__init__(self, *kargs)
103        self._drawbox = False
104        self._zoom_area = False
105        self._select_area = False
106        self._inited = False
107        self._leftisdown = False
108        self._middleisdown = False
109        self._rightisdown = False
110        self._selection = None
111        self._drawtext = True
112
113    def InitDriver(self):
114        self._display = OCCViewer.Viewer3d(self.GetHandle())
115        self._display.Create()
116        # background gradient
117        self._display.set_bg_gradient_color(206, 215, 222, 128, 128, 128)
118        # background gradient
119        self._display.display_trihedron()
120        self._display.SetModeShaded()
121        self._display.EnableAntiAliasing()
122        self._inited = True
123        # dict mapping keys to functions
124        self._SetupKeyMap()
125
126    def _SetupKeyMap(self):
127        def set_shade_mode():
128            self._display.DisableAntiAliasing()
129            self._display.SetModeShaded()
130
131        self._key_map = {ord('W'): self._display.SetModeWireFrame,
132                         ord('S'): set_shade_mode,
133                         ord('A'): self._display.EnableAntiAliasing,
134                         ord('B'): self._display.DisableAntiAliasing,
135                         ord('H'): self._display.SetModeHLR,
136                         ord('F'): self._display.FitAll,
137                         ord('G'): self._display.SetSelectionMode
138                         }
139
140    def keyPressEvent(self, event):
141        code = event.key()
142        if code in self._key_map:
143            self._key_map[code]()
144        else:
145            print('key', code, ' not mapped to any function')
146
147    def Test(self):
148        if self._inited:
149            self._display.Test()
150
151    def focusInEvent(self, event):
152        if self._inited:
153            self._display.Repaint()
154
155    def focusOutEvent(self, event):
156        if self._inited:
157            self._display.Repaint()
158
159    def paintEvent(self, event):
160        if self._inited:
161            self._display.Context.UpdateCurrentViewer()
162            # important to allow overpainting of the OCC OpenGL context in Qt
163            self.swapBuffers()
164
165        if self._drawbox:
166            self.makeCurrent()
167            painter = QtGui.QPainter(self)
168            painter.setPen(QtGui.QPen(QtGui.QColor(0, 0, 0), 1))
169            rect = QtCore.QRect(*self._drawbox)
170            painter.drawRect(rect)
171            painter.end()
172            self.doneCurrent()
173
174    def resizeGL(self, width, height):
175        self.setupViewport(width, height)
176
177    def ZoomAll(self, evt):
178        self._display.FitAll()
179
180    def wheelEvent(self, event):
181        if event.delta() > 0:
182            zoom_factor = 2
183        else:
184            zoom_factor = 0.5
185        self._display.Repaint()
186        self._display.ZoomFactor(zoom_factor)
187
188    def dragMoveEvent(self, event):
189        pass
190
191    def mousePressEvent(self, event):
192        self.setFocus()
193        self.dragStartPos = point(event.pos())
194        self._display.StartRotation(self.dragStartPos.x, self.dragStartPos.y)
195
196    def mouseReleaseEvent(self, event):
197        pt = point(event.pos())
198        modifiers = event.modifiers()
199
200        if event.button() == QtCore.Qt.LeftButton:
201            pt = point(event.pos())
202            if self._select_area:
203                [Xmin, Ymin, dx, dy] = self._drawbox
204                self._display.SelectArea(Xmin, Ymin, Xmin+dx, Ymin+dy)
205                self._select_area = False
206            else:
207                # multiple select if shift is pressed
208                if modifiers == QtCore.Qt.ShiftModifier:
209                    self._display.ShiftSelect(pt.x, pt.y)
210                else:
211                    # single select otherwise
212                    self._display.Select(pt.x, pt.y)
213        elif event.button() == QtCore.Qt.RightButton:
214            if self._zoom_area:
215                [Xmin, Ymin, dx, dy] = self._drawbox
216                self._display.ZoomArea(Xmin, Ymin, Xmin+dx, Ymin+dy)
217                self._zoom_area = False
218
219    def DrawBox(self, event):
220        tolerance = 2
221        pt = point(event.pos())
222        dx = pt.x - self.dragStartPos.x
223        dy = pt.y - self.dragStartPos.y
224        if abs(dx) <= tolerance and abs(dy) <= tolerance:
225            return
226        self._drawbox = [self.dragStartPos.x, self.dragStartPos.y, dx, dy]
227        self.update()
228
229    def mouseMoveEvent(self, evt):
230        pt = point(evt.pos())
231        buttons = int(evt.buttons())
232        modifiers = evt.modifiers()
233        # ROTATE
234        if (buttons == QtCore.Qt.LeftButton and not modifiers == QtCore.Qt.ShiftModifier):
235            dx = pt.x - self.dragStartPos.x
236            dy = pt.y - self.dragStartPos.y
237            self._display.Rotation(pt.x, pt.y)
238            self._drawbox = False
239        # DYNAMIC ZOOM
240        elif (buttons == QtCore.Qt.RightButton and not modifiers == QtCore.Qt.ShiftModifier):
241            self._display.Repaint()
242            self._display.DynamicZoom(abs(self.dragStartPos.x), abs(self.dragStartPos.y), abs(pt.x), abs(pt.y))
243            self.dragStartPos.x = pt.x
244            self.dragStartPos.y = pt.y
245            self._drawbox = False
246        # PAN
247        elif buttons == QtCore.Qt.MidButton:
248            dx = pt.x - self.dragStartPos.x
249            dy = pt.y - self.dragStartPos.y
250            self.dragStartPos.x = pt.x
251            self.dragStartPos.y = pt.y
252            self._display.Pan(dx, -dy)
253            self._drawbox = False
254        # DRAW BOX
255        # ZOOM WINDOW
256        elif (buttons == QtCore.Qt.RightButton and modifiers == QtCore.Qt.ShiftModifier):
257            self._zoom_area = True
258            self.DrawBox(evt)
259        # SELECT AREA
260        elif (buttons == QtCore.Qt.LeftButton and modifiers == QtCore.Qt.ShiftModifier):
261            self._select_area = True
262            self.DrawBox(evt)
263        else:
264            self._drawbox = False
265            self._display.MoveTo(pt.x, pt.y)
266
267
268def Test3d():
269    class AppFrame(QtGui.QWidget):
270        def __init__(self, parent=None):
271            QtGui.QWidget.__init__(self, parent)
272            self.setWindowTitle(self.tr("qtDisplay3d sample"))
273            self.resize(640, 480)
274            self.canva = qtViewer3d(self)
275            mainLayout = QtGui.QHBoxLayout()
276            mainLayout.addWidget(self.canva)
277            mainLayout.setContentsMargins(0, 0, 0, 0)
278            self.setLayout(mainLayout)
279
280        def runTests(self):
281            self.canva._display.Test()
282
283    app = QtGui.QApplication(sys.argv)
284    frame = AppFrame()
285    frame.show()
286    frame.canva.InitDriver()
287    frame.runTests()
288    sys.exit(app.exec_())
289
290if __name__ == "__main__":
291    Test3d()
292
293