def drawBackground(self, painter: QPainter, rect: QRectF): currentColor = self.backgroundBrush().color() if currentColor != self.backgroundColor: self.setBackgroundBrush(QBrush(self.backgroundColor)) super().drawBackground(painter, rect) if self._zoom <= self.gridZoomThreshold or not self.showGrid: return painter.setPen(QPen(self.gridColor, self.gridThickness)) lines = [] if self.gridSpacing.width() > 0: xStart = rect.left() - rect.left() % self.gridSpacing.width() while xStart <= rect.right(): line = QLineF(xStart, rect.bottom(), xStart, rect.top()) lines.append(line) xStart = xStart + self.gridSpacing.width() if self.gridSpacing.height() > 0: yStart = rect.top() - rect.top() % self.gridSpacing.height() while yStart <= rect.bottom(): line = QLineF(rect.left(), yStart, rect.right(), yStart) lines.append(line) yStart = yStart + self.gridSpacing.height() painter.drawLines(lines)
def default(self) -> None: self.path = QLineF(QPointF(0.0, 0.0), QPointF(0.0, 0.0)) self.pos = self.path.p2() self.res = QSize(1920, 1080) self.fps = 24.0 self.easing = QEasingCurve.Type.Linear self.time_max = 1.0 self.frames = [self.p1, self.p2]
def __init__(self, a: QPointF, b: QPointF, parent=None): super().__init__(parent=parent) self.setPen(QPen("#00CC00")) self._a: QPointF = a self._b: QPointF = b self.setLine(QLineF(self.a, self.b))
def __init__(self, pos, parent=None): super().__init__(parent=parent) self.setPen(QPen("#FFAA00")) self.anchor = pos self.setLine(QLineF(self.anchor[0], self.anchor[1], self.anchor[0], self.anchor[1]))
def from_pts(self, p1: QPointF, p2: QPointF, res: QSize, fps=24.0, tmax: float | None = None ): ln = QLineF(p1, p2) self.from_ln(ln, res, fps, QEasingCurve.Type.Linear, tmax)
def __init__( self, p1=QPointF(0.0, 0.0), p2=QPointF(0.0, 0.0), res=QSize(1920, 1080), fps=24.0, ease=QEasingCurve.Type.Linear, tmax: None | float = 1.0, ) -> None: self.from_line(QLineF(p1, p2), res, fps, ease, tmax)
def input_to_line_item(self, input_stream: QDataStream, item: QGraphicsLineItem): self.input_to_graphics_item(input_stream, item) # Type line = QLineF() pen = QPen() # Read input_stream >> line input_stream >> pen # Set item.setLine(line) item.setPen(pen)
def build(self) -> Path: if self.easing is None: raise ValueError("easing is None") if self.path is None: if self.p1 is None: raise ValueError("p1 is None - and no path") if self.p2 is None: raise ValueError("p2 is None - and no path") if self.time_max is None: raise ValueError("time_max is None") if self.easing is None: self.easing = QEasingCurve.Type.Linear ln, e = QLineF(self.p1, self.p2), self.easing else: ln = self.path rs, fp, tm = self.res, self.fps, self.time_max return Path.from_ln(ln, rs, fp, e, tm)
def from_steps( self, s1: Step, n2: Step, fps=24.0, tmax: float | None = 1.0, ease=QEasingCurve.Type.Linear ) -> None: ln = QLineF((s1.mouse_x, s1.mouse_y), (s2.mouse_x, s2.mouse_y)) res = Image.open(n1.img).size d1, d2 = s1.get_delay(), s2.get_delay() a1, a2 = s1.animated, s2.animated mh1 = QPointF(s1.mouse_hover[0], s1.mouse_hover[1]) hm1 = s1.has_mouse mp1, mp2 = s1.audio, s2.audio h1, h2 = s1.hover, h2.hover ht1, ht2 = s1.hover_time, s2.hover_time t1, t2 = s1.transition, s2.transition self.from_ln(line=ln, res=res, fps=fps, ease=ease, tmax=None)
def draw_simple_shape_to_scene(view: QGraphicsView, p_prev: QPointF, p_act: QPointF, to_gim: bool = True) -> None: if view.actual_selection.value in [2, 4]: width = math.fabs(p_prev.x() - p_act.x()) height = math.fabs(p_prev.y() - p_act.y()) xmin = min(p_prev.x(), p_act.x()) ymin = min(p_prev.y(), p_act.y()) item: QAbstractGraphicsShapeItem if view.actual_selection.value == 2: item = QGraphicsRectItem(0, 0, width, height) else: item = QGraphicsEllipseItem(0, 0, width, height) item.setPos(QPointF(xmin, ymin)) item.setPen(view.actual_pen) item.setBrush(view.actual_brush) DrawTools.set_item_flags(item) view.scene().addItem(item) view.gim.append_shape(item, item.type(), view.actual_pen, view.actual_brush) elif view.actual_selection.value in [3, 5, 6]: x = p_act.x() - p_prev.x() y = p_act.y() - p_prev.y() item: QGraphicsItem if view.actual_selection.value == 3: item = QGraphicsPolygonItem( QPolygonF( [QPointF(0, 0), QPointF(0 + x, 0), QPointF(x / 2, y)])) item.setBrush(view.actual_brush) else: item = QGraphicsLineItem(QLineF(0, 0, x, y)) item.setPos(p_prev) item.setPen(view.actual_pen) DrawTools.set_item_flags(item) view.scene().addItem(item) if to_gim: view.gim.append_shape(item, item.type(), view.actual_pen, view.actual_brush)
class Builder(QObject): p1: None | QPointF = None p2: None | QPointF = None fps: float = 24.0 res: QSize = QSize(0, 0) easing: QEasingCurve | None = None path: QLineF | None = None frames: List[QPointF] = field(default_factory=list) time_max: float | None = None @classmethod def default(self) -> None: self.path = QLineF(QPointF(0.0, 0.0), QPointF(0.0, 0.0)) self.pos = self.path.p2() self.res = QSize(1920, 1080) self.fps = 24.0 self.easing = QEasingCurve.Type.Linear self.time_max = 1.0 self.frames = [self.p1, self.p2] def build(self) -> Path: if self.easing is None: raise ValueError("easing is None") if self.path is None: if self.p1 is None: raise ValueError("p1 is None - and no path") if self.p2 is None: raise ValueError("p2 is None - and no path") if self.time_max is None: raise ValueError("time_max is None") if self.easing is None: self.easing = QEasingCurve.Type.Linear ln, e = QLineF(self.p1, self.p2), self.easing else: ln = self.path rs, fp, tm = self.res, self.fps, self.time_max return Path.from_ln(ln, rs, fp, e, tm)
def drag_line(self, follow_pos): self.setLine(QLineF(self.anchor[0], self.anchor[1], follow_pos[0], follow_pos[1]))
def b(self, val: QPointF): self._b = val self.setLine(QLineF(self.a, self.b))
def a(self, val: QPointF): self._a = val self.setLine(QLineF(self.a, self.b))
class Path(object): pos: QPointF frame_i: int = 0 time_i: float = 0.0 easing: QEasingCurve.Type = QEasingCurve.Type.Linear path: QLineF = field(default_factory=QLineF((0.0, 0.0), (0.0, 0.0))) frames: List[QPointF] = field(default_factory=list) time_max: None | float = 1.0 def __init__( self, p1=QPointF(0.0, 0.0), p2=QPointF(0.0, 0.0), res=QSize(1920, 1080), fps=24.0, ease=QEasingCurve.Type.Linear, tmax: None | float = 1.0, ) -> None: self.from_line(QLineF(p1, p2), res, fps, ease, tmax) def from_ln(self, line: QLineF, res: QSize, fps: float, ease: QEasingCurve.Type, tmax: float | None = None ): self.start() self.path = ln self.res = res self.fps = fps self.frames = [ln.p1(), ln.p2()] self.easing = ease self.time_max: None | float = tmax def from_pts(self, p1: QPointF, p2: QPointF, res: QSize, fps=24.0, tmax: float | None = None ): ln = QLineF(p1, p2) self.from_ln(ln, res, fps, QEasingCurve.Type.Linear, tmax) @classmethod def start(self) -> None: self.frame_i: int = 0 self.time_i: float = 0.0 @classmethod def end(self) -> None: self.frame_i = self.frame_len() self.time_i = self.time_len() @property def p1(self) -> QPointF: return self.path.p1() @property def p2(self) -> QPointF: return self.path.p2() @property def y2(self) -> float: return self.path.y2() @property def x2(self) -> float: return self.path.x2() @property def y1(self) -> float: return self.path.y1() @property def x1(self) -> float: return self.path.x1() def point_at(self, pct: float) -> QPointF: return self.path.pointAt(pct) def init_frames(self) -> List[QPointF]: return [] def frame_len(self) -> int: " The length of the animation in frames " return len(self.frames) def time_len(self) -> float: " The length of the animation in seconds " return round(self.frame_len() / self.fps) @property.setter(self, orig) def set_orig(self, o: QPointF) -> None: self.orig = value @property.setter(self, dest) def set_dest(self, d: QPointF) -> None: self.dest = value @property.setter(self, time_i) def set_time(self, t: float) -> None: self.time_i = t @property.setter(self, frame_i) def set_idx(self, i: int) -> None: self.frame_i = i @property.getter(self, index) def index(self) -> int: return self.frame_i @property.getter(self, time) def time(self) -> float: return self.time_i @property.setter(self, pos) def set_pos(self, p: QPointF) -> None: self.pos = p @property.setter(self, value) def set_time_max(self, tmax: float) -> None: self.time_max = tmax def pct_to_time(self, pct: float) -> float: return pct * self.time_len() def pct_path(self, pct: float) -> float: return self.path.center(pct) def from_sect(self, s: Section, fps=24.0, tmax: float|None = 1.0, ease=QEasingCurve.Type.Linear ): self.frames = [] step_n = len(s.steps) for i, step in enumerate(s.steps): if i == 0: self.frames.append(QPointF(step.mouse_x, step.mouse_y)) self.frames.append(QPointF(step.mouse_x, step.mouse_y)) else: self.from_pts(step.pos, s.steps[i-1].pos, s.res, fps, tmax) self.from_pts(sect.p1, sect.p2, sect.res, fps, tmax, ease) def from_steps( self, s1: Step, n2: Step, fps=24.0, tmax: float | None = 1.0, ease=QEasingCurve.Type.Linear ) -> None: ln = QLineF((s1.mouse_x, s1.mouse_y), (s2.mouse_x, s2.mouse_y)) res = Image.open(n1.img).size d1, d2 = s1.get_delay(), s2.get_delay() a1, a2 = s1.animated, s2.animated mh1 = QPointF(s1.mouse_hover[0], s1.mouse_hover[1]) hm1 = s1.has_mouse mp1, mp2 = s1.audio, s2.audio h1, h2 = s1.hover, h2.hover ht1, ht2 = s1.hover_time, s2.hover_time t1, t2 = s1.transition, s2.transition self.from_ln(line=ln, res=res, fps=fps, ease=ease, tmax=None) @classmethod def from_p1(self, p1: QPointF = QPointF(0.0, 0.0), tmax: float = 1.0): self.idx: int = 0 self.time: float = 0.0 self.easing = QEasingCurve.Type.Linear self.time_max: None | float = tmax self.pos = QPointF(p1) self.frames: List[QPointF] = [p1] def dist(self) -> float: return self.path.length() def center(self) -> QPointF: return self.path.center() def __append__(self, p: QPointF) -> None: self.frames.insert(index=len(self.frames)-1, obj=p) def __pop__(self) -> QPointF: return self.frames.pop(0) def __getitem__(self, i: int) -> QPointF: return self.frames[i] def __len__(self) -> int: return self.frame_len() def __str__(self) -> str: return self.__repr__() def __repr__(self) -> str: return f"{self.__class__.__name__}: " + \ f"(frame_i={self.frame_i}, time_i={self.time_i}, " + \ f"p1={self.p1}, p2={self.p2}, pos={self.pos}" + \ f"res={self.res}, fps={self.fps}, easing={self.easing})" + \ f" time_max={self.time_max}, frames={self.frames})" def __setitem__(self, i: int, p: QPointF) -> None: self.frames[i] = p def __next__(self) -> QPointF: self.idx += 1 if self.frame_i < len(self.frames) if self.time_i < self.time_max: else: self.idx += 1 self.time = self.time + 1.0/self.fps self.idx = 0 return self.frames[self.idx] def __iter__(self) -> bool: pass @dataclass class Builder(QObject): p1: None | QPointF = None p2: None | QPointF = None fps: float = 24.0 res: QSize = QSize(0, 0) easing: QEasingCurve | None = None path: QLineF | None = None frames: List[QPointF] = field(default_factory=list) time_max: float | None = None @classmethod def default(self) -> None: self.path = QLineF(QPointF(0.0, 0.0), QPointF(0.0, 0.0)) self.pos = self.path.p2() self.res = QSize(1920, 1080) self.fps = 24.0 self.easing = QEasingCurve.Type.Linear self.time_max = 1.0 self.frames = [self.p1, self.p2] def build(self) -> Path: if self.easing is None: raise ValueError("easing is None") if self.path is None: if self.p1 is None: raise ValueError("p1 is None - and no path") if self.p2 is None: raise ValueError("p2 is None - and no path") if self.time_max is None: raise ValueError("time_max is None") if self.easing is None: self.easing = QEasingCurve.Type.Linear ln, e = QLineF(self.p1, self.p2), self.easing else: ln = self.path rs, fp, tm = self.res, self.fps, self.time_max return Path.from_ln(ln, rs, fp, e, tm) easing: QEasingCurve.Type = QEasingCurve.Type.Linear path: Path = Path() orig: QPointF = QPointF(0.0, 0.0) dest: QPointF = QPointF(1920.0, 1080.0) t_lim: Optional[float] = None def t_at_pos(self, pos: QPointF = QPointF(0.0, 0.0)) -> float: """ Get the time of the easing function at position pos. """ return self.curr_pos t: float = 0.0 match self: case EasingFn.LINEAR: return pos case EasingFn.EASE_IN: return pos * pos case EasingFn.EASE_OUT: return t * (2.0 - t) case EasingFn.EASE_IN_OUT: return self.curr_t * self.curr_t * (2.0 - self.curr_t) case EasingFn.QUADRATIC: pass case EasingFn.CUBIC: pass case EasingFn.QUARTIC: pass return t def pos_at_t(self, t: float = 0.0) -> QPointF: """ Get the position of the easing function at time t. """ p: QPointF = QPointF(0.0, 0.0) match self.easing_fn: case EasingFn.LINEAR: return t case EasingFn.EASE_IN: return t * t case EasingFn.EASE_OUT: return t * (2 - t) case EasingFn.EASE_IN_OUT: if t < 0.5: return 2 * t * t else: return -2 * t * t + 4 * t - 1 case EasingFn.QUADRATIC: return t * t case EasingFn.CUBIC: return t * t * t case EasingFn.QUARTIC: return t * t * t * t return p