94 lines
4.6 KiB
Python
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')
|
|
'''
|