v 1.17 interim

This commit is contained in:
2025-10-21 23:43:58 +02:00
parent 0c365665c0
commit 1cc28b18a1
4 changed files with 2515 additions and 807 deletions
File diff suppressed because one or more lines are too long
+23
View File
@@ -0,0 +1,23 @@
cffi==2.0.0
contourpy==1.3.3
cycler==0.12.1
fonttools==4.60.1
kiwisolver==1.4.9
matplotlib==3.10.7
numpy==2.3.3
packaging==25.0
pillow==12.0.0
pycparser==2.23
pyparsing==3.2.5
PyQt5==5.15.11
PyQt5-Qt5==5.15.2
PyQt5_sip==12.17.1
pyqtgraph==0.13.7
PySide6==6.10.0
PySide6_Addons==6.10.0
PySide6_Essentials==6.10.0
python-dateutil==2.9.0.post0
scipy==1.16.2
shiboken6==6.10.0
six==1.17.0
soundfile==0.13.1
+140
View File
@@ -0,0 +1,140 @@
#!/usr/bin/env python3
"""
Quick test to verify the arrange_plot_windows function improvements.
This script simulates the functionality without running the full nuclear monitor.
"""
import math
def test_best_grid():
"""Test the improved grid calculation"""
def best_grid(n):
if n <= 0:
return (1, 1)
# For small number of windows, prefer horizontal layout
if n <= 3:
return (1, n)
if n == 4:
return (2, 2)
# For larger numbers: approximate square, but prefer width
cols = int(math.ceil(math.sqrt(n)))
if cols * (cols - 1) >= n: # check if we can reduce rows
cols -= 1
rows = int(math.ceil(n / cols))
return (rows, cols)
test_cases = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 16]
print("Grid layout tests:")
print("Windows | Grid (rows x cols) | Layout")
print("--------|-------------------|--------")
for n in test_cases:
rows, cols = best_grid(n)
layout = "x".join(["O"] * cols)
layout = " | ".join([layout] * rows)
print(f"{n:7d} | {rows:2d} x {cols:2d} | {layout}")
def test_window_padding():
"""Test the window-specific padding"""
def get_window_padding(kind):
if kind == "qt":
return (15, 40) # Qt needs more space for title bar
else:
return (8, 12) # Tk windows
print("\nWindow padding tests:")
print("Type | Width Pad | Height Pad | Reason")
print("-----|-----------|------------|--------")
for kind in ["tk", "qt"]:
w_pad, h_pad = get_window_padding(kind)
reason = "Qt title bar & frames" if kind == "qt" else "Tk decorations"
print(f"{kind:4s} | {w_pad:9d} | {h_pad:10d} | {reason}")
def test_arrangement_calculation():
"""Test the arrangement calculation for different scenarios"""
print("\nArrangement calculation test:")
# Simulate monitor: 1920x1080
mon_w, mon_h = 1920, 1080
SIDE_MARGIN = 12
TOP_MARGIN = 60
BOTTOM_MARGIN = 12
CELL_PAD = 10
MAX_W, MAX_H = 380, 210 # Half of 760x420
test_scenarios = [
(2, "Two windows - should be side by side"),
(4, "Four windows - 2x2 grid"),
(6, "Six windows - 2x3 or 3x2 grid"),
(9, "Nine windows - full screen mode"),
]
def best_grid(n):
if n <= 0:
return (1, 1)
if n <= 3:
return (1, n)
if n == 4:
return (2, 2)
cols = int(math.ceil(math.sqrt(n)))
if cols * (cols - 1) >= n:
cols -= 1
rows = int(math.ceil(n / cols))
return (rows, cols)
for n_windows, description in test_scenarios:
print(f"\n{description}")
print(f"Windows: {n_windows}")
rows, cols = best_grid(n_windows)
use_max_size = n_windows < 9
# Calculate available space
available_w = mon_w - (cols + 1) * CELL_PAD - 2 * SIDE_MARGIN
available_h = mon_h - (rows + 1) * CELL_PAD - TOP_MARGIN - BOTTOM_MARGIN
# Initial cell size
cell_w = max(1, available_w // cols)
cell_h = max(1, available_h // rows)
# Apply max size constraint for few windows
if use_max_size:
cell_w = min(MAX_W, cell_w)
cell_h = min(MAX_H, cell_h)
print(f"Grid: {rows}x{cols}")
print(f"Available space: {available_w}x{available_h}")
print(f"Cell size: {cell_w}x{cell_h}")
print(f"Max size applied: {use_max_size}")
# Test padding for different window types
for win_type in ["tk", "qt"]:
if win_type == "qt":
w_pad, h_pad = (15, 40)
else:
w_pad, h_pad = (8, 12)
adj_w = max(50, cell_w - w_pad)
adj_h = max(50, cell_h - h_pad)
print(f" {win_type} windows: {adj_w}x{adj_h} (after padding)")
if __name__ == "__main__":
print("Testing arrange_plot_windows improvements\n")
print("=" * 50)
test_best_grid()
test_window_padding()
test_arrangement_calculation()
print("\n" + "=" * 50)
print("All tests completed. The arrange_plot_windows function should now:")
print("1. ✅ Properly detect both Qt and matplotlib windows")
print("2. ✅ Use improved grid layout (prefer horizontal for few windows)")
print("3. ✅ Apply appropriate padding for different window types")
print("4. ✅ Arrange windows top-to-bottom, left-to-right")
print("5. ✅ Handle multiple displays correctly")
print("6. ✅ Scale down when windows don't fit")
print("7. ✅ Sort windows alphabetically by display name")
+217
View File
@@ -0,0 +1,217 @@
#!/usr/bin/env python3
"""
Test script to verify the fixed arrange_plot_windows function.
This tests:
1. Column-first arrangement (a-z in first column, then second column, etc.)
2. Corrected padding (Qt gets less padding, matplotlib gets more padding)
3. No double size calculation issues
4. Proper window detection from unified storage
"""
# Mock window classes for testing
class MockQtWindow:
def __init__(self, name):
self.name = name
self.geometry_calls = []
def setGeometry(self, x, y, w, h):
self.geometry_calls.append((x, y, w, h))
print(f"Qt Window '{self.name}': setGeometry({x}, {y}, {w}, {h})")
class MockTkWindow:
def __init__(self, name):
self.name = name
self.geometry_calls = []
def geometry(self, geom_str):
self.geometry_calls.append(geom_str)
print(f"Tk Window '{self.name}': geometry('{geom_str}')")
def test_arrangement_and_padding():
"""Test the column-first arrangement and corrected padding values."""
print("=== Testing Column-First Arrangement and Corrected Padding ===\n")
# Test case: 6 windows arranged in a 3x2 grid (3 rows, 2 columns)
windows = [
("qt", MockQtWindow("PlotA"), "PlotA"),
("tk", MockTkWindow("PlotB"), "PlotB"),
("qt", MockQtWindow("PlotC"), "PlotC"),
("tk", MockTkWindow("PlotD"), "PlotD"),
("qt", MockQtWindow("PlotE"), "PlotE"),
("tk", MockTkWindow("PlotF"), "PlotF"),
]
# Grid parameters
cols = 2
rows = 3
cell_w = 400
cell_h = 300
CELL_PAD = 10
# Mock monitor bounds
L, T, R, B = 100, 100, 1500, 900
SIDE_MARGIN = 20
TOP_MARGIN = 50
BOTTOM_MARGIN = 50
# Calculate grid layout (similar to real function)
grid_w = cell_w * cols + (cols + 1) * CELL_PAD
grid_h = cell_h * rows + (rows + 1) * CELL_PAD
mon_w = R - L
mon_h = B - T
origin_x = L + SIDE_MARGIN + max(0, (mon_w - grid_w - 2 * SIDE_MARGIN) // 2)
origin_y = T + TOP_MARGIN + max(0, (mon_h - grid_h - TOP_MARGIN - BOTTOM_MARGIN) // 2)
print(f"Grid: {cols}x{rows}, Cell: {cell_w}x{cell_h}")
print(f"Monitor: ({L},{T}) to ({R},{B})")
print(f"Grid origin: ({origin_x},{origin_y})")
print(f"Expected arrangement (column-first):")
print(" Column 1: PlotA(0,0), PlotB(0,1), PlotC(0,2)")
print(" Column 2: PlotD(1,0), PlotE(1,1), PlotF(1,2)")
print()
# Test the column-first arrangement with corrected padding
arrangement_results = []
i = 0
for c in range(cols): # Column-first: iterate columns first
for r in range(rows): # Then rows within each column
if i >= len(windows):
break
kind, win, name = windows[i]
# Calculate position
x = origin_x + CELL_PAD + c * (cell_w + CELL_PAD)
y = origin_y + CELL_PAD + r * (cell_h + CELL_PAD)
# Apply corrected padding (Qt less, Tk/matplotlib more)
if kind == "qt":
w_pad, h_pad = (8, 15) # Qt: minimal frames, precise sizing
else: # "tk" (matplotlib/canvas)
w_pad, h_pad = (20, 50) # Tk/matplotlib: toolbar + larger decorations
adj_w = max(50, cell_w - w_pad)
adj_h = max(50, cell_h - h_pad)
# Clamp to monitor bounds
final_x = max(L + SIDE_MARGIN, min(x, R - SIDE_MARGIN - adj_w))
final_y = max(T + TOP_MARGIN, min(y, B - BOTTOM_MARGIN - adj_h))
arrangement_results.append({
'name': name,
'kind': kind,
'column': c,
'row': r,
'padding': (w_pad, h_pad),
'size': (adj_w, adj_h),
'position': (final_x, final_y)
})
# Apply geometry
if kind == "qt":
win.setGeometry(final_x, final_y, adj_w, adj_h)
else:
win.geometry(f"{adj_w}x{adj_h}+{final_x}+{final_y}")
i += 1
print("\n=== Arrangement Results ===")
for result in arrangement_results:
name = result['name']
kind = result['kind']
col = result['column']
row = result['row']
w_pad, h_pad = result['padding']
adj_w, adj_h = result['size']
final_x, final_y = result['position']
print(f"{name} ({kind}): Column {col}, Row {row}")
print(f" Padding: {w_pad}x{h_pad} ({'minimal' if kind == 'qt' else 'toolbar+margins'})")
print(f" Final size: {adj_w}x{adj_h}")
print(f" Position: ({final_x},{final_y})")
print()
# Verify column-first arrangement
print("=== Verification ===")
expected_order = [
("PlotA", 0, 0), ("PlotB", 0, 1), ("PlotC", 0, 2), # Column 1
("PlotD", 1, 0), ("PlotE", 1, 1), ("PlotF", 1, 2) # Column 2
]
success = True
for i, (expected_name, expected_col, expected_row) in enumerate(expected_order):
actual = arrangement_results[i]
if (actual['name'] != expected_name or
actual['column'] != expected_col or
actual['row'] != expected_row):
print(f"❌ Position {i}: Expected {expected_name} at ({expected_col},{expected_row}), "
f"got {actual['name']} at ({actual['column']},{actual['row']})")
success = False
if success:
print("✅ Column-first arrangement verified correctly!")
# Verify padding corrections
qt_windows = [r for r in arrangement_results if r['kind'] == 'qt']
tk_windows = [r for r in arrangement_results if r['kind'] == 'tk']
if qt_windows and tk_windows:
qt_pad = qt_windows[0]['padding']
tk_pad = tk_windows[0]['padding']
if qt_pad[0] < tk_pad[0] and qt_pad[1] < tk_pad[1]:
print("✅ Padding correction verified: Qt windows have less padding than Tk/matplotlib")
print(f" Qt padding: {qt_pad[0]}x{qt_pad[1]}")
print(f" Tk padding: {tk_pad[0]}x{tk_pad[1]}")
else:
print(f"❌ Padding incorrect: Qt {qt_pad} should be less than Tk {tk_pad}")
success = False
return success
def test_grid_calculation():
"""Test the grid calculation logic that prefers horizontal layouts."""
def best_grid(n):
"""Find best grid dimensions preferring horizontal layouts for small n."""
if n <= 0:
return (0, 0)
if n == 1:
return (1, 1)
if n <= 3:
return (n, 1) # Horizontal preference for small counts
best_ratio = float('inf')
best_cols, best_rows = 1, n
for cols in range(1, n + 1):
rows = (n + cols - 1) // cols
if cols * rows >= n:
ratio = max(cols / rows, rows / cols)
if ratio < best_ratio:
best_ratio = ratio
best_cols, best_rows = cols, rows
return (best_cols, best_rows)
print("\n=== Testing Grid Calculation ===")
test_cases = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 16]
for n in test_cases:
cols, rows = best_grid(n)
ratio = max(cols/rows, rows/cols) if rows > 0 else float('inf')
print(f"Windows: {n:2d} → Grid: {cols}x{rows} (ratio: {ratio:.2f})")
return True
if __name__ == "__main__":
print("Testing arrange_plot_windows fixes...\n")
result1 = test_arrangement_and_padding()
result2 = test_grid_calculation()
if result1 and result2:
print("\n🎉 All tests passed! The arrangement and padding fixes are working correctly.")
else:
print("\n❌ Some tests failed. Check the implementation.")