Source code for manim_dsa.m_collection.m_stack

from __future__ import annotations

from typing import Any, override

from manim import *
from manim.typing import Point3D, Vector3D

from manim_dsa.constants import *
from manim_dsa.m_collection.m_collection import *
from manim_dsa.utils.utils import *


[docs] class MStack(MCollection): """Manim Stack: a class for visualizing the stack data structure using the Manim animation engine. Parameters ---------- arr : list, optional The initial list of values to populate the stack. Default is an empty list. buff : float, optional The buffer (margin) between elements in the stack. Default is ``0.1``. style : :class:`MStackStyle._DefaultStyle`, optional The style configuration for the stack elements. Default is ``MStackStyle.DEFAULT``. """ def __init__( self, arr: list = [], buff: float = 0.1, style: MStackStyle._DefaultStyle = MStackStyle.DEFAULT, ): super().__init__(arr, UP, buff, style) elem = self.elements[0].square if self.elements else self._hidden_element.square container_height = ( (len(arr) + 3) * elem.height if arr else self._hidden_element.square.height * 7 ) self.bottom_line: Line = Line(ORIGIN, [elem.width + 2 * buff, 0, 0]).next_to( elem, DOWN, buff ) self.left_line: Line = Line([0, container_height, 0], ORIGIN).next_to( self.bottom_line, UL, 0 ) self.right_line: Line = self.left_line.copy().next_to(self.bottom_line, UR, 0) self.container: VGroup = VGroup( self.left_line, self.bottom_line, self.right_line ) self += self.container self.move_to(ORIGIN) self.spawnpoint: Point3D = None # When the stack is scaled or moved, # the spawn_point of the objects must be changed as well def update_stack_attr(obj): obj.spawnpoint = obj.get_spawn_point() obj.margin = buff * self._hidden_element.square.width self.add_updater(update_stack_attr)
[docs] def get_spawn_point(self) -> Point3D: """Calculates the drop point for new elements in the stack. Returns ------- :class:`~manim.typing.Point3D` The spawn point position in 3D space. """ return ( self.bottom_line.get_center() + (UP * self.right_line.height) + UP * self._hidden_element.square.width )
[docs] def append(self, value: Any) -> Self: """Appends a new value to the top of the stack. Parameters ---------- value : Any The value to be added to the stack. It will be converted to a string representation. Returns ------- self The instance of the :class:`MStack` with the newly appended element. """ return super().append(value)
@override_animate(append) def _append_animation(self, value: Any, anim_args: dict = None) -> Succession: """Creates an animation for appending a new value to the stack. Parameters ---------- value : Any The value to be added to the stack. It will be converted to a string representation. anim_args : dict, optional Additional animation arguments. Returns ------- :class:`~manim.animation.composition.Succession` The animation object representing the append operation. """ self.append(value) new_pos = self.elements[-1].get_center() self.elements[-1].move_to(self.spawnpoint) return Succession( Create(self.elements[-1]), ApplyMethod(self.elements[-1].move_to, new_pos), **anim_args, group=self, )
[docs] @override def pop(self) -> Self: """Removes the top element from the stack. Returns ------- self The instance of the :class:`MStack` with the top element removed. """ return super().pop(len(self.elements) - 1)
@override_animate(pop) def _pop_animation(self, anim_args: dict = None) -> Succession: """Creates an animation for removing the top element from the stack. Parameters ---------- anim_args : dict, optional Additional animation arguments. Returns ------- :class:`~manim.animation.composition.Succession` The animation object representing the pop operation. """ popped_element = self.elements[-1].copy() self.pop() return Succession( ApplyMethod(popped_element.move_to, self.spawnpoint), FadeOut(popped_element), **anim_args, group=VGroup(self, popped_element), )
[docs] def add_label( self, text: Text, direction: Vector3D = UP, buff: float = 0.5, **kwargs, ) -> Self: """Adds a label to the stack. Parameters ---------- text : :class:`~manim.mobject.text.text_mobject.Text` The label text. direction : :class:`~manim.typing.Vector3D`, optional The direction in which to position the label. Default is ``UP``. buff : float, optional The distance (buffer) between the stack and the label. Default is 0.5. **kwargs : Additional keyword arguments that are passed to the ``next_to()`` method of the underlying ``add_label`` method. Returns ------- self The instance of the :class:`MStack` with the label added. """ super().add_label(text, direction, buff, **kwargs) self.label.move_to(self.get_spawn_point()) return self