Значки Icons8, окно «О программе» с указанием авторства
Значки заменены на присланные. Они вшиты в программу модулем uIconData,
который собирается из icons_online командой tools/make_icons.py — правятся
исходные картинки, а не он. Размер выбран под кнопку: двадцать четыре
точки в клетке двадцать восемь, уменьшение делает convert, пропорции
сохранены — все исходники квадратные.
Цвет значку задаётся при отрисовке: берётся прозрачность точки, а цвет —
тот, каким сейчас рисуется кнопка. Поэтому один значок годится и для
тёмной кнопки, и для оранжевой, и для недоступной. Перекрашенные
запоминаются: цветов ровно три.
Значок программы стал значком окна. Значок самого файла под Windows
задаётся не отсюда, а ресурсом при сборке — это осталось как было.
Окно «О программе» (Справка → О программе). Две вкладки: «Библиотеки и
авторство» и «Что умеет». Первая обязательна — бесплатная лицензия
Icons8 требует ссылку на каждый значок; заодно там перечислено всё, на
чём программа держится, и под какой лицензией. Списки разные по
системам: под Linux ffmpeg и libmpv ставит пакетный менеджер, под
Windows их скачивает сама программа, и это разные сборки.
Вкладки свои, а не TPageControl: системные вкладки под Windows остались
бы светлой полосой поверх тёмного окна.
Текст показывается нашим журналом — его можно выделить и скопировать,
так что ссылку из списка получится взять в браузер. Перенос по словам
свой: ссылки не рвутся, отступ списка сохраняется на продолжениях.
Свои рисованные значки из icons/ убраны: они больше не используются, и
держать рядом два набора значило бы путать.
2026-08-22 10:54:30 +03:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
"""
|
|
|
|
|
|
Готовит модуль с данными значков из файлов в icons_online.
|
|
|
|
|
|
|
|
|
|
|
|
Зачем модулем, а не файлами рядом с программой: программа не должна
|
|
|
|
|
|
зависеть от того, лежит ли что-то в её каталоге. Значки маленькие, все
|
|
|
|
|
|
вместе занимают единицы килобайт.
|
|
|
|
|
|
|
|
|
|
|
|
Размер выбран под кнопку: у неё двадцать восемь точек стороны, значку
|
|
|
|
|
|
достаётся клетка двадцать четыре на двадцать четыре. Уменьшение делает
|
|
|
|
|
|
convert с обычным сглаживанием, пропорции при этом сохраняются — все
|
|
|
|
|
|
исходники квадратные, растягивать нечего.
|
|
|
|
|
|
|
|
|
|
|
|
Запуск: python3 tools/make_icons.py
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import subprocess
|
|
|
|
|
|
import sys
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
SRC = ROOT / 'icons_online'
|
|
|
|
|
|
OUT = ROOT / 'src' / 'uIconData.pas'
|
|
|
|
|
|
|
|
|
|
|
|
# Имя в программе -> файл исходника и сторона в точках.
|
|
|
|
|
|
# Для «схлопывания» берётся вариант на шестьдесят четыре точки: чем крупнее
|
|
|
|
|
|
# исходник, тем чище получается уменьшение.
|
|
|
|
|
|
ICONS = [
|
|
|
|
|
|
('Snap', 'icons8-магнит-30.png', 24),
|
|
|
|
|
|
('Ripple', 'icons8-merge-vertical-64.png', 24),
|
|
|
|
|
|
('Log', 'icons8-property-30.png', 24),
|
Курсор прилипает к границам клипов
Курсор воспроизведения по щелчку вставал ровно туда, куда попала мышь.
В стык двух кусков так не попасть: на общем плане одна точка экрана —
это секунды материала, а ставят курсор чаще всего именно на стык.
Теперь он притягивается к границам клипов на любой дорожке и к началу
монтажа. Работает и при щелчке по клипу, и по линейке, и по пустому
месту, и при протяжке. Shift меняет решение на противоположное — как у
прилипания клипов.
Переключатель свой, со значком клея, рядом с магнитом: клипы липнут при
перетаскивании, курсор — при щелчке, это разные привычки, и одно бывает
нужно без другого. Состояние переживает перезапуск.
Расчёт открыт наружу и проверяется числами: семь проверок в lfmcheck,
от «стык рядом — притянуло» до «выключено — не притягивает».
2026-08-31 00:32:44 +03:00
|
|
|
|
('Glue', 'icons8-клей-30.png', 24),
|
2026-09-02 02:06:05 +03:00
|
|
|
|
('Target', 'icons8-цель-30.png', 24),
|
Выделение по времени, рез по краям промежутка, курсор идёт за резом
Режимов выделения стало два, переключаются клавишей D и кнопкой внизу,
режим показан её значком.
Рамкой по клипам — как было. По времени — протяжка отмечает промежуток по
всем дорожкам сразу, он остаётся виден пунктиром, и S режет все дорожки по
обоим его краям. Выделенной после этого остаётся ровно середина: следующим
действием её обычно удаляют, а выделение на старых клипах убрало бы не то.
Курсор теперь идёт за резом: после S встаёт на место реза (в режиме по
времени — на начало промежутка), после удаления куска — на место стыка,
после схлопывания дыры — туда же. Раньше в это место приходилось попадать
мышью заново.
Рез кладётся на кадровую сетку: между кадрами времени нет, и рез на доле
кадра оставлял бы в монтаже время, которого не бывает.
Выделение рамкой требует настоящего перекрытия, а не касания краями:
сосед, кончающийся ровно на краю рамки, попадал в выделение из-за разницы
в последнем знаке дробей.
Кнопка журнала и строка состояния сдвинуты вправо: переключатель выделения
встал в один ряд с прилипанием и схлопыванием.
Значки — icons8, набор ios-glyphs, авторство дописано в attribution.txt.
Набора «ios26» на их раздаче нет (404), взят ближайший по виду к нынешним.
Проверки: рез по курсору и по краям промежутка, кадровая сетка, выделение
середины, курсор после удаления и после схлопывания.
2026-09-29 23:58:30 +03:00
|
|
|
|
('SelectClips', 'icons8-select-all-90.png', 24),
|
|
|
|
|
|
('SelectRange', 'icons8-width-90.png', 24),
|
Значки Icons8, окно «О программе» с указанием авторства
Значки заменены на присланные. Они вшиты в программу модулем uIconData,
который собирается из icons_online командой tools/make_icons.py — правятся
исходные картинки, а не он. Размер выбран под кнопку: двадцать четыре
точки в клетке двадцать восемь, уменьшение делает convert, пропорции
сохранены — все исходники квадратные.
Цвет значку задаётся при отрисовке: берётся прозрачность точки, а цвет —
тот, каким сейчас рисуется кнопка. Поэтому один значок годится и для
тёмной кнопки, и для оранжевой, и для недоступной. Перекрашенные
запоминаются: цветов ровно три.
Значок программы стал значком окна. Значок самого файла под Windows
задаётся не отсюда, а ресурсом при сборке — это осталось как было.
Окно «О программе» (Справка → О программе). Две вкладки: «Библиотеки и
авторство» и «Что умеет». Первая обязательна — бесплатная лицензия
Icons8 требует ссылку на каждый значок; заодно там перечислено всё, на
чём программа держится, и под какой лицензией. Списки разные по
системам: под Linux ffmpeg и libmpv ставит пакетный менеджер, под
Windows их скачивает сама программа, и это разные сборки.
Вкладки свои, а не TPageControl: системные вкладки под Windows остались
бы светлой полосой поверх тёмного окна.
Текст показывается нашим журналом — его можно выделить и скопировать,
так что ссылку из списка получится взять в браузер. Перенос по словам
свой: ссылки не рвутся, отступ списка сохраняется на продолжениях.
Свои рисованные значки из icons/ убраны: они больше не используются, и
держать рядом два набора значило бы путать.
2026-08-22 10:54:30 +03:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
# Значок самой программы: отдельно, потому что окну нужен формат ico —
|
|
|
|
|
|
# только его умеет читать TIcon в LCL.
|
|
|
|
|
|
APP_ICON = ('icons8-показ-видеокадров-30.png', 32)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def make_ico(path: Path, side: int) -> bytes:
|
|
|
|
|
|
out = subprocess.run(
|
|
|
|
|
|
['convert', str(path), '-background', 'none', '-alpha', 'on',
|
|
|
|
|
|
'-resize', '%dx%d' % (side, side), 'ico:-'],
|
|
|
|
|
|
check=True, capture_output=True)
|
|
|
|
|
|
return out.stdout
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def scale(path: Path, side: int) -> bytes:
|
|
|
|
|
|
out = subprocess.run(
|
|
|
|
|
|
['convert', str(path), '-background', 'none', '-alpha', 'on',
|
|
|
|
|
|
'-resize', '%dx%d' % (side, side), 'png:-'],
|
|
|
|
|
|
check=True, capture_output=True)
|
|
|
|
|
|
return out.stdout
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pascal_bytes(data: bytes, indent: str = ' ') -> str:
|
|
|
|
|
|
parts = []
|
|
|
|
|
|
for i in range(0, len(data), 16):
|
|
|
|
|
|
chunk = ', '.join('$%02X' % b for b in data[i:i + 16])
|
|
|
|
|
|
parts.append(indent + chunk)
|
|
|
|
|
|
return ',\n'.join(parts)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main() -> int:
|
|
|
|
|
|
if not SRC.is_dir():
|
|
|
|
|
|
print('нет каталога с исходниками:', SRC, file=sys.stderr)
|
|
|
|
|
|
return 1
|
|
|
|
|
|
|
|
|
|
|
|
blocks = []
|
|
|
|
|
|
names = []
|
|
|
|
|
|
for name, filename, side in ICONS:
|
|
|
|
|
|
path = SRC / filename
|
|
|
|
|
|
if not path.is_file():
|
|
|
|
|
|
print('нет файла:', path, file=sys.stderr)
|
|
|
|
|
|
return 1
|
|
|
|
|
|
data = scale(path, side)
|
|
|
|
|
|
names.append((name, len(data)))
|
|
|
|
|
|
blocks.append(
|
|
|
|
|
|
' { %s, %d на %d точек }\n'
|
|
|
|
|
|
' Icon%sData: array[0..%d] of Byte = (\n%s\n );'
|
|
|
|
|
|
% (filename, side, side, name, len(data) - 1, pascal_bytes(data)))
|
|
|
|
|
|
|
|
|
|
|
|
app_src, app_side = APP_ICON
|
|
|
|
|
|
app_path = SRC / app_src
|
|
|
|
|
|
if not app_path.is_file():
|
|
|
|
|
|
print('нет файла:', app_path, file=sys.stderr)
|
|
|
|
|
|
return 1
|
|
|
|
|
|
app_data = make_ico(app_path, app_side)
|
|
|
|
|
|
names.append(('App (ico)', len(app_data)))
|
|
|
|
|
|
blocks.append(
|
|
|
|
|
|
' { %s, значок окна, %d на %d точек, формат ico }\n'
|
|
|
|
|
|
' IconAppData: array[0..%d] of Byte = (\n%s\n );'
|
|
|
|
|
|
% (app_src, app_side, app_side, len(app_data) - 1,
|
|
|
|
|
|
pascal_bytes(app_data)))
|
|
|
|
|
|
|
|
|
|
|
|
text = '''{
|
|
|
|
|
|
uIconData — значки, вшитые в программу.
|
|
|
|
|
|
|
|
|
|
|
|
Собран из файлов в icons_online командой:
|
|
|
|
|
|
|
|
|
|
|
|
python3 tools/make_icons.py
|
|
|
|
|
|
|
|
|
|
|
|
Правится не он, а исходные картинки: этот файл переписывается целиком.
|
|
|
|
|
|
|
|
|
|
|
|
Значки взяты у Icons8 и требуют указания авторства — оно есть в окне
|
|
|
|
|
|
«О программе», вкладка «Библиотеки и авторство». Ссылки на каждый значок
|
|
|
|
|
|
лежат в icons_online/attribution.txt.
|
|
|
|
|
|
|
|
|
|
|
|
Картинки чёрные на прозрачном фоне. Цвет им задаётся при отрисовке:
|
|
|
|
|
|
берётся прозрачность точки, а цвет — тот, каким сейчас рисуется кнопка.
|
|
|
|
|
|
Поэтому один и тот же значок годится и для тёмной кнопки, и для
|
|
|
|
|
|
оранжевой.
|
|
|
|
|
|
}
|
|
|
|
|
|
unit uIconData;
|
|
|
|
|
|
|
|
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
|
|
|
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
|
|
|
|
const
|
|
|
|
|
|
%s
|
|
|
|
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
|
|
|
|
end.
|
|
|
|
|
|
''' % ('\n\n'.join(blocks))
|
|
|
|
|
|
|
|
|
|
|
|
OUT.write_text(text, encoding='utf-8')
|
|
|
|
|
|
print('записан', OUT)
|
|
|
|
|
|
for name, size in names:
|
|
|
|
|
|
print(' %-8s %d байт' % (name, size))
|
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
sys.exit(main())
|