class NotificationServer(QObject): def __init__(self, parent=None): QObject.__init__(self, parent) self.notifications = set() self.size = QSize(300, 100) self.margin = QPoint(10, 10) def notify(self, html): note = Notification(html) self.connect(note, SIGNAL("done"), self.noteDestroyed) desktop = QApplication.desktop().availableGeometry(note) me = QRect(QPoint(0, 0), self.size) me.moveBottomRight(desktop.bottomRight() - self.margin) while self.notePosTaken(me): me.translate(0, 0 - (self.size.height() + (self.margin.y() * 2))) if not desktop.contains(me): me.moveBottom(desktop.bottom() - self.margin.y()) me.translate(0 - (self.size.width() + self.margin.x() * 2), 0) note.setGeometry(me) self.notifications.add(note) note.display() def notePosTaken(self, rect): for note in self.notifications: if note.geometry().intersects(rect): return True return False def noteDestroyed(self, note): self.notifications.remove(note)
def get_border(self, p: QPoint): if p.x() <= 2: return Alignment.Left elif p.x() >= self.width() - 2: return Alignment.Right elif p.y() <= 2: return Alignment.Top elif p.y() >= self.height() - 2: return Alignment.Bottom return None
class MovingMessage(FadeMessage): def __init__(self, message, str=None, pos=None): cfg = Config('messages', message) if (pos is None): self.pos = QPoint(*cfg.get('position')) else: self.pos = QPoint(*pos) self.velocity = cfg.get('velocity') FadeMessage.__init__(self, message, str) def with_controller(self): self.rect = QRect(0, 0, self.controller.width(), self.controller.height()) self.rect.moveCenter(self.pos) def tick(self, elapsed): FadeMessage.tick(self, elapsed) self.pos.setX(self.pos.x() + self.velocity[0] * elapsed) self.pos.setY(self.pos.y() + self.velocity[1] * elapsed) self.rect.moveCenter(self.pos) def draw(self): FadeMessage.draw(self) if (self.color.alpha() == 0): self.rect = self.bounding_text_rect
class MovingMessage(FadeMessage): def __init__(self, message, str = None, pos = None): cfg = Config('messages', message) if (pos is None): self.pos = QPoint(*cfg.get('position')) else: self.pos = QPoint(*pos) self.velocity = cfg.get('velocity') FadeMessage.__init__(self, message, str) def with_controller(self): self.rect = QRect(0, 0, self.controller.width(), self.controller.height()) self.rect.moveCenter(self.pos) def tick(self, elapsed): FadeMessage.tick(self, elapsed) self.pos.setX(self.pos.x() + self.velocity[0] * elapsed) self.pos.setY(self.pos.y() + self.velocity[1] * elapsed) self.rect.moveCenter(self.pos) def draw(self): FadeMessage.draw(self) if (self.color.alpha() == 0): self.rect = self.bounding_text_rect
def readSettings(self): self.imageFolder = os.path.normpath(str(self.settings.value("imageFolder").toString())) self.ui.actionIgnore_Transparent_Pixels.setChecked( self.settings.value("ignoreAlpha", True).toBool()) self.ui.actionCheck_for_update_at_start.setChecked( self.settings.value("checkupdate", True).toBool()) self.ui.tolerance_le.setText( self.settings.value("tolerance").toString()) self.settings.beginGroup("/geometry") p = QPoint() # position s = QSize() # size x = self.settings.value("X", -1).toInt()[0] y = self.settings.value("Y", -1).toInt()[0] # don't position outside current screen qRect = QtGui.QDesktopWidget.availableGeometry(app.desktop()) if x > qRect.right(): x = 10 if y > qRect.bottom(): y = 10 p.setX(x) p.setY(y) s.setWidth(self.settings.value("W", -1).toInt()[0]) s.setHeight(self.settings.value("H", -1).toInt()[0]) self.settings.endGroup() if p.x() > 0 and p.y() > 0 and s.width() > 0 and s.height() > 0: self.resize(s) # restore size self.move(p) # restore position
def contains(self, p: QPoint): d = self.size * Info.dpi pos = self.real_pos() dx = pos.x() - p.x() dy = pos.y() - p.y() if dx * dx + dy * dy <= d * d: return True return False
def showPopup(self): if not self.popup: return pos = QPoint(self.width(), self.height()) pos = self.mapToGlobal(pos) size = self.popup.size() self.popup.move(pos.x() - size.width(), pos.y()) self.popup.show()
def kineticMove(self, oldx, oldy, newx, newy ): """Start a kinetic move from (oldx, oldy) to (newx, newy)""" if newx == oldx and newy == oldy: return speed = QPoint(0,0) # solve speed*(speed+1)/2 = delta to ensure 1+2+3+...+speed is as close as possible under delta.. speed.setX((sqrt(1+8*abs(newx-oldx))-1)/2) speed.setY((sqrt(1+8*abs(newy-oldy))-1)/2) # compute the amount of displacement still needed because we're dealing with integer values. diff = QPoint(0,0) diff.setX(-abs(newx-oldx) + speed.x()*(speed.x()+1)/2) diff.setY(-abs(newy-oldy) + speed.y()*(speed.y()+1)/2) # Since this function is called for exact moves (not free scrolling) # limit the kinetic time to 2 seconds, which means 100 ticks, 5050 pixels. if speed.y() > 100: speed.setY(100) diff.setY(-abs(newy-oldy) + 5050) # Although it is less likely to go beyond that limit for horizontal scrolling, # do it for x as well. if speed.x() > 100: speed.setX(100) diff.setX(-abs(newx-oldx) + 5050) # move left or right, up or down if newx > oldx : speed.setX(-speed.x()) diff.setX(-diff.x()) if newy > oldy : speed.setY(-speed.y()) diff.setY(-diff.y()) # move immediately by the step that cannot be handled by kinetic scrolling. # By construction that step is smaller that the initial speed value. self.fastScrollBy(diff) self.kineticStart(speed)
def kineticMove(self, oldx, oldy, newx, newy): """Start a kinetic move from (oldx, oldy) to (newx, newy)""" if newx == oldx and newy == oldy: return speed = QPoint(0, 0) # solve speed*(speed+1)/2 = delta to ensure 1+2+3+...+speed is as close as possible under delta.. speed.setX((sqrt(1 + 8 * abs(newx - oldx)) - 1) / 2) speed.setY((sqrt(1 + 8 * abs(newy - oldy)) - 1) / 2) # compute the amount of displacement still needed because we're dealing with integer values. diff = QPoint(0, 0) diff.setX((speed.x() * (speed.x() + 1) // 2) - abs(newx - oldx)) diff.setY((speed.y() * (speed.y() + 1) // 2) - abs(newy - oldy)) # Since this function is called for exact moves (not free scrolling) # limit the kinetic time to 2 seconds, which means 100 ticks, 5050 pixels. if speed.y() > 100: speed.setY(100) diff.setY(-abs(newy - oldy) + 5050) # Although it is less likely to go beyond that limit for horizontal scrolling, # do it for x as well. if speed.x() > 100: speed.setX(100) diff.setX(-abs(newx - oldx) + 5050) # move left or right, up or down if newx > oldx: speed.setX(-speed.x()) diff.setX(-diff.x()) if newy > oldy: speed.setY(-speed.y()) diff.setY(-diff.y()) # move immediately by the step that cannot be handled by kinetic scrolling. # By construction that step is smaller that the initial speed value. self.fastScrollBy(diff) self.kineticStart(speed)
def drawNetwork(self, qp): #for each vehicle for j in range(len(self.vehicleList)): #we check others vehicles for k in range(len(self.vehicleList)): #if we are testing the current vehicle if j == k: continue # if we are testing an other vehicle else: # calculating the distance between the 2 vehicles xDiff = self.vehicleList[k].position.x() - self.vehicleList[j].position.x() yDiff = self.vehicleList[k].position.y() - self.vehicleList[j].position.y() dist = math.sqrt(math.pow(xDiff, 2) + math.pow(yDiff, 2)) if dist < globalvars.msg_distance: # creating a connection between the 2 vehicles qp.drawLine( self.vehicleList[j].position.x(), self.vehicleList[j].position.y(), self.vehicleList[k].position.x(), self.vehicleList[k].position.y() ) # creating a random movement if not self.isPause: isPosX = bool(random.getrandbits(1)) isPosY = bool(random.getrandbits(1)) if isPosX: if self.vehicleList[j].position.x() < self.size.width() - 50: self.vehicleList[j].position.setX(self.vehicleList[j].position.x() + 1) else: if self.vehicleList[j].position.x() > 25: self.vehicleList[j].position.setX(self.vehicleList[j].position.x() - 1) if isPosY: if self.vehicleList[j].position.y() < self.size.height() - 50: self.vehicleList[j].position.setY(self.vehicleList[j].position.y() + 1) else: if self.vehicleList[j].position.y() > 25: self.vehicleList[j].position.setY(self.vehicleList[j].position.y() - 1) pos = QPoint(self.vehicleList[j].position.x() - (self.vehicleImg[j].size().width()/2), self.vehicleList[j].position.y() - (self.vehicleImg[j].size().height()/2)) self.vehicleImg[j].move(pos.x(), pos.y()) time.sleep(0.001) # calling paintEvent self.update()
class Circle(): def __init__(self, diameter, x, y): self.diameter = diameter self.radius = math.floor(diameter / 2.0) self.center = QPoint(x, y) def drawCircle(self, event, qp): qp.setBrush(QtGui.QColor(34, 34, 200)) qp.drawEllipse(self.center, self.radius, self.radius) def isClicked(self, pos): result = math.pow((pos.x() - self.center.x()), 2) + math.pow( (pos.y() - self.center.y()), 2) if result <= math.pow(self.radius, 2): return True else: return False def x(self): return self.center.x() def y(self): return self.center.y()
class Circle(): def __init__(self, diameter, x, y): self.diameter = diameter self.radius = math.floor(diameter / 2.0) self.center = QPoint(x, y) def drawCircle(self, event, qp): qp.setBrush(QtGui.QColor(34, 34, 200)) qp.drawEllipse(self.center, self.radius, self.radius) def isClicked(self, pos): result = math.pow((pos.x() - self.center.x()), 2) + math.pow((pos.y() - self.center.y()), 2) if result <= math.pow(self.radius, 2): return True else: return False def x(self): return self.center.x() def y(self): return self.center.y()
def kineticAddDelta(self, delta ): """Add a kinetic delta to an already started kinetic move.""" speed = QPoint(0,0) # Get the remaining scroll amount. currentSpeed = abs( self._kineticData._speed.y() ) leftToScroll = (currentSpeed+1)*currentSpeed / 2 ; if self._kineticData._speed.y() < 0: leftToScroll *= -1 leftToScroll += delta speed.setY((sqrt(1+8*abs(leftToScroll))-1)/2) speed.setX( self._kineticData._speed.x() ) if leftToScroll < 0: speed.setY(-speed.y()) self.kineticStart(speed)
class Window(QLabel): #First of all, user can watch the full screenshot def __init__(self, parent=None): QLabel.__init__(self, parent) self.rubberBand = QRubberBand(QRubberBand.Rectangle, self) self.origin = QPoint() img = QPixmap.grabWindow(QApplication.desktop().winId()) self.setPixmap(img) #Using Mouse, user can select area of screenshot to choose word(english) for searching. # This version cannot support capture of area. def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.origin = QPoint(event.pos()) posDictionary1.append(self.origin.x()) posDictionary1.append(self.origin.y()) self.rubberBand.setGeometry(QRect(self.origin, QSize())) self.rubberBand.show() def mouseMoveEvent(self, event): if not self.origin.isNull(): self.rubberBand.setGeometry( QRect(self.origin, event.pos()).normalized()) def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: x = (QPoint(event.pos())).x() y = (QPoint(event.pos())).y() posDictionary2.append(x) posDictionary2.append(y) self.rubberBand.hide() self.close() Capture(posDictionary1[0], posDictionary1[1], posDictionary2[0], posDictionary2[1]) Result_Window()
def __init__(self, level_number, level): self.level_number = level_number self.info = {} self.fields = set() self.level = level self.player_state = Player.get_instance() cfg = Config('interface', 'Settings') font_name = cfg.get('field_font') font_size = cfg.get('field_font_sz') self.field_font = FontManager.getFont(font_name) self.field_font.setPointSize(font_size) self.field_color = QColor.fromRgb(*cfg.get('field_color')) for f_name in ConfigManager.getOptions('interface', 'Fields'): s = ConfigManager.getVal('interface', 'Fields', f_name) s = map(str.strip, s.split('||')) img = QImage('resources/images/'+s[0]) img_pos = QPoint(*eval(s[1])) info_rect = QRect(*eval(s[2])) scale = float(s[3]) if (len(s) >= 5): font = QFont(self.field_font) font.setPointSize(int(s[4])) else: font = self.field_font img_w, img_h = img.width(), img.height() img_rect = QRect( img_pos.x(), img_pos.y(), int(img_w*scale), int(img_h*scale) ) self.info[f_name] = '' self.fields.add(Field(f_name, img, img_rect, info_rect, font)) self.radar = Radar.from_config('E-Radar', self) self.missile = GuidedMissile.from_config('GuidedMissile', self)
def drawXInfos(self): pen = self.painter.pen() i = 1 scale = 6 x = self.yLeftMargin y = self.ploter.height - self.m if not self.selDateMin: date = self.baseDateMin shift_date = (self.baseDateMax - self.baseDateMin) / scale else: date = self.selDateMin shift_date = (self.selDateMax - self.selDateMin) / scale while i <= scale + 1: pen.setColor(Qt.black) pen.setStyle(Qt.SolidLine) pos = QPoint(x - 40, y + 17) self.painter.setPen(pen) # Draw vertical doted line self.painter.drawLine(x, y - 3, x, y + 3) # Draw date self.painter.drawText( pos, str(self.timeline.fromUSec(date).strftime('%d.%m.%Y'))) # If number of days shown < scale, draw time if shift_date <= (86400 * 1000000): pos.setY(pos.y() + 15) pos.setX(pos.x() + 9) # Draw time self.painter.drawText( pos, str(self.timeline.fromUSec(date).strftime('%H:%M:%S'))) pen.setColor(Qt.gray) pen.setStyle(Qt.DotLine) self.painter.setPen(pen) if i != 1: self.painter.drawLine(x, y + 3, x, self.m / 3) x = self.yLeftMargin + (i * ( (self.ploter.width - self.m - self.yLeftMargin) / (scale))) i += 1 date += shift_date pen.setStyle(Qt.SolidLine) self.painter.setPen(pen)
def drawXInfos(self): pen = self.painter.pen() i = 1 scale = 6 x = self.yLeftMargin y = self.ploter.height - self.m if not self.selDateMin: date = self.baseDateMin shift_date = (self.baseDateMax - self.baseDateMin) / scale else: date = self.selDateMin shift_date = (self.selDateMax - self.selDateMin) / scale while i <= scale + 1: pen.setColor(Qt.black) pen.setStyle(Qt.SolidLine) pos = QPoint(x - 40, y + 17) self.painter.setPen(pen) # Draw vertical doted line self.painter.drawLine(x, y - 3, x, y + 3) # Draw date self.painter.drawText(pos, str(self.timeline.fromUSec(date).strftime('%d.%m.%Y'))) # If number of days shown < scale, draw time if shift_date <= (86400 * 1000000): pos.setY(pos.y() + 15) pos.setX(pos.x() + 9) # Draw time self.painter.drawText(pos, str(self.timeline.fromUSec(date).strftime('%H:%M:%S'))) pen.setColor(Qt.gray) pen.setStyle(Qt.DotLine) self.painter.setPen(pen) if i != 1: self.painter.drawLine(x, y + 3, x, self.m / 3) x = self.yLeftMargin + (i * ((self.ploter.width - self.m - self.yLeftMargin) / (scale))) i += 1 date += shift_date pen.setStyle(Qt.SolidLine) self.painter.setPen(pen)
class VispaWidgetOwner(object): """ Interface for classes containing VispaWidgets Only makes sense if implementing class also inherits QWidget or class inheriting QWidget. """ def enableMultiSelect(self, multiSelect=True): self._multiSelectEnabledFlag = multiSelect def multiSelectEnabled(self): return hasattr( self, "_multiSelectEnabledFlag") and self._multiSelectEnabledFlag def selectedWidgets(self): """ Returns a list of all selected widgets. """ if hasattr(self, "_selectedWidgets"): return self._selectedWidgets return [ child for child in self.children() if hasattr(child, "isSelected") and child.isSelected() ] def widgetSelected(self, widget, multiSelect=False): """ Forward selection information to super class if it is a VispaWidgetOwner. """ logging.debug(self.__class__.__name__ + ": widgetSelected()") if isinstance(self, QObject): if not hasattr(self, "_selectedWidgets"): self._selectedWidgets = [] if not multiSelect or not self.multiSelectEnabled(): self.deselectAllWidgets(widget) self._selectedWidgets = [] if widget.parent() == self and not widget in self._selectedWidgets: self._selectedWidgets.append(widget) for widget in [ child for child in self._selectedWidgets if hasattr(child, "isSelected") and not child.isSelected() ]: self._selectedWidgets.remove(widget) if isinstance(self.parent(), VispaWidgetOwner): self.parent().widgetSelected(widget) def widgetDoubleClicked(self, widget): """ Forward selection information to super class if it is a VispaWidgetOwner. """ #logging.debug(self.__class__.__name__ +": widgetDoubleClicked()") if isinstance(self, QObject): if isinstance(self.parent(), VispaWidgetOwner): self.parent().widgetDoubleClicked(widget) def initWidgetMovement(self, widget): self._lastMovedWidgets = [] if self.multiSelectEnabled(): pos = widget.pos() for child in self.children(): if child != widget and hasattr( child, "isSelected") and child.isSelected(): child.setDragReferencePoint(pos - child.pos()) def widgetDragged(self, widget): """ Tell parent widget has moved. Only informs parent if it is a VispaWidgetOwner, too. """ if isinstance(self.parent(), VispaWidgetOwner): self.parent().widgetDragged(widget) if hasattr(self, "_lastMovedWidgets"): self._lastMovedWidgets.append(widget) if self.multiSelectEnabled(): for child in self.children(): if hasattr( child, "dragReferencePoint") and child != widget and hasattr( child, "isSelected") and child.isSelected(): if hasattr(child, "setPreviousDragPosition"): child.setPreviousDragPosition(child.pos()) child.move(widget.pos() - child.dragReferencePoint()) self._lastMovedWidgets.append(child) # apparently unused feature (2010-07-02), remove if really unnecessary # also see self._lastMovedWidget definition above def lastMovedWidgets(self): if hasattr(self, "_lastMovedWidgets"): return self._lastMovedWidgets return None def widgetAboutToDelete(self, widget): """ This function is called from the delete() function of VispaWidget. """ pass def keyPressEvent(self, event): """ Calls delete() method of selected child widgets if multi-select is activated. """ if self.multiSelectEnabled() and (event.key() == Qt.Key_Backspace or event.key() == Qt.Key_Delete): selection = self.selectedWidgets()[:] for widget in selection: widget.delete() def deselectAllWidgets(self, exception=None): """ Deselects all widgets except the widget given as exception. """ #logging.debug(self.__class__.__name__ +": deselectAllWidgets()") self._selectedWidgets = [] for child in self.children(): if child != exception: if hasattr(child, 'select'): child.select(False) else: self._selectedWidgets.append(child) if isinstance(child, VispaWidgetOwner): child.deselectAllWidgets(exception) self.update() def mousePressEvent(self, event): """ Calls deselectAllWidgets. """ multiSelectEnabled = self.multiSelectEnabled() if event.modifiers() != Qt.ControlModifier: self.deselectAllWidgets() if multiSelectEnabled: self._selectionRectStartPos = QPoint(event.pos()) self._selectionRect = None def mouseMoveEvent(self, event): if self.multiSelectEnabled() and self._selectionRectStartPos and ( event.pos() - self._selectionRectStartPos ).manhattanLength() >= QApplication.startDragDistance(): eventX = event.pos().x() eventY = event.pos().y() startX = self._selectionRectStartPos.x() startY = self._selectionRectStartPos.y() oldRect = self._selectionRect self._selectionRect = QRect(min(startX, eventX), min(startY, eventY), abs(eventX - startX), abs(eventY - startY)) if oldRect: self.update( self._selectionRect.united(oldRect).adjusted(-5, -5, 5, 5)) else: self.update(self._selectionRect) # dynamically update selection statur # currently bad performance (2010-07-07) # TODO: improve selection mechanism # for child in self.children(): # if hasattr(child, "select") and hasattr(child, "isSelected"): # child.select(self._selectionRect.contains(child.geometry()), True) # select, mulitSelect def mouseReleaseEvent(self, event): if hasattr(self, "_selectionRect" ) and self._selectionRect and self.multiSelectEnabled(): for child in self.children(): if hasattr(child, "select") and hasattr( child, "isSelected") and self._selectionRect.contains( child.geometry()) and not child.isSelected(): child.select(True, True) # select, mulitSelect self.update(self._selectionRect.adjusted(-5, -5, 5, 5)) self._selectionRect = None self._selectionRectStartPos = None
class GLWidget(QtOpenGL.QGLWidget): """ This class renders something with OpenGL """ def __init__(self, parent=None): """ Constructor """ self.__image_width = 250 self.__image_height = 250 self.__isMouseDown = False self.__zoomFactor = 1.0 self.__scrollOffset = QPoint() if hasattr(QGLFormat, "setVersion"): # Modern OpenGL f = QGLFormat() f.setVersion(3, 3) f.setProfile(QGLFormat.CoreProfile) f.setSampleBuffers(True) c = QGLContext(f, None) QGLWidget.__init__(self, c, parent) print "Version is set to 3.3" else: QGLWidget.__init__(self, parent) # self.__svgItem = QtSvg.QGraphicsSvgItem("circle_star.svg") self.__mySvgTool = MySvgTool() self.__mySvgWriter = MySvgWriter() self.__mySvgWriter.DrawSomething() self.__myBufferPainter = MyBufferPainter() def initializeGL(self): glClearColor(0.5, 0.5, 0.5, 1.0) glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) glEnable(GL_LINE_SMOOTH) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) self.__shaderProgram = QGLShaderProgram() if self.__shaderProgram.addShaderFromSourceFile(QGLShader.Vertex, "shader.vert"): print "Main - Vertex shader OK" if self.__shaderProgram.addShaderFromSourceFile(QGLShader.Fragment, "shader.frag"): print "Main - Fragment shader OK" self.__shaderProgram.link() self.__texCoordLocation = self.__shaderProgram.attributeLocation("uv") self.__vertexLocation = self.__shaderProgram.attributeLocation("position") self.__colorLocation = self.__shaderProgram.attributeLocation("color") self.__use_color_location = self.__shaderProgram.uniformLocation("use_color") self.__mvpMatrixLocation = self.__shaderProgram.uniformLocation("mvpMatrix") # Returns -1 if name is not a valid attribute for this shader program. print "\n__texCoordLocation :", self.__texCoordLocation, " ", "\n__vertexLocation :", self.__vertexLocation, " ", "\n__colorLocation :", self.__colorLocation, " ", "\n__use_color_location :", self.__use_color_location, " ", "\n__mvpMatrixLocation :", self.__mvpMatrixLocation self.__blurProgram = QGLShaderProgram() if self.__blurProgram.addShaderFromSourceFile(QGLShader.Vertex, "shader.vert"): print "Gaussian blur - Vertex shader OK" # if I use shader.frag it's okay ??? # if self.__blurProgram.addShaderFromSourceFile(QGLShader.Fragment, "gaussian_blur.frag") : if self.__blurProgram.addShaderFromSourceFile(QGLShader.Fragment, "gaussian_blur.frag"): print "Gaussian blur - fragment shader OK" self.__blurProgram.link() self.__myBufferPainter.SetThings(self.__shaderProgram, self.__blurProgram) self.__myBufferPainter.initializeGL(self.bindTexture(QtGui.QPixmap("laughing_man.png"))) self.__myBufferPainter.prepareFrameRect( self.__scrollOffset.x(), self.__scrollOffset.y(), self.width(), self.height(), self.__zoomFactor ) """ ### texture self.__ori_tex = self.bindTexture(QtGui.QPixmap("laughing_man.png")) vertexData = numpy.array([ 0.0, 0.0, 0.0, 1.0, 0.0, 250.0, 0.0, 1.0, 250.0, 250.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 250.0, 250.0, 0.0, 1.0, 250.0, 0.0, 0.0, 1.0, # uv 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1], dtype = numpy.float32) colorData = numpy.array([1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,], dtype = numpy.float32) ### create VAO self.__VAO = glGenVertexArrays(1) glBindVertexArray(self.__VAO) ### create a VBO for position and uv posVBO = glGenBuffers(1) glBindBuffer(GL_ARRAY_BUFFER, posVBO) glBufferData(GL_ARRAY_BUFFER, vertexData.nbytes, vertexData, GL_STATIC_DRAW) glEnableVertexAttribArray(self.__vertexLocation) glVertexAttribPointer(self.__vertexLocation, 4, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(self.__texCoordLocation) glVertexAttribPointer(self.__texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(96)) ### create VBO for color colVBO = glGenBuffers(1) glBindBuffer(GL_ARRAY_BUFFER, colVBO) glBufferData(GL_ARRAY_BUFFER, colorData.nbytes, colorData, GL_STATIC_DRAW) glEnableVertexAttribArray(self.__colorLocation) glVertexAttribPointer(self.__colorLocation, 4, GL_FLOAT, GL_FALSE, 0, None) ### unbind vao and vbo glBindBuffer(GL_ARRAY_BUFFER, 0) glBindVertexArray(0) """ def paintGL(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ### this doesn't work # frameBufferA.bind() # frameBufferA.release() glViewport(0, 0, self.width(), self.height()) orthoMatrix = QMatrix4x4() orthoMatrix.ortho( 0 + self.__scrollOffset.x(), self.width() + self.__scrollOffset.x(), self.height() + self.__scrollOffset.y(), 0 + self.__scrollOffset.y(), -100, 100, ) transformMatrix = QMatrix4x4() transformMatrix.setToIdentity() transformMatrix.scale(self.__zoomFactor) ### activate shader program # self.__shaderProgram.bind() ### set a shader attribute (0 means use texture, 1 means use color) # self.__shaderProgram.setUniformValue(self.__use_color_location, 0.0) ### feed the mpv matrix mpvMatrix = orthoMatrix * transformMatrix # self.__shaderProgram.setUniformValue(self.__mvpMatrixLocation, mpvMatrix) # Draw Something self.__myBufferPainter.paintGL( self.__scrollOffset.x(), self.__scrollOffset.y(), self.width(), self.height(), self.__zoomFactor, mpvMatrix ) """ ### DRAW SOMETHING ### bind texture glBindTexture(GL_TEXTURE_2D, self.__ori_tex) ### bind VAO glBindVertexArray(self.__VAO) ### draw triangle glDrawArrays(GL_TRIANGLES, 0, 18) """ ### unbind # glBindVertexArray(0) # glUseProgram(0) # self.__shaderProgram.release() def SetSomething(self): pass def DrawSomething(self): pass def ZoomIn(self): self.__zoomFactor += 0.1 def ZoomOut(self): self.__zoomFactor -= 0.1 if self.__zoomFactor < 0.1: self.__zoomFactor = 0.1 """ Get / Set """ def GetImageSize(self): """ Get the size of the canvas / image """ return QSize(self.__image_width, self.__image_height) def SetZoomFactor(self, val): """ Set the value of magnification """ self.__zoomFactor = val def GetZoomFactor(self): """ Obtain the value of the magnification """ return self.__zoomFactor def SetMouseDown(self, val): """ Set the value of mouse down """ self.__isMouseDown = val def SetHorizontalScroll(self, val): """ Set horizontal scroll value """ self.__scrollOffset.setX(val) def SetVerticalScroll(self, val): """ Set vertical scroll value """ self.__scrollOffset.setY(val)
class MikiView(QWebView): def __init__(self, parent=None): super(MikiView, self).__init__(parent) self.parent = parent self.settings().clearMemoryCaches() self.notePath = parent.settings.notePath self.settings().setUserStyleSheetUrl( QUrl('file://'+self.parent.settings.cssfile)) print(QUrl('file://'+self.parent.settings.cssfile)) self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) self.page().linkClicked.connect(self.linkClicked) self.page().linkHovered.connect(self.linkHovered) self.page().mainFrame( ).contentsSizeChanged.connect(self.contentsSizeChanged) self.scrollPosition = QPoint(0, 0) def linkClicked(self, qurl): '''three kinds of link: external uri: http/https page ref link: toc anchor link: # ''' name = qurl.toString() http = re.compile('https?://') if http.match(name): # external uri QDesktopServices.openUrl(qurl) return self.load(qurl) name = name.replace('file://', '') name = name.replace(self.notePath, '').split('#') item = self.parent.notesTree.pageToItem(name[0]) if not item or item == self.parent.notesTree.currentItem(): return else: self.parent.notesTree.setCurrentItem(item) if len(name) > 1: link = "file://" + self.notePath + "/#" + name[1] self.load(QUrl(link)) viewFrame = self.page().mainFrame() self.scrollPosition = viewFrame.scrollPosition() def linkHovered(self, link, title, textContent): '''show link in status bar ref link shown as: /parent/child/pageName toc link shown as: /parent/child/pageName#anchor (ToFix) ''' # TODO: link to page by: /parent/child/pageName#anchor if link == '': # not hovered self.parent.statusBar.showMessage(self.parent.notesTree.currentPage()) else: # beautify link link = link.replace('file://', '') link = link.replace(self.notePath, '') self.parent.statusBar.showMessage(link) def contentsSizeChanged(self, newSize): '''scroll notesView while editing (adding new lines) Whithout this, every `updateView` will result in scroll to top. ''' if self.scrollPosition == QPoint(0, 0): return viewFrame = self.page().mainFrame() newY = self.scrollPosition.y( ) + newSize.height() - self.contentsSize.height() self.scrollPosition.setY(newY) viewFrame.setScrollPosition(self.scrollPosition) def updateView(self): # url_notebook = 'file://' + os.path.join(self.notePath, '/') viewFrame = self.page().mainFrame() # Store scrollPosition before update notesView self.scrollPosition = viewFrame.scrollPosition() self.contentsSize = viewFrame.contentsSize() url_notebook = 'file://' + self.notePath + '/' self.setHtml(self.parent.notesEdit.toHtml(), QUrl(url_notebook)) # Restore previous scrollPosition viewFrame.setScrollPosition(self.scrollPosition) def updateLiveView(self): if self.parent.actions.get('split').isChecked(): QTimer.singleShot(1000, self.updateView)
class ContainerWidget(QWidget): def __init__(self, container, parent: QWidget = None): QWidget.__init__(self, parent) self.setWindowTitle('Container') self.__b_widgets = [] self.__container = container self.__translation = QPoint(0, 0) self.setMouseTracking(True) self.setFocusPolicy(Qt.ClickFocus) self.setFocus() for b in container.blocks: w = b.get_widget(self) self.__b_widgets.append(w) pal = QPalette(self.palette()) pal.setColor(QPalette.Background, QColor(55, 50, 47)) self.setAutoFillBackground(True) self.setPalette(pal) container.block_added.connect(self.add_block) container.block_removed.connect(self.remove_block) self.__moving = False self.__origin = QPoint() def paintEvent(self, e: QPaintEvent): if e.isAccepted() and e.accept(): QWidget.paintEvent(self, e) p = QPainter(self) p.setRenderHint(QPainter.Antialiasing) for l in self.__container.lines: l.paint(p) def add_block(self, b): w = b.get_widget(self) self.__b_widgets.append(w) def __get_b_widget(self, b): for w in self.__b_widgets: if w.block() == b: return w return None def remove_block(self, b): w = self.__get_b_widget(b) if b is not None: self.__b_widgets.remove(b) w.deleteLater() def mousePressEvent(self, e: QMouseEvent): BlockManager.deselect_all() if e.button() == Qt.LeftButton: self.__moving = True self.__origin = e.pos() self.setCursor(Qt.DragMoveCursor) elif e.button() == Qt.RightButton: self.show_popup(e.pos()) def mouseDoubleClickEvent(self, e: QMouseEvent): BlockManager.deselect_all() if e.button() == Qt.LeftButton: self.__moving = False self.__translation = QPoint() self.translate(0, 0) def show_popup(self, pos): print('here') def mouseMoveEvent(self, e: QMouseEvent): if self.__moving: dx = e.x() - self.__origin.x() dy = e.y() - self.__origin.y() self.__origin = e.pos() self.translate(dx, dy) def mouseReleaseEvent(self, e): self.__moving = False self.setCursor(Qt.ArrowCursor) def translate(self, dx, dy): p = QPoint(self.__translation.x() + dx, self.__translation.y() + dy) self.__translation = p for b in self.__b_widgets: b.translate(p) self.repaint()
class MapSwipeTool(QgsMapTool): def __init__(self, iface): canvas = iface.mapCanvas() super(MapSwipeTool, self).__init__( canvas ) self.view = iface.layerTreeView() self.msgBar = iface.messageBar() self.swipe = SwipeMap( canvas ) self.checkDirection = self.hasSwipe = self.disabledSwipe = None self.firstPoint = QPoint() self.cursorV = QCursor( Qt.SplitVCursor ) self.cursorH = QCursor( Qt.SplitHCursor ) def activate(self): self.canvas().setCursor( QCursor( Qt.CrossCursor ) ) self._connect() self.hasSwipe = False self.disabledSwipe = False self.setLayersSwipe( self.view.currentIndex() ) def canvasPressEvent(self, e): if len(self.swipe.layers) == 0: msg = "Select active Layer or Group(with layers) in legend." self.msgBar.clearWidgets() self.msgBar.pushMessage( "MapSwipeTool", msg, QgsMessageBar.WARNING, 4 ) return self.hasSwipe = True self.firstPoint.setX( e.x() ) self.firstPoint.setY( e.y() ) self.checkDirection = True def canvasReleaseEvent(self, e): self.hasSwipe = False self.canvas().setCursor( QCursor( Qt.CrossCursor ) ) def canvasMoveEvent(self, e): if self.hasSwipe: if self.checkDirection: dX = abs( e.x() - self.firstPoint.x() ) dY = abs( e.y() - self.firstPoint.y() ) isVertical = dX > dY self.swipe.setIsVertical( isVertical ) self.checkDirection = False self.canvas().setCursor( self.cursorH if isVertical else self.cursorV ) self.swipe.setLength( e.x(), e.y() ) def _connect(self, isConnect = True): signal_slot = ( { 'signal': self.canvas().mapCanvasRefreshed, 'slot': self.swipe.setMap }, { 'signal': self.view.activated, 'slot': self.setLayersSwipe }, { 'signal': QgsMapLayerRegistry.instance().removeAll, 'slot': self.disable } ) if isConnect: for item in signal_slot: item['signal'].connect( item['slot'] ) else: for item in signal_slot: item['signal'].disconnect( item['slot'] ) @pyqtSlot( "QModelIndex" ) def setLayersSwipe(self, index): if self.disabledSwipe: return ids = msg = None node = self.view.currentNode() if isinstance( node, QgsLayerTreeLayer ): layer = node.layer() ids = [ layer.id() ] msg = "Active layer is '%s'." % layer.name() else: group = self.view.currentGroupNode() if group.parent() is None: # Root return ids = group.findLayerIds() msg = "Active group is '%s'." % group.name() self.swipe.clear() self.swipe.setLayersId( ids ) self.msgBar.clearWidgets() self.msgBar.pushMessage( "MapSwipeTool", msg, QgsMessageBar.INFO, 2 ) self.swipe.setMap() @pyqtSlot() def disable(self): self.swipe.clear() self.hasSwipe = False self.disabledSwipe = True def deactivate(self): super( MapSwipeTool, self ).deactivate() self.deactivated.emit() self.swipe.clear() self._connect( False )
class OIBlock(QWidget): border_color = QColor(137, 117, 89) padding = 0.05 radius = 0.08 def __init__(self, block, parent): QWidget.__init__(self, parent) self.__nodes = [] self.__block = block self._resizable = True self.__block.repaint.connect(self.repaint) self._bg_color = QColor(159, 160, 144, 255) self._fg_color = QColor(255, 255, 255) self.setGeometry(block.get_geometry(Info.dpi)) self.__action = Action.NONE self.__status = Mode.EDIT_LOGIC self.__corner_path = None self.__origin = None self.__translation = QPoint() if self._resizable: self.__init_corner() self.__init_nodes() self.__init_listeners() self.setMouseTracking(True) def __init_nodes(self): y = .45 x = .01 for k in self.__block.inputs: i = self.__block.inputs[k] n = OINode(QPointF(x, y), Alignment.Left, i) self.__nodes.append(n) y += 0.05 + n.size x = self.width() / Info.dpi - .12 y = 0.45 for k in self.__block.outputs: o = self.__block.outputs[k] n = OINode(QPointF(x, y), Alignment.Right, o) self.__nodes.append(n) y += .05 + n.size def __init_listeners(self): self.__block.selected.connect(self.select) self.__block.settings['Width'].value_update.connect( self.geometry_update) self.__block.settings['Height'].value_update.connect( self.geometry_update) self.__block.settings['X'].value_update.connect(self.geometry_update) self.__block.settings['Y'].value_update.connect(self.geometry_update) def select(self, val: bool): if val: effect = QGraphicsDropShadowEffect() effect.setBlurRadius(20) effect.setXOffset(0) effect.setYOffset(0) effect.setColor(QColor(0, 0, 0, 180)) self.setGraphicsEffect(effect) self.raise_() else: eff = self.graphicsEffect() del eff self.setGraphicsEffect(None) def geometry_update(self): r = self.__block.get_geometry(Info.dpi) r.translate(self.__translation) self.setGeometry(r) self.__update_nodes() def __update_nodes(self): x = self.width() / Info.dpi - .12 for n in self.__nodes: if n.alignment == Alignment.Right: y = n.pos.y() n.pos = QPointF(x, y) self.repaint() def selected(self): return self.__block.is_selected() def bg(self): return self._bg_color def title_bg(self): return self._bg_color.light(80) def block(self): return self.__block def _paint(self, p: QPainter): self._paint_bg(p) self._paint_title(p) p.setPen(QPen(self.pen().brush(), 0.01 * Info.dpi)) self._paint_nodes(p) # self._paint_outs(p) # self._paint_content(p) def pen(self): p = QPen( OIBlock.border_color.lighter().lighter() if self.selected() else OIBlock.border_color, .02 * Info.dpi) return p def _paint_bg(self, p: QPainter): dpi = Info.dpi pen = self.pen() p.setRenderHint(QPainter.Antialiasing, True) p.setPen(pen) p.setBrush(self.bg()) p.drawRoundedRect(OIBlock.padding * dpi, OIBlock.padding * dpi, self.width() - 2 * OIBlock.padding * dpi, self.height() - 2 * OIBlock.padding * dpi, OIBlock.radius * dpi, OIBlock.radius * dpi) p.setBrush(self.title_bg()) p.drawRoundedRect(OIBlock.padding * dpi, OIBlock.padding * dpi, self.width() - 2 * OIBlock.padding * dpi, .35 * dpi + OIBlock.padding * dpi, OIBlock.radius * dpi, OIBlock.radius * dpi) p.setBrush(self.bg()) p.setPen(QColor(0, 0, 0, 0)) p.drawRect(0.01 * dpi + OIBlock.padding * dpi, 0.35 * dpi + OIBlock.padding * dpi, self.width() - 0.02 * dpi - 2 * OIBlock.padding * dpi, 0.10 * dpi) p.setPen(pen) if self._resizable: if self.__corner_path is None: self.__init_corner() p.setBrush(pen.brush()) p.drawPath( self.__corner_path.translated(self.width(), self.height())) def _paint_title(self, p: QPainter): dpi = Info.dpi p.drawLine(OIBlock.padding * dpi, 0.35 * dpi + OIBlock.padding * dpi, self.width() - (0.01 + OIBlock.padding) * dpi, 0.35 * dpi + OIBlock.padding * dpi) p.setPen(self._fg_color) f = p.font() f.setPointSize(10) f.setBold(True) p.setFont(f) p.drawText( QRectF((0.04 + OIBlock.padding) * dpi, (OIBlock.padding + .01) * dpi, self.width() - .12 * dpi, .25 * dpi), str(self.__block.name())) f.setBold(False) f.setPointSize(8) p.setPen( QColor(self._fg_color.red(), self._fg_color.green(), self._fg_color.blue(), 100)) p.setFont(f) p.drawText( QRectF((.04 + OIBlock.padding) * dpi, (.17 + OIBlock.padding) * dpi, self.width() - .12 * dpi, .15 * dpi), str(self.__block.type_name())) def __init_corner(self): path = QPainterPath() dpi = Info.dpi path.moveTo(-OIBlock.padding * 1.2 * dpi, (-.15 - OIBlock.padding * 1.2) * dpi) path.lineTo((-.15 - OIBlock.padding * 1.2) * dpi, -OIBlock.padding * 1.2 * dpi) path.lineTo(-OIBlock.padding * 1.2 * dpi, -OIBlock.padding * 1.2 * dpi) path.closeSubpath() self.__corner_path = path def _paint_nodes(self, p: QPainter): for n in self.__nodes: n.paint(p) return def _paint_content(self, p: QPainter): # nothing to do return def paintEvent(self, e: QPaintEvent): if e.isAccepted(): p = QPainter(self) self._paint(p) def _check_corner(self, pos): path = self.__corner_path.translated(self.width(), self.height()) return path.contains(pos) def _check_action(self, action): if self.__action != Action.NONE and action != Action.NONE: return False return True def _check_nodes(self, p: QPoint): for n in self.__nodes: if n.contains(p): return n return None def mousePressEvent(self, e: QMouseEvent): self.__block.select() n = self._check_nodes(e.pos()) if n is not None: print('Node found') return if e.button() == Qt.LeftButton: if self._resizable: if self._check_corner(e.pos()) and self._check_action( Action.RESIZE): self.__origin = e.pos() self.__action = Action.RESIZE self.setCursor(Qt.SizeFDiagCursor) return if self._check_action(Action.DRAG): self.__origin = e.pos() self.__action = Action.DRAG self.setCursor(Qt.DragMoveCursor) def mouseMoveEvent(self, e: QMouseEvent): if self.__action == Action.DRAG: dx = e.x() - self.__origin.x() dy = e.y() - self.__origin.y() self.set_pos(self.x() + dx, self.y() + dy) elif self.__action == Action.RESIZE: self.set_size(e.x(), e.y()) else: if self._resizable and self.__corner_path.translated( self.width(), self.height()).contains(e.pos()): self.setCursor(Qt.SizeFDiagCursor) else: self.setCursor(Qt.ArrowCursor) def mouseReleaseEvent(self, e: QMouseEvent): self.__action = Action.NONE self.setCursor(Qt.ArrowCursor) def set_size(self, w, h): w1 = w / Info.dpi h1 = h / Info.dpi W = self.__block.settings['Width'].value() H = self.__block.settings['Height'].value() if w1 < W.min: w1 = W.min elif w1 > W.max: w1 = W.max if h1 < H.min: h1 = H.min elif h1 > H.max: h1 = H.max self.__block.set_setting('Width', w1) self.__block.set_setting('Height', h1) def set_pos(self, x, y): x = x - self.__translation.x() y = y - self.__translation.y() self.__block.set_setting('X', x / Info.dpi) self.__block.set_setting('Y', y / Info.dpi) def translate(self, p): self.__translation = p self.geometry_update()
class Canvas3d(QtOpenGL.QGLWidget): MODE_EXPLORE = 0 MODE_DRAW = 1 MODE_SELECT = 2 MODE_ERASE = 3 MODE_OPERATION = 4 DRAW_POINTS = 0 DRAW_SEGMENTS = 1 DRAW_POLYGONS = 2 DRAW_POLYLINES = 3 def __init__(self, parent=None): self.parent = parent QtOpenGL.QGLWidget.__init__(self, parent) self.shader_program = None # QtOpenGL.QGLShaderProgram() self.camera = Camera( ) # initialize a camera object (initially located at the origin and facing (0, 0, -1) self.xy_grid = MyGrid() self.renderables3d = set( ) # this contains all the geometries on canvas self.selection_box = None # this contains at most 1 selection box self.last_mouse_position = QPoint( 0, 0) # last position of the mouse in viewport-coordinates self.bounding_box = Box3D(the_min=Point3(-20, -20, -20), the_max=Point3(20, 20, 20)) # the bounding_box of all the geometries in the canvas. # BUT is never smaller than the values set here! Because it is used to set the viewport in VIEW_2D mode self.mode = Canvas3d.MODE_EXPLORE # by default in "scene exploration" mode self.draw_what = None # when in MODE_DRAW, this contains an indication of what is being drawn, else None self.currently_drawn_geom = None # this maintains a reference to a geometry being drawn, until the drawing is complete self.selected_geoms = set( ) # will contain geometries in the canvas selected via the select tool self.canvas_cube_proportion = None self.setMouseTracking(True) @pyqtSlot(bool) def set_mode_explore(self, toggled): if toggled: self.mode = Canvas3d.MODE_EXPLORE @pyqtSlot(bool) def set_mode_select(self, toggled): if toggled: self.mode = Canvas3d.MODE_SELECT @pyqtSlot(bool) def set_mode_erase(self, toggled): if toggled: self.mode = Canvas3d.MODE_ERASE @pyqtSlot(bool) def set_mode_operation(self, toggled): if toggled: self.mode = Canvas3d.MODE_OPERATION @pyqtSlot(bool) def set_mode_draw_points(self, toggled): if toggled: # print("MODE: DRAW_POINTS") self.mode = Canvas3d.MODE_DRAW self.draw_what = Canvas3d.DRAW_POINTS @pyqtSlot(bool) def set_mode_draw_segments(self, toggled): if toggled: self.mode = Canvas3d.MODE_DRAW self.draw_what = Canvas3d.DRAW_SEGMENTS @pyqtSlot(bool) def set_mode_draw_polygons(self, toggled): if toggled: self.mode = Canvas3d.MODE_DRAW self.draw_what = Canvas3d.DRAW_POLYGONS @pyqtSlot(bool) def set_mode_draw_polylines(self, toggled): if toggled: self.mode = Canvas3d.MODE_DRAW self.draw_what = Canvas3d.DRAW_POLYLINES @pyqtSlot(bool) def reset_view_2d(self, toggled): GL.glDisable( GL.GL_DEPTH_TEST ) # disables the depth test (used to display only "visible" faces) GL.glDisable( GL.GL_CULL_FACE ) # disables culling (improves performance as only "visible" faces are processed) self.xy_grid.hide() # hide the grid self.camera.set_view_2d( toggled) # reset the position of the camera for 2D View self.setMouseTracking(True) self.updateGL() # update the rendered scene @pyqtSlot(bool) def reset_view_3d(self, toggled): GL.glEnable( GL.GL_DEPTH_TEST ) # enables the depth test (used to display only "visible" faces) GL.glEnable( GL.GL_CULL_FACE ) # enables culling (improves performance as only "visible" faces are processed) self.drawingEventEnd() # if we were drawing something end the drawing self.xy_grid.show() # un-hide the grid self.camera.set_view_3d( toggled) # reset the position of the camera for 3D view self.window().update_status_bar("3D VIEW") self.setMouseTracking(False) self.updateGL() # update the rendered scene @pyqtSlot() def reset_view(self): self.camera.reset_view() # reset the view self.updateGL() # update the rendered scene def mousePressEvent(self, event): # when we press a mouse button on the canvas the canvas get the keyboard focus self.setFocus() # if in drawing mode if self.mode == Canvas3d.MODE_DRAW: # drawing events are only accepted in 2D View if self.camera.view_mode == Camera.VIEW_2D: self.drawingEventAddVertex(event=event) # if we are in "selection" or "erase" mode elif self.mode == Canvas3d.MODE_SELECT or self.mode == Canvas3d.MODE_ERASE: # selection events are only accepted in 2D View if self.camera.view_mode == Camera.VIEW_2D: event_x, event_y, z = self.camera.canvas2world( event.x(), event.y()) self.selection_box = SelectionBox(Point3(event_x, event_y, 0)) # update the rendered scene self.updateGL() self.last_mouse_position = event.pos() event.accept() def mouseReleaseEvent(self, event): # if in drawing mode if self.mode == Canvas3d.MODE_DRAW: # drawing events are only accepted in 2D View if self.camera.view_mode == Camera.VIEW_2D: self.drawingEventConfirmLastVertex(event=event) # if we are in "selection" mode elif self.mode == Canvas3d.MODE_SELECT: # selection events are only accepted in 2D View if self.camera.view_mode == Camera.VIEW_2D: # select geometries inside the box before deleting it self.selected_geoms = self.selection_box.select_geometries( self.renderables3d) self.window().console_add_line("\nSELECTED SHAPES") # self.parent.parent.console_add_line("\nSELECTED SHAPES") for g in self.selected_geoms: self.window().console_add_line(str(g)) self.selection_box = None # if we are in "erase" mode elif self.mode == Canvas3d.MODE_ERASE: # erase events are only accepted in 2D View if self.camera.view_mode == Camera.VIEW_2D: # select geometries inside the box before deleting it selected_geoms = self.selection_box.select_geometries( self.renderables3d) for g in selected_geoms: self.remove_geometry(g) self.selection_box = None # update the rendered scene self.updateGL() self.last_mouse_position = event.pos() event.accept() def mouseMoveEvent(self, event): if self.camera.view_mode == Camera.VIEW_2D: x, y, z = self.camera.canvas2world(event.x(), event.y()) self.window().update_status_bar("(x, y): ({:.3f}, {:.3f})".format( x, y)) # if moving while pressing the left button if event.buttons() and event.buttons() == QtCore.Qt.LeftButton: # if in draw mode: continue drawing if self.mode == Canvas3d.MODE_DRAW: self.drawingEventMoveLastVertex(event) # if we are in "selection" or "erase" mode elif self.mode == Canvas3d.MODE_SELECT or self.mode == Canvas3d.MODE_ERASE: # selection events are only accepted in 2D View if self.camera.view_mode == Camera.VIEW_2D: event_x, event_y, z = self.camera.canvas2world( event.x(), event.y()) x, y, z = self.camera.canvas2world( self.last_mouse_position.x(), self.last_mouse_position.y()) delta_x, delta_y = event_x - x, event_y - y self.selection_box.move_corner2(Point3( delta_x, delta_y, 0)) # if in exploration mode elif self.mode == Canvas3d.MODE_EXPLORE: # if no button is held down: pan if QtGui.QApplication.keyboardModifiers( ) == QtCore.Qt.NoModifier: self.panEvent(event) # if in 3D View if self.camera.view_mode == Camera.VIEW_3D: # if the ctrl (cmd on mac) button is held down: rotate if QtGui.QApplication.keyboardModifiers( ) == QtCore.Qt.ControlModifier: self.rotateEvent(event) # update the rendered scene self.updateGL() self.last_mouse_position = event.pos() event.accept() def keyPressEvent(self, event): # if in drawing mode if self.mode == Canvas3d.MODE_DRAW: # if the escape key is pressed: cancel the current drawing if event.key() == QtCore.Qt.Key_Escape: # print("pressed Esc") self.drawingEventCancel() # if either enter or return key is pressed: end the current drawing elif event.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter): # print("pressed Enter") self.drawingEventEnd() elif event.key() == QtCore.Qt.Key_Backspace: self.drawingEventRemoveLastVertex() # update the rendered scene self.updateGL() def wheelEvent(self, event): # if scrolling vertically if event.orientation() == QtCore.Qt.Vertical: # if in exploration mode: zoom if self.mode == Canvas3d.MODE_EXPLORE: self.zoomEvent(event) # update the rendered scene self.updateGL() event.accept() def rotateEvent(self, event): delta_x = event.x() - self.last_mouse_position.x() # delta_y is computed the opposite way, because the canvas origin is at the up-left corner # with positive y-axis point downwards delta_y = self.last_mouse_position.y() - event.y() # ORBIT (i.e., rotate) the camera around the camera._target self.camera.orbit(delta_x, delta_y) def panEvent(self, event): delta_x = event.x() - self.last_mouse_position.x() # delta_y is computed the opposite way, because the canvas origin is at the up-left corner # with positive y-axis point downwards delta_y = self.last_mouse_position.y() - event.y() # PAN the scene by altering camera._target self.camera.pan(delta_x, delta_y) def zoomEvent(self, event): delta = event.delta() # if in 3D View mode, the zoom is obtained by changing the distance of the camera from the target if self.camera.view_mode == Camera.VIEW_3D: # MOVE the camera wrt its _target (change the distance to _target) self.camera.move_radial(delta) # else, the zoom is obtained by changing the size of the viewed area else: # ZOOM if delta < 0: self.camera.zoom(1.05) elif delta > 0: self.camera.zoom(0.95) x, y, z = self.camera.canvas2world(event.x(), event.y()) self.window().update_status_bar("(x, y): ({:.3f}, {:.3f})".format( x, y)) def drawingEventAddVertex(self, event): """if no geometry is being drawn, create one. add a vertex to the drawn geometry""" # only if in draw mode if self.mode == Canvas3d.MODE_DRAW: x, y, z = self.camera.canvas2world(event.x(), event.y()) new_point = Point3(x, y, z) if self.draw_what == Canvas3d.DRAW_POINTS: self.currently_drawn_geom = new_point elif self.draw_what == Canvas3d.DRAW_SEGMENTS: if self.currently_drawn_geom is None: self.currently_drawn_geom = Line() self.currently_drawn_geom.add_vertex(new_point) elif self.draw_what == Canvas3d.DRAW_POLYGONS: if self.currently_drawn_geom is None: self.currently_drawn_geom = Polygon() self.currently_drawn_geom.add_vertex(new_point) elif self.draw_what == Canvas3d.DRAW_POLYLINES: if self.currently_drawn_geom is None: self.currently_drawn_geom = LineString() self.currently_drawn_geom.add_vertex(new_point) if isinstance(self.currently_drawn_geom, Geometry): self.add_geometry(self.currently_drawn_geom) def drawingEventRemoveLastVertex(self): """if possible, remove the last vertex from the drawn geometry (depends on the type of geometry)""" # only if in draw mode if self.mode == Canvas3d.MODE_DRAW: # if a geom is being drawn if self.currently_drawn_geom is not None: # if the geometry has at least one vertex if len(self.currently_drawn_geom) > 0: self.currently_drawn_geom.remove_vertex() # if the current geom has no vertices, cancel it if len(self.currently_drawn_geom) == 0: self.drawingEventCancel() def drawingEventMoveLastVertex(self, event): """move the last drawn vertex of the currently drawn geometry""" # only if in draw mode if self.mode == Canvas3d.MODE_DRAW: if self.currently_drawn_geom is not None: x, y, z = self.camera.canvas2world(event.x(), event.y()) if self.draw_what == Canvas3d.DRAW_POINTS: self.currently_drawn_geom.set_coords(x, y, z) elif self.draw_what in (Canvas3d.DRAW_SEGMENTS, Canvas3d.DRAW_POLYGONS, Canvas3d.DRAW_POLYLINES): self.currently_drawn_geom.update_vertex(Point3(x, y, z)) def drawingEventConfirmLastVertex(self, event): """this functions does nothing, unless the drawn geometry can have at most a fixed number of vertices, in which case, end the drawing""" # only if in draw mode if self.mode == Canvas3d.MODE_DRAW: if self.currently_drawn_geom is not None: # points and segments have a limited number of vertices. When we reach this amount we end the drawing if isinstance(self.currently_drawn_geom, Point3) \ or (isinstance(self.currently_drawn_geom, Line) and len(self.currently_drawn_geom) == 2): self.drawingEventEnd() def drawingEventCancel(self): """cancel the drawing event (including the removal of the geometry drawn so far from the canvas)""" # only if in draw mode and there is a geometry being drawn if self.mode == Canvas3d.MODE_DRAW and self.currently_drawn_geom is not None: self.remove_geometry(self.currently_drawn_geom) self.currently_drawn_geom = None def drawingEventEnd(self): """ends the drawing of the geometry and prepares the canvas for a new drawing""" # only if in draw mode and there is a geometry being drawn if self.mode == Canvas3d.MODE_DRAW and self.currently_drawn_geom is not None: # if the drawn geometry is valid if not self.currently_drawn_geom.is_valid(): self.remove_geometry(self.currently_drawn_geom) self.currently_drawn_geom = None def prepare_shader_program(self, v_shader_path="", f_shader_path=""): v_shader_file = open(v_shader_path, 'r') vertex_shader_code = v_shader_file.read() v_shader_file.close() f_shader_file = open(f_shader_path, 'r') fragment_shader_code = f_shader_file.read() f_shader_file.close() if not self.shader_program: # print("The shader is None, initialize it.") self.shader_program = GL.glCreateProgram() if not self.shader_program: print("ERROR in shader PROGRAM creation") return # VERTEX SHADER # create a vertex shader vertex_shader = GL.glCreateShader(GL.GL_VERTEX_SHADER) # set shader source_vertex GL.glShaderSource(vertex_shader, vertex_shader_code) # compile shader GL.glCompileShader(vertex_shader) # FRAGMENT SHADER # create a fragment shader fragment_shader = GL.glCreateShader(GL.GL_FRAGMENT_SHADER) # set shader source_vertex GL.glShaderSource(fragment_shader, fragment_shader_code) # compile shader GL.glCompileShader(fragment_shader) # build and link the shader program given the vertex and the fragment shader GL.glAttachShader(self.shader_program, vertex_shader) GL.glAttachShader(self.shader_program, fragment_shader) GL.glLinkProgram(self.shader_program) # get rid of the shaders as 1. they have been compiled in the program, 2. we do not need them any longer GL.glDetachShader(self.shader_program, vertex_shader) GL.glDetachShader(self.shader_program, fragment_shader) # make the shader program we just compiled the default program to be run GL.glUseProgram(self.shader_program) def initializeGL(self): # set the background color (to white) self.qglClearColor(QtGui.QColor(255, 255, 255)) GL.glDepthMask(GL.GL_TRUE) GL.glEnable(GL.GL_POINT_SMOOTH ) # makes point smooth (looks approx like a sphere) GL.glPointSize(config_rendering_point_size) # size of points GL.glEnable(GL.GL_LINE_SMOOTH) GL.glLineWidth(config_rendering_line_width) GL.glFrontFace( GL.GL_CCW ) # the "front" of a face is those for which vertices are seen in CCW order # FOR TRANSPARENCY? # GL.glAlphaFunc(GL.GL_GREATER, 0.1) # GL.glEnable(GL.GL_ALPHA_TEST) # FOR TRANSPARENCY? GL.glEnable(GL.GL_BLEND) GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA) # load and link the shader program self.prepare_shader_program('shaders/vertex_shader.glsl', 'shaders/fragment_shader.glsl') def resizeGL(self, width, height): """This function is called automatically by QT when a resize event occurs. We need to resize the viewport accordingly""" # print("resizeGL") # resize the viewport GL.glViewport(0, 0, width, height) # adjust the view accordingly with the new size of the canvas self.camera.resize_view(width, height) def paintGL(self): # print("paintGL") GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT) # bind (i.e., pass) the up-to-date view matrix to the vertex shader loc = GL.glGetUniformLocation(self.shader_program, "u_view") GL.glUniformMatrix4fv(loc, 1, GL.GL_FALSE, self.camera.get_view_matrix().data()) # bind (i.e., pass) the up-to-date projection matrix to the vertex shader loc = GL.glGetUniformLocation(self.shader_program, "u_projection") GL.glUniformMatrix4fv(loc, 1, GL.GL_FALSE, self.camera.get_projection_matrix().data()) # if visible not hidden, render the xy grid (only visible in 3D mode) self.xy_grid.render(self.shader_program) # render all the geometries in the canvas for renderable in self.renderables3d: # print("Going to paint the renderable: " + str(cube.renderable_vertex_array['position'])) renderable.render(self.shader_program) if self.selection_box is not None: self.selection_box.render(self.shader_program) def add_geometry(self, *geoms): """ add a geometry to the canvas (namely to the list renderables) :param geom: the geometry to add :return: None """ for geom in geoms: self.renderables3d.add(geom) self.updateGL() def remove_geometry(self, geom): """ removes the given geometry from the canvas :param geom: the geometry to be removed :return: None """ self.renderables3d.remove(geom) self.updateGL()
class ControllerPage(QWebPage): evaljsSignalSent = pyqtSignal(str) avaljsSignalSent = pyqtSignal(str) def __init__(self, parent,contentPage,args): super(ControllerPage, self).__init__(parent) self.phantom = parent self.contentPage = contentPage self.evaljsSignalSent.connect(self.onEval) self.avaljsSignalSent.connect(self.onAval) self.mainFrame().addToJavaScriptWindowObject('page', self) self.m_scrollPosition = QPoint() self.contentFrame = self.contentPage.mainFrame() # #def shouldInterruptJavaScript(self): # QApplication.processEvents(QEventLoop.AllEvents, 42) # return False # #def javaScriptAlert(self, originatingFrame, msg): # self.parent().javaScriptAlertSent.emit(msg) # def javaScriptConsoleMessage(self, message, lineNumber, sourceID): self.parent().javaScriptConsoleMessageSent.emit(message, lineNumber, sourceID) def onEval(self,data): a = unicode(data).split(" ",1) if ( len(a) != 2 ): self.phantom.error("EVAL format error len(a)=%d" % len(a)) else: (eid,cmd) = a self.lastError = None javascript = "try { %s } catch(e) {page.setLastError(e);}" % cmd retVal = self.mainFrame().evaluateJavaScript(javascript).toPyObject() if self.lastError: self.phantom.errret(eid,self.lastError) else: self.phantom.ret(eid,retVal) def onAval(self,data): a = unicode(data).split(" ",1) if ( len(a) != 2 ): self.phantom.error("EVAL format error len(a)=%d" % len(a)) else: (eid,cmd) = a self.lastError = None javascript = "try { var AVAL=function (eid){ %s };AVAL(%s); } catch(e) {page.setLastError(e);}" % (cmd,eid) retVal = self.mainFrame().evaluateJavaScript(javascript).toPyObject() if self.lastError: self.phantom.errret(eid,self.lastError) #else: # self.phantom.ret(eid,retVal) @pyqtSlot(str, result='QVariant') def setLastError(self, code): self.lastError = code return None @pyqtSlot(str, result='QVariant') def render(self,fname): contentsSize = self.contentFrame.contentsSize() contentsSize -= QSize(self.m_scrollPosition.x(), self.m_scrollPosition.y()) frameRect = QRect(QPoint(0, 0), contentsSize) #if not self.m_clipRect.isEmpty(): # frameRect = self.m_clipRect viewportSize = self.contentPage.viewportSize() self.contentPage.setViewportSize(contentsSize) image = QImage(frameRect.size(), QImage.Format_ARGB32) image.fill(qRgba(255, 255, 255, 0)) painter = QPainter() # We use tiling approach to work-around Qt software rasterizer bug # when dealing with very large paint device. # See http://code.google.com/p/phantomjs/issues/detail?id=54. tileSize = 4096 htiles = (image.width() + tileSize - 1) / tileSize vtiles = (image.height() + tileSize - 1) / tileSize for x in range(htiles): for y in range(vtiles): tileBuffer = QImage(tileSize, tileSize, QImage.Format_ARGB32) tileBuffer.fill(qRgba(255, 255, 255, 0)) # Render the web page onto the small tile first painter.begin(tileBuffer) painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHint(QPainter.TextAntialiasing, True) painter.setRenderHint(QPainter.SmoothPixmapTransform, True) painter.translate(-frameRect.left(), -frameRect.top()) painter.translate(-x * tileSize, -y * tileSize) self.contentFrame.render(painter, QRegion(frameRect)) painter.end() # Copy the tile to the main buffer painter.begin(image) painter.setCompositionMode(QPainter.CompositionMode_Source) painter.drawImage(x * tileSize, y * tileSize, tileBuffer) painter.end() self.contentPage.setViewportSize(viewportSize) image.save(fname) return True #@pyqtSlot(str, str,result='QVariant') @pyqtSlot(str,result='QVariant') def evaluateJavaScript(self, code): #args = [] #for arg in arguments: # arg = arg.toPyObject() # tp = type(arg).__name__ # print arg,tp # if tp == 'float': # arg = unicode(arg) # elif tp == "NoneType": # arg = "null" # elif tp == "QString": # arg = unicode('"' + arg.replace("\"","\\\"") +'"') # else: # self.error("unkwnon type %s" % tp) # self.lastError = "unkwnon type %s" % tp # return # args.append(arg) # #args = ",".join(args) function = '(%s)()' % ( code) self.phantom.debug("EVAL " + function) ret = self.contentPage.mainFrame().evaluateJavaScript(function) return ret @pyqtSlot() def stop(self): self.contentPage.triggerAction(QWebPage.Stop) @pyqtSlot(str, 'QVariant', 'QVariant') def sendEvent(self, type_, arg1, arg2): type_ = str(type_).lower() if type_ in ('mousedown', 'mouseup', 'mousemove'): if type(arg1).__name__ == "QVariant": arg1 = arg1.toInt()[0] if type(arg2).__name__ == "QVariant": arg2 = arg2.toInt()[0] eventType = QMouseEvent.Type(QEvent.None) button = Qt.MouseButton(Qt.LeftButton) buttons = Qt.MouseButtons(Qt.LeftButton) if type_ == 'mousedown': eventType = QEvent.MouseButtonPress elif type_ == 'mouseup': eventType = QEvent.MouseButtonRelease elif type_ == 'mousemove': eventType = QEvent.MouseMove button = buttons = Qt.NoButton assert eventType != QEvent.None event = QMouseEvent(eventType, QPoint(arg1, arg2), button, buttons, Qt.NoModifier) QApplication.postEvent(self.contentPage, event) QApplication.processEvents() return if type_ == 'click': if type(arg1).__name__ == "QVariant": arg1 = arg1.toInt()[0] if type(arg2).__name__ == "QVariant": arg2 = arg2.toInt()[0] self.sendEvent('mousedown', arg1, arg2) self.sendEvent('mouseup', arg1, arg2) return if type_ == 'keypress': if type(arg1).__name__ == "QVariant": arg1 = str(arg1.toPyObject()) #if type(arg2).__name__ == "QVariant": # arg2 = Qt.KeyboardModifiers(arg2.toInt()[0]) for c in arg1: if c.islower(): self.sendEvent('keydown', QVariant(c), QVariant(0)) self.sendEvent('keyup', QVariant(c), QVariant(0)) else: self.sendEvent('keydown', QVariant(c), QVariant(0x02000000)) self.sendEvent('keyup', QVariant(c), QVariant(0x02000000)) return if type_ in ('keydown', 'keyup' ): if type_ == "keydown": keyEventType = QKeyEvent.KeyPress else: keyEventType = QKeyEvent.KeyRelease if type(arg1).__name__ == "QVariant": text = QString(arg1.toString().at(0)) key = text.at(0).toUpper().unicode() else: key = arg1 text = arg1 if type(arg2).__name__ == "QVariant": arg2 = Qt.KeyboardModifiers(arg2.toInt()[0]) event = QKeyEvent(keyEventType, key, arg2,text) QApplication.postEvent(self.contentPage, event) QApplication.processEvents() @pyqtProperty('QVariantMap') def viewportSize(self): vps = self.contentPage.viewportSize() result = { 'height': vps.height(), 'width': vps.width() } return result @pyqtProperty('QVariantMap') def scrollPosition(self): scroll = self.m_scrollPosition result = { 'left': scroll.x(), 'top': scroll.y() } return result @scrollPosition.setter def scrollPosition(self, size): positions = {'left': 0, 'top': 0} for item in positions: try: positions[item] = int(size[item]) if positions[item] < 0: positions[item] = 0 except (KeyError, ValueError): positions[item] = self.scrollPosition[item] self.m_scrollPosition = QPoint(positions['left'], positions['top']) self.m_mainFrame.setScrollPosition(self.m_scrollPosition)
class ThresholdingInterpreter( QObject ): # states FINAL = 0 DEFAULT_MODE = 1 # normal navigation functionality THRESHOLDING_MODE = 2 # while pressing left mouse button allow thresholding NO_VALID_LAYER = 3 # not a grayscale layer @property def state( self ): return self._current_state def __init__( self, navigationController, layerStack, posModel ): QObject.__init__( self ) self._navCtrl = navigationController self._navIntr = NavigationInterpreter( navigationController ) self._layerStack = layerStack self._active_layer = None self._active_channel_idx = -1 self._current_state = self.FINAL self._current_position = QPoint(0,0) # Setting default values, scaled on actual data later on self._steps_mean = 10 self._steps_delta = self._steps_mean*2 self._steps_scaling = 0.07 self._range_max = 4096.0 # hardcoded, in the case drange is not set in the data file or in the dataSelectionDialogue self._range_min = -4096.0 self._range = np.abs(self._range_max-self._range_min) self._channel_range = dict() self._posModel = posModel def start( self ): if self._current_state == self.FINAL: self._navIntr.start() self._current_state = self.DEFAULT_MODE self._init_layer() else: pass def stop( self ): self._current_state = self.FINAL if self.valid_layer(): self._active_layer.channelChanged.disconnect(self.channel_changed) self._navIntr.stop() def eventFilter( self, watched, event ): etype = event.type() if self._current_state == self.DEFAULT_MODE: if etype == QEvent.MouseButtonPress \ and event.button() == Qt.LeftButton \ and event.modifiers() == Qt.NoModifier \ and self._navIntr.mousePositionValid(watched, event): # TODO maybe remove, if we can find out which view is active self.set_active_layer() if self.valid_layer(): self._current_state = self.THRESHOLDING_MODE self._current_position = watched.mapToGlobal( event.pos() ) return True else: self._current_state = self.NO_VALID_LAYER return self._navIntr.eventFilter( watched, event ) elif etype == QEvent.MouseButtonPress \ and event.button() == Qt.RightButton \ and event.modifiers() == Qt.NoModifier \ and self._navIntr.mousePositionValid(watched, event): self.set_active_layer() if self.valid_layer(): self.onRightClick_resetThreshold(watched, event) else: pass # do nothing return True else: return self._navIntr.eventFilter( watched, event ) elif self._current_state == self.NO_VALID_LAYER: self.set_active_layer() if self.valid_layer(): self._current_state = self.DEFAULT_MODE return self._navIntr.eventFilter( watched, event ) elif self._current_state == self.THRESHOLDING_MODE: if self._active_layer == None: # No active layer set, should not go here return self._navIntr.eventFilter( watched, event ) if etype == QEvent.MouseButtonRelease and event.button() == Qt.LeftButton: self._current_state = self.DEFAULT_MODE self._active_layer = None self.onExit_threshold( watched, event ) return True elif etype == QEvent.MouseMove and event.buttons() == Qt.LeftButton: self.onMouseMove_thresholding(watched, event) return True else: return self._navIntr.eventFilter( watched, event ) else: # let the navigation interpreter handle common events return self._navIntr.eventFilter( watched, event ) def onRightClick_resetThreshold(self, imageview, event): range = self.get_min_max_of_current_view(imageview) self._active_layer.set_normalize(0, (range[0],range[1])) self._channel_range[self._active_channel_idx] = (range[0],range[1]) def set_active_layer(self): """ determines the layer postion in the stack and the currently displayed channel. Needs to be called constantly, because the user can change the position of the input layer within the stack """ for idx, layer in enumerate(self._layerStack): if isinstance(layer, GrayscaleLayer): if layer.window_leveling: self._active_layer = layer self._active_channel_idx= layer._channel return self._active_layer = None def _init_layer(self): self.set_active_layer() if self.valid_layer(): self._active_layer.channelChanged.connect(self.channel_changed) if self.get_drange() != None: self._range_min, self._range_max = self.get_drange() def onExit_threshold( self, watched, event ): pass def get_drange(self): """ returns tuple of drange (min, max) as set in hdf5 file or None if nothing is specified """ return self._active_layer._datasources[0]._rawSource._op5.Output.meta.drange def valid_layer(self): if isinstance(self._active_layer, GrayscaleLayer): return self._active_layer.window_leveling else: return False def channel_changed(self): self.set_active_layer() if self._active_channel_idx in self._channel_range: self._active_layer.set_normalize(0, self._channel_range[self._active_channel_idx]) else: self._active_layer.set_normalize(0,(self._range_min, self._range_max)) def get_min_max_of_current_view(self, imageview): """ Function returns min and max value of the current view based on the raw data. Ugly hack, but all we got for now """ shape2D = posView2D( list(self._posModel.shape5D[1:4]), axis=self._posModel.activeView ) data_x, data_y = 0, 0 data_x2, data_y2 = shape2D[0], shape2D[1] if self._posModel.activeView == 0: x_pos = self._posModel.slicingPos5D[1] slicing = [slice(0, 1), slice(x_pos, x_pos+1), slice(data_x, data_x2), slice(data_y, data_y2), slice(self._active_channel_idx, self._active_channel_idx+1)] if self._posModel.activeView == 1: y_pos = self._posModel.slicingPos5D[2] slicing = [slice(0, 1), slice(data_x, data_x2), slice(y_pos, y_pos+1), slice(data_y, data_y2), slice(self._active_channel_idx, self._active_channel_idx+1)] if self._posModel.activeView == 2: z_pos = self._posModel.slicingPos5D[3] slicing = [slice(0, 1), slice(data_x, data_x2), slice(data_y, data_y2), slice(z_pos, z_pos+1), slice(self._active_channel_idx, self._active_channel_idx+1)] request = self._active_layer._datasources[0].request(slicing) result = request.wait() return result.min(), result.max() def onMouseMove_thresholding(self, imageview, event): if self._active_channel_idx not in self._channel_range: range = self.get_min_max_of_current_view(imageview) range_lower = range[0] range_upper = range[1] else: range = self._channel_range[self._active_channel_idx] range_lower = range[0] range_upper = range[1] # don't know what version is more efficient # range_delta = np.sqrt((range_upper - range_lower)**2) range_delta = np.abs(range_upper - range_lower) range_mean = range_lower + range_delta/2.0 self._steps_mean = range_delta * self._steps_scaling self._steps_delta = self._steps_mean * 2 pos = imageview.mapToGlobal( event.pos() ) dx = pos.x() - self._current_position.x() dy = self._current_position.y() - pos.y() if dx > 0.0: # move mean to right range_mean += self._steps_mean elif dx < 0.0: # move mean to left range_mean -= self._steps_mean if dy > 0.0: # increase delta range_delta += self._steps_delta elif dy < 0.0: # decrease delta range_delta -= self._steps_delta # check the bounds, ugly use min max values actually present if range_mean < self._range_min: range_mean = self._range_min elif range_mean > self._range_max: range_mean = self._range_max if range_delta < 1: range_delta = 1 elif range_delta > self._range: range_delta = self._range a = range_mean - range_delta/2.0 b = range_mean + range_delta/2.0 if a < self._range_min: a = self._range_min elif a > self._range_max: a = self._range_max if b < self._range_min: b = self._range_min elif b > self._range_max: b = self._range_max assert a <= b # TODO test if in allowed range (i.e. max and min of data) self._active_layer.set_normalize(0, (a,b)) self._channel_range[self._active_channel_idx] = (a,b) self._current_position = pos
def calculateRoute(self): """ Calculates the route and stores all route points in internal list. If start and end points have not changed since last last calculation, the route wont be recalculated unless forceRouteRecalculation() was called before. If route was recalculated function returns True otherwise False. """ if not self._recalculateRouteFlag and self._route != None and len( self._route) > 1: if self._route[0] == self.sourcePoint() and self._route[ len(self._route) - 1] == self.targetPoint(): # Nothing has changed, so route not recalculated return False # Recaclucating route # Whenever the start directions point at each other, the connection has to go through the center of the points throughCenter = False rowKind = False columnKind = False sourceDirection = self.sourceDirection() targetDirection = self.targetDirection() if self._type == "ORTHOGONAL": if sourceDirection == self.ConnectionDirection.RIGHT and targetDirection == self.ConnectionDirection.LEFT: throughCenter = True rowKind = True elif sourceDirection == self.ConnectionDirection.LEFT and targetDirection == self.ConnectionDirection.RIGHT: throughCenter = True rowKind = True elif sourceDirection == self.ConnectionDirection.DOWN and targetDirection == self.ConnectionDirection.UP: throughCenter = True columnKind = True elif sourceDirection == self.ConnectionDirection.UP and targetDirection == self.ConnectionDirection.DOWN: throughCenter = True columnKind = True self._route = [] sP = QPoint(self.sourcePoint()) # start eP = QPoint(self.targetPoint()) # end self._route.append(sP) if throughCenter: # ORTHOGONAL centerP = (sP + eP) * 0.5 firstP = self.nextPointByDistance( self._route, self.CONNECTOR_LENGTH * self.zoomFactor(), sourceDirection) lastP = self.getPointByDistance( eP, self.CONNECTOR_LENGTH * self.zoomFactor(), targetDirection) self._route.append(firstP) if rowKind: #if lastP.x() - firstP.x() > self.CONNECTOR_LENGTH * self.zoomFactor() * 0.5: if eP.x() - sP.x() > (self.CONNECTOR_LENGTH + 1) * self.zoomFactor() * 2: self._route.append( self.nextPointByTarget( self._route, centerP, self.DrawOrientation.HORIZONTAL)) #self._route.append(centerP) self._route.append( self.nextPointByTarget(self._route, lastP, self.DrawOrientation.VERTICAL)) else: self._route.append( self.nextPointByTarget(self._route, centerP, self.DrawOrientation.VERTICAL)) #self._route.append(centerP) self._route.append( self.nextPointByTarget( self._route, lastP + QPoint( -self.CONNECTOR_LENGTH * self.zoomFactor(), 0), self.DrawOrientation.HORIZONTAL)) #self._route.append(self.nextPointByDistance(self._route, self.CONNECTOR_LENGTH * self.zoomFactor() , self.targetDirection())) self._route.append( self.nextPointByTarget(self._route, lastP, self.DrawOrientation.VERTICAL)) elif columnKind: #print " columnKind" route.append( self.nextPointByTarget(self._route, centerP, self.DrawOrientation.VERTICAL)) route.append(centerP) route.append( self.nextPointByTarget(self._route, lastP, self.DrawOrientation.HORIZONTAL)) else: logging.error( "PointToPointConnection.calculateRoute() - Sorry connections going through the center have to be either rowKind or columKind." ) self._route.append(lastP) else: # STRAIGHT or DIAGONAL if self._type == "DIAGONAL": width = abs(sP.x() - eP.x()) height = abs(sP.y() - eP.y()) if width > 0: directionX = (sP.x() - eP.x()) / width else: directionX = 0 if height > 0: directionY = (sP.y() - eP.y()) / height else: directionY = 0 if width > height: diagonal = height / 2 else: diagonal = width / 2 self._route.append( QPoint(sP.x() - directionX * diagonal, sP.y() - directionY * diagonal)) self._route.append( QPoint(sP.x() - directionX * (width - diagonal), sP.y() - directionY * (height - diagonal))) self._route.append(eP) self._recalculateRouteFlag = False return True
class MSGLCanvas2D(QGLWidget): """ Canvas GL plotting in 2 dimensions """ MAX = 100. corner_ = 100.0 zoom_ = 1.5 xrot_ = 220 yrot_ = 220 trans_x_ = 0.0 trans_y_ = 0.0 def __init__(self, data, parent=None, **kw): """ Constructor, initialization """ QGLWidget.__init__(self, parent) self.setFormat(QGLFormat(QGL.SampleBuffers)) self.setMinimumSize(500, 300) #300 self.setMouseTracking(True) self.setFocusPolicy(Qt.StrongFocus) self.data = data vertexes = [] colors = [] from utils.misc import IceAndFire maxY = max(map(max, [log10(el.y_data) for el in data])) maxX = max(map(max, [el.x_data for el in data])) rtmax = max([z.rtmin for z in data]) for el in data: for i, x in enumerate(el.x_data): c = IceAndFire.getQColor(log10(el.y_data[i]) / maxY) colors.append(c) vertexes.append([(x * 2 * self.corner_) / maxX, (el.rt * 2 * self.corner_) / rtmax]) from OpenGL.arrays.vbo import VBO self.vertexes = VBO(array(vertexes, 'f')) self.colors = VBO(array(colors, 'f')) self.mode = "None" # "ZOOMING", "PANNING", "NONE" self.lastpos = QPoint() self.counter_trans_x = 0 self.counter_trans_y = 0 self.defaultColors = { 'ticks': (0., 0., 0., 0.), 'axes': (0., 0., 0., 0.), 'curves': (0., 0., 1., 0.), 'backgroundColor': (1., 1., 1., 1.) } #self.axes=self.drawAxes() self.transformationMatrix = self.setupTransformationMatrix( self.width(), self.height()) def setupTransformationMatrix(self, w, h): """ use a matrix to translate in the gl landmark """ m = QMatrix() m.translate(-w / 2, h / 2) m.scale(300. / w, 300. / h) print w, h, w / 300., 1 - ((h / 300) - 1) #m.scale((self.width()*100)/300, -(self.height()*100)/300) #self.currentSize.x = w #self.currentSize.y = h return m def inGLCoordinate(self, point): return self.transformationMatrix.map(point) def resizeGL(self, w, h): """ called when window is being resized """ glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_ * self.zoom_, self.corner_ * self.zoom_, -self.corner_ * self.zoom_, self.corner_ * self.zoom_) #self.transformationMatrix = self.setupTransformationMatrix(w, h) glMatrixMode(GL_MODELVIEW) def initializeGL(self): """needed, initialize GL parameters""" #glClearColor(1.,1.,1.,1.) glDisable(GL_DEPTH_TEST) glEnable(GL_LINE_SMOOTH) glEnable(GL_POINT_SMOOTH) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) glLoadIdentity() #model view by default # self.grid_lines = self.drawGridLines() # self.ticks =self.drawAxisTick() # self.axes = self.drawAxes() def paintGL(self): """Draw the scene, needed, called each time glDraw""" glClear(GL_COLOR_BUFFER_BIT) glTranslated(self.trans_x_, self.trans_y_, 0.) #addition glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_ * self.zoom_, self.corner_ * self.zoom_, -self.corner_ * self.zoom_, self.corner_ * self.zoom_) glMatrixMode(GL_MODELVIEW) #end addition #glCallList(self.grid_lines) #glCallList(self.ticks) #glCallList(self.axes) glLineWidth(30.0) self.scatterPlot() # if self.flags == "chrom": # self.drawAxisLegend("retention time[s]", "intensity[%]") # glCallList(self.lines) # elif self.flags == "spectrum": # self.drawAxisLegend("m/z", "intensity") def drawAxes(self, width=2., colour=(0., 0., 0.)): """ Draw Axes """ #width must be a float axes = glGenLists(1) glNewList(axes, GL_COMPILE) glLineWidth(width) glColor(colour[0], colour[1], colour[2]) glBegin(GL_LINES) #x_achse glVertex2d(-self.corner_, -self.corner_) glVertex2d(self.corner_, -self.corner_) #y-achse glVertex2d(-self.corner_, -self.corner_) glVertex2d(-self.corner_, self.corner_) glEnd() glEndList() return axes def drawLegends(self, pos): """ draw legend at the specified position """ pass def drawAxisLegend(self, x_label, y_label): """ Draw Axis Legend """ font = QFont("Typewriter") #RT axis legend font.setPixelSize(12) self.renderText(self.corner_, -self.corner_ - 20.0, 0., x_label) # font self.renderText(-self.corner_ - 20.0, self.corner_, 0., y_label, font) def resetTranslations(self): """ reset the different translation to 0 """ self.trans_x_ = 0. self.trans_y_ = 0. self.counter_trans_x = 0. self.counter_trans_y = 0. def normalizeAngle(self, angle): while (angle < 0): angle += 360 * 16 while (angle > 360 * 16): angle -= 360 * 16 ########DRAWING METHODS################################################## def drawLine(self, point_, point): glBegin(GL_LINES) glVertex2d(point_.x(), point_.y()) glVertex2d(point.x(), point.y()) glEnd() def drawRect(self, p_1, p_2, p_3=None, p_4=None): pass def drawOnePoint(self, point, colour=Qt.yellow): pass def scatterPlot(self): """ Draw Data (x, y)""" if self.vertexes is not None and self.colors is not None: self.vertexes.bind() glEnableClientState(GL_VERTEX_ARRAY) glVertexPointerf(self.vertexes) self.colors.bind() glEnableClientState(GL_COLOR_ARRAY) glColorPointerf(self.colors) glDrawArrays(GL_LINES, 0, len(self.vertexes)) self.vertexes.unbind() self.colors.unbind() #self.textures.unbind() glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) def spectrumPlot(self, points): pass def histogramPlot(self, points, bin=5.): pass def barPlot(points, width=2.): pass ########MOUSE AND KEYBOARDS EVENTS########################################################################### def wheelEvent(self, event): if event.delta() > 0: self.zoom_ -= .05 else: self.zoom_ += .05 glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_ * self.zoom_, self.corner_ * self.zoom_, -self.corner_ * self.zoom_, self.corner_ * self.zoom_) self.updateGL() glMatrixMode(GL_MODELVIEW) event.accept() def keyPressEvent(self, event): if event.key() == Qt.Key_Plus: self.zoom_ -= .1 glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_ * self.zoom_, self.corner_ * self.zoom_, -self.corner_ * self.zoom_, self.corner_ * self.zoom_) glMatrixMode(GL_MODELVIEW) if event.key() == Qt.Key_Minus: self.zoom_ += .1 glMatrixMode(GL_PROJECTION) #// You had GL_MODELVIEW glLoadIdentity() gluOrtho2D(-self.corner_ * self.zoom_, self.corner_ * self.zoom_, -self.corner_ * self.zoom_, self.corner_ * self.zoom_) glMatrixMode(GL_MODELVIEW) if event.key() == Qt.Key_Up: self.trans_y_ += 2 self.counter_trans_y += 2 if event.key() == Qt.Key_Down: self.trans_y_ -= 2 self.counter_trans_y -= 2 if event.key() == Qt.Key_Left: self.trans_x_ -= 2 self.counter_trans_x -= 2 if event.key() == Qt.Key_Right: self.trans_x_ += 2 self.counter_trans_x += 2 if event.key() == Qt.Key_Z: self.mode = "ZOOMING" if self.counter_trans_x < 0 and self.counter_trans_y < 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x += 1 self.counter_trans_y += 1 if self.counter_trans_x > 0 and self.counter_trans_y < 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x -= 1 self.counter_trans_y += 1 if self.counter_trans_x < 0 and self.counter_trans_y > 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x += 1 self.counter_trans_y -= 1 if self.counter_trans_x < 0 and self.counter_trans_y > 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x -= 1 self.counter_trans_y -= 1 if self.zoom_ != 1.5: self.zoom = 1.5 #self.updateGL() self.updateGL() self.resetTranslations() def mousePressEvent(self, event): if self.mode == "ZOOMING": self.mode = "None" self.computeSelection() else: self.lastpos = QPoint(event.pos()) self.setCursor(QCursor(Qt.ClosedHandCursor)) #if event.buttons() == Qt.RightButton: # self.mode = "PANNING" def computeSelection(self): print "selected" def mouseMoveEvent(self, event): dx = event.x() - self.lastpos.x() dy = event.y() - self.lastpos.y() if self.mode == "ZOOMING": font = QFont("Typewriter") self.renderText(-self.corner_ - 30.0, self.corner_, 0., "ZOOMING MODE ACTIVATED", font) self.updateGL() glColor(0., 0., 1., .5) XMAX = 900. XMIN = 180. pointer_x = (self.lastpos.x() * 200.) / XMAX norm_dx = (dx * 200.) / XMAX """ if pointer_x > 100. or pointer_x < 100. \ or norm_dx >100. or norm_dx<-100.: event.ignore() """ glBegin(GL_QUADS) glVertex2d(pointer_x, -100.) glVertex2d(pointer_x + norm_dx, -100.) glVertex2d(pointer_x + norm_dx, 100.) glVertex2d(pointer_x, 100.) glEnd() self.updateGL() #update for seeing the rectangle mapping = self.mapFromGlobal cursorPos = self.inGLCoordinate(mapping(self.cursor().pos())) QToolTip.showText(self.cursor().pos(), "x:"+str(cursorPos.x())+ \ ", y:"+str(cursorPos.y()) ) if self.mode == "None": if event.buttons() == Qt.LeftButton: self.trans_y_ -= dy / 5 self.counter_trans_y -= dy / 5 self.trans_x_ += dx / 5 self.counter_trans_x += dx / 5 self.lastpos = QPoint(event.pos()) self.glDraw() self.resetTranslations() def mouseReleaseEvent(self, event): self.setCursor(QCursor(Qt.ArrowCursor))
def calculateRoute(self): """ Calculates the route and stores all route points in internal list. If start and end points have not changed since last last calculation, the route wont be recalculated unless forceRouteRecalculation() was called before. If route was recalculated function returns True otherwise False. """ if not self._recalculateRouteFlag and self._route != None and len(self._route) > 1: if self._route[0] == self.sourcePoint() and self._route[len(self._route) - 1] == self.targetPoint(): # Nothing has changed, so route not recalculated return False # Recaclucating route # Whenever the start directions point at each other, the connection has to go through the center of the points throughCenter = False rowKind = False columnKind = False sourceDirection = self.sourceDirection() targetDirection = self.targetDirection() if self._type == "ORTHOGONAL": if sourceDirection == self.ConnectionDirection.RIGHT and targetDirection == self.ConnectionDirection.LEFT: throughCenter = True rowKind = True elif sourceDirection == self.ConnectionDirection.LEFT and targetDirection == self.ConnectionDirection.RIGHT: throughCenter = True rowKind = True elif sourceDirection == self.ConnectionDirection.DOWN and targetDirection == self.ConnectionDirection.UP: throughCenter = True columnKind = True elif sourceDirection == self.ConnectionDirection.UP and targetDirection == self.ConnectionDirection.DOWN: throughCenter = True columnKind = True self._route = [] sP = QPoint(self.sourcePoint()) # start eP = QPoint(self.targetPoint()) # end self._route.append(sP) if throughCenter: # ORTHOGONAL centerP = (sP + eP) * 0.5 firstP = self.nextPointByDistance(self._route, self.CONNECTOR_LENGTH * self.zoomFactor(), sourceDirection) lastP = self.getPointByDistance(eP, self.CONNECTOR_LENGTH * self.zoomFactor() , targetDirection) self._route.append(firstP) if rowKind: #if lastP.x() - firstP.x() > self.CONNECTOR_LENGTH * self.zoomFactor() * 0.5: if eP.x() - sP.x() > (self.CONNECTOR_LENGTH +1) * self.zoomFactor() * 2: self._route.append(self.nextPointByTarget(self._route, centerP, self.DrawOrientation.HORIZONTAL)) #self._route.append(centerP) self._route.append(self.nextPointByTarget(self._route, lastP, self.DrawOrientation.VERTICAL)) else: self._route.append(self.nextPointByTarget(self._route, centerP, self.DrawOrientation.VERTICAL)) #self._route.append(centerP) self._route.append(self.nextPointByTarget(self._route, lastP +QPoint(-self.CONNECTOR_LENGTH * self.zoomFactor(), 0), self.DrawOrientation.HORIZONTAL)) #self._route.append(self.nextPointByDistance(self._route, self.CONNECTOR_LENGTH * self.zoomFactor() , self.targetDirection())) self._route.append(self.nextPointByTarget(self._route, lastP, self.DrawOrientation.VERTICAL)) elif columnKind: #print " columnKind" route.append(self.nextPointByTarget(self._route, centerP, self.DrawOrientation.VERTICAL)) route.append(centerP) route.append(self.nextPointByTarget(self._route, lastP, self.DrawOrientation.HORIZONTAL)) else: logging.error("PointToPointConnection.calculateRoute() - Sorry connections going through the center have to be either rowKind or columKind.") self._route.append(lastP) else: # STRAIGHT or DIAGONAL if self._type == "DIAGONAL": width = abs(sP.x() - eP.x()) height = abs(sP.y() - eP.y()) if width > 0: directionX = (sP.x() - eP.x()) / width else: directionX = 0 if height > 0: directionY = (sP.y() - eP.y()) / height else: directionY = 0 if width > height: diagonal = height / 2 else: diagonal = width / 2 self._route.append(QPoint(sP.x() - directionX * diagonal, sP.y() - directionY * diagonal)) self._route.append(QPoint(sP.x() - directionX * (width - diagonal), sP.y() - directionY * (height - diagonal))) self._route.append(eP) self._recalculateRouteFlag = False return True
class OGLViewer (QGLWidget): ''' OpenGL viewer class ''' def __init__ (self, parent = None): ''' Viewer's Constructor ''' frmt = QGLFormat () frmt.setSampleBuffers (True) super (OGLViewer, self).__init__ (frmt, parent) #self.setMouseTracking (True) self.__mouse = QCursor () self.setCursor (Qt.OpenHandCursor) self.setFocusPolicy (Qt.ClickFocus) self.__Ctrl_or_Meta_key_pressed = False self.__Alt_key_pressed = False self.__w = 720 self.__h = 450 self._init_camera_vars () self._init_objec_vars () # matrix changed signal. The signal's payload is the matrix itself. self.__GLMatrixChanged = SIGNAL ("MatrixChanged (PyQt_PyObject)") self.__compo_light_pos = QVector3D (.3,.2,.1) self.__AmbientMaterial = QVector3D ( .2, .2, .2) def _init_camera_vars (self): ''' static method. It initializes the math variables. ''' self.__compo_mtools = MathTools.Tools () self.__curr_angles = QPoint (0,0) self.__last_pos = QPoint (0,0) self.__delta = QPoint (0,0) self.__orig = QVector3D (0.0, 0.0, 0.0) self.__cam_dist = 0.0 self.__z_near = 0.1 self.__z_far = 2000.0 self.__fovy = 45.0 self.__angle = self.__compo_mtools.getAngle (self.__fovy) self.__norm_mtx = QMatrix4x4 () #(GLdouble * 16)() self.__norm_mtx.setToIdentity () self.__mtx = QMatrix4x4 () #(GLdouble * 16)() self.__mtx.setToIdentity () self.__aspect_ratio = float(self.__w)/float(self.__h) self.__camera_list = [] def _init_objec_vars (self): self.__arrows_list = [] self.__arrow_len = 2.0 self.__lines_list = [] self.__l_param = 200.0 self.__intersections_list = [] self.__poly_model = None self.__poly_list = [] # by polygon I mean triangle. def initializeGL (self): ''' usual OpenGL method ''' glClearColor (0.93, 0.93, 0.93, 1.0) glClearDepth (1.0) glMatrixMode (GL_PROJECTION) glLoadIdentity() gluPerspective (self.__fovy, float(self.__w)/float(self.__h), self.__z_near, self.__z_far) self.refreshMatrices () def resizeGL (self, w, h): ''' usual OpenGL method ''' self.__w = w self.__h = h self.__aspect_ratio = float (self.__w)/float(self.__h) glMatrixMode (GL_MODELVIEW) glLoadIdentity () gluPerspective (self.__fovy, self.__aspect_ratio, self.__z_near, self.__z_far) glViewport (0, 0, self.__w, self.__h) gluLookAt (0, 0,-1, # CameraPos 0, 0 ,0, # CameraLookAt 0, 1 ,0) # CameraUp def paintGL (self): ''' usual OpenGL method ''' self.__delta = QPoint (0,0) q = self.__mouse.pos() if self.__Ctrl_or_Meta_key_pressed ^ self.__Alt_key_pressed: # xor (strictly one or the other) if self.__Ctrl_or_Meta_key_pressed: # rotation self.__delta = q - self.__last_pos else: # translation # transform mouse deltas and camera's local axes so that it'll look like as if the camera gets # translated based on the local axes x and y. What really happens is that the origin shifts along. # The resulting behaviour reminds of the Maya Camera Track Tool. d_x = q.x() - self.__last_pos.x() d_y = q.y() - self.__last_pos.y() zero = 0.0 #GLdouble (0.0) m_ref = self.__mtx.data () # retrieves the 16 items in this matrix and copies them to values in row-major order. vec_x = - m_ref[0]*d_x + m_ref[4]*d_y + zero*m_ref[8] vec_y = - m_ref[1]*d_x + m_ref[5]*d_y + zero*m_ref[9] vec_z = - m_ref[2]*d_x + m_ref[6]*d_y + zero*m_ref[10] mult = 0.03 self.__orig.setX (self.__orig.x() + mult*vec_x) self.__orig.setY (self.__orig.y() + mult*vec_y) self.__orig.setZ (self.__orig.z() + mult*vec_z) # fire signal after done changing the model matrix. self.emit (self.__GLMatrixChanged, self.__mtx) self.__last_pos = q self.__curr_angles += self.__delta if glCheckFramebufferStatus (GL_FRAMEBUFFER) == 36053: # 36053 = GL_FRAMEBUFFER_COMPLETE glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity () # Set the camera orientation : glMatrixMode (GL_MODELVIEW) glLoadIdentity () gluLookAt (self.__orig.x(), self.__orig.y(), self.__orig.z() - 40, # CameraPos self.__orig.x(), self.__orig.y(), self.__orig.z(), # CameraLookAt 0.0, 1.0, 1.0) # CameraUp # Rotate and move camera forward or backward. glTranslatef (0, 0, -self.__cam_dist) glTranslatef (self.__orig.x(), self.__orig.y(), self.__orig.z()) # rotation around current origin. glRotatef (-30 - self.__curr_angles.y() * 0.15, 1, 0, 0) # rotate around axis x. glRotatef (-30 + self.__curr_angles.x() * 0.1, 0, 1, 0) # rotate around axis y. glTranslatef (-self.__orig.x(), -self.__orig.y(), -self.__orig.z()) # rotation around current origin. self.refreshMatrices () self.displayObjects () self.displayArrows () self.displayLines () self.displayIntersections () self.drawGrid () self.drawFixedOriginAxes () self.drawCurrentOriginAxes () self.displayCamera () def refreshMatrices (self): tmp = glGetDoublev (GL_MODELVIEW_MATRIX) # this returns a list of lists BUT QMatrix4x4 accepts a list of floats. tmp_qmtx = QMatrix4x4 ([item for sublist in tmp for item in sublist]) # flattens the list of lists out in a single list. self.__mtx = tmp_qmtx tmp_tuple = tmp_qmtx.inverted () self.__norm_mtx = (tmp_tuple[0]).transposed () # assumption : matrix always invertible so I'm not going to check the boolean tmp_tuple[1]. def run (self): ''' method refreshed cyclically by a timer when it is in focus. When out of focus, the timer stops calling it and so freezing the image to what it looked like when last used. ''' self.paintGL () # render actual frame self.swapBuffers () def addCamera (self): self.__compo_mtools.setNormalMatrix (self.__norm_mtx) angle_by_aspect_ratio = self.__angle * self.__aspect_ratio inv_w = 1.0/self.__w inv_h = 1.0/self.__h m = -1.0 w_param = (inv_w-1) * angle_by_aspect_ratio h_param = (1-inv_h) * self.__angle # compute center + corners cam_centre = self.__compo_mtools.cameraToWorldTransform (0, 0, 0) top_left = self.__compo_mtools.cameraToWorldTransform ( w_param, h_param, m) top_right = self.__compo_mtools.cameraToWorldTransform ( w_param, -h_param, m) bottom_left = self.__compo_mtools.cameraToWorldTransform (-w_param, h_param, m) bottom_right = self.__compo_mtools.cameraToWorldTransform (-w_param, -h_param, m) self.__camera_list.append ([cam_centre, top_left, top_right, bottom_left, bottom_right]) # - - - viewer graphics - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def displayCamera (self): glLineWidth (1.0) for cam in self.__camera_list: cc=cam[0]; tl=cam[1]; tr=cam[2]; bl=cam[3]; br=cam[4] glBegin (GL_LINES) glColor3f (0.6, 0.6, 0.6) glVertex3f (cc[0],cc[1],cc[2]); glVertex3f (tl[0],tl[1],tl[2]) glVertex3f (cc[0],cc[1],cc[2]); glVertex3f (tr[0],tr[1],tr[2]) glVertex3f (cc[0],cc[1],cc[2]); glVertex3f (br[0],br[1],br[2]) glVertex3f (cc[0],cc[1],cc[2]); glVertex3f (bl[0],bl[1],bl[2]) glVertex3f (tl[0],tl[1],tl[2]); glVertex3f (tr[0],tr[1],tr[2]) glVertex3f (tr[0],tr[1],tr[2]); glVertex3f (br[0],br[1],br[2]) glVertex3f (br[0],br[1],br[2]); glVertex3f (bl[0],bl[1],bl[2]) glVertex3f (bl[0],bl[1],bl[2]); glVertex3f (tl[0],tl[1],tl[2]) glEnd () def displayObjects (self): glClear (GL_COLOR_BUFFER_BIT) glEnable (GL_DEPTH_TEST) glDepthMask (GL_TRUE) #glEnable (GL_CULL_FACE) for poly in self.__poly_list: p0 = poly[0]; p1 = poly[1]; p2 = poly[2] glBegin (GL_TRIANGLES) col = .4 + 0.5*QVector3D.dotProduct (poly[3], self.__compo_light_pos) glColor3f (col, col, col) glVertex3f (p0.x(), p0.y(), p0.z()) glVertex3f (p1.x(), p1.y(), p1.z()) glVertex3f (p2.x(), p2.y(), p2.z()) glEnd () def displayIntersections (self): for intsect in self.__intersections_list: p = intsect[0] c = intsect[1] # Draw a translated solid sphere glPushMatrix () glTranslatef (p[0], p[1], p[2]) glColor3f (c[0], c[1], c[2]) glutSolidSphere (GLdouble (0.03), 9, 9) glPopMatrix () def displayLines (self): glLineWidth (1.0) for line in self.__lines_list: p = line[0] # line initial position (3-list) d = line[1] # line direction (3-list) t = str(line[2]) # line type (o:open line, p:point-to-point line) glBegin (GL_LINES) glColor3ub (255, 255, 255) glVertex3f (p[0], p[1], p[2]) # open line if t=='o': glVertex3f (self.__l_param*d[0] + p[0], self.__l_param*d[1] + p[1], self.__l_param*d[2] + p[2]) # point-to-point line elif t=='p': glVertex3f (d[0], d[1], d[2]) else: raise sys.exit ('*** Unrecognised line type : "' + t + '"') glEnd () def displayArrows (self): for arrow in self.__arrows_list: p = arrow[0] # arrow position (3-list) d = arrow[1] # arrow direction (3-list) t = str(arrow[2]) # arrow type (i:inwards, o:outwards) # scale parameters scale_x = 0.01 scale_y = scale_x scale_z = 0.5 t_z = scale_z * self.__arrow_len # arrow type if t=='o': add_t = 0 elif t=='i': add_t = -t_z*2.5 else: raise sys.exit ('*** Unrecognised arrow type : "' + t + '"') glPushMatrix () # arrow shaft glColor3f (0.5, 0.5, 0) glTranslatef (p[0], p[1], p[2]) angles_from_orient = self.__compo_mtools.alignZAxisToVector (d[0], d[1], d[2]) glRotatef ( 180, 0, 0, 1) glRotatef (angles_from_orient[1], 0, 1, 0) glRotatef (angles_from_orient[0], 1, 0, 0) glScale (scale_x, scale_y, scale_z) glTranslatef (0, 0, t_z+add_t) glutSolidCube (GLdouble(self.__arrow_len)) # arrow head # REMEMBER ! The head's transformations are built on top of the arrow shaft's and are NOT independent ! # The reason for doing that is that the user can change the scale of the arrow from UI's slider. glColor3f (0.6, 0.6, 0) glTranslatef (0, 0, t_z) glutSolidCone (GLdouble(t_z*5), GLdouble(t_z*0.5), GLint(6), GLint(2)) glPopMatrix () def drawGrid (self): glLineWidth (1.0) for i in range (-10, 11): glBegin (GL_LINES) glColor3ub (185, 185, 185) glVertex3f (-10, 0, i) glVertex3f (10, 0, i) glVertex3f (i, 0,-10) glVertex3f (i, 0, 10) glEnd () def drawFixedOriginAxes (self): glLineWidth (2.0) glBegin (GL_LINES) glColor3ub (250, 0, 0); glVertex3f (0, 0, 0); glVertex3f (0, 0, 5) glColor3ub (255, 150, 150); glVertex3f (0, 0, 5); glVertex3f (0, 0, 10); glEnd () glBegin (GL_LINES) glColor3ub (0, 250, 0); glVertex3f (0, 0, 0); glVertex3f (0, 5, 0) glColor3ub (150, 255, 150); glVertex3f (0, 5, 0); glVertex3f (0, 10, 0); glEnd () glBegin (GL_LINES) glColor3ub (0, 0, 250); glVertex3f (0, 0, 0); glVertex3f (5, 0, 0) glColor3ub (150, 150, 255); glVertex3f (5, 0, 0); glVertex3f (10, 0, 0); glEnd () def drawCurrentOriginAxes (self): glPointSize (6.0) glBegin (GL_POINTS) glColor3f (0.0,1.0,1.0) glVertex3f (self.__orig.x(), self.__orig.y(), self.__orig.z()); glEnd () glBegin (GL_LINES); glColor3ub (250, 0, 0) glVertex3f (self.__orig.x(), self.__orig.y(), self.__orig.z()) glVertex3f (self.__orig.x(), self.__orig.y(), self.__orig.z()+5); glEnd () glBegin (GL_LINES); glColor3ub (0, 250, 0); glVertex3f (self.__orig.x(), self.__orig.y(), self.__orig.z()) glVertex3f (self.__orig.x(), self.__orig.y()+5, self.__orig.z()); glEnd () glBegin (GL_LINES); glColor3ub (0, 0, 250); glVertex3f (self.__orig.x(), self.__orig.y(), self.__orig.z()) glVertex3f (self.__orig.x()+5, self.__orig.y(), self.__orig.z()); glEnd () # - - - listeners - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def changeArrowsSize (self, new_size): if len(self.__arrows_list) > 0: self.__arrow_len = new_size def addArrow (self, pos, orient, arrow_type): self.__arrows_list.append ([pos, orient, arrow_type]) def addLine (self, pos, orient_or_second_point, line_type): self.__lines_list.append ([pos, orient_or_second_point, line_type]) def addIntersection (self, pos, icolor): self.__intersections_list.append ([pos, icolor]) def keyPressEvent (self, e): if e.key() == Qt.Key_Control or e.key() == Qt.Key_Meta: self.__Ctrl_or_Meta_key_pressed = True if e.key() == Qt.Key_Alt: self.__Alt_key_pressed = True def keyReleaseEvent (self, e): if e.key() == Qt.Key_Control or e.key() == Qt.Key_Meta: self.__Ctrl_or_Meta_key_pressed = False if e.key() == Qt.Key_Alt: self.__Alt_key_pressed = False def wheelEvent (self, e): if self.__Ctrl_or_Meta_key_pressed: self.__cam_dist += e.delta() * 0.01 # the three methods below are for regulate the OpenGL widget's FPS based on the focus received by the user. def setUi_Form (self, uif): self.uiform = uif def focusInEvent (self, e): self.uiform.speedUpGLFrameRate () def focusOutEvent (self, e): self.uiform.freezeGLFrameRate () def getFovy (self): return self.__fovy def getMatrix (self): return self.__mtx def getNormalMatrix (self): return self.__norm_mtx def setModel (self, model): self.__poly_model = model self.__poly_list = model.getPolyListCopy ()
class CImprovedButton(QToolButton): def __init__(self, parent=None): QToolButton.__init__(self, parent) #TESTO ALTERNATIVO #Spesso se il pulsante ha icona troppo grossa e quando per ragioni di spazio o altro non si può spostare #o ridimensionare il pulsante stesso, la label ha posizioni assurde e schifose. Aggiungerne una "+ controllabile" #è l'unico modo.. self.__fixed_label = QLabel("alternative label", self) self.__fixed_label.move(0, self.geometry().height() - 35) self.__fixed_label.resize(self.geometry().width(), self.__fixed_label.geometry().height()) self.__fixed_label.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) self.__font = QtGui.QFont("Arial", 10) self.__fixed_label.setFont(self.__font) self.__fixed_label.show() #INDICATORE STILE iOS self.__indicator = QLabel("0", self) self.__indicator.setStyleSheet("border-image: url(':/images/backgrounds/indicator.png'); padding-right:1px; color: white;") self.__indicator.geometry().setWidth(25) self.__indicator.geometry().setHeight(20) self.__indicator.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) self.__indicator.setVisible(False) self.setIndicatorPos(QPoint(self.width() - self.__indicator.width(), 0)) #default top-right corner #Quando il pulsante viene ridimensionato (designer o meno) devo anche sistemare la label di conseguenza self.resizeEvent = self.__onResize self.__indicator.resizeEvent = self.__on_indicator_Resize self.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) self.clicked.connect(self.stopAllAnimations) #BLINK self.__blink_timer = QTimer(parent) self.__blink_timer.timeout.connect(self.__on_blink_timer) self.__blink_timer_interval = 1000 #FADING self.__opacity_effect = QGraphicsOpacityEffect() self.__fading_timer = QTimer(parent) self.__fading_timer.timeout.connect(self.__on_fading_timer) self.__FADE_TYPE = Enum("IN", "OUT") self.__fade_time = 20 self.__opacity = 1.0 self.__opacity_fading_coefficient = 0.02 self.__selected_fade_type = self.__FADE_TYPE.IN # ANIMAZIONI GROW self.__animationGrow = QPropertyAnimation(self, "iconSize", self) self.__animationGrow.setDuration(1000) self.__animationGrow.setEasingCurve(QEasingCurve.Linear) self.__animationGrow.finished.connect(self.__on_growed) self.__animationShrink = QPropertyAnimation(self, "iconSize", self) self.__animationShrink.setDuration(1000) self.__animationShrink.setEasingCurve(QEasingCurve.Linear) self.__animationShrink.finished.connect(self.__on_shrinked) self.__defaultIconDimension = 60 self.__iconGrowsBy = 40 self.__growing = False # ANIMAZIONI BOUNCE self.__animationUp = QPropertyAnimation(self, "pos", self) self.__animationUp.setDuration(200) self.__animationUp.setEasingCurve(QEasingCurve.Linear) self.__animationUp.finished.connect(self.__on_top_reached) self.__animationBounce = QPropertyAnimation(self, "pos", self) self.__animationBounce.setDuration(1000) self.__animationBounce.setEasingCurve(QEasingCurve.OutBounce) self.__animationBounce.finished.connect(self.__on_bounce_finished) self.__bouncing = False self.__startPos = QPoint(self.pos().x(), self.pos().y()) #PIXMAP & MASCHERA self.__pmap = QPixmap(self.size()) self.__pmap_fname = "" self.__show_mask_preview = False def setDefaultIconSize(self, value): """ Sets default icon size when growing stops. @param value: size (both width and height) @type value: int """ self.__defaultIconDimension = value def getDefaultIconSize(self): return self.__defaultIconDimension defaultIconSize = QtCore.pyqtProperty("int", getDefaultIconSize, setDefaultIconSize) def setFixetTextVisibility(self, bool): """ Sets if fixed text is visible or not. @param bool: visible or not @type bool: bool """ self.__fixed_label.setVisible(bool) def getFixetTextVisibility(self): return self.__fixed_label.isVisible() fixetTextVisibility = QtCore.pyqtProperty("bool", fget=getFixetTextVisibility, fset=setFixetTextVisibility) def setFixedText(self, txt): """ Sets text on the button. @param txt: text @type txt: string """ self.__fixed_label.setText(txt) def getFixedText(self): return self.__fixed_label.text() fixedText = QtCore.pyqtProperty("QString", getFixedText, setFixedText) def setFixedTextPos(self, qpoint): """ Sets text position in the button. @param qpoint: Position RELATIVE. 0,0 is top left corner of the button. @type qpoint: QPoint """ self.__fixed_label.move(qpoint) def getFixedTextPos(self): return self.__fixed_label.pos() fixedTextPos = QtCore.pyqtProperty("QPoint", getFixedTextPos, setFixedTextPos) def setFixedTextFont(self, font): """ Sets text font. @param font: Font for fixed text. @type font: QFont """ self.__font = font self.__fixed_label.setFont(self.__font) def getFixedTextFont(self): return self.__font fixedTextFont = QtCore.pyqtProperty("QFont", getFixedTextFont, setFixedTextFont) #FUNZIONI INDICATORE def setIndicatorVisibility(self, bool): """ Sets if indicator is visible or not. @param bool: visible or not @type bool: bool """ self.__indicator.setVisible(bool) def getIndicatorVisibility(self): return self.__indicator.isVisible() indicatorVisibility = QtCore.pyqtProperty("bool", fget=getIndicatorVisibility, fset=setIndicatorVisibility) def setIndicatorPos(self, qpoint): """ Sets indicator position in the button. @param qpoint: Position RELATIVE. 0,0 is top left corner of the button. @type qpoint: QPoint """ self.__indicator.move(qpoint) def getIndicatorPos(self): return self.__indicator.pos() indicatorPos = QtCore.pyqtProperty("QPoint", getIndicatorPos, setIndicatorPos) def setIndicatorSize(self, size): """ Sets indicator size. @param size: Size @type size: QSize """ self.__indicator.resize(size) def getIndicatorSize(self): return self.__indicator.size() indicatorSize = QtCore.pyqtProperty("QSize", getIndicatorSize, setIndicatorSize) def setIndicatorFont(self, font): """ Sets indicator text font. @param font: Font for indicator text. @type font: QFont """ self.__indicator.setFont(font) def getIndicatorFont(self): return self.__indicator.font() indicatorFont = QtCore.pyqtProperty("QFont", getIndicatorFont, setIndicatorFont) ## FUNZIONI PER BLINK def __on_blink_timer(self): self.setVisible(not (self.isVisible())) def setBlinking(self, blink): """ Sets if the button have to blink or not. @param blink: blinking or not @type blink: bool """ if blink: self.__blink_timer.setInterval(self.__blink_timer_interval) self.__blink_timer.start() else: self.__blink_timer.stop() self.setVisible(True) def setBlinkInterval(self, value): """ Sets blink interval. @param blink: blink interval (msec) @type blink: int """ self.__blink_timer_interval = value def getBlinkInterval(self): return self.__blink_timer_interval blinkInterval = QtCore.pyqtProperty("int", getBlinkInterval, setBlinkInterval) ##FUNZIONI PER FADING def fadeIn(self): """ Button fades in from completely invisible to completely visible. """ self.__opacity = 0.0 self.__selected_fade_type = self.__FADE_TYPE.IN self.__fading_timer.start(self.__fade_time) def fadeOut(self): """ Button fades out from completely visible to completely invisible. """ self.__selected_fade_type = self.__FADE_TYPE.OUT self.__fading_timer.start(self.__fade_time) def setFadeTime(self, value): """ Sets fading time. Everytime interval is reached, alpha is increased (or decreased) by __opacity_fading_coefficient. @param value: fade time (msec) @type value: int """ self.__fade_time = value def getFadeTime(self): return self.__fade_time fadeInterval = QtCore.pyqtProperty("int", getFadeTime, setFadeTime) def setFadeCoefficient(self, value): """ Sets fading coefficient. Alpha is increased (or decreased) by this value. @param value: coefficient (min 0.0 - max 1.0) @type value: float """ self.__opacity_fading_coefficient = value def getFadeCoefficient(self): return self.__opacity_fading_coefficient fadeCoefficient = QtCore.pyqtProperty("double", getFadeCoefficient, setFadeCoefficient) def __on_fading_timer(self): if self.__selected_fade_type == self.__FADE_TYPE.OUT: if self.__opacity > 0: self.__opacity -= self.__opacity_fading_coefficient self.__opacity_effect.setOpacity(self.__opacity) self.setGraphicsEffect(self.__opacity_effect) else: self.__fading_timer.stop() if self.__selected_fade_type == self.__FADE_TYPE.IN: if self.__opacity <= 1.0: self.__opacity += self.__opacity_fading_coefficient self.__opacity_effect.setOpacity(self.__opacity) self.setGraphicsEffect(self.__opacity_effect) else: self.__fading_timer.stop() # FUNZIONI PER GROW\SHRINK def __on_growed(self): self.__animationShrink.setStartValue(QSize(self.iconSize().width(), self.iconSize().height())) self.__animationShrink.setEndValue( QSize(self.iconSize().width() - self.__iconGrowsBy, self.iconSize().height() - self.__iconGrowsBy)) self.__animationShrink.start() def __on_shrinked(self): self.__animationGrow.setStartValue(QSize(self.iconSize().width(), self.iconSize().height())) self.__animationGrow.setEndValue( QSize(self.iconSize().width() + self.__iconGrowsBy, self.iconSize().height() + self.__iconGrowsBy)) self.__animationGrow.start() def startGrow(self): """ Button ICON starts to grow and shrink to standard value when maximum size (configured) is reached """ if self.__growing: return self.__animationGrow.setStartValue(QSize(self.iconSize().width(), self.iconSize().height())) self.__animationGrow.setEndValue( QSize(self.iconSize().width() + self.__iconGrowsBy, self.iconSize().height() + self.__iconGrowsBy)) self.__animationGrow.start() self.__growing = True def stopGrow(self): if self.__animationGrow.startValue().toSize() != QSize(0, 0) and self.__animationShrink.startValue().toSize() != QPoint( 0, 0): self.__animationGrow.stop() self.__animationShrink.stop() self.setIconSize(QSize(self.__defaultIconDimension, self.__defaultIconDimension)) self.__growing = False #FUNZIONI PER BOUNCE def startBounce(self): """ Button starts to bounce requiring attention. """ if self.__bouncing: return self.__startPos = QPoint(self.pos().x(), self.pos().y()) self.__animationUp.setStartValue(QPoint(self.__startPos.x(), self.__startPos.y())) self.__animationUp.setEndValue(QPoint(self.__startPos.x(), self.__startPos.y() - self.geometry().height())) self.__animationUp.start() self.__bouncing = True def stopBounce(self): if self.__animationUp.startValue().toPoint() != QPoint(0,0) and self.__animationBounce.startValue().toPoint() != QPoint(0,0): self.__animationBounce.stop() self.__animationUp.stop() self.setGeometry(self.__startPos.x(), self.__startPos.y(), self.geometry().width(), self.geometry().height()) self.__bouncing = False def __on_top_reached(self): self.__animationBounce.setStartValue(QPoint(self.pos().x(), self.pos().y())) self.__animationBounce.setEndValue(QPoint(self.__startPos.x(), self.__startPos.y())) self.__animationBounce.start() def __on_bounce_finished(self): self.__animationUp.start() def stopAllAnimations(self): self.stopBounce() self.stopGrow() #FUNZIONI PER PIXMAP & MASCHERA def setPixmapFile(self, image_file): self.__pmap = image_file self.__pmap.scaled(self.size()) #NB: Il pixmap deve essere BIANCO e NERO. Con heuristicMask il primo pixel in alto a sinistra (0,0) viene #usato per decidere il colore trasparente, tutto il resto è visibile. def getPixmapFile(self): return self.__pmap pixmapFile = QtCore.pyqtProperty("QPixmap", getPixmapFile, setPixmapFile) def applyMask(self, bool): self.__show_mask_preview = bool if bool: self.setMask(QBitmap(self.__pmap.createHeuristicMask().scaled(self.size()))) else: self.setMask(QBitmap()) def getMask(self): return self.__show_mask_preview appliedMask = QtCore.pyqtProperty("bool", fget=getMask, fset=applyMask) def __onResize(self, event): self.__fixed_label.move(0, self.geometry().height() - 35) self.__fixed_label.resize(self.geometry().width(), self.__fixed_label.geometry().height()) self.setIndicatorPos(QPoint(self.width() - self.__indicator.width(), 0)) self.__pmap.scaled(self.size()) if self.__show_mask_preview: self.setMask(QBitmap(self.__pmap.createHeuristicMask().scaled(self.size()))) def __on_indicator_Resize(self, event): self.setIndicatorPos(QPoint(self.width() - self.__indicator.width(), 0))
class OIBlock(QWidget): border_color = QColor(137, 117, 89) padding = 0.05 radius = 0.08 def __init__(self, block, parent): QWidget.__init__(self, parent) self.__nodes = [] self.__block = block self._resizable = True self.__block.repaint.connect(self.repaint) self._bg_color = QColor(159, 160, 144, 255) self._fg_color = QColor(255, 255, 255) self.setGeometry(block.get_geometry(Info.dpi)) self.__action = Action.NONE self.__status = Mode.EDIT_LOGIC self.__corner_path = None self.__origin = None self.__translation = QPoint() if self._resizable: self.__init_corner() self.__init_nodes() self.__init_listeners() self.setMouseTracking(True) def __init_nodes(self): y = .45 x = .01 for k in self.__block.inputs: i = self.__block.inputs[k] n = OINode(QPointF(x, y), Alignment.Left, i) self.__nodes.append(n) y += 0.05 + n.size x = self.width() / Info.dpi - .12 y = 0.45 for k in self.__block.outputs: o = self.__block.outputs[k] n = OINode(QPointF(x, y), Alignment.Right, o) self.__nodes.append(n) y += .05 + n.size def __init_listeners(self): self.__block.selected.connect(self.select) self.__block.settings['Width'].value_update.connect(self.geometry_update) self.__block.settings['Height'].value_update.connect(self.geometry_update) self.__block.settings['X'].value_update.connect(self.geometry_update) self.__block.settings['Y'].value_update.connect(self.geometry_update) def select(self, val: bool): if val: effect = QGraphicsDropShadowEffect() effect.setBlurRadius(20) effect.setXOffset(0) effect.setYOffset(0) effect.setColor(QColor(0, 0, 0, 180)) self.setGraphicsEffect(effect) self.raise_() else: eff = self.graphicsEffect() del eff self.setGraphicsEffect(None) def geometry_update(self): r = self.__block.get_geometry(Info.dpi) r.translate(self.__translation) self.setGeometry(r) self.__update_nodes() def __update_nodes(self): x = self.width() / Info.dpi - .12 for n in self.__nodes: if n.alignment == Alignment.Right: y = n.pos.y() n.pos = QPointF(x, y) self.repaint() def selected(self): return self.__block.is_selected() def bg(self): return self._bg_color def title_bg(self): return self._bg_color.light(80) def block(self): return self.__block def _paint(self, p: QPainter): self._paint_bg(p) self._paint_title(p) p.setPen(QPen(self.pen().brush(), 0.01 * Info.dpi)) self._paint_nodes(p) # self._paint_outs(p) # self._paint_content(p) def pen(self): p = QPen(OIBlock.border_color.lighter().lighter() if self.selected() else OIBlock.border_color, .02 * Info.dpi) return p def _paint_bg(self, p: QPainter): dpi = Info.dpi pen = self.pen() p.setRenderHint(QPainter.Antialiasing, True) p.setPen(pen) p.setBrush(self.bg()) p.drawRoundedRect(OIBlock.padding * dpi, OIBlock.padding * dpi, self.width() - 2 * OIBlock.padding * dpi, self.height() - 2 * OIBlock.padding * dpi, OIBlock.radius * dpi, OIBlock.radius * dpi) p.setBrush(self.title_bg()) p.drawRoundedRect(OIBlock.padding * dpi, OIBlock.padding * dpi, self.width() - 2 * OIBlock.padding * dpi, .35 * dpi + OIBlock.padding * dpi, OIBlock.radius * dpi, OIBlock.radius * dpi) p.setBrush(self.bg()) p.setPen(QColor(0, 0, 0, 0)) p.drawRect(0.01 * dpi + OIBlock.padding * dpi, 0.35 * dpi + OIBlock.padding * dpi, self.width() - 0.02 * dpi - 2 * OIBlock.padding * dpi, 0.10 * dpi) p.setPen(pen) if self._resizable: if self.__corner_path is None: self.__init_corner() p.setBrush(pen.brush()) p.drawPath(self.__corner_path.translated(self.width(), self.height())) def _paint_title(self, p: QPainter): dpi = Info.dpi p.drawLine(OIBlock.padding * dpi, 0.35 * dpi + OIBlock.padding * dpi, self.width() - (0.01 + OIBlock.padding) * dpi, 0.35 * dpi + OIBlock.padding * dpi) p.setPen(self._fg_color) f = p.font() f.setPointSize(10) f.setBold(True) p.setFont(f) p.drawText( QRectF((0.04 + OIBlock.padding) * dpi, (OIBlock.padding + .01) * dpi, self.width() - .12 * dpi, .25 * dpi), str(self.__block.name())) f.setBold(False) f.setPointSize(8) p.setPen(QColor(self._fg_color.red(), self._fg_color.green(), self._fg_color.blue(), 100)) p.setFont(f) p.drawText( QRectF((.04 + OIBlock.padding) * dpi, (.17 + OIBlock.padding) * dpi, self.width() - .12 * dpi, .15 * dpi), str(self.__block.type_name())) def __init_corner(self): path = QPainterPath() dpi = Info.dpi path.moveTo(-OIBlock.padding * 1.2 * dpi, (-.15 - OIBlock.padding * 1.2) * dpi) path.lineTo((-.15 - OIBlock.padding * 1.2) * dpi, -OIBlock.padding * 1.2 * dpi) path.lineTo(-OIBlock.padding * 1.2 * dpi, -OIBlock.padding * 1.2 * dpi) path.closeSubpath() self.__corner_path = path def _paint_nodes(self, p: QPainter): for n in self.__nodes: n.paint(p) return def _paint_content(self, p: QPainter): # nothing to do return def paintEvent(self, e: QPaintEvent): if e.isAccepted(): p = QPainter(self) self._paint(p) def _check_corner(self, pos): path = self.__corner_path.translated(self.width(), self.height()) return path.contains(pos) def _check_action(self, action): if self.__action != Action.NONE and action != Action.NONE: return False return True def _check_nodes(self, p:QPoint): for n in self.__nodes: if n.contains(p): return n return None def mousePressEvent(self, e: QMouseEvent): self.__block.select() n = self._check_nodes(e.pos()) if n is not None: print('Node found') return if e.button() == Qt.LeftButton: if self._resizable: if self._check_corner(e.pos()) and self._check_action(Action.RESIZE): self.__origin = e.pos() self.__action = Action.RESIZE self.setCursor(Qt.SizeFDiagCursor) return if self._check_action(Action.DRAG): self.__origin = e.pos() self.__action = Action.DRAG self.setCursor(Qt.DragMoveCursor) def mouseMoveEvent(self, e: QMouseEvent): if self.__action == Action.DRAG: dx = e.x() - self.__origin.x() dy = e.y() - self.__origin.y() self.set_pos(self.x() + dx, self.y() + dy) elif self.__action == Action.RESIZE: self.set_size(e.x(), e.y()) else: if self._resizable and self.__corner_path.translated(self.width(), self.height()).contains(e.pos()): self.setCursor(Qt.SizeFDiagCursor) else: self.setCursor(Qt.ArrowCursor) def mouseReleaseEvent(self, e: QMouseEvent): self.__action = Action.NONE self.setCursor(Qt.ArrowCursor) def set_size(self, w, h): w1 = w / Info.dpi h1 = h / Info.dpi W = self.__block.settings['Width'].value() H = self.__block.settings['Height'].value() if w1 < W.min: w1 = W.min elif w1 > W.max: w1 = W.max if h1 < H.min: h1 = H.min elif h1 > H.max: h1 = H.max self.__block.set_setting('Width', w1) self.__block.set_setting('Height', h1) def set_pos(self, x, y): x = x - self.__translation.x() y = y - self.__translation.y() self.__block.set_setting('X', x / Info.dpi) self.__block.set_setting('Y', y / Info.dpi) def translate(self, p): self.__translation = p self.geometry_update()
class MSGLCanvas3D(QGLWidget): """Canvas GL plotting in 3 dimensions spectra""" corner = 100.0 near = 0.0 far = 600.0 zoom = 1.5 xrot = 220 yrot = 220 zrot = 0 trans_x = 0.0 trans_y = 0.0 def __init__( self, vertexes, colors, parent=None, **kw ): #vertexes, colors, texturePath='graphics/Texture-Example.jpg', parent=None):#spl, peak=None, parent=None): """ Constructor, initialization kw: -texturePath:pathway to the file to text -textures: coord textures to apply -parent:the parent widget """ QGLWidget.__init__(self, parent) self.setFormat(QGLFormat(QGL.SampleBuffers)) self.setMinimumSize(500, 300) self.setMouseTracking(True) self.setFocusPolicy(Qt.StrongFocus) # if not 'texturePath'in kw.keys() and not 'textures' in kw.keys(): # pass # #print ('Could not apply texture, no coordinates') # else: # try: # self._imageID = self.loadImage(kw.get('texturePath')) # self.textures = textures # except OSError: # print ('Could not apply texture, no coordinates') self.vertexes = vertexes self.colors = colors #self.axes=None self.zoom_mode = False self.pan_mode = True #self.axes = self.makeAxes() self.parameters = { 'axes_color': 'b', 'axes_line_width': 3., 'draw_line_width': 1., 'colormap': True, 'fish_eye': False, 'cell_shading': False } self.lastpos = QPoint() def loadImage(self, imageName): im = open(imageName) try: ix, iy, image = im.size[0], im.size[1], im.tostring( "raw", "RGBA", 0, -1) except SystemError: ix, iy, image = im.size[0], im.size[1], im.tostring( "raw", "RGBX", 0, -1) ID = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, ID) glPixelStorei(GL_UNPACK_ALIGNMENT, 1) glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE, image) return ID def setupTexture(self): glEnable(GL_TEXTURE_2D) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) glBindTexture(GL_TEXTURE_2D, self.imageID) def texturesCalc(self): from OpenGL.arrays.vbo import VBO basis = [[0., 0.], [0., 1.]] hola = [] length = len(self.vertexes) for i in range(length / 2): hola += basis return VBO(array(hola)) def recalcVertexesAndColors(self, colormap, **kwargs): pass def resizeGL(self, w, h): """called when window is being resized""" glViewport(0, 0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(-self.corner * self.zoom, self.corner * self.zoom, -self.corner * self.zoom, self.corner * self.zoom, self.near, self.far) #gluPerspective(70,w/h, 1,1000) glMatrixMode(GL_MODELVIEW) def initializeGL(self): """opengl options""" #glClearColor(1., 1., 1., 1.) #glClearColor(0.,0.,0.) glEnable(GL_DEPTH_TEST) #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glEnable(GL_LINE_SMOOTH) #glEnable(GL_POINT_SMOOTH) #glHint (GL_LINE_SMOOTH_HINT, GL_NICEST)# #glDepthFunc(GL_LEQUAL) glEnable(GL_CULL_FACE) #glCullFace(GL_BACK) #glEnable(GL_LIGHTING) #glLightfv(GL_LIGHT0, GL_DIFFUSE,(0.8, 0.8, 0.8, 1)) #glEnable(GL_LIGHT0) #glEnable(GL_COLOR_MATERIAL) #glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE) #self.shader = compileProgram(vertex_shader, frag_shader)#vertex_shader)#shader #self.drawAxisLegend() def paintGL(self): """needed, called each time glDraw""" glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() glTranslated(0.0, 0.0, -3.0 * self.corner) glRotated(self.xrot / 16.0, 1.0, 0.0, 0.0) glRotated(self.yrot / 16.0, 0.0, 1.0, 0.0) glRotated(self.zrot / 16.0, 0.0, 0.0, 1.0) glTranslated(self.trans_x, self.trans_y, 3.0 * self.corner) #testing #glEnable(GL_DEPTH_TEST) #glEnable(GL_BLEND) #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) #self.setupTexture() #self.textures = self.texturesCalc() self.drawScene() #if self.zoom_mode: # self.drawQuad() def renderTextModes(self): self.renderText(10, 10, 'mode:%s' % "zoom" if self.zoom_mode else 'mode:%s' % "pan", font=QFont()) self.renderText(10, 20, 'selection mode:%s' % str(False), font=QFont()) def drawScene(self): # self.renderTextModes() glLineWidth(1.) #glUseProgram(self.shader) if self.vertexes is not None and self.colors is not None: self.vertexes.bind() glEnableClientState(GL_VERTEX_ARRAY) glVertexPointerf(self.vertexes) self.colors.bind() glEnableClientState(GL_COLOR_ARRAY) glColorPointerf(self.colors) """ self.textures.bind() glEnableClientState(GL_TEXTURE_COORD_ARRAY) glTexCoordPointerf(self.textures) """ glDrawArrays(GL_LINES, 0, len(self.vertexes)) self.vertexes.unbind() self.colors.unbind() #self.textures.unbind() glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) #glDisableClientState(GL_TEXTURE_COORD_ARRAY) #glUseProgram(0) #glUseProgram(0) #if hasattr(self, 'axes'): #glCallList(self.axes) #glCallList(self.surface) #self.drawAxisLegend() def makeAxes(self): """Draw Axes """ glLineWidth(2.0) glColor(0., 0., 1.) lspectr = glGenLists(1) glNewList(lspectr, GL_COMPILE) glBegin(GL_LINES) #glEnable(GL_LINE_STIPPLE) #glLineStipple(1, 1) glVertex3d(self.corner, -self.corner, -self.near - 2 * self.corner) glVertex3d(self.corner, self.corner, -self.near - 2 * self.corner) glVertex3d(self.corner, -self.corner, -self.far + 2 * self.corner) glVertex3d(self.corner, +self.corner, -self.far + 2 * self.corner) glVertex3d(-self.corner, -self.corner, -self.far + 2 * self.corner) glVertex3d(-self.corner, +self.corner, -self.far + 2 * self.corner) glVertex3d(-self.corner, +self.corner, -self.far + 2 * self.corner) glVertex3d(self.corner, +self.corner, -self.far + 2 * self.corner) glVertex3d(+self.corner, +self.corner, -self.far + 2 * self.corner) glVertex3d(+self.corner, +self.corner, -self.near - 2 * self.corner) #glDisable(GL_LINE_STIPPLE) glVertex3d(+self.corner, -self.corner, -self.far + 2 * self.corner) glVertex3d(+self.corner, -self.corner, -self.near - 2 * self.corner) glVertex3d(-self.corner, -self.corner, -self.far + 2 * self.corner) glVertex3d(self.corner, -self.corner, -self.far + 2 * self.corner) glEnd() glEndList() return lspectr def drawAxisLegend(self): """Draw Axis Legend""" font = QFont("Typewriter") font.setPixelSize(10) #RT axis legend font.setPixelSize(12) self.qglColor(Qt.blue) mz_label = "retention time [s]" rt_label = "m/z" self.renderText(0.0, -self.corner - 20.0, -self.near - 2 * self.corner + 20.0, rt_label, font) self.renderText(-self.corner - 20.0, -self.corner - 20.0, -self.near - 3 * self.corner, mz_label, font) self.renderText(-self.corner - 20.0, self.corner + 10.0, -self.near - 2 * self.corner + 20.0, "intensity %", font) font.setPixelSize(10) # #for rt number # for i in xrange (0,len(self.rtList), 100): # text = str(math.ceil(((self.rtList[i][0])*self.max_rt )/ self.max_rt)) # self.renderText(-self.corner, # -self.corner -5.0, # -self.near-2*self.corner - self.rtList[i][0], # text, # font) # for i in xrange (0, len(self.massList[0]), 100): # text = str(math.ceil(((self.massList[0][i])*self.max_mass )/ 2*self.corner)) # self.renderText( self.corner, # self.corner -5.0, # -self.near-2*self.corner - self.massList[0][i], # text, # font) # #for mz number def resetTranslations(self): """reset the different translation to 0""" self.trans_x = 0. self.trans_y = 0. def normalizeAngle(self, angle): """taken from qt documentation""" while (angle < 0): angle += 360 * 16 while (angle > 360 * 16): angle -= 360 * 16 return angle def computeSelection(self): pass #=============================================================================== # MOUSE AND KEYBOARDS EVENTS #=============================================================================== def wheelEvent(self, event): if event.delta() > 0: self.zoom -= .05 else: self.zoom += .05 glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(-self.corner * self.zoom, self.corner * self.zoom, -self.corner * self.zoom, self.corner * self.zoom, self.near, self.far) glMatrixMode(GL_MODELVIEW) self.updateGL() event.accept() def keyPressEvent(self, event): if event.key() == Qt.Key_Minus: self.zoom -= .1 glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(-self.corner * self.zoom, self.corner * self.zoom, -self.corner * self.zoom, self.corner * self.zoom, self.near, self.far) glMatrixMode(GL_MODELVIEW) if event.key() == Qt.Key_Plus: self.zoom += .1 glMatrixMode(GL_PROJECTION) #// You had GL_MODELVIEW glLoadIdentity() glOrtho(-self.corner * self.zoom, self.corner * self.zoom, -self.corner * self.zoom, self.corner * self.zoom, self.near, self.far) glMatrixMode(GL_MODELVIEW) if event.key() == Qt.Key_Z: #store all values self.zoom_mode = True glMatrixMode(GL_MODELVIEW) glLoadIdentity() font = QFont("Typewriter") self.renderText(0., 0., 0., "zooming mode", font) #little animation #a = -5 #count = 0 if self.yrot < 1444: while self.yrot < 1444: #and self.xrot < ref_rotx_: #count += 1 self.xrot -= 20 self.yrot += 20 #if self.zoom > a: # self.zoom-=1 self.updateGL() elif self.yrot > 1444: while self.yrot < 1444: #and self.xrot < ref_rotx_: #count += 1 self.xrot -= 20 self.yrot -= 20 #if self.zoom > a: # self.zoom-=1 self.updateGL() """ count_ = 0 tmp = self.xrot while tmp < 1422: count_+=1 tmp += 1 b = count / count_ count__ = 0 """ while self.xrot < 1422: #count__+=1 self.xrot += 20 #if self.zoom < 1: #and count__%b == 0: # self.zoom+=1 self.updateGL() if event.key() == Qt.Key_Up: self.trans_y += 10 if event.key() == Qt.Key_Down: self.trans_y -= 10 if event.key() == Qt.Key_Left: self.trans_x -= 10 if event.key() == Qt.Key_Right: self.trans_x += 10 self.updateGL() def mousePressEvent(self, event): self.lastpos = QPoint(event.pos()) # modelview, projection =[], [] # z =1 # x, y =event.x(), event.y() # projection =glGetDoublev(GL_PROJECTION_MATRIX) # modelview= glGetDoublev(GL_MODELVIEW_MATRIX) # viewport=glGetIntegerv(GL_VIEWPORT) # glReadPixels( x, viewport[3]-y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, z ) # objx, objy, objz =gluUnProject( x, viewport[3]-y, z, modelview, projection, viewport) # print objx, objy, objz def mouseMoveEvent(self, event): dx = event.x() - self.lastpos.x() dy = event.y() - self.lastpos.y() if not self.zoom_mode: if event.buttons() == Qt.LeftButton: a = self.normalizeAngle(self.xrot + 8 * dy) b = self.normalizeAngle(self.yrot + 8 * dx) self.xrot = a #self.xrot + 8 * dy self.yrot = b #self.yrot + 8 * dx if event.buttons() == Qt.RightButton: self.setCursor(QCursor(Qt.ClosedHandCursor)) self.trans_y -= dy / 5 self.trans_x += dx / 5 self.lastpos = QPoint(event.pos()) self.updateGL() def drawQuad(self): '''change to accept arguments pass''' glColor(0., 0., 1.) glLineWidth(4.0) pointer_x = self.lastpos.x() / 200. #self.corner pointer_y = self.lastpos.y() / 200. #/(self.corner) norm_dx = dx / 200. #/(self.corner) norm_dy = dy / 200. #/(self.corner) #print -self.corner, pointer_x, pointer_y, norm_dx, norm_dy glBegin(GL_QUADS) glVertex3f(-self.corner + pointer_x, -self.corner + pointer_y, -self.near + 2 * self.corner) glVertex3f(-self.corner + pointer_x + norm_dx, -self.corner + pointer_y, -self.near + 2 * self.corner) glVertex3f(-self.corner + pointer_x + norm_dx, -self.corner + pointer_y + norm_dy, -self.near + 2 * self.corner) glVertex3f(-self.corner + pointer_x, -self.corner + pointer_y, -self.near + 2 * self.corner) glEnd() self.lastpos = QPoint(event.pos()) #redraw eachtime mouse 's moving self.updateGL() def mouseReleaseEvent(self, event): self.setCursor(QCursor(Qt.ArrowCursor)) if self.zoom_mode: self.computeSelection() self.zoom_mode = False def closeEvent(self, event): self.releaseKeyboard()
def mouseMoveEvent(self, event): delta = QPoint(event.globalPos() - self.oldPos) #print(delta) self.move(self.x() + delta.x(), self.y() + delta.y()) self.oldPos = event.globalPos()
class TwoDPlotWidget(pg.PlotWidget): """ Widget to display a two dimensional graph based on elements with (x,y) coordinates. The widget allow to select a rectangular region of elements by their coordinates """ def __init__(self, parent=None): pg.PlotWidget.__init__(self, parent) plot_item = self.getPlotItem() view_box = plot_item.getViewBox() view_box.mouseDragEvent = lambda ev, axis=0: False # variables for rectangular selection manipulation self.mousePressed = False self.lastPoint = QPoint(0, 0) self.oldX, self.oldY = 0, 0 self.ElementSelectionRect = QtGui.QGraphicsRectItem( QtCore.QRectF(0, 0, 0, 0)) self.ElementSelectionRect.setPen( QtGui.QPen(QtGui.QColor(255, 255, 255))) # region Mouse Events def mousePressEvent(self, ev): pg.PlotWidget.mousePressEvent(self, ev) if ev.button() == QtCore.Qt.LeftButton: self.mousePressed = True # get the local graph coordinate point from the pixel # where the cursor was pressed update last point self.lastPoint = self.getPlotItem().getViewBox().mapSceneToView( QtCore.QPointF(ev.x(), ev.y())) self.ElementSelectionRect.setRect(self.lastPoint.x(), self.lastPoint.y(), 0, 0) self.update() def mouseReleaseEvent(self, ev): """ Widget response for a mouse release event. :param ev: """ pg.PlotWidget.mouseReleaseEvent(self, ev) self.mousePressed = False def mouseMoveEvent(self, ev): pg.PlotWidget.mouseMoveEvent(self, ev) if self.mousePressed: # update (if necessary) the coordinates of the visual rectangle. self.__updateSelectionRect(ev) self.update() # endregion # region Axis Settings def setAxisLabel(self, axis_location="bottom", label="", **extra_args): """ Set the label on the x or y axis :param axis_location: the location of the axis to set the label. (One of "bottom", "left") :param label: The label to set (str) :param extra_args: dict with extra arguments to give to the axis item setLabel. :return: """ if axis_location not in ["bottom", "left"]: raise ValueError("axis location must one of 'bottom' or 'left'") self.getPlotItem().getAxis(axis_location).setLabel(label, **extra_args) def setAxisFont(self, axis_location="bottom", font=None): """ Set the font on the x or y axis :param axis_location: the location of the axis to set the label. (One of "bottom", "left") :param font: The font to set (QFont) :return: """ if axis_location not in ["bottom", "left"]: raise ValueError("axis location must one of 'bottom' or 'left'") if font is not None: self.getPlotItem().getAxis(axis_location).setTickFont(font) def showGrid(self, x=True, y=True): """ Set the visibility of grid on the widget :param x: The x grid visibility :param y: The y grid visibility :return: """ self.getPlotItem().showGrid(x=x, y=y) # endregion # region Selection Rectangle def removeSelectionRect(self): """ Removes (if exist) the visual rectangle of the widget. """ if self.ElementSelectionRect in self.items(): self.removeItem(self.ElementSelectionRect) def addSelectionRect(self): """ Adds a visual rectangle in the widget to select elements """ if self.ElementSelectionRect not in self.items(): self.addItem(self.ElementSelectionRect) def __updateSelectionRect(self, ev): """ Update the selection rectangle figure with the information of a new gui event like mouse press :param ev: The event of the gui system """ point = self.getPlotItem().getViewBox().mapSceneToView( QtCore.QPointF(ev.x(), ev.y())) x, y = point.x(), point.y() self.ElementSelectionRect.setRect(self.lastPoint.x(), self.lastPoint.y(), x - self.lastPoint.x(), y - self.lastPoint.y()) # endregion def setRange(self, xRange=(0, 0), yRange=(0, 0)): """ Set the visible range of the widget :return: """ self.getPlotItem().setRange(xRange=xRange, yRange=yRange)
class EchoSet(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.mCenter = QPoint(0, 0) self.mRadius = 0 self.mEchoLines = [] self.mEchoLinesIndex = 0 self.SetCenter(QPoint(0, 0)) self.SetRadius(0) self.SetRange("50m") self.SetHdt(0) # 制作回波线角度表,用于提升性能 step = 2.0 * gPI / gEchoLineCountAFrame self.mCosAngleTable = [] self.mSinAngleTable = [] for i in range(0, gEchoLineCountAFrame): self.mCosAngleTable.append(0) self.mSinAngleTable.append(0) for i in range(0, gEchoLineCountAFrame): angle = i * step - 90 * g1Deg self.mCosAngleTable[i] = math.cos(angle) self.mSinAngleTable[i] = math.sin(angle) def SetData(self, echoSetStrs): for echoStr in echoSetStrs: echoLine = EchoLine(echoStr) self.mEchoLines.append(echoLine) # 绘制时的圆心坐标 def SetCenter(self, center): self.mCenter = center # 绘制半径 def SetRadius(self, radius): self.mRadius = radius * gRadarEchoScale # 设置量程 def SetRange(self, radarRange): assert radarRange in gRangeTable, "量程表中没有量程:" + radarRange self.mRangeName = radarRange self.mRange = gRangeTable[radarRange][0] self.mPrecision = gRangeTable[radarRange][1] # 设置船艏向 def SetHdt(self, hdt): self.mHdt = 0 # 绘制 def Draw(self, p): self.__DrawAEchoLine(p, self.mEchoLinesIndex) self.__DrawShipHeadLine(p) self.__DrawDisCircle(p) self.__DrawRangeCicle(p) self.__DrawSysInfo(p) self.mEchoLinesIndex += 1 indexMax = len(self.mEchoLines) if self.mEchoLinesIndex == indexMax: self.mEchoLinesIndex = 0 # 绘制量程范围 def __DrawRangeCicle(self, p): pen = QPen(QColor(0, 255, 0)) p.setPen(pen) # 绘制距标圈 def __DrawDisCircle(self, p): pen = QPen(QColor(0, 150, 0)) p.setPen(pen) p.setBrush(Qt.NoBrush) r = self.mRadius rHalf = 0.5 * r rHalfOne = 1.5 * r self.__DrawCircle(p, self.mCenter, r) self.__DrawCircle(p, self.mCenter, rHalf) self.__DrawCircle(p, self.mCenter, rHalfOne) # 绘制船艏线 def __DrawShipHeadLine(self, p): pen = QPen(QColor(255, 255, 255)) p.setPen(pen) angle = self.mHdt - 90 * g1Deg xStart = int(self.mCenter.x()) yStart = int(self.mCenter.y()) xEnd = int(self.mRadius * math.cos(angle) + xStart) yEnd = int(self.mRadius * math.sin(angle) + yStart) p.drawLine(xStart, yStart, xEnd, yEnd) brush = QBrush(QColor(255, 255, 255), Qt.SolidPattern) p.setBrush(brush) angle = self.mHdt + 90 * g1Deg ang = angle - 30 * g1Deg cos_a = math.cos(ang) sin_a = math.sin(ang) x1 = xEnd + gShipLegendLen * cos_a y1 = yEnd - gShipLegendLen * sin_a ang = angle + 30 * g1Deg cos_a = math.cos(ang) sin_a = math.sin(ang) x2 = xEnd + gShipLegendLen * cos_a y2 = yEnd - gShipLegendLen * sin_a p1 = QPointF(xEnd, yEnd) p2 = QPointF(x1, y1) p3 = QPointF(x2, y2) p.drawPolygon(p1, p2, p3) # 绘制系统信息 def __DrawSysInfo(self, p): pen = QPen(QColor(0, 255, 0)) p.setPen(pen) p.drawText(2, 20, "量程:" + self.mRangeName) p.drawText(2, 40, "船艏:" + str(self.mHdt) + "度") # 绘制回波 def __DrawAEchoLine(self, p, i): self.__DrawShadeLine(p, i) echoLinsCount = len(self.mEchoLines) if 0 == echoLinsCount: return assert i < echoLinsCount, "回波线索引越界" # TODO: 使用查表法 提速 cosAngle = self.mCosAngleTable[i] sinAngle = self.mSinAngleTable[i] echoLine = self.mEchoLines[i] echoLine.Draw(p, self.mCenter, self.mRadius, cosAngle, sinAngle, self.mRange, self.mPrecision) # 清除回波线上的上一帧数据 def __DrawShadeLine(self, p, i): pen = QPen(QColor(0, 0, 0)) angle = i / gEchoLineCountAFrame * 2 * gPI - 90 * g1Deg + g1Deg xStart = int(self.mCenter.x()) yStart = int(self.mCenter.y()) xEnd = int(self.mRadius * math.cos(angle) + xStart) yEnd = int(self.mRadius * math.sin(angle) + yStart) p.setPen(pen) p.drawLine(xStart, yStart, xEnd, yEnd) def __DrawCircle(self, p, center, r): x = center.x() - r y = center.y() - r width = 2 * r height = 2 * r p.drawEllipse(x, y, width, height)
class VispaWidgetOwner(object): """ Interface for classes containing VispaWidgets Only makes sense if implementing class also inherits QWidget or class inheriting QWidget. """ def enableMultiSelect(self, multiSelect=True): self._multiSelectEnabledFlag = multiSelect def multiSelectEnabled(self): return hasattr(self, "_multiSelectEnabledFlag") and self._multiSelectEnabledFlag def selectedWidgets(self): """ Returns a list of all selected widgets. """ if hasattr(self, "_selectedWidgets"): return self._selectedWidgets return [child for child in self.children() if hasattr(child, "isSelected") and child.isSelected()] def widgetSelected(self, widget, multiSelect=False): """ Forward selection information to super class if it is a VispaWidgetOwner. """ logging.debug(self.__class__.__name__ +": widgetSelected()") if isinstance(self, QObject): if not hasattr(self, "_selectedWidgets"): self._selectedWidgets = [] if not multiSelect or not self.multiSelectEnabled(): self.deselectAllWidgets(widget) self._selectedWidgets = [] if widget.parent() == self and not widget in self._selectedWidgets: self._selectedWidgets.append(widget) for widget in [child for child in self._selectedWidgets if hasattr(child, "isSelected") and not child.isSelected()]: self._selectedWidgets.remove(widget) if isinstance(self.parent(), VispaWidgetOwner): self.parent().widgetSelected(widget) def widgetDoubleClicked(self, widget): """ Forward selection information to super class if it is a VispaWidgetOwner. """ #logging.debug(self.__class__.__name__ +": widgetDoubleClicked()") if isinstance(self, QObject): if isinstance(self.parent(), VispaWidgetOwner): self.parent().widgetDoubleClicked(widget) def initWidgetMovement(self, widget): self._lastMovedWidgets = [] if self.multiSelectEnabled(): pos = widget.pos() for child in self.children(): if child != widget and hasattr(child, "isSelected") and child.isSelected(): child.setDragReferencePoint(pos - child.pos()) def widgetDragged(self, widget): """ Tell parent widget has moved. Only informs parent if it is a VispaWidgetOwner, too. """ if isinstance(self.parent(), VispaWidgetOwner): self.parent().widgetDragged(widget) if hasattr(self, "_lastMovedWidgets"): self._lastMovedWidgets.append(widget) if self.multiSelectEnabled(): for child in self.children(): if hasattr(child, "dragReferencePoint") and child != widget and hasattr(child, "isSelected") and child.isSelected(): if hasattr(child, "setPreviousDragPosition"): child.setPreviousDragPosition(child.pos()) child.move(widget.pos() - child.dragReferencePoint()) self._lastMovedWidgets.append(child) # apparently unused feature (2010-07-02), remove if really unnecessary # also see self._lastMovedWidget definition above def lastMovedWidgets(self): if hasattr(self, "_lastMovedWidgets"): return self._lastMovedWidgets return None def widgetAboutToDelete(self, widget): """ This function is called from the delete() function of VispaWidget. """ pass def keyPressEvent(self, event): """ Calls delete() method of selected child widgets if multi-select is activated. """ if self.multiSelectEnabled() and ( event.key() == Qt.Key_Backspace or event.key() == Qt.Key_Delete ): selection = self.selectedWidgets()[:] for widget in selection: widget.delete() def deselectAllWidgets(self, exception=None): """ Deselects all widgets except the widget given as exception. """ #logging.debug(self.__class__.__name__ +": deselectAllWidgets()") self._selectedWidgets = [] for child in self.children(): if child != exception: if hasattr(child, 'select'): child.select(False) else: self._selectedWidgets.append(child) if isinstance(child, VispaWidgetOwner): child.deselectAllWidgets(exception) self.update() def mousePressEvent(self, event): """ Calls deselectAllWidgets. """ multiSelectEnabled = self.multiSelectEnabled() if event.modifiers() != Qt.ControlModifier: self.deselectAllWidgets() if multiSelectEnabled: self._selectionRectStartPos = QPoint(event.pos()) self._selectionRect = None def mouseMoveEvent(self, event): if self.multiSelectEnabled() and self._selectionRectStartPos and (event.pos() - self._selectionRectStartPos).manhattanLength() >= QApplication.startDragDistance(): eventX = event.pos().x() eventY = event.pos().y() startX = self._selectionRectStartPos.x() startY = self._selectionRectStartPos.y() oldRect = self._selectionRect self._selectionRect = QRect(min(startX, eventX), min(startY, eventY), abs(eventX - startX), abs(eventY - startY)) if oldRect: self.update(self._selectionRect.united(oldRect).adjusted(-5, -5, 5, 5)) else: self.update(self._selectionRect) # dynamically update selection statur # currently bad performance (2010-07-07) # TODO: improve selection mechanism # for child in self.children(): # if hasattr(child, "select") and hasattr(child, "isSelected"): # child.select(self._selectionRect.contains(child.geometry()), True) # select, mulitSelect def mouseReleaseEvent(self, event): if hasattr(self, "_selectionRect") and self._selectionRect and self.multiSelectEnabled(): for child in self.children(): if hasattr(child, "select") and hasattr(child, "isSelected") and self._selectionRect.contains(child.geometry()) and not child.isSelected(): child.select(True, True) # select, mulitSelect self.update(self._selectionRect.adjusted(-5, -5, 5, 5)) self._selectionRect = None self._selectionRectStartPos = None
class EchoSet(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.mCenter = QPoint(0, 0) self.mRadius = 0 self.mEchoLines = [] self.mEchoLinesIndex = 0 self.SetCenter(QPoint(0,0)) self.SetRadius(0) self.SetRange("50m") self.SetHdt(0) # 制作回波线角度表,用于提升性能 step = 2.0 * gPI / gEchoLineCountAFrame self.mCosAngleTable = [] self.mSinAngleTable = [] for i in range(0, gEchoLineCountAFrame): self.mCosAngleTable.append(0) self.mSinAngleTable.append(0) for i in range(0, gEchoLineCountAFrame): angle = i * step - 90 * g1Deg self.mCosAngleTable[i] = math.cos(angle) self.mSinAngleTable[i] = math.sin(angle) def SetData(self, echoSetStrs): for echoStr in echoSetStrs: echoLine = EchoLine(echoStr) self.mEchoLines.append(echoLine) # 绘制时的圆心坐标 def SetCenter(self, center): self.mCenter = center; # 绘制半径 def SetRadius(self, radius): self.mRadius = radius * gRadarEchoScale # 设置量程 def SetRange(self, radarRange): assert radarRange in gRangeTable, "量程表中没有量程:" + radarRange self.mRangeName = radarRange self.mRange = gRangeTable[radarRange][0] self.mPrecision = gRangeTable[radarRange][1] # 设置船艏向 def SetHdt(self, hdt): self.mHdt = 0 # 绘制 def Draw(self, p): self.__DrawAEchoLine(p, self.mEchoLinesIndex) self.__DrawShipHeadLine(p) self.__DrawDisCircle(p) self.__DrawRangeCicle(p) self.__DrawSysInfo(p) self.mEchoLinesIndex += 1 indexMax = len(self.mEchoLines) if self.mEchoLinesIndex == indexMax: self.mEchoLinesIndex = 0 # 绘制量程范围 def __DrawRangeCicle(self, p): pen = QPen(QColor(0, 255, 0)) p.setPen(pen) # 绘制距标圈 def __DrawDisCircle(self, p): pen = QPen(QColor(0, 150, 0)) p.setPen(pen) p.setBrush(Qt.NoBrush) r = self.mRadius rHalf = 0.5 * r rHalfOne = 1.5 * r self.__DrawCircle(p, self.mCenter, r) self.__DrawCircle(p, self.mCenter, rHalf) self.__DrawCircle(p, self.mCenter, rHalfOne) # 绘制船艏线 def __DrawShipHeadLine(self, p): pen = QPen(QColor(255, 255, 255)) p.setPen(pen) angle = self.mHdt - 90 * g1Deg xStart = int(self.mCenter.x()) yStart = int(self.mCenter.y()) xEnd = int(self.mRadius * math.cos(angle) + xStart) yEnd = int(self.mRadius * math.sin(angle) + yStart) p.drawLine(xStart, yStart, xEnd, yEnd) brush = QBrush(QColor(255, 255, 255), Qt.SolidPattern); p.setBrush(brush); angle = self.mHdt + 90 * g1Deg ang = angle - 30 * g1Deg; cos_a = math.cos(ang); sin_a = math.sin(ang); x1 = xEnd + gShipLegendLen * cos_a; y1 = yEnd - gShipLegendLen * sin_a; ang = angle + 30 * g1Deg; cos_a = math.cos(ang); sin_a = math.sin(ang); x2 = xEnd + gShipLegendLen * cos_a; y2 = yEnd - gShipLegendLen * sin_a; p1 = QPointF(xEnd, yEnd) p2 = QPointF(x1, y1) p3 = QPointF(x2, y2) p.drawPolygon(p1, p2, p3); # 绘制系统信息 def __DrawSysInfo(self, p): pen = QPen(QColor(0, 255, 0)) p.setPen(pen) p.drawText(2, 20, "量程:" + self.mRangeName) p.drawText(2, 40, "船艏:" + str(self.mHdt) + "度") # 绘制回波 def __DrawAEchoLine(self, p, i): self.__DrawShadeLine(p, i) echoLinsCount = len(self.mEchoLines) if 0 == echoLinsCount: return assert i < echoLinsCount, "回波线索引越界" # TODO: 使用查表法 提速 cosAngle = self.mCosAngleTable[i] sinAngle = self.mSinAngleTable[i] echoLine = self.mEchoLines[i] echoLine.Draw(p, self.mCenter, self.mRadius, cosAngle, sinAngle, self.mRange, self.mPrecision) # 清除回波线上的上一帧数据 def __DrawShadeLine(self,p, i): pen = QPen(QColor(0, 0, 0)) angle = i / gEchoLineCountAFrame * 2 * gPI - 90 * g1Deg + g1Deg xStart = int(self.mCenter.x()) yStart = int(self.mCenter.y()) xEnd = int(self.mRadius * math.cos(angle) + xStart) yEnd = int(self.mRadius * math.sin(angle) + yStart) p.setPen(pen) p.drawLine(xStart, yStart, xEnd, yEnd) def __DrawCircle(self, p, center, r): x = center.x() - r y = center.y() - r width = 2 * r height = 2 * r p.drawEllipse(x, y, width, height)
def click_by_gui_simulation(self, element): """Uses Qt GUI-level events to simulate a full user click. Takes a QWebElement as input. Implementation taken from Artemis: https://github.com/cs-au-dk/Artemis/blob/720f051c4afb4cd69e560f8658ebe29465c59362/artemis-code/src/runtime/input/clicksimulator.cpp#L73 Method: * Find coordinates of the centre of the element. * Scroll viewport to show element. * Generate a GUI click at those coordinates. N.B. This will be different from click(..., full_simulation=True) in cases where the target element is obscured. In these cases the click will go at the centre coordinates of the taregt element, whether that means we click the target or the obscuring element. """ verbose = False # We can avoid pulling the position from JavaScript (as Artemis needs to) because we allow the browser to process events all the time, so it should respond to position updates OK. targetCoordsInPage = element.geometry().center() targetCoords = QPoint( targetCoordsInPage.x() - self.page().mainFrame().scrollBarValue(Qt.Horizontal), targetCoordsInPage.y() - self.page().mainFrame().scrollBarValue(Qt.Vertical)) viewportSize = self.page().viewportSize() if verbose: print "click_by_gui_simulation: Clicking viewport coordinates ({}, {})".format( targetCoords.x(), targetCoords.y()) print "click_by_gui_simulation:", element.toOuterXml() print "click_by_gui_simulation: Dimensions of web view are X: {} Y: {}".format( viewportSize.width(), viewportSize.height()) if ((viewportSize.width() + self.page().mainFrame().scrollBarValue( Qt.Horizontal)) < targetCoords.x() or self.page().mainFrame().scrollBarValue( Qt.Horizontal) > targetCoords.x() or (viewportSize.height() + self.page().mainFrame().scrollBarValue( Qt.Vertical)) < targetCoords.y() or self.page().mainFrame().scrollBarValue( Qt.Vertical) > targetCoords.y()): if verbose: print "click_by_gui_simulation: Target outside viewport, repositioning" xScroll = min( self.page().mainFrame().contentsSize().width() - viewportSize.width(), # Scroll to the far right max( 0, # Don't scroll / Scroll to the far left targetCoords.x() - (viewportSize.width() / 2) # Put the target in the middle )) self.page().mainFrame().setScrollBarValue(Qt.Horizontal, xScroll) yScroll = min( self.page().mainFrame().contentsSize().height() - viewportSize.height(), # Scroll to the bottom max( 0, # Don't scroll / Scroll to the top targetCoords.y() - (viewportSize.height() / 2))) self.page().mainFrame().setScrollBarValue(Qt.Vertical, yScroll) targetCoords = QPoint(targetCoords.x() - xScroll, targetCoords.y() - yScroll) if verbose: print "click_by_gui_simulation: Changed coordinates to ({}, {})".format( targetCoords.x(), targetCoords.y()) #element.setFocus(); # This is already implied by the browser handling the click. # Click the target element's coordinates. mouseButtonPress = QMouseEvent(QEvent.MouseButtonPress, targetCoords, Qt.LeftButton, Qt.LeftButton, Qt.NoModifier) QApplication.sendEvent(self.page(), mouseButtonPress) mouseButtonRelease = QMouseEvent(QEvent.MouseButtonRelease, targetCoords, Qt.LeftButton, Qt.LeftButton, Qt.NoModifier) QApplication.sendEvent(self.page(), mouseButtonRelease)
class MikiView(QWebView): def __init__(self, parent=None): super(MikiView, self).__init__(parent) self.parent = parent self.settings().clearMemoryCaches() self.notePath = parent.settings.notePath self.settings().setUserStyleSheetUrl( QUrl('file://' + self.parent.settings.cssfile)) print(QUrl('file://' + self.parent.settings.cssfile)) self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) self.page().linkClicked.connect(self.linkClicked) self.page().linkHovered.connect(self.linkHovered) self.page().mainFrame().contentsSizeChanged.connect( self.contentsSizeChanged) self.scrollPosition = QPoint(0, 0) def linkClicked(self, qurl): '''three kinds of link: external uri: http/https page ref link: toc anchor link: # ''' name = qurl.toString() http = re.compile('https?://') if http.match(name): # external uri QDesktopServices.openUrl(qurl) return self.load(qurl) name = name.replace('file://', '') name = name.replace(self.notePath, '').split('#') item = self.parent.notesTree.pageToItem(name[0]) if not item or item == self.parent.notesTree.currentItem(): return else: self.parent.notesTree.setCurrentItem(item) if len(name) > 1: link = "file://" + self.notePath + "/#" + name[1] self.load(QUrl(link)) viewFrame = self.page().mainFrame() self.scrollPosition = viewFrame.scrollPosition() def linkHovered(self, link, title, textContent): '''show link in status bar ref link shown as: /parent/child/pageName toc link shown as: /parent/child/pageName#anchor (ToFix) ''' # TODO: link to page by: /parent/child/pageName#anchor if link == '': # not hovered self.parent.statusBar.showMessage( self.parent.notesTree.currentPage()) else: # beautify link link = link.replace('file://', '') link = link.replace(self.notePath, '') self.parent.statusBar.showMessage(link) def contentsSizeChanged(self, newSize): '''scroll notesView while editing (adding new lines) Whithout this, every `updateView` will result in scroll to top. ''' if self.scrollPosition == QPoint(0, 0): return viewFrame = self.page().mainFrame() newY = self.scrollPosition.y() + newSize.height( ) - self.contentsSize.height() self.scrollPosition.setY(newY) viewFrame.setScrollPosition(self.scrollPosition) def updateView(self): # url_notebook = 'file://' + os.path.join(self.notePath, '/') viewFrame = self.page().mainFrame() # Store scrollPosition before update notesView self.scrollPosition = viewFrame.scrollPosition() self.contentsSize = viewFrame.contentsSize() url_notebook = 'file://' + self.notePath + '/' self.setHtml(self.parent.notesEdit.toHtml(), QUrl(url_notebook)) # Restore previous scrollPosition viewFrame.setScrollPosition(self.scrollPosition) def updateLiveView(self): if self.parent.actions.get('split').isChecked(): QTimer.singleShot(1000, self.updateView)
class VisionneurImagePourEKD(QScrollArea): ''' Classe pour l'affichage des images (avec des barres de défilement)''' def __init__(self, img=None): QScrollArea.__init__(self) # Déclaration du drapeau: a-t-on chargé un *.gif if img and os.path.splitext(img)[1]!=".gif": self.gif = 1 else: self.gif = 0 # Facteur de redimensionnement de l'image à afficher par rapport à la taille réelle de l'image self.factor = 1 # Variables de paramètres self.modeTransformation=Qt.SmoothTransformation #self.modeTransformation=Qt.FastTransformation # widget qui contiendra l'image self.imageLabel = QLabel() self.imageLabel.setAlignment(Qt.AlignCenter) self.setBackgroundRole(QPalette.Dark) self.setWidget(self.imageLabel) # Indispensable pour ne pas avoir d'images tronquées, lors du chargement de nvll img self.setWidgetResizable(True) # Position du curseur dans le QScrollArea au moment du clic de la souris self.positionPresseeSourisIni = QPoint() # Position du point haut-gauche du QScrollArea par rapport au QPixMap entier au # moment du clic de la souris (par la suite appelée "position de la barre de défilement") self.positionBarrePresseeSourisIni = QPoint() # Création du menu contextuel self.menuZoom=QMenu("Zoom") # Entrée zoom taille réelle self.menuTailleReelle=self.menuZoom.addAction(_(u'&Taille Réelle')) self.menuTailleReelle.setIcon(QIcon("Icones" + os.sep + "taillereelle.png")) self.connect(self.menuTailleReelle, SIGNAL("triggered()"), self.setTailleReelle) # Entrée zoom taille fenetre self.menuTailleFenetre=self.menuZoom.addAction(_(u'&Adapter à la fenêtre')) self.menuTailleFenetre.setIcon(QIcon("Icones" + os.sep + "fenetre.png")) self.connect(self.menuTailleFenetre, SIGNAL("triggered()"), self.setTailleFenetre) # Entrée zoom + self.menuZoomPlus=self.menuZoom.addAction(_(u'&Zoom Avant')) self.menuZoomPlus.setIcon(QIcon("Icones" + os.sep + "zoomplus.png")) self.connect(self.menuZoomPlus, SIGNAL("triggered()"), self.zoomAvant) # Entrée zoom - self.menuZoomMoins=self.menuZoom.addAction(_(u'&Zoom Arrière')) self.menuZoomMoins.setIcon(QIcon("Icones" + os.sep + "zoommoins.png")) self.connect(self.menuZoomMoins, SIGNAL("triggered()"), self.zoomArriere) # Entrée mettre en pause/démarrer l'animation du gif self.menuStartPauseGif=self.menuZoom.addAction(_(u"Mettre en pause/démarrer l'animation")) self.menuStartPauseGif.setIcon(QIcon("Icones" + os.sep + "player_end.png")) self.connect(self.menuStartPauseGif, SIGNAL("triggered()"), self.startPauseGif) # Entrée mettre en pause/démarrer l'animation du gif self.menuStopGif=self.menuZoom.addAction(_(u"Arrêter l'animation")) self.menuStopGif.setIcon(QIcon("Icones" + os.sep + "player_stop.png")) self.connect(self.menuStopGif, SIGNAL("triggered()"), self.stopGif) # On cache les 2 menus de *.gif si on ne traite pas ce format if not self.gif: self.menuStartPauseGif.setVisible(False) self.menuStopGif.setVisible(False) # Si une image est en paramètre de classe, on l'affiche directement # sinon on pourra toujours l'afficher plus tard en appelant la # méthode setImage(), le moment venu if img: self.setImage(img) self.setToolTip(img) else: # image par défaut self.setImage("Icones" + os.sep + "avant-image.png") self.setToolTip(_(u"image d'accueil")) self.setTailleReelle() def mousePressEvent(self, event): "Menu contextuel et enregistrement de données préparant le déplacement de l'image par pincement" # Menu contextuel if event.button() == Qt.RightButton: self.menuZoom.popup(event.globalPos()) # On enregistre la position du curseur et de la barre de défilement au moment du clic elif event.button() == Qt.LeftButton: self.positionPresseeSourisIni = QPoint(event.pos()) self.positionBarrePresseeSourisIni.setX(self.horizontalScrollBar().value()) self.positionBarrePresseeSourisIni.setY(self.verticalScrollBar().value()) if PYQT_VERSION_STR >= "4.1.0": # curseur main fermée self.setCursor(Qt.ClosedHandCursor) else: self.setCursor(Qt.SizeAllCursor) event.accept() def mouseMoveEvent(self, event): "Déplacement de l'image dans le QScrollArea quand la souris est pressée" if self.positionPresseeSourisIni.isNull(): event.ignore() return # Nouvelles positions de la barre de défilement (selon x et y) self.horizontalScrollBar().setValue(self.positionBarrePresseeSourisIni.x() + (self.positionPresseeSourisIni.x() - event.pos().x())) self.verticalScrollBar().setValue(self.positionBarrePresseeSourisIni.y() + (self.positionPresseeSourisIni.y() - event.pos().y())) self.horizontalScrollBar().update() self.verticalScrollBar().update() event.accept() def mouseReleaseEvent(self, event): "Réaffichage du curseur classique de la souris" self.setCursor(Qt.ArrowCursor) event.accept() def setScaleMode(self, mode): "Choix du mode de redimensionnement" # Mise à jour du paramètre self.modeTransformation=mode def setTailleFenetre(self): "Affichage taille fenetre" # Gestion de la taille #- Si l'image rentre ##- Si l'image est trop grande # On retaille l'image en gardant le ratio entre # le min (si l'image ne rentre pas dans le cadre), le max (sinon) de : # * La largeur de la fenetre # * La largeur de l'image # * La hauteur de la fenetre # * La hauteur de l'image if (self.preview.height() < self.height()) and (self.preview.width() < self.width()): width=max(self.preview.width(), self.width()) height=max(self.preview.height(), self.height()) else : width=min(self.preview.width(), self.width()) height=min(self.preview.height(), self.height()) if self.gif: self.redimGif(width - 5, height - 5) else: resultat = self.preview.get_preview().scaled(width - 5, height - 5, Qt.KeepAspectRatio, self.modeTransformation) debug(u"Preview : %s, taille : %d, %d" % (self.preview.get_imageName(), self.preview.width(), self.preview.height())) self.factor = min(float(self.height())/self.preview.height(), float(self.width())/self.preview.width()) #-- On met l'image et on redimensionne le Label pour les images simples if not self.gif: self.imageLabel.setPixmap(resultat) def setTailleReelle(self): "Fonction d'affichage en taille réelle" self.preview.origin() width, height = self.preview.width(), self.preview.height() # On redimensionne le label à la taille de l'image if self.gif: self.redimGif(width, height) else: self.imageLabel.setPixmap(self.preview.get_preview()) self.factor = 1 def zoomAvant(self): "Fonction de zoom avant 25%" # On redimensionne l'image à 125% de la taille actuelle factor = 5/4. * self.factor width = int(self.preview.width() * factor) height = int(self.preview.height() * factor) if self.gif: self.redimGif(width, height) else: image = self.preview.get_preview().scaled(width, height, Qt.KeepAspectRatio) self.imageLabel.setPixmap(image) self.factor = factor def zoomArriere(self): "Fonction de zoom arrière 25%" # On redimensionne l'image à 75% de la taille actuelle factor = 3/4. * self.factor width = int(self.preview.width() * factor) height = int(self.preview.height() * factor) if self.gif: self.redimGif(width, height) else: image = self.preview.get_preview().scaled(width, height, Qt.KeepAspectRatio) self.imageLabel.setPixmap(image) self.factor = factor def startPauseGif(self): "Démarrer/mettre en pause l'animation de l'image gif" if self.movie.state() == QMovie.NotRunning: self.movie.start() else: self.movie.setPaused(self.movie.state() != QMovie.Paused) def stopGif(self): "Arrêter l'animation de l'image gif" if self.movie.state() != QMovie.NotRunning: self.movie.stop() def redimGif(self, width, height): """Changer la taille d'affichage du gif en prenant soin d'arrêter et de reprendre l'animation si nécessaire. Il y a un petit bogue d'affichage sur la redimension (il disparait en changeant d'onglet ou de cadre et en revenant. """ etatInitial = self.movie.state() if etatInitial == QMovie.Running: self.movie.stop() self.movie.setScaledSize(QSize(width, height)) if etatInitial == QMovie.Running: self.movie.start() else: # On redémarre le gif sinon l'image n'est pas actualisée et reste à la même taille self.movie.start() self.movie.stop() def isGif(self): "Indique si l'image affichée est un gif. Le test est effectué sur l'extension du fichier" return self.gif def setImage(self, img=None, fauxChemin=None, anim=False): """Fonction de mise en place de l'image. Le faux chemin est utile pour dissocier le chemin que verra l'utilisateur du chemin de l'image affichée. Ils sont différents uniquement lorsqu'une image composite est affichée (cadres masque alpha 3D et image composite). L'argument "anim" dit si une image gif doit être animée. """ if not img: img = "Icones" + os.sep + "avant-image.png" self.setToolTip(_(u"image d'accueil")) self.setTailleReelle() return elif fauxChemin: self.setToolTip(fauxChemin) else: self.setToolTip(img) # Chargement du gif le cas échéant if isinstance(img, str) or isinstance(img, unicode): # En général extension = os.path.splitext(img)[1] elif isinstance(img, QString): # Pour selectWidget.py principalement extension = "." + QFileInfo(img).suffix() if extension == ".gif": self.menuStartPauseGif.setVisible(True) self.menuStopGif.setVisible(True) self.gif = 1 self.movie = QMovie(img) # On démarre le gif de toute façon sinon l'image n'est pas visible self.movie.start() if not anim: self.movie.stop() self.imageLabel.setMovie(self.movie) else: # Pour des images non-gif, on cache les menus d'animation self.menuStartPauseGif.setVisible(False) self.menuStopGif.setVisible(False) self.gif = 0 # Visiblement sous windows la taille du QScrollArea renvoie 0, # on passe par l'Objet à l'intérieur pour obtenir la taille de l'image à créer self.preview = EkdPreview(img, self.width(), 0, 10, False, True, True) #(chemin, largeur, qualité, cache?, keepRatio?, magnify? ) # Par défault on charge en taille fenetre self.setTailleFenetre()
class ScribbleArea(QWidget): """ this scales the image but it's not good, too many refreshes really mess it up!!! """ def __init__(self, w, h, parent=None): super(ScribbleArea, self).__init__(parent) self.setAttribute(Qt.WA_StaticContents) self.scribbling = 0 self.width = w self.height = h self.image_pen_width = 50 self.pen_width = 1 self.draw_color = Qt.red self.image = QImage(QSize(w, h), QImage.Format_RGB32) self.setMaximumSize(w * self.image_pen_width, w * self.image_pen_width) self.setMinimumSize(w * self.image_pen_width, h * self.image_pen_width) self.last_point = QPoint() self.clear_image() def set_draw_color(self, color): self.draw_color = color def array_draw(self, r, g, b, scale=1): for i in range(len(r)): self.image.setPixel(QPoint(i % 8, i // 8), (r[i] * scale << 16) | (g[i] * scale << 8) | b[i] * scale) self.update() def fill_image(self, color): self.image.fill(color) self.update() def clear_image(self): self.image.fill(Qt.black) self.update() def mousePressEvent(self, event): self.parent().state = self.parent().STATE_COLOR_SCRIBBLE if event.button() == Qt.LeftButton: self.last_point = event.pos() self.scribbling = 1 elif event.button() == Qt.RightButton: self.last_point = event.pos() self.scribbling = 2 def mouseMoveEvent(self, event): if (event.buttons() & Qt.LeftButton) and self.scribbling == 1: self.draw_line_to(event.pos()) elif (event.buttons() & Qt.RightButton) and self.scribbling == 2: self.draw_line_to(event.pos()) def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton and self.scribbling == 1: self.draw_line_to(event.pos()) self.scribbling = 0 elif event.button() == Qt.RightButton and self.scribbling == 2: self.draw_line_to(event.pos()) self.scribbling = 0 def paintEvent(self, event): painter = QPainter(self) painter.drawImage( event.rect(), self.image.scaledToWidth(self.width * self.image_pen_width)) def draw_line_to(self, end_point): painter = QPainter(self.image) painter.setPen( QPen(self.draw_color if self.scribbling == 1 else Qt.black, self.pen_width, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) painter.drawLine( QPoint(self.last_point.x() // self.image_pen_width, self.last_point.y() // self.image_pen_width), QPoint(end_point.x() // self.image_pen_width, end_point.y() // self.image_pen_width)) self.update() self.last_point = QPoint(end_point)
class View(KineticScrollArea): viewModeChanged = pyqtSignal(int) def __init__(self, parent=None): super(View, self).__init__(parent) self.setAlignment(Qt.AlignCenter) self.setBackgroundRole(QPalette.Dark) self.setMouseTracking(True) self._viewMode = FixedScale self._wheelZoomEnabled = True self._wheelZoomModifier = Qt.CTRL # delayed resize self._centerPos = False self._resizeTimer = QTimer(singleShot = True, timeout = self._resizeTimeout) def surface(self): """Returns our Surface, the widget drawing the page(s).""" sf = self.widget() if not sf: sf = surface.Surface(self) self.setSurface(sf) return sf def setSurface(self, sf): """Sets the given surface as our widget.""" self.setWidget(sf) # For some reason mouse tracking *must* be enabled on the child as well... sf.setMouseTracking(True) self.kineticScrollingActive.connect(sf.updateKineticCursor) def viewMode(self): """Returns the current ViewMode.""" return self._viewMode def setViewMode(self, mode): """Sets the current ViewMode.""" if mode == self._viewMode: return self._viewMode = mode if mode: self.fit() self.viewModeChanged.emit(mode) def wheelZoomEnabled(self): """Returns whether wheel zoom is enabled.""" return self._wheelZoomEnabled def setWheelZoomEnabled(self, enabled): """Sets whether wheel zoom is enabled. Wheel zoom is zooming using the mouse wheel and a keyboard modifier key (defaulting to Qt.CTRL). Use setWheelZoomModifier() to set a key (or key combination). """ self._wheelZoomEnabled = enabled def wheelZoomModifier(self): """Returns the modifier key to wheel-zoom with (defaults to Qt.CTRL).""" return self._wheelZoomModifier def setWheelZoomModifier(self, key): """Sets the modifier key to wheel-zoom with (defaults to Qt.CTRL). Can also be set to a ORed value, e.g. Qt.SHIFT|Qt.ALT. Only use Qt.ALT, Qt.CTRL, Qt.SHIFT and/or Qt.META. """ self._wheelZoomModifier = key def load(self, document): """Convenience method to load all the pages from the given Poppler.Document.""" self.surface().pageLayout().load(document) # dont do a fit() before the very first resize as the size is then bogus if self.viewMode(): self.fit() self.surface().pageLayout().update() def clear(self): """Convenience method to clear the current layout.""" self.surface().pageLayout().clear() self.surface().pageLayout().update() def scale(self): """Returns the scale of the pages in the View.""" return self.surface().pageLayout().scale() def setScale(self, scale): """Sets the scale of all pages in the View.""" self.surface().pageLayout().setScale(scale) self.surface().pageLayout().update() self.setViewMode(FixedScale) def visiblePages(self): """Yields the visible pages.""" rect = self.viewport().rect() rect.translate(-self.surface().pos()) rect.intersect(self.surface().rect()) return self.surface().pageLayout().pagesAt(rect) def redraw(self): """Redraws, e.g. when you changed rendering hints or papercolor on the document.""" pages = list(self.visiblePages()) documents = set(page.document() for page in pages) for document in documents: cache.clear(document) for page in pages: page.repaint() def fit(self): """(Internal). Fits the layout according to the view mode. Prevents scrollbar/resize loops by precalculating which scrollbars will appear. """ mode = self.viewMode() if mode == FixedScale: return maxsize = self.maximumViewportSize() # can vertical or horizontal scrollbars appear? vcan = self.verticalScrollBarPolicy() == Qt.ScrollBarAsNeeded hcan = self.horizontalScrollBarPolicy() == Qt.ScrollBarAsNeeded # width a scrollbar takes off the viewport size framewidth = 0 if self.style().styleHint(QStyle.SH_ScrollView_FrameOnlyAroundContents, None, self): framewidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) * 2 scrollbarextent = self.style().pixelMetric(QStyle.PM_ScrollBarExtent, None, self) + framewidth # first try to fit full size layout = self.surface().pageLayout() layout.fit(maxsize, mode) layout.reLayout() # minimal values minwidth = maxsize.width() minheight = maxsize.height() if vcan: minwidth -= scrollbarextent if hcan: minheight -= scrollbarextent # do width and/or height fit? fitw = layout.width() <= maxsize.width() fith = layout.height() <= maxsize.height() if not fitw and not fith: if vcan or hcan: layout.fit(QSize(minwidth, minheight), mode) elif mode & FitWidth and fitw and not fith and vcan: # a vertical scrollbar will appear w = minwidth layout.fit(QSize(w, maxsize.height()), mode) layout.reLayout() if layout.height() <= maxsize.height(): # now the vert. scrollbar would disappear! # enlarge it as long as the vertical scrollbar would not be needed while True: w += 1 layout.fit(QSize(w, maxsize.height()), mode) layout.reLayout() if layout.height() > maxsize.height(): layout.fit(QSize(w - 1, maxsize.height()), mode) break elif mode & FitHeight and fith and not fitw and hcan: # a horizontal scrollbar will appear h = minheight layout.fit(QSize(maxsize.width(), h), mode) layout.reLayout() if layout.width() <= maxsize.width(): # now the hor. scrollbar would disappear! # enlarge it as long as the horizontal scrollbar would not be needed while True: h += 1 layout.fit(QSize(maxsize.width(), h), mode) layout.reLayout() if layout.width() > maxsize.width(): layout.fit(QSize(maxsize.width(), h - 1), mode) break layout.update() def resizeEvent(self, ev): super(View, self).resizeEvent(ev) # Adjust the size of the document if desired if self.viewMode() and any(self.surface().pageLayout().pages()): if self._centerPos is False: self._centerPos = QPoint(0, 0) elif self._centerPos is None: # store the point currently in the center self._centerPos = self.viewport().rect().center() - self.surface().pos() if not self._resizeTimer.isActive(): self._resizeTimeout() self._resizeTimer.start(150) def _resizeTimeout(self): if self._centerPos is None: return oldSize = self.surface().size() # resize the layout self.fit() # restore our position newSize = self.surface().size() newx = self._centerPos.x() * newSize.width() / oldSize.width() newy = self._centerPos.y() * newSize.height() / oldSize.height() # we explicitely want the non-kinetic centering function regardless of kinetic state. self.fastCenter(QPoint(newx, newy)) self._centerPos = None def zoom(self, scale, pos=None): """Changes the display scale (1.0 is 100%). If pos is given, keeps that point at the same place if possible. Pos is a QPoint relative to ourselves. """ scale = max(0.05, min(4.0, scale)) if scale == self.scale(): return if self.surface().pageLayout().count() == 0: self.setScale(scale) return if pos is None: pos = self.viewport().rect().center() surfacePos = pos - self.surface().pos() page = self.surface().pageLayout().pageAt(surfacePos) if page: pagePos = surfacePos - page.pos() x = pagePos.x() / float(page.width()) y = pagePos.y() / float(page.height()) self.setScale(scale) newPos = QPoint(round(x * page.width()), round(y * page.height())) + page.pos() else: x = surfacePos.x() / float(self.surface().width()) y = surfacePos.y() / float(self.surface().height()) self.setScale(scale) newPos = QPoint(round(x * self.surface().width()), round(y * self.surface().height())) surfacePos = pos - self.surface().pos() # use fastScrollBy as we do not want kinetic scrolling here regardless of its state. self.fastScrollBy(newPos - surfacePos) def zoomIn(self, pos=None, factor=1.1): self.zoom(self.scale() * factor, pos) def zoomOut(self, pos=None, factor=1.1): self.zoom(self.scale() / factor, pos) def wheelEvent(self, ev): if (self._wheelZoomEnabled and int(ev.modifiers()) & _SCAM == self._wheelZoomModifier): factor = 1.1 ** (ev.delta() / 120) if ev.delta(): self.zoom(self.scale() * factor, ev.pos()) else: super(View, self).wheelEvent(ev) def mousePressEvent(self, ev): """Mouse press event handler. Passes the event to the surface, and back to the base class if the surface did not do anything with it.""" if not self.surface().handleMousePressEvent(ev): super(View, self).mousePressEvent(ev) def mouseReleaseEvent(self, ev): """Mouse release event handler. Passes the event to the surface, and back to the base class if the surface did not do anything with it.""" if not self.surface().handleMouseReleaseEvent(ev): super(View, self).mouseReleaseEvent(ev) def mouseMoveEvent(self, ev): """Mouse move event handler. Passes the event to the surface, and back to the base class if the surface did not do anything with it.""" if self.kineticIsIdle(): if self.surface().handleMouseMoveEvent(ev): return super(View, self).mouseMoveEvent(ev) def moveEvent(self, ev): """Move event handler. Passes the event to the surface if we've not started any kinetic move, and back to the base class if the surface did not do anything with it.""" if self.kineticIsIdle(): if self.surface().handleMoveEvent(ev): return super(View, self).moveEvent(ev) def event(self, ev): if isinstance(ev, QHelpEvent): if self.surface().handleHelpEvent(ev): ev.accept() return True return super(View, self).event(ev) def currentPage(self): """Returns the Page currently mostly in the center, or None if there are no pages.""" pos = self.viewport().rect().center() - self.surface().pos() layout = self.surface().pageLayout() if len(layout): d = layout.spacing() * 2 for dx, dy in ((0, 0), (-d, 0), (0, -d), (d, 0), (0, d)): dist = QPoint(dx, dy) page = layout.pageAt(pos + dist) if page: return page def currentPageNumber(self): """Returns the number (index in the layout) of the currentPage(), or -1 if there are no pages.""" page = self.currentPage() if page: return self.surface().pageLayout().index(page) return -1 def gotoPageNumber(self, num): """Aligns the page at the given index in the layout to the topleft of our View.""" layout = self.surface().pageLayout() if num < len(layout) and num != self.currentPageNumber(): margin = QPoint(layout.margin(), layout.margin()) self.scrollBy(layout[num].pos() + self.surface().pos() - margin) def position(self): """Returns a three-tuple(num, x, y) describing the page currently in the center of the View. the number is the index of the Page in the Layout, and x and y are the coordinates in the range 0.0 -> 1.0 of the point that is at the center of the View. This way a position can be retained even if the scale or the orientation of the Layout changed. Returns None, None, None if the layout is empty. """ page = self.currentPage() if page: layout = self.surface().pageLayout() pos = self.viewport().rect().center() - self.surface().pos() pagePos = pos - page.pos() x = pagePos.x() / float(page.width()) y = pagePos.y() / float(page.height()) return layout.index(page), x, y return None, None, None def setPosition(self, position, overrideKinetic=False): """Sets the position to a three-tuple as previously returned by position(). Setting overrideKinetic to true allows for fast setup, instead of scrolling all the way to the visible point. """ layout = self.surface().pageLayout() pageNum, x, y = position if pageNum is None or pageNum >= len(layout): return page = layout[pageNum] # center this point newPos = QPoint(round(x * page.width()), round(y * page.height())) + page.pos() if overrideKinetic: self.fastCenter(newPos) else: self.center(newPos)
class MainMayaWindow (QObject): ''' Base QObject for the JADE Maya scripted plugin. Notice the difference with the MainMWindow. This class is subclassing QObject while the Standalone one subclasses QWidget. This class handles the Maya way to deal with the contextual pop-up menu. Additionally, this class shares some of the responsibilities with graph.py. ''' def __init__ (self, graph, parent=None): '''constructor @param graph the model @param parent a parent QObject, or None for root window. ''' super (MainMayaWindow, self).__init__(parent) QObject.__init__(self) # initiation indispensable for sending and receiving signals! # define scene and constrain its workspace self.scene = QGraphicsScene () self.scene.setSceneRect (QRectF (-1000, -1000, 2000, 2000)) self.graph_model = graph self.helper = utility.Helper (self, self.scene, self.graph_model) self.graph_view = grv.GraphView (self.graph_model, self.helper) self.helper.setGraphView (self.graph_view) # wirings self.comm = self.graph_model.getComm () self.connect (self.comm, SIGNAL ('deleteNode_MSignal(int)'), self.graph_view.removeTag) self.connect (self.comm, SIGNAL ('addLink_MSignal(int,int)'), self.graph_view.addWire) self.connect (self.comm, SIGNAL ('deleteLink_MSignal(int,int)'), self.graph_view.checkIfEmpty) self.connect (self.comm, SIGNAL ('addNode_MSignal(int, float, float)'), self.graph_view.addTag) self.scene.addItem (self.helper.getHarpoon ()) self.hovered_tag_id = None # register a new command that takes care of deleting selected items and bind it to the key 'd'. cmds.nameCommand ('delSelection', ann='deleteSelectedItems', c='python (\"ClientMaya.ui.graph_view.removeSelectedItems ()\");') cmds.hotkey (k='d', name='delSelection') def setupUi (self, MainWindow): '''sets up the Maya UI. @param MainWindow ''' MainWindow.setObjectName ('MainWindow') MainWindow.resize (800, 1396) sizePolicy = QSizePolicy (QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch (0) sizePolicy.setVerticalStretch (0) sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) MainWindow.setSizePolicy(sizePolicy) font = QFont () font.setPointSize (11) MainWindow.setFont (font) MainWindow.setWindowTitle (QApplication.translate("MainWindow", "Location Tool", None, QApplication.UnicodeUTF8)) MainWindow.setTabShape (QTabWidget.Rounded) MainWindow.setDockOptions (QMainWindow.AllowTabbedDocks|QMainWindow.AnimatedDocks) self.scrollAreaWidgetContents_3 = QWidget (MainWindow) self.scrollAreaWidgetContents_3.setGeometry (QRect(10, 10, 900, 940)) self.scrollAreaWidgetContents_3.setObjectName ('scrollAreaWidgetContents_3') self._view = View0.View ("JADEview", self.graph_view, self.scene, self.scrollAreaWidgetContents_3) self._view.setObjectName ('JADEview') # real ui name self._view.graphicsView.setObjectName ('JADEInnerView') self.connect (self.scene, SIGNAL("selectionChanged()"), self._view.selectionChanged) self._view.wireViewItemsUp () self._view.getGraphicsView().setScene (self.scene) self._view.setToolboxCSSColorScheme ('background-color: rgb(68,68,68);color: rgb(200,200,200)') # this needs to be done since the toolbox's background didn't have a uniform colour otherwise. #self._view.setGraphicsViewCSSBackground () # the CSS background doesn't seem to work in Maya as there seems to be a problem with cleaning QGraphicsLineItems when they move, that doesn't happen when there's no CSS applied to the background. self.graphicsView = self._view.getGraphicsView () self.node_coords = QPoint (0,0) layout = QHBoxLayout (self.scrollAreaWidgetContents_3) layout.setContentsMargins (QMargins(0,0,0,0)); layout.addWidget (self._view) QMetaObject.connectSlotsByName (MainWindow) """ cmds.control('JADEInnerView', edit=True, ebg=True, bgc=[.5,.5,.9]) print cmds.control('JADEInnerView', query=True, p=True) """ # wiring the Maya Contextual pop-up Menus - yes, in Maya we've split the pop-up menu definition in three pop-up menus although only one will be present at any time. self.menu = cmds.popupMenu ('JADEmenu', parent='JADEInnerView', button=3, pmc = 'ClientMaya.ui.ctxMenu()', aob=True) self.menuAddOuts = cmds.popupMenu ('JADEmenuAddOuts', parent='JADEInnerView', button=3, pmc = 'ClientMaya.ui.ctxMenuAddOuts()', aob=True, alt=True) self.menuAddIns = cmds.popupMenu ('JADEmenuAddIns', parent='JADEInnerView', button=3, pmc = 'ClientMaya.ui.ctxMenuAddIns()', aob=True, ctl=True) # this class property is used to keep track of the mouse position. self._mouse = QCursor # self._view's zoom slider (we need this to correct the bias added to sort the mouse position when the zoom changes - ONLY in Maya) self._zoom_slider = self._view.getZoomSlider() # - - - context menus methods - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def ctxMenu (self): '''this method invokes the general Maya pop-up menu. ''' self.hovered_tag_id = self.comm.getHoveredItemId() cmds.popupMenu ('JADEmenu', edit=True, dai=True) # clear all the menu items out. if self.hovered_tag_id==None: # ctx menu to establish what node is going to be retrieved tmp_ls = [] [tmp_ls.append(key) for key in self.graph_model.getNodesDecription()] self.prepareGeneralCtxMenu (tmp_ls) def prepareGeneralCtxMenu (self, list0): '''populates the self.menu dynamically with available node infos. @param list0 list of menu items ''' self.node_coords = self.graphicsView.mapToScene (self._mouse.pos()) # populate the QMenu dynamically and pass the menu string name to the receiver for i in sorted (list0): cmds.menuItem (parent=self.menu, label=str(i), c='ClientMaya.ui.addTag ("'+str(i)+'")') def addTag (self, name0): '''adds a Tag0 instance by name. the constants added to the are needed to make the tag pop up near the mouse pointer. @param name0 string ''' if self._view.getCurrentClusterIndex () != 0: # the piece-wise linear interpolation below is a workaround only present in the Maya JADE mapping tool since # the self.graphicsView.mapToScene() doesn't seem to work as the standalone's one. if self._zoom_slider.value() > 199 and self._zoom_slider.value() < 241: x_bias = -22.5*(self._zoom_slider.value()-200) + 2100 y_bias = -3.75*(self._zoom_slider.value()-200) + 400 elif self._zoom_slider.value() > 240 and self._zoom_slider.value() < 281: x_bias = -12.5*(self._zoom_slider.value()-240) + 1200 y_bias = -2.5* (self._zoom_slider.value()-240) + 250 new_node = self.graph_model.addNode (name0, self.node_coords.x() - x_bias, self.node_coords.y() - y_bias) self._view.updateCurrentClusterNodeList (new_node) self._view.setMessageBarText ('') else: self._view.setMessageBarText ('** Choose or create a cluster first. Node not created.') def ctxMenuAddOuts (self): '''this method invokes the Maya add-outs pop-up menu. ''' self.hovered_tag_id = self.comm.getHoveredItemId() cmds.popupMenu ('JADEmenuAddOuts', edit=True, dai=True) # clear all the menu items out. if self.hovered_tag_id!=None: right_list = self.graph_model.getOutsTypesLeft (self.hovered_tag_id) if len(right_list)!=0: self.prepareNodeCtxMenuOnAddingOuts (right_list) def ctxMenuAddIns (self): '''this method invokes the Maya add-ins pop-up menu. ''' self.hovered_tag_id = self.comm.getHoveredItemId() cmds.popupMenu ('JADEmenuAddIns', edit=True, dai=True) # clear all the menu items out. if self.hovered_tag_id!=None: left_list = self.graph_model.getInsTypesLeft (self.hovered_tag_id) if len(left_list)!=0: self.prepareNodeCtxMenuOnAddingIns (left_list) def prepareNodeCtxMenuOnAddingOuts (self, list0): '''populates the self.menuAddOuts dynamically with available node infos. @param list0 list of menu items ''' for i in sorted(list0): cmds.menuItem (parent=self.menuAddOuts, label=str(i), c='ClientMaya.ui.addOutSocketAction ("'+str(i)+'")') self.helper.setMenu (self.menuAddOuts) def prepareNodeCtxMenuOnAddingIns (self, list0): '''populates the self.menuAddIns dynamically with available node infos. @param list0 list of menu items ''' for i in sorted (list0): cmds.menuItem (parent=self.menuAddIns, label=str(i), c='ClientMaya.ui.addInSocketAction ("'+str(i)+'")') self.helper.setMenu (self.menuAddIns) def addOutSocketAction (self, value): '''adds an out-socket name based on the pressed key modifier. @param value ''' self.graph_view.getTag (self.hovered_tag_id) # retrieve the tag the ctx menu was open above. # the event released by adding an InSocket signal will trigger the Tag0's method appendOutHook as a result. self.graph_model.addOutSocket (self.hovered_tag_id, value) def addInSocketAction (self, value): '''adds an in-socket name based on the pressed key modifier. @param value ''' self.graph_view.getTag (self.hovered_tag_id) # retrieve the tag the ctx menu was open above. # the event released by adding an InSocket signal will trigger the Tag0's method appendInHook() as a result. self.graph_model.addInSocket (self.hovered_tag_id, value)
class ThresholdingInterpreter(QObject): # states FINAL = 0 DEFAULT_MODE = 1 # normal navigation functionality THRESHOLDING_MODE = 2 # while pressing left mouse button allow thresholding NO_VALID_LAYER = 3 # not a grayscale layer @property def state(self): return self._current_state def __init__(self, navigationControler, layerStack, posModel): QObject.__init__(self) self._navCtrl = navigationControler self._navIntr = NavigationInterpreter(navigationControler) self._layerStack = layerStack self._active_layer = None self._active_channel_idx = -1 self._current_state = self.FINAL self._current_position = QPoint(0, 0) # Setting default values, scaled on actual data later on self._steps_mean = 10 self._steps_delta = self._steps_mean * 2 self._steps_scaling = 0.07 self._range_max = 4096.0 # hardcoded, in the case drange is not set in the data file or in the dataSelectionDialogue self._range_min = -4096.0 self._range = np.abs(self._range_max - self._range_min) self._channel_range = dict() self._posModel = posModel def start(self): if self._current_state == self.FINAL: self._navIntr.start() self._current_state = self.DEFAULT_MODE self._init_layer() else: pass def stop(self): self._current_state = self.FINAL if self.valid_layer(): self._active_layer.channelChanged.disconnect(self.channel_changed) self._navIntr.stop() def eventFilter(self, watched, event): etype = event.type() if self._current_state == self.DEFAULT_MODE: if etype == QEvent.MouseButtonPress \ and event.button() == Qt.LeftButton \ and event.modifiers() == Qt.NoModifier \ and self._navIntr.mousePositionValid(watched, event): # TODO maybe remove, if we can find out which view is active self.set_active_layer() if self.valid_layer(): self._current_state = self.THRESHOLDING_MODE self._current_position = watched.mapToGlobal(event.pos()) return True else: self._current_state = self.NO_VALID_LAYER return self._navIntr.eventFilter(watched, event) elif etype == QEvent.MouseButtonPress \ and event.button() == Qt.RightButton \ and event.modifiers() == Qt.NoModifier \ and self._navIntr.mousePositionValid(watched, event): self.set_active_layer() if self.valid_layer(): self.onRightClick_resetThreshold(watched, event) else: pass # do nothing return True else: return self._navIntr.eventFilter(watched, event) elif self._current_state == self.NO_VALID_LAYER: self.set_active_layer() if self.valid_layer(): self._current_state = self.DEFAULT_MODE return self._navIntr.eventFilter(watched, event) elif self._current_state == self.THRESHOLDING_MODE: if self._active_layer == None: # No active layer set, should not go here return self._navIntr.eventFilter(watched, event) if etype == QEvent.MouseButtonRelease and event.button( ) == Qt.LeftButton: self._current_state = self.DEFAULT_MODE self._active_layer = None self.onExit_threshold(watched, event) return True elif etype == QEvent.MouseMove and event.buttons( ) == Qt.LeftButton: self.onMouseMove_thresholding(watched, event) return True else: return self._navIntr.eventFilter(watched, event) else: # let the navigation interpreter handle common events return self._navIntr.eventFilter(watched, event) def onRightClick_resetThreshold(self, imageview, event): range = self.get_min_max_of_current_view(imageview) self._active_layer.set_normalize(0, (range[0], range[1])) self._channel_range[self._active_channel_idx] = (range[0], range[1]) def set_active_layer(self): """ determines the layer postion in the stack and the currently displayed channel. Needs to be called constantly, because the user can change the position of the input layer within the stack """ for idx, layer in enumerate(self._layerStack): if isinstance(layer, GrayscaleLayer): if layer.window_leveling: self._active_layer = layer self._active_channel_idx = layer._channel return self._active_layer = None def _init_layer(self): self.set_active_layer() if self.valid_layer(): self._active_layer.channelChanged.connect(self.channel_changed) if self.get_drange() != None: self._range_min, self._range_max = self.get_drange() def onExit_threshold(self, watched, event): pass def get_drange(self): """ returns tuple of drange (min, max) as set in hdf5 file or None if nothing is specified """ return self._active_layer._datasources[ 0]._rawSource._op5.Output.meta.drange def valid_layer(self): if isinstance(self._active_layer, GrayscaleLayer): return self._active_layer.window_leveling else: return False def channel_changed(self): self.set_active_layer() if self._active_channel_idx in self._channel_range: self._active_layer.set_normalize( 0, self._channel_range[self._active_channel_idx]) else: self._active_layer.set_normalize( 0, (self._range_min, self._range_max)) def get_min_max_of_current_view(self, imageview): """ Function returns min and max value of the current view based on the raw data. Ugly hack, but all we got for now """ shape2D = posView2D(list(self._posModel.shape5D[1:4]), axis=self._posModel.activeView) data_x, data_y = 0, 0 data_x2, data_y2 = shape2D[0], shape2D[1] if self._posModel.activeView == 0: x_pos = self._posModel.slicingPos5D[1] slicing = [ slice(0, 1), slice(x_pos, x_pos + 1), slice(data_x, data_x2), slice(data_y, data_y2), slice(self._active_channel_idx, self._active_channel_idx + 1) ] if self._posModel.activeView == 1: y_pos = self._posModel.slicingPos5D[2] slicing = [ slice(0, 1), slice(data_x, data_x2), slice(y_pos, y_pos + 1), slice(data_y, data_y2), slice(self._active_channel_idx, self._active_channel_idx + 1) ] if self._posModel.activeView == 2: z_pos = self._posModel.slicingPos5D[3] slicing = [ slice(0, 1), slice(data_x, data_x2), slice(data_y, data_y2), slice(z_pos, z_pos + 1), slice(self._active_channel_idx, self._active_channel_idx + 1) ] request = self._active_layer._datasources[0].request(slicing) result = request.wait() return result.min(), result.max() def onMouseMove_thresholding(self, imageview, event): if self._active_channel_idx not in self._channel_range: range = self.get_min_max_of_current_view(imageview) range_lower = range[0] range_upper = range[1] else: range = self._channel_range[self._active_channel_idx] range_lower = range[0] range_upper = range[1] # don't know what version is more efficient # range_delta = np.sqrt((range_upper - range_lower)**2) range_delta = np.abs(range_upper - range_lower) range_mean = range_lower + range_delta / 2.0 self._steps_mean = range_delta * self._steps_scaling self._steps_delta = self._steps_mean * 2 pos = imageview.mapToGlobal(event.pos()) dx = pos.x() - self._current_position.x() dy = self._current_position.y() - pos.y() if dx > 0.0: # move mean to right range_mean += self._steps_mean elif dx < 0.0: # move mean to left range_mean -= self._steps_mean if dy > 0.0: # increase delta range_delta += self._steps_delta elif dy < 0.0: # decrease delta range_delta -= self._steps_delta # check the bounds, ugly use min max values actually present if range_mean < self._range_min: range_mean = self._range_min elif range_mean > self._range_max: range_mean = self._range_max if range_delta < 1: range_delta = 1 elif range_delta > self._range: range_delta = self._range a = range_mean - range_delta / 2.0 b = range_mean + range_delta / 2.0 if a < self._range_min: a = self._range_min elif a > self._range_max: a = self._range_max if b < self._range_min: b = self._range_min elif b > self._range_max: b = self._range_max assert a <= b # TODO test if in allowed range (i.e. max and min of data) self._active_layer.set_normalize(0, (a, b)) self._channel_range[self._active_channel_idx] = (a, b) self._current_position = pos
class WebPage(QObject): initialized = pyqtSignal() javaScriptAlertSent = pyqtSignal(str) javaScriptConsoleMessageSent = pyqtSignal(str, int, str) loadStarted = pyqtSignal() loadFinished = pyqtSignal(str) resourceReceived = pyqtSignal('QVariantMap') resourceRequested = pyqtSignal('QVariantMap') blankHtml = '<html><head></head><body></body></html>' def __init__(self, parent, args): super(WebPage, self).__init__(parent) # variable declarations self.m_paperSize = {} self.m_clipRect = QRect() self.m_libraryPath = '' self.m_scrollPosition = QPoint() self.setObjectName('WebPage') self.m_webPage = CustomPage(self) self.m_mainFrame = self.m_webPage.mainFrame() self.m_mainFrame.javaScriptWindowObjectCleared.connect(self.initialized) self.m_webPage.loadStarted.connect(self.loadStarted) self.m_webPage.loadFinished.connect(self.finish) # Start with transparent background palette = self.m_webPage.palette() palette.setBrush(QPalette.Base, Qt.transparent) self.m_webPage.setPalette(palette) # Page size does not need to take scrollbars into account self.m_webPage.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff) self.m_webPage.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff) self.m_webPage.settings().setAttribute(QWebSettings.OfflineStorageDatabaseEnabled, True) self.m_webPage.settings().setOfflineStoragePath(QDesktopServices.storageLocation(QDesktopServices.DataLocation)) self.m_webPage.settings().setAttribute(QWebSettings.LocalStorageDatabaseEnabled, True) self.m_webPage.settings().setAttribute(QWebSettings.OfflineWebApplicationCacheEnabled, True) self.m_webPage.settings().setOfflineWebApplicationCachePath(QDesktopServices.storageLocation(QDesktopServices.DataLocation)) self.m_webPage.settings().setAttribute(QWebSettings.FrameFlatteningEnabled, True) self.m_webPage.settings().setAttribute(QWebSettings.LocalStorageEnabled, True) self.m_webPage.settings().setLocalStoragePath(QDesktopServices.storageLocation(QDesktopServices.DataLocation)) # Ensure we have a document.body. self.m_webPage.mainFrame().setHtml(self.blankHtml) # Custom network access manager to allow traffic monitoring self.m_networkAccessManager = NetworkAccessManager(self.parent(), args) self.m_webPage.setNetworkAccessManager(self.m_networkAccessManager) self.m_networkAccessManager.resourceRequested.connect(self.resourceRequested) self.m_networkAccessManager.resourceReceived.connect(self.resourceReceived) self.m_webPage.setViewportSize(QSize(400, 300)) do_action('WebPageInit') def applySettings(self, defaults): opt = self.m_webPage.settings() opt.setAttribute(QWebSettings.AutoLoadImages, defaults['loadImages']) opt.setAttribute(QWebSettings.PluginsEnabled, defaults['loadPlugins']) opt.setAttribute(QWebSettings.JavascriptEnabled, defaults['javascriptEnabled']) opt.setAttribute(QWebSettings.XSSAuditingEnabled, defaults['XSSAuditingEnabled']) opt.setAttribute(QWebSettings.LocalContentCanAccessRemoteUrls, defaults['localToRemoteUrlAccessEnabled']) if 'userAgent' in defaults: self.m_webPage.m_userAgent = defaults['userAgent'] if 'userName' in defaults: self.m_networkAccessManager.m_userName = defaults['userName'] if 'password' in defaults: self.m_networkAccessManager.m_password = defaults['password'] def finish(self, ok): status = 'success' if ok else 'fail' self.loadFinished.emit(status) def mainFrame(self): return self.m_mainFrame def renderImage(self): contentsSize = self.m_mainFrame.contentsSize() contentsSize -= QSize(self.m_scrollPosition.x(), self.m_scrollPosition.y()) frameRect = QRect(QPoint(0, 0), contentsSize) if not self.m_clipRect.isEmpty(): frameRect = self.m_clipRect viewportSize = self.m_webPage.viewportSize() self.m_webPage.setViewportSize(contentsSize) image = QImage(frameRect.size(), QImage.Format_ARGB32) image.fill(qRgba(255, 255, 255, 0)) painter = QPainter() # We use tiling approach to work-around Qt software rasterizer bug # when dealing with very large paint device. # See http://code.google.com/p/phantomjs/issues/detail?id=54. tileSize = 4096 htiles = (image.width() + tileSize - 1) / tileSize vtiles = (image.height() + tileSize - 1) / tileSize for x in range(htiles): for y in range(vtiles): tileBuffer = QImage(tileSize, tileSize, QImage.Format_ARGB32) tileBuffer.fill(qRgba(255, 255, 255, 0)) # Render the web page onto the small tile first painter.begin(tileBuffer) painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHint(QPainter.TextAntialiasing, True) painter.setRenderHint(QPainter.SmoothPixmapTransform, True) painter.translate(-frameRect.left(), -frameRect.top()) painter.translate(-x * tileSize, -y * tileSize) self.m_mainFrame.render(painter, QRegion(frameRect)) painter.end() # Copy the tile to the main buffer painter.begin(image) painter.setCompositionMode(QPainter.CompositionMode_Source) painter.drawImage(x * tileSize, y * tileSize, tileBuffer) painter.end() self.m_webPage.setViewportSize(viewportSize) return image # Different defaults. # OSX: 72, X11: 75(?), Windows: 96 pdf_dpi = 72 def renderPdf(self, fileName): p = QPrinter() p.setOutputFormat(QPrinter.PdfFormat) p.setOutputFileName(fileName) p.setResolution(self.pdf_dpi) paperSize = self.m_paperSize if not len(paperSize): pageSize = QSize(self.m_webPage.mainFrame().contentsSize()) paperSize['width'] = str(pageSize.width()) + 'px' paperSize['height'] = str(pageSize.height()) + 'px' paperSize['border'] = '0px' if paperSize.get('width') and paperSize.get('height'): sizePt = QSizeF(ceil(self.stringToPointSize(paperSize['width'])), ceil(self.stringToPointSize(paperSize['height']))) p.setPaperSize(sizePt, QPrinter.Point) elif 'format' in paperSize: orientation = QPrinter.Landscape if paperSize.get('orientation') and paperSize['orientation'].lower() == 'landscape' else QPrinter.Portrait orientation = QPrinter.Orientation(orientation) p.setOrientation(orientation) formats = { 'A0': QPrinter.A0, 'A1': QPrinter.A1, 'A2': QPrinter.A2, 'A3': QPrinter.A3, 'A4': QPrinter.A4, 'A5': QPrinter.A5, 'A6': QPrinter.A6, 'A7': QPrinter.A7, 'A8': QPrinter.A8, 'A9': QPrinter.A9, 'B0': QPrinter.B0, 'B1': QPrinter.B1, 'B2': QPrinter.B2, 'B3': QPrinter.B3, 'B4': QPrinter.B4, 'B5': QPrinter.B5, 'B6': QPrinter.B6, 'B7': QPrinter.B7, 'B8': QPrinter.B8, 'B9': QPrinter.B9, 'B10': QPrinter.B10, 'C5E': QPrinter.C5E, 'Comm10E': QPrinter.Comm10E, 'DLE': QPrinter.DLE, 'Executive': QPrinter.Executive, 'Folio': QPrinter.Folio, 'Ledger': QPrinter.Ledger, 'Legal': QPrinter.Legal, 'Letter': QPrinter.Letter, 'Tabloid': QPrinter.Tabloid } p.setPaperSize(QPrinter.A4) # fallback for format_, size in formats.items(): if format_.lower() == paperSize['format'].lower(): p.setPaperSize(size) break else: return False border = floor(self.stringToPointSize(paperSize['border'])) if paperSize.get('border') else 0 p.setPageMargins(border, border, border, border, QPrinter.Point) self.m_webPage.mainFrame().print_(p) return True def stringToPointSize(self, string): units = ( ('mm', 72 / 25.4), ('cm', 72 / 2.54), ('in', 72.0), ('px', 72.0 / self.pdf_dpi / 2.54), ('', 72.0 / self.pdf_dpi / 2.54) ) for unit, format_ in units: if string.endswith(unit): value = string.rstrip(unit) return float(value) * format_ return 0 def userAgent(self): return self.m_webPage.m_userAgent ## # Properties and methods exposed to JavaScript ## @pyqtSlot(str) def _appendScriptElement(self, scriptUrl): self.m_mainFrame.evaluateJavaScript(''' var el = document.createElement('script'); el.onload = function() { alert('%(scriptUrl)s'); }; el.src = '%(scriptUrl)s'; document.body.appendChild(el); ''' % {'scriptUrl': scriptUrl}) @pyqtProperty('QVariantMap') def clipRect(self): clipRect = self.m_clipRect result = { 'width': clipRect.width(), 'height': clipRect.height(), 'top': clipRect.top(), 'left': clipRect.left() } return result @clipRect.setter def clipRect(self, size): sizes = {'width': 0, 'height': 0, 'top': 0, 'left': 0} for item in sizes: try: sizes[item] = int(size[item]) if sizes[item] < 0: if item not in ('top', 'left'): sizes[item] = 0 except (KeyError, ValueError): sizes[item] = self.clipRect[item] self.m_clipRect = QRect(sizes['left'], sizes['top'], sizes['width'], sizes['height']) @pyqtProperty(str) def content(self): return self.m_mainFrame.toHtml() @content.setter def content(self, content): self.m_mainFrame.setHtml(content) @pyqtSlot(str, result='QVariant') def evaluate(self, code): function = '(%s)()' % code return self.m_mainFrame.evaluateJavaScript(function) @pyqtSlot(str, result=bool) def injectJs(self, filePath): return injectJsInFrame(filePath, self.parent().m_scriptEncoding.encoding, self.m_libraryPath, self.m_mainFrame) @pyqtSlot(str, str, 'QVariantMap') @pyqtSlot(str, 'QVariantMap', 'QVariantMap') def openUrl(self, address, op, settings): operation = op body = QByteArray() self.applySettings(settings) self.m_webPage.triggerAction(QWebPage.Stop) if type(op) is dict: operation = op.get('operation') body = QByteArray(op.get('data', '')) if operation == '': operation = 'get' networkOp = QNetworkAccessManager.CustomOperation operation = operation.lower() if operation == 'get': networkOp = QNetworkAccessManager.GetOperation elif operation == 'head': networkOp = QNetworkAccessManager.HeadOperation elif operation == 'put': networkOp = QNetworkAccessManager.PutOperation elif operation == 'post': networkOp = QNetworkAccessManager.PostOperation elif operation == 'delete': networkOp = QNetworkAccessManager.DeleteOperation if networkOp == QNetworkAccessManager.CustomOperation: self.m_mainFrame.evaluateJavaScript('console.error("Unknown network operation: %s");' % operation) return if address.lower() == 'about:blank': self.m_mainFrame.setHtml(self.blankHtml) else: self.m_mainFrame.load(QNetworkRequest(QUrl(address)), networkOp, body) @pyqtProperty('QVariantMap') def paperSize(self): return self.m_paperSize @paperSize.setter def paperSize(self, size): self.m_paperSize = size @pyqtSlot() def release(self): self.parent().m_pages.remove(self) sip.delete(self) @pyqtSlot(str, result=bool) def render(self, fileName): if self.m_mainFrame.contentsSize() == '': return False fileInfo = QFileInfo(fileName) path = QDir() path.mkpath(fileInfo.absolutePath()) if fileName.lower().endswith('.pdf'): return self.renderPdf(fileName) image = self.renderImage() return image.save(fileName) @pyqtProperty(str) def libraryPath(self): return self.m_libraryPath @libraryPath.setter def libraryPath(self, dirPath): self.m_libraryPath = dirPath @pyqtSlot(str, 'QVariant', 'QVariant') def sendEvent(self, type_, arg1, arg2): type_ = type_.lower() if type_ in ('mousedown', 'mouseup', 'mousemove'): eventType = QMouseEvent.Type(QEvent.None) button = Qt.MouseButton(Qt.LeftButton) buttons = Qt.MouseButtons(Qt.LeftButton) if type_ == 'mousedown': eventType = QEvent.MouseButtonPress elif type_ == 'mouseup': eventType = QEvent.MouseButtonRelease elif type_ == 'mousemove': eventType = QEvent.MouseMove button = buttons = Qt.NoButton assert eventType != QEvent.None event = QMouseEvent(eventType, QPoint(arg1, arg2), button, buttons, Qt.NoModifier) QApplication.postEvent(self.m_webPage, event) QApplication.processEvents() return if type_ == 'click': self.sendEvent('mousedown', arg1, arg2) self.sendEvent('mouseup', arg1, arg2) @pyqtProperty('QVariantMap') def scrollPosition(self): scroll = self.m_scrollPosition result = { 'left': scroll.x(), 'top': scroll.y() } return result @scrollPosition.setter def scrollPosition(self, size): positions = {'left': 0, 'top': 0} for item in positions: try: positions[item] = int(size[item]) if positions[item] < 0: positions[item] = 0 except (KeyError, ValueError): positions[item] = self.scrollPosition[item] self.m_scrollPosition = QPoint(positions['left'], positions['top']) self.m_mainFrame.setScrollPosition(self.m_scrollPosition) @pyqtSlot(str, str) def uploadFile(self, selector, fileName): el = self.m_mainFrame.findFirstElement(selector) if el.isNull(): return self.m_webPage.m_uploadFile = fileName el.evaluateJavaScript(''' (function (el) { var ev = document.createEvent('MouseEvents'); ev.initEvent('click', true, true); el.dispatchEvent(ev); })(this) ''') @pyqtProperty('QVariantMap') def viewportSize(self): size = self.m_webPage.viewportSize() result = { 'width': size.width(), 'height': size.height() } return result @viewportSize.setter def viewportSize(self, size): sizes = {'width': 0, 'height': 0} for item in sizes: try: sizes[item] = int(size[item]) if sizes[item] < 0: sizes[item] = 0 except (KeyError, ValueError): sizes[item] = self.viewportSize[item] self.m_webPage.setViewportSize(QSize(sizes['width'], sizes['height'])) do_action('WebPage')
class View(KineticScrollArea): viewModeChanged = pyqtSignal(int) def __init__(self, parent=None): super(View, self).__init__(parent) self.setAlignment(Qt.AlignCenter) self.setBackgroundRole(QPalette.Dark) self.setMouseTracking(True) self._viewMode = FixedScale self._wheelZoomEnabled = True self._wheelZoomModifier = Qt.CTRL # delayed resize self._centerPos = False self._resizeTimer = QTimer(singleShot=True, timeout=self._resizeTimeout) def surface(self): """Returns our Surface, the widget drawing the page(s).""" sf = self.widget() if not sf: sf = surface.Surface(self) self.setSurface(sf) return sf def setSurface(self, sf): """Sets the given surface as our widget.""" self.setWidget(sf) # For some reason mouse tracking *must* be enabled on the child as well... sf.setMouseTracking(True) self.kineticScrollingActive.connect(sf.updateKineticCursor) def viewMode(self): """Returns the current ViewMode.""" return self._viewMode def setViewMode(self, mode): """Sets the current ViewMode.""" if mode == self._viewMode: return self._viewMode = mode if mode: self.fit() self.viewModeChanged.emit(mode) def wheelZoomEnabled(self): """Returns whether wheel zoom is enabled.""" return self._wheelZoomEnabled def setWheelZoomEnabled(self, enabled): """Sets whether wheel zoom is enabled. Wheel zoom is zooming using the mouse wheel and a keyboard modifier key (defaulting to Qt.CTRL). Use setWheelZoomModifier() to set a key (or key combination). """ self._wheelZoomEnabled = enabled def wheelZoomModifier(self): """Returns the modifier key to wheel-zoom with (defaults to Qt.CTRL).""" return self._wheelZoomModifier def setWheelZoomModifier(self, key): """Sets the modifier key to wheel-zoom with (defaults to Qt.CTRL). Can also be set to a ORed value, e.g. Qt.SHIFT|Qt.ALT. Only use Qt.ALT, Qt.CTRL, Qt.SHIFT and/or Qt.META. """ self._wheelZoomModifier = key def load(self, document): """Convenience method to load all the pages from the given Poppler.Document.""" self.surface().pageLayout().load(document) # dont do a fit() before the very first resize as the size is then bogus if self.viewMode(): self.fit() self.surface().pageLayout().update() def clear(self): """Convenience method to clear the current layout.""" self.surface().pageLayout().clear() self.surface().pageLayout().update() def scale(self): """Returns the scale of the pages in the View.""" return self.surface().pageLayout().scale() def setScale(self, scale): """Sets the scale of all pages in the View.""" self.surface().pageLayout().setScale(scale) self.surface().pageLayout().update() self.setViewMode(FixedScale) def visiblePages(self): """Yields the visible pages.""" rect = self.viewport().rect() rect.translate(-self.surface().pos()) rect.intersect(self.surface().rect()) return self.surface().pageLayout().pagesAt(rect) def redraw(self): """Redraws, e.g. when you changed rendering hints or papercolor on the document.""" pages = list(self.visiblePages()) documents = set(page.document() for page in pages) for document in documents: cache.clear(document) for page in pages: page.repaint() def fit(self): """(Internal). Fits the layout according to the view mode. Prevents scrollbar/resize loops by precalculating which scrollbars will appear. """ mode = self.viewMode() if mode == FixedScale: return maxsize = self.maximumViewportSize() # can vertical or horizontal scrollbars appear? vcan = self.verticalScrollBarPolicy() == Qt.ScrollBarAsNeeded hcan = self.horizontalScrollBarPolicy() == Qt.ScrollBarAsNeeded # width a scrollbar takes off the viewport size framewidth = 0 if self.style().styleHint(QStyle.SH_ScrollView_FrameOnlyAroundContents, None, self): framewidth = self.style().pixelMetric( QStyle.PM_DefaultFrameWidth) * 2 scrollbarextent = self.style().pixelMetric(QStyle.PM_ScrollBarExtent, None, self) + framewidth # first try to fit full size layout = self.surface().pageLayout() layout.fit(maxsize, mode) layout.reLayout() # minimal values minwidth = maxsize.width() minheight = maxsize.height() if vcan: minwidth -= scrollbarextent if hcan: minheight -= scrollbarextent # do width and/or height fit? fitw = layout.width() <= maxsize.width() fith = layout.height() <= maxsize.height() if not fitw and not fith: if vcan or hcan: layout.fit(QSize(minwidth, minheight), mode) elif mode & FitWidth and fitw and not fith and vcan: # a vertical scrollbar will appear w = minwidth layout.fit(QSize(w, maxsize.height()), mode) layout.reLayout() if layout.height() <= maxsize.height(): # now the vert. scrollbar would disappear! # enlarge it as long as the vertical scrollbar would not be needed while True: w += 1 layout.fit(QSize(w, maxsize.height()), mode) layout.reLayout() if layout.height() > maxsize.height(): layout.fit(QSize(w - 1, maxsize.height()), mode) break elif mode & FitHeight and fith and not fitw and hcan: # a horizontal scrollbar will appear h = minheight layout.fit(QSize(maxsize.width(), h), mode) layout.reLayout() if layout.width() <= maxsize.width(): # now the hor. scrollbar would disappear! # enlarge it as long as the horizontal scrollbar would not be needed while True: h += 1 layout.fit(QSize(maxsize.width(), h), mode) layout.reLayout() if layout.width() > maxsize.width(): layout.fit(QSize(maxsize.width(), h - 1), mode) break layout.update() def resizeEvent(self, ev): super(View, self).resizeEvent(ev) # Adjust the size of the document if desired if self.viewMode() and any(self.surface().pageLayout().pages()): if self._centerPos is False: self._centerPos = QPoint(0, 0) elif self._centerPos is None: # store the point currently in the center self._centerPos = self.viewport().rect().center( ) - self.surface().pos() if not self._resizeTimer.isActive(): self._resizeTimeout() self._resizeTimer.start(150) def _resizeTimeout(self): if self._centerPos is None: return oldSize = self.surface().size() # resize the layout self.fit() # restore our position newSize = self.surface().size() newx = self._centerPos.x() * newSize.width() / oldSize.width() newy = self._centerPos.y() * newSize.height() / oldSize.height() # we explicitely want the non-kinetic centering function regardless of kinetic state. self.fastCenter(QPoint(newx, newy)) self._centerPos = None def zoom(self, scale, pos=None): """Changes the display scale (1.0 is 100%). If pos is given, keeps that point at the same place if possible. Pos is a QPoint relative to ourselves. """ scale = max(0.05, min(4.0, scale)) if scale == self.scale(): return if self.surface().pageLayout().count() == 0: self.setScale(scale) return if pos is None: pos = self.viewport().rect().center() surfacePos = pos - self.surface().pos() page = self.surface().pageLayout().pageAt(surfacePos) if page: pagePos = surfacePos - page.pos() x = pagePos.x() / float(page.width()) y = pagePos.y() / float(page.height()) self.setScale(scale) newPos = QPoint(round(x * page.width()), round( y * page.height())) + page.pos() else: x = surfacePos.x() / float(self.surface().width()) y = surfacePos.y() / float(self.surface().height()) self.setScale(scale) newPos = QPoint(round(x * self.surface().width()), round(y * self.surface().height())) surfacePos = pos - self.surface().pos() # use fastScrollBy as we do not want kinetic scrolling here regardless of its state. self.fastScrollBy(newPos - surfacePos) def zoomIn(self, pos=None, factor=1.1): self.zoom(self.scale() * factor, pos) def zoomOut(self, pos=None, factor=1.1): self.zoom(self.scale() / factor, pos) def wheelEvent(self, ev): if (self._wheelZoomEnabled and int(ev.modifiers()) & _SCAM == self._wheelZoomModifier): factor = 1.1**(ev.delta() / 120) if ev.delta(): self.zoom(self.scale() * factor, ev.pos()) else: super(View, self).wheelEvent(ev) def mousePressEvent(self, ev): """Mouse press event handler. Passes the event to the surface, and back to the base class if the surface did not do anything with it.""" if not self.surface().handleMousePressEvent(ev): super(View, self).mousePressEvent(ev) def mouseReleaseEvent(self, ev): """Mouse release event handler. Passes the event to the surface, and back to the base class if the surface did not do anything with it.""" if not self.surface().handleMouseReleaseEvent(ev): super(View, self).mouseReleaseEvent(ev) def mouseMoveEvent(self, ev): """Mouse move event handler. Passes the event to the surface, and back to the base class if the surface did not do anything with it.""" if self.kineticIsIdle(): if self.surface().handleMouseMoveEvent(ev): return super(View, self).mouseMoveEvent(ev) def moveEvent(self, ev): """Move event handler. Passes the event to the surface if we've not started any kinetic move, and back to the base class if the surface did not do anything with it.""" if self.kineticIsIdle(): if self.surface().handleMoveEvent(ev): return super(View, self).moveEvent(ev) def event(self, ev): if isinstance(ev, QHelpEvent): if self.surface().handleHelpEvent(ev): ev.accept() return True return super(View, self).event(ev) def currentPage(self): """Returns the Page currently mostly in the center, or None if there are no pages.""" pos = self.viewport().rect().center() - self.surface().pos() layout = self.surface().pageLayout() if len(layout): d = layout.spacing() * 2 for dx, dy in ((0, 0), (-d, 0), (0, -d), (d, 0), (0, d)): dist = QPoint(dx, dy) page = layout.pageAt(pos + dist) if page: return page def currentPageNumber(self): """Returns the number (index in the layout) of the currentPage(), or -1 if there are no pages.""" page = self.currentPage() if page: return self.surface().pageLayout().index(page) return -1 def gotoPageNumber(self, num): """Aligns the page at the given index in the layout to the topleft of our View.""" layout = self.surface().pageLayout() if num < len(layout) and num != self.currentPageNumber(): margin = QPoint(layout.margin(), layout.margin()) self.scrollBy(layout[num].pos() + self.surface().pos() - margin) def position(self): """Returns a three-tuple(num, x, y) describing the page currently in the center of the View. the number is the index of the Page in the Layout, and x and y are the coordinates in the range 0.0 -> 1.0 of the point that is at the center of the View. This way a position can be retained even if the scale or the orientation of the Layout changed. Returns None, None, None if the layout is empty. """ page = self.currentPage() if page: layout = self.surface().pageLayout() pos = self.viewport().rect().center() - self.surface().pos() pagePos = pos - page.pos() x = pagePos.x() / float(page.width()) y = pagePos.y() / float(page.height()) return layout.index(page), x, y return None, None, None def setPosition(self, position, overrideKinetic=False): """Sets the position to a three-tuple as previously returned by position(). Setting overrideKinetic to true allows for fast setup, instead of scrolling all the way to the visible point. """ layout = self.surface().pageLayout() pageNum, x, y = position if pageNum is None or pageNum >= len(layout): return page = layout[pageNum] # center this point newPos = QPoint(round(x * page.width()), round( y * page.height())) + page.pos() if overrideKinetic: self.fastCenter(newPos) else: self.center(newPos)
class MSGLCanvas2D(QGLWidget): """ Canvas GL plotting in 2 dimensions """ MAX = 100. corner_=100.0 zoom_= 1.5 xrot_=220 yrot_ = 220 trans_x_ =0.0 trans_y_ = 0.0 def __init__(self, data, parent=None, **kw): """ Constructor, initialization """ QGLWidget.__init__(self, parent) self.setFormat(QGLFormat(QGL.SampleBuffers)) self.setMinimumSize(500,300)#300 self.setMouseTracking(True) self.setFocusPolicy(Qt.StrongFocus) self.data=data vertexes=[] colors=[] from utils.misc import IceAndFire maxY=max(map(max, [log10(el.y_data) for el in data])) maxX=max(map(max, [el.x_data for el in data])) rtmax=max([z.rtmin for z in data]) for el in data: for i, x in enumerate(el.x_data): c=IceAndFire.getQColor(log10(el.y_data[i])/maxY) colors.append(c) vertexes.append([(x*2*self.corner_)/maxX, (el.rt*2*self.corner_)/rtmax]) from OpenGL.arrays.vbo import VBO self.vertexes= VBO(array(vertexes,'f')) self.colors=VBO(array(colors,'f')) self.mode = "None" # "ZOOMING", "PANNING", "NONE" self.lastpos = QPoint() self.counter_trans_x = 0 self.counter_trans_y = 0 self.defaultColors = {'ticks':(0.,0.,0.,0.), 'axes':(0.,0.,0.,0.), 'curves':(0.,0.,1.,0.), 'backgroundColor':(1.,1.,1.,1.) } #self.axes=self.drawAxes() self.transformationMatrix = self.setupTransformationMatrix(self.width(), self.height()) def setupTransformationMatrix(self,w, h): """ use a matrix to translate in the gl landmark """ m = QMatrix() m.translate(-w/2, h/2) m.scale(300./w, 300./h) print w, h, w/300., 1-((h/300)-1) #m.scale((self.width()*100)/300, -(self.height()*100)/300) #self.currentSize.x = w #self.currentSize.y = h return m def inGLCoordinate(self, point): return self.transformationMatrix.map(point) def resizeGL(self, w, h): """ called when window is being resized """ glViewport(0,0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_*self.zoom_, self.corner_*self.zoom_, -self.corner_*self.zoom_, self.corner_*self.zoom_) #self.transformationMatrix = self.setupTransformationMatrix(w, h) glMatrixMode(GL_MODELVIEW) def initializeGL(self): """needed, initialize GL parameters""" #glClearColor(1.,1.,1.,1.) glDisable(GL_DEPTH_TEST) glEnable(GL_LINE_SMOOTH) glEnable(GL_POINT_SMOOTH) glHint (GL_LINE_SMOOTH_HINT, GL_NICEST) glLoadIdentity() #model view by default # self.grid_lines = self.drawGridLines() # self.ticks =self.drawAxisTick() # self.axes = self.drawAxes() def paintGL(self): """Draw the scene, needed, called each time glDraw""" glClear(GL_COLOR_BUFFER_BIT) glTranslated(self.trans_x_, self.trans_y_, 0.) #addition glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_*self.zoom_, self.corner_*self.zoom_, -self.corner_*self.zoom_, self.corner_*self.zoom_) glMatrixMode(GL_MODELVIEW) #end addition #glCallList(self.grid_lines) #glCallList(self.ticks) #glCallList(self.axes) glLineWidth(30.0) self.scatterPlot() # if self.flags == "chrom": # self.drawAxisLegend("retention time[s]", "intensity[%]") # glCallList(self.lines) # elif self.flags == "spectrum": # self.drawAxisLegend("m/z", "intensity") def drawAxes(self, width=2., colour=(0.,0.,0.)): """ Draw Axes """ #width must be a float axes = glGenLists(1) glNewList(axes, GL_COMPILE) glLineWidth(width) glColor(colour[0],colour[1],colour[2]) glBegin(GL_LINES) #x_achse glVertex2d(-self.corner_, -self.corner_) glVertex2d( self.corner_, -self.corner_) #y-achse glVertex2d(-self.corner_, -self.corner_) glVertex2d( -self.corner_, self.corner_) glEnd() glEndList() return axes def drawLegends(self, pos): """ draw legend at the specified position """ pass def drawAxisLegend(self, x_label, y_label): """ Draw Axis Legend """ font =QFont("Typewriter") #RT axis legend font.setPixelSize(12) self.renderText(self.corner_, -self.corner_-20.0, 0., x_label)# font self.renderText(-self.corner_-20.0, self.corner_, 0., y_label, font) def resetTranslations(self): """ reset the different translation to 0 """ self.trans_x_ =0. self.trans_y_ =0. self.counter_trans_x=0. self.counter_trans_y=0. def normalizeAngle(self,angle): while (angle < 0): angle += 360 * 16 while (angle > 360 * 16): angle -= 360 * 16 ########DRAWING METHODS################################################## def drawLine(self, point_, point): glBegin(GL_LINES) glVertex2d(point_.x(), point_.y()) glVertex2d(point.x(), point.y()) glEnd() def drawRect(self, p_1, p_2, p_3=None, p_4 = None): pass def drawOnePoint(self, point, colour= Qt.yellow): pass def scatterPlot(self): """ Draw Data (x, y)""" if self.vertexes is not None and self.colors is not None: self.vertexes.bind() glEnableClientState(GL_VERTEX_ARRAY) glVertexPointerf(self.vertexes) self.colors.bind() glEnableClientState(GL_COLOR_ARRAY) glColorPointerf(self.colors) glDrawArrays(GL_LINES, 0, len(self.vertexes)) self.vertexes.unbind() self.colors.unbind() #self.textures.unbind() glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) def spectrumPlot(self, points): pass def histogramPlot(self, points, bin = 5.): pass def barPlot(points, width =2.):pass ########MOUSE AND KEYBOARDS EVENTS########################################################################### def wheelEvent(self, event): if event.delta() >0: self.zoom_ -= .05 else: self.zoom_ += .05 glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_*self.zoom_, self.corner_*self.zoom_, -self.corner_*self.zoom_, self.corner_*self.zoom_) self.updateGL() glMatrixMode(GL_MODELVIEW) event.accept() def keyPressEvent(self, event): if event.key() == Qt.Key_Plus: self.zoom_ -= .1 glMatrixMode(GL_PROJECTION) glLoadIdentity() gluOrtho2D(-self.corner_*self.zoom_, self.corner_*self.zoom_, -self.corner_*self.zoom_, self.corner_*self.zoom_) glMatrixMode(GL_MODELVIEW) if event.key() == Qt.Key_Minus: self.zoom_ += .1 glMatrixMode(GL_PROJECTION) #// You had GL_MODELVIEW glLoadIdentity() gluOrtho2D(-self.corner_*self.zoom_, self.corner_*self.zoom_, -self.corner_*self.zoom_, self.corner_*self.zoom_) glMatrixMode(GL_MODELVIEW) if event.key() == Qt.Key_Up: self.trans_y_ += 2 self.counter_trans_y +=2 if event.key() == Qt.Key_Down: self.trans_y_ -=2 self.counter_trans_y -=2 if event.key() == Qt.Key_Left: self.trans_x_ -=2 self.counter_trans_x -=2 if event.key() == Qt.Key_Right: self.trans_x_ +=2 self.counter_trans_x +=2 if event.key() == Qt.Key_Z: self.mode= "ZOOMING" if self.counter_trans_x < 0 and self.counter_trans_y < 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x += 1 self.counter_trans_y += 1 if self.counter_trans_x > 0 and self.counter_trans_y < 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x -= 1 self.counter_trans_y += 1 if self.counter_trans_x < 0 and self.counter_trans_y > 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x += 1 self.counter_trans_y -= 1 if self.counter_trans_x < 0 and self.counter_trans_y > 0: while self.counter_trans_x < 0 and self.counter_trans_y < 0: self.trans_x_ = self.counter_trans_x self.trans_y_ = self.counter_trans_y self.updateGL() self.counter_trans_x -= 1 self.counter_trans_y -= 1 if self.zoom_ != 1.5: self.zoom = 1.5 #self.updateGL() self.updateGL() self.resetTranslations() def mousePressEvent(self, event): if self.mode == "ZOOMING": self.mode = "None" self.computeSelection() else: self.lastpos = QPoint(event.pos()) self.setCursor(QCursor(Qt.ClosedHandCursor)) #if event.buttons() == Qt.RightButton: # self.mode = "PANNING" def computeSelection(self): print "selected" def mouseMoveEvent(self, event): dx = event.x() - self.lastpos.x() dy = event.y() - self.lastpos.y() if self.mode == "ZOOMING": font = QFont("Typewriter") self.renderText(-self.corner_ -30.0, self.corner_, 0., "ZOOMING MODE ACTIVATED", font) self.updateGL() glColor(0., 0., 1., .5) XMAX = 900.; XMIN = 180. pointer_x = (self.lastpos.x()*200.)/XMAX norm_dx = (dx*200.)/XMAX """ if pointer_x > 100. or pointer_x < 100. \ or norm_dx >100. or norm_dx<-100.: event.ignore() """ glBegin(GL_QUADS) glVertex2d(pointer_x, -100.) glVertex2d(pointer_x+ norm_dx, -100.) glVertex2d(pointer_x+ norm_dx, 100.) glVertex2d(pointer_x, 100.) glEnd() self.updateGL()#update for seeing the rectangle mapping = self.mapFromGlobal cursorPos = self.inGLCoordinate(mapping(self.cursor().pos())) QToolTip.showText(self.cursor().pos(), "x:"+str(cursorPos.x())+ \ ", y:"+str(cursorPos.y()) ) if self.mode == "None": if event.buttons()== Qt.LeftButton: self.trans_y_ -= dy/5 self.counter_trans_y -= dy/5 self.trans_x_ += dx/5 self.counter_trans_x += dx/5 self.lastpos = QPoint(event.pos()) self.glDraw() self.resetTranslations() def mouseReleaseEvent(self, event): self.setCursor(QCursor(Qt.ArrowCursor))
class MSGLCanvas3D(QGLWidget): """Canvas GL plotting in 3 dimensions spectra""" corner=100.0 near=0.0 far=600.0 zoom= 1.5 xrot=220 yrot = 220 zrot=0 trans_x =0.0 trans_y = 0.0 def __init__(self, vertexes, colors, parent=None, **kw):#vertexes, colors, texturePath='graphics/Texture-Example.jpg', parent=None):#spl, peak=None, parent=None): """ Constructor, initialization kw: -texturePath:pathway to the file to text -textures: coord textures to apply -parent:the parent widget """ QGLWidget.__init__(self, parent) self.setFormat(QGLFormat(QGL.SampleBuffers)) self.setMinimumSize(500,300) self.setMouseTracking(True) self.setFocusPolicy(Qt.StrongFocus) # if not 'texturePath'in kw.keys() and not 'textures' in kw.keys(): # pass # #print ('Could not apply texture, no coordinates') # else: # try: # self._imageID = self.loadImage(kw.get('texturePath')) # self.textures = textures # except OSError: # print ('Could not apply texture, no coordinates') self.vertexes = vertexes self.colors = colors #self.axes=None self.zoom_mode = False self.pan_mode = True #self.axes = self.makeAxes() self.parameters={'axes_color':'b', 'axes_line_width':3., 'draw_line_width':1., 'colormap':True, 'fish_eye':False, 'cell_shading':False} self.lastpos = QPoint() def loadImage(self, imageName): im = open(imageName) try: ix, iy, image = im.size[0], im.size[1], im.tostring("raw", "RGBA", 0, -1) except SystemError: ix, iy, image = im.size[0], im.size[1], im.tostring("raw", "RGBX", 0, -1) ID = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, ID) glPixelStorei(GL_UNPACK_ALIGNMENT,1) glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE, image) return ID def setupTexture(self): glEnable(GL_TEXTURE_2D) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) glBindTexture(GL_TEXTURE_2D, self.imageID) def texturesCalc(self): from OpenGL.arrays.vbo import VBO basis = [[0.,0.], [0.,1.]] hola =[] length = len(self.vertexes) for i in range(length/2): hola+=basis return VBO(array(hola)) def recalcVertexesAndColors(self, colormap, **kwargs): pass def resizeGL(self, w, h): """called when window is being resized""" glViewport(0,0, w, h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(-self.corner*self.zoom, self.corner*self.zoom, -self.corner*self.zoom, self.corner*self.zoom , self.near, self.far) #gluPerspective(70,w/h, 1,1000) glMatrixMode(GL_MODELVIEW) def initializeGL(self): """opengl options""" #glClearColor(1., 1., 1., 1.) #glClearColor(0.,0.,0.) glEnable(GL_DEPTH_TEST) #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glEnable(GL_LINE_SMOOTH) #glEnable(GL_POINT_SMOOTH) #glHint (GL_LINE_SMOOTH_HINT, GL_NICEST)# #glDepthFunc(GL_LEQUAL) glEnable(GL_CULL_FACE) #glCullFace(GL_BACK) #glEnable(GL_LIGHTING) #glLightfv(GL_LIGHT0, GL_DIFFUSE,(0.8, 0.8, 0.8, 1)) #glEnable(GL_LIGHT0) #glEnable(GL_COLOR_MATERIAL) #glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE) #self.shader = compileProgram(vertex_shader, frag_shader)#vertex_shader)#shader #self.drawAxisLegend() def paintGL(self): """needed, called each time glDraw""" glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() glTranslated(0.0, 0.0,-3.0*self.corner) glRotated(self.xrot / 16.0, 1.0, 0.0, 0.0) glRotated(self.yrot / 16.0, 0.0, 1.0, 0.0) glRotated(self.zrot/16.0, 0.0, 0.0, 1.0) glTranslated(self.trans_x, self.trans_y, 3.0*self.corner) #testing #glEnable(GL_DEPTH_TEST) #glEnable(GL_BLEND) #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) #self.setupTexture() #self.textures = self.texturesCalc() self.drawScene() #if self.zoom_mode: # self.drawQuad() def renderTextModes(self): self.renderText(10, 10, 'mode:%s'%"zoom" if self.zoom_mode else 'mode:%s'%"pan", font=QFont()) self.renderText(10, 20, 'selection mode:%s'%str(False), font=QFont()) def drawScene(self): # self.renderTextModes() glLineWidth(1.) #glUseProgram(self.shader) if self.vertexes is not None and self.colors is not None: self.vertexes.bind() glEnableClientState(GL_VERTEX_ARRAY) glVertexPointerf(self.vertexes) self.colors.bind() glEnableClientState(GL_COLOR_ARRAY) glColorPointerf(self.colors) """ self.textures.bind() glEnableClientState(GL_TEXTURE_COORD_ARRAY) glTexCoordPointerf(self.textures) """ glDrawArrays(GL_LINES, 0, len(self.vertexes)) self.vertexes.unbind() self.colors.unbind() #self.textures.unbind() glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) #glDisableClientState(GL_TEXTURE_COORD_ARRAY) #glUseProgram(0) #glUseProgram(0) #if hasattr(self, 'axes'): #glCallList(self.axes) #glCallList(self.surface) #self.drawAxisLegend() def makeAxes(self): """Draw Axes """ glLineWidth(2.0) glColor(0.,0.,1.) lspectr = glGenLists(1) glNewList(lspectr,GL_COMPILE) glBegin(GL_LINES) #glEnable(GL_LINE_STIPPLE) #glLineStipple(1, 1) glVertex3d(self.corner, -self.corner, -self.near-2*self.corner) glVertex3d(self.corner, self.corner, -self.near-2*self.corner) glVertex3d(self.corner, -self.corner, -self.far+2*self.corner) glVertex3d(self.corner, +self.corner, -self.far+2*self.corner) glVertex3d(-self.corner, -self.corner, -self.far+2*self.corner) glVertex3d(-self.corner, +self.corner, -self.far+2*self.corner) glVertex3d(-self.corner, +self.corner, -self.far+2*self.corner) glVertex3d(self.corner, +self.corner, -self.far+2*self.corner) glVertex3d(+self.corner, +self.corner, -self.far+2*self.corner) glVertex3d(+self.corner, +self.corner, -self.near-2*self.corner) #glDisable(GL_LINE_STIPPLE) glVertex3d(+self.corner, -self.corner, -self.far+2*self.corner) glVertex3d(+self.corner, -self.corner, -self.near-2*self.corner) glVertex3d(-self.corner, -self.corner, -self.far+2*self.corner) glVertex3d(self.corner, -self.corner, -self.far+2*self.corner) glEnd() glEndList() return lspectr def drawAxisLegend(self): """Draw Axis Legend""" font = QFont("Typewriter") font.setPixelSize(10) #RT axis legend font.setPixelSize(12) self.qglColor(Qt.blue) mz_label = "retention time [s]";rt_label = "m/z" self.renderText(0.0, -self.corner-20.0, -self.near-2*self.corner+20.0, rt_label, font) self.renderText(-self.corner-20.0, -self.corner-20.0, -self.near-3*self.corner, mz_label, font) self.renderText(-self.corner-20.0, self.corner+10.0, -self.near-2*self.corner+20.0, "intensity %", font) font.setPixelSize(10) # #for rt number # for i in xrange (0,len(self.rtList), 100): # text = str(math.ceil(((self.rtList[i][0])*self.max_rt )/ self.max_rt)) # self.renderText(-self.corner, # -self.corner -5.0, # -self.near-2*self.corner - self.rtList[i][0], # text, # font) # for i in xrange (0, len(self.massList[0]), 100): # text = str(math.ceil(((self.massList[0][i])*self.max_mass )/ 2*self.corner)) # self.renderText( self.corner, # self.corner -5.0, # -self.near-2*self.corner - self.massList[0][i], # text, # font) # #for mz number def resetTranslations(self): """reset the different translation to 0""" self.trans_x =0. self.trans_y =0. def normalizeAngle(self,angle): """taken from qt documentation""" while (angle < 0): angle += 360 * 16 while (angle > 360 * 16): angle -= 360 * 16 return angle def computeSelection(self):pass #=============================================================================== # MOUSE AND KEYBOARDS EVENTS #=============================================================================== def wheelEvent(self, event): if event.delta() >0: self.zoom -= .05 else: self.zoom += .05 glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(-self.corner*self.zoom, self.corner*self.zoom, -self.corner*self.zoom, self.corner*self.zoom , self.near, self.far) glMatrixMode(GL_MODELVIEW) self.updateGL() event.accept() def keyPressEvent(self, event): if event.key() == Qt.Key_Minus: self.zoom -= .1 glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(-self.corner*self.zoom, self.corner*self.zoom, -self.corner*self.zoom, self.corner*self.zoom , self.near, self.far) glMatrixMode(GL_MODELVIEW) if event.key() == Qt.Key_Plus: self.zoom += .1 glMatrixMode(GL_PROJECTION) #// You had GL_MODELVIEW glLoadIdentity() glOrtho(-self.corner*self.zoom, self.corner*self.zoom, -self.corner*self.zoom, self.corner*self.zoom , self.near, self.far) glMatrixMode(GL_MODELVIEW) if event.key() ==Qt.Key_Z: #store all values self.zoom_mode = True glMatrixMode(GL_MODELVIEW) glLoadIdentity() font = QFont("Typewriter") self.renderText(0.,0.,0., "zooming mode", font) #little animation #a = -5 #count = 0 if self.yrot < 1444: while self.yrot < 1444:#and self.xrot < ref_rotx_: #count += 1 self.xrot -=20 self.yrot +=20 #if self.zoom > a: # self.zoom-=1 self.updateGL() elif self.yrot > 1444: while self.yrot <1444 :#and self.xrot < ref_rotx_: #count += 1 self.xrot -=20 self.yrot -=20 #if self.zoom > a: # self.zoom-=1 self.updateGL() """ count_ = 0 tmp = self.xrot while tmp < 1422: count_+=1 tmp += 1 b = count / count_ count__ = 0 """ while self.xrot < 1422: #count__+=1 self.xrot+= 20 #if self.zoom < 1: #and count__%b == 0: # self.zoom+=1 self.updateGL() if event.key() == Qt.Key_Up: self.trans_y +=10 if event.key() == Qt.Key_Down: self.trans_y -=10 if event.key() == Qt.Key_Left: self.trans_x -=10 if event.key() == Qt.Key_Right: self.trans_x +=10 self.updateGL() def mousePressEvent(self, event): self.lastpos = QPoint(event.pos()) # modelview, projection =[], [] # z =1 # x, y =event.x(), event.y() # projection =glGetDoublev(GL_PROJECTION_MATRIX) # modelview= glGetDoublev(GL_MODELVIEW_MATRIX) # viewport=glGetIntegerv(GL_VIEWPORT) # glReadPixels( x, viewport[3]-y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, z ) # objx, objy, objz =gluUnProject( x, viewport[3]-y, z, modelview, projection, viewport) # print objx, objy, objz def mouseMoveEvent(self, event): dx = event.x() - self.lastpos.x() dy = event.y() - self.lastpos.y() if not self.zoom_mode: if event.buttons() == Qt.LeftButton: a = self.normalizeAngle(self.xrot + 8 * dy) b = self.normalizeAngle(self.yrot + 8 * dx) self.xrot= a#self.xrot + 8 * dy self.yrot= b#self.yrot + 8 * dx if event.buttons()== Qt.RightButton: self.setCursor(QCursor(Qt.ClosedHandCursor)) self.trans_y -= dy/5 self.trans_x += dx/5 self.lastpos = QPoint(event.pos()) self.updateGL() def drawQuad(self): '''change to accept arguments pass''' glColor( 0., 0., 1.) glLineWidth(4.0) pointer_x = self.lastpos.x()/200.#self.corner pointer_y = self.lastpos.y()/200.#/(self.corner) norm_dx = dx/200.#/(self.corner) norm_dy = dy/200.#/(self.corner) #print -self.corner, pointer_x, pointer_y, norm_dx, norm_dy glBegin(GL_QUADS) glVertex3f(-self.corner + pointer_x, -self.corner + pointer_y, -self.near+2*self.corner) glVertex3f(-self.corner + pointer_x+ norm_dx, -self.corner + pointer_y, -self.near+2*self.corner) glVertex3f(-self.corner + pointer_x+ norm_dx, -self.corner + pointer_y + norm_dy, -self.near+2*self.corner) glVertex3f(-self.corner + pointer_x, -self.corner + pointer_y, -self.near+2*self.corner) glEnd() self.lastpos = QPoint(event.pos()) #redraw eachtime mouse 's moving self.updateGL() def mouseReleaseEvent(self, event): self.setCursor(QCursor(Qt.ArrowCursor)) if self.zoom_mode: self.computeSelection() self.zoom_mode = False def closeEvent(self, event): self.releaseKeyboard()
class GLWidget(QtOpenGL.QGLWidget): """ This class renders something with OpenGL """ def __init__(self, parent=None): """ Constructor """ self.__image_width = 250 self.__image_height = 250 self.__isMouseDown = False self.__zoomFactor = 1.0 self.__scrollOffset = QPoint() if hasattr(QGLFormat, "setVersion"): # Modern OpenGL f = QGLFormat() f.setVersion(3, 3) f.setProfile(QGLFormat.CoreProfile) f.setSampleBuffers(True) c = QGLContext(f, None) QGLWidget.__init__(self, c, parent) print "Version is set to 3.3" else: QGLWidget.__init__(self, parent) #self.__svgItem = QtSvg.QGraphicsSvgItem("circle_star.svg") self.__mySvgTool = MySvgTool() self.__mySvgWriter = MySvgWriter() self.__mySvgWriter.DrawSomething() self.__myBufferPainter = MyBufferPainter() def initializeGL(self): glClearColor(0.5, 0.5, 0.5, 1.0) glEnable(GL_DEPTH_TEST) glEnable(GL_CULL_FACE) glEnable(GL_LINE_SMOOTH) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) self.__shaderProgram = QGLShaderProgram() if self.__shaderProgram.addShaderFromSourceFile( QGLShader.Vertex, "shader.vert"): print "Main - Vertex shader OK" if self.__shaderProgram.addShaderFromSourceFile( QGLShader.Fragment, "shader.frag"): print "Main - Fragment shader OK" self.__shaderProgram.link() self.__texCoordLocation = self.__shaderProgram.attributeLocation("uv") self.__vertexLocation = self.__shaderProgram.attributeLocation( "position") self.__colorLocation = self.__shaderProgram.attributeLocation("color") self.__use_color_location = self.__shaderProgram.uniformLocation( "use_color") self.__mvpMatrixLocation = self.__shaderProgram.uniformLocation( "mvpMatrix") # Returns -1 if name is not a valid attribute for this shader program. print "\n__texCoordLocation :", self.__texCoordLocation, " ", \ "\n__vertexLocation :", self.__vertexLocation, " ", \ "\n__colorLocation :", self.__colorLocation, " ", \ "\n__use_color_location :", self.__use_color_location, " ", \ "\n__mvpMatrixLocation :", self.__mvpMatrixLocation self.__blurProgram = QGLShaderProgram() if self.__blurProgram.addShaderFromSourceFile(QGLShader.Vertex, "shader.vert"): print "Gaussian blur - Vertex shader OK" # if I use shader.frag it's okay ??? # if self.__blurProgram.addShaderFromSourceFile(QGLShader.Fragment, "gaussian_blur.frag") : if self.__blurProgram.addShaderFromSourceFile(QGLShader.Fragment, "gaussian_blur.frag"): print "Gaussian blur - fragment shader OK" self.__blurProgram.link() self.__myBufferPainter.SetThings(self.__shaderProgram, self.__blurProgram) self.__myBufferPainter.initializeGL( self.bindTexture(QtGui.QPixmap("laughing_man.png"))) self.__myBufferPainter.prepareFrameRect(self.__scrollOffset.x(), self.__scrollOffset.y(), self.width(), self.height(), self.__zoomFactor) """ ### texture self.__ori_tex = self.bindTexture(QtGui.QPixmap("laughing_man.png")) vertexData = numpy.array([ 0.0, 0.0, 0.0, 1.0, 0.0, 250.0, 0.0, 1.0, 250.0, 250.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 250.0, 250.0, 0.0, 1.0, 250.0, 0.0, 0.0, 1.0, # uv 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1], dtype = numpy.float32) colorData = numpy.array([1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,], dtype = numpy.float32) ### create VAO self.__VAO = glGenVertexArrays(1) glBindVertexArray(self.__VAO) ### create a VBO for position and uv posVBO = glGenBuffers(1) glBindBuffer(GL_ARRAY_BUFFER, posVBO) glBufferData(GL_ARRAY_BUFFER, vertexData.nbytes, vertexData, GL_STATIC_DRAW) glEnableVertexAttribArray(self.__vertexLocation) glVertexAttribPointer(self.__vertexLocation, 4, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(self.__texCoordLocation) glVertexAttribPointer(self.__texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(96)) ### create VBO for color colVBO = glGenBuffers(1) glBindBuffer(GL_ARRAY_BUFFER, colVBO) glBufferData(GL_ARRAY_BUFFER, colorData.nbytes, colorData, GL_STATIC_DRAW) glEnableVertexAttribArray(self.__colorLocation) glVertexAttribPointer(self.__colorLocation, 4, GL_FLOAT, GL_FALSE, 0, None) ### unbind vao and vbo glBindBuffer(GL_ARRAY_BUFFER, 0) glBindVertexArray(0) """ def paintGL(self): glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ### this doesn't work #frameBufferA.bind() #frameBufferA.release() glViewport(0, 0, self.width(), self.height()) orthoMatrix = QMatrix4x4() orthoMatrix.ortho(0 + self.__scrollOffset.x(), self.width() + self.__scrollOffset.x(), self.height() + self.__scrollOffset.y(), 0 + self.__scrollOffset.y(), -100, 100) transformMatrix = QMatrix4x4() transformMatrix.setToIdentity() transformMatrix.scale(self.__zoomFactor) ### activate shader program #self.__shaderProgram.bind() ### set a shader attribute (0 means use texture, 1 means use color) #self.__shaderProgram.setUniformValue(self.__use_color_location, 0.0) ### feed the mpv matrix mpvMatrix = orthoMatrix * transformMatrix #self.__shaderProgram.setUniformValue(self.__mvpMatrixLocation, mpvMatrix) # Draw Something self.__myBufferPainter.paintGL(self.__scrollOffset.x(), self.__scrollOffset.y(), self.width(), self.height(), self.__zoomFactor, mpvMatrix) """ ### DRAW SOMETHING ### bind texture glBindTexture(GL_TEXTURE_2D, self.__ori_tex) ### bind VAO glBindVertexArray(self.__VAO) ### draw triangle glDrawArrays(GL_TRIANGLES, 0, 18) """ ### unbind #glBindVertexArray(0) #glUseProgram(0) #self.__shaderProgram.release() def SetSomething(self): pass def DrawSomething(self): pass def ZoomIn(self): self.__zoomFactor += 0.1 def ZoomOut(self): self.__zoomFactor -= 0.1 if (self.__zoomFactor < 0.1): self.__zoomFactor = 0.1 """ Get / Set """ def GetImageSize(self): """ Get the size of the canvas / image """ return QSize(self.__image_width, self.__image_height) def SetZoomFactor(self, val): """ Set the value of magnification """ self.__zoomFactor = val def GetZoomFactor(self): """ Obtain the value of the magnification """ return self.__zoomFactor def SetMouseDown(self, val): """ Set the value of mouse down """ self.__isMouseDown = val def SetHorizontalScroll(self, val): """ Set horizontal scroll value """ self.__scrollOffset.setX(val) def SetVerticalScroll(self, val): """ Set vertical scroll value """ self.__scrollOffset.setY(val)
class MapSwipeTool(QgsMapTool): def __init__(self, iface): canvas = iface.mapCanvas() super(MapSwipeTool, self).__init__(canvas) self.view = iface.layerTreeView() self.msgBar = iface.messageBar() self.swipe = SwipeMap(canvas) self.checkDirection = self.hasSwipe = self.disabledSwipe = None self.firstPoint = QPoint() self.cursorV = QCursor(Qt.SplitVCursor) self.cursorH = QCursor(Qt.SplitHCursor) def tr(self, sourceText): context = 'MapSwipeTool' return QCoreApplication.translate(context, sourceText) def activate(self): self.canvas().setCursor(QCursor(Qt.CrossCursor)) self._connect() self.hasSwipe = False self.disabledSwipe = False self.setLayersSwipe(None, None) self.checkLayer() def canvasPressEvent(self, e): if self.checkLayer(): self.hasSwipe = True self.firstPoint.setX(e.x()) self.firstPoint.setY(e.y()) self.checkDirection = True def canvasReleaseEvent(self, e): self.hasSwipe = False self.canvas().setCursor(QCursor(Qt.CrossCursor)) def canvasMoveEvent(self, e): if self.hasSwipe: if self.checkDirection: dX = abs(e.x() - self.firstPoint.x()) dY = abs(e.y() - self.firstPoint.y()) isVertical = dX > dY self.swipe.setIsVertical(isVertical) self.checkDirection = False self.canvas().setCursor( self.cursorH if isVertical else self.cursorV) self.swipe.setLength(e.x(), e.y()) def _connect(self, isConnect=True): signal_slot = ({ 'signal': self.canvas().mapCanvasRefreshed, 'slot': self.swipe.setMap }, { 'signal': self.view.selectionModel().selectionChanged, 'slot': self.setLayersSwipe }, { 'signal': QgsMapLayerRegistry.instance().removeAll, 'slot': self.disable }) if isConnect: for item in signal_slot: item['signal'].connect(item['slot']) else: for item in signal_slot: item['signal'].disconnect(item['slot']) def checkLayer(self): if len(self.swipe.layers) == 0: msg = self.tr( "Select active Layer or Group(with layers) in legend.") self.msgBar.clearWidgets() self.msgBar.pushMessage("MapSwipeTool", msg, QgsMessageBar.WARNING, 4) return False else: return True @pyqtSlot("QModelIndex, QModelIndex") def setLayersSwipe(self, selected=None, deselected=None): if self.disabledSwipe: return ids = msg = None node = self.view.currentNode() if isinstance(node, QgsLayerTreeLayer): layer = node.layer() ids = [layer.id()] msg = self.tr("Active layer is '%s'.") % layer.name() else: group = self.view.currentGroupNode() if group.parent() is None: # Root return ids = group.findLayerIds() msg = self.tr("Active group is '%s'.") % group.name() self.swipe.clear() self.swipe.setLayersId(ids) self.swipe.setMap() if self.checkLayer(): self.msgBar.clearWidgets() self.msgBar.pushMessage("MapSwipeTool", msg, QgsMessageBar.INFO, 2) @pyqtSlot() def disable(self): self.swipe.clear() self.hasSwipe = False self.disabledSwipe = True def deactivate(self): super(MapSwipeTool, self).deactivate() self.deactivated.emit() self.swipe.clear() self._connect(False)
class ContainerWidget(QWidget): def __init__(self, container, parent: QWidget=None): QWidget.__init__(self, parent) self.setWindowTitle('Container') self.__b_widgets = [] self.__container = container self.__translation = QPoint(0, 0) self.setMouseTracking(True) self.setFocusPolicy(Qt.ClickFocus) self.setFocus() for b in container.blocks: w = b.get_widget(self) self.__b_widgets.append(w) pal = QPalette(self.palette()) pal.setColor(QPalette.Background, QColor(55, 50, 47)) self.setAutoFillBackground(True) self.setPalette(pal) container.block_added.connect(self.add_block) container.block_removed.connect(self.remove_block) self.__moving = False self.__origin = QPoint() def paintEvent(self, e: QPaintEvent): if e.isAccepted() and e.accept(): QWidget.paintEvent(self, e) p = QPainter(self) p.setRenderHint(QPainter.Antialiasing) for l in self.__container.lines: l.paint(p) def add_block(self, b): w = b.get_widget(self) self.__b_widgets.append(w) def __get_b_widget(self, b): for w in self.__b_widgets: if w.block() == b: return w return None def remove_block(self, b): w = self.__get_b_widget(b) if b is not None: self.__b_widgets.remove(b) w.deleteLater() def mousePressEvent(self, e: QMouseEvent): BlockManager.deselect_all() if e.button() == Qt.LeftButton: self.__moving = True self.__origin = e.pos() self.setCursor(Qt.DragMoveCursor) elif e.button() == Qt.RightButton: self.show_popup(e.pos()) def mouseDoubleClickEvent(self, e: QMouseEvent): BlockManager.deselect_all() if e.button() == Qt.LeftButton: self.__moving = False self.__translation = QPoint() self.translate(0, 0) def show_popup(self, pos): print('here') def mouseMoveEvent(self, e: QMouseEvent): if self.__moving: dx = e.x() - self.__origin.x() dy = e.y() - self.__origin.y() self.__origin = e.pos() self.translate(dx, dy) def mouseReleaseEvent(self, e): self.__moving = False self.setCursor(Qt.ArrowCursor) def translate(self, dx, dy): p = QPoint(self.__translation.x() + dx, self.__translation.y() + dy) self.__translation = p for b in self.__b_widgets: b.translate(p) self.repaint()
class CImprovedButton(QToolButton): def __init__(self, parent=None): QToolButton.__init__(self, parent) #TESTO ALTERNATIVO #Spesso se il pulsante ha icona troppo grossa e quando per ragioni di spazio o altro non si può spostare #o ridimensionare il pulsante stesso, la label ha posizioni assurde e schifose. Aggiungerne una "+ controllabile" #è l'unico modo.. self.__fixed_label = QLabel("alternative label", self) self.__fixed_label.move(0, self.geometry().height() - 35) self.__fixed_label.resize(self.geometry().width(), self.__fixed_label.geometry().height()) self.__fixed_label.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) self.__font = QtGui.QFont("Arial", 10) self.__fixed_label.setFont(self.__font) self.__fixed_label.show() #INDICATORE STILE iOS self.__indicator = QLabel("0", self) self.__indicator.setStyleSheet( "border-image: url(':/images/backgrounds/indicator.png'); padding-right:1px; color: white;" ) self.__indicator.geometry().setWidth(25) self.__indicator.geometry().setHeight(20) self.__indicator.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) self.__indicator.setVisible(False) self.setIndicatorPos(QPoint(self.width() - self.__indicator.width(), 0)) #default top-right corner #Quando il pulsante viene ridimensionato (designer o meno) devo anche sistemare la label di conseguenza self.resizeEvent = self.__onResize self.__indicator.resizeEvent = self.__on_indicator_Resize self.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) self.clicked.connect(self.stopAllAnimations) #BLINK self.__blink_timer = QTimer(parent) self.__blink_timer.timeout.connect(self.__on_blink_timer) self.__blink_timer_interval = 1000 #FADING self.__opacity_effect = QGraphicsOpacityEffect() self.__fading_timer = QTimer(parent) self.__fading_timer.timeout.connect(self.__on_fading_timer) self.__FADE_TYPE = Enum("IN", "OUT") self.__fade_time = 20 self.__opacity = 1.0 self.__opacity_fading_coefficient = 0.02 self.__selected_fade_type = self.__FADE_TYPE.IN # ANIMAZIONI GROW self.__animationGrow = QPropertyAnimation(self, "iconSize", self) self.__animationGrow.setDuration(1000) self.__animationGrow.setEasingCurve(QEasingCurve.Linear) self.__animationGrow.finished.connect(self.__on_growed) self.__animationShrink = QPropertyAnimation(self, "iconSize", self) self.__animationShrink.setDuration(1000) self.__animationShrink.setEasingCurve(QEasingCurve.Linear) self.__animationShrink.finished.connect(self.__on_shrinked) self.__defaultIconDimension = 60 self.__iconGrowsBy = 40 self.__growing = False # ANIMAZIONI BOUNCE self.__animationUp = QPropertyAnimation(self, "pos", self) self.__animationUp.setDuration(200) self.__animationUp.setEasingCurve(QEasingCurve.Linear) self.__animationUp.finished.connect(self.__on_top_reached) self.__animationBounce = QPropertyAnimation(self, "pos", self) self.__animationBounce.setDuration(1000) self.__animationBounce.setEasingCurve(QEasingCurve.OutBounce) self.__animationBounce.finished.connect(self.__on_bounce_finished) self.__bouncing = False self.__startPos = QPoint(self.pos().x(), self.pos().y()) #PIXMAP & MASCHERA self.__pmap = QPixmap(self.size()) self.__pmap_fname = "" self.__show_mask_preview = False def setDefaultIconSize(self, value): """ Sets default icon size when growing stops. @param value: size (both width and height) @type value: int """ self.__defaultIconDimension = value def getDefaultIconSize(self): return self.__defaultIconDimension defaultIconSize = QtCore.pyqtProperty("int", getDefaultIconSize, setDefaultIconSize) def setFixetTextVisibility(self, bool): """ Sets if fixed text is visible or not. @param bool: visible or not @type bool: bool """ self.__fixed_label.setVisible(bool) def getFixetTextVisibility(self): return self.__fixed_label.isVisible() fixetTextVisibility = QtCore.pyqtProperty("bool", fget=getFixetTextVisibility, fset=setFixetTextVisibility) def setFixedText(self, txt): """ Sets text on the button. @param txt: text @type txt: string """ self.__fixed_label.setText(txt) def getFixedText(self): return self.__fixed_label.text() fixedText = QtCore.pyqtProperty("QString", getFixedText, setFixedText) def setFixedTextPos(self, qpoint): """ Sets text position in the button. @param qpoint: Position RELATIVE. 0,0 is top left corner of the button. @type qpoint: QPoint """ self.__fixed_label.move(qpoint) def getFixedTextPos(self): return self.__fixed_label.pos() fixedTextPos = QtCore.pyqtProperty("QPoint", getFixedTextPos, setFixedTextPos) def setFixedTextFont(self, font): """ Sets text font. @param font: Font for fixed text. @type font: QFont """ self.__font = font self.__fixed_label.setFont(self.__font) def getFixedTextFont(self): return self.__font fixedTextFont = QtCore.pyqtProperty("QFont", getFixedTextFont, setFixedTextFont) #FUNZIONI INDICATORE def setIndicatorVisibility(self, bool): """ Sets if indicator is visible or not. @param bool: visible or not @type bool: bool """ self.__indicator.setVisible(bool) def getIndicatorVisibility(self): return self.__indicator.isVisible() indicatorVisibility = QtCore.pyqtProperty("bool", fget=getIndicatorVisibility, fset=setIndicatorVisibility) def setIndicatorPos(self, qpoint): """ Sets indicator position in the button. @param qpoint: Position RELATIVE. 0,0 is top left corner of the button. @type qpoint: QPoint """ self.__indicator.move(qpoint) def getIndicatorPos(self): return self.__indicator.pos() indicatorPos = QtCore.pyqtProperty("QPoint", getIndicatorPos, setIndicatorPos) def setIndicatorSize(self, size): """ Sets indicator size. @param size: Size @type size: QSize """ self.__indicator.resize(size) def getIndicatorSize(self): return self.__indicator.size() indicatorSize = QtCore.pyqtProperty("QSize", getIndicatorSize, setIndicatorSize) def setIndicatorFont(self, font): """ Sets indicator text font. @param font: Font for indicator text. @type font: QFont """ self.__indicator.setFont(font) def getIndicatorFont(self): return self.__indicator.font() indicatorFont = QtCore.pyqtProperty("QFont", getIndicatorFont, setIndicatorFont) ## FUNZIONI PER BLINK def __on_blink_timer(self): self.setVisible(not (self.isVisible())) def setBlinking(self, blink): """ Sets if the button have to blink or not. @param blink: blinking or not @type blink: bool """ if blink: self.__blink_timer.setInterval(self.__blink_timer_interval) self.__blink_timer.start() else: self.__blink_timer.stop() self.setVisible(True) def setBlinkInterval(self, value): """ Sets blink interval. @param blink: blink interval (msec) @type blink: int """ self.__blink_timer_interval = value def getBlinkInterval(self): return self.__blink_timer_interval blinkInterval = QtCore.pyqtProperty("int", getBlinkInterval, setBlinkInterval) ##FUNZIONI PER FADING def fadeIn(self): """ Button fades in from completely invisible to completely visible. """ self.__opacity = 0.0 self.__selected_fade_type = self.__FADE_TYPE.IN self.__fading_timer.start(self.__fade_time) def fadeOut(self): """ Button fades out from completely visible to completely invisible. """ self.__selected_fade_type = self.__FADE_TYPE.OUT self.__fading_timer.start(self.__fade_time) def setFadeTime(self, value): """ Sets fading time. Everytime interval is reached, alpha is increased (or decreased) by __opacity_fading_coefficient. @param value: fade time (msec) @type value: int """ self.__fade_time = value def getFadeTime(self): return self.__fade_time fadeInterval = QtCore.pyqtProperty("int", getFadeTime, setFadeTime) def setFadeCoefficient(self, value): """ Sets fading coefficient. Alpha is increased (or decreased) by this value. @param value: coefficient (min 0.0 - max 1.0) @type value: float """ self.__opacity_fading_coefficient = value def getFadeCoefficient(self): return self.__opacity_fading_coefficient fadeCoefficient = QtCore.pyqtProperty("double", getFadeCoefficient, setFadeCoefficient) def __on_fading_timer(self): if self.__selected_fade_type == self.__FADE_TYPE.OUT: if self.__opacity > 0: self.__opacity -= self.__opacity_fading_coefficient self.__opacity_effect.setOpacity(self.__opacity) self.setGraphicsEffect(self.__opacity_effect) else: self.__fading_timer.stop() if self.__selected_fade_type == self.__FADE_TYPE.IN: if self.__opacity <= 1.0: self.__opacity += self.__opacity_fading_coefficient self.__opacity_effect.setOpacity(self.__opacity) self.setGraphicsEffect(self.__opacity_effect) else: self.__fading_timer.stop() # FUNZIONI PER GROW\SHRINK def __on_growed(self): self.__animationShrink.setStartValue( QSize(self.iconSize().width(), self.iconSize().height())) self.__animationShrink.setEndValue( QSize(self.iconSize().width() - self.__iconGrowsBy, self.iconSize().height() - self.__iconGrowsBy)) self.__animationShrink.start() def __on_shrinked(self): self.__animationGrow.setStartValue( QSize(self.iconSize().width(), self.iconSize().height())) self.__animationGrow.setEndValue( QSize(self.iconSize().width() + self.__iconGrowsBy, self.iconSize().height() + self.__iconGrowsBy)) self.__animationGrow.start() def startGrow(self): """ Button ICON starts to grow and shrink to standard value when maximum size (configured) is reached """ if self.__growing: return self.__animationGrow.setStartValue( QSize(self.iconSize().width(), self.iconSize().height())) self.__animationGrow.setEndValue( QSize(self.iconSize().width() + self.__iconGrowsBy, self.iconSize().height() + self.__iconGrowsBy)) self.__animationGrow.start() self.__growing = True def stopGrow(self): if self.__animationGrow.startValue().toSize() != QSize( 0, 0) and self.__animationShrink.startValue().toSize() != QPoint( 0, 0): self.__animationGrow.stop() self.__animationShrink.stop() self.setIconSize( QSize(self.__defaultIconDimension, self.__defaultIconDimension)) self.__growing = False #FUNZIONI PER BOUNCE def startBounce(self): """ Button starts to bounce requiring attention. """ if self.__bouncing: return self.__startPos = QPoint(self.pos().x(), self.pos().y()) self.__animationUp.setStartValue( QPoint(self.__startPos.x(), self.__startPos.y())) self.__animationUp.setEndValue( QPoint(self.__startPos.x(), self.__startPos.y() - self.geometry().height())) self.__animationUp.start() self.__bouncing = True def stopBounce(self): if self.__animationUp.startValue().toPoint() != QPoint( 0, 0) and self.__animationBounce.startValue().toPoint() != QPoint( 0, 0): self.__animationBounce.stop() self.__animationUp.stop() self.setGeometry(self.__startPos.x(), self.__startPos.y(), self.geometry().width(), self.geometry().height()) self.__bouncing = False def __on_top_reached(self): self.__animationBounce.setStartValue( QPoint(self.pos().x(), self.pos().y())) self.__animationBounce.setEndValue( QPoint(self.__startPos.x(), self.__startPos.y())) self.__animationBounce.start() def __on_bounce_finished(self): self.__animationUp.start() def stopAllAnimations(self): self.stopBounce() self.stopGrow() #FUNZIONI PER PIXMAP & MASCHERA def setPixmapFile(self, image_file): self.__pmap = image_file self.__pmap.scaled(self.size()) #NB: Il pixmap deve essere BIANCO e NERO. Con heuristicMask il primo pixel in alto a sinistra (0,0) viene #usato per decidere il colore trasparente, tutto il resto è visibile. def getPixmapFile(self): return self.__pmap pixmapFile = QtCore.pyqtProperty("QPixmap", getPixmapFile, setPixmapFile) def applyMask(self, bool): self.__show_mask_preview = bool if bool: self.setMask( QBitmap(self.__pmap.createHeuristicMask().scaled(self.size()))) else: self.setMask(QBitmap()) def getMask(self): return self.__show_mask_preview appliedMask = QtCore.pyqtProperty("bool", fget=getMask, fset=applyMask) def __onResize(self, event): self.__fixed_label.move(0, self.geometry().height() - 35) self.__fixed_label.resize(self.geometry().width(), self.__fixed_label.geometry().height()) self.setIndicatorPos(QPoint(self.width() - self.__indicator.width(), 0)) self.__pmap.scaled(self.size()) if self.__show_mask_preview: self.setMask( QBitmap(self.__pmap.createHeuristicMask().scaled(self.size()))) def __on_indicator_Resize(self, event): self.setIndicatorPos(QPoint(self.width() - self.__indicator.width(), 0))
class OGLViewer(QGLWidget): ''' OpenGL viewer class ''' def __init__(self, parent=None): ''' Viewer's Constructor ''' frmt = QGLFormat() frmt.setSampleBuffers(True) super(OGLViewer, self).__init__(frmt, parent) #self.setMouseTracking (True) self.__mouse = QCursor() self.setCursor(Qt.OpenHandCursor) self.setFocusPolicy(Qt.ClickFocus) self.__Ctrl_or_Meta_key_pressed = False self.__Alt_key_pressed = False self.__w = 720 self.__h = 450 self._init_camera_vars() self._init_objec_vars() # matrix changed signal. The signal's payload is the matrix itself. self.__GLMatrixChanged = SIGNAL("MatrixChanged (PyQt_PyObject)") self.__compo_light_pos = QVector3D(.3, .2, .1) self.__AmbientMaterial = QVector3D(.2, .2, .2) def _init_camera_vars(self): ''' static method. It initializes the math variables. ''' self.__compo_mtools = MathTools.Tools() self.__curr_angles = QPoint(0, 0) self.__last_pos = QPoint(0, 0) self.__delta = QPoint(0, 0) self.__orig = QVector3D(0.0, 0.0, 0.0) self.__cam_dist = 0.0 self.__z_near = 0.1 self.__z_far = 2000.0 self.__fovy = 45.0 self.__angle = self.__compo_mtools.getAngle(self.__fovy) self.__norm_mtx = QMatrix4x4() #(GLdouble * 16)() self.__norm_mtx.setToIdentity() self.__mtx = QMatrix4x4() #(GLdouble * 16)() self.__mtx.setToIdentity() self.__aspect_ratio = float(self.__w) / float(self.__h) self.__camera_list = [] def _init_objec_vars(self): self.__arrows_list = [] self.__arrow_len = 2.0 self.__lines_list = [] self.__l_param = 200.0 self.__intersections_list = [] self.__poly_model = None self.__poly_list = [] # by polygon I mean triangle. def initializeGL(self): ''' usual OpenGL method ''' glClearColor(0.93, 0.93, 0.93, 1.0) glClearDepth(1.0) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(self.__fovy, float(self.__w) / float(self.__h), self.__z_near, self.__z_far) self.refreshMatrices() def resizeGL(self, w, h): ''' usual OpenGL method ''' self.__w = w self.__h = h self.__aspect_ratio = float(self.__w) / float(self.__h) glMatrixMode(GL_MODELVIEW) glLoadIdentity() gluPerspective(self.__fovy, self.__aspect_ratio, self.__z_near, self.__z_far) glViewport(0, 0, self.__w, self.__h) gluLookAt( 0, 0, -1, # CameraPos 0, 0, 0, # CameraLookAt 0, 1, 0) # CameraUp def paintGL(self): ''' usual OpenGL method ''' self.__delta = QPoint(0, 0) q = self.__mouse.pos() if self.__Ctrl_or_Meta_key_pressed ^ self.__Alt_key_pressed: # xor (strictly one or the other) if self.__Ctrl_or_Meta_key_pressed: # rotation self.__delta = q - self.__last_pos else: # translation # transform mouse deltas and camera's local axes so that it'll look like as if the camera gets # translated based on the local axes x and y. What really happens is that the origin shifts along. # The resulting behaviour reminds of the Maya Camera Track Tool. d_x = q.x() - self.__last_pos.x() d_y = q.y() - self.__last_pos.y() zero = 0.0 #GLdouble (0.0) m_ref = self.__mtx.data( ) # retrieves the 16 items in this matrix and copies them to values in row-major order. vec_x = -m_ref[0] * d_x + m_ref[4] * d_y + zero * m_ref[8] vec_y = -m_ref[1] * d_x + m_ref[5] * d_y + zero * m_ref[9] vec_z = -m_ref[2] * d_x + m_ref[6] * d_y + zero * m_ref[10] mult = 0.03 self.__orig.setX(self.__orig.x() + mult * vec_x) self.__orig.setY(self.__orig.y() + mult * vec_y) self.__orig.setZ(self.__orig.z() + mult * vec_z) # fire signal after done changing the model matrix. self.emit(self.__GLMatrixChanged, self.__mtx) self.__last_pos = q self.__curr_angles += self.__delta if glCheckFramebufferStatus( GL_FRAMEBUFFER) == 36053: # 36053 = GL_FRAMEBUFFER_COMPLETE glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() # Set the camera orientation : glMatrixMode(GL_MODELVIEW) glLoadIdentity() gluLookAt( self.__orig.x(), self.__orig.y(), self.__orig.z() - 40, # CameraPos self.__orig.x(), self.__orig.y(), self.__orig.z(), # CameraLookAt 0.0, 1.0, 1.0) # CameraUp # Rotate and move camera forward or backward. glTranslatef(0, 0, -self.__cam_dist) glTranslatef(self.__orig.x(), self.__orig.y(), self.__orig.z()) # rotation around current origin. glRotatef(-30 - self.__curr_angles.y() * 0.15, 1, 0, 0) # rotate around axis x. glRotatef(-30 + self.__curr_angles.x() * 0.1, 0, 1, 0) # rotate around axis y. glTranslatef(-self.__orig.x(), -self.__orig.y(), -self.__orig.z()) # rotation around current origin. self.refreshMatrices() self.displayObjects() self.displayArrows() self.displayLines() self.displayIntersections() self.drawGrid() self.drawFixedOriginAxes() self.drawCurrentOriginAxes() self.displayCamera() def refreshMatrices(self): tmp = glGetDoublev( GL_MODELVIEW_MATRIX ) # this returns a list of lists BUT QMatrix4x4 accepts a list of floats. tmp_qmtx = QMatrix4x4([ item for sublist in tmp for item in sublist ]) # flattens the list of lists out in a single list. self.__mtx = tmp_qmtx tmp_tuple = tmp_qmtx.inverted() self.__norm_mtx = (tmp_tuple[0]).transposed( ) # assumption : matrix always invertible so I'm not going to check the boolean tmp_tuple[1]. def run(self): ''' method refreshed cyclically by a timer when it is in focus. When out of focus, the timer stops calling it and so freezing the image to what it looked like when last used. ''' self.paintGL() # render actual frame self.swapBuffers() def addCamera(self): self.__compo_mtools.setNormalMatrix(self.__norm_mtx) angle_by_aspect_ratio = self.__angle * self.__aspect_ratio inv_w = 1.0 / self.__w inv_h = 1.0 / self.__h m = -1.0 w_param = (inv_w - 1) * angle_by_aspect_ratio h_param = (1 - inv_h) * self.__angle # compute center + corners cam_centre = self.__compo_mtools.cameraToWorldTransform(0, 0, 0) top_left = self.__compo_mtools.cameraToWorldTransform( w_param, h_param, m) top_right = self.__compo_mtools.cameraToWorldTransform( w_param, -h_param, m) bottom_left = self.__compo_mtools.cameraToWorldTransform( -w_param, h_param, m) bottom_right = self.__compo_mtools.cameraToWorldTransform( -w_param, -h_param, m) self.__camera_list.append( [cam_centre, top_left, top_right, bottom_left, bottom_right]) # - - - viewer graphics - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def displayCamera(self): glLineWidth(1.0) for cam in self.__camera_list: cc = cam[0] tl = cam[1] tr = cam[2] bl = cam[3] br = cam[4] glBegin(GL_LINES) glColor3f(0.6, 0.6, 0.6) glVertex3f(cc[0], cc[1], cc[2]) glVertex3f(tl[0], tl[1], tl[2]) glVertex3f(cc[0], cc[1], cc[2]) glVertex3f(tr[0], tr[1], tr[2]) glVertex3f(cc[0], cc[1], cc[2]) glVertex3f(br[0], br[1], br[2]) glVertex3f(cc[0], cc[1], cc[2]) glVertex3f(bl[0], bl[1], bl[2]) glVertex3f(tl[0], tl[1], tl[2]) glVertex3f(tr[0], tr[1], tr[2]) glVertex3f(tr[0], tr[1], tr[2]) glVertex3f(br[0], br[1], br[2]) glVertex3f(br[0], br[1], br[2]) glVertex3f(bl[0], bl[1], bl[2]) glVertex3f(bl[0], bl[1], bl[2]) glVertex3f(tl[0], tl[1], tl[2]) glEnd() def displayObjects(self): glClear(GL_COLOR_BUFFER_BIT) glEnable(GL_DEPTH_TEST) glDepthMask(GL_TRUE) #glEnable (GL_CULL_FACE) for poly in self.__poly_list: p0 = poly[0] p1 = poly[1] p2 = poly[2] glBegin(GL_TRIANGLES) col = .4 + 0.5 * QVector3D.dotProduct(poly[3], self.__compo_light_pos) glColor3f(col, col, col) glVertex3f(p0.x(), p0.y(), p0.z()) glVertex3f(p1.x(), p1.y(), p1.z()) glVertex3f(p2.x(), p2.y(), p2.z()) glEnd() def displayIntersections(self): for intsect in self.__intersections_list: p = intsect[0] c = intsect[1] # Draw a translated solid sphere glPushMatrix() glTranslatef(p[0], p[1], p[2]) glColor3f(c[0], c[1], c[2]) glutSolidSphere(GLdouble(0.03), 9, 9) glPopMatrix() def displayLines(self): glLineWidth(1.0) for line in self.__lines_list: p = line[0] # line initial position (3-list) d = line[1] # line direction (3-list) t = str(line[2]) # line type (o:open line, p:point-to-point line) glBegin(GL_LINES) glColor3ub(255, 255, 255) glVertex3f(p[0], p[1], p[2]) # open line if t == 'o': glVertex3f(self.__l_param * d[0] + p[0], self.__l_param * d[1] + p[1], self.__l_param * d[2] + p[2]) # point-to-point line elif t == 'p': glVertex3f(d[0], d[1], d[2]) else: raise sys.exit('*** Unrecognised line type : "' + t + '"') glEnd() def displayArrows(self): for arrow in self.__arrows_list: p = arrow[0] # arrow position (3-list) d = arrow[1] # arrow direction (3-list) t = str(arrow[2]) # arrow type (i:inwards, o:outwards) # scale parameters scale_x = 0.01 scale_y = scale_x scale_z = 0.5 t_z = scale_z * self.__arrow_len # arrow type if t == 'o': add_t = 0 elif t == 'i': add_t = -t_z * 2.5 else: raise sys.exit('*** Unrecognised arrow type : "' + t + '"') glPushMatrix() # arrow shaft glColor3f(0.5, 0.5, 0) glTranslatef(p[0], p[1], p[2]) angles_from_orient = self.__compo_mtools.alignZAxisToVector( d[0], d[1], d[2]) glRotatef(180, 0, 0, 1) glRotatef(angles_from_orient[1], 0, 1, 0) glRotatef(angles_from_orient[0], 1, 0, 0) glScale(scale_x, scale_y, scale_z) glTranslatef(0, 0, t_z + add_t) glutSolidCube(GLdouble(self.__arrow_len)) # arrow head # REMEMBER ! The head's transformations are built on top of the arrow shaft's and are NOT independent ! # The reason for doing that is that the user can change the scale of the arrow from UI's slider. glColor3f(0.6, 0.6, 0) glTranslatef(0, 0, t_z) glutSolidCone(GLdouble(t_z * 5), GLdouble(t_z * 0.5), GLint(6), GLint(2)) glPopMatrix() def drawGrid(self): glLineWidth(1.0) for i in range(-10, 11): glBegin(GL_LINES) glColor3ub(185, 185, 185) glVertex3f(-10, 0, i) glVertex3f(10, 0, i) glVertex3f(i, 0, -10) glVertex3f(i, 0, 10) glEnd() def drawFixedOriginAxes(self): glLineWidth(2.0) glBegin(GL_LINES) glColor3ub(250, 0, 0) glVertex3f(0, 0, 0) glVertex3f(0, 0, 5) glColor3ub(255, 150, 150) glVertex3f(0, 0, 5) glVertex3f(0, 0, 10) glEnd() glBegin(GL_LINES) glColor3ub(0, 250, 0) glVertex3f(0, 0, 0) glVertex3f(0, 5, 0) glColor3ub(150, 255, 150) glVertex3f(0, 5, 0) glVertex3f(0, 10, 0) glEnd() glBegin(GL_LINES) glColor3ub(0, 0, 250) glVertex3f(0, 0, 0) glVertex3f(5, 0, 0) glColor3ub(150, 150, 255) glVertex3f(5, 0, 0) glVertex3f(10, 0, 0) glEnd() def drawCurrentOriginAxes(self): glPointSize(6.0) glBegin(GL_POINTS) glColor3f(0.0, 1.0, 1.0) glVertex3f(self.__orig.x(), self.__orig.y(), self.__orig.z()) glEnd() glBegin(GL_LINES) glColor3ub(250, 0, 0) glVertex3f(self.__orig.x(), self.__orig.y(), self.__orig.z()) glVertex3f(self.__orig.x(), self.__orig.y(), self.__orig.z() + 5) glEnd() glBegin(GL_LINES) glColor3ub(0, 250, 0) glVertex3f(self.__orig.x(), self.__orig.y(), self.__orig.z()) glVertex3f(self.__orig.x(), self.__orig.y() + 5, self.__orig.z()) glEnd() glBegin(GL_LINES) glColor3ub(0, 0, 250) glVertex3f(self.__orig.x(), self.__orig.y(), self.__orig.z()) glVertex3f(self.__orig.x() + 5, self.__orig.y(), self.__orig.z()) glEnd() # - - - listeners - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def changeArrowsSize(self, new_size): if len(self.__arrows_list) > 0: self.__arrow_len = new_size def addArrow(self, pos, orient, arrow_type): self.__arrows_list.append([pos, orient, arrow_type]) def addLine(self, pos, orient_or_second_point, line_type): self.__lines_list.append([pos, orient_or_second_point, line_type]) def addIntersection(self, pos, icolor): self.__intersections_list.append([pos, icolor]) def keyPressEvent(self, e): if e.key() == Qt.Key_Control or e.key() == Qt.Key_Meta: self.__Ctrl_or_Meta_key_pressed = True if e.key() == Qt.Key_Alt: self.__Alt_key_pressed = True def keyReleaseEvent(self, e): if e.key() == Qt.Key_Control or e.key() == Qt.Key_Meta: self.__Ctrl_or_Meta_key_pressed = False if e.key() == Qt.Key_Alt: self.__Alt_key_pressed = False def wheelEvent(self, e): if self.__Ctrl_or_Meta_key_pressed: self.__cam_dist += e.delta() * 0.01 # the three methods below are for regulate the OpenGL widget's FPS based on the focus received by the user. def setUi_Form(self, uif): self.uiform = uif def focusInEvent(self, e): self.uiform.speedUpGLFrameRate() def focusOutEvent(self, e): self.uiform.freezeGLFrameRate() def getFovy(self): return self.__fovy def getMatrix(self): return self.__mtx def getNormalMatrix(self): return self.__norm_mtx def setModel(self, model): self.__poly_model = model self.__poly_list = model.getPolyListCopy()