def _convert_animation_value_to_float(self, prop: str, val: Union[str, int, float], event_args) -> Union[float, int]: """ Convert an animation property value to a numeric value. Args: prop: The name of the property to animate val: The animation target value (may be a string that contains a % sign) Returns: Numeric value (float or int). """ if val.startswith("(") and val.endswith(")"): try: val = event_args[val[1:-1]] except KeyError: raise AssertionError("Excepted an event parameter {}".format(val[1:-1])) try: val = percent_to_float(val, self._percent_prop_dicts[prop]) except KeyError: # because widget properties can include a % sign, they are # all strings, so even ones that aren't on the list to look # for percent signs have to be converted to numbers. if '.' in val: val = float(val) else: val = int(val) return val
def build_animation_from_config(self, config_list): """Build animation object from config.""" if not isinstance(config_list, list): raise TypeError('build_animation_from_config requires a list') # find any named animations and replace them with the real ones animation_list = list() for entry in config_list: if 'named_animation' in entry: for named_anim_settings in ( self.mc.animations[entry['named_animation']]): animation_list.append(named_anim_settings) else: animation_list.append(entry) final_anim = None repeat = False for settings in animation_list: prop_dict = dict() for prop, val in zip(settings['property'], settings['value']): try: val = percent_to_float(val, self._percent_prop_dicts[prop]) except KeyError: # because widget properties can include a % sign, they are # all strings, so even ones that aren't on the list to look # for percent signs have to be converted to numbers. if '.' in val: val = float(val) else: val = int(val) prop_dict[prop] = val if prop not in self._pre_animated_settings: self._pre_animated_settings[prop] = getattr(self, prop) anim = Animation(duration=settings['duration'], transition=settings['easing'], **prop_dict) if not final_anim: final_anim = anim elif settings['timing'] == 'with_previous': final_anim &= anim elif settings['timing'] == 'after_previous': final_anim += anim if settings['repeat']: repeat = True if repeat: final_anim.repeat = True return final_anim
def _calculate_y_position( parent_h: int, y: Optional[Union[int, str]] = None, round_y: Optional[Union[bool, str]] = None) -> float: # Set defaults if y is None: y = 'middle' # -------------------- # Y / height / vertical # -------------------- # Calculate position if isinstance(y, str): y = str(y).replace(' ', '') start_y = 0 if y.startswith('top'): y = y.strip('top') start_y = parent_h elif y.startswith('middle'): y = y.strip('middle') start_y = parent_h / 2 elif y.startswith('center'): y = y.strip('center') start_y = parent_h / 2 elif y.startswith('bottom'): y = y.strip('bottom') if not y: y = '0' y = percent_to_float(y, parent_h) y += start_y if round_y == 'bottom': y = math.floor(y) elif round_y == 'top': y = math.ceil(y) return y
def _calculate_x_position( parent_w: int, x: Optional[Union[int, str]] = None, round_x: Optional[Union[bool, str]] = None) -> float: # ---------------------- # X / width / horizontal # ---------------------- if x is None: x = 'center' # Calculate position if isinstance(x, str): x = str(x).replace(' ', '') start_x = 0 if x.startswith('right'): x = x.strip('right') start_x = parent_w elif x.startswith('middle'): x = x.strip('middle') start_x = parent_w / 2 elif x.startswith('center'): x = x.strip('center') start_x = parent_w / 2 elif x.startswith('left'): x = x.strip('left') if not x: x = '0' x = percent_to_float(x, parent_w) x += start_x if round_x == 'left': x = math.floor(x) elif round_x == 'right': x = math.ceil(x) return x
def _convert_animation_value_to_float( self, prop: str, val: Union[str, int, float]) -> Union[float, int]: """ Convert an animation property value to a numeric value. Args: prop: The name of the property to animate val: The animation target value (may be a string that contains a % sign) Returns: Numeric value (float or int). """ try: val = percent_to_float(val, self._percent_prop_dicts[prop]) except KeyError: # because widget properties can include a % sign, they are # all strings, so even ones that aren't on the list to look # for percent signs have to be converted to numbers. if '.' in val: val = float(val) else: val = int(val) return val
def test_percent_to_float(self): num = 1 total = 1 self.assertEqual(percent_to_float(num, total), 1.0) num = 1 total = 2 self.assertEqual(percent_to_float(num, total), 1.0) num = 0 total = 2 self.assertEqual(percent_to_float(num, total), 0.0) num = '1' total = 1 self.assertEqual(percent_to_float(num, total), 1.0) num = '1' total = 2 self.assertEqual(percent_to_float(num, total), 1.0) num = '0' total = 2 self.assertEqual(percent_to_float(num, total), 0.0) num = '100%' total = 1 self.assertEqual(percent_to_float(num, total), 1.0) num = '100%' total = 2 self.assertEqual(percent_to_float(num, total), 2.0) num = '0%' total = 2 self.assertEqual(percent_to_float(num, total), 0.0) num = '25%' total = 800 self.assertEqual(percent_to_float(num, total), 200.0) num = '200%' total = 1 self.assertEqual(percent_to_float(num, total), 2.0)
def calculate_initial_position( parent_w: int, parent_h: int, x: Optional[Union[int, str]] = None, y: Optional[Union[int, str]] = None, round_x: Optional[Union[bool, str]] = None, round_y: Optional[Union[bool, str]] = None) -> tuple: """Returns the initial x,y position for the widget within a larger parent frame based on several positioning parameters. This position will be combined with the widget anchor position to determine its actual position on the screen. Args: parent_w: Width of the parent frame. parent_h: Height of the parent frame. x: (Optional) Specifies the x (horizontal) position of the widget from the left edge of the slide. Can be a numeric value which represents the actual x value, or can be a percentage (string with percent sign, like '20%') which is set taking into account the size of the parent width. (e.g. parent width of 800 with x='20%' results in x=160. Can also be negative to position the widget partially off the left of the slide. Default value of None will return the horizontal center (parent width / 2). Can also start with the strings "left", "center", or "right" which can be combined with values. (e.g right-2, left+4, center-1) y: (Optional) Specifies the y (vertical) position of the widget from the bottom edge of the slide. Can be a numeric value which represents the actual y value, or can be a percentage (string with percent sign, like '20%') which is set taking into account the size of the parent height. (e.g. parent height of 600 with y='20%' results in y=120. Can also be negative to position the widget partially off the bottom of the slide. Default value of None will return the vertical center (parent height / 2). Can also start with the strings "top", "middle", or "bottom" which can be combined with values. (e.g top-2, bottom+4, middle-1) round_x: (Optional) Specifies a direction of either "left" or "right" to round the calculated pixel value for the horizontal position. Used to prevent partial pixel placement on DMDs, especially when position/anchors are specified in percentages round_y: (Optional) Specifies a direction of either "bottom" or "top" to round the calculated pixel value for the vertical position. Used to prevent partial pixel placement on DMDs, especially when position/anchors are specified in percentages Returns: Tuple of x, y coordinates for the lower-left corner of the widget you're placing. See the widgets documentation for examples. """ # Set defaults if x is None: x = 'center' if y is None: y = 'middle' # ---------------------- # X / width / horizontal # ---------------------- # Set position if isinstance(x, str): x = str(x).replace(' ', '') start_x = 0 if x.startswith('right'): x = x.strip('right') start_x = parent_w elif x.startswith('middle'): x = x.strip('middle') start_x = parent_w / 2 elif x.startswith('center'): x = x.strip('center') start_x = parent_w / 2 elif x.startswith('left'): x = x.strip('left') if not x: x = '0' x = percent_to_float(x, parent_w) x += start_x if round_x == 'left': x = math.floor(x) elif round_x == 'right': x = math.ceil(x) # -------------------- # Y / height / vertical # -------------------- # Set position if isinstance(y, str): y = str(y).replace(' ', '') start_y = 0 if y.startswith('top'): y = y.strip('top') start_y = parent_h elif y.startswith('middle'): y = y.strip('middle') start_y = parent_h / 2 elif y.startswith('center'): y = y.strip('center') start_y = parent_h / 2 elif y.startswith('bottom'): y = y.strip('bottom') if not y: y = '0' y = percent_to_float(y, parent_h) y += start_y if round_y == 'bottom': y = math.floor(y) elif round_y == 'top': y = math.ceil(y) return x, y