#!/usr/bin/env python3 """The manual's scenes: `scenes.py OUT_DIR scene [scene...]`, or `all`. Each scene drives the running app through `drive.py` and leaves a PNG or an MP4 in OUT_DIR, named after itself. `record.sh` runs them in order and turns the MP4s into GIFs. Coordinates are window pixels for a 1600×1100 window over the manual's own library (see record.sh): which cell holds which photograph is part of the scene, so a different library needs the numbers looked at again. Panel coordinates hold for any library. """ import os import sys import time sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import drive as dr # noqa: E402 OUT = sys.argv[1] if len(sys.argv) > 1 else '.' def shot(name): dr.shot(f'{OUT}/{name}.png') def rec(name): dr.rec_start(f'{OUT}/{name}.mp4') def cut(): dr.rec_stop() def pause(s): time.sleep(s) def hold(px, py, seconds): dr.move(px, py) pause(0.15) dr.x('mousedown', 1) pause(seconds) dr.x('mouseup', 1) def wheel(n, px, py): dr.move(px, py) dr.x('click', '--repeat', abs(n), '--delay', 40, 5 if n > 0 else 4) def ctrl_wheel(n, px, py): dr.move(px, py) dr.x('keydown', 'ctrl') for _ in range(abs(n)): dr.x('click', 5 if n > 0 else 4) pause(0.35) dr.x('keyup', 'ctrl') # --- places on the screen --------------------------------------------------- LIBRARY = (55, 22) # ‹ Library, in the develop header SELECT = (942, 22) # Select / Done, in the library header SETTINGS_LIB = (1543, 22) SETTINGS_DEV = (1343, 22) EXPORT = (720, 22) BACK = (60, 22) # ‹ Back, on the settings page RAIL = {'photo': (30, 75), 'compose': (30, 130), 'local': (30, 185), 'repair': (30, 240)} GROUPS = {'all': 1269, 'optics': 1313, 'light': 1359, 'colour': 1406, 'effects': 1457, 'detail': 1506} BEFORE = (210, 1045) RESET_ADJUST = (1565, 741) # "reset" in the Adjust heading, All group, scrolled to top CELL_TEAPOT = (424, 165) CELL_PANO_FIRST = (1264, 165) CELL_CHINATOWN = (963, 525) CELL_NY_LAST = (1502, 525) COLLECTION_ROW = (60, 90) def group(name): dr.click(GROUPS[name], 67) pause(0.9) def to_library(): dr.click(*LIBRARY) pause(2) def open_chinatown(): dr.click(*CELL_CHINATOWN) pause(6) def reset_edit(): group('all') wheel(-60, 1420, 700) dr.click(*RESET_ADJUST) pause(1) # --- library ---------------------------------------------------------------- def library(): shot('library') def library_rating(): rec('library-rating') dr.move(424, 900); pause(1.0) dr.click(444, 939); pause(1.2) dr.move(604, 900); pause(0.8) dr.click(644, 939); pause(1.2) dr.move(800, 700); pause(0.6) dr.click(665, 61); pause(1.5) # 3+ dr.click(384, 61); pause(1.2) # All cut() def library_timeline(): rec('library-timeline') dr.drag(300, 200, 300, 900, 40); pause(1.0) dr.drag(300, 900, 300, 150, 40); pause(1.0) cut() def library_thumbsize(): rec('library-thumbsize') ctrl_wheel(-4, 900, 500); pause(0.8) ctrl_wheel(4, 900, 500); pause(0.8) cut() def library_selection(): dr.click(*SELECT); pause(0.5) dr.click(*CELL_PANO_FIRST); pause(0.3) dr.x('keydown', 'shift'); dr.click(*CELL_NY_LAST); dr.x('keyup', 'shift'); pause(0.8) for x in (963, 1143, 1323, 1502): dr.x('keydown', 'ctrl'); dr.click(x, 525); dr.x('keyup', 'ctrl'); pause(0.3) pause(0.5) shot('library-selection') def library_keywords(): # Continues from library_selection: twelve frames selected. rec('library-keywords') dr.click(1117, 1079); pause(1.2) for word in ('alps', 'panorama', 'summer'): dr.x('type', '--delay', 90, word); dr.x('key', 'Return'); pause(0.7) pause(0.8) dr.click(800, 673); pause(1.0) # Done cut() dr.click(*SELECT); pause(0.5) # leave selecting def library_collections(): dr.click(212, 22); pause(0.3) # + in the collections header dr.x('type', '--delay', 90, 'Alps'); dr.x('key', 'Return'); pause(1.2) rec('library-collections') dr.drag(*CELL_PANO_FIRST, *COLLECTION_ROW, 40); pause(1.5) dr.click(*SELECT); pause(0.5) dr.click(424, 350); pause(0.3) dr.x('keydown', 'shift'); dr.click(1502, 350); dr.x('keyup', 'shift'); pause(0.8) dr.drag(963, 350, *COLLECTION_ROW, 40); pause(1.5) dr.click(*SELECT); pause(0.5) dr.click(*COLLECTION_ROW); pause(1.5) cut() shot('library-collection') dr.click(60, 48); pause(1.2) # All photographs # --- develop ---------------------------------------------------------------- def develop(): open_chinatown() group('all') shot('develop') def develop_groups(): rec('develop-groups') for g in ['optics', 'light', 'colour', 'effects', 'detail', 'all']: group(g); pause(0.6) cut() def develop_light(): group('light') rec('develop-light') pause(0.5) dr.drag(1398, 792, 1422, 792, 25); pause(0.8) # exposure up dr.drag(1398, 918, 1320, 918, 25); pause(0.8) # highlights down dr.drag(1398, 964, 1450, 964, 25); pause(0.8) # shadows up hold(*BEFORE, 1.6); pause(1.0) cut() reset_edit() def develop_zoom(): rec('develop-zoom') dr.move(650, 500); pause(0.3) dr.x('click', '--repeat', 2, '--delay', 80, 1); pause(1.5) dr.drag(650, 500, 900, 700, 30); pause(0.8) dr.drag(900, 700, 500, 450, 30); pause(0.8) dr.x('click', '--repeat', 2, '--delay', 80, 1); pause(1.2) cut() def develop_wb(): group('colour') rec('develop-wb') pause(0.4) dr.click(1542, 767); pause(0.8) # pick dr.click(1000, 300); pause(1.5) # a neutral wall hold(*BEFORE, 1.4); pause(0.8) cut() reset_edit() def compose(): dr.click(*RAIL['compose']); pause(1.2) rec('compose') pause(0.4) dr.drag(66, 182, 260, 330, 30); pause(0.8) dr.drag(1236, 964, 1100, 900, 25); pause(0.8) dr.drag(1420, 593, 1448, 593, 20); pause(1.0) # straighten dr.click(1466, 647); pause(1.2) # 1:1 dr.click(1378, 647); pause(1.0) # Original dr.click(132, 1045); pause(1.2) # Done composing cut() shot('compose-done') dr.click(1567, 510); pause(1.0) # reset compose dr.click(115, 1045); pause(1.0) # refit def local_segment(): dr.click(*RAIL['local']); pause(1.2) dr.click(1420, 435); pause(14) # Find subjects shot('local-categories') dr.click(1266, 646); pause(2.5) # Sky shot('local-segment') def local_paint(): # Continues from local_segment: the sky mask selected and shown. rec('local-paint') wheel(12, 1420, 800); pause(0.8) shot('local-mask-row') cut() def local_done(): dr.click(62, 1045); pause(1.0) # Done masking reset_edit() def repair(): dr.click(*RAIL['repair']); pause(1.2) rec('repair') pause(0.4) dr.click(700, 620); pause(3) dr.drag(1264, 460, 1330, 460, 20); pause(1.5) # size hold(*BEFORE, 1.4); pause(0.8) cut() dr.click(125, 1045); pause(1.0) # Done repairing reset_edit() def film(): group('all') rec('film') dr.click(1420, 779); pause(1.5) # Film ▸ dr.click(1420, 953); pause(3) # Velvia 100 hold(*BEFORE, 1.4); pause(0.8) cut() reset_edit() def presets(): dr.click(1420, 692); pause(1.5) shot('presets') dr.click(800, 783); pause(1.0) # Done def develop_export(): dr.click(*EXPORT); pause(8) shot('export-done') # --- panorama --------------------------------------------------------------- def panorama(): to_library() library_selection() rec('panorama') dr.click(1325, 1079); pause(40) # Merge to panorama dr.click(184, 637); pause(45) # Fill the border dr.click(1543, 22); pause(60) # Merge cut() shot('panorama-done') dr.click(*BACK); pause(2) # --- settings --------------------------------------------------------------- def settings(): dr.click(*SETTINGS_LIB); pause(2) shot('settings') wheel(30, 700, 600); pause(1) shot('settings-export') dr.click(*BACK); pause(1.5) ALL = [ 'library', 'library_rating', 'library_timeline', 'library_thumbsize', 'library_selection', 'library_keywords', 'library_collections', 'develop', 'develop_groups', 'develop_light', 'develop_zoom', 'develop_wb', 'compose', 'local_segment', 'local_paint', 'local_done', 'repair', 'film', 'presets', 'panorama', 'settings', ] if __name__ == '__main__': names = sys.argv[2:] if names == ['all']: names = ALL for name in names: print(f'-- {name}', flush=True) globals()[name]()