feat(controller): add refresh_display_bounds and dynamic resolution and monitor change detection
This commit is contained in:
+65
-18
@@ -84,24 +84,10 @@ class CatController:
|
|||||||
self.config = config
|
self.config = config
|
||||||
self.assets = assets
|
self.assets = assets
|
||||||
|
|
||||||
# Primary monitor work area (excludes taskbar)
|
# Dynamic display topology signature & periodic checker
|
||||||
work_area = WindowManager.get_work_area()
|
self._current_display_signature = None
|
||||||
self.screen_left = work_area[0]
|
self.next_display_check_time = time.time() + 1.5
|
||||||
self.screen_top = work_area[1]
|
self.refresh_display_bounds(force=True)
|
||||||
self.screen_right = work_area[2]
|
|
||||||
self.screen_bottom = work_area[3]
|
|
||||||
|
|
||||||
# Full virtual desktop spanning ALL monitors – used for roaming, platforming,
|
|
||||||
# and dragging so the cat can freely explore secondary displays.
|
|
||||||
vd = WindowManager.get_virtual_desktop_bounds()
|
|
||||||
self.vd_left = vd[0]
|
|
||||||
self.vd_top = vd[1]
|
|
||||||
self.vd_right = vd[2]
|
|
||||||
self.vd_bottom = vd[3]
|
|
||||||
|
|
||||||
# Horizontal roaming boundaries across all monitors
|
|
||||||
self.min_x = float(self.vd_left + 15)
|
|
||||||
self.max_x = float(self.vd_right - self.config.cat_width - 15)
|
|
||||||
|
|
||||||
# Position & motion
|
# Position & motion
|
||||||
self.x = float(self.screen_left + 100)
|
self.x = float(self.screen_left + 100)
|
||||||
@@ -155,6 +141,62 @@ class CatController:
|
|||||||
self.walk_speed_px = (WALK_SPEED / config.cat_width) * (config.cat_width * 5.0)
|
self.walk_speed_px = (WALK_SPEED / config.cat_width) * (config.cat_width * 5.0)
|
||||||
self.run_speed_px = (RUN_SPEED / config.cat_width) * (config.cat_width * 4.0)
|
self.run_speed_px = (RUN_SPEED / config.cat_width) * (config.cat_width * 4.0)
|
||||||
|
|
||||||
|
def refresh_display_bounds(self, force: bool = False) -> bool:
|
||||||
|
"""
|
||||||
|
Dynamically refreshes monitor geometries, virtual desktop boundaries,
|
||||||
|
and clamps cat position if display topology or resolution changed.
|
||||||
|
Returns True if a display change occurred, False otherwise.
|
||||||
|
"""
|
||||||
|
new_signature = WindowManager.get_display_topology_signature()
|
||||||
|
if not force and new_signature == self._current_display_signature:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self._current_display_signature = new_signature
|
||||||
|
|
||||||
|
# Update primary monitor work area (excludes taskbar)
|
||||||
|
work_area = WindowManager.get_work_area()
|
||||||
|
self.screen_left = work_area[0]
|
||||||
|
self.screen_top = work_area[1]
|
||||||
|
self.screen_right = work_area[2]
|
||||||
|
self.screen_bottom = work_area[3]
|
||||||
|
|
||||||
|
# Update full virtual desktop spanning all monitors
|
||||||
|
vd = WindowManager.get_virtual_desktop_bounds()
|
||||||
|
self.vd_left = vd[0]
|
||||||
|
self.vd_top = vd[1]
|
||||||
|
self.vd_right = vd[2]
|
||||||
|
self.vd_bottom = vd[3]
|
||||||
|
|
||||||
|
# Update horizontal roaming boundaries
|
||||||
|
self.min_x = float(self.vd_left + 15)
|
||||||
|
self.max_x = float(self.vd_right - self.config.cat_width - 15)
|
||||||
|
|
||||||
|
monitors = WindowManager.get_monitors()
|
||||||
|
logger.info(
|
||||||
|
f"Dynamic display configuration updated: {len(monitors)} monitor(s) detected, "
|
||||||
|
f"virtual desktop=({self.vd_left}, {self.vd_top}, {self.vd_right}, {self.vd_bottom}), "
|
||||||
|
f"primary work area={work_area}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ensure the cat is not stranded outside newly active bounds
|
||||||
|
if hasattr(self, "x") and hasattr(self, "y"):
|
||||||
|
prev_x = self.x
|
||||||
|
self.x = max(self.min_x, min(self.max_x, self.x))
|
||||||
|
|
||||||
|
# Re-evaluate floor at current position
|
||||||
|
new_floor = WindowManager.get_floor_y_at(self.x + self.config.cat_width * 0.5, self.config.cat_height)
|
||||||
|
self.floor_y = new_floor
|
||||||
|
|
||||||
|
# If walking or resting on floor, adjust Y to new floor
|
||||||
|
if hasattr(self, "current_ledge") and not self.current_ledge:
|
||||||
|
if hasattr(self, "state") and self.state in (CatState.WALK, CatState.SIT, CatState.SLEEP, CatState.RELEASE):
|
||||||
|
self.y = new_floor
|
||||||
|
|
||||||
|
if prev_x != self.x:
|
||||||
|
logger.info(f"Clamped cat X from {prev_x} to {self.x} due to display boundary change")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
# State Transitions & Targeting
|
# State Transitions & Targeting
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
@@ -348,6 +390,11 @@ class CatController:
|
|||||||
|
|
||||||
face_type = "happy" if self.state == CatState.HAPPY else ("blink" if self.is_blinking else "open")
|
face_type = "happy" if self.state == CatState.HAPPY else ("blink" if self.is_blinking else "open")
|
||||||
|
|
||||||
|
# Dynamic check for monitor addition/removal, resolution or work-area change
|
||||||
|
if now >= self.next_display_check_time:
|
||||||
|
self.next_display_check_time = now + 1.5
|
||||||
|
self.refresh_display_bounds()
|
||||||
|
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# State: WALK (roaming desktop floors and window ledges)
|
# State: WALK (roaming desktop floors and window ledges)
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user