-
Notifications
You must be signed in to change notification settings - Fork 158
Initial Implementation for display_segment update_method replace #1820
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
25c3d9c
05fb459
3d3673a
0b4777e
2f6d028
b9fc7b6
66b5e1f
8217e6f
fcb590a
2794923
57c5a11
55f3f02
67dcd6a
7e65d9d
b8d0509
37bfbc0
8763e6b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -106,12 +106,22 @@ 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, 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: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not really sure what this means, in what scenario would the value be
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the weirdness of this here comes from copying |
||
| self.delay.remove(instance_dict[display][key]) | ||
| del instance_dict[display][key] | ||
| else: | ||
| display.clear_segment_display(None) | ||
|
|
||
| self._reset_instance_dict(context) | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -51,7 +51,8 @@ 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 +74,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.""" | ||||
|
|
@@ -86,8 +90,16 @@ 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: | ||||
|
|
@@ -145,6 +157,11 @@ def add_text_entry(self, text, color, flashing, flash_mask, transition, transiti | |||
|
|
||||
| This will replace texts with the same key. | ||||
| """ | ||||
| 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) | ||||
|
|
@@ -155,11 +172,43 @@ 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 | ||||
| previous_text = self._previous_text or "" | ||||
| self._previous_text = text # Save the new text as the next previous text | ||||
|
|
||||
| # Handle new and previous 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: | ||||
| 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, | ||||
| previous_color, color, | ||||
| self.config['default_transition_update_hz'], flashing, flash_mask) | ||||
|
|
||||
| else: # No transition configured | ||||
| 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)) | ||||
|
|
||||
| # 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. | ||||
|
|
@@ -170,13 +219,20 @@ 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.") | ||||
| return | ||||
| 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) | ||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a good use of an existing method to clear out a display, but the I would suggest instead that this behavior check the current text to see if it has the requested key, and if so remove the text and pass an empty key, and if not do nothing.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would tend to disagree on this point. But maybe I misunderstood something For the On a side note: I am working on one fix for the show If you really believe that the
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's a use case I'm picturing where key and priority would be helpful, let me know what you think. A player starts a non-exclusive hurry-up mode (priority 1000) with a jackpot on the left loop, and that hurry-up mode sends the text "HIT LEFT LOOP" to a display. Instead of going for the hurry-up, the player instead starts a multi ball (priority 5000) and the multi ball mode sends the text "JACKPOT: 5M" to the display. During the multi ball, the hurry-up mode times out and ends. By default, the hurry-up mode is set to remove the "HIT LEFT LOOP" text from the display, so it will send a command to the displays to replace the text with empty string. Without a key, the display doesn't know that the text being shown is not the text that's expected to be removed, and will instead remove the "JACKPOT: 5M" text from the display even though the multi ball is still running. As a result, the multi ball will have a blank display. Reverse the situation and start the multi ball before the hurry-up. The multi ball mode is higher priority so its display text should have precedence, and the hurry-up display text should be ignored. Otherwise the multi ball "JACKPOT: 5M" will turn into "HIT LEFT LOOP" and then disappear after the hurry-up, again leaving the multi ball with a blank display. I realize that this type of use case is exactly what the Thoughts?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The described use case is very valid and is very much a use case for the
indicates that the text is written straight to the display. Can you describe in words what would be the logic of
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, I'm overthinking it and trying to keep stack-like functionality where it doesn't belong. The concept of replace doesn't need to have any considerations for priority or key or what's currently on the display, and should always overwrite when called. |
||||
|
|
||||
| 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 | ||||
|
|
||||
| if key in self._text_stack: | ||||
| del self._text_stack[key] | ||||
| self._update_stack() | ||||
| self.remove_text_by_key(key) | ||||
|
|
||||
| # pylint: disable=too-many-arguments | ||||
| def _start_transition(self, transition: TransitionBase, current_text: str, new_text: str, | ||||
|
|
@@ -224,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 | ||||
|
|
||||
|
|
||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In what situation would keys_dict not be a dict? It feels weird to convert it to dict here instead of
for key in keys_dict.keys()