swayfx-mosaic/tooling/probes/step20c-rotated-output/scenario.py

94 lines
4.6 KiB
Python

"""Rotation scenario inserted into the inherited bounded runner try/finally."""
from pathlib import Path
# Reuse the published two-reference correction and real XDG-grab helpers.
# WHY: both references are positioned before either input calibration is scored.
# CONTRACT: the dynamic-output fixture source is read-only; no old campaign runs.
repo = Path(__file__).resolve().parents[3]
namespace = {}
exec((repo / 'tooling/probes/step20c-dynamic-output/scenario.py').read_text(), namespace)
PREFIX = namespace['SCENARIO'].split(" calibrate('D0')", 1)[0]
PREFIX = PREFIX.replace(" command('output * bg #1e1e2e solid_color')\n", '')
SCENARIO = PREFIX + r'''
# WHY: exact colors identify PNG orientation before interpreting output pixels.
# CONTRACT: marker positions/colors were fixed before the first transition.
colors = {'TL':(255,32,32),'TR':(32,255,32),'BL':(32,32,255),
'BR':(255,255,32),'C':(192,32,255)}
def marker_gate(tag, rotated):
im = Image.open(run / f'left-{tag}.png').convert('RGB')
points = {name: [] for name in colors}
reverse = {v:k for k,v in colors.items()}
for y in range(im.height):
for x in range(im.width):
name = reverse.get(im.getpixel((x,y)))
if name: points[name].append((x,y))
centers = {}
for name, positions in points.items():
if len(positions) < 100:
raise RuntimeError(f'{tag}: marker {name} absent ({len(positions)})')
centers[name] = [sum(p[0] for p in positions)/len(positions),
sum(p[1] for p in positions)/len(positions)]
logical = (im.size == (1000,750) and
centers['TL'][0] < centers['TR'][0] and
centers['TL'][1] < centers['BL'][1])
physical = (im.size == (750,1000) and
centers['TL'][0] > centers['BL'][0] and
centers['TL'][1] < centers['TR'][1])
frame = 'logical-oriented PNG' if logical else 'physical-buffer-oriented PNG' if physical else 'unknown'
record('marker_calibration', tag=tag, dimensions=list(im.size),
centers=centers, counts={k:len(v) for k,v in points.items()},
png_frame=frame)
if (rotated and not (logical or physical)) or (not rotated and not logical):
raise RuntimeError(f'{tag}: PNG frame not established')
return frame
rotation_stage = 'R0'
marker_gate('startup', False)
calibrate('R0')
command('[app_id="org.mosaic.NestedGrabProbe"] focus')
stable('R0', 'HEADLESS-1'); owner_hit('R0')
open_chain('R0-chain'); stable('R0-popups', 'HEADLESS-1')
reserve(lab, args.mode, 'R90')
record('dynamic_launch', action='R90',
command='output HEADLESS-1 mode 750x1000 scale 1.25 transform 90 position -800 0')
command('output HEADLESS-1 mode 750x1000 scale 1.25 transform 90 position -800 0')
rotation_stage = 'R90'
stable('R90-popups', 'HEADLESS-1')
command('workspace 3')
time.sleep(.5)
snapshot('R90-marker')
marker_gate('R90-marker', True)
command('workspace 1')
stable('R90-workspace-return', 'HEADLESS-1')
closed(); calibrate('R90')
command('[app_id="org.mosaic.NestedGrabProbe"] focus')
owner_hit('R90')
open_chain('R90-chain'); stable('R90-reopened', 'HEADLESS-1')
if args.mode == 'private_mosaic':
initial_camera = workspace()['mosaic']['rows'][0]['scroll_x']
reserve(lab,args.mode,'camera_hide'); record('dynamic_launch',action='camera_hide')
scroll(1280); stable('R90-hidden', 'HEADLESS-1')
reserve(lab,args.mode,'camera_return'); record('dynamic_launch',action='camera_return')
scroll(initial_camera); stable('R90-camera-return', 'HEADLESS-1')
a = configured('POPUP_A'); b = configured('POPUP_B'); o = owner()
sx = workspace()['mosaic']['rows'][0]['scroll_x']
bx = int(o['rect']['x']-sx+o['window_rect']['x']+a[0]+b[0]+35)
by = int(o['rect']['y']+o['window_rect']['y']+a[1]+b[1]+30)
before = len(client_text())
inject('move',bx,by); inject('right',bx,by)
record('restored_popup_hit',point=[bx,by],
delivered='POINTER_BUTTON target=POPUP_B' in client_text()[before:])
reserve(lab,args.mode,'R0')
record('dynamic_launch',action='R0',
command='output HEADLESS-1 mode 1000x750 scale 1.25 transform normal position -800 0')
command('output HEADLESS-1 mode 1000x750 scale 1.25 transform normal position -800 0')
rotation_stage = 'R0'
stable('R0-return', 'HEADLESS-1')
if args.mode == 'private_mosaic':
command('layout splith')
stable('standard-return', 'HEADLESS-1')
'''