Масштаб таймлайна берётся от точки под мышкой
Ctrl с колесом должен оставлять на месте то, на что смотрит мышь, а оставлял точку левее — ровно на левый край таймлайна. При мыши у левого края опора и вовсе уходила за пределы окна. Причина: MousePos у DoMouseWheel по описанию экранный, но под gtk2 в нём уже клиентские координаты, и ScreenToClient переводил их второй раз. Берём Mouse.CursorPos — он экранный в любой системе. Замерено на невидимом экране: до правки мышь в 700, 1000 и 1300 давала опору в 260, 560 и 860; после — ровно 700, 1000 и 1300. Проверка оформлена в tests/zoomanchor.py и прогнана на обеих сборках: на прежней она падает, на новой проходит.
This commit is contained in:
parent
4526f65fcc
commit
d0ec869743
4 changed files with 130 additions and 2 deletions
107
tests/zoomanchor.py
Executable file
107
tests/zoomanchor.py
Executable file
|
|
@ -0,0 +1,107 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Проверка того, что масштаб таймлайна берётся от точки под мышкой.
|
||||
|
||||
Ctrl с колесом меняет масштаб. Точка монтажа, на которую смотрит мышь,
|
||||
обязана остаться на месте: иначе прицелиться масштабом нельзя — картинка
|
||||
уезжает из-под курсора.
|
||||
|
||||
Как меряется. Курсор воспроизведения ставится в известное место и служит
|
||||
меткой: он привязан ко времени, а не к пикселям, и при смене масштаба
|
||||
едет вместе с монтажом. Зная, что один щелчок колеса меняет масштаб ровно
|
||||
в 1.25 раза, неподвижную точку считаем по двум положениям метки:
|
||||
|
||||
p1 - a = k * (p0 - a) => a = (k * p0 - p1) / (k - 1)
|
||||
|
||||
Ошибку это не прячет: если опора уедет, a разойдётся с положением мыши.
|
||||
|
||||
Запуск (редактор уже должен идти на невидимом экране :99):
|
||||
tests/zoomanchor.py <окно>
|
||||
где окно — из `DISPLAY=:99 xdotool search --name nlve`.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
from PIL import Image
|
||||
|
||||
DISP = os.environ.get('ЭКРАН', ':99')
|
||||
ENV = {'DISPLAY': DISP, 'PATH': '/usr/bin:/bin'}
|
||||
# Один щелчок колеса. Должен совпадать с ZoomStep в uTimelineCtrl.
|
||||
STEP = 1.25
|
||||
# Полоса окна, по которой всё и меряется: линейка и первая дорожка.
|
||||
BAND = '1500x120+0+450'
|
||||
SHOT = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
'кадры-зума.png')
|
||||
|
||||
|
||||
def run(*args):
|
||||
subprocess.run(list(args), env=ENV, check=True)
|
||||
|
||||
|
||||
def playhead(win):
|
||||
"""Где сейчас курсор воспроизведения. Он единственный красный."""
|
||||
run('import', '-window', win, '-crop', BAND, '+repage', SHOT)
|
||||
im = Image.open(SHOT).convert('RGB')
|
||||
px = im.load()
|
||||
w, h = im.size
|
||||
best = (0, None)
|
||||
for x in range(10, w - 10):
|
||||
red = sum(1 for y in range(h)
|
||||
if px[x, y][0] > 120
|
||||
and px[x, y][0] - px[x, y][1] > 40
|
||||
and px[x, y][0] - px[x, y][2] > 40)
|
||||
if red > best[0]:
|
||||
best = (red, x)
|
||||
return best[1] if best[0] > 60 else None
|
||||
|
||||
|
||||
def measure(win, mouse_x):
|
||||
before = playhead(win)
|
||||
run('xdotool', 'mousemove', str(mouse_x), '520')
|
||||
time.sleep(0.4)
|
||||
run('xdotool', 'keydown', 'ctrl', 'click', '4', 'keyup', 'ctrl')
|
||||
time.sleep(0.9)
|
||||
after = playhead(win)
|
||||
run('xdotool', 'keydown', 'ctrl', 'click', '5', 'keyup', 'ctrl')
|
||||
time.sleep(0.9)
|
||||
if before is None or after is None:
|
||||
return None
|
||||
return (STEP * before - after) / (STEP - 1)
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print(__doc__)
|
||||
return 2
|
||||
win = sys.argv[1]
|
||||
|
||||
# Метку ставим щелчком по пустому месту под дорожками.
|
||||
run('xdotool', 'mousemove', '900', '600', 'click', '1')
|
||||
time.sleep(0.8)
|
||||
|
||||
bad = 0
|
||||
for mouse_x in (700, 1000, 1300):
|
||||
anchor = measure(win, mouse_x)
|
||||
if anchor is None:
|
||||
print('мышь %4d: метку не видно, замер не вышел' % mouse_x)
|
||||
bad += 1
|
||||
continue
|
||||
off = anchor - mouse_x
|
||||
ok = abs(off) <= 2
|
||||
print('мышь %4d: опора %6.0f, промах %+.0f точек — %s'
|
||||
% (mouse_x, anchor, off, 'ok' if ok else 'ПЛОХО'))
|
||||
if not ok:
|
||||
bad += 1
|
||||
|
||||
print()
|
||||
if bad:
|
||||
print('ВЕРДИКТ: масштаб берётся не от мыши, случаев: %d' % bad)
|
||||
return 1
|
||||
print('ВЕРДИКТ: точка под мышкой остаётся на месте')
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue