Refactor scrolling loop for better clarity; more comments
What changed, and why it matters
This commit is a code cleanup of the on-screen text-scrolling animation. It restructures the scrolling loop to make it easier to read and adds explanatory comments. The only functional tweak visible is lowering the threshold that decides when text should scroll from 2 pixels to 1 pixel. There is no indication this change fixes or introduces a security problem.
No security action needed. Treat as a normal UI refactor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors TextArea’s horizontal scrolling thread in src/seedsigner/gui/components.py. It separates hold/pause logic from scroll/render logic, moves rendering inside the ‘we actually moved’ branch, and adds comments. min_scrollable_diff changes from 2 to 1, meaning scrolling activates when text overflows the visible area by 1 pixel instead of 2. No input handling, cryptography, memory safety, or privilege changes are present.
Changed components
src/seedsigner/gui/components.py:TextArea scrolling animationInspect captured patch +57 / −48
diff --git a/src/seedsigner/gui/components.py b/src/seedsigner/gui/components.py
index d3012e5..622db59 100644
--- a/src/seedsigner/gui/components.py
+++ b/src/seedsigner/gui/components.py
@@ -441,10 +441,10 @@ class TextArea(BaseComponent):
self.text_lines = [{"text": self.text, "text_width": full_text_width}]
self.text_width = full_text_width
- # Technically, the math says that we should enable scrolling for as little 1px
- # beyond the available width, but it's not worth having the text twitch back
- # and forth by such a small amount.
- min_scrollable_diff = 2
+ # Technically, the math says that we should enable scrolling for as little as
+ # 1px beyond the available width, but it's not worth having the text twitch
+ # back and forth by such a small amount.
+ min_scrollable_diff = 1
if self.text_width > self.visible_width + min_scrollable_diff:
# We'll have to left justify the text and scroll it (if scrolling is enabled,
@@ -650,9 +650,10 @@ class TextArea(BaseComponent):
readability. 45px/sec is better but still perceptually a bit stuttery.
"""
max_scroll = self.rendered_text_img.width - self.visible_width
+ last_render_time = None
- # The scrolling holds / pauses at the start and end of the text line. These
- # vars track when we started holding and how long we should hold for.
+ # The scrolling pauses at the start and end of the text line. These vars track
+ # when we started holding and how long we should hold for.
hold_started_at = None
cur_hold_duration = None
@@ -662,55 +663,43 @@ class TextArea(BaseComponent):
continue
if cur_hold_duration is not None:
+ # We're currently holding; see if we've held long enough
hold_time_elapsed = time.time() - hold_started_at
if hold_time_elapsed < cur_hold_duration:
- # Still holding; skip scrolling logic
+ # Still have to hold longer; skip scrolling logic
time.sleep(0.1)
continue
+ else:
+ # We've held long enough; reset the vars and resume scrolling
+ hold_started_at = None
+ cur_hold_duration = None
- with self.renderer.lock:
- if not self.scrolling_active:
- # We were stopped while waiting for the lock
+ else:
+ # We're not holding, but if we've reached either end, we need to start
+ # holding.
+ if self.horizontal_scroll_position == 0:
+ # Pause on initial (left-justified) position...
+ hold_started_at = time.time()
+ cur_hold_duration = self.begin_hold_secs
+
+ # Next scroll direction will be left
+ self.scroll_increment_sign = 1
+
+ # Don't count those pause seconds
+ last_render_time = None
continue
- # Render the latest scroll update
- img = self.rendered_text_img.crop((self.horizontal_scroll_position, 0, self.horizontal_scroll_position + self.visible_width, self.rendered_text_img.height))
- self.renderer.canvas.paste(img, (self.screen_x, self.screen_y - self.scroll_y))
- self.renderer.show_image()
-
- if hold_started_at is not None:
- # If we're here, we've held long enough; reset the vars and resume
- # scrolling.
- hold_started_at = None
- cur_hold_duration = None
+ elif self.horizontal_scroll_position == max_scroll:
+ # ...and slight pause at end of scroll
+ hold_started_at = time.time()
+ cur_hold_duration = self.end_hold_secs
- elif self.horizontal_scroll_position == 0:
- # Pause on initial (left-justified) position...
- hold_started_at = time.time()
- cur_hold_duration = self.begin_hold_secs
+ # Don't count those pause seconds
+ last_render_time = None
- # Next scroll direction will be left
- self.scroll_increment_sign = 1
-
- # Don't count those pause seconds
- last_render_time = None
- continue
-
- elif self.horizontal_scroll_position == max_scroll:
- # ...and slight pause at end of scroll
- hold_started_at = time.time()
- cur_hold_duration = self.end_hold_secs
-
- # Don't count those pause seconds
- last_render_time = None
-
- # Scroll will be to the right
- self.scroll_increment_sign = -1
- continue
-
- else:
- # No need to CPU limit when running in its own thread?
- time.sleep(0.02)
+ # Scroll will be to the right
+ self.scroll_increment_sign = -1
+ continue
next_render_time = time.time()
@@ -719,13 +708,33 @@ class TextArea(BaseComponent):
# "get off zero" for the real increment calc logic to kick in.
scroll_position_increment = 1 * self.scroll_increment_sign
else:
+ # Calculate how far to scroll based on time elapsed since last render
scroll_position_increment = int(self.horizontal_scroll_speed * (next_render_time - last_render_time) * self.scroll_increment_sign)
+ # Only render an update if we're going to move at least 1px
if abs(scroll_position_increment) > 0:
- self.horizontal_scroll_position += scroll_position_increment
- self.horizontal_scroll_position = max(0, min(self.horizontal_scroll_position, max_scroll))
+ # max: Ensure we don't scroll past left edge (0)
+ # min: Ensure we don't scroll past right edge (max_scroll)
+ self.horizontal_scroll_position = max(
+ 0,
+ min(self.horizontal_scroll_position + scroll_position_increment, max_scroll)
+ )
+
+ # Render the scroll update
+ with self.renderer.lock:
+ if not self.scrolling_active:
+ # We were stopped while waiting for the lock
+ continue
+
+ # The pre-rendered text img slides within a cropping window
+ img = self.rendered_text_img.crop((self.horizontal_scroll_position, 0, self.horizontal_scroll_position + self.visible_width, self.rendered_text_img.height))
+ self.renderer.canvas.paste(img, (self.screen_x, self.screen_y - self.scroll_y))
+ self.renderer.show_image()
last_render_time = next_render_time
+
+ # No need to CPU limit when running in its own thread?
+ time.sleep(0.02)
else:
# Wait to accumulate more time before scrolling
pass
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.