class CombinerIcon(ProjectItemIcon): _SHAKE_FACTOR = 0.05 def __init__(self, toolbox, x, y, project_item, icon): """View icon for the Design View. Args: toolbox (ToolBoxUI): QMainWindow instance x (float): Icon x coordinate y (float): Icon y coordinate project_item (ProjectItem): Item icon (str): icon resource path """ super().__init__(toolbox, x, y, project_item, icon, icon_color=QColor("#990000"), background_color=QColor("#ffcccc")) self.time_line = QTimeLine() self.time_line.setLoopCount(0) # loop forever self.time_line.setFrameRange(0, 10) self.time_line.setDirection(QTimeLine.Backward) self.time_line.valueChanged.connect( self._handle_time_line_value_changed) self.time_line.stateChanged.connect( self._handle_time_line_state_changed) self._svg_item_pos = self.svg_item.pos() @Slot(float) def _handle_time_line_value_changed(self, value): rect = self.svg_item.sceneBoundingRect() width = rect.width() height = rect.height() x = random.uniform(-self._SHAKE_FACTOR, self._SHAKE_FACTOR) * width y = random.uniform(-self._SHAKE_FACTOR, self._SHAKE_FACTOR) * height self.svg_item.setPos(self._svg_item_pos + QPointF(x, y)) @Slot("QTimeLine::State") def _handle_time_line_state_changed(self, new_state): if new_state == QTimeLine.NotRunning: self.svg_item.setPos(self._svg_item_pos) def start_animation(self): """Start the animation that plays when the Combiner associated to this GraphicsItem is running. """ if self.time_line.state() == QTimeLine.Running: return self.time_line.start() def stop_animation(self): """Stop animation""" if self.time_line.state() != QTimeLine.Running: return self.time_line.stop()
class ToolIcon(ProjectItemIcon): def __init__(self, toolbox, x, y, project_item, icon): """Tool icon for the Design View. Args: toolbox (ToolBoxUI): QMainWindow instance x (float): Icon x coordinate y (float): Icon y coordinate project_item (ProjectItem): Item icon (str): icon resource path """ super().__init__( toolbox, x, y, project_item, icon, icon_color=QColor("red"), background_color=QColor("#ffe6e6") ) self.time_line = QTimeLine() self.time_line.setLoopCount(0) # loop forever self.time_line.setFrameRange(0, 10) self.time_line.setDuration(1200) self.time_line.setDirection(QTimeLine.Backward) self.time_line.valueChanged.connect(self._handle_time_line_value_changed) self.time_line.stateChanged.connect(self._handle_time_line_state_changed) self._svg_item_pos = self.svg_item.pos() rect = self.svg_item.sceneBoundingRect() self._anim_transformation_origin_point_y = -0.75 * rect.height() self._anim_delta_x_factor = 0.5 * rect.width() @Slot(float) def _handle_time_line_value_changed(self, value): angle = value * 45.0 self.svg_item.setRotation(angle) delta_y = 0.5 * self.svg_item.sceneBoundingRect().height() delta = QPointF(self._anim_delta_x_factor * value, delta_y) self.svg_item.setPos(self._svg_item_pos + delta) @Slot("QTimeLine::State") def _handle_time_line_state_changed(self, new_state): if new_state == QTimeLine.Running: self.svg_item.setTransformOriginPoint(0, self._anim_transformation_origin_point_y) elif new_state == QTimeLine.NotRunning: self.svg_item.setTransformOriginPoint(0, 0) self.svg_item.setPos(self._svg_item_pos) self.svg_item.setRotation(0) def start_animation(self): """Starts the item execution animation. """ if self.time_line.state() == QTimeLine.Running: return self.time_line.start() def stop_animation(self): """Stop animation""" if self.time_line.state() != QTimeLine.Running: return self.time_line.stop()
class ImporterExporterAnimation: def __init__(self, item, duration=2000, count=5, percentage_size=0.24, x_shift=0): """Initializes animation stuff. Args: item (QGraphicsItem): The item on top of which the animation should play. """ self._item = item self.cubes = [QGraphicsTextItem("\uf1b2", item) for i in range(count)] self.opacity_at_value_path = QPainterPath(QPointF(0.0, 0.0)) self.opacity_at_value_path.lineTo(QPointF(0.01, 1.0)) self.opacity_at_value_path.lineTo(QPointF(0.5, 1.0)) self.opacity_at_value_path.lineTo(QPointF(1.0, 0.0)) self.time_line = QTimeLine() self.time_line.setLoopCount(0) # loop forever self.time_line.setFrameRange(0, 10) self.time_line.setDuration(duration) self.time_line.setCurveShape(QTimeLine.LinearCurve) self.time_line.valueChanged.connect( self._handle_time_line_value_changed) self.time_line.stateChanged.connect( self._handle_time_line_state_changed) font = QFont('Font Awesome 5 Free Solid') item_rect = item.rect() cube_size = percentage_size * 0.875 * item_rect.height() font.setPixelSize(cube_size) rect = item_rect.translated(-0.5 * cube_size + x_shift, -cube_size) end = rect.center() ctrl = end - QPointF(0, 0.6 * rect.height()) lower, upper = 0.2, 0.8 starts = [lower + i * (upper - lower) / count for i in range(count)] starts = [ rect.topLeft() + QPointF(start * rect.width(), 0) for start in starts ] self.paths = [QPainterPath(start) for start in starts] for path in self.paths: path.quadTo(ctrl, end) self.offsets = [i / count for i in range(count)] for cube in self.cubes: cube.setFont(font) cube.setDefaultTextColor("#003333") cube.setTransformOriginPoint(cube.boundingRect().center()) cube.hide() cube.setOpacity(0) @Slot(float) def _handle_time_line_value_changed(self, value): for cube, offset, path in zip(self.cubes, self.offsets, self.paths): value = (offset + value) % 1.0 opacity = self.opacity_at_value_path.pointAtPercent(value).y() cube.setOpacity(opacity) percent = self.percent(value) point = path.pointAtPercent(percent) angle = percent * 360.0 cube.setPos(point) cube.setRotation(angle) @Slot("QTimeLine::State") def _handle_time_line_state_changed(self, new_state): if new_state == QTimeLine.Running: random.shuffle(self.offsets) for cube in self.cubes: cube.show() elif new_state == QTimeLine.NotRunning: for cube in self.cubes: cube.hide() def start(self): """Starts the animation.""" if self.time_line.state() == QTimeLine.Running: return self.time_line.start() @staticmethod def percent(value): raise NotImplementedError() def stop(self): """Stops the animation""" self.time_line.stop()
class ToolIcon(ProjectItemIcon): def __init__(self, toolbox, x, y, w, h, name): """Tool icon for the Design View. Args: toolbox (ToolBoxUI): QMainWindow instance x (float): Icon x coordinate y (float): Icon y coordinate w (float): Width of master icon h (float): Height of master icon name (str): Item name """ super().__init__( toolbox, x, y, w, h, name, ":/icons/project_item_icons/hammer.svg", icon_color=QColor("red"), background_color=QColor("#ffe6e6"), ) # animation stuff self.timer = QTimeLine() self.timer.setLoopCount(0) # loop forever self.timer.setFrameRange(0, 10) # self.timer.setCurveShape(QTimeLine.CosineCurve) self.timer.valueForTime = self._value_for_time self.tool_animation = QGraphicsItemAnimation() self.tool_animation.setItem(self.svg_item) self.tool_animation.setTimeLine(self.timer) self.delta = 0.25 * self.svg_item.sceneBoundingRect().height() @staticmethod def _value_for_time(msecs): rem = (msecs % 1000) / 1000 return 1.0 - rem def start_animation(self): """Start the animation that plays when the Tool associated to this GraphicsItem is running. """ if self.timer.state() == QTimeLine.Running: return self.svg_item.moveBy(0, -self.delta) offset = 0.75 * self.svg_item.sceneBoundingRect().height() for angle in range(1, 45): step = angle / 45.0 self.tool_animation.setTranslationAt(step, 0, offset) self.tool_animation.setRotationAt(step, angle) self.tool_animation.setTranslationAt(step, 0, -offset) self.tool_animation.setPosAt( step, QPointF(self.svg_item.pos().x(), self.svg_item.pos().y() + offset)) self.timer.start() def stop_animation(self): """Stop animation""" if self.timer.state() != QTimeLine.Running: return self.timer.stop() self.svg_item.moveBy(0, self.delta) self.timer.setCurrentTime(999)