Blob Blame Raw
"""
Param.py
Will store the Parameters class for Synfig parameters 
"""

import sys
import copy
from lxml import etree
import settings
import common
import synfig.group
from synfig.animation import is_animated, get_bool_at_frame, get_vector_at_frame, print_animation
from properties.multiDimensionalKeyframed import gen_properties_multi_dimensional_keyframed
from properties.valueKeyframed import gen_value_Keyframed
sys.path.append("..")


class Param:
    """
    Class to keep Synfig format parameters
    """
    def __init__(self, param, parent):
        """
        This parent can be another parameter or a Layer
        """
        self.parent = parent
        self.param = param
        self.subparams = {}
        self.IS_ANIMATED = 0
        self.PATH_GENERATED = 0
        self.TRANSFORM_PATH_GENERATED = 0

    def get(self):
        """
        Returns the original param
        """
        return self.param

    def get_text(self):
        """
        Returns the text stored inside
        """
        return self.param.text

    def __getitem__(self, itr):
        """
        Returns the child corresponding to itr
        """
        return self.param[itr]

    def __setitem__(self, itr, val):
        """
        Sets the value of child corresponding to itr
        """
        self.param[itr] = val

    def get_layer_type(self):
        """
        Recursively go till the top until layer is not reached
        """
        if isinstance(self.parent, common.Layer.Layer):
            return self.parent.get_type()
        return self.parent.get_layer_type()

    def get_layer(self):
        """
        Recursively find the layer
        """
        if isinstance(self.parent, common.Layer.Layer):
            return self.parent
        return self.parent.get_layer()

    def getparent(self):
        """
        Returns the parent of this parameter
        """
        return self.parent

    def add_subparam(self, key, val):
        """
        Adds sub parameters
        """
        self.subparams[key] = val

    def get_subparam_dict(self):
        """
        Returns the address of the dict
        """
        return self.subparams

    def get_subparam(self, key):
        """
        Given a key, returns it's dictionary
        """
        return self.subparams[key]

    def animate(self, anim_type):
        """
        If this parameter is not animated, it generates dummy waypoints and
        animates this parameter
        """
        if self.IS_ANIMATED:
            return
        self.IS_ANIMATED = 1

        is_animate = common.misc.is_animated(self.param[0])
        if is_animate == 2:
            # If already animated, no need to add waypoints
            # Forcibly set it's animation type to the anim_type
            self.param[0].attrib["type"] = anim_type
            return
        elif is_animate == 0:
            st = '<animated type="{anim_type}"><waypoint time="0s" before="constant" after="constant"></waypoint></animated>'
            st = st.format(anim_type=anim_type)
            root = etree.fromstring(st)
            root[0].append(copy.deepcopy(self.param[0]))
            self.param[0] = root
        elif is_animate == 1:
            self.param[0].attrib["type"] = anim_type
            self.param[0][0].attrib["before"] = self.param[0][0].attrib["after"] = "constant"

        new_waypoint = copy.deepcopy(self.param[0][0])
        frame = common.misc.get_frame(self.param[0][0])
        frame += 1
        time = frame / settings.lottie_format["fr"]
        time = str(time) + 's'
        new_waypoint.attrib["time"] = time
        self.param[0].insert(1, new_waypoint)

    def gen_path(self, anim_type="real", idx=0):
        """
        Generates the path for this parameter over time depending on the
        animation type of this parameter
        """
        if self.PATH_GENERATED:
            return
        self.PATH_GENERATED, self.TRANSFORM_PATH_GENERATED = 1, 0

        self.path = {}
        if anim_type == "real":
            gen_value_Keyframed(self.path, self.param[0], idx)
        else:
            gen_properties_multi_dimensional_keyframed(self.path, self.param[0], idx)

    def get_path(self):
        """
        Returns the dictionary which stores the path of this parameter
        """
        return self.path

    def gen_path_with_transform(self, anim_type="vector", idx=0):
        """
        Generates the path for this parameter over time with transform_axis
        being set true
        """
        if self.TRANSFORM_PATH_GENERATED:
            return
        self.TRANSFORM_PATH_GENERATED, self.PATH_GENERATED = 1, 0
        self.path = {}
        # anim_type can not be real here
        self.param[0].attrib["transform_axis"] = "true"
        gen_properties_multi_dimensional_keyframed(self.path, self.param[0], idx)
        self.param[0].attrib["transform_axis"] = "false"

    def get_value(self, frame):
        """
        Returns the value of the parameter at a given frame
        """
        if self.param[0].attrib["type"] == "bool":  # No need of lottie format path here
            return get_bool_at_frame(self.param[0], frame)

        if not self.PATH_GENERATED and not self.TRANSFORM_PATH_GENERATED:
            raise KeyError("Please calculate the path of this parameter before getting value at a frame")
        return get_vector_at_frame(self.path, frame)

    def add_offset(self):
        """
        Updates the position parameter of Synfig format which has offset due to
        increase in widht and height of pre-comp layer(group layer)
        """
        # Only for 2-D animations
        offset = synfig.group.get_offset()
        is_animate = is_animated(self.param[0])
        if is_animate == 0:
            self.add(self.param[0], offset)
        else:
            for waypoint in self.param[0]:
                self.add(waypoint[0], offset)

    def add(self, vector, offset):
        """ 
        Helper function to modify Synfig xml

        Args:
            vector (lxml.etree._Element) : Position in Synfig format
            offset (common.Vector.Vector) : offset to be added to that position

        Returns:
            (None)
        """
        vector[0].text = str(float(vector[0].text) + offset[0])
        vector[1].text = str(float(vector[1].text) + offset[1])