From 25c3d9ca5101845679fc47dd5169e3c45c17c79d Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Thu, 15 Aug 2024 19:29:22 +0200 Subject: [PATCH 01/17] segement_display_player default for flashing changed from not_set to off --- mpf/config_spec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpf/config_spec.yaml b/mpf/config_spec.yaml index 435229bf5..46067109d 100644 --- a/mpf/config_spec.yaml +++ b/mpf/config_spec.yaml @@ -1505,7 +1505,7 @@ segment_display_player: action: single|enum(add,remove,flash,no_flash,flash_match,flash_mask,set_color)|add transition: ignore transition_out: ignore - flashing: single|enum(off,all,match,mask,not_set)|not_set + flashing: single|enum(off,all,match,mask,not_set)|off flash_mask: single|str|None key: single|str|None expire: single|ms_or_token|None From 05fb459cfbd86651d65679345468adcc1bacbcf5 Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Thu, 15 Aug 2024 19:49:35 +0200 Subject: [PATCH 02/17] Initial implementation for update_method replace in segment_display --- .../segment_display/segment_display.py | 63 ++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/mpf/devices/segment_display/segment_display.py b/mpf/devices/segment_display/segment_display.py index 98a8c4344..6fe852d72 100644 --- a/mpf/devices/segment_display/segment_display.py +++ b/mpf/devices/segment_display/segment_display.py @@ -51,7 +51,7 @@ class SegmentDisplay(SystemWideDevice): __slots__ = ["hw_display", "size", "virtual_connector", "_text_stack", "_current_placeholder", "_current_text_stack_entry", "_transition_update_task", "_current_transition", "_default_color", - "_current_state", "_current_placeholder_future"] + "_current_state", "_current_placeholder_future", "_previous_text", "_previous_color", "_previous_transition_out"] config_section = 'segment_displays' collection = 'segment_displays' @@ -73,6 +73,9 @@ def __init__(self, machine, name: str) -> None: self._current_transition = None # type: Optional[TransitionRunner] self._default_color = None # type: Optional[RGBColor] self._current_state = None # type: Optional[SegmentDisplayState] + self._previous_text = None # Last text entry for transitions if update_method = replace + self._previous_color = None # Last color for transitions if update_method = replace + self._previous_transition_out = None # Last transistion_out if update_method = replace async def _initialize(self): """Initialize display.""" @@ -155,11 +158,57 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti raise ValueError(f"Unknown update_method '{self.config['update_method']}' for segment display {self.name}") # For the replace-text update method, skip the stack and write straight to the display - new_text = TextTemplate(self.machine, text).evaluate({}) - text = SegmentDisplayText.from_str(new_text, self.size, self.config['integrated_dots'], - self.config['integrated_commas'], self.config['use_dots_for_commas'], - color) - self._update_display(SegmentDisplayState(text, flashing, flash_mask)) + + ############################### + #Store current color and text as previous text/color of next run even if no transition in this step, + #the next step might have a transition, that the old text/color needs to be included into that transition + ############################### + + # Handle new and previous text + if self._previous_text: + previous_text = self._previous_text + else: + previous_text = "" + self._previous_text = text # Save the new text as the next previous text + + # Handle new and previous color + if self._previous_color: + previous_color = self._previous_color + else: + previous_color = self._default_color + self._previous_color = color # Save the new color as the next previous color + + if transition or self._previous_transition_out: + if transition: #if transition exists, then ignore transition_out of previous text/color + transition_conf = TransitionManager.get_transition(self.size, + self.config['integrated_dots'], + self.config['integrated_commas'], + self.config['use_dots_for_commas'], + transition) + elif self._previous_transition_out: + transition_conf = TransitionManager.get_transition(self.size, + self.config['integrated_dots'], + self.config['integrated_commas'], + self.config['use_dots_for_commas'], + self._previous_transition_out) + if transition_out: #in case transition_out is set we need to preserve it for the next step but only after the previous transition_out is in this step's config + self._previous_transition_out = transition_out + + #start transition + self._start_transition(transition_conf, previous_text, text, + previous_color, color, + self.config['default_transition_update_hz'], flashing, flash_mask) + + else: #No transition configured + if len(color) == 0: #no color set in show, case handled in transition, so extra treatment here for no transition + color = self._default_color + if transition_out: #in case transition_out is set we need to preserve it for the next step + self._previous_transition_out = transition_out + new_text = TextTemplate(self.machine, text).evaluate({}) + text = SegmentDisplayText.from_str(new_text, self.size, self.config['integrated_dots'], + self.config['integrated_commas'], self.config['use_dots_for_commas'], + color) + self._update_display(SegmentDisplayState(text, flashing, flash_mask)) def add_text(self, text: str, priority: int = 0, key: str = None) -> None: """Add text to display stack. @@ -171,7 +220,7 @@ def add_text(self, text: str, priority: int = 0, key: str = None) -> None: def remove_text_by_key(self, key: Optional[str]): """Remove entry from text stack.""" if self.config['update_method'] != "stack": - self.info_log("Segment display 'remove' action is TBD.") + self.add_text_entry("", self._previous_color, FlashingType.NO_FLASH, "", None, None, 100, key) return if key in self._text_stack: From 3d3673aa763d24ca7641d4060b47ebad66c0152b Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Wed, 28 Aug 2024 19:03:48 +0200 Subject: [PATCH 03/17] fixed transition_out issue if the next step doesnt have a transition_out --- mpf/devices/segment_display/segment_display.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mpf/devices/segment_display/segment_display.py b/mpf/devices/segment_display/segment_display.py index 6fe852d72..6d6f33423 100644 --- a/mpf/devices/segment_display/segment_display.py +++ b/mpf/devices/segment_display/segment_display.py @@ -191,6 +191,7 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti self.config['integrated_commas'], self.config['use_dots_for_commas'], self._previous_transition_out) + self._previous_transition_out = None # Once the transistion_out is played removed it that is not played in the next step again if transition_out: #in case transition_out is set we need to preserve it for the next step but only after the previous transition_out is in this step's config self._previous_transition_out = transition_out From 0b4777e2436bf14db06e507d96b32d6c3b50d0d0 Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Sat, 31 Aug 2024 10:30:04 +0200 Subject: [PATCH 04/17] fixed and clean up of color handling in segment displays --- .../segment_display/segment_display.py | 12 ++++--- .../segment_display/segment_display_text.py | 34 ++++++++++++------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/mpf/devices/segment_display/segment_display.py b/mpf/devices/segment_display/segment_display.py index 6d6f33423..1ac59a983 100644 --- a/mpf/devices/segment_display/segment_display.py +++ b/mpf/devices/segment_display/segment_display.py @@ -148,7 +148,14 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti This will replace texts with the same key. """ + + if len(color) == 0: + color = self._current_state.text.get_colors() + + if self.config['update_method'] == "stack": + + self._text_stack[key] = TextStackEntry( text, color, flashing, flash_mask, transition, transition_out, priority, key) self._update_stack() @@ -201,8 +208,6 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti self.config['default_transition_update_hz'], flashing, flash_mask) else: #No transition configured - if len(color) == 0: #no color set in show, case handled in transition, so extra treatment here for no transition - color = self._default_color if transition_out: #in case transition_out is set we need to preserve it for the next step self._previous_transition_out = transition_out new_text = TextTemplate(self.machine, text).evaluate({}) @@ -232,9 +237,8 @@ def remove_text_by_key(self, key: Optional[str]): def _start_transition(self, transition: TransitionBase, current_text: str, new_text: str, current_colors: List[RGBColor], new_colors: List[RGBColor], update_hz: float, flashing, flash_mask): + """Start the specified transition.""" - current_colors = self._expand_colors(current_colors, len(current_text)) - new_colors = self._expand_colors(new_colors, len(new_text)) if self._current_transition: self._stop_transition() self._current_transition = TransitionRunner(self.machine, transition, current_text, new_text, diff --git a/mpf/devices/segment_display/segment_display_text.py b/mpf/devices/segment_display/segment_display_text.py index 8ef8630c5..c37c9a572 100644 --- a/mpf/devices/segment_display/segment_display_text.py +++ b/mpf/devices/segment_display/segment_display_text.py @@ -76,28 +76,36 @@ def _create_characters(cls, text: str, display_size: int, collapse_dots: bool, c """Create characters from text and color them. - Colors are used from the left to the right (starting with the first character). - - If colors are shorter than text the last color is repeated for text. - - The first color is used to pad the text to the left if text is shorter than the display - thus text is right - aligned. - Dots and commas are embedded on the fly. + - Text will be right aligned on the display, thus if text is shorter than display spaces will be padded before the text + - Provided colors are assumed to be for the text itself, thus the list of colors is "right aligned" too + - If list of colors is less than the display size the list will be extended with white as default color on the left endswith + so that the provided colors are for the text and not being used for invisible spaces """ char_list = [] - left_pad_color = colors[0] if colors else None - default_right_color = colors[len(colors) - 1] if colors else None uncolored_chars = cls._embed_dots_and_commas(text, collapse_dots, collapse_commas, use_dots_for_commas) - colors = colors[-len(uncolored_chars):] - for char_code, char_has_dot, char_has_comma in uncolored_chars: - color = colors.pop(0) if colors else default_right_color - char_list.append(DisplayCharacter(char_code, char_has_dot, char_has_comma, color)) - # ensure list is the same size as the segment display (cut off on left or right justify characters) - current_length = len(char_list) + # Adujust the color array if needed + color_length = len(colors) + if color_length > display_size: + for _ in range(color_length - display_size): + colors.pop(0) # remove very left color of array if too long + elif color_length < display_size: + for _ in range(display_size - color_length): + colors.append(RGBColor("white")) # add default color on the left of the array if too few colors + + # ensure list is the same size as the segment display (cut off on left if too long or right justify characters if too short) + current_length = len(uncolored_chars) if current_length > display_size: for _ in range(current_length - display_size): - char_list.pop(0) + uncolored_chars.pop(0) # remove very left char of array if too long elif current_length < display_size: for _ in range(display_size - current_length): - char_list.insert(0, DisplayCharacter(SPACE_CODE, False, False, left_pad_color)) + uncolored_chars.insert(0, (SPACE_CODE, False, False)) + + for _ in range(len(uncolored_chars)): + color = colors[_] + char_list.append(DisplayCharacter(uncolored_chars[_][0], uncolored_chars[_][1], uncolored_chars[_][2], color)) return char_list From 2f6d028eec285449c11535aca2eb37dd5259aef9 Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Tue, 17 Sep 2024 20:47:49 +0200 Subject: [PATCH 05/17] mainly feedback from last PR, plus improved clear context --- mpf/config_players/segment_display_player.py | 23 ++++-- .../segment_display/segment_display.py | 70 ++++++++++--------- .../segment_display/segment_display_text.py | 24 +++---- 3 files changed, 63 insertions(+), 54 deletions(-) diff --git a/mpf/config_players/segment_display_player.py b/mpf/config_players/segment_display_player.py index 9862e8a2c..a574a9b87 100644 --- a/mpf/config_players/segment_display_player.py +++ b/mpf/config_players/segment_display_player.py @@ -106,12 +106,23 @@ def _remove(self, instance_dict, key, display): del instance_dict[display][key] def clear_context(self, context): - """Remove all texts.""" - instance_dict = self._get_instance_dict(context) - for display, keys in instance_dict.items(): - for key in dict(keys).keys(): - self._remove(instance_dict=instance_dict, - key=key, display=display) + + ############## + # Remove all texts. Ignore what keys are available, that will be checked later in the segment display code. + # Especially important for update_method replace since there are no keys. + ############## + + instance_dict = self._get_instance_dict(context) # key of the dict is the display, the value is another dict + + for display, keys_dict in instance_dict.items(): # keys_dict key is the show key, the value is a boolean (with yet unknown usage) + if(keys_dict): #depending on the situation the keys_dict might be empty, still need to clear the display + for key in dict(keys_dict).keys(): + display.clear_segment_display(key) + if instance_dict[display][key] is not True: + self.delay.remove(instance_dict[display][key]) + del instance_dict[display][key] + else: + display.clear_segment_display(None) self._reset_instance_dict(context) diff --git a/mpf/devices/segment_display/segment_display.py b/mpf/devices/segment_display/segment_display.py index 1ac59a983..1c4371d42 100644 --- a/mpf/devices/segment_display/segment_display.py +++ b/mpf/devices/segment_display/segment_display.py @@ -89,8 +89,14 @@ async def _initialize(self): self.size = self.config['size'] self._default_color = [RGBColor(color) for color in self.config["default_color"][0:self.size]] - if len(self._default_color) < self.size: - self._default_color += [RGBColor("white")] * (self.size - len(self._default_color)) + + if (len(self._default_color)) == 1: + self._default_color = self._default_color * self.size + elif len(self._default_color) != self.size: + self.warning_log("The amount of colors you specified for your text has to be either equal to " + "the amount of digits in your display or equals 1. Your display has a size of %s and the " + "amount of colors specified is %s. All display colors will be set to white.", self.size, len(self._default_color)) + self._default_color = [RGBColor("white")] * self.size # configure hardware try: @@ -148,11 +154,9 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti This will replace texts with the same key. """ - - if len(color) == 0: + if not color: color = self._current_state.text.get_colors() - if self.config['update_method'] == "stack": @@ -172,35 +176,19 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti ############################### # Handle new and previous text - if self._previous_text: - previous_text = self._previous_text - else: - previous_text = "" + previous_text = self._previous_text or "" self._previous_text = text # Save the new text as the next previous text # Handle new and previous color - if self._previous_color: - previous_color = self._previous_color - else: - previous_color = self._default_color + previous_color = self._previous_color or self._default_color self._previous_color = color # Save the new color as the next previous color if transition or self._previous_transition_out: - if transition: #if transition exists, then ignore transition_out of previous text/color - transition_conf = TransitionManager.get_transition(self.size, - self.config['integrated_dots'], - self.config['integrated_commas'], - self.config['use_dots_for_commas'], - transition) - elif self._previous_transition_out: - transition_conf = TransitionManager.get_transition(self.size, - self.config['integrated_dots'], - self.config['integrated_commas'], - self.config['use_dots_for_commas'], - self._previous_transition_out) - self._previous_transition_out = None # Once the transistion_out is played removed it that is not played in the next step again - if transition_out: #in case transition_out is set we need to preserve it for the next step but only after the previous transition_out is in this step's config - self._previous_transition_out = transition_out + transition_conf = TransitionManager.get_transition(self.size, + self.config['integrated_dots'], + self.config['integrated_commas'], + self.config['use_dots_for_commas'], + transition or self._previous_transition_out) #start transition self._start_transition(transition_conf, previous_text, text, @@ -216,6 +204,12 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti color) self._update_display(SegmentDisplayState(text, flashing, flash_mask)) + ############################### + # Once the transistion_out is played, removed it that is not played in the next step again, but in case transition_out is set in the current step + # then we need to preserve it for the next step but only after the previous step's transition_out is in this step's config (or the transition of the current step) + ############################### + self._previous_transition_out = transition_out or None + def add_text(self, text: str, priority: int = 0, key: str = None) -> None: """Add text to display stack. @@ -225,13 +219,23 @@ def add_text(self, text: str, priority: int = 0, key: str = None) -> None: def remove_text_by_key(self, key: Optional[str]): """Remove entry from text stack.""" - if self.config['update_method'] != "stack": + if self.config['update_method'] == "stack": + if key in self._text_stack: + del self._text_stack[key] + self._update_stack() + else: # must be update_method replace, send empyt text since no key in that case self.add_text_entry("", self._previous_color, FlashingType.NO_FLASH, "", None, None, 100, key) - return - if key in self._text_stack: - del self._text_stack[key] - self._update_stack() + + def clear_segment_display(self, key: Optional[str]): + """Clear segment dispaly if context is removed from player.""" + + if self.config['update_method'] == "replace": + self._stop_transition() + self._previous_transition_out = None + + self.remove_text_by_key(key) + # pylint: disable=too-many-arguments def _start_transition(self, transition: TransitionBase, current_text: str, new_text: str, diff --git a/mpf/devices/segment_display/segment_display_text.py b/mpf/devices/segment_display/segment_display_text.py index c37c9a572..60b28dc64 100644 --- a/mpf/devices/segment_display/segment_display_text.py +++ b/mpf/devices/segment_display/segment_display_text.py @@ -74,25 +74,19 @@ def _embed_dots_and_commas(cls, text: str, collapse_dots: bool, collapse_commas: def _create_characters(cls, text: str, display_size: int, collapse_dots: bool, collapse_commas: bool, use_dots_for_commas: bool, colors: List[Optional[RGBColor]]) -> List[DisplayCharacter]: """Create characters from text and color them. - - - Colors are used from the left to the right (starting with the first character). - Dots and commas are embedded on the fly. - Text will be right aligned on the display, thus if text is shorter than display spaces will be padded before the text - - Provided colors are assumed to be for the text itself, thus the list of colors is "right aligned" too - - If list of colors is less than the display size the list will be extended with white as default color on the left endswith - so that the provided colors are for the text and not being used for invisible spaces + - If list of colors is less than the display size then all white will be used, if only one color is given that will be used for the full display """ char_list = [] uncolored_chars = cls._embed_dots_and_commas(text, collapse_dots, collapse_commas, use_dots_for_commas) # Adujust the color array if needed - color_length = len(colors) - if color_length > display_size: - for _ in range(color_length - display_size): - colors.pop(0) # remove very left color of array if too long - elif color_length < display_size: - for _ in range(display_size - color_length): - colors.append(RGBColor("white")) # add default color on the left of the array if too few colors + if (len(colors)) == 1: + colors = colors * display_size + elif len(colors) != display_size: + #TODO: Log that colors were adjusted to white as default + colors = [RGBColor("white")] * display_size # ensure list is the same size as the segment display (cut off on left if too long or right justify characters if too short) current_length = len(uncolored_chars) @@ -103,9 +97,9 @@ def _create_characters(cls, text: str, display_size: int, collapse_dots: bool, c for _ in range(display_size - current_length): uncolored_chars.insert(0, (SPACE_CODE, False, False)) - for _ in range(len(uncolored_chars)): - color = colors[_] - char_list.append(DisplayCharacter(uncolored_chars[_][0], uncolored_chars[_][1], uncolored_chars[_][2], color)) + for i, char in enumerate(uncolored_chars): + color = colors[i] + char_list.append(DisplayCharacter(char[0], char[1], char[2], color)) #0: char code 1: char_has_dot 2: char_has_comma return char_list From b9fc7b6267a2b6a1f1be541d115d1e6c7753b466 Mon Sep 17 00:00:00 2001 From: worldpeace-germany <69395448+worldpeace-germany@users.noreply.github.com> Date: Sun, 12 Jan 2025 16:12:10 +0100 Subject: [PATCH 06/17] Update segment_display_player.py comments improved --- mpf/config_players/segment_display_player.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mpf/config_players/segment_display_player.py b/mpf/config_players/segment_display_player.py index a574a9b87..11e07b718 100644 --- a/mpf/config_players/segment_display_player.py +++ b/mpf/config_players/segment_display_player.py @@ -107,10 +107,8 @@ def _remove(self, instance_dict, key, display): def clear_context(self, context): - ############## # Remove all texts. Ignore what keys are available, that will be checked later in the segment display code. # Especially important for update_method replace since there are no keys. - ############## instance_dict = self._get_instance_dict(context) # key of the dict is the display, the value is another dict From 66b5e1fee3737dd403d93e860e4e984d9c55e43b Mon Sep 17 00:00:00 2001 From: worldpeace-germany <69395448+worldpeace-germany@users.noreply.github.com> Date: Sun, 12 Jan 2025 16:13:14 +0100 Subject: [PATCH 07/17] Update segment_display.py comments improved --- mpf/devices/segment_display/segment_display.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mpf/devices/segment_display/segment_display.py b/mpf/devices/segment_display/segment_display.py index 1c4371d42..04638696e 100644 --- a/mpf/devices/segment_display/segment_display.py +++ b/mpf/devices/segment_display/segment_display.py @@ -170,10 +170,8 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti # For the replace-text update method, skip the stack and write straight to the display - ############################### - #Store current color and text as previous text/color of next run even if no transition in this step, - #the next step might have a transition, that the old text/color needs to be included into that transition - ############################### + # Store current color and text as previous text/color of next run even if no transition in this step, + # the next step might have a transition, that the old text/color needs to be included into that transition # Handle new and previous text previous_text = self._previous_text or "" From 8217e6f5772d679e087cfbefded2641a6085657d Mon Sep 17 00:00:00 2001 From: worldpeace-germany <69395448+worldpeace-germany@users.noreply.github.com> Date: Sun, 12 Jan 2025 16:13:45 +0100 Subject: [PATCH 08/17] Update segment_display_text.py --- mpf/devices/segment_display/segment_display_text.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpf/devices/segment_display/segment_display_text.py b/mpf/devices/segment_display/segment_display_text.py index 60b28dc64..c18cccc91 100644 --- a/mpf/devices/segment_display/segment_display_text.py +++ b/mpf/devices/segment_display/segment_display_text.py @@ -81,7 +81,7 @@ def _create_characters(cls, text: str, display_size: int, collapse_dots: bool, c char_list = [] uncolored_chars = cls._embed_dots_and_commas(text, collapse_dots, collapse_commas, use_dots_for_commas) - # Adujust the color array if needed + # Adjust the color array if needed if (len(colors)) == 1: colors = colors * display_size elif len(colors) != display_size: From fcb590af3221fe6d9a006fab340535fa29676873 Mon Sep 17 00:00:00 2001 From: worldpeace-germany <69395448+worldpeace-germany@users.noreply.github.com> Date: Sun, 12 Jan 2025 17:31:24 +0100 Subject: [PATCH 09/17] Update segment_display_player.py not needed parenthesis removed --- mpf/config_players/segment_display_player.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpf/config_players/segment_display_player.py b/mpf/config_players/segment_display_player.py index 11e07b718..37c7e110a 100644 --- a/mpf/config_players/segment_display_player.py +++ b/mpf/config_players/segment_display_player.py @@ -113,7 +113,7 @@ def clear_context(self, context): instance_dict = self._get_instance_dict(context) # key of the dict is the display, the value is another dict for display, keys_dict in instance_dict.items(): # keys_dict key is the show key, the value is a boolean (with yet unknown usage) - if(keys_dict): #depending on the situation the keys_dict might be empty, still need to clear the display + if keys_dict: #depending on the situation the keys_dict might be empty, still need to clear the display for key in dict(keys_dict).keys(): display.clear_segment_display(key) if instance_dict[display][key] is not True: From 2794923b9672b882ce79a632d4b90f3a130fb604 Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Thu, 16 Jan 2025 17:43:43 +0100 Subject: [PATCH 10/17] Lint issues fixed --- mpf/config_players/segment_display_player.py | 11 +++++------ .../segment_display/.segment_display.py.kate-swp | Bin 0 -> 1980 bytes .../segment_display/segment_display_text.py | 13 ++++++++----- 3 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 mpf/devices/segment_display/.segment_display.py.kate-swp diff --git a/mpf/config_players/segment_display_player.py b/mpf/config_players/segment_display_player.py index 37c7e110a..27bfb2e2b 100644 --- a/mpf/config_players/segment_display_player.py +++ b/mpf/config_players/segment_display_player.py @@ -106,14 +106,13 @@ def _remove(self, instance_dict, key, display): del instance_dict[display][key] def clear_context(self, context): + """Remove all texts. Ignore what keys are available, that will be checked later in the segment display code. + Especially important for update_method replace since there are no keys.""" - # Remove all texts. Ignore what keys are available, that will be checked later in the segment display code. - # Especially important for update_method replace since there are no keys. + instance_dict = self._get_instance_dict(context) # key of the dict is the display, the value is another dict - instance_dict = self._get_instance_dict(context) # key of the dict is the display, the value is another dict - - for display, keys_dict in instance_dict.items(): # keys_dict key is the show key, the value is a boolean (with yet unknown usage) - if keys_dict: #depending on the situation the keys_dict might be empty, still need to clear the display + for display, keys_dict in instance_dict.items(): # keys_dict key is the show key, value is bool(unknown usage) + if keys_dict: #depending on the situation the keys_dict might be empty, still need to clear the display for key in dict(keys_dict).keys(): display.clear_segment_display(key) if instance_dict[display][key] is not True: diff --git a/mpf/devices/segment_display/.segment_display.py.kate-swp b/mpf/devices/segment_display/.segment_display.py.kate-swp new file mode 100644 index 0000000000000000000000000000000000000000..c940cf7dff1e4a5da2b6ac452f904686cb9e3b32 GIT binary patch literal 1980 zcmaKt&1w`u5XWc1LsSSc#uzn$Mh~78@e{i?eAUzHj*%d*Lb{i+PbPJbBgZ)}#~`qgV$ zmQ5X7d-eLqpT7rhXZ8n6`v+g2-kp9|Jg`X5?4DWYVt(W=*M1XSIgCECy=O*rB`;cT zll}j*ytLeUDC9+6tXiPQ#oW_3V@-tCN+%~Q+^J7C51(>m(vj1SOgVDKk!eTHIx^$P zIY-Vra>0>VAv8iOg=nP^trVh_LbOtdRtnKdAzCR!D}`vK5UmuVl|p=_b4JtulpNM< zYX-z+2%F2gaXK0|-So_ow2Kh!B1F3g(Jn%?ixBN1M7s#lE<&`65bYvFy9m)PLbQtz zTGD*X_(kpWmEb+Dz4-Mu*@vHBolM@E8EZ~j-FEWgiRHXG+Bo^%Y~C#O9&*Exn~roH zS#V_0ktIiN3He~2>Vc>pi0XlK%~BN*)dNvI5Y+=wJs*vz9*F9Js2)hyEa`zPIHG#U zQ9TgV^T~+nfv6sc>Vc>pi0XkXnkCH;)dNX-nA<%w*5x==dvQ*`L List[DisplayCharacter]: """Create characters from text and color them. - Dots and commas are embedded on the fly. - - Text will be right aligned on the display, thus if text is shorter than display spaces will be padded before the text - - If list of colors is less than the display size then all white will be used, if only one color is given that will be used for the full display + - Text will be right aligned on the display, if text is shorter than display spaces add on the left + - If list of colors is less than the display size then all white will be used, + - If only one color is given that will be used for the full display """ char_list = [] uncolored_chars = cls._embed_dots_and_commas(text, collapse_dots, collapse_commas, use_dots_for_commas) @@ -88,18 +89,20 @@ def _create_characters(cls, text: str, display_size: int, collapse_dots: bool, c #TODO: Log that colors were adjusted to white as default colors = [RGBColor("white")] * display_size - # ensure list is the same size as the segment display (cut off on left if too long or right justify characters if too short) + # ensure list is the same size as the segment display + # cut off on left if too long or right justify characters if too short current_length = len(uncolored_chars) if current_length > display_size: for _ in range(current_length - display_size): - uncolored_chars.pop(0) # remove very left char of array if too long + uncolored_chars.pop(0) # remove very left char of array if too long elif current_length < display_size: for _ in range(display_size - current_length): uncolored_chars.insert(0, (SPACE_CODE, False, False)) for i, char in enumerate(uncolored_chars): color = colors[i] - char_list.append(DisplayCharacter(char[0], char[1], char[2], color)) #0: char code 1: char_has_dot 2: char_has_comma + #0: char code 1: char_has_dot 2: char_has_comma + char_list.append(DisplayCharacter(char[0], char[1], char[2], color)) return char_list From 57c5a1106bb2b8f4834f57b1cdf2fa633b4fb63e Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Thu, 16 Jan 2025 17:54:31 +0100 Subject: [PATCH 11/17] Lint issues fixed --- mpf/config_players/segment_display_player.py | 9 ++-- .../.segment_display.py.kate-swp | Bin 1980 -> 0 bytes .../segment_display/segment_display.py | 40 +++++++++--------- .../segment_display/segment_display_text.py | 5 ++- 4 files changed, 27 insertions(+), 27 deletions(-) delete mode 100644 mpf/devices/segment_display/.segment_display.py.kate-swp diff --git a/mpf/config_players/segment_display_player.py b/mpf/config_players/segment_display_player.py index 27bfb2e2b..a5b93ae1c 100644 --- a/mpf/config_players/segment_display_player.py +++ b/mpf/config_players/segment_display_player.py @@ -106,13 +106,14 @@ def _remove(self, instance_dict, key, display): del instance_dict[display][key] def clear_context(self, context): - """Remove all texts. Ignore what keys are available, that will be checked later in the segment display code. - Especially important for update_method replace since there are no keys.""" - + """ + Remove all texts. Ignore what keys are available, that will be checked later in the segment display code. + Especially important for update_method replace since there are no keys. + """ instance_dict = self._get_instance_dict(context) # key of the dict is the display, the value is another dict for display, keys_dict in instance_dict.items(): # keys_dict key is the show key, value is bool(unknown usage) - if keys_dict: #depending on the situation the keys_dict might be empty, still need to clear the display + if keys_dict: # depending on the situation the keys_dict might be empty, still need to clear the display for key in dict(keys_dict).keys(): display.clear_segment_display(key) if instance_dict[display][key] is not True: diff --git a/mpf/devices/segment_display/.segment_display.py.kate-swp b/mpf/devices/segment_display/.segment_display.py.kate-swp deleted file mode 100644 index c940cf7dff1e4a5da2b6ac452f904686cb9e3b32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1980 zcmaKt&1w`u5XWc1LsSSc#uzn$Mh~78@e{i?eAUzHj*%d*Lb{i+PbPJbBgZ)}#~`qgV$ zmQ5X7d-eLqpT7rhXZ8n6`v+g2-kp9|Jg`X5?4DWYVt(W=*M1XSIgCECy=O*rB`;cT zll}j*ytLeUDC9+6tXiPQ#oW_3V@-tCN+%~Q+^J7C51(>m(vj1SOgVDKk!eTHIx^$P zIY-Vra>0>VAv8iOg=nP^trVh_LbOtdRtnKdAzCR!D}`vK5UmuVl|p=_b4JtulpNM< zYX-z+2%F2gaXK0|-So_ow2Kh!B1F3g(Jn%?ixBN1M7s#lE<&`65bYvFy9m)PLbQtz zTGD*X_(kpWmEb+Dz4-Mu*@vHBolM@E8EZ~j-FEWgiRHXG+Bo^%Y~C#O9&*Exn~roH zS#V_0ktIiN3He~2>Vc>pi0XlK%~BN*)dNvI5Y+=wJs*vz9*F9Js2)hyEa`zPIHG#U zQ9TgV^T~+nfv6sc>Vc>pi0XkXnkCH;)dNX-nA<%w*5x==dvQ*`L None: @@ -221,25 +223,21 @@ def remove_text_by_key(self, key: Optional[str]): if key in self._text_stack: del self._text_stack[key] self._update_stack() - else: # must be update_method replace, send empyt text since no key in that case + else: # must be update_method replace, send empyt text since no key in that case self.add_text_entry("", self._previous_color, FlashingType.NO_FLASH, "", None, None, 100, key) - def clear_segment_display(self, key: Optional[str]): """Clear segment dispaly if context is removed from player.""" - if self.config['update_method'] == "replace": self._stop_transition() self._previous_transition_out = None self.remove_text_by_key(key) - # pylint: disable=too-many-arguments def _start_transition(self, transition: TransitionBase, current_text: str, new_text: str, current_colors: List[RGBColor], new_colors: List[RGBColor], update_hz: float, flashing, flash_mask): - """Start the specified transition.""" if self._current_transition: self._stop_transition() diff --git a/mpf/devices/segment_display/segment_display_text.py b/mpf/devices/segment_display/segment_display_text.py index 8d7188860..bb0103485 100644 --- a/mpf/devices/segment_display/segment_display_text.py +++ b/mpf/devices/segment_display/segment_display_text.py @@ -73,7 +73,8 @@ def _embed_dots_and_commas(cls, text: str, collapse_dots: bool, collapse_commas: @classmethod def _create_characters(cls, text: str, display_size: int, collapse_dots: bool, collapse_commas: bool, use_dots_for_commas: bool, colors: List[Optional[RGBColor]]) -> List[DisplayCharacter]: - """Create characters from text and color them. + """ + Create characters from text and color them. - Dots and commas are embedded on the fly. - Text will be right aligned on the display, if text is shorter than display spaces add on the left - If list of colors is less than the display size then all white will be used, @@ -94,7 +95,7 @@ def _create_characters(cls, text: str, display_size: int, collapse_dots: bool, c current_length = len(uncolored_chars) if current_length > display_size: for _ in range(current_length - display_size): - uncolored_chars.pop(0) # remove very left char of array if too long + uncolored_chars.pop(0) # remove very left char of array if too long elif current_length < display_size: for _ in range(display_size - current_length): uncolored_chars.insert(0, (SPACE_CODE, False, False)) From 55f3f02899f3cace6b82e7b256a831bc3cab2842 Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Thu, 16 Jan 2025 18:02:45 +0100 Subject: [PATCH 12/17] Lint issues fixed --- mpf/config_players/segment_display_player.py | 4 ++-- mpf/devices/segment_display/segment_display.py | 2 +- mpf/devices/segment_display/segment_display_text.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mpf/config_players/segment_display_player.py b/mpf/config_players/segment_display_player.py index a5b93ae1c..01b836725 100644 --- a/mpf/config_players/segment_display_player.py +++ b/mpf/config_players/segment_display_player.py @@ -106,10 +106,10 @@ def _remove(self, instance_dict, key, display): del instance_dict[display][key] def clear_context(self, context): - """ - Remove all texts. Ignore what keys are available, that will be checked later in the segment display code. + """Remove all texts. Ignore what keys are available, that will be checked later in the segment display code. Especially important for update_method replace since there are no keys. """ + instance_dict = self._get_instance_dict(context) # key of the dict is the display, the value is another dict for display, keys_dict in instance_dict.items(): # keys_dict key is the show key, value is bool(unknown usage) diff --git a/mpf/devices/segment_display/segment_display.py b/mpf/devices/segment_display/segment_display.py index 462fcb2fd..8e1263968 100644 --- a/mpf/devices/segment_display/segment_display.py +++ b/mpf/devices/segment_display/segment_display.py @@ -194,7 +194,7 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti previous_color, color, self.config['default_transition_update_hz'], flashing, flash_mask) - else: # No transition configured + else: # No transition configured if transition_out: # in case transition_out is set we need to preserve it for the next step self._previous_transition_out = transition_out new_text = TextTemplate(self.machine, text).evaluate({}) diff --git a/mpf/devices/segment_display/segment_display_text.py b/mpf/devices/segment_display/segment_display_text.py index bb0103485..3ffd02631 100644 --- a/mpf/devices/segment_display/segment_display_text.py +++ b/mpf/devices/segment_display/segment_display_text.py @@ -73,13 +73,13 @@ def _embed_dots_and_commas(cls, text: str, collapse_dots: bool, collapse_commas: @classmethod def _create_characters(cls, text: str, display_size: int, collapse_dots: bool, collapse_commas: bool, use_dots_for_commas: bool, colors: List[Optional[RGBColor]]) -> List[DisplayCharacter]: - """ - Create characters from text and color them. + """Create characters from text and color them. - Dots and commas are embedded on the fly. - Text will be right aligned on the display, if text is shorter than display spaces add on the left - If list of colors is less than the display size then all white will be used, - If only one color is given that will be used for the full display """ + char_list = [] uncolored_chars = cls._embed_dots_and_commas(text, collapse_dots, collapse_commas, use_dots_for_commas) From 67dcd6accd9f342a77dcf57bc54f4965a59642a0 Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Thu, 16 Jan 2025 18:06:13 +0100 Subject: [PATCH 13/17] Lint issues fixed --- mpf/config_players/segment_display_player.py | 5 +++-- mpf/devices/segment_display/segment_display_text.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mpf/config_players/segment_display_player.py b/mpf/config_players/segment_display_player.py index 01b836725..7b5a18554 100644 --- a/mpf/config_players/segment_display_player.py +++ b/mpf/config_players/segment_display_player.py @@ -106,10 +106,11 @@ def _remove(self, instance_dict, key, display): del instance_dict[display][key] def clear_context(self, context): - """Remove all texts. Ignore what keys are available, that will be checked later in the segment display code. + """Remove all texts. + + Ignore what keys are available, that will be checked later in the segment display code. Especially important for update_method replace since there are no keys. """ - instance_dict = self._get_instance_dict(context) # key of the dict is the display, the value is another dict for display, keys_dict in instance_dict.items(): # keys_dict key is the show key, value is bool(unknown usage) diff --git a/mpf/devices/segment_display/segment_display_text.py b/mpf/devices/segment_display/segment_display_text.py index 3ffd02631..2b1419ac7 100644 --- a/mpf/devices/segment_display/segment_display_text.py +++ b/mpf/devices/segment_display/segment_display_text.py @@ -74,12 +74,12 @@ def _embed_dots_and_commas(cls, text: str, collapse_dots: bool, collapse_commas: def _create_characters(cls, text: str, display_size: int, collapse_dots: bool, collapse_commas: bool, use_dots_for_commas: bool, colors: List[Optional[RGBColor]]) -> List[DisplayCharacter]: """Create characters from text and color them. + - Dots and commas are embedded on the fly. - Text will be right aligned on the display, if text is shorter than display spaces add on the left - If list of colors is less than the display size then all white will be used, - If only one color is given that will be used for the full display """ - char_list = [] uncolored_chars = cls._embed_dots_and_commas(text, collapse_dots, collapse_commas, use_dots_for_commas) From 7e65d9d89d6597ddde975e3e39af995c5aab4269 Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Thu, 16 Jan 2025 19:48:21 +0100 Subject: [PATCH 14/17] feedback of PR implemented --- mpf/devices/segment_display/segment_display.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mpf/devices/segment_display/segment_display.py b/mpf/devices/segment_display/segment_display.py index 8e1263968..2a17d8fe3 100644 --- a/mpf/devices/segment_display/segment_display.py +++ b/mpf/devices/segment_display/segment_display.py @@ -195,8 +195,6 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti self.config['default_transition_update_hz'], flashing, flash_mask) else: # No transition configured - if transition_out: # in case transition_out is set we need to preserve it for the next step - self._previous_transition_out = transition_out new_text = TextTemplate(self.machine, text).evaluate({}) text = SegmentDisplayText.from_str(new_text, self.size, self.config['integrated_dots'], self.config['integrated_commas'], self.config['use_dots_for_commas'], From b8d05098ff3c99fce227e24b4b898322c59a5cbc Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Mon, 28 Apr 2025 18:33:35 +0200 Subject: [PATCH 15/17] flashing default set again to not_set --- mpf/config_spec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpf/config_spec.yaml b/mpf/config_spec.yaml index 46067109d..435229bf5 100644 --- a/mpf/config_spec.yaml +++ b/mpf/config_spec.yaml @@ -1505,7 +1505,7 @@ segment_display_player: action: single|enum(add,remove,flash,no_flash,flash_match,flash_mask,set_color)|add transition: ignore transition_out: ignore - flashing: single|enum(off,all,match,mask,not_set)|off + flashing: single|enum(off,all,match,mask,not_set)|not_set flash_mask: single|str|None key: single|str|None expire: single|ms_or_token|None From 37bfbc0b6311ec01e7e6c7ab90a4aac3cc148733 Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Sun, 4 May 2025 18:51:35 +0200 Subject: [PATCH 16/17] Changes to fix failing tests --- mpf/devices/segment_display/segment_display.py | 13 +++++++++---- mpf/tests/test_SegmentDisplay.py | 18 +++++++++--------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/mpf/devices/segment_display/segment_display.py b/mpf/devices/segment_display/segment_display.py index 2a17d8fe3..01b8d9432 100644 --- a/mpf/devices/segment_display/segment_display.py +++ b/mpf/devices/segment_display/segment_display.py @@ -160,6 +160,8 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti if not color: color = self._current_state.text.get_colors() + self._expand_colors(color, len(text)) + if self.config['update_method'] == "stack": self._text_stack[key] = TextStackEntry( text, color, flashing, flash_mask, transition, transition_out, priority, key) @@ -237,6 +239,8 @@ def _start_transition(self, transition: TransitionBase, current_text: str, new_t current_colors: List[RGBColor], new_colors: List[RGBColor], update_hz: float, flashing, flash_mask): """Start the specified transition.""" + current_colors = self._expand_colors(current_colors, len(current_text)) + new_colors = self._expand_colors(new_colors, len(new_text)) if self._current_transition: self._stop_transition() self._current_transition = TransitionRunner(self.machine, transition, current_text, new_text, @@ -276,10 +280,11 @@ def _expand_colors(self, colors, length): """Expand color to a certain length.""" if not colors: colors = self._default_color - if len(colors) > length: - colors = colors[0:length] - elif len(colors) < length: - colors = colors + [colors[len(colors) - 1]] * (length - len(colors)) + else: + if (len(colors)) == 1: + colors = colors * length + elif len(colors) != length: + colors = [RGBColor("white")] * length return colors diff --git a/mpf/tests/test_SegmentDisplay.py b/mpf/tests/test_SegmentDisplay.py index 1fc928f83..a4632b9f3 100644 --- a/mpf/tests/test_SegmentDisplay.py +++ b/mpf/tests/test_SegmentDisplay.py @@ -476,8 +476,8 @@ def test_segment_display_text(self): self.assertEqual(5, len(test_text)) colors = test_text.get_colors() self.assertEqual(5, len(colors)) - self.assertEqual([RGBColor("white"), RGBColor("red"), RGBColor("red"), - RGBColor("red"), RGBColor("red")], colors) + self.assertEqual([RGBColor("white"), RGBColor("white"), RGBColor("white"), + RGBColor("white"), RGBColor("white")], colors) # multiple colors (fewer colors than letters and fewer letters than characters) test_text = SegmentDisplayText.from_str("COLOR", 8, False, False, False, @@ -487,7 +487,7 @@ def test_segment_display_text(self): colors = test_text.get_colors() self.assertEqual(8, len(colors)) self.assertEqual([RGBColor("white"), RGBColor("white"), RGBColor("white"), RGBColor("white"), - RGBColor("red"), RGBColor("red"), RGBColor("red"), RGBColor("red")], colors) + RGBColor("white"), RGBColor("white"), RGBColor("white"), RGBColor("white")], colors) def test_transitions(self): """Test segment display text transitions.""" @@ -1240,16 +1240,16 @@ def test_colors_and_transitions(self): self.advance_time_and_run(.5) self.assertEqual(" EVENT1", self.machine.segment_displays["display1"].text) self.assertEqual( - [RGBColor("red"), RGBColor("red"), RGBColor("red"), RGBColor("red"), RGBColor("red"), RGBColor("blue"), - RGBColor("yellow"), RGBColor("green"), RGBColor("white"), RGBColor("purple")], + [RGBColor("white"), RGBColor("white"), RGBColor("white"), RGBColor("white"), RGBColor("white"), RGBColor("white"), + RGBColor("white"), RGBColor("white"), RGBColor("white"), RGBColor("white")], self.machine.segment_displays["display1"].colors) self.post_event("test_event2") self.advance_time_and_run(2) self.assertEqual(" EVENT2", self.machine.segment_displays["display1"].text) self.assertEqual( - [RGBColor("red"), RGBColor("red"), RGBColor("red"), RGBColor("red"), RGBColor("red"), RGBColor("blue"), - RGBColor("yellow"), RGBColor("green"), RGBColor("white"), RGBColor("purple")], + [RGBColor("white"), RGBColor("white"), RGBColor("white"), RGBColor("white"), RGBColor("white"), RGBColor("white"), + RGBColor("white"), RGBColor("white"), RGBColor("white"), RGBColor("white")], self.machine.segment_displays["display1"].colors) @test_config("config_flashing.yaml") @@ -1362,12 +1362,12 @@ def test_text_stack(self): # remove "FIRST" entry display1.remove_text_by_key(None) self.assertEqual(" 3rd", display1.text) - self.assertEqual([RGBColor("blue")] * 10, display1.colors) + self.assertEqual([RGBColor("yellow")] * 10, display1.colors) self.assertEqual(FlashingType.NO_FLASH, display1.flashing) # set flashing display1.set_flashing(FlashingType.FLASH_MASK, "FFF ") - self.assertEqual([RGBColor("blue")] * 10, display1.colors) + self.assertEqual([RGBColor("yellow")] * 10, display1.colors) self.assertEqual(FlashingType.FLASH_MASK, display1.flashing) self.assertEqual("FFF ", display1.flash_mask) From 8763e6bba7c296c0eae11b97586eb10e5799d8f6 Mon Sep 17 00:00:00 2001 From: worldpeace-germany Date: Thu, 8 May 2025 20:19:22 +0200 Subject: [PATCH 17/17] Fixed tests in Virtual Segment Display Connector --- mpf/tests/test_VirtualSegmentDisplayConnector.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mpf/tests/test_VirtualSegmentDisplayConnector.py b/mpf/tests/test_VirtualSegmentDisplayConnector.py index 1c686fe00..c738440f7 100644 --- a/mpf/tests/test_VirtualSegmentDisplayConnector.py +++ b/mpf/tests/test_VirtualSegmentDisplayConnector.py @@ -45,7 +45,7 @@ def test_plugin(self, mock_bcp_trigger_client): self.assertIsNone(display3.virtual_connector) display1.add_text("NEW TEXT") - display1.set_color([RGBColor("FF0000"), RGBColor("00FF00")]) + display1.set_color([RGBColor("red"), RGBColor("lime"),RGBColor("red"), RGBColor("lime"),RGBColor("red"), RGBColor("lime"),RGBColor("red")]) self.assertTrue(mock_bcp_trigger_client.called) mock_bcp_trigger_client.assert_has_calls([call(client=ANY, flashing='False', flash_mask='', name='update_segment_display', segment_display_name='display1', @@ -54,8 +54,7 @@ def test_plugin(self, mock_bcp_trigger_client): call(client=ANY, name='update_segment_display', segment_display_name='display1', text='EW TEXT', flashing='False', flash_mask='', - colors=['ff0000', '00ff00','00ff00', '00ff00', '00ff00', - '00ff00', '00ff00'])]) + colors=['ff0000', '00ff00', 'ff0000', '00ff00', 'ff0000', '00ff00', 'ff0000'])]) mock_bcp_trigger_client.reset_mock() display2.add_text_entry("OTHER TEXT", [RGBColor("green")], FlashingType.FLASH_ALL, "", None, None, None, None)