class FaderWidget(QLabel): """Custom Placeholder Fading Widget for tabs on TabWidget.""" def __init__(self, parent): """Init class.""" super(FaderWidget, self).__init__(parent) self.timeline, self.opacity, self.old_pic = QTimeLine(), 1.0, None self.timeline.valueChanged.connect(self.animate) self.timeline.finished.connect(self.close) self.timeline.setDuration(750) # 500 ~ 750 Ms is Ok, Not more. def paintEvent(self, event): """Overloaded paintEvent to set opacity and pic.""" painter = QPainter(self) painter.setOpacity(self.opacity) if self.old_pic: painter.drawPixmap(0, 0, self.old_pic) def animate(self, value): """Animation of Opacity.""" self.opacity = 1.0 - value return self.hide() if self.opacity < 0.1 else self.repaint() def fade(self, old_pic, old_geometry, move_to): """Fade from previous tab to new tab.""" if self.isVisible(): self.close() if self.timeline.state(): self.timeline.stop() self.setGeometry(old_geometry) self.move(1, move_to) self.old_pic = old_pic self.timeline.start() self.show()
class FaderWidget(QtWidgets.QWidget): pixmap_opacity = 0 def __init__(self, old_widget, new_widget): QtWidgets.QWidget.__init__(self, new_widget) self.old_pixmap = QtGui.QPixmap(new_widget.size()) old_widget.render(self.old_pixmap) self.pixmap_opacity = 1.0 self.timeline = QTimeLine() self.timeline.valueChanged.connect(self.animate) self.timeline.finished.connect(self.close) self.timeline.setDuration(500) self.timeline.start() self.resize(new_widget.size()) self.show() def paintEvent(self, event): painter = QtGui.QPainter() painter.begin(self) painter.setOpacity(self.pixmap_opacity) painter.drawPixmap(0, 0, self.old_pixmap) painter.end() def animate(self, value): self.pixmap_opacity = 1.0 - value self.repaint()
class FaderWidget(QWidget): """ A QWidget that allows for fading in and out on display. """ def __init__(self, old_widget, new_widget): QWidget.__init__(self, new_widget) self.old_pixmap = QPixmap(new_widget.size()) old_widget.render(self.old_pixmap) self.pixmap_opacity = 1.0 self.timeline = QTimeLine() self.timeline.valueChanged.connect(self.animate) self.timeline.finished.connect(self.close) self.timeline.setDuration(450) self.timeline.start() self.resize(new_widget.size()) self.show() def paintEvent(self, event): painter = QPainter() painter.begin(self) painter.setOpacity(self.pixmap_opacity) painter.drawPixmap(0, 0, self.old_pixmap) painter.end() def animate(self, value): self.pixmap_opacity = 1.0 - value self.repaint()
class FaderWidget(QWidget): def __init__(self, old_widget, new_widget): super(FaderWidget, self).__init__(new_widget) self.old_pixmap = QPixmap(new_widget.size()) old_widget.render(self.old_pixmap) self.pixmap_opacity = 1.0 self.timeline = QTimeLine() self.timeline.valueChanged.connect(self.animate) self.timeline.finished.connect(self.close) self.timeline.setDuration(500) self.timeline.start() self.resize(new_widget.size()) self.show() def paintEvent(self, event): painter = QPainter() painter.begin(self) painter.setOpacity(self.pixmap_opacity) painter.drawPixmap(0, 0, self.old_pixmap) painter.end() def animate(self, value): self.pixmap_opacity = 1.0 - value self.repaint()
class CCountUp(QLabel): def __init__(self, *args, **kwargs): super(CCountUp, self).__init__(*args, **kwargs) self.isFloat = False # 是否是小数 font = self.font() or QFont() font.setBold(True) self.setFont(font) self.timeline = QTimeLine(6000, self) self.timeline.setEasingCurve(QEasingCurve.OutExpo) self.timeline.frameChanged.connect(self.onFrameChanged) def pause(self): """暂停 """ self.timeline.setPaused(True) def resume(self): """继续 """ self.timeline.resume() def isPaused(self): """是否暂停 """ return self.timeline.state() == QTimeLine.Paused def reset(self): """重置 """ self.timeline.stop() self.isFloat = False # 是否是小数 self.setText('0') def onFrameChanged(self, value): if self.isFloat: value = round(value / 100.0 + 0.00001, 2) value = str(format(value, ',')) self.setText(value + '0' if value.endswith('.0') else value) def setDuration(self, duration): """设置动画持续时间 :param duration: """ self.timeline.setDuration(duration) def setNum(self, number): """设置数字 :param number: int or float """ if isinstance(number, int): self.isFloat = False self.timeline.setFrameRange(0, number) elif isinstance(number, float): self.isFloat = True self.timeline.setFrameRange(0, number * 100) self.timeline.stop() self.setText('0') self.timeline.start()
class Robot(RobotPart): def __init__(self): super(Robot, self).__init__() self.torsoItem = RobotTorso(self) self.headItem = RobotHead(self.torsoItem) self.upperLeftArmItem = RobotLimb(self.torsoItem) self.lowerLeftArmItem = RobotLimb(self.upperLeftArmItem) self.upperRightArmItem = RobotLimb(self.torsoItem) self.lowerRightArmItem = RobotLimb(self.upperRightArmItem) self.upperRightLegItem = RobotLimb(self.torsoItem) self.lowerRightLegItem = RobotLimb(self.upperRightLegItem) self.upperLeftLegItem = RobotLimb(self.torsoItem) self.lowerLeftLegItem = RobotLimb(self.upperLeftLegItem) self.timeline = QTimeLine() settings = [ # item position rotation at # x y time 0 / 1 ( self.headItem, 0, -18, 20, -20 ), ( self.upperLeftArmItem, -15, -10, 190, 180 ), ( self.lowerLeftArmItem, 30, 0, 50, 10 ), ( self.upperRightArmItem, 15, -10, 300, 310 ), ( self.lowerRightArmItem, 30, 0, 0, -70 ), ( self.upperRightLegItem, 10, 32, 40, 120 ), ( self.lowerRightLegItem, 30, 0, 10, 50 ), ( self.upperLeftLegItem, -10, 32, 150, 80 ), ( self.lowerLeftLegItem, 30, 0, 70, 10 ), ( self.torsoItem, 0, 0, 5, -20 ) ] self.animations = [] for item, pos_x, pos_y, rotation1, rotation2 in settings: item.setPos(pos_x,pos_y) animation = QGraphicsItemAnimation() animation.setItem(item) animation.setTimeLine(self.timeline) animation.setRotationAt(0, rotation1) animation.setRotationAt(1, rotation2) self.animations.append(animation) self.animations[0].setScaleAt(1, 1.1, 1.1) self.timeline.setUpdateInterval(1000 / 25) self.timeline.setCurveShape(QTimeLine.SineCurve) self.timeline.setLoopCount(0) self.timeline.setDuration(2000) self.timeline.start() def boundingRect(self): return QRectF() def paint(self, painter, option, widget=None): pass
class Robot(RobotPart): def __init__(self): super(Robot, self).__init__() self.torsoItem = RobotTorso(self) self.headItem = RobotHead(self.torsoItem) self.upperLeftArmItem = RobotLimb(self.torsoItem) self.lowerLeftArmItem = RobotLimb(self.upperLeftArmItem) self.upperRightArmItem = RobotLimb(self.torsoItem) self.lowerRightArmItem = RobotLimb(self.upperRightArmItem) self.upperRightLegItem = RobotLimb(self.torsoItem) self.lowerRightLegItem = RobotLimb(self.upperRightLegItem) self.upperLeftLegItem = RobotLimb(self.torsoItem) self.lowerLeftLegItem = RobotLimb(self.upperLeftLegItem) self.timeline = QTimeLine() settings = [ # item position rotation at # x y time 0 / 1 (self.headItem, 0, -18, 20, -20), (self.upperLeftArmItem, -15, -10, 190, 180), (self.lowerLeftArmItem, 30, 0, 50, 10), (self.upperRightArmItem, 15, -10, 300, 310), (self.lowerRightArmItem, 30, 0, 0, -70), (self.upperRightLegItem, 10, 32, 40, 120), (self.lowerRightLegItem, 30, 0, 10, 50), (self.upperLeftLegItem, -10, 32, 150, 80), (self.lowerLeftLegItem, 30, 0, 70, 10), (self.torsoItem, 0, 0, 5, -20) ] self.animations = [] for item, pos_x, pos_y, rotation1, rotation2 in settings: item.setPos(pos_x, pos_y) animation = QGraphicsItemAnimation() animation.setItem(item) animation.setTimeLine(self.timeline) animation.setRotationAt(0, rotation1) animation.setRotationAt(1, rotation2) self.animations.append(animation) self.animations[0].setScaleAt(1, 1.1, 1.1) self.timeline.setUpdateInterval(1000 / 25) self.timeline.setCurveShape(QTimeLine.SineCurve) self.timeline.setLoopCount(0) self.timeline.setDuration(2000) self.timeline.start() def boundingRect(self): return QRectF() def paint(self, painter, option, widget=None): pass
def wheelEvent(self, event): numDegrees = event.angleDelta() / 8 print("wheel: {}".format(numDegrees)) numSteps = numDegrees.y() / 15 self._numScheduledScalings += numSteps if self._numScheduledScalings * numSteps < 0: self._numScheduledScalings = numSteps anim = QTimeLine(350, self) anim.setUpdateInterval(20) anim.valueChanged.connect(self.ScalingTime) anim.finished.connect(self.AnimFinished) anim.start()
def wheelEvent(self, event): # Check if zooming is enabled if not self.parent.menu.options[1].isChecked(): return # Zooming event on mouse scroll numDegrees = event.angleDelta() / 8 numSteps = (numDegrees / 15).y() self._numScheduledScalings += numSteps if self._numScheduledScalings * numSteps < 0: self._numScheduledScalings = numSteps anim = QTimeLine(350, self) anim.setUpdateInterval(20) anim.valueChanged.connect(self.scalingTime) anim.finished.connect(self.animFinished) anim.start()
def wheelEvent(self, event): numDegrees = event.angleDelta() / 8 numSteps = numDegrees / 15 self._numScheduledScalings += numSteps.y() """ if user moved the wheel in another direction, we reset previously scheduled scalings """ if self._numScheduledScalings * numSteps.y() < 0: self._numScheduledScalings = numSteps.y() anim = QTimeLine(350, self) anim.setUpdateInterval(20) anim.valueChanged.connect(self.scalingTime) anim.finished.connect(self.animFinished) anim.start()
def zoom(self, numDegrees): numSteps = numDegrees / 15 self._numScheduledScalings += numSteps if ( self._numScheduledScalings * numSteps < 0 ): # if user moved the wheel in another direction, we reset previously scheduled scalings self._numScheduledScalings = numSteps anim = QTimeLine(350, self) anim.setUpdateInterval(20) anim.valueChanged.connect(self.scalingTime) anim.finished.connect(self.scaleAnimFinished) anim.start()
def wheelEvent(self, event): degree = event.angleDelta().y() / 8 step = degree / 15 self.scheduledscaling = self.scheduledscaling + step animation = QTimeLine(350) animation.setUpdateInterval(20) animation.valueChanged.connect( animation.currentValue ) #Timeline does not start without this line, maybe a QT bug animation.valueChanged.connect( lambda: self.scale(1.0 + self.scheduledscaling / 300.0, 1.0 + self. scheduledscaling / 300.0)) animation.finished.connect(self.reset) animation.start()
def translateVerticalEvent(self, dy): numSteps = dy * 20 self._numScheduledVTranslations += numSteps if ( self._numScheduledVTranslations * numSteps < 0 ): # if user moved the wheel in another direction, we reset previously scheduled scalings self._numScheduledVTranslations = numSteps if not self.animatingV: anim = QTimeLine(350, self) anim.setUpdateInterval(10) anim.valueChanged.connect(self.translateVTime) anim.finished.connect(self.translateVAnimFinished) anim.start()
class AnimationView(QWidget): """docstring for AnimationView""" frameIndex = 0 frameCount = 0 def __init__(self, bmpFrames): super(AnimationView, self).__init__() self.setFixedSize(frameWidth,frameHeight) self.bmpSize =64 if bmpFrames : self.bmpFrames = bmpFrames self.frameCount = len(bmpFrames) self.bmpSize = bmpFrames[0].width() else : self.initDefaultFrames() def initDefaultFrames(self): self.bmpFrames = [] defaultImage = QImage("..\\resource\\default.bmp") imageWidth = defaultImage.width() imageHeight = defaultImage.height() #判断各幀图片是否是横向排列 isHorizontal = min(imageWidth,imageHeight) == imageHeight #计算幀数 self.frameCount = imageWidth//frameWidth if isHorizontal else imageHeight//frameHeight for i in range(0,self.frameCount): pixmap = QPixmap(defaultImage.copy(i*frameWidth if isHorizontal else 0, 0 if isHorizontal else i*frameHeight,frameWidth,frameHeight)) eliminateBackgroundColor(pixmap) self.bmpFrames.append(pixmap) def createAnimation(self): self.timeLine = QTimeLine(10*1000) self.timeLine.setFrameRange(0,60//(4/self.frameCount)) self.timeLine.frameChanged.connect(self.refreshFrameIndex) self.timeLine.setLoopCount(0) self.timeLine.setCurveShape(3) self.timeLine.start() def refreshFrameIndex(self,currFrame): self.update() self.frameIndex = (self.frameIndex+1) % self.frameCount def paintEvent(self,event): painter = QPainter(self) painter.drawPixmap((frameWidth-self.bmpSize)//2,(frameHeight-self.bmpSize)//2,self.bmpFrames[self.frameIndex])
class MyView(QGraphicsView): def __init__(self): super().__init__() self.initView() self.setupScene() self.setupAnimation() self.setGeometry(300, 150, 250, 250) def initView(self): self.setWindowTitle("Progress meter") self.setRenderHint(QPainter.Antialiasing) policy = Qt.ScrollBarAlwaysOff self.setVerticalScrollBarPolicy(policy) self.setHorizontalScrollBarPolicy(policy) self.setBackgroundBrush(self.palette().window()) self.pm = ProgressMeter(self) self.pm.setPos(55, 55) def setupScene(self): self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, 250, 250) self.scene.addItem(self.pm) self.setScene(self.scene) def setupAnimation(self): self.timer = QTimeLine() self.timer.setLoopCount(0) self.timer.setFrameRange(0, 100) self.timer.frameChanged[int].connect(self.doStep) self.timer.start() def doStep(self, i): if not self.pm.increment(): self.timer.stop() self.pm.update()
def __init__(self, size, color): super().__init__() self._loading_angle = 0 self.width = 0 self.color = color self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground) self.setStyleSheet("background:transparent;") self.resize(size, size) self.center() self.initUI() timeline = QTimeLine(3000, self) timeline.setFrameRange(360, 0) timeline.frameChanged.connect(self.setLoadingAngle) timeline.start()
def __init__(self, size, color, side): super().__init__() self._next_step = 0 self.width = 0 self.color = color self.side = side self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground) self.setStyleSheet("background:transparent;") self.resize(size, size) self.center() self.initUI() timeline = QTimeLine(3000, self) timeline.setFrameRange(size, 0) timeline.frameChanged.connect(self.setNextStep) timeline.start()
def wheelEvent(self, event: QWheelEvent) -> None: if event.modifiers() & Qt.ControlModifier: num_degrees = event.angleDelta().y() / 8.0 num_steps = num_degrees / 15.0 self.num_scheduled_steps += num_steps if self.num_scheduled_steps * num_steps < 0: self.num_scheduled_steps = num_steps animation = QTimeLine(duration=350, parent=self) animation.setUpdateInterval(20) value_changed_sig: pyqtBoundSignal = animation.valueChanged value_changed_sig.connect(self.scaling_step) finished_sig: pyqtBoundSignal = animation.finished finished_sig.connect(self.animation_finished) animation.start() else: super().wheelEvent(event)
class FaderWidget(QWidget): def __init__(self, old_widget, new_widget): QWidget.__init__(self, new_widget) self.old_pixmap = QPixmap(new_widget.size()) old_widget.render(self.old_pixmap) self.pixmap_opacity = None self.timeline = QTimeLine(333, self) self.timeline.valueChanged.connect(self.animate) self.timeline.finished.connect(self.close) self.resize(new_widget.size()) self.show() def start(self, old_widget, new_widget): self.pixmap_opacity = 1.0 self.old_pixmap = QPixmap(new_widget.size()) old_widget.render(self.old_pixmap) self.timeline.start() self.resize(new_widget.size()) self.show() def animate(self, value): self.pixmap_opacity = 1.0 - value self.repaint() def paintEvent(self, event): if self.pixmap_opacity: QWidget.paintEvent(self, event) painter = QPainter(self) painter.setOpacity(self.pixmap_opacity) painter.drawPixmap(0, 0, self.old_pixmap)
class E5AnimatedWidget(QWidget): """ Class implementing an animated widget. """ DirectionDown = 0 DirectionUp = 1 def __init__(self, direction=DirectionDown, duration=300, parent=None): """ Constructor @param direction direction of the animation @type int (one of DirectionDown or DirectionUp) @param duration duration of the animation @type int @param parent reference to the parent widget @type QWidget """ super(E5AnimatedWidget, self).__init__(parent) self.__direction = direction self.__stepHeight = 0.0 self.__stepY = 0.0 self.__startY = 0 self.__widget = QWidget(self) self.__timeline = QTimeLine(duration) self.__timeline.setFrameRange(0, 100) self.__timeline.frameChanged.connect(self.__animateFrame) self.setMaximumHeight(0) def widget(self): """ Public method to get a reference to the animated widget. @return reference to the animated widget @rtype QWidget """ return self.__widget @pyqtSlot() def startAnimation(self): """ Public slot to start the animation. """ if self.__timeline.state() == QTimeLine.Running: return shown = 0 hidden = 0 if self.__direction == self.DirectionDown: shown = 0 hidden = -self.__widget.height() self.__widget.move(QPoint(self.__widget.pos().x(), hidden)) self.__stepY = (hidden - shown) / 100.0 self.__startY = hidden self.__stepHeight = self.__widget.height() / 100.0 self.__timeline.setDirection(QTimeLine.Forward) self.__timeline.start() @pyqtSlot(int) def __animateFrame(self, frame): """ Private slot to animate the next frame. @param frame frame number @type int """ self.setFixedHeight(frame * self.__stepHeight) self.__widget.move(self.pos().x(), self.__startY - frame * self.__stepY) @pyqtSlot() def hide(self): """ Public slot to hide the animated widget. """ if self.__timeline.state() == QTimeLine.Running: return self.__timeline.setDirection(QTimeLine.Backward) self.__timeline.finished.connect(self.close) self.__timeline.start() p = self.parentWidget() if p is not None: p.setFocus() def resizeEvent(self, evt): """ Protected method to handle a resize event. @param evt reference to the event object @type QResizeEvent """ if evt.size().width() != self.__widget.width(): self.__widget.resize(evt.size().width(), self.__widget.height()) super(E5AnimatedWidget, self).resizeEvent(evt)
class TSScene(QGraphicsScene): starttimechanged = pyqtSignal(str) endtimechanged = pyqtSignal(str) def __init__(self, parent, width=14, height=12, numofchannel=6): super(TSScene, self).__init__(parent) # set waveform windows figure = Figure() figure.set_size_inches(width, height) self.graphwidth = figure.dpi * width self.canvas = FigureCanvas(figure) self.addWidget(self.canvas) self.canvas.mpl_connect('button_press_event',self.button_press_event) self.canvas.mpl_connect('button_release_event', self.button_release_event) self.canvas.mpl_connect('motion_notify_event', self.motion_notify_event) self.canvas.mpl_connect('scroll_event', self.scroll_event) self.axesavailability = [True for i in range(numofchannel)] self.axes = [] for i in range(numofchannel): self.axes.append(figure.add_subplot(str(numofchannel)+'1'+str(i+1))) # set backend data model self.data = TSData() self.visibleWave = {} self.starttime = None self.endtime = None # prepare for user input self.downxcoord = None self.wheelactive = False self.rect = None self.installEventFilter(self) self.showgap = False self.downbutton = None self.currentxdata = None self.count = 0 self.state = 'ready' self.timeline = QTimeLine(1) self.timeline.setCurrentTime(0) self.timeline.setUpdateInterval(1) self.timeline.finished.connect(self.timeshift) self.timeline.finished.connect(self.animfinished) def animfinished(self): self.state = 'ready' self.timeline.setCurrentTime(0) def togglegap(self): self.showgap = ~self.showgap tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave,tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][1]) def applytime(self, start: str, end: str): if self.data is None: return for wave in self.visibleWave: if start<self.visibleWave[wave][3]: start = self.visibleWave[wave][3] if end>self.visibleWave[wave][4]: end = self.visibleWave[wave][4] self.starttime = UTCDateTime(start) self.endtime = UTCDateTime(end) print((self.starttime, self.endtime, '-----------------')) tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][2]) def loadfile(self, filename: str): self.data.loadFile(filename) def getlist(self): return self.data.getlist() def getsegments(self, item: object): waves = self.data.getsegments(item.text(0)) wavelist = QListWidget() for w in waves: wavelist.addItem(w) # print(w) wavelist.itemDoubleClicked.connect(self.segmentselected) wavelistwindowlayout = QVBoxLayout() wavelistwindowlayout.addWidget(wavelist) self.wavelistwindow = QDialog(self.parent()) self.wavelistwindow.setWindowTitle('segments') self.wavelistwindow.setLayout(wavelistwindowlayout) self.wavelistwindow.resize(800,600) self.wavelistwindow.show() self.segmentsource = item.text(0) self.currentitem = item def segmentselected(self, segment: str): matches = re.match(r'[^ ]+ \| ([^ ]+) - ([^ ]+) \| .*', segment.text(), flags=0) start = UTCDateTime(matches.group(1)) end = UTCDateTime(matches.group(2)) print(start) print(end) if self.segmentsource in self.visibleWave: self.applytime(start, end) else: self.starttime = start self.endtime = end print((self.segmentsource)) self.togglewave(self.segmentsource) self.currentitem.setSelected(True) def refreshwave(self, wave: str, colorcode:int=0): if wave in self.visibleWave: axes, lines, _, _, _, _ = self.visibleWave[wave] self.removewave(axes, lines) self.visibleWave.pop(wave, None) channelid = self.axes.index(axes) self.axesavailability[channelid] = True waveform, wavename, starttime, endtime, gaps = self.data.getwaveform(wave, self.starttime, self.endtime) axes, lines = self.displaywave(wavename, waveform, gaps) if axes is not None: self.visibleWave[wave] = (axes, lines, colorcode, starttime, endtime, gaps) def hidewave(self, wave: str, colorcode:int=0): if wave in self.visibleWave: axes, lines, _, _, _, _ = self.visibleWave[wave] self.removewave(axes, lines) self.visibleWave.pop(wave, None) channelid = self.axes.index(axes) self.axesavailability[channelid] = True if len(self.visibleWave)==0: self.starttime = None self.endtime = None return True def showwave(self, wave: str, starttime=None, endtime=None): if starttime is None or endtime is None: if wave in self.visibleWave: pass else: self.togglewave(wave) else: self.starttime = starttime self.endtime = endtime tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) if wave not in self.visibleWave: self.togglewave(wave) def togglewave(self, wave: str, colorcode:int=0): if wave in self.visibleWave: axes, lines, _, _, _, _ = self.visibleWave[wave] self.removewave(axes, lines) self.visibleWave.pop(wave, None) channelid = self.axes.index(axes) self.axesavailability[channelid] = True if len(self.visibleWave)==0: self.starttime = None self.endtime = None else: # print(wave) waveform, wavename, starttime, endtime, gaps = self.data.getwaveform(wave, self.starttime, self.endtime) print((starttime, endtime)) axes, lines = self.displaywave(wavename, waveform, gaps) if axes is not None: self.visibleWave[wave] = (axes, lines, colorcode, starttime, endtime, gaps) #print("togglewave:", starttime, endtime) def displaywave(self, wavename: str, waveform: np.array, gaps, colorcode: int=None): if True not in self.axesavailability: return None, None else: location = self.axesavailability.index(True) axes = self.axes[location] self.axesavailability[location] = False if wavename is not None and waveform is not None: if colorcode is None: colorcode = 'C'+str(location%10) times = waveform[0,:] span = round(len(times)/4) if span<1: span = 1 axes.set_xticks(times[::span]) axes.set_xticklabels([UTCDateTime(t).strftime("%Y-%m-%d %H:%M:%S") for t in times[::span]]) lines = axes.plot(times, waveform[1,:],linestyle="-", label=wavename, color=colorcode) if self.showgap: for g in gaps: if g[4].timestamp>=times[0] and g[5].timestamp<times[-1]: axes.axvspan(g[4],g[5],facecolor='0.2',alpha=0.5) axes.legend() self.canvas.draw() if self.endtime is not None and self.starttime is not None and len(times)>0: timewindow = self.endtime-self.starttime if abs(times[0]-times[-1]-timewindow)/timewindow<0.1: self.starttime = UTCDateTime(times[0]) self.endtime = self.starttime + timewindow elif len(times)>0: self.starttime = UTCDateTime(times[0]) self.endtime = UTCDateTime(times[-1]) self.starttimechanged.emit(self.starttime.strftime("%Y-%m-%d %H:%M:%S")) self.endtimechanged.emit(self.endtime.strftime("%Y-%m-%d %H:%M:%S")) return axes, lines else: lines = None axes.legend([wavename]) return axes, lines def removewave(self, axes: Axes, lines: Line2D): if lines is not None: lines.pop(0).remove() axes.relim() axes.autoscale_view(True, True, True) axes.clear() self.canvas.draw() def timeshift(self): if self.downxcoord is None or self.currentxdata is None: return shift = self.downxcoord-self.currentxdata if shift == 0: print('skipped') return if self.starttime is None: return starttime = self.starttime + shift endtime = self.endtime + shift for wave in self.visibleWave: if starttime<self.visibleWave[wave][3]: starttime = self.visibleWave[wave][3] if endtime>self.visibleWave[wave][4]: endtime = self.visibleWave[wave][4] if starttime!=self.starttime and endtime!=self.endtime: self.starttime = starttime self.endtime = endtime tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][2]) return def timescale(self, delta: float): if self.starttime is None: return shift = (self.endtime - self.starttime) * -delta*0.1 starttime = self.starttime + shift endtime = self.endtime - shift for wave in self.visibleWave: if starttime<self.visibleWave[wave][3]: starttime = self.starttime if endtime>self.visibleWave[wave][4]: endtime = self.endtime if endtime-starttime<0.1: pass elif starttime==self.starttime and endtime==self.endtime: pass else: self.starttime = starttime self.endtime = endtime tmplist = self.visibleWave.copy() for wave in tmplist: self.refreshwave(wave, tmplist[wave][1]) # self.togglewave(wave) # self.togglewave(wave, tmplist[wave][1]) def button_press_event(self, event): if self.starttime is None: return self.downxcoord = event.xdata self.downx = event.x self.downbutton = event.button self.count = 0 def motion_notify_event(self, event): # print(event.button, self.starttime, self.downbutton, self.downxcoord, event.xdata) self.count += 1 self.currentxdata = event.xdata #print(self.currentxdata,"+" * 10) if self.starttime is None: return elif self.downxcoord is not None: if self.downbutton == 1 and self.timeline.currentTime()==0: self.state = 'busy' self.timeline.start() elif self.downbutton == 1: pass elif self.downbutton == 3: if self.rect is not None: self.removeItem(self.rect) if self.downx < event.x: self.rect = self.addRect(self.downx, 0, event.x - self.downx, self.height(), pen=QPen(Qt.red)) else: self.rect = self.addRect(event.x, 0, self.downx - event.x, self.height(), pen=QPen(Qt.red)) def button_release_event(self, event): if self.starttime is None: return if event.button == 3: left = 225 right = 1215 if self.downxcoord < event.xdata: start = self.downxcoord end = event.xdata else: start = event.xdata end = self.downxcoord start = UTCDateTime(start) end = UTCDateTime(end) print((start,end,'================')) self.applytime(start, end) # self.downx = None self.downbutton = None self.removeItem(self.rect) self.rect = None self.downxcoord = None self.currentxdata = None #print(self.count,'count!!!!!!!!') self.count=0 def scroll_event(self, event): delta = -event.step if self.wheelactive==False and event.xdata>= self.starttime and event.xdata<= self.endtime: self.wheelactive = True self.timescale(delta) self.wheelactive = False def exportmetadata(self, filename: tuple): wavelist = self.getlist() outfile = open(filename[0]+'.txt','w') for network in wavelist: for station in wavelist[network]: for wave in wavelist[network][station]: for w in wavelist[network][station][wave]: outfile.write("%s\n\n" % w) outfile.close() def exportwaveform(self, filename: tuple): traces = [] for wave in self.visibleWave: fill_value = 'last' waveform, wavename, starttime, endtime, gaps = self.data.readdisc(wave, self.starttime, self.endtime, resample=False, fill_value=fill_value) traces.append(waveform) stream = Stream(traces=traces) if 'MSEED' in filename[1]: stream.write(filename[0] + ".mseed", format='MSEED') elif 'txt' in filename[1]: stream.write(filename[0] + ".txt", format='TSPAIR') def gettimeboundary(self): return self.starttime, self.endtime return False
class CustomProxy(QGraphicsProxyWidget): def __init__(self, parent=None, wFlags=0): super(CustomProxy, self).__init__(parent, wFlags) self.popupShown = False self.currentPopup = None self.timeLine = QTimeLine(250, self) self.timeLine.valueChanged.connect(self.updateStep) self.timeLine.stateChanged.connect(self.stateChanged) def boundingRect(self): return QGraphicsProxyWidget.boundingRect(self).adjusted(0, 0, 10, 10) def paintWindowFrame(self, painter, option, widget): color = QColor(0, 0, 0, 64) r = self.windowFrameRect() right = QRectF(r.right(), r.top()+10, 10, r.height()-10) bottom = QRectF(r.left()+10, r.bottom(), r.width(), 10) intersectsRight = right.intersects(option.exposedRect) intersectsBottom = bottom.intersects(option.exposedRect) if intersectsRight and intersectsBottom: path = QPainterPath() path.addRect(right) path.addRect(bottom) painter.setPen(Qt.NoPen) painter.setBrush(color) painter.drawPath(path) elif intersectsBottom: painter.fillRect(bottom, color) elif intersectsRight: painter.fillRect(right, color) super(CustomProxy, self).paintWindowFrame(painter, option, widget) def hoverEnterEvent(self, event): super(CustomProxy, self).hoverEnterEvent(event) self.scene().setActiveWindow(self) if self.timeLine.currentValue != 1: self.zoomIn() def hoverLeaveEvent(self, event): super(CustomProxy, self).hoverLeaveEvent(event) if not self.popupShown and (self.timeLine.direction() != QTimeLine.Backward or self.timeLine.currentValue() != 0): self.zoomOut() def sceneEventFilter(self, watched, event): if watched.isWindow() and (event.type() == QEvent.UngrabMouse or event.type() == QEvent.GrabMouse): self.popupShown = watched.isVisible() if not self.popupShown and not self.isUnderMouse(): self.zoomOut() return super(CustomProxy, self).sceneEventFilter(watched, event) def itemChange(self, change, value): if change == self.ItemChildAddedChange or change == self.ItemChildRemovedChange : if change == self.ItemChildAddedChange: self.currentPopup = value self.currentPopup.setCacheMode(self.ItemCoordinateCache) if self.scene() is not None: self.currentPopup.installSceneEventFilter(self) elif self.scene() is not None: self.currentPopup.removeSceneEventFilter(self) self.currentPopup = None elif self.currentPopup is not None and change == self.ItemSceneHasChanged: self.currentPopup.installSceneEventFilter(self) return super(CustomProxy, self).itemChange(change, value) def updateStep(self, step): r = self.boundingRect() self.setTransform(QTransform() \ .translate(r.width() / 2, r.height() / 2)\ .rotate(step * 30, Qt.XAxis)\ .rotate(step * 10, Qt.YAxis)\ .rotate(step * 5, Qt.ZAxis)\ .scale(1 + 1.5 * step, 1 + 1.5 * step)\ .translate(-r.width() / 2, -r.height() / 2)) def stateChanged(self, state): if state == QTimeLine.Running: if self.timeLine.direction() == QTimeLine.Forward: self.setCacheMode(self.NoCache) elif state == QTimeLine.NotRunning: if self.timeLine.direction() == QTimeLine.Backward: self.setCacheMode(self.DeviceCoordinateCache) def zoomIn(self): if self.timeLine.direction() != QTimeLine.Forward: self.timeLine.setDirection(QTimeLine.Forward) if self.timeLine.state() == QTimeLine.NotRunning: self.timeLine.start() def zoomOut(self): if self.timeLine.direction() != QTimeLine.Backward: self.timeLine.setDirection(QTimeLine.Backward) if self.timeLine.state() == QTimeLine.NotRunning: self.timeLine.start()
class SideSlideDecorator(QWidget): m_slidePos: QPoint m_slideWidgetPixmap: QPixmap m_timeline: QTimeLine m_backgroundPixmap: QPixmap m_decorationColor: QColor clicked = pyqtSignal() def __init__(self, *args, **kwargs): super(SideSlideDecorator, self).__init__(*args, **kwargs) self.resize(self.maximumSize()) self.m_backgroundPixmap = QPixmap() self.m_slidePos = QPoint() self.m_timeline = QTimeLine() self.m_timeline.setDuration(260) self.m_timeline.setUpdateInterval(40) self.m_timeline.setEasingCurve(QEasingCurve.OutQuad) self.m_timeline.setStartFrame(0) self.m_timeline.setEndFrame(10000) self.m_decorationColor = QColor(0, 0, 0, 0) def frameChanged(_value): self.m_decorationColor = QColor(0, 0, 0, _value / 100) self.update() self.m_timeline.frameChanged.connect(frameChanged) def grabSlideWidget(self, _slideWidget): self.m_slideWidgetPixmap = _slideWidget.grab() def grabParent(self): # self.m_backgroundPixmap = self.parentWidget().grab() pass def decorate(self, _dark): if self.m_timeline.state() == QTimeLine.Running: self.m_timeline.stop() self.m_timeline.setDirection( QTimeLine.Forward if _dark else QTimeLine.Backward) self.m_timeline.start() def slidePos(self): return self.m_slidePos def setSlidePos(self, _pos): if self.m_slidePos != _pos: self.m_slidePos = _pos self.update() def paintEvent(self, _event): painter = QPainter(self) painter.drawPixmap(0, 0, self.m_backgroundPixmap) painter.fillRect(self.rect(), self.m_decorationColor) painter.drawPixmap(self.m_slidePos, self.m_slideWidgetPixmap) super(SideSlideDecorator, self).paintEvent(_event) def mousePressEvent(self, _event): self.clicked.emit() super(SideSlideDecorator, self).mousePressEvent(_event) _slidePos = pyqtProperty(QPoint, fget=slidePos, fset=setSlidePos)
class E5AnimatedWidget(QWidget): """ Class implementing an animated widget. """ DirectionDown = 0 DirectionUp = 1 def __init__(self, direction=DirectionDown, duration=300, parent=None): """ Constructor @param direction direction of the animation @type int (one of DirectionDown or DirectionUp) @param duration duration of the animation @type int @param parent reference to the parent widget @type QWidget """ super(E5AnimatedWidget, self).__init__(parent) self.__direction = direction self.__stepHeight = 0.0 self.__stepY = 0.0 self.__startY = 0 self.__widget = QWidget(self) self.__timeline = QTimeLine(duration) self.__timeline.setFrameRange(0, 100) self.__timeline.frameChanged.connect(self.__animateFrame) self.setMaximumHeight(0) def widget(self): """ Public method to get a reference to the animated widget. @return reference to the animated widget @rtype QWidget """ return self.__widget @pyqtSlot() def startAnimation(self): """ Public slot to start the animation. """ if self.__timeline.state() == QTimeLine.Running: return shown = 0 hidden = 0 if self.__direction == self.DirectionDown: shown = 0 hidden = -self.__widget.height() self.__widget.move(QPoint(self.__widget.pos().x(), hidden)) self.__stepY = (hidden - shown) / 100.0 self.__startY = hidden self.__stepHeight = self.__widget.height() / 100.0 self.__timeline.setDirection(QTimeLine.Forward) self.__timeline.start() @pyqtSlot(int) def __animateFrame(self, frame): """ Private slot to animate the next frame. @param frame frame number @type int """ self.setFixedHeight(frame * self.__stepHeight) self.__widget.move(self.pos().x(), self.__startY - frame * self.__stepY) @pyqtSlot() def hide(self): """ Public slot to hide the animated widget. """ if self.__timeline.state() == QTimeLine.Running: return self.__timeline.setDirection(QTimeLine.Backward) self.__timeline.finished.connect(self.close) self.__timeline.start() p = self.parentWidget() if p is not None: p.setFocus() def resizeEvent(self, evt): """ Protected method to handle a resize event. @param evt reference to the event object @type QResizeEvent """ if evt.size().width() != self.__widget.width(): self.__widget.resize(evt.size().width(), self.__widget.height()) super(E5AnimatedWidget, self).resizeEvent(evt)
def closeItem(self, item): animation = QTimeLine(ANIMATE_TIME, self) animation.setFrameRange(146, CLOSED_SIZE) animation.frameChanged.connect( lambda x: item.setSizeHint(QSize(32, x))) animation.start()
class ExplorerNode(BaseNode): def __init__(self, nx_node, center_pos, nx_pos, steps, steps_max): """ Create node in the graph scene :param tuple nx_node: Node info :param center_pos: The position of the center node :param nx_pos: Position of the nodes in the graph :param int steps: The steps from the center identity :param int steps_max: The steps max of the graph """ super().__init__(nx_node, nx_pos) self.steps = steps self.steps_max = steps_max self.highlighted = False # text inside ellipse self.text_item = QGraphicsSimpleTextItem(self) self.text_item.setText(self.text) # center ellipse around text self.setRect( 0, 0, self.text_item.boundingRect().width() * 2, self.text_item.boundingRect().height() * 2 ) # set anchor to the center self.setTransform( QTransform().translate(-self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) # center text in ellipse self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0) # cursor change on hover self.setAcceptHoverEvents(True) self.setZValue(1) # animation and moves self.timeline = None self.loading_timer = QTimer() self.loading_timer.timeout.connect(self.next_tick) self.loading_counter = 0 self._refresh_colors() self.setPos(center_pos) self.move_to(nx_pos) def _refresh_colors(self): """ Refresh elements in the node """ # color around ellipse outline_color = QColor('black') outline_style = Qt.SolidLine outline_width = 1 if self.status_wallet: outline_color = QColor('grey') outline_width = 2 if not self.status_member: outline_color = QColor('red') outline_style = Qt.SolidLine self.setPen(QPen(outline_color, outline_width, outline_style)) if self.highlighted: text_color = QColor('grey') else: text_color = QColor('black') if self.status_wallet == NodeStatus.HIGHLIGHTED: text_color = QColor('grey') self.text_item.setBrush(QBrush(text_color)) # create gradient inside the ellipse gradient = QRadialGradient(QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width()) color = QColor() color.setHsv(120 - 60 / self.steps_max * self.steps, 180 + 50 / self.steps_max * self.steps, 60 + 170 / self.steps_max * self.steps) if self.highlighted: color = color.darker(200) color = color.lighter(math.fabs(math.sin(self.loading_counter / 100 * math.pi) * 100) + 100) gradient.setColorAt(0, color) gradient.setColorAt(1, color.darker(150)) self.setBrush(QBrush(gradient)) def move_to(self, nx_pos): """ Move to corresponding position :param nx_pos: :return: """ origin_x = self.x() origin_y = self.y() final_x = nx_pos[self.id][0] final_y = nx_pos[self.id][1] def frame_move(frame): value = self.timeline.valueForTime(self.timeline.currentTime()) x = origin_x + (final_x - origin_x) * value y = origin_y + (final_y - origin_y) * value self.setPos(x, y) self.scene().node_moved.emit(self.id, x, y) def timeline_ends(): self.setPos(final_x, final_y) self.timeline = None # Remember to hold the references to QTimeLine and QGraphicsItemAnimation instances. # They are not kept anywhere, even if you invoke QTimeLine.start(). self.timeline = QTimeLine(1000) self.timeline.setFrameRange(0, 100) self.timeline.frameChanged.connect(frame_move) self.timeline.finished.connect(timeline_ends) self.timeline.start() def highlight(self): """ Highlight the edge in the scene """ self.highlighted = True self._refresh_colors() self.update(self.boundingRect()) def neutralize(self): """ Neutralize the edge in the scene """ self.highlighted = False self._refresh_colors() self.update(self.boundingRect()) def start_loading_animation(self): """ Neutralize the edge in the scene """ if not self.loading_timer.isActive(): self.loading_timer.start(10) def stop_loading_animation(self): """ Neutralize the edge in the scene """ self.loading_timer.stop() self.loading_counter = 100 self._refresh_colors() self.update(self.boundingRect()) def next_tick(self): """ Next tick :return: """ self.loading_counter += 1 self.loading_counter %= 100 self._refresh_colors() self.update(self.boundingRect())
class Widget(Ui_CollectionsWidget, QWidget, ScreenWidget): name = "collectionSelection" def __init__(self): QWidget.__init__(self) self.setupUi(self) self.collections = None self.current_item = None self.last_item = None self.collectionList.itemClicked.connect(self.openItem) self.collectionList.currentItemChanged.connect(self.itemChanged) def fillCollections(self): self.collectionList.clear() selected = None for index, collection in enumerate(self.collections): self.addItem(collection) if ctx.installData.autoCollection == collection: selected = index if not selected: selected = 0 self.current_item = self.collectionList.item(selected) self.last_item = self.current_item self.collectionList.setCurrentRow(selected) def shown(self): self.collections = ctx.collections self.fillCollections() ctx.mainScreen.disableNext() if self.current_item: self.openItem(self.current_item) else: self.openItem(self.collectionList.item(0)) self.check() def execute(self): ctx.installData.autoCollection = self.collectionList.itemWidget(self.current_item).collection return True def check(self): if self.current_item: ctx.mainScreen.enableNext() else: ctx.mainScreen.disableNext() def itemChanged(self, current, previous): self.current_item = current self.check() def addItem(self, collection): item = QListWidgetItem(self.collectionList) item.setSizeHint(QSize(36, CLOSED_SIZE)) self.collectionList.addItem(item) self.collectionList.setItemWidget(item, CollectionItem(self, collection, item)) def openItem(self, item): if item == self.last_item: return if self.last_item: self.closeItem(self.last_item) self.animation = QTimeLine(ANIMATE_TIME, self) self.animation.setFrameRange(36, EXPANDED_SIZE) self.animation.frameChanged.connect(lambda x: item.setSizeHint(QSize(32, x))) self.animation.start() self.last_item = item self.animation.finished.connect(lambda: self.collectionList.setCurrentItem(item)) def closeItem(self, item): animation = QTimeLine(ANIMATE_TIME, self) animation.setFrameRange(146, CLOSED_SIZE) animation.frameChanged.connect(lambda x: item.setSizeHint(QSize(32, x))) animation.start()
class startAiDialog(QDialog): def __init__(self, parent = None): super().__init__() self.timer = QTimeLine(2000, self) #self.address = parent.address #self.port = parent.port self.address = "127.0.0.1" self.port = "5577" h1 = QHBoxLayout(None) self.yourLabel = QLabel(_("Your color:"), self) self.blackStone = QRadioButton(_("Black"), self) self.blackStone.setChecked(True) self.whiteStone = QRadioButton(_("White"), self) h1.addWidget(self.yourLabel) h1.addWidget(self.blackStone) h1.addWidget(self.whiteStone) h2 = QHBoxLayout(None) self.levelLabel = QLabel(_("Gnugo level:"), self) self.gnuLevel = QSpinBox(self) self.gnuLevel.setRange(1, 10) self.gnuLevel.setValue(8) h2.addWidget(self.levelLabel) h2.addWidget(self.gnuLevel) h3 = QHBoxLayout(None) self.komiLabel = QLabel(_("Set komi:"), self) self.komi = QSpinBox(self) self.komi.setEnabled(False) self.komi.setRange(0, 9) self.komi.setValue(0) h3.addWidget(self.komiLabel) h3.addWidget(self.komi) h4 = QHBoxLayout(None) self.startButton = QPushButton(_("Start Server"), self) buttonBox = QDialogButtonBox(self) self.okButton = QPushButton(_("OK")) self.okButton.setEnabled(False) self.cancelButton = QPushButton(_("Cancel")) buttonBox.addButton(self.okButton, QDialogButtonBox.AcceptRole) buttonBox.addButton(self.cancelButton, QDialogButtonBox.RejectRole) h4.addWidget(self.startButton) h4.addWidget(buttonBox) mainLayout = QVBoxLayout(None) mainLayout.addLayout(h1) mainLayout.addLayout(h2) mainLayout.addLayout(h3) mainLayout.addLayout(h4) self.setLayout(mainLayout) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) self.startButton.clicked.connect(self.startServer) self.timer.finished.connect(self.serverStarted) def serverStarted(self): self.goSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.goSocket.connect(("127.0.0.1", int(self.port))) self.startButton.setText(_("Server started")) self.okButton.setEnabled(True) def startServer(self): self.startButton.setEnabled(False) self.startButton.setText(_("Starting...")) if self.blackStone.isChecked(): cl = "black" else: cl = "white" args = "gnugo --mode gtp --boardsize 19 --color {0} --level {1} --gtp-listen {2}:{3}".format(cl, str(self.gnuLevel.value()), self.address, self.port) print(args) self.process = subprocess.Popen(args.split()) self.timer.start()
class QTreeWidget(CoreQTreeWidget): def __init__(self, tableWidget, icons, showHidden): super(QTreeWidget, self).__init__(tableWidget, icons, showHidden) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setAcceptDrops(True) self.dragModSoon = False # dragMod just starts after 0.1 sec self.started = 0 # to take the time of dragModSoon self.dragSource = None self.dragMod = False self.copyDrag = False self.lastp = QtCore.QPoint(0, 0) # Last position of the dragged item # USED FOR PREVIEW # # idx of a temporary moved/inserted item (not Voiditem) self.callback = None # Used for the drag and drop preview self.stillInItem = None self.voididxlist = [] # SIZES(some handeld automatically) # self.circleSize = 1.5/2. # Scaling factor for the nodes self.rw = 0 self.rh = 0 self.minr = 0 # ANIMATION HELP # self.lineList_old = [] self.lineList_new = [] self.nodeCopy = [] # dictionarys filled with information self.old_opacity = 1 self.timeline = None self.animationDuration = 200 self.needUpdate = False def getItemList(self): """Returns a list of the items (Depth-first search [preordering])""" itemlist = [] self.rekursivHelp(self.topLevelItem(0), itemlist) return itemlist def rekursivHelp(self, item, list): """Recursive help for the getItemList method""" list.append(item) for i in range(item.childCount()): self.rekursivHelp(item.child(i), list) def tableChanged(self): super(QTreeWidget, self).tableChanged() self.needUpdate = True def paintEvent(self, event): """Painting the view, if there is a root item""" if self.itemAt(0, 0) is None: return painter = QPainter(self.viewport()) self.makeImage(painter) # drawing the dragged item if (self.dragMod and self.dragSource == self.source and self.currentItem() is not None): pos = self.lastp - QtCore.QPoint(self.minr/4, self.minr/4) self.paintItem(self.currentItem(), pos, painter, self.xml) if self.timeline is None: # paintItem saves the drawn node. But the dragged Node is not # fixed thats why I remove it again. del self.nodeCopy[-1] painter.end() def makeImage(self, painter): """ This method draws the image to a given painter. The algorithm works like this: - Find out how the items have to be placed, relativly - Take the relativ height and width of the tree - Now, set the position with absolute values - Save the lines - Check if some transitions have to be made: - if there is no transition required at the moment - and the lines changed or needUpdate flag is set For the tranistion take a look at the methods 'animate' and 'animationEnd'. """ painter.setRenderHint(QPainter.TextAntialiasing, True) painter.setRenderHint(QPainter.Antialiasing, True) itemList = self.getItemList() wDSF = 1 # width Dependend Scaling Factor hDSF = 1 # height Dependend Scaling Factor width = self.width() height = self.height() # The depth of the Tree maxlevel = 4 # Max width in a Tree level maxlevelwidth = 1 # Setting up maxlevel & item.level values for item in itemList: item.pos = QtCore.QPoint(0, 0) if item.parent() is not None: if item.getType() not in ['PULSE']: item.level = item.parent().level+1 if item.level > maxlevel: maxlevel = item.level # List of the width in a tree level levelwidth = [0] * len(itemList) for item in itemList: if item.parent() is not None: # This way, we dont write a node over the child of another node for j in range(item.level, len(levelwidth)): if levelwidth[item.level] < levelwidth[j]: levelwidth[item.level] = levelwidth[j] # Setting up the Item position item.pos = QtCore.QPoint(levelwidth[item.level], item.level) # A child cant be on the left side of a parent node if item.pos.x() < item.parent().pos.x(): item.pos = QtCore.QPoint(item.parent().pos.x(), item.pos.y()) levelwidth[item.level] = item.pos.x() # PULSE nodes don't grow to the side if item.getType() not in ['PULSE']: levelwidth[item.level] += 1 # To handle multiply PULSE nodes, we take their parent node if item.getType() in ['ATOMICSEQUENCE']: if item.childCount() != 0: # Multiple PULSE nodes takes 1 width in a tree level levelwidth[item.level+1] += 1 # Multiple PULES nodes increasing the tree depth if (item.level + item.childCount()) > maxlevel: maxlevel = (item.level + item.childCount()) # Getting the maxlevelwidth maxlevelwidth = max(levelwidth) if maxlevelwidth == 0: maxlevelwidth = 1 self.rw = width/(maxlevelwidth) * wDSF self.rh = height/(maxlevel+1) * hDSF # +1 is needed, to make it fit self.minr = self.rw if self.rw < self.rh else self.rh # ------------------------------------------------------------------- # # Positioning # # ------------------------------------------------------------------- # for item in itemList: if item.getType() not in ['PULSE']: qpoint = QtCore.QPoint(self.minr/6 + 3, 3) item.pos = QtCore.QPoint(item.pos.x()*self.rw, item.pos.y()*self.rh) + qpoint if item.getType() in ['ATOMICSEQUENCE']: for i in range(item.childCount()): child = item.child(i) child.pos = QtCore.QPoint( item.pos.x(), item.pos.y() + (i+1)*self.minr*self.circleSize) # ------------------------------------------------------------------- # # Save Lines # # ------------------------------------------------------------------- # painter.linePainter(item) self.lineList_new = [[]] for item in itemList: # No lines between ATOMIC... and PULSE if item.getType() not in ['ATOMICSEQUENCE', 'COILARRAY']: for i in range(item.childCount()): if not item.child(i).visible: continue self.lineList_new += [[ item.pos + QtCore.QPoint(self.minr*self.circleSize/2, self.minr*self.circleSize/2), item.child(i).pos + QtCore.QPoint(self.minr*self.circleSize/2, self.minr*self.circleSize/2)]] # ------------------------------------------------------------------- # # possible Animation start # # ------------------------------------------------------------------- # if (self.timeline is None and (self.lineList_new[:] != self.lineList_old[:] or self.needUpdate)): self.needUpdate = False self.timeline = QTimeLine() self.timeline.valueChanged.connect(self.animate) self.timeline.finished.connect(self.animationEnd) self.timeline.setDuration(self.animationDuration) self.timeline.start() # ------------------------------------------------------------------- # # Drawing Lines # # ------------------------------------------------------------------- # painter.setOpacity(self.old_opacity) for line in self.lineList_old: if line != []: painter.drawLine(line[0], line[1]) if self.old_opacity != 1: # with Animation painter.setOpacity(1-self.old_opacity) for line in self.lineList_new: if line != []: painter.drawLine(line[0], line[1]) # ------------------------------------------------------------------- # # Drawing Nodes # # ------------------------------------------------------------------- # painter.setOpacity(1) if self.timeline is None: # without Animation if len(self.nodeCopy) == 0: tmp = copy.deepcopy(self.xml) for item in itemList: # drawing and saving new nodes if item is not None and item.visible: self.paintItem(item, item.pos, painter, tmp) else: for cp in self.nodeCopy: # using old nodes for drawing self.paintItem2(cp, painter) else: # with Animation painter.setOpacity(self.old_opacity) for cp in self.nodeCopy: self.paintItem2(cp, painter) painter.setOpacity(1-self.old_opacity) for item in itemList: if item is not None and item.visible: self.paintItem(item, item.pos, painter, self.xml) def animationEnd(self): """ AnimationEnd cleans up the animation. Called by QTimeLine. """ self.lineList_old = self.lineList_new self.lineList_new = None self.old_opacity = 1.0 self.nodeCopy = [] # removing old nodes self.timeline = None self.updateImage() def animate(self, value): """ Animate makes a little change for the tranistion. Called by QTimeLine. """ self.old_opacity = 1.0 - value self.updateImage() def calcVoidItems(self): """ This method creates the Voiditems for the preview. """ if not self.dragMod: return # ------------------------------------------------------------------- # # Calculating VoidItems indexes # # ------------------------------------------------------------------- # self.voididxlist = [] for item in self.getItemList(): if item.getType() not in ['PULSE']: idx = item.idx() + [item.childCount()] if self.checkVoidItem(idx): self.voididxlist += [idx] dragIndex = None if self.currentItem() is not None: # saving the current item idx dragIndex = self.currentItem().idx() # ------------------------------------------------------------------- # # Creation of Voiditems # # ------------------------------------------------------------------- # for voididx in self.voididxlist: if self.dragSource == self.source: # not using button drag if self.callback is not None: # item not moved/copyd self.setCurrentItem(self.getItem(self.callback)) # self.itemCopy.emit() self.itemMoved.emit(self.callback, voididx) else: # item moved/copyd if voididx is self.voididxlist[0]: dragIndex[-1] += 1 self.itemCopy.emit() self.itemMoved.emit(dragIndex, voididx) dragIndex[-1] -= 1 self.setCurrentItem(self.getItem(dragIndex)) else: self.setCurrentItem(self.getItem(self.voididxlist[0])) self.itemCopy.emit() self.itemMoved.emit(self.voididxlist[0], voididx) else: # using button drag if self.callback is None: # item not inserted if voididx is self.voididxlist[0]: self.insertItem(voididx) else: self.setCurrentItem(self.getItem(self.voididxlist[0])) self.itemCopy.emit() self.itemMoved.emit(self.voididxlist[0], voididx) else: # item already inserted self.setCurrentItem(self.getItem(self.callback)) self.itemCopy.emit() self.itemMoved.emit(self.callback, voididx) if dragIndex is not None: # setting the current item back self.setCurrentItem(self.getItem(dragIndex)) self.markVoidItems() # finishing void items def checkVoidItem(self, idx): """ Checks, if an idx can be taken for a new VoidItem. First some special cases are caught and then the standard checkDrop function is used. """ if self.callback is not None: if len(idx) == len(self.callback): numb = len(self.callback)-1 if (idx[0:numb] == self.callback[0:numb] and idx[numb] >= self.callback[numb]): return False else: if len(idx) >= len(self.callback): numb = len(self.callback) if idx[0:numb] == self.callback[0:numb]: return False return self.checkDrop(idx) def setBranchVoid(self, root, isVoid): """ This Method sets the isVoid flag of a hole branch to the given boolean value in 'isVoid'. """ change = [root] for node in change: node.isVoid = isVoid for i in range(node.childCount()): change += [node.child(i)] def checkDrop(self, dropidx): """ This Methods checks, if a (copy)move/insertion of an item is legal. """ dropIndex = dropidx[:] tmp = copy.deepcopy(self.xml) if self.dragSource == self.source: dragIndex = self.currentItem().idx() if self.copyDrag: tmp.copy(dragIndex) dragIndex[-1] += 1 else: if len(dropIndex) >= len(dragIndex): numb = len(dragIndex) if dragIndex[0:numb] <= dropIndex[0:numb]: if dropIndex[0:numb] == dragIndex[0:numb]: return False dropIndex[numb-1] -= 1 try: tmp._move(dragIndex, dropIndex) status, msg = tmp.checkCommand(dropIndex) if msg is not None: return False # exception caused, when tmp.checkCommand wont return 2 values except: return False else: tag = self.dragSource.text() idx = dropIndex[0:-1] if len(idx) == 0: return False tmp = copy.deepcopy(self.xml) msg = tmp._insert(idx, tag) if msg is not None: return False return True def deleteVoidItems(self): """ Removs all Items, which are VoidItems. """ savedidx = None if self.currentItem() is not None: savedidx = self.currentItem().idx() for idx in self.voididxlist: self.setCurrentItem(self.getItem(idx)) self.treeItemDelete() if savedidx is not None: self.setCurrentItem(self.getItem(savedidx)) self.voididxlist = [] def paintItem(self, item, pos, painter, xml): """ This method is a preparation for the item painting in 'paintItem2'. The infomation, which is required to draw an item, is saved if needed (for the animation). """ informlist = { "pos": pos, "text": item.getName(), "backgroundColor": item.background(0).color(), "isVoid": item.isVoid, "type": item.getType(), "iscurrent": item is self.currentItem(), "idx": item.idx(), "xml": xml, "textcolor": item.foreground(0).color(), "font": item.font(0), "minr": self.minr} if self.timeline is None: self.nodeCopy.append(informlist) self.paintItem2(informlist, painter) def paintItem2(self, itemInfos, painter): """ In this method, the items are painted. The attribute 'iteminfos' should contain a dictionary with the needed informtion. """ minSizeForPulsPic = 25 sIC = QtGui.QColor(0, 150, 200) # selected item color sICBW = 2 # selected item color border width minr = itemInfos["minr"] # ------------------------------------------------------------------- # # Draw Form # # ------------------------------------------------------------------- # # drawshape = needed shape # rect = Postion + size of the shape if itemInfos["type"] in ['PULSE', 'COIL']: rect = QtCore.QRect(itemInfos["pos"].x()-minr/6, itemInfos["pos"].y(), minr*self.circleSize + self.minr/3, minr*self.circleSize) drawshape = painter.drawRect else: rect = QtCore.QRect(itemInfos["pos"].x(), itemInfos["pos"].y(), minr*self.circleSize, minr*self.circleSize) drawshape = painter.drawEllipse # shape color colorB = itemInfos["backgroundColor"] if self.callback is not None: if ((self.dragSource == self.source and itemInfos["idx"] == self.callback and not itemInfos["iscurrent"]) or (self.dragSource != self.source and itemInfos["iscurrent"])): colorB = QtGui.QColor(220, 220, 220) # alphaf(1) to overdraw the lines, which connects the nodes # TODO: colorB.setAlphaF(1) if itemInfos["iscurrent"]: # draw a blue border for the currentItem painter.setBrush(sIC) drawshape(QtCore.QRect(rect.x() - sICBW, rect.y() - sICBW, rect.width() + 2*sICBW, rect.height() + 2*sICBW)) if itemInfos["isVoid"]: # VoidItems are drawn with orange colorB = QtGui.QColor('orange') painter.formPainter(rect, None, colorB, itemtype=itemInfos["type"]) else: painter.formPainter(rect, None, colorB, itemtype=itemInfos["type"]) drawshape(rect) # Drawing the shape # ------------------------------------------------------------------- # # Draw Icon # # ------------------------------------------------------------------- # painter.iconPainter() icon = None if minr >= minSizeForPulsPic: xitem = itemInfos["xml"].read(itemInfos["idx"]) if xitem.get('type') in ['PULSE', 'COIL']: icon = self.icons[xitem.tag] painter.drawPixmap( itemInfos["pos"] + QtCore.QPoint(0, minr * 1/7), icon, QtCore.QRect(0, 0, icon.width(), icon.height())) # ------------------------------------------------------------------- # # Draw Text # # ------------------------------------------------------------------- # painter.textPainter(textColor=itemInfos["textcolor"], font=itemInfos["font"]) if icon is not None: painter.drawText(itemInfos["pos"] + QtCore.QPoint( icon.width(), icon.height() + minr*1/7), itemInfos["text"]) else: painter.drawText(QtCore.QRectF(rect), QtCore.Qt.AlignCenter, itemInfos["text"]) def pointInItem(self, p, item): """ Checks if a point is in the shape of an Item. This is used to detect, if a user clicks or hovers over an item (possible drop action). """ m = self.minr if item.getType() in ['PULSE']: # Checks if p is in a Rectangle return (p.x() > item.pos.x()-m/6 and p.y() > item.pos.y() and p.x() < item.pos.x()-m/6-2+m*self.circleSize+m/3 and p.y() < item.pos.y()+m*self.circleSize) else: # Checks if p is in a Circle return (math.sqrt((p.x()-item.pos.x()-m*self.circleSize/2)**2 + (p.y()-item.pos.y()-m*self.circleSize/2)**2) < m*self.circleSize/2) def mousePressEvent(self, e): self.lastp = e.pos() for item in self.getItemList(): if self.pointInItem(self.lastp, item): self.setCurrentItem(item) self.treeItemClicked() self.dragModSoon = True self.started = time.time() self.nodeCopy = [] self.updateImage() break def mouseReleaseEvent(self, e): self.lastp = e.pos() if self.dragMod: dropevent = QtGui.QDropEvent(e.pos(), QtCore.Qt.DropAction(), QtCore.QMimeData(), QtCore.Qt.MouseButton(), QtCore.Qt.KeyboardModifiers(), QtCore.QEvent.Drop) dropevent.source = self.source if self.callback is not None and self.callback in self.voididxlist: self.voididxlist.remove(self.callback) self.deleteVoidItems() if self.callback is not None: if self.dragSource == self.source and not self.copyDrag: self.treeItemDelete() self.callback = None self.dragMod = False self.needUpdate = True self.updateImage() self.dragModSoon = False def mouseMoveEvent(self, event): e = QtGui.QMouseEvent(event) self.lastp = e.pos() if self.dragModSoon and not self.dragMod: if time.time() - self.started > 0.1: self.dragMod = True self.dragSource = self.source self.calcVoidItems() if self.dragMod: self.previewManager(event) self.updateImage() def stillInItemFunc(self, p): """ This Method detects, if the cursor is still hovering over the shape, which causes a change. By making a move/copy/insert preview, it is possible, that the new shapes don't matches the cursor position, so that a preview would be volatile without this method. """ m = self.stillInItem[2] itempos = self.stillInItem[1] if self.stillInItem[0] in ['PULSE']: # p in Rectangle return (p.x() > itempos.x()-m/6 and p.y() > itempos.y() and p.x() < itempos.x()-m/6-2+m*self.circleSize+m/3 and p.y() < itempos.y()+m*self.circleSize) else: # p in Circle return (math.sqrt((p.x()-itempos.x()-m*self.circleSize/2)**2 + (p.y()-itempos.y()-m*self.circleSize/2)**2) < m*self.circleSize/2) def setBranchVisible(self, item, visible): """ Changes the visibility of a complete branch. The given item should be the root of the branch. This method is used in the move preview (without copy). """ change = [item] for node in change: node.visible = visible for i in range(node.childCount()): change += [node.child(i)] def previewManager(self, event): """ This method decides, if a (copy)move/insert preview has to be done. It can also delete a preview, if the dragged item is not over a shape anymore. """ # Limiting the the calls of this method if time.time() - self.started > 0.1: self.started = time.time() dropIndex = self.calcDropIndex(event.pos()) if dropIndex is not None: # Cursor over shape if self.callback is None: # There is no preview self.makePreview(event, dropIndex) # make move/copy/insert elif (self.callback is not None and not self.stillInItemFunc(event.pos())): self.deletePreview() # undo move/copy/insert self.stillInItem = None def deletePreview(self): """ This method deletes a preview, that is caused by dragging an item over another item. """ self.deleteVoidItems() if self.dragSource == self.source: # not caused by a button drag item = self.getItem(self.callback) self.setCurrentItem(item) self.treeItemDelete() self.callback = None self.setCurrentItem(self.getItem(self.copyhelp)) if not self.copyDrag: self.currentItem().visible = True else: # caused by a button drag self.setCurrentItem(self.getItem(self.callback)) self.treeItemDelete() self.callback = None self.calcVoidItems() self.needUpdate = True def makePreview(self, event, dropIndex): """ Checks and creates a new (copy)move/insert preview. """ if not self.checkDrop(dropIndex): # We can't drop the Item here return if self.dragSource == self.source: # not caused by a button self.makePreviewCopyDrag(event, dropIndex) # (copy)move else: # caused by a button self.makePreviewInsert(event, dropIndex) # insert self.needUpdate = True # repainting the image of the widget def makePreviewCopyDrag(self, event, dropIndex): """ This Method creates a preview of a (copy)move action. """ self.deleteVoidItems() dragIndex = self.currentItem().idx() self.callback = dropIndex event.source = self.source self.copydropEvent(event, dropIndex) self.copyhelp = dragIndex[:] if len(dragIndex) >= len(dropIndex): numb = len(dropIndex)-1 if (dropIndex[0:numb] == dragIndex[0:numb] and dropIndex[numb] <= dragIndex[numb]): dragIndex[numb] += 1 self.setCurrentItem(self.getItem(dragIndex)) self.calcVoidItems() if not self.copyDrag: self.setBranchVisible(self.currentItem(), False) self.paintactivated = True def makePreviewInsert(self, event, dropIndex): """ This method creates a preview of a button drag action. """ if dropIndex == [0]: # you can't drop anything on the root item return self.deleteVoidItems() self.insertItem(dropIndex) new = self.getItem(dropIndex) self.setCurrentItem(new) self.callback = dropIndex self.calcVoidItems() def insertItem(self, dropIndex): """ Insert an item as a consequence of a button action. """ idx = dropIndex[0:-1] prep = self.getItem(idx) self.setCurrentItem(prep) idx += [prep.childCount()] self.dragSource.sendInsertSignal() self.itemMoved.emit(idx, dropIndex) # self.emit(QtCore.SIGNAL('itemMoved'), idx, dropIndex) def markVoidItems(self, dropIndex=None): """ This method marks all VoidItems, which are children of a VoidItem. """ for voididx in self.voididxlist: if dropIndex is not None and len(voididx) >= len(dropIndex): numb = len(dropIndex) if (dropIndex[0:numb] <= voididx[0:numb]): voididx[numb-1] += 1 self.setBranchVoid(self.getItem(voididx), True) voididx[numb-1] -= 1 else: self.setBranchVoid(self.getItem(voididx), True) def getItem(self, idx): """ Returns the item at a given item index. """ for item in self.getItemList(): if item.idx() == idx: return item def source(self): # just for creating the dropevent return self def updateImage(self): # forcing this widget to create a paintEvent self.viewport().repaint() def calcDropIndex(self, pos): """ This methods finds out, if a dragged item is hovering over another item. """ idx = None for item in self.getItemList(): if self.pointInItem(pos, item): searched = item idx = searched.idx() if searched.isVoid: for voididx in self.voididxlist: if len(idx) >= len(voididx): numb = len(voididx) if idx[0:numb] == voididx[0:numb]: idx = voididx self.stillInItem = [searched.getType(), searched.pos, self.minr] break return idx def copydropEvent(self, event, dropIndex=None): """ Make a copy of an Item and then move it to the given dropIndex. """ if event.source() == self: dragIndex = self.currentItem().idx() if dropIndex is None: dropIndex = self.calcDropIndex(event.pos()) if dropIndex is None: return tmp = copy.deepcopy(self.xml) tmp.copy(dragIndex) dragIndex[-1] += 1 tmp._move(dragIndex, dropIndex) status, msg = tmp.checkCommand(dropIndex) if status: self.itemCopy.emit() self.itemMoved.emit(dragIndex, dropIndex) def dragEnterEvent(self, e): # button drag is over the widget e.accept() self.dragSource = e.source() self.dragMod = True self.calcVoidItems() self.paintactivated = True self.updateImage() def dragLeaveEvent(self, e): # button drag leaves the widget self.deleteVoidItems() self.dragMod = False self.dragSource = None self.paintactivated = True self.updateImage() def dragMoveEvent(self, e): """ This method gets called, when the button drag function is used. """ self.previewManager(e) def dropEvent(self, event): if event.source() == self: # not a button item = self.currentItem() dragIndex = item.idx() dropIndex = self.calcDropIndex(event.pos()) if dropIndex is None: return self.itemMoved.emit(dragIndex, dropIndex) else: # a button if self.callback is None: for item in self.getItemList(): if self.pointInItem(event.pos(), item): self.setCurrentItem(item) self.treeItemInsert() break self.callback = None self.dragMod = False self.deleteVoidItems() self.paintactivated = True self.dragMod = False def keyPressEvent(self, event): """ Detects if the CopyDrag gets enabled. """ if not self.dragMod: super(QTreeWidget, self).keyPressEvent(event) if event.key() == QtCore.Qt.Key_Shift: if self.dragMod: if self.callback is not None: dropIndex = self.callback[:] self.deletePreview() self.copyDrag = True self.makePreview(event, dropIndex) else: self.deleteVoidItems() self.copyDrag = True self.calcVoidItems() self.paintactivated = True else: self.nodeCopy = [] self.copyDrag = True self.updateImage() def keyReleaseEvent(self, event): """ Detects if the CopyDrag gets disabled. """ if event.key() == QtCore.Qt.Key_Shift: if self.dragMod: if self.callback is not None: dropIndex = self.callback[:] self.deletePreview() self.copyDrag = False self.makePreview(event, dropIndex) else: self.deleteVoidItems() self.copyDrag = False self.calcVoidItems() self.needUpdate = True else: self.copyDrag = False self.nodeCopy = [] self.updateImage()
r = 0 for i in range(self.m_digits): r = c % 10 c = c // 10 rect = QRectF(x + self.X_OFFSET, self.Y_OFFSET, w, h) self.m_svg.render(p, "d{}".format(r), rect) x -= w p.restore() def inicio(self): import analogwidgets_rc self.m_value = 0 self.m_digits = 4 self.m_svg = None self.setDigitsFile(":/default/resources/train_digits.svg") if __name__ == '__main__': import sys from PyQt5.QtCore import QTimeLine app = QApplication(sys.argv) w = PyCounter() timeline = QTimeLine(10000) timeline.setFrameRange(0, 9999) timeline.frameChanged.connect(w.setValue) timeline.start() w.show() sys.exit(app.exec_())
class CustomProxy(QGraphicsProxyWidget): def __init__(self, parent=None, wFlags=0): super(CustomProxy, self).__init__(parent, wFlags) self.popupShown = False self.currentPopup = None self.timeLine = QTimeLine(250, self) self.timeLine.valueChanged.connect(self.updateStep) self.timeLine.stateChanged.connect(self.stateChanged) def boundingRect(self): return QGraphicsProxyWidget.boundingRect(self).adjusted(0, 0, 10, 10) def paintWindowFrame(self, painter, option, widget): color = QColor(0, 0, 0, 64) r = self.windowFrameRect() right = QRectF(r.right(), r.top() + 10, 10, r.height() - 10) bottom = QRectF(r.left() + 10, r.bottom(), r.width(), 10) intersectsRight = right.intersects(option.exposedRect) intersectsBottom = bottom.intersects(option.exposedRect) if intersectsRight and intersectsBottom: path = QPainterPath() path.addRect(right) path.addRect(bottom) painter.setPen(Qt.NoPen) painter.setBrush(color) painter.drawPath(path) elif intersectsBottom: painter.fillRect(bottom, color) elif intersectsRight: painter.fillRect(right, color) super(CustomProxy, self).paintWindowFrame(painter, option, widget) def hoverEnterEvent(self, event): super(CustomProxy, self).hoverEnterEvent(event) self.scene().setActiveWindow(self) if self.timeLine.currentValue != 1: self.zoomIn() def hoverLeaveEvent(self, event): super(CustomProxy, self).hoverLeaveEvent(event) if not self.popupShown and ( self.timeLine.direction() != QTimeLine.Backward or self.timeLine.currentValue() != 0): self.zoomOut() def sceneEventFilter(self, watched, event): if watched.isWindow() and (event.type() == QEvent.UngrabMouse or event.type() == QEvent.GrabMouse): self.popupShown = watched.isVisible() if not self.popupShown and not self.isUnderMouse(): self.zoomOut() return super(CustomProxy, self).sceneEventFilter(watched, event) def itemChange(self, change, value): if change == self.ItemChildAddedChange or change == self.ItemChildRemovedChange: if change == self.ItemChildAddedChange: self.currentPopup = value self.currentPopup.setCacheMode(self.ItemCoordinateCache) if self.scene() is not None: self.currentPopup.installSceneEventFilter(self) elif self.scene() is not None: self.currentPopup.removeSceneEventFilter(self) self.currentPopup = None elif self.currentPopup is not None and change == self.ItemSceneHasChanged: self.currentPopup.installSceneEventFilter(self) return super(CustomProxy, self).itemChange(change, value) def updateStep(self, step): r = self.boundingRect() self.setTransform(QTransform() \ .translate(r.width() / 2, r.height() / 2)\ .rotate(step * 30, Qt.XAxis)\ .rotate(step * 10, Qt.YAxis)\ .rotate(step * 5, Qt.ZAxis)\ .scale(1 + 1.5 * step, 1 + 1.5 * step)\ .translate(-r.width() / 2, -r.height() / 2)) def stateChanged(self, state): if state == QTimeLine.Running: if self.timeLine.direction() == QTimeLine.Forward: self.setCacheMode(self.NoCache) elif state == QTimeLine.NotRunning: if self.timeLine.direction() == QTimeLine.Backward: self.setCacheMode(self.DeviceCoordinateCache) def zoomIn(self): if self.timeLine.direction() != QTimeLine.Forward: self.timeLine.setDirection(QTimeLine.Forward) if self.timeLine.state() == QTimeLine.NotRunning: self.timeLine.start() def zoomOut(self): if self.timeLine.direction() != QTimeLine.Backward: self.timeLine.setDirection(QTimeLine.Backward) if self.timeLine.state() == QTimeLine.NotRunning: self.timeLine.start()
class QPageWidget(QScrollArea): """ The QPageWidget provides a stack widget with animated page transitions. """ #Emits currentChanged = pyqtSignal() def __init__(self, parent=None, direction="ltr", rtf=False): """ Creates a new QPageWidget on given parent object. parent: QWidget parent direction: "ltr" -> Left To Right "ttb" -> Top To Bottom rtf: Return to first, if its True it flips to the first page when next page requested at the last page """ # First initialize, QPageWidget is based on QScrollArea QScrollArea.__init__(self, parent) # Properties for QScrollArea self.setFrameShape(QFrame.NoFrame) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setWidgetResizable(True) # Main widget, which stores all Pages in it self.widget = QWidget(self) # Layout based on QBoxLayout which supports Vertical or Horizontal layout if direction == "ltr": self.layout = QBoxLayout(QBoxLayout.LeftToRight, self.widget) self.__scrollBar = self.horizontalScrollBar() self.__base_value = self.width else: self.layout = QBoxLayout(QBoxLayout.TopToBottom, self.widget) self.__scrollBar = self.verticalScrollBar() self.__base_value = self.height self.layout.setSpacing(0) #qboxlayout setmargin özelliği yok #self.layout.setMargin(0) # Return to first self.__return_to_first = rtf # TMP_PAGE, its using as last page in stack # A workaround for a QScrollArea bug self.__tmp_page = Page(QWidget(self.widget)) self.__pages = [self.__tmp_page] self.__current = 0 self.__last = 0 # Set main widget self.setWidget(self.widget) # Animation TimeLine self.__timeline = QTimeLine() self.__timeline.setUpdateInterval(2) # Updates scrollbar position when frame changed self.__timeline.frameChanged.connect( lambda x: self.__scrollBar.setValue(x)) # End of the animation self.__timeline.finished.connect(self._animateFinished) # Initialize animation self.setAnimation() self.setDuration() def _animateFinished(self): """ Its called by TimeLine when animation finished. It first runs the outMethod of last Page and then the inMethod of current Page Finally tt gives the focus to the current page and fixes the scrollBar """ # Disable other widgets for page in self.__pages: if not page == self.__pages[self.__current]: page.widget.setEnabled(False) # Run last page's outMethod if exists if self.__pages[self.__last].outMethod: self.__pages[self.__last].outMethod() # Run new page's inMethod if exists if self.__pages[self.__current].inMethod: self.__pages[self.__current].inMethod() # Give focus to the current Page self.__pages[self.__current].widget.setFocus() # Update scrollbar position for current page self.__scrollBar.setValue(self.__current * self.__base_value()) # Emit currentChanged SIGNAL self.currentChanged.emit() def event(self, event): """ Overrides the main event handler to catch resize events """ # Catch Resize event if event.type() == QEvent.Resize: # Update each page size limits to mainwidget's new size for page in self.__pages: page.widget.setMinimumSize(self.size()) page.widget.setMaximumSize(self.size()) # Update viewport size limits to mainwidget's new size # It's a workaround for QScrollArea updateGeometry bug self.viewport().setMinimumSize(self.size()) self.viewport().setMaximumSize(self.size()) # Update scrollbar position for current page self.__scrollBar.setValue(self.__current * self.__base_value()) # Return the Event return QScrollArea.event(self, event) def keyPressEvent(self, event): """ Overrides the keyPressEvent to ignore them """ pass def wheelEvent(self, event): """ Overrides the wheelEvent to ignore them """ pass def createPage(self, widget, inMethod=None, outMethod=None): """ Creates and adds new Page for given widget with given in/out methods. widget: A QWidget which is the mainwidget for this Page inMethod: (optional) QPageWidget triggers this method when the Page appear outMethod: (optional) QPageWidget triggers this method when the Page disappear """ self.addPage(Page(widget, inMethod, outMethod)) def addPage(self, page): """ Adds the given Page to the stack. page: A Page object """ # First remove the last page; its __tmp_page self.__pages.pop() # Add new page self.__pages.append(page) self.layout.addWidget(page.widget) # Add __tmp_page to end self.__pages.append(self.__tmp_page) self.layout.addWidget(self.__tmp_page.widget) # Create connections for page navigation signals from new page try: page.widget.pageNext.connect(self.next) page.widget.pagePrevious.connect(self.prev) page.widget.setCurrent[int].connect(self.setCurrent) except: pass def __setCurrent(self, pageNumber): """ Internal method to set current page index. """ self.__last = self.__current self.__current = min(max(0, pageNumber), len(self.__pages) - 2) if pageNumber == len(self.__pages) - 1 and self.__return_to_first: self.__current = 0 def setCurrent(self, pageNumber=0): """ Set and flip the page with given pageNumber. pageNumber: index number of Page (default is 0) """ self.__setCurrent(pageNumber) self.flipPage() def getCurrent(self): """ Returns current page index. """ return self.__current def getCurrentWidget(self): """ Returns current page widget. """ return self.getWidget(self.getCurrent()) def getWidget(self, pageNumber): """ Returns widget for given page index pageNumber: index number of Page """ try: return self.__pages[pageNumber].widget except: return None def count(self): """ Returns number of pages. """ return len(self.__pages) - 1 def setAnimation(self, animation=35): """ Set the transition animation with the given animation. animation: the number represents predefined QEasingCurves List of predefined QEasingCurves can be found from: http://doc.qt.nokia.com/4/qeasingcurve.html#Type-enum Default is QEasingCurve::InOutBack (35) """ self.__animation = animation self.__timeline.setEasingCurve(QEasingCurve(self.__animation)) def setDuration(self, duration=400): """ Set the transition duration. duration: duration time in ms """ self.__duration = duration self.__timeline.setDuration(self.__duration) def flipPage(self, direction=0): """ Flip the page with given direction. direction: can be -1, 0 or +1 -1: previous page (if exists) 0: just flip to current page +1: next page (if exists) """ # Enable all widgets for page in self.__pages: page.widget.setEnabled(True) # Check given direction direction = direction if direction == 0 else max(min(1, direction), -1) # If direction is equal to zero no need to re-set current if not direction == 0: self.__setCurrent(self.__current + direction) # If last page is different from new page, flip it ! if not self.__last == self.__current: self.__timeline.setFrameRange(self.__scrollBar.value(), self.__current * self.__base_value()) self.__timeline.start() def next(self): """ Helper method to flip next page. """ self.flipPage(1) def prev(self): """ Helper method to flip previous page. """ self.flipPage(-1)
class Window(QWidget): def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) self.resize(600, 200) layout = QVBoxLayout(self) # 配置全局属性(也可以通过start方法里的参数配置单独的属性) CLoadingBar.config(height=2, direction=CLoadingBar.TOP, color='#2d8cf0', failedColor='#ed4014') # 子控件顶部进度 self.widget1 = QWidget(self) layout.addWidget(self.widget1) CLoadingBar.start(self.widget1, color='#19be6b', failedColor='#ff9900') widget = QWidget(self) layoutc = QHBoxLayout(widget) layoutc.addWidget(QPushButton('开始', self, clicked=self.doStart)) layoutc.addWidget(QPushButton('结束', self, clicked=self.doFinish)) layoutc.addWidget(QPushButton('错误', self, clicked=self.doError)) layout.addWidget(widget) # 子控件底部进度 self.widget2 = QWidget(self) layout.addWidget(self.widget2) CLoadingBar.start(self.widget2, direction=CLoadingBar.BOTTOM, height=6) # 模拟进度 self.updateTimer = QTimeLine(10000, self, frameChanged=self.doUpdateProgress) self.updateTimer.setFrameRange(0, 100) # 设置数字变化曲线模拟进度的不规则变化 self.updateTimer.setCurveShape(QTimeLine.EaseInOutCurve) def doStart(self): """模拟开始 """ self.updateTimer.stop() self.updateTimer.start() def doFinish(self): """模拟结束 """ self.updateTimer.stop() CLoadingBar.finish(self.widget1) CLoadingBar.finish(self.widget2) def doError(self): """模拟出错 """ self.updateTimer.stop() CLoadingBar.error(self.widget1) CLoadingBar.error(self.widget2) def doUpdateProgress(self, value): """模拟进度值变化 :param value: """ CLoadingBar.update(self.widget1, value) CLoadingBar.update(self.widget2, value) if value == 100: self.updateTimer.stop() self.doFinish()
class QPageWidget(QScrollArea): """ The QPageWidget provides a stack widget with animated page transitions. """ #Emits currentChanged = pyqtSignal() def __init__(self, parent = None, direction = "ltr", rtf = False): """ Creates a new QPageWidget on given parent object. parent: QWidget parent direction: "ltr" -> Left To Right "ttb" -> Top To Bottom rtf: Return to first, if its True it flips to the first page when next page requested at the last page """ # First initialize, QPageWidget is based on QScrollArea QScrollArea.__init__(self, parent) # Properties for QScrollArea self.setFrameShape(QFrame.NoFrame) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setWidgetResizable(True) # Main widget, which stores all Pages in it self.widget = QWidget(self) # Layout based on QBoxLayout which supports Vertical or Horizontal layout if direction == "ltr": self.layout = QBoxLayout(QBoxLayout.LeftToRight, self.widget) self.__scrollBar = self.horizontalScrollBar() self.__base_value = self.width else: self.layout = QBoxLayout(QBoxLayout.TopToBottom, self.widget) self.__scrollBar = self.verticalScrollBar() self.__base_value = self.height self.layout.setSpacing(0) #qboxlayout setmargin özelliği yok #self.layout.setMargin(0) # Return to first self.__return_to_first = rtf # TMP_PAGE, its using as last page in stack # A workaround for a QScrollArea bug self.__tmp_page = Page(QWidget(self.widget)) self.__pages = [self.__tmp_page] self.__current = 0 self.__last = 0 # Set main widget self.setWidget(self.widget) # Animation TimeLine self.__timeline = QTimeLine() self.__timeline.setUpdateInterval(2) # Updates scrollbar position when frame changed self.__timeline.frameChanged.connect(lambda x: self.__scrollBar.setValue(x)) # End of the animation self.__timeline.finished.connect(self._animateFinished) # Initialize animation self.setAnimation() self.setDuration() def _animateFinished(self): """ Its called by TimeLine when animation finished. It first runs the outMethod of last Page and then the inMethod of current Page Finally tt gives the focus to the current page and fixes the scrollBar """ # Disable other widgets for page in self.__pages: if not page == self.__pages[self.__current]: page.widget.setEnabled(False) # Run last page's outMethod if exists if self.__pages[self.__last].outMethod: self.__pages[self.__last].outMethod() # Run new page's inMethod if exists if self.__pages[self.__current].inMethod: self.__pages[self.__current].inMethod() # Give focus to the current Page self.__pages[self.__current].widget.setFocus() # Update scrollbar position for current page self.__scrollBar.setValue(self.__current * self.__base_value()) # Emit currentChanged SIGNAL self.currentChanged.emit() def event(self, event): """ Overrides the main event handler to catch resize events """ # Catch Resize event if event.type() == QEvent.Resize: # Update each page size limits to mainwidget's new size for page in self.__pages: page.widget.setMinimumSize(self.size()) page.widget.setMaximumSize(self.size()) # Update viewport size limits to mainwidget's new size # It's a workaround for QScrollArea updateGeometry bug self.viewport().setMinimumSize(self.size()) self.viewport().setMaximumSize(self.size()) # Update scrollbar position for current page self.__scrollBar.setValue(self.__current * self.__base_value()) # Return the Event return QScrollArea.event(self, event) def keyPressEvent(self, event): """ Overrides the keyPressEvent to ignore them """ pass def wheelEvent(self, event): """ Overrides the wheelEvent to ignore them """ pass def createPage(self, widget, inMethod = None, outMethod = None): """ Creates and adds new Page for given widget with given in/out methods. widget: A QWidget which is the mainwidget for this Page inMethod: (optional) QPageWidget triggers this method when the Page appear outMethod: (optional) QPageWidget triggers this method when the Page disappear """ self.addPage(Page(widget, inMethod, outMethod)) def addPage(self, page): """ Adds the given Page to the stack. page: A Page object """ # First remove the last page; its __tmp_page self.__pages.pop() # Add new page self.__pages.append(page) self.layout.addWidget(page.widget) # Add __tmp_page to end self.__pages.append(self.__tmp_page) self.layout.addWidget(self.__tmp_page.widget) # Create connections for page navigation signals from new page try: page.widget.pageNext.connect(self.next) page.widget.pagePrevious.connect(self.prev) page.widget.setCurrent[int].connect(self.setCurrent) except: pass def __setCurrent(self, pageNumber): """ Internal method to set current page index. """ self.__last = self.__current self.__current = min(max(0, pageNumber), len(self.__pages) - 2) if pageNumber == len(self.__pages) - 1 and self.__return_to_first: self.__current = 0 def setCurrent(self, pageNumber = 0): """ Set and flip the page with given pageNumber. pageNumber: index number of Page (default is 0) """ self.__setCurrent(pageNumber) self.flipPage() def getCurrent(self): """ Returns current page index. """ return self.__current def getCurrentWidget(self): """ Returns current page widget. """ return self.getWidget(self.getCurrent()) def getWidget(self, pageNumber): """ Returns widget for given page index pageNumber: index number of Page """ try: return self.__pages[pageNumber].widget except: return None def count(self): """ Returns number of pages. """ return len(self.__pages) - 1 def setAnimation(self, animation = 35): """ Set the transition animation with the given animation. animation: the number represents predefined QEasingCurves List of predefined QEasingCurves can be found from: http://doc.qt.nokia.com/4/qeasingcurve.html#Type-enum Default is QEasingCurve::InOutBack (35) """ self.__animation = animation self.__timeline.setEasingCurve(QEasingCurve(self.__animation)) def setDuration(self, duration = 400): """ Set the transition duration. duration: duration time in ms """ self.__duration = duration self.__timeline.setDuration(self.__duration) def flipPage(self, direction=0): """ Flip the page with given direction. direction: can be -1, 0 or +1 -1: previous page (if exists) 0: just flip to current page +1: next page (if exists) """ # Enable all widgets for page in self.__pages: page.widget.setEnabled(True) # Check given direction direction = direction if direction == 0 else max(min(1, direction), -1) # If direction is equal to zero no need to re-set current if not direction == 0: self.__setCurrent(self.__current + direction) # If last page is different from new page, flip it ! if not self.__last == self.__current: self.__timeline.setFrameRange(self.__scrollBar.value(), self.__current * self.__base_value()) self.__timeline.start() def next(self): """ Helper method to flip next page. """ self.flipPage(1) def prev(self): """ Helper method to flip previous page. """ self.flipPage(-1)
def closeItem(self, item): animation = QTimeLine(ANIMATE_TIME, self) animation.setFrameRange(146, CLOSED_SIZE) animation.frameChanged.connect(lambda x: item.setSizeHint(QSize(32, x))) animation.start()
class ExplorerNode(BaseNode): def __init__(self, nx_node, center_pos, nx_pos, steps, steps_max, small): """ Create node in the graph scene :param tuple nx_node: Node info :param center_pos: The position of the center node :param nx_pos: Position of the nodes in the graph :param int steps: The steps from the center identity :param int steps_max: The steps max of the graph :param bool small: Small dots for big networks """ super().__init__(nx_node, nx_pos) self.steps = steps self.steps_max = steps_max self.highlighted = False self.status_sentry = False if small: self.setRect(0, 0, 10, 10) self.text_item = None else: # text inside ellipse self.text_item = QGraphicsSimpleTextItem(self) self.text_item.setText(self.text) # center ellipse around text self.setRect(0, 0, self.text_item.boundingRect().width() * 2, self.text_item.boundingRect().height() * 2) # center text in ellipse self.text_item.setPos(self.boundingRect().width() / 4.0, self.boundingRect().height() / 4.0) # set anchor to the center self.setTransform(QTransform().translate( -self.boundingRect().width() / 2.0, -self.boundingRect().height() / 2.0)) # cursor change on hover self.setAcceptHoverEvents(True) self.setZValue(1) # animation and moves self.timeline = None self.loading_timer = QTimer() self.loading_timer.timeout.connect(self.next_tick) self.loading_counter = 0 self._refresh_colors() self.setPos(center_pos) self.move_to(nx_pos) def update_metadata(self, metadata): super().update_metadata(metadata) self.status_sentry = self.metadata[ 'is_sentry'] if 'is_sentry' in self.metadata else False self._refresh_colors() def _refresh_colors(self): """ Refresh elements in the node """ # color around ellipse outline_color = QColor('grey') outline_style = Qt.SolidLine outline_width = 1 if self.status_wallet: outline_width = 2 if not self.status_member: outline_color = QColor('red') if self.status_sentry: outline_color = QColor('black') outline_width = 3 self.setPen(QPen(outline_color, outline_width, outline_style)) if self.highlighted: text_color = QColor('grey') else: text_color = QColor('black') if self.status_wallet == NodeStatus.HIGHLIGHTED: text_color = QColor('grey') if self.text_item: self.text_item.setBrush(QBrush(text_color)) # create gradient inside the ellipse gradient = QRadialGradient( QPointF(0, self.boundingRect().height() / 4), self.boundingRect().width()) color = QColor() color.setHsv(120 - 60 / self.steps_max * self.steps, 180 + 50 / self.steps_max * self.steps, 60 + 170 / self.steps_max * self.steps) if self.highlighted: color = color.darker(200) color = color.lighter( math.fabs(math.sin(self.loading_counter / 100 * math.pi) * 100) + 100) gradient.setColorAt(0, color) gradient.setColorAt(1, color.darker(150)) self.setBrush(QBrush(gradient)) def move_to(self, nx_pos): """ Move to corresponding position :param nx_pos: :return: """ origin_x = self.x() origin_y = self.y() final_x = nx_pos[self.id][0] final_y = nx_pos[self.id][1] def frame_move(frame): value = self.timeline.valueForTime(self.timeline.currentTime()) x = origin_x + (final_x - origin_x) * value y = origin_y + (final_y - origin_y) * value self.setPos(x, y) if self.scene(): self.scene().node_moved.emit(self.id, x, y) def timeline_ends(): self.setPos(final_x, final_y) self.timeline = None # Remember to hold the references to QTimeLine and QGraphicsItemAnimation instances. # They are not kept anywhere, even if you invoke QTimeLine.start(). self.timeline = QTimeLine(1000) self.timeline.setFrameRange(0, 100) self.timeline.frameChanged.connect(frame_move) self.timeline.finished.connect(timeline_ends) self.timeline.start() def highlight(self): """ Highlight the edge in the scene """ self.highlighted = True self._refresh_colors() self.update(self.boundingRect()) def neutralize(self): """ Neutralize the edge in the scene """ self.highlighted = False self._refresh_colors() self.update(self.boundingRect()) def start_loading_animation(self): """ Neutralize the edge in the scene """ if not self.loading_timer.isActive(): self.loading_timer.start(10) def stop_loading_animation(self): """ Neutralize the edge in the scene """ self.loading_timer.stop() self.loading_counter = 100 self._refresh_colors() self.update(self.boundingRect()) def next_tick(self): """ Next tick :return: """ self.loading_counter += 1 self.loading_counter %= 100 self._refresh_colors() self.update(self.boundingRect())
class Widget(Ui_CollectionsWidget, QWidget, ScreenWidget): name = "collectionSelection" def __init__(self): QWidget.__init__(self) self.setupUi(self) self.collections = None self.current_item = None self.last_item = None self.collectionList.itemClicked.connect(self.openItem) self.collectionList.currentItemChanged.connect(self.itemChanged) def fillCollections(self): self.collectionList.clear() selected = None for index, collection in enumerate(self.collections): self.addItem(collection) if ctx.installData.autoCollection == collection: selected = index if not selected: selected = 0 self.current_item = self.collectionList.item(selected) self.last_item = self.current_item self.collectionList.setCurrentRow(selected) def shown(self): self.collections = ctx.collections self.fillCollections() ctx.mainScreen.disableNext() if self.current_item: self.openItem(self.current_item) else: self.openItem(self.collectionList.item(0)) self.check() def execute(self): ctx.installData.autoCollection = self.collectionList.itemWidget( self.current_item).collection return True def check(self): if self.current_item: ctx.mainScreen.enableNext() else: ctx.mainScreen.disableNext() def itemChanged(self, current, previous): self.current_item = current self.check() def addItem(self, collection): item = QListWidgetItem(self.collectionList) item.setSizeHint(QSize(36, CLOSED_SIZE)) self.collectionList.addItem(item) self.collectionList.setItemWidget( item, CollectionItem(self, collection, item)) def openItem(self, item): if item == self.last_item: return if self.last_item: self.closeItem(self.last_item) self.animation = QTimeLine(ANIMATE_TIME, self) self.animation.setFrameRange(36, EXPANDED_SIZE) self.animation.frameChanged.connect( lambda x: item.setSizeHint(QSize(32, x))) self.animation.start() self.last_item = item self.animation.finished.connect( lambda: self.collectionList.setCurrentItem(item)) def closeItem(self, item): animation = QTimeLine(ANIMATE_TIME, self) animation.setFrameRange(146, CLOSED_SIZE) animation.frameChanged.connect( lambda x: item.setSizeHint(QSize(32, x))) animation.start()
class Widget(QWidget, ScreenWidget): name = "accounts" def __init__(self): super(Widget, self).__init__() self.ui = Ui_SetupUsersWidget() self.ui.setupUi(self) self.edititemindex = None self.time_line = QTimeLine(400, self) self.time_line.setFrameRange(0, 220) self.time_line.frameChanged[int].connect(self.animate) self.ui.scrollArea.setFixedHeight(0) # User Icons self.normal_user_icon = QPixmap(":/gui/pics/users.png") self.super_user_icon = QPixmap(":/gui/pics/users.png") # Set disabled the create Button self.ui.createButton.setEnabled(False) # Connections self.ui.pass1.textChanged[str].connect(self.slotTextChanged) self.ui.pass2.textChanged[str].connect(self.slotTextChanged) self.ui.username.textChanged[str].connect(self.slotTextChanged) self.ui.realname.textChanged[str].connect(self.slotTextChanged) self.ui.username.textEdited[str].connect(self.slotUserNameChanged) self.ui.realname.textEdited[str].connect(self.slotRealNameChanged) self.ui.userID.valueChanged[int].connect(self.slotTextChanged) self.ui.userIDCheck.stateChanged[int].connect(self.slotuserIDCheck) self.ui.createButton.clicked.connect(self.slotCreateUser) self.ui.cancelButton.clicked.connect(self.resetWidgets) self.ui.deleteButton.clicked.connect(self.slotDeleteUser) self.ui.editButton.clicked.connect(self.slotEditUser) self.ui.addMoreUsers.clicked.connect(self.slotAdvanced) self.ui.userList.itemDoubleClicked[QListWidgetItem].connect(self.slotEditUser) self.ui.pass2.returnPressed.connect(self.slotReturnPressed) # focusInEvent is not a signal # self.ui.pass1.focusInEvent[QFocusEvent].connect(self.checkCapsLock) # self.ui.pass2.focusInEvent[QFocusEvent].connect(self.checkCapsLock) # self.ui.username.focusInEvent[QFocusEvent].connect(self.checkCapsLock) # self.ui.realname.focusInEvent[QFocusEvent].connect(self.checkCapsLock) ctx.installData.users = [] ctx.installData.autoLoginUser = None self.user_name_changed = False self.used_ids = [] def eventFilter(self, obj, event): if event.type() == QEvent.FocusIn: # even.type() ==... if obj == self.ui.pass1 or obj == self.ui.pass2 or \ obj == self.ui.username or obj == self.ui.realname: self.checkCapsLock() def shown(self): self.ui.cancelButton.hide() self.ui.realname.setFocus() if len(yali.users.PENDING_USERS) > 0 and self.ui.userList.count() == 0: for u in yali.users.PENDING_USERS: pix = self.normal_user_icon if "wheel" in u.groups: pix = self.super_user_icon UserItem(self.ui.userList, pix, user=u) self.ui.autoLogin.addItem(u.username) if len(yali.users.PENDING_USERS) == 1: self.slotEditUser(self.ui.userList.item(0)) elif len(yali.users.PENDING_USERS) > 1: self.ui.addMoreUsers.setChecked(True) self.checkUsers() self.checkCapsLock() def backCheck(self): self.refill() self.ui.cancelButton.hide() return True def refill(self): # reset and fill PENDING_USERS yali.users.reset_pending_users() for index in range(self.ui.userList.count()): user = self.ui.userList.item(index).getUser() ctx.installData.users.append(user) yali.users.PENDING_USERS.append(user) def execute(self): if self.checkUsers(): ctx.installData.autoLoginUser = str(self.ui.autoLogin.currentText()) if self.ui.createButton.text() == _("General", "Update"): return self.slotCreateUser() return True if not self.slotCreateUser(): ctx.mainScreen.step_increment = 0 return True self.refill() ctx.interface.informationWindow.hide() ctx.installData.autoLoginUser = str(self.ui.autoLogin.currentText()) return True def setCapsLockIcon(self, child): if type(child) == QLineEdit: if pardus.xorg.capslock.isOn(): child.setStyleSheet("""QLineEdit { background-image: url(:/gui/pics/caps.png); background-repeat: no-repeat; background-position: right; padding-right: 35px; }""") else: child.setStyleSheet("""QLineEdit { background-image: none; padding-right: 0px; }""") def checkCapsLock(self): for child in self.ui.groupBox.children(): self.setCapsLockIcon(child) for child in self.ui.groupBox_2.children(): self.setCapsLockIcon(child) def keyReleaseEvent(self, e): self.checkCapsLock() def showError(self, message): ctx.interface.informationWindow.update(message, type="error") ctx.mainScreen.disableNext() def animate(self, value): self.ui.scrollArea.setFixedHeight(int(value)) self.ui.frame.setMinimumHeight(250) if self.ui.scrollArea.height() == 0: self.ui.scrollArea.hide() else: self.ui.scrollArea.show() if self.ui.scrollArea.height() == 220: self.time_line.setDirection(1) self.ui.frame.setMinimumHeight(420) if self.ui.scrollArea.height() == 0: self.time_line.setDirection(0) def slotuserIDCheck(self, state): if state: self.ui.userID.setEnabled(True) else: self.ui.userID.setEnabled(False) def slotAdvanced(self): icon_path = None if self.ui.scrollArea.isVisible(): icon_path = ":/gui/pics/expand.png" self.time_line.start() else: self.ui.scrollArea.show() icon_path = ":/gui/pics/collapse.png" self.time_line.start() icon = QIcon() icon.addPixmap(QPixmap(icon_path), QIcon.Normal, QIcon.Off) self.ui.addMoreUsers.setIcon(icon) self.checkUsers() def slotTextChanged(self): username = str(self.ui.username.text()) realname = unicode(self.ui.realname.text()) password = unicode(self.ui.pass1.text()) password_confirm = unicode(self.ui.pass2.text()) if not password == '' and (password.lower() == username.lower() or password.lower() == realname.lower()): self.showError(_("General", 'Don\'t use your user name or name as a password')) return elif password_confirm != password and password_confirm: self.showError(_("General", 'Passwords do not match')) return elif len(password) == len(password_confirm) and len(password_confirm) < 4 and not password =='': self.showError(_("General", 'Password is too short')) return else: ctx.interface.informationWindow.hide() if self.ui.username.text() and password and password_confirm: self.ui.createButton.setEnabled(True) if not self.ui.addMoreUsers.isChecked(): ctx.mainScreen.enableNext() ctx.mainScreen.enableBack() else: self.ui.createButton.setEnabled(False) if not self.ui.addMoreUsers.isChecked(): ctx.mainScreen.disableNext() def currentUsers(self): users = [] for index in range(self.ui.userList.count()): users.append(self.ui.userList.item(index).getUser().username) return users def slotUserNameChanged(self): self.user_name_changed = True def slotRealNameChanged(self): if not self.user_name_changed: used_users = yali.users.get_users() used_users.extend(self.currentUsers()) self.ui.username.setText(yali.users.nick_guess(self.ui.realname.text(), used_users)) def slotCreateUser(self): user = yali.users.User() user.username = str(self.ui.username.text()) # ignore last character. see bug #887 user.realname = unicode(self.ui.realname.text()) user.passwd = unicode(self.ui.pass1.text()) user.groups = ["users", "pnp", "disk", "audio", "video", "power", "dialout", "lp", "lpadmin", "cdrom", "floppy"] pix = self.normal_user_icon if self.ui.admin.isChecked(): user.groups.append("wheel") pix = self.super_user_icon user.no_password = self.ui.noPass.isChecked() # check user validity if user.exists() or (user.username in self.currentUsers() and self.edititemindex == None): self.showError(_("General", "This user name is already taken, please choose another one.")) return False elif not user.usernameIsValid(): # FIXME: Mention about what are the invalid characters! self.showError(_("General", "The user name contains invalid characters.")) return False elif not user.realnameIsValid(): self.showError(_("General", "The real name contains invalid characters.")) return False # Dont check in edit mode if self.ui.addMoreUsers.isChecked() and self.ui.userIDCheck.isChecked(): uid = self.ui.userID.value() if self.edititemindex == None: if uid in self.used_ids: self.showError(_("General", 'User ID used before, choose another one!')) return False self.used_ids.append(uid) user.uid = uid self.ui.createButton.setText(_("General", "Add")) self.ui.cancelButton.hide() update_item = None try: self.ui.userList.takeItem(self.edititemindex) self.ui.autoLogin.removeItem(self.edititemindex + 1) except: update_item = self.edititemindex # nothing wrong. just adding a new user... pass item = UserItem(self.ui.userList, pix, user=user) # add user to auto-login list. self.ui.autoLogin.addItem(user.username) if update_item: self.ui.autoLogin.setCurrentIndex(self.ui.autoLogin.count()) # clear form self.resetWidgets() ctx.logger.debug("slotCreateUser :: user (%s) '%s (%s)' added/updated" % (user.uid, user.realname, user.username)) ctx.logger.debug("slotCreateUser :: user groups are %s" % str(','.join(user.groups))) # give focus to realname widget for a new user. #3280 #self.ui.realname.setFocus() self.checkUsers() self.user_name_changed = False self.refill() return True def slotDeleteUser(self): if self.ui.userList.currentRow() == self.edititemindex: self.resetWidgets() self.ui.autoLogin.setCurrentIndex(0) _cur = self.ui.userList.currentRow() item = self.ui.userList.item(_cur).getUser() if item.uid in self.used_ids: self.used_ids.remove(item.uid) self.ui.userList.takeItem(_cur) self.ui.autoLogin.removeItem(_cur + 1) self.ui.createButton.setText(_("General", "Add")) icon = QIcon() icon.addPixmap(QPixmap(":/gui/pics/user-group-new.png"), QIcon.Normal, QIcon.Off) self.ui.createButton.setIcon(icon) self.ui.cancelButton.hide() self.checkUsers() def slotEditUser(self, item=None): if not item: item = self.ui.userList.currentItem() self.ui.userList.setCurrentItem(item) user = item.getUser() if user.uid > -1: self.ui.userIDCheck.setChecked(True) self.ui.userID.setValue(user.uid) self.ui.username.setText(user.username) self.ui.realname.setText(user.realname) self.ui.pass1.setText(user.passwd) self.ui.pass2.setText(user.passwd) if "wheel" in user.groups: self.ui.admin.setChecked(True) else: self.ui.admin.setChecked(False) self.ui.noPass.setChecked(user.no_password) self.edititemindex = self.ui.userList.currentRow() self.ui.createButton.setText(_("General", "Update")) icon = QIcon() icon.addPixmap(QPixmap(":/gui/pics/tick.png"), QIcon.Normal, QIcon.Off) self.ui.createButton.setIcon(icon) self.ui.cancelButton.setVisible(self.ui.createButton.isVisible()) def checkUserFields(self): username = unicode(self.ui.username.text()) realname = unicode(self.ui.realname.text()) password = unicode(self.ui.pass1.text()) password_confirm = unicode(self.ui.pass2.text()) if username and realname and password and password_confirm and \ (password == password_confirm) and \ (password.lower() != username.lower() and password.lower() != realname.lower()): return True else: return False def checkUsers(self): if self.ui.userList.count() > 0: self.ui.userList.setCurrentRow(0) self.ui.deleteButton.setEnabled(True) self.ui.editButton.setEnabled(True) self.ui.autoLogin.setEnabled(True) ctx.mainScreen.enableNext() ctx.mainScreen.enableBack() return True else: if self.checkUserFields(): ctx.mainScreen.enableNext() else: ctx.mainScreen.disableNext() # there is no user in list so noting to delete self.ui.deleteButton.setEnabled(False) self.ui.editButton.setEnabled(False) self.ui.autoLogin.setEnabled(False) return False def resetWidgets(self): # clear all self.edititemindex = None self.ui.username.clear() self.ui.realname.clear() self.ui.pass1.clear() self.ui.pass2.clear() self.ui.admin.setChecked(False) self.ui.noPass.setChecked(False) self.ui.userIDCheck.setChecked(False) self.ui.createButton.setEnabled(False) if self.ui.cancelButton.isVisible(): self.ui.cancelButton.setHidden(self.sender() == self.ui.cancelButton) self.checkUsers() self.ui.createButton.setText(_("General", "Add")) icon = QIcon() icon.addPixmap(QPixmap(":/gui/pics/user-group-new.png"), QIcon.Normal, QIcon.Off) self.ui.createButton.setIcon(icon) def slotReturnPressed(self): if self.ui.createButton.isEnabled() and self.ui.addMoreUsers.isChecked(): self.slotCreateUser()