def __init__(self, gui): super(JoystickButton, self).__init__() self.gui = gui # parent widget self.size = 360 # size in pixels of the push button self.state = None # a QPoint representing the position of the crosshair in pixels self.pan_limits = (0, 360) # width of the push button in pixels self.tilt_limits = (0, 360) # height of the push button in pixels self.setCheckable(True) # allow the push button to be 'checked' self.setFixedWidth(self.size) self.setFixedHeight(self.size) self.center = QPoint( self.size / 2.0, self.size / 2.0 ) # (0,0) in pixels start from the upper left corner of the push button, so set the center to the middle (QPoint type) self.current_pos = QPoint( self.size / 2.0, self.size / 2.0 ) # a QPoint representing the current position of the turret in pixels self.pan_deg_limits = [ self.gui.name_map["pan"]["min_lower_limit"], self.gui.name_map["pan"]["max_upper_limit"] ] # Pan joint limits in degrees self.tilt_deg_limits = [ self.gui.name_map["tilt"]["min_lower_limit"], self.gui.name_map["tilt"]["max_upper_limit"] ] # Tilt joint limits in degrees self.setJointCommands([ float(self.gui.name_map["pan"]["display"].text()), float(self.gui.name_map["tilt"]["display"].text()) ]) # set the default crosshair position to the current turret position
def transformPointToPixelCoordinates(pt, map, image_size): map_point_f = ((pt - QPointF(map.map.info.origin.position.x, map.map.info.origin.position.y)) * (1.0 / map.map.info.resolution)) map_point = QPoint(int(map_point_f.x()), int(map_point_f.y())) map_size = QSize(map.map.info.width, map.map.info.height) scaled_point = scalePoint(map_point, map_size, image_size) return QPoint(scaled_point.x(), image_size.height() - scaled_point.y() - 1)
def mousePressEvent(self, event): ''' Set the starting position for a drag event when the mouse button is pressed ''' self.drag_droped_pos = QPoint(0, 0) self.drag_initiated = False if event.button() == Qt.LeftButton: self.drag_start_pos = event.pos() QTabBar.mousePressEvent(self, event)
def dragEnterEvent(self, event): ''' Determine if the drag has entered a tab position from another tab position ''' self.drag_droped_pos = QPoint(0, 0) mime_data = event.mimeData() formats = mime_data.formats() if 'action' in formats and mime_data.data('action') == 'application/tab-detach': event.acceptProposedAction() QTabBar.dragMoveEvent(self, event)
def setJointStates(self, positions): new_pan = round( self.deg2Pxl(positions[0], self.pan_deg_limits[0], self.pan_deg_limits[1])) new_tilt = round(self.size - self.deg2Pxl( positions[1], self.tilt_deg_limits[0], self.tilt_deg_limits[1])) # Since this function is called at around 100 Hz, only update the QPushButton if the current position has significantly changed if (abs(new_pan - self.current_pos.x()) >= 1 or abs(new_tilt - self.current_pos.y()) >= 1): self.current_pos = QPoint(new_pan, new_tilt) self.update()
def __init__(self, parent=None): QTabBar.__init__(self, parent) self.setAcceptDrops(True) self.setElideMode(Qt.ElideRight) self.setSelectionBehaviorOnRemove(QTabBar.SelectLeftTab) self.drag_start_pos = QPoint() self.drag_droped_pos = QPoint() self.mouse_cursor = QCursor() self.drag_initiated = False
def __init__(self, parent=None): glformat = QGLFormat() glformat.setSampleBuffers(True) super(GLWidget, self).__init__(glformat, parent) self.setCursor(Qt.OpenHandCursor) self.setMouseTracking(True) self._modelview_matrix = numpy.identity(4) self._near = 0.001 self._far = 100000.0 self._fovy = 45.0 self._radius = 5.0 self._last_point_2d = QPoint() self._last_point_3d = [0.0, 0.0, 0.0] self._last_point_3d_ok = False
def paintEvent(self, event): geom = super(AxisWidget, self).geometry() h = geom.height() w = geom.width() box = QRect(2, 2, w - 4, h - 4) horiz = QLine(2, h / 2, w - 2, h / 2) vert = QLine(w / 2, 2, w / 2, h - 2) targ = QPoint(self._x * (w - 4) / 2 + w / 2, self._y * (h - 4) / 2 + h / 2) plt = super(AxisWidget, self).palette() linebrsh = plt.dark() targetbrsh = plt.highlight() linepen = QPen(linebrsh, 1, Qt.SolidLine, Qt.SquareCap) targetpen = QPen(targetbrsh, 2, Qt.SolidLine, Qt.SquareCap) qp = QPainter() qp.begin(self) qp.setPen(linepen) qp.drawRect(box) qp.drawLine(horiz) qp.drawLine(vert) qp.setPen(targetpen) qp.drawEllipse(targ, 10, 10) qp.end()
def paint(self, painter, option, index): ''' Use the QTextDokument to represent the HTML text. @see: U{http://www.pyside.org/docs/pyside/PySide/QtGui/QAbstractItemDelegate.html#PySide.QtGui.QAbstractItemDelegate} ''' options = QStyleOptionViewItem(option) self.initStyleOption(options, index) style = QApplication.style( ) if options.widget is None else options.widget.style() doc = QTextDocument() doc.setHtml(self.toHTML(options.text)) # doc.setTextWidth(option.rect.width()) options.text = '' style.drawControl(QStyle.CE_ItemViewItem, options, painter) ctx = QAbstractTextDocumentLayout.PaintContext() # Highlighting text if item is selected # if (optionV4.state and QStyle::State_Selected): # ctx.palette.setColor(QPalette::Text, optionV4.palette.color(QPalette::Active, QPalette::HighlightedText)); textRect = style.subElementRect(QStyle.SE_ItemViewItemText, options, options.widget) painter.save() painter.translate( QPoint(textRect.topLeft().x(), textRect.topLeft().y() - 3)) painter.setClipRect(textRect.translated(-textRect.topLeft())) doc.documentLayout().draw(painter, ctx) painter.restore()
def setJointCommands(self, commands): new_pan = round( self.deg2Pxl(commands[0], self.pan_deg_limits[0], self.pan_deg_limits[1])) new_tilt = round(self.size - self.deg2Pxl( commands[1], self.tilt_deg_limits[0], self.tilt_deg_limits[1])) self.setState(QPoint(new_pan, new_tilt)) self.update()
def __init__(self, parent=None): glformat = QGLFormat() glformat.setSampleBuffers(True) super(GLWidget, self).__init__(glformat, parent) self.setCursor(Qt.OpenHandCursor) self.setMouseTracking(True) self._modelview_matrix = numpy.identity(4) self._near = 0.1 self._far = 4000.0 self._fovy = 45.0 self._radius = 50.0 self._last_point_2d = QPoint() self._last_point_3d = [0.0, 0.0, 0.0] self._last_point_3d_ok = False
def readSettings(self): if nm.settings().store_geometry: settings = nm.settings().qsettings(nm.settings().CFG_GUI_FILE) settings.beginGroup("editor") maximized = settings.value("maximized", 'false') == 'true' if maximized: self.showMaximized() else: self.resize(settings.value("size", QSize(800, 640))) self.move(settings.value("pos", QPoint(0, 0))) try: self.restoreState(settings.value("window_state")) except: import traceback print traceback.format_exc() settings.endGroup()
def drawControl (self, element, opt, painter, widget=None): # print element if element == QStyle.CE_HeaderLabel: hv = widget # if not hv or hv.orientation() != Qt.Horizontal: # return super(StateHistoryDialog.MyStyle, self).drawControl(element, opt, p, widget) header = opt if header.section < 3: return super(StateHistoryDialog.MyStyle, self).drawControl(element, opt, painter, widget) painter.save() #// painter->translate(header->rect.topLeft()) rect = header.rect.bottomLeft() painter.translate(QPoint(rect.x() + 10, rect.y() + 5)) # print "drawControl" painter.rotate(-90) painter.drawText(0,0,header.text) painter.restore() return # return QProxyStyle::drawControl(element, option, painter, widget); # print "drawControl" return super(StateHistoryDialog.MyStyle, self).drawControl(element, opt, painter, widget)
def setState(self, ev): pnt = QPoint(ev.x(), ev.y()) # Since (0,0) is in the upper left corner, that means that increasingly negative Tilt values will be closer to the top of the push button; However, # However, it makes visual sense to flip this so that increasingly negative Tilt values are closer to the bottom of the push button; thus, the funky math... :) if (pnt.x() < self.pan_limits[0] or pnt.y() < (self.size - self.tilt_limits[1]) or pnt.x() > self.pan_limits[1] or pnt.y() > (self.size - self.tilt_limits[0])): return if self.state == pnt: return self.state = pnt self.update() if self.isChecked(): cmd_x = self.pxl2Deg(self.state.x(), self.pan_deg_limits[0], self.pan_deg_limits[1]) cmd_y = -self.pxl2Deg(self.state.y(), self.tilt_deg_limits[0], self.tilt_deg_limits[1]) self.gui.name_map["pan"]["display"].setText("%.1f" % cmd_x) self.gui.name_map["tilt"]["display"].setText("%.1f" % cmd_y) self.gui.update_slider_bar("pan") self.gui.update_slider_bar("tilt")
class GLWidget(QGLWidget): def __init__(self, parent=None): glformat = QGLFormat() glformat.setSampleBuffers(True) super(GLWidget, self).__init__(glformat, parent) self.setCursor(Qt.OpenHandCursor) self.setMouseTracking(True) self._modelview_matrix = numpy.identity(4) self._near = 0.1 self._far = 4000.0 self._fovy = 45.0 self._radius = 50.0 self._last_point_2d = QPoint() self._last_point_3d = [0.0, 0.0, 0.0] self._last_point_3d_ok = False def initializeGL(self): glClearColor(0.65, 0.65, 0.65, 0.0) glEnable(GL_DEPTH_TEST) def resizeGL(self, width, height): glViewport(0, 0, width, height) self.set_projection(self._near, self._far, self._fovy) self.updateGL() def paintGL(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glMatrixMode(GL_MODELVIEW) glLoadMatrixd(self._modelview_matrix) def get_view_matrix(self): return self._modelview_matrix.tolist() def set_view_matrix(self, matrix): self._modelview_matrix = numpy.array(matrix) def load_view_matrix(self,view_matrix): self.makeCurrent() glMatrixMode(GL_MODELVIEW) glLoadIdentity() glLoadMatrixd(view_matrix) self._modelview_matrix = glGetDoublev(GL_MODELVIEW_MATRIX) def set_projection(self, near, far, fovy): self._near = near self._far = far self._fovy = fovy self.makeCurrent() glMatrixMode(GL_PROJECTION) glLoadIdentity() height = max(self.height(), 1) gluPerspective(self._fovy, float(self.width()) / float(height), self._near, self._far) self.updateGL() def reset_view(self): # scene pos and size glMatrixMode(GL_MODELVIEW) glLoadIdentity() self._modelview_matrix = glGetDoublev(GL_MODELVIEW_MATRIX) self.view_all() def reset_rotation(self): self._modelview_matrix[0] = [1.0, 0.0, 0.0, 0.0] self._modelview_matrix[1] = [0.0, 1.0, 0.0, 0.0] self._modelview_matrix[2] = [0.0, 0.0, 1.0, 0.0] glMatrixMode(GL_MODELVIEW) glLoadMatrixd(self._modelview_matrix) def translate(self, trans): # translate the object self.makeCurrent() glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslated(trans[0], trans[1], trans[2]) glMultMatrixd(self._modelview_matrix) # update _modelview_matrix self._modelview_matrix = glGetDoublev(GL_MODELVIEW_MATRIX) def translate_absolute(self, trans): # translate the object self.makeCurrent() glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslated(trans[0], trans[1], trans[2]) self._modelview_matrix[3] = [0, 0, 0, self._modelview_matrix[3][3]] glMultMatrixd(self._modelview_matrix) # update _modelview_matrix self._modelview_matrix = glGetDoublev(GL_MODELVIEW_MATRIX) def rotate(self, axis, angle): # rotate the object self.makeCurrent() glMatrixMode(GL_MODELVIEW) glLoadIdentity() t = [self._modelview_matrix[3][0], self._modelview_matrix[3][1], self._modelview_matrix[3][2]] glTranslatef(t[0], t[1], t[2]) glRotated(angle, axis[0], axis[1], axis[2]) glTranslatef(-t[0], -t[1], -t[2]) glMultMatrixd(self._modelview_matrix) # update _modelview_matrix self._modelview_matrix = glGetDoublev(GL_MODELVIEW_MATRIX) def rotate_absolute(self,axis,angle): # rotate the object self.makeCurrent() glMatrixMode(GL_MODELVIEW) glLoadIdentity() t = [self._modelview_matrix[3][0], self._modelview_matrix[3][1], self._modelview_matrix[3][2]] glTranslatef(t[0], t[1], t[2]) glRotated(angle, axis[0], axis[1], axis[2]) glTranslatef(-t[0], -t[1], -t[2]) matrix = glGetDoublev(GL_MODELVIEW_MATRIX) matrix[3][0], matrix[3][1],matrix[3][2] = t glLoadMatrixd(matrix) # update _modelview_matrix self._modelview_matrix = glGetDoublev(GL_MODELVIEW_MATRIX) def view_all(self): self.translate([-self._modelview_matrix[0][3], -self._modelview_matrix[1][3], -self._modelview_matrix[2][3] - self._radius / 2.0]) def wheelEvent(self, event): # only zoom when no mouse buttons are pressed, to prevent interference with other user interactions if event.buttons() == Qt.NoButton: try: delta = event.angleDelta().y() except AttributeError: delta = event.delta() d = float(delta) / 200.0 * self._radius self.translate([0.0, 0.0, d]) self.updateGL() event.accept() def mousePressEvent(self, event): self._last_point_2d = event.pos() self._last_point_3d_ok, self._last_point_3d = self._map_to_sphere(self._last_point_2d) def mouseMoveEvent(self, event): new_point_2d = event.pos() if not self.rect().contains(new_point_2d): return new_point_3d_ok, new_point_3d = self._map_to_sphere(new_point_2d) dy = float(new_point_2d.y() - self._last_point_2d.y()) h = float(self.height()) # left button: move in x-y-direction if event.buttons() == Qt.LeftButton and event.modifiers() == Qt.NoModifier: dx = float(new_point_2d.x() - self._last_point_2d.x()) w = float(self.width()) z = -self._modelview_matrix[3][2] / self._modelview_matrix[3][3] n = 0.01 * self._radius up = math.tan(self._fovy / 2.0 * math.pi / 180.0) * n right = up * w / h self.translate([2.0 * dx / w * right / n * z, -2.0 * dy / h * up / n * z, 0.0]) # left and middle button (or left + ctrl): rotate around center elif event.buttons() == (Qt.LeftButton | Qt.MidButton) or (event.buttons() == Qt.LeftButton and event.modifiers() == Qt.ControlModifier): if self._last_point_3d_ok and new_point_3d_ok: cos_angle = numpy.dot(self._last_point_3d, new_point_3d) if abs(cos_angle) < 1.0: axis = numpy.cross(self._last_point_3d, new_point_3d) angle = 2.0 * math.acos(cos_angle) * 180.0 / math.pi self.rotate(axis, angle) # middle button (or left + shift): move in z-direction elif event.buttons() == Qt.MidButton or (event.buttons() == Qt.LeftButton and event.modifiers() == Qt.ShiftModifier): delta_z = self._radius * dy * 20.0 / h self.translate([0.0, 0.0, delta_z]) # remember the new points and flag self._last_point_2d = new_point_2d self._last_point_3d = new_point_3d self._last_point_3d_ok = new_point_3d_ok # trigger redraw self.updateGL() def mouseReleaseEvent(self, _event): self._last_point_3d_ok = False def _map_to_sphere(self, pos): v = [0.0, 0.0, 0.0] # check if inside widget if self.rect().contains(pos): # map widget coordinates to the centered unit square [-0.5..0.5] x [-0.5..0.5] v[0] = float(pos.x() - 0.5 * self.width()) / self.width() v[1] = float(0.5 * self.height() - pos.y()) / self.height() # use Pythagoras to compute z (the sphere has radius sqrt(2.0*0.5*0.5)) v[2] = math.sqrt(max(0.5 - v[0] * v[0] - v[1] * v[1], 0.0)) # normalize direction to unit sphere v = numpy.array(v) / numpy.linalg.norm(v) return True, v else: return False, v def unproject_mouse_on_scene(self,pos): start_x, start_y, start_z = gluUnProject(pos.x(), pos.y(), 1, model=self._modelview_matrix, proj=glGetDoublev(GL_PROJECTION_MATRIX)) end_x, end_y, end_z = gluUnProject(pos.x(), pos.y(), 0, model=self._modelview_matrix, proj=glGetDoublev(GL_PROJECTION_MATRIX)) diff_x = end_x - start_x diff_y = end_y - start_y diff_z = end_z - start_z t = (0 - start_z) / diff_z x = start_x + (diff_x * t) y = start_y + (diff_y * t) return x, y,0
def get_rectangular_polygon(self, pt1, pt2): return QPolygon( [pt1, QPoint(pt1.x(), pt2.y()), pt2, QPoint(pt2.x(), pt1.y())])
class JoystickButton(QPushButton): ### @brief Initialization of the JoystickButton class; it builds up from a QPushButton ### @param gui - the parent widget ### @details - code inspired from the JoystickButton class created in 'pyqtgraph' def __init__(self, gui): super(JoystickButton, self).__init__() self.gui = gui # parent widget self.size = 360 # size in pixels of the push button self.state = None # a QPoint representing the position of the crosshair in pixels self.pan_limits = (0, 360) # width of the push button in pixels self.tilt_limits = (0, 360) # height of the push button in pixels self.setCheckable(True) # allow the push button to be 'checked' self.setFixedWidth(self.size) self.setFixedHeight(self.size) self.center = QPoint( self.size / 2.0, self.size / 2.0 ) # (0,0) in pixels start from the upper left corner of the push button, so set the center to the middle (QPoint type) self.current_pos = QPoint( self.size / 2.0, self.size / 2.0 ) # a QPoint representing the current position of the turret in pixels self.pan_deg_limits = [ self.gui.name_map["pan"]["min_lower_limit"], self.gui.name_map["pan"]["max_upper_limit"] ] # Pan joint limits in degrees self.tilt_deg_limits = [ self.gui.name_map["tilt"]["min_lower_limit"], self.gui.name_map["tilt"]["max_upper_limit"] ] # Tilt joint limits in degrees self.setJointCommands([ float(self.gui.name_map["pan"]["display"].text()), float(self.gui.name_map["tilt"]["display"].text()) ]) # set the default crosshair position to the current turret position ### @brief Returns whether the joystick button is currently pressed ### @param <boolean> [out] - current button state def isActive(self): if self.isChecked(): return True else: return False ### @brief Redefines what happens when the Joystick button is pressed ### @param ev - QMouseEvent def mousePressEvent(self, ev): ev.accept() self.setChecked(True) self.setState(ev) ### @brief Redefines what happens when the mouse is moved ### @param ev - QMouseEvent def mouseMoveEvent(self, ev): ev.accept() self.setState(ev) ### @brief Redefines what happens when the mouse is released ### @param ev - QMouseEvent def mouseReleaseEvent(self, ev): ev.accept() self.setChecked(False) ### @brief Draws a circle in the QPushButton ### @param pnt - QPoint specifying where the circle should be drawn ### @param color - QColor specifying the circle color ### @param fill - whether the inside of the circle should be colored def drawCircle(self, pnt, color, fill=True): p = QPainter(self) p.setPen(color) if (fill): p.setBrush(QBrush(color)) p.drawEllipse(pnt, 3, 3) ### @brief Draws a crosshair centered at the specified point ### @param pnt - QPoint specifying the point at which to draw the crosshair def drawCrosshair(self, pnt): p = QPainter(self) horz_line = QLine(0, pnt.y(), self.size, pnt.y()) vert_line = QLine(pnt.x(), 0, pnt.x(), self.size) p.drawLines(horz_line, vert_line) ### @brief Draws a green rectangle showing the valid positions that the pan and tilt motors can be commanded def drawRect(self): p = QPainter(self) in_bounds = QRect(self.pan_limits[0], self.size - self.tilt_limits[1], self.pan_limits[1] - self.pan_limits[0], self.tilt_limits[1] - self.tilt_limits[0]) p.fillRect(in_bounds, QColor(0, 200, 0, 128)) p.drawRect(in_bounds) ### @brief Redefines a paint event (essentially what is drawn on the QPushButton) ### @param ev - QPaintEvent def paintEvent(self, ev): QPushButton.paintEvent(self, ev) self.drawRect() self.drawCircle(self.state, QColor(0, 0, 0), False) self.drawCircle(self.center, QColor(0, 0, 0)) self.drawCircle(self.current_pos, QColor(255, 0, 0)) self.drawCrosshair(self.state) ### @brief Converts from degrees to pixels ### @param value - values in degrees to convert to pixels ### @param min_lower_limit - absolute minimum angle that the motor can reach in degrees ### @param max_upper_limit - absolute maximum angle that the motor can reach in degrees ### @param new_val - value converted to pixels def deg2Pxl(self, value, min_lower_limit, max_upper_limit): degree_span = max_upper_limit - min_lower_limit value_scaled = float(value - min_lower_limit) / degree_span new_val = value_scaled * self.size return new_val ### @brief Converts from pixels to degrees ### @param value - values in pixels to convert to degrees ### @param min_lower_limit - absolute minimum angle that the motor can reach in degrees ### @param max_upper_limit - absolute maximum angle that the motor can reach in degrees ### @param new_val - value converted to degrees def pxl2Deg(self, value, min_lower_limit, max_upper_limit): value_scaled = float(value) / self.size new_val = min_lower_limit + value_scaled * (max_upper_limit - min_lower_limit) return new_val ### @brief Sets the state of the crosshair in pixels ### @param ev - QMouseEvent containing the position of the cursor in pixels ### @details - checks to make sure that the desired crosshair position is within the pan and tilt limits before setting it; it ### also converts the cursor position from pixels to degrees and updates the parent widget's slider bars accordingly def setState(self, ev): pnt = QPoint(ev.x(), ev.y()) # Since (0,0) is in the upper left corner, that means that increasingly negative Tilt values will be closer to the top of the push button; However, # However, it makes visual sense to flip this so that increasingly negative Tilt values are closer to the bottom of the push button; thus, the funky math... :) if (pnt.x() < self.pan_limits[0] or pnt.y() < (self.size - self.tilt_limits[1]) or pnt.x() > self.pan_limits[1] or pnt.y() > (self.size - self.tilt_limits[0])): return if self.state == pnt: return self.state = pnt self.update() if self.isChecked(): cmd_x = self.pxl2Deg(self.state.x(), self.pan_deg_limits[0], self.pan_deg_limits[1]) cmd_y = -self.pxl2Deg(self.state.y(), self.tilt_deg_limits[0], self.tilt_deg_limits[1]) self.gui.name_map["pan"]["display"].setText("%.1f" % cmd_x) self.gui.name_map["tilt"]["display"].setText("%.1f" % cmd_y) self.gui.update_slider_bar("pan") self.gui.update_slider_bar("tilt") ### @brief If the user changes the default Pan min/max values, this function converts the values from degrees to pixels ### @param min_value - new lower limit in degrees ### @param max_value - new upper limit in degrees def setPanMinMax(self, min_value, max_value): new_min = round( self.deg2Pxl(min_value, self.pan_deg_limits[0], self.pan_deg_limits[1])) new_max = round( self.deg2Pxl(max_value, self.pan_deg_limits[0], self.pan_deg_limits[1])) self.pan_limits = (new_min, new_max) self.update() ### @brief If the user changes the default Tilt min/max values, this function converts the values from degrees to pixels ### @param min_value - new lower limit in degrees ### @param max_value - new upper limit in degrees def setTiltMinMax(self, min_value, max_value): new_min = round( self.deg2Pxl(min_value, self.tilt_deg_limits[0], self.tilt_deg_limits[1])) new_max = round( self.deg2Pxl(max_value, self.tilt_deg_limits[0], self.tilt_deg_limits[1])) self.tilt_limits = (new_min, new_max) self.update() ### @brief Converts the current joint positions from degrees to pixels ### @param positions - list containing the pan and tilt values in degrees def setJointStates(self, positions): new_pan = round( self.deg2Pxl(positions[0], self.pan_deg_limits[0], self.pan_deg_limits[1])) new_tilt = round(self.size - self.deg2Pxl( positions[1], self.tilt_deg_limits[0], self.tilt_deg_limits[1])) # Since this function is called at around 100 Hz, only update the QPushButton if the current position has significantly changed if (abs(new_pan - self.current_pos.x()) >= 1 or abs(new_tilt - self.current_pos.y()) >= 1): self.current_pos = QPoint(new_pan, new_tilt) self.update() ### @brief Converts the current joint commands from degrees to pixels ### @param commands - list containing the pan and tilt values in degrees def setJointCommands(self, commands): new_pan = round( self.deg2Pxl(commands[0], self.pan_deg_limits[0], self.pan_deg_limits[1])) new_tilt = round(self.size - self.deg2Pxl( commands[1], self.tilt_deg_limits[0], self.tilt_deg_limits[1])) self.setState(QPoint(new_pan, new_tilt)) self.update()
def _event(self, e): if e.type() == QEvent.MouseButtonPress and e.button() == Qt.LeftButton: qDebug('%spress, rel=%s, global=%s, diff=%s' % ( (' - pseudo ' if self._releasing_and_repressing_while_dragging else ''), e.pos(), e.globalPos(), e.globalPos() - self.pos())) if e.type() == QEvent.MouseButtonRelease and e.button( ) == Qt.LeftButton: qDebug('%srelease, rel=%s, global=%s, diff=%s' % ( (' - pseudo ' if self._releasing_and_repressing_while_dragging else ''), e.pos(), e.globalPos(), e.globalPos() - self.pos())) # store local position when pressing button before starting the custom drag'n'drop # only allow when layout is not frozen if self._dragging_parent is None and e.type( ) == QEvent.MouseButtonPress and e.button() == Qt.LeftButton and bool( self.features() & QDockWidget.DockWidgetMovable): self._dragging_local_pos = e.pos() if self._dragging_parent is None and self._dragging_local_pos is not None and e.type( ) == QEvent.Move and QApplication.mouseButtons() & Qt.LeftButton: if self._widget_at(e.pos()) is not None: qDebug( 'DockWidget._event() start drag, dockwidget=%s, parent=%s, floating=%s, pos=%s' % (str(self), str(self.parent()), str( self.isFloating()), str(self._dragging_local_pos))) self._dragging_parent = self.parent() # ignore further mouse events so that the widget behind this dock widget can be determined self.setAttribute(Qt.WA_TransparentForMouseEvents) # collect all main windows (except self.main_window) to re-implement QApplication.widgetAt() in self._widget_at() self._main_windows = [ self._container_manager.get_root_main_window() ] for container in self._container_manager.get_containers(): if container == self: continue self._main_windows.append(container.main_window) # unset local position when releasing button even when custom drag'n'drop has not been started if self._dragging_local_pos is not None and e.type( ) == QEvent.MouseButtonRelease and e.button( ) == Qt.LeftButton and not self._releasing_and_repressing_while_dragging: self._dragging_local_pos = None if self._dragging_parent is not None and e.type( ) == QEvent.MouseButtonRelease and e.button( ) == Qt.LeftButton and not self._releasing_and_repressing_while_dragging: qDebug( 'DockWidget._event() stop drag, dockwidget=%s, parent=%s\n' % (self, self.parent())) self._dragging_parent = None self.setAttribute(Qt.WA_TransparentForMouseEvents, False) self._main_windows = [] if self._dragging_parent is not None and e.type( ) == QEvent.MouseMove and e.buttons( ) & Qt.LeftButton and not self._releasing_and_repressing_while_dragging: widget = self._widget_at(e.globalPos()) new_parent = self._get_new_parent(widget) #print 'new_parent', new_parent, (new_parent.objectName() if new_parent else '') if new_parent is not None and new_parent != self.parent(): self._releasing_and_repressing_while_dragging = True # schedule stop of pseudo drag'n'drop and let it complete mouse_release_event = QMouseEvent(QEvent.MouseButtonRelease, self._dragging_local_pos, e.globalPos(), Qt.LeftButton, Qt.NoButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_release_event) QApplication.sendPostedEvents() # schedule reparent to hovered main window and let it complete reparent_event = ReparentEvent(self, new_parent) QApplication.instance().postEvent(self._container_manager, reparent_event) QApplication.sendPostedEvents() # reenable mouse events to be able to receive upcoming pseudo mouse events self.setAttribute(Qt.WA_TransparentForMouseEvents, False) # schedule restart of pseudo drag'n'drop and let it complete mouse_repress_event = QMouseEvent(QEvent.MouseButtonPress, self._dragging_local_pos, e.globalPos(), Qt.LeftButton, Qt.LeftButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_repress_event) QApplication.sendPostedEvents() # schedule move to trigger dock widget drag'n'drop required for snapping and showing rubber band and let it complete # move forth... mouse_move_event = QMouseEvent( QEvent.MouseMove, self._dragging_local_pos, e.globalPos() + QPoint(QApplication.startDragDistance(), 1), Qt.NoButton, Qt.LeftButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_move_event) QApplication.sendPostedEvents() # ...and back mouse_move_event = QMouseEvent(QEvent.MouseMove, self._dragging_local_pos, e.globalPos(), Qt.NoButton, Qt.LeftButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_move_event) QApplication.sendPostedEvents() # restore attributes after repressing the button self.setAttribute(Qt.WA_TransparentForMouseEvents) self._releasing_and_repressing_while_dragging = False return super(DockWidget, self).event(e)
def transformPointToRealWorldCoordinates(pt, map, image_size): map_size = QSize(map.map.info.width, map.map.info.height) vertically_flipped_point = QPoint(pt.x(), image_size.height() - pt.y() - 1) map_point = scalePoint(vertically_flipped_point, image_size, map_size) return QPointF(map.map.info.origin.position.x, map.map.info.origin.position.y) + \ QPointF(map_point) * map.map.info.resolution
class GLWidget(QGLWidget): def __init__(self, parent=None): glformat = QGLFormat() glformat.setSampleBuffers(True) super(GLWidget, self).__init__(glformat, parent) self.setCursor(Qt.OpenHandCursor) self.setMouseTracking(True) self._modelview_matrix = numpy.identity(4) self._near = 0.001 self._far = 100000.0 self._fovy = 45.0 self._radius = 5.0 self._last_point_2d = QPoint() self._last_point_3d = [0.0, 0.0, 0.0] self._last_point_3d_ok = False ## ============================================ ## callbacks for QGLWidget def initializeGL(self): glClearColor(1.0, 0.0, 0.0, 0.0) glEnable(GL_DEPTH_TEST) def resizeGL(self, width, height): glViewport(0, 0, width, height) self.set_projection(self._near, self._far, self._fovy) self.updateGL() def paintGL(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glMatrixMode(GL_MODELVIEW) glLoadMatrixd(self._modelview_matrix) def get_view_matrix(self): return self._modelview_matrix.tolist() def set_view_matrix(self, matrix): self._modelview_matrix = numpy.array(matrix) def set_projection(self, near, far, fovy): self._near = near self._far = far self._fovy = fovy self.makeCurrent() glMatrixMode(GL_PROJECTION) glLoadIdentity() height = max(self.height(), 1) gluPerspective(self._fovy, float(self.width()) / float(height), self._near, self._far) self.updateGL() def reset_view(self): # scene pos and size glMatrixMode(GL_MODELVIEW) glLoadIdentity() self._modelview_matrix = glGetDoublev(GL_MODELVIEW_MATRIX) self.view_all() def reset_rotation(self): self._modelview_matrix[0] = [1.0, 0.0, 0.0, 0.0] self._modelview_matrix[1] = [0.0, 1.0, 0.0, 0.0] self._modelview_matrix[2] = [0.0, 0.0, 1.0, 0.0] glMatrixMode(GL_MODELVIEW) glLoadMatrixd(self._modelview_matrix) def translate(self, trans): # translate the object self.makeCurrent() glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslated(trans[0], trans[1], trans[2]) glMultMatrixd(self._modelview_matrix) # update _modelview_matrix self._modelview_matrix = glGetDoublev(GL_MODELVIEW_MATRIX) def rotate(self, axis, angle): # rotate the object self.makeCurrent() glMatrixMode(GL_MODELVIEW) glLoadIdentity() t = [ self._modelview_matrix[3][0], self._modelview_matrix[3][1], self._modelview_matrix[3][2] ] glTranslatef(t[0], t[1], t[2]) glRotated(angle, axis[0], axis[1], axis[2]) glTranslatef(-t[0], -t[1], -t[2]) glMultMatrixd(self._modelview_matrix) # update _modelview_matrix self._modelview_matrix = glGetDoublev(GL_MODELVIEW_MATRIX) def view_all(self): self.translate([ -self._modelview_matrix[0][3], -self._modelview_matrix[1][3], -self._modelview_matrix[2][3] - self._radius / 2.0 ]) ## ============================================ ## Qt's event(?) def wheelEvent(self, event): # only zoom when no mouse buttons are pressed, to prevent interference with other user interactions if event.buttons() == Qt.NoButton: d = float(event.delta()) / 200.0 * self._radius self.translate([0.0, 0.0, d]) self.updateGL() event.accept() def mousePressEvent(self, event): self._last_point_2d = event.pos() self._last_point_3d_ok, self._last_point_3d = self._map_to_sphere( self._last_point_2d) def mouseMoveEvent(self, event): new_point_2d = event.pos() if not self.rect().contains(new_point_2d): return new_point_3d_ok, new_point_3d = self._map_to_sphere(new_point_2d) dy = float(new_point_2d.y() - self._last_point_2d.y()) h = float(self.height()) # left button: rotate around center if event.buttons() == Qt.LeftButton and event.modifiers( ) == Qt.NoModifier: if self._last_point_3d_ok and new_point_3d_ok: cos_angle = numpy.dot(self._last_point_3d, new_point_3d) if abs(cos_angle) < 1.0: axis = numpy.cross(self._last_point_3d, new_point_3d) angle = 2.0 * math.acos(cos_angle) * 180.0 / math.pi self.rotate(axis, angle) # middle button (or left + shift): move in x-y-direction elif event.buttons() == Qt.MidButton or ( event.buttons() == Qt.LeftButton and event.modifiers() == Qt.ShiftModifier): dx = float(new_point_2d.x() - self._last_point_2d.x()) w = float(self.width()) z = -self._modelview_matrix[3][2] / self._modelview_matrix[3][3] n = 0.01 * self._radius up = math.tan(self._fovy / 2.0 * math.pi / 180.0) * n right = up * w / h self.translate([ 2.0 * dx / w * right / n * z, -2.0 * dy / h * up / n * z, 0.0 ]) # left and middle button (or left + ctrl): move in z-direction elif event.buttons() == (Qt.LeftButton | Qt.MidButton) or ( event.buttons() == Qt.LeftButton and event.modifiers() == Qt.ControlModifier): delta_z = self._radius * dy * 2.0 / h self.translate([0.0, 0.0, delta_z]) # remember the new points and flag self._last_point_2d = new_point_2d self._last_point_3d = new_point_3d self._last_point_3d_ok = new_point_3d_ok # trigger redraw self.updateGL() def mouseReleaseEvent(self, _event): self._last_point_3d_ok = False def _map_to_sphere(self, pos): v = [0.0, 0.0, 0.0] # check if inside widget if self.rect().contains(pos): # map widget coordinates to the centered unit square [-0.5..0.5] x [-0.5..0.5] v[0] = float(pos.x() - 0.5 * self.width()) / self.width() v[1] = float(0.5 * self.height() - pos.y()) / self.height() # use Pythagoras to compute z (the sphere has radius sqrt(2.0*0.5*0.5)) v[2] = math.sqrt(max(0.5 - v[0] * v[0] - v[1] * v[1], 0.0)) # normalize direction to unit sphere v = numpy.array(v) / numpy.linalg.norm(v) return True, v else: return False, v def get_texture(self, qimage): return self.bindTexture(qimage)
def __init__(self, items=list(), buttons=QDialogButtonBox.Cancel | QDialogButtonBox.Ok, exclusive=False, preselect_all=False, title='', description='', icon='', parent=None, select_if_single=True, checkitem1='', checkitem2='', closein=0, store_geometry=''): ''' Creates an input dialog. @param items: a list with strings @type items: C{list()} ''' QDialog.__init__(self, parent=parent) self.setObjectName(' - '.join(['SelectDialog', utf8(items)])) self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setContentsMargins(3, 3, 3, 3) # add filter row self.filter_field = EnhancedLineEdit(self) self.filter_field.setPlaceholderText("filter") self.filter_field.textChanged.connect(self._on_filter_changed) self.verticalLayout.addWidget(self.filter_field) if description: self.description_frame = QFrame(self) descriptionLayout = QHBoxLayout(self.description_frame) # descriptionLayout.setContentsMargins(1, 1, 1, 1) if icon: self.icon_label = QLabel(self.description_frame) self.icon_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.icon_label.setPixmap( QPixmap(icon).scaled(30, 30, Qt.KeepAspectRatio)) descriptionLayout.addWidget(self.icon_label) self.description_label = QLabel(self.description_frame) self.description_label.setWordWrap(True) self.description_label.setText(description) descriptionLayout.addWidget(self.description_label) self.verticalLayout.addWidget(self.description_frame) # create area for the parameter self.content = MainBox(self) if items: self.scroll_area = QScrollArea(self) self.scroll_area.setFocusPolicy(Qt.NoFocus) self.scroll_area.setObjectName("scroll_area") self.scroll_area.setWidgetResizable(True) self.scroll_area.setWidget(self.content) self.verticalLayout.addWidget(self.scroll_area) self.checkitem1 = checkitem1 self.checkitem1_result = False self.checkitem2 = checkitem2 self.checkitem2_result = False # add select all option if not exclusive and items: self._ignore_next_toggle = False self.select_all_checkbox = QCheckBox('all entries') self.select_all_checkbox.setTristate(True) self.select_all_checkbox.stateChanged.connect( self._on_select_all_checkbox_stateChanged) self.verticalLayout.addWidget(self.select_all_checkbox) self.content.toggled.connect(self._on_main_toggle) if self.checkitem1: self.checkitem1_checkbox = QCheckBox(self.checkitem1) self.checkitem1_checkbox.stateChanged.connect( self._on_select_checkitem1_checkbox_stateChanged) self.verticalLayout.addWidget(self.checkitem1_checkbox) if self.checkitem2: self.checkitem2_checkbox = QCheckBox(self.checkitem2) self.checkitem2_checkbox.stateChanged.connect( self._on_select_checkitem2_checkbox_stateChanged) self.verticalLayout.addWidget(self.checkitem2_checkbox) if not items: spacerItem = QSpacerItem(1, 1, QSizePolicy.Expanding, QSizePolicy.Expanding) self.verticalLayout.addItem(spacerItem) self._close_timer = None self._closein = closein - 1 if closein > 0: self.closein_label = QLabel("OK in %d sec..." % closein) self.closein_label.setAlignment(Qt.AlignRight) self.verticalLayout.addWidget(self.closein_label) self._close_timer = threading.Timer(1.0, self._on_close_timer) self._close_timer.start() # create buttons self.buttonBox = QDialogButtonBox(self) self.buttonBox.setObjectName("buttonBox") self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(buttons) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.verticalLayout.addWidget(self.buttonBox) # set the input fields if items: self.content.createFieldsFromValues(items, exclusive) if (select_if_single and len(items) == 1) or preselect_all: self.select_all_checkbox.setCheckState(Qt.Checked) if not items or len(items) < 7: self.filter_field.setVisible(False) # restore from configuration file self._geometry_name = store_geometry if store_geometry and nm.settings().store_geometry: settings = nm.settings().qsettings(nm.settings().CFG_GUI_FILE) settings.beginGroup(store_geometry) self.resize(settings.value("size", QSize(480, 320))) pos = settings.value("pos", QPoint(0, 0)) if pos.x() != 0 and pos.y() != 0: self.move(pos) settings.endGroup()
class my_widget(QWidget): mouse_is_pressed = False cursor_pos = QPoint(0,0) cur_nradius = 0 #normalized radius cur_sector = 0 def __init__ (self,*args): QWidget. __init__ (self,*args) def paintEvent(self,event=None): #global mouse_is_pressed w_height = self.frameGeometry().height() w_width = self.frameGeometry().width() if w_height > w_width: diam = w_width else: diam = w_height radius = int(diam / 2) - 10 start_x = w_width/2 - radius start_y = w_height/2 - radius line1_x1 = w_width/2 + radius*0.707 line1_x2 = w_width/2 - radius*0.707 line1_y1 = w_height/2 - radius*0.707 line1_y2 = w_height/2 + radius*0.707 line2_x1 = w_width/2 - radius*0.707 line2_x2 = w_width/2 + radius*0.707 line2_y1 = line1_y1 line2_y2 = line1_y2 painter=QPainter() painter.begin(self) painter.setPen(QPen(Qt.black)) painter.drawLine(line1_x1, line1_y1, line1_x2, line1_y2) #cross painter.drawLine(line2_x1, line2_y1, line2_x2, line2_y2) painter.drawEllipse(start_x,start_y , (radius*2), (radius*2)) if self.mouse_is_pressed == True: painter.setBrush(Qt.blue) rad = self.get_radius(w_width, w_height, self.cursor_pos) pos = self.get_pos(w_width, w_height, self.cursor_pos) if (radius < rad): rad = radius self.draw_arc(painter, w_width, w_height, pos, rad) self.cur_nradius = rad*1.0/radius self.cur_sector = pos else: self.cur_nradius = 0.0 self.cur_sector = 0.0 painter.end() #print self.mouse_is_pressed pass #get direction of mouse point def get_pos(self, w_width, w_height, cursor_pos): center_x = w_width/2 center_y = w_height/2 angle = math.atan2((center_x - cursor_pos.x()),(center_y - cursor_pos.y()))*180.0/math.pi angle = angle - 45 if (angle<0): angle = 360+angle pos = int(angle/90) + 1 if (pos>3): pos = 0 return pos #get radius of mouse point def get_radius(self, w_width, w_height, cursor_pos): center_x = w_width/2 center_y = w_height/2 tmp_val = math.pow((center_x - cursor_pos.x()),2) + math.pow((center_y - cursor_pos.y()),2) rad = int(math.sqrt(tmp_val)) return rad def draw_arc(self,qp, w_width, w_height, pos, rad): start_x = w_width/2 - rad start_y = w_height/2 - rad rectangle = QRect(start_x,start_y,(rad*2),(rad*2)) qp.drawPie(rectangle, (45+90*pos)*16, 90*16) def mousePressEvent(self, QMouseEvent): self.cursor_pos = QMouseEvent.pos() self.mouse_is_pressed = True my_widget.update(self) def mouseMoveEvent(self, QMouseEvent): self.cursor_pos = QMouseEvent.pos() self.mouse_is_pressed = True def mouseReleaseEvent(self, QMouseEvent): self.cursor_pos = QMouseEvent.pos() self.mouse_is_pressed = False my_widget.update(self)
class DetachableTabBar(QTabBar): ''' The TabBar class re-implements some of the functionality of the QTabBar widget ''' detach_tab_signal = Signal(int, QPoint, bool) # tab at pos, mouse cursor position, by double click move_tab_signal = Signal(int, int) empty_signal = Signal() def __init__(self, parent=None): QTabBar.__init__(self, parent) self.setAcceptDrops(True) self.setElideMode(Qt.ElideRight) self.setSelectionBehaviorOnRemove(QTabBar.SelectLeftTab) self.drag_start_pos = QPoint() self.drag_droped_pos = QPoint() self.mouse_cursor = QCursor() self.drag_initiated = False def mouseDoubleClickEvent(self, event): ''' Send the detach_tab_signal when a tab is double clicked ''' event.accept() self.detach_tab_signal.emit(self.tabAt(event.pos()), self.mouse_cursor.pos(), True) def mousePressEvent(self, event): ''' Set the starting position for a drag event when the mouse button is pressed ''' self.drag_droped_pos = QPoint(0, 0) self.drag_initiated = False if event.button() == Qt.LeftButton: self.drag_start_pos = event.pos() QTabBar.mousePressEvent(self, event) def mouseMoveEvent(self, event): ''' Determine if the current movement is a drag. If it is, convert it into a QDrag. If the drag ends inside the tab bar, emit an move_tab_signal. If the drag ends outside the tab bar, emit an detach_tab_signal. ''' # Determine if the current movement is detected as a drag if not self.drag_start_pos.isNull() and ((event.pos() - self.drag_start_pos).manhattanLength() > QApplication.startDragDistance()): self.drag_initiated = True # If the current movement is a drag initiated by the left button if ((event.buttons() & Qt.LeftButton)) and self.drag_initiated: # Stop the move event finishMoveEvent = QMouseEvent(QEvent.MouseMove, event.pos(), Qt.NoButton, Qt.NoButton, Qt.NoModifier) QTabBar.mouseMoveEvent(self, finishMoveEvent) # Convert the move event into a drag drag = QDrag(self) mime_data = QMimeData() mime_data.setData('action', b'application/tab-detach') drag.setMimeData(mime_data) # Create the appearance of dragging the tab content # tab_index = self.tabAt(self.drag_start_pos) pixmap = self.parentWidget().grab() targetPixmap = QPixmap(pixmap.size()) targetPixmap.fill(Qt.transparent) painter = QPainter(targetPixmap) painter.setOpacity(0.85) painter.drawPixmap(0, 0, pixmap) painter.end() drag.setPixmap(targetPixmap) # Initiate the drag dropAction = drag.exec_(Qt.MoveAction | Qt.CopyAction) # If the drag completed outside of the tab bar, detach the tab and move # the content to the current cursor position if dropAction == Qt.IgnoreAction: event.accept() self.detach_tab_signal.emit(self.tabAt(self.drag_start_pos), self.mouse_cursor.pos(), False) elif dropAction == Qt.MoveAction: # else if the drag completed inside the tab bar, move the selected tab to the new position if not self.drag_droped_pos.isNull(): self.move_tab_signal.emit(self.tabAt(self.drag_start_pos), self.tabAt(self.drag_droped_pos)) else: # else if the drag completed inside the tab bar new TabBar, move the selected tab to the new TabBar self.detach_tab_signal.emit(self.tabAt(self.drag_start_pos), self.mouse_cursor.pos(), False) event.accept() else: QTabBar.mouseMoveEvent(self, event) def dragEnterEvent(self, event): ''' Determine if the drag has entered a tab position from another tab position ''' self.drag_droped_pos = QPoint(0, 0) mime_data = event.mimeData() formats = mime_data.formats() if 'action' in formats and mime_data.data('action') == 'application/tab-detach': event.acceptProposedAction() QTabBar.dragMoveEvent(self, event) def dropEvent(self, event): ''' Get the position of the end of the drag ''' self.drag_droped_pos = event.pos() mime_data = event.mimeData() formats = mime_data.formats() if 'action' in formats and mime_data.data('action') == 'application/tab-detach': event.acceptProposedAction() QTabBar.dropEvent(self, event) def prepared_for_drop(self): return not self.drag_droped_pos.isNull() def tabRemoved(self, index): QTabBar.tabRemoved(self, index) if self.count() == 0: self.empty_signal.emit()