Skip to content

Conversation

@AdvancedImagingUTSW
Copy link
Collaborator

PR Summary

This PR improves the Diagnostics popup screenshot capture, with a focus on Windows multi‑monitor behavior. On Windows, ImageGrab.grab() defaults to the primary display, which produced empty screenshots when the popup was moved to a secondary monitor, and the main GUI window could appear above the popup in the captured image.

What changed

  • On Windows, screenshot capture now uses all_screens=True (and include_layered_windows when available) so secondary displays are included.
  • The diagnostics popup is temporarily lifted and set -topmost during capture to prevent the main window from obscuring it, then restored afterward.
  • Added basic guardrails around capture failures and window sizing.

Motivation

Users on Windows with multiple displays reported blank screenshots when the diagnostics popup was moved off the primary monitor, and screenshots that were partially obscured by the main window. This update makes capture reliable across multi‑monitor setups while keeping behavior unchanged on other platforms.

Add a Reset button and logic to the diagnostics popup to clear/ignore prior data and only display logs collected after the reset. Controller: import time, track reset_timestamp, add reset_plots() and _filter_log_since_reset() to filter performance logs, call populate_plots() after reset, and make plot initialization use the dynamic number of label frames. View: add Reset HoverButton and adjust grid columns/plot count/layout to accommodate the new button. Log functions: handle empty date_dirs in load_performance_log() by returning None early. UI/layout tweaks and minor defensive checks included.
Add a new "Performance Diagnostics" section to the user interface walkthrough (docs/source/02_user_guide/03_user_interface_walkthrough/user_interface_walkthrough.rst) and include the accompanying image (images/performance_diagnostics.png). The section documents launching the Performance Diagnostics window (File → Performance Diagnostics), the Update/Reset/Save Image/Close actions, and the timing distribution plots displayed (image acquisition, display, histogram population, DAQ trigger timing, stage position queries, Z/F stage moves, and serial communication).
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves the Performance Diagnostics popup by adding a plot reset capability and making screenshot capture more reliable on Windows multi-monitor setups.

Changes:

  • Added a Reset button to the Diagnostics popup and corresponding controller logic to filter performance logs after a reset timestamp.
  • Updated screenshot capture to temporarily lift/set -topmost and, on Windows, use ImageGrab.grab(all_screens=True) with a fallback for include_layered_windows.
  • Added tests for diagnostics popup layout and controller behaviors; added a small guard in performance log loading when no log directories exist; documented the UI.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/view/popups/test_diagnostics_popup.py New UI/layout assertions for the Diagnostics popup (buttons + plot widgets).
test/controller/sub_controllers/test_diagnostics_popup.py New controller tests for reset behavior, log filtering, close behavior, and no-data handling.
src/navigate/view/popups/diagnostics_popup.py Added Reset button and adjusted layout/plot count to 7 panels.
src/navigate/log_files/log_functions.py Returns None when no dated log directories exist (avoids max([]) crash).
src/navigate/controller/sub_controllers/diagnostics_popup.py Added reset timestamp filtering and improved screenshot capture behavior for Windows/multi-monitor.
docs/source/02_user_guide/03_user_interface_walkthrough/user_interface_walkthrough.rst Added “Performance Diagnostics” documentation section with screenshot and control descriptions.
.github/AGENTS.md Updated recommended pytest invocation (PYTHONPATH-based).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +157 to +202
was_topmost = False
try:
try:
was_topmost = bool(int(self.view.popup.attributes("-topmost")))
except Exception:
was_topmost = False

# Ensure the diagnostics popup is on top before capture.
self.view.popup.lift()
self.view.popup.attributes("-topmost", 1)
self.view.popup.update_idletasks()

# Get the window geometry
x = self.view.diagnostics_frame.winfo_rootx()
y = self.view.diagnostics_frame.winfo_rooty()
width = self.view.diagnostics_frame.winfo_width()
height = self.view.diagnostics_frame.winfo_height()

if width <= 1 or height <= 1:
self.view.popup.update_idletasks()
width = self.view.diagnostics_frame.winfo_width()
height = self.view.diagnostics_frame.winfo_height()

bbox = (x, y, x + width, y + height)
grab_kwargs = {}
if os.name == "nt":
grab_kwargs["all_screens"] = True
try:
grab_kwargs["include_layered_windows"] = True
screenshot = ImageGrab.grab(bbox=bbox, **grab_kwargs)
except TypeError:
grab_kwargs.pop("include_layered_windows", None)
screenshot = ImageGrab.grab(bbox=bbox, **grab_kwargs)
else:
screenshot = ImageGrab.grab(bbox=bbox)

screenshot.save(file_path)
logger.info(f"Diagnostics screenshot saved to: {file_path}")
except Exception:
logger.exception("Failed to capture diagnostics screenshot.")
finally:
if not was_topmost:
try:
self.view.popup.attributes("-topmost", 0)
except Exception:
pass
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New screenshot logic in _take_screenshot (Windows all_screens / include_layered_windows fallback + temporary -topmost) isn’t covered by tests. Since test/controller/sub_controllers/test_diagnostics_popup.py already exercises this controller, add a unit test that patches PIL.ImageGrab.grab and asserts: (1) on os.name == "nt", all_screens=True is passed and the include_layered_windows TypeError fallback is used; (2) -topmost is restored to its prior value in finally; and (3) save() is called with the expected path without touching the real filesystem.

Copilot uses AI. Check for mistakes.
try:
self.view.popup.attributes("-topmost", 0)
except Exception:
pass
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
pass
logger.debug(
"Failed to reset '-topmost' attribute on diagnostics popup.",
exc_info=True,
)

Copilot uses AI. Check for mistakes.
try:
if controller.view.popup.winfo_exists():
controller.view.popup.destroy()
except Exception:
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Suggested change
except Exception:
except Exception:
# Ignore any errors during popup teardown to avoid spurious test failures.

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Feb 4, 2026

Codecov Report

❌ Patch coverage is 31.03448% with 40 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.85%. Comparing base (56b9a0c) to head (b409c38).
⚠️ Report is 2 commits behind head on develop.

Files with missing lines Patch % Lines
...te/controller/sub_controllers/diagnostics_popup.py 25.49% 38 Missing ⚠️
src/navigate/log_files/log_functions.py 0.00% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1174      +/-   ##
===========================================
+ Coverage    52.51%   52.85%   +0.33%     
===========================================
  Files          197      197              
  Lines        23976    24023      +47     
===========================================
+ Hits         12592    12698     +106     
+ Misses       11384    11325      -59     
Flag Coverage Δ
unittests 52.85% <31.03%> (+0.33%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AdvancedImagingUTSW AdvancedImagingUTSW merged commit 6c5bc85 into develop Feb 4, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant