From 58d7748d51adbd3274725510017f8c2984f8f856 Mon Sep 17 00:00:00 2001 From: 4aiman Date: Sat, 22 Aug 2026 10:54:30 +0300 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=BD=D0=B0=D1=87=D0=BA=D0=B8=20Icons8,?= =?UTF-8?q?=20=D0=BE=D0=BA=D0=BD=D0=BE=20=C2=AB=D0=9E=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B3=D1=80=D0=B0=D0=BC=D0=BC=D0=B5=C2=BB=20=D1=81=20=D1=83?= =?UTF-8?q?=D0=BA=D0=B0=D0=B7=D0=B0=D0=BD=D0=B8=D0=B5=D0=BC=20=D0=B0=D0=B2?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D1=81=D1=82=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Значки заменены на присланные. Они вшиты в программу модулем uIconData, который собирается из icons_online командой tools/make_icons.py — правятся исходные картинки, а не он. Размер выбран под кнопку: двадцать четыре точки в клетке двадцать восемь, уменьшение делает convert, пропорции сохранены — все исходники квадратные. Цвет значку задаётся при отрисовке: берётся прозрачность точки, а цвет — тот, каким сейчас рисуется кнопка. Поэтому один значок годится и для тёмной кнопки, и для оранжевой, и для недоступной. Перекрашенные запоминаются: цветов ровно три. Значок программы стал значком окна. Значок самого файла под Windows задаётся не отсюда, а ресурсом при сборке — это осталось как было. Окно «О программе» (Справка → О программе). Две вкладки: «Библиотеки и авторство» и «Что умеет». Первая обязательна — бесплатная лицензия Icons8 требует ссылку на каждый значок; заодно там перечислено всё, на чём программа держится, и под какой лицензией. Списки разные по системам: под Linux ffmpeg и libmpv ставит пакетный менеджер, под Windows их скачивает сама программа, и это разные сборки. Вкладки свои, а не TPageControl: системные вкладки под Windows остались бы светлой полосой поверх тёмного окна. Текст показывается нашим журналом — его можно выделить и скопировать, так что ссылку из списка получится взять в браузер. Перенос по словам свой: ссылки не рвутся, отступ списка сохраняется на продолжениях. Свои рисованные значки из icons/ убраны: они больше не используются, и держать рядом два набора значило бы путать. --- icons/log.png | Bin 482 -> 0 bytes icons/log.svg | 11 - icons/ripple.png | Bin 589 -> 0 bytes icons/ripple.svg | 9 - icons/snap.png | Bin 783 -> 0 bytes icons/snap.svg | 8 - icons_online/attribution.txt | 4 + icons_online/icons8-merge-vertical-64.png | Bin 0 -> 463 bytes icons_online/icons8-property-30.png | Bin 0 -> 190 bytes icons_online/icons8-магнит-30.png | Bin 0 -> 291 bytes .../icons8-объединение-по-вертикали-30.png | Bin 0 -> 228 bytes icons_online/icons8-показ-видеокадров-30.png | Bin 0 -> 183 bytes src/uAboutForm.pas | 347 +++++++++++++++ src/uIconData.pas | 398 ++++++++++++++++++ src/uMainForm.pas | 43 +- src/uTheme.pas | 192 +++++---- tools/make_icons.py | 135 ++++++ 17 files changed, 1025 insertions(+), 122 deletions(-) delete mode 100644 icons/log.png delete mode 100644 icons/log.svg delete mode 100644 icons/ripple.png delete mode 100644 icons/ripple.svg delete mode 100644 icons/snap.png delete mode 100644 icons/snap.svg create mode 100644 icons_online/attribution.txt create mode 100644 icons_online/icons8-merge-vertical-64.png create mode 100644 icons_online/icons8-property-30.png create mode 100644 icons_online/icons8-магнит-30.png create mode 100644 icons_online/icons8-объединение-по-вертикали-30.png create mode 100644 icons_online/icons8-показ-видеокадров-30.png create mode 100644 src/uAboutForm.pas create mode 100644 src/uIconData.pas create mode 100644 tools/make_icons.py diff --git a/icons/log.png b/icons/log.png deleted file mode 100644 index 00c89e07da8f3c60ccbf123f56e1358f2ee2e510..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 482 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tg=CK)Uj~LMH3o);76yi2K%s^g z3=E|}g|8AA7_4S6Fo+k-*%fF5lweBoc6VW5Sk?NMQuI#TkM8%l6o_*0OV_;xZ@^ooDvSBFIh2#9Q{n{=SI{<=mVAjh8Z##t zT$9u=y5<)Y_+9?J?T=dKg_fHYf4i;gbaXlN#C4N1)3zlkX`)BMQsgI|ZtT2=O~ z#`#$njyS$Ovp=ZO`0u~NtFLNKIwB)$bN{iHa%gi$i)Egez}kZk_L=Pn*0v3J^2K(| zM$1*Lu6N3v>K7Qlm&|(Ab#=ceFaRY>Tq8 - - - - - - - - diff --git a/icons/ripple.png b/icons/ripple.png deleted file mode 100644 index de2c28cd2a2e9b6f111f59d9ca550bc426cd704c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 589 zcmV-T0004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0063uBQgL0010qN zS#tmY4#NNd4#NS*Z>VGd000McNliru>IfAU0t=Dz8sGo`0gXvSK~z}7?bXd{)L<0G z@n7b%mC}?>OVv%Mf`}kfs5&4DLKmgiA$nEnHMsHybSW+xaMwlcMv!qnq)f5%5m(*R z&LkOvAm+bJ@|@>=4)4jKprD}OKOjJ;X$|o;@A^&*=I9f(6>NLqvDoCwM`eM}-Z+|L z(Dc&78QM?YiYf@TJeg5oEWGyl4eQ1_R_ADc38^gD+6_-ld@%i^IakPP5D2W;vS(jc zB+lQUZpVRV9*C?YmCt5SQnjwBZQq_vr>glTsA<@BsBK$AkX$^CK`gfHjt#M8n|3{S zPfd{aR7nO?6HTwQ#bQ;VTUpAdNidx|CyA6673P&7P|_1w5}PUu-L{(LSV;yYWhY*H zCsxFPSOo@atfi!;YAluh(C@=kC`$46rwcheXQMCvov-qDPWJTwG9 zMXEEjk-=YB`U`fbprD}O-{Lnj_;g!XKe-D4000?uMObuGZ)S9NVRB^vcXxL#X>MzC bV_|S*E^l&Yo9;Xs00000NkvXXu0mjfLFf77 diff --git a/icons/ripple.svg b/icons/ripple.svg deleted file mode 100644 index b1ea32e..0000000 --- a/icons/ripple.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/icons/snap.png b/icons/snap.png deleted file mode 100644 index 150c24749583b48323eeabbb58ecb3282b9c24ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 783 zcmV+q1MvKbP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00002VoOIv0063uBQgL0010qN zS#tmY4#NNd4#NS*Z>VGd000McNliru>IfAU0t=Dz8sGo`0#8XqK~z}7?bu&S6k!y{ z@z3hE{s|p5D5yvyBE858Ybg{W@O5-iy{zgTL@%H}5GX_#re0`8Xhc+q>1>$mYHk-R zf%VKdD_R)-ZqIq1@AI2EGv~~($I8`_8|l`GMeoH~7d6%a=ylso!;YEtCF`PmT@Eg} zhILW)MGbWTcBBKqzX#+I>DjFBx$O0wqAmO7(e0M2c;T*zT>$jBqloA3nXEbJSHx;P z^_}YAf+D_){)e0VSE?vY%_79g!C0+U%4r*H=b+Po0iD5Em!hJsojWLK(`!iCtWQDs zWi6JiiB)z2h+K5tu#X-Eu2{}icwc>~GHj-Q<0U{R- z8g^d0s%kK&s;W)DMzkim2muNreTED=r=5iDZARLhRY6(R(w{CufDV@oxuH*+EQ*}h zq(Q4OpMMXA%Cy;Wr*-RcC=(#B(*- zzM1pZ2P@eCB@^lAeQ- zDHT*)kxO`E<>Zu%d*-oerSL{cfHhyeQE*7Rd8@&kig`0ejCgG!$zfs!lbwcc<;W4YQySoXwF>^)IJtB9qh))yVb!j?f;v60N7UbeCfx=>d8l&ZgLjV8(8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H1 N002ovPDHLkV1m1+T%iB} diff --git a/icons/snap.svg b/icons/snap.svg deleted file mode 100644 index 1bec0db..0000000 --- a/icons/snap.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/icons_online/attribution.txt b/icons_online/attribution.txt new file mode 100644 index 0000000..633e7a9 --- /dev/null +++ b/icons_online/attribution.txt @@ -0,0 +1,4 @@ +Log panel: Property icon by Icons8 +Ripple gaps: Merge Vertical icon by Icons8 +Magnet: Magnet icon by Icons8 +App icon: Showing Video Frames icon by Icons8 \ No newline at end of file diff --git a/icons_online/icons8-merge-vertical-64.png b/icons_online/icons8-merge-vertical-64.png new file mode 100644 index 0000000000000000000000000000000000000000..d03c248518d144e9886c1d8b2af5e244bcf2d040 GIT binary patch literal 463 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9GG!XV7ZFl&wk0|R5D zr;B4q#hkY@4852gMcV8GqE*#5eB|L`thQ}fx;A`+?@Q5~qon63`>vUu^HO}Jd1ky`*j$&C$J_kZeq}J5NlvP!L)%P zRYqPel0i&?JHeb~55rzvfdU?zi%d*z2T~Il#Sc_R=l6DUGG=hwG^&9xd8`w4PLG)T&0xCyGfVvvs-v*uyPe=ps!s+9Xr#nqfw<_ zm%PbrG)mp-_)KKOx{H6!xu;luW}E5l5V@FJ+rhQ@jOv0cJ#K{s4G*`~GEHt-;`4)- zr{VA{UQym6M=KuBKkz>$`q;ia_JG8W kRTA~FN(Uv9d2~N8rxgBp$60#O3K&BSp00i_>zopr0G|4=82|tP literal 0 HcmV?d00001 diff --git a/icons_online/icons8-property-30.png b/icons_online/icons8-property-30.png new file mode 100644 index 0000000000000000000000000000000000000000..f37634ccb7afbb5ee671f5878c985e53abac5153 GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3oCO|{#S9GG!XV7ZFl&wkP_V$$ z#WAE}&fBSuTn!2WuJ^w#idK(R*?qi!f$NG^ZqwD3AH)wou$d9bacsUsqiDd=iUg0& zTGy3*I+`1$R1Y1=(p}f;Q*(U=qxcoe@{*aK^`(C|Xs#$e^4$D=RHIbd=#MRV4HFoi3{ zEVo>j$`$A-gzglX7~UAmx$>0a`;F&yJVMoiGG%u}i?Cn1es8-*=u597-iIfs8?Z!q zx}A&)OIH+}&*Pl5^4yIJA5|Y+Fi`oIW;Ji2u-B1gzc=0WE_`&Nvp#H%vgq@-OaH95 m`1M6L-{{n9^Di>?r?~g74GH$$(=!R^K?YA(KbLh*2~7ZW?{A3! literal 0 HcmV?d00001 diff --git a/icons_online/icons8-объединение-по-вертикали-30.png b/icons_online/icons8-объединение-по-вертикали-30.png new file mode 100644 index 0000000000000000000000000000000000000000..0bcfe981e7dfc253c04f0bcd1553f973ebae54b1 GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3oCO|{#S9GG!XV7ZFl&wkP;i>3 zi(^Q|oVQbaxf&D%-1d8ml>ASAq9q=7I;vz2XQG(liinJkGtH4aKR%}XVVu%-lVOKT zJny5fuUdL+Di!zvtAXxh1Z6Jzu+}%k${g4Ub+=-g`;R Ze4W( literal 0 HcmV?d00001 diff --git a/icons_online/icons8-показ-видеокадров-30.png b/icons_online/icons8-показ-видеокадров-30.png new file mode 100644 index 0000000000000000000000000000000000000000..28ea57080e2274fab70b7769e9fac9fdbbe90c81 GIT binary patch literal 183 zcmeAS@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3oCO|{#S9GG!XV7ZFl&wkP%zWe z#WAE}&fBSuTnz?1EYB;&>et$5{&jaz6hGK>=|Y$FhIWS+4&MR<>XX^b4oEF$SgEGR z805dMv-YLc{ 0) then + begin + Result := Result + Rest + LineEnding; + Continue; + end; + + { Отступ запоминается и повторяется на всех продолжениях. } + Indent := 0; + while (Indent < Length(Rest)) and (Rest[Indent + 1] = ' ') do + Inc(Indent); + + while Length(Rest) > AWidth do + begin + { Ищем последний пробел в пределах ширины; не нашли — рвём по + ширине, иначе одно длинное слово повесило бы разбор. } + Space := AWidth; + while (Space > Indent + 1) and (Rest[Space] <> ' ') do + Dec(Space); + if Space <= Indent + 1 then + Space := AWidth; + Line := Copy(Rest, 1, Space); + Rest := StringOfChar(' ', Indent) + Copy(Rest, Space + 1, Length(Rest)); + Result := Result + TrimRight(Line) + LineEnding; + end; + Result := Result + Rest + LineEnding; + end; + finally + Src.Free; + end; +end; + +type + { Обработчики живут в объекте: событиям нужны методы. } + TAboutDialog = class(TComponent) + public + Form: TForm; + BtnCredits: TThemedButton; + BtnFeatures: TThemedButton; + ViewCredits: TLogView; + ViewFeatures: TLogView; + procedure ShowCredits(Sender: TObject); + procedure ShowFeatures(Sender: TObject); + procedure Select(ACredits: Boolean); + end; + +procedure TAboutDialog.Select(ACredits: Boolean); +begin + BtnCredits.Down := ACredits; + BtnFeatures.Down := not ACredits; + ViewCredits.Visible := ACredits; + ViewFeatures.Visible := not ACredits; +end; + +procedure TAboutDialog.ShowCredits(Sender: TObject); +begin + Select(True); +end; + +procedure TAboutDialog.ShowFeatures(Sender: TObject); +begin + Select(False); +end; + +{ Кто это написал и на чём оно держится. + + Списки разные по системам не для красоты: под Linux ffmpeg и libmpv + ставит пакетный менеджер, под Windows их скачивает сама программа из + окна «Зависимости», и это разные сборки с разными лицензиями. Указывать + надо то, что стоит у человека, а не то, что бывает вообще. } +function CreditsText: string; +begin + Result := + 'nlve — монтаж без перекодирования' + LineEnding + + LineEnding + + 'Автор: 4aiman' + LineEnding + + LineEnding + + 'Замысел в одном: куски видео вырезаются и склеиваются копированием ' + + 'потока, без пересчёта картинки. То, что обычный монтажный редактор ' + + 'считает часами, здесь собирается за время копирования файла. ' + + 'Пересобирается только то, что иначе никак: переходы, прозрачность, ' + + 'точные резы и куски файлов с чужими параметрами.' + LineEnding + + LineEnding + + '── Значки ──' + LineEnding + + LineEnding + + 'Значки взяты у Icons8 и требуют указания авторства.' + LineEnding + + LineEnding + + 'Прилипание — значок «Magnet» от Icons8:' + LineEnding + + ' https://icons8.com/icon/79942/magnet' + LineEnding + + 'Схлопывание — значок «Merge Vertical» от Icons8:' + LineEnding + + ' https://icons8.com/icon/2EQegp8tbR6Q/merge-vertical' + LineEnding + + 'Журнал — значок «Property» от Icons8:' + LineEnding + + ' https://icons8.com/icon/79872/property' + LineEnding + + 'Значок программы — «Showing Video Frames» от Icons8:' + LineEnding + + ' https://icons8.com/icon/69093/showing-video-frames' + LineEnding + + LineEnding + + 'Сам Icons8: https://icons8.com' + LineEnding + + LineEnding + + '── Чем режется и что показывает ──' + LineEnding + + LineEnding + + {$IFDEF WINDOWS} + 'ffmpeg и ffprobe — вся работа с видео и звуком: нарезка, склейка, ' + + 'перекодирование, разбор файлов.' + LineEnding + + ' Сборка BtbN, вариант gpl:' + LineEnding + + ' https://github.com/BtbN/FFmpeg-Builds' + LineEnding + + ' Лицензия сборки: GPL-3.0' + LineEnding + + ' Сам ffmpeg: https://ffmpeg.org' + LineEnding + + LineEnding + + 'libmpv — предпросмотр монтажа. Играет виртуальный список кусков, ' + + 'не собирая при этом ни одного файла.' + LineEnding + + ' Сборка shinchiro/mpv-winbuild-cmake:' + LineEnding + + ' https://github.com/shinchiro/mpv-winbuild-cmake' + LineEnding + + ' Лицензия сборки: GPL' + LineEnding + + ' Сам mpv: https://mpv.io' + LineEnding + + LineEnding + + '7-Zip (7zr.exe) — распаковка сборок libmpv, они раздаются в .7z.' + + LineEnding + + ' https://www.7-zip.org' + LineEnding + + ' Лицензия: LGPL-2.1' + LineEnding + + {$ELSE} + 'ffmpeg и ffprobe — вся работа с видео и звуком: нарезка, склейка, ' + + 'перекодирование, разбор файлов.' + LineEnding + + ' Ставится пакетным менеджером: sudo apt install ffmpeg' + LineEnding + + ' https://ffmpeg.org' + LineEnding + + ' Лицензия сборок в Ubuntu: GPL-2 и новее' + LineEnding + + LineEnding + + 'libmpv — предпросмотр монтажа. Играет виртуальный список кусков, ' + + 'не собирая при этом ни одного файла.' + LineEnding + + ' Ставится пакетным менеджером: sudo apt install mpv' + LineEnding + + ' https://mpv.io' + LineEnding + + ' Лицензия сборок в Ubuntu: GPL-3 и новее' + LineEnding + + {$ENDIF} + LineEnding + + '── На чём написано ──' + LineEnding + + LineEnding + + 'Free Pascal — компилятор.' + LineEnding + + ' https://www.freepascal.org' + LineEnding + + ' Лицензия: GPL с оговоркой о компоновке для библиотеки времени ' + + 'выполнения' + LineEnding + + LineEnding + + 'Lazarus LCL — библиотека окон и элементов управления.' + LineEnding + + ' https://www.lazarus-ide.org' + LineEnding + + ' Лицензия: LGPL-2 с оговоркой о компоновке' + LineEnding + + LineEnding + + 'Ни ffmpeg, ни libmpv в состав программы не входят и вместе с ней не ' + + 'раздаются: ffmpeg запускается отдельной программой, libmpv ' + + 'подключается на ходу и ставится отдельно.'; +end; + +{ Что программа умеет. Не список кнопок, а список того, ради чего её + открывают. } +function FeaturesText: string; +begin + Result := + 'Монтаж' + LineEnding + + LineEnding + + ' Дорожки для картинки и для звука, сколько нужно. При перекрытии ' + + 'картинку даёт верхняя дорожка целиком, а звук всех дорожек ' + + 'смешивается: под голос кладётся музыка.' + LineEnding + + ' Клипы переносятся, растягиваются за края, режутся по курсору ' + + '(S) и удаляются. Прилипание к краям соседей и к курсору; Shift во ' + + 'время перетаскивания отменяет его.' + LineEnding + + ' Связки: видео и его звук ходят вместе, Ctrl+G связывает и ' + + 'развязывает. Развязанный звук двигается отдельно от своей картинки.' + + LineEnding + + ' Схлопывание дыр: вручную (Ctrl+Shift+R) или само при ' + + 'перетаскивании, на текущей дорожке или на всех сразу.' + LineEnding + + ' Отмена и повтор любого действия.' + LineEnding + + LineEnding + + 'Что видно на дорожках' + LineEnding + + LineEnding + + ' Форма звука на звуковых клипах; Shift со стрелками вверх и вниз ' + + 'усиливает её, когда запись тихая.' + LineEnding + + ' Громкость клипа — ручкой прямо на нём, прозрачность — так же на ' + + 'видеоклипе.' + LineEnding + + ' Появление и уход — за верхние углы клипа. Перекрытие двух клипов ' + + 'одной дорожки помечено косым крестом: там сам собой выходит переход.' + + LineEnding + + ' Цвет краёв показывает, притянут рез к опорному кадру или потребует ' + + 'перекодирования.' + LineEnding + + LineEnding + + 'Предпросмотр' + LineEnding + + LineEnding + + ' Играет монтаж целиком, не собирая ни одного файла: плееру ' + + 'скармливается виртуальный список кусков.' + LineEnding + + ' Показывает кадр проекта, а не кадр очередного исходника — что ' + + 'видно здесь, то и получится в ролике.' + LineEnding + + ' Участки с прозрачностью и переходами заранее сводятся в отдельные ' + + 'файлы, поэтому видны и они.' + LineEnding + + LineEnding + + 'Кадрирование' + LineEnding + + LineEnding + + ' У каждого клипа своё: вписать целиком, заполнить кадр с обрезкой ' + + 'или растянуть. Плюс увеличение, смещение, поворот и отражение.' + + LineEnding + + ' Рамку в окне кадрирования можно тянуть мышью, а не только задавать ' + + 'числами.' + LineEnding + + LineEnding + + 'Сборка ролика' + LineEnding + + LineEnding + + ' Обычная — копированием потоков. Час материала собирается за время ' + + 'копирования файла.' + LineEnding + + ' Перед сборкой программа говорит, сколько секунд придётся ' + + 'пересобрать и почему.' + LineEnding + + ' Точный рез перекодирует только огрызок до ближайшего опорного ' + + 'кадра, остальное копируется.' + LineEnding + + ' Отдельно — сборка с перекодированием: размер кадра от 720p до 4K, ' + + 'поток в килобитах, кодек HEVC или H.264. Считает видеокарта.' + + LineEnding + + ' Перепаковка готовых файлов в другой контейнер, без пересчёта.' + + LineEnding + + LineEnding + + 'Мелочи, которые важны' + LineEnding + + LineEnding + + ' Индекс опорных кадров читается из заголовка файла, а не ' + + 'перебором: на шестигигабайтном файле это двадцать миллисекунд ' + + 'вместо двенадцати секунд.' + LineEnding + + ' Фоновая работа видна внизу полоской и отмечена на монтаже ' + + 'штриховкой.' + LineEnding + + ' Все окна в своих цветах, а не в системных.' + LineEnding + + ' Настройки, недавние проекты и размеры окна переживают перезапуск.'; +end; + +procedure ShowAboutForm; +var + Dlg: TAboutDialog; + BtnClose: TThemedButton; +begin + Dlg := TAboutDialog.Create(nil); + try + Dlg.Form := TForm.CreateNew(nil); + Dlg.Form.Caption := 'О программе'; + Dlg.Form.Position := poScreenCenter; + Dlg.Form.ClientWidth := 720; + Dlg.Form.ClientHeight := 560; + Dlg.Form.Constraints.MinWidth := 480; + Dlg.Form.Constraints.MinHeight := 320; + + Dlg.BtnCredits := TThemedButton.Create(Dlg.Form); + Dlg.BtnCredits.Parent := Dlg.Form; + Dlg.BtnCredits.SetBounds(12, 12, 240, 28); + Dlg.BtnCredits.Caption := 'Библиотеки и авторство'; + Dlg.BtnCredits.TabStop := False; + Dlg.BtnCredits.OnClick := @Dlg.ShowCredits; + + Dlg.BtnFeatures := TThemedButton.Create(Dlg.Form); + Dlg.BtnFeatures.Parent := Dlg.Form; + Dlg.BtnFeatures.SetBounds(258, 12, 180, 28); + Dlg.BtnFeatures.Caption := 'Что умеет'; + Dlg.BtnFeatures.TabStop := False; + Dlg.BtnFeatures.OnClick := @Dlg.ShowFeatures; + + Dlg.ViewCredits := TLogView.Create(Dlg.Form); + Dlg.ViewCredits.Parent := Dlg.Form; + Dlg.ViewCredits.SetBounds(12, 48, 696, 460); + Dlg.ViewCredits.Anchors := [akTop, akLeft, akRight, akBottom]; + { Ширина подобрана замером: при 720 точках окна в строку входит около + ста шестидесяти знаков, берём с запасом. } + Dlg.ViewCredits.SetText(Wrap(CreditsText, 150)); + + Dlg.ViewFeatures := TLogView.Create(Dlg.Form); + Dlg.ViewFeatures.Parent := Dlg.Form; + Dlg.ViewFeatures.SetBounds(12, 48, 696, 460); + Dlg.ViewFeatures.Anchors := [akTop, akLeft, akRight, akBottom]; + Dlg.ViewFeatures.SetText(Wrap(FeaturesText, 150)); + + BtnClose := TThemedButton.Create(Dlg.Form); + BtnClose.Parent := Dlg.Form; + BtnClose.SetBounds(608, 520, 100, 28); + BtnClose.Anchors := [akRight, akBottom]; + BtnClose.Caption := 'Закрыть'; + BtnClose.ModalResult := mrOk; + BtnClose.Default := True; + BtnClose.Cancel := True; + + ApplyDarkTheme(Dlg.Form); + { Значок окна берётся у главного окна: своего у диалога нет. } + Dlg.Select(True); + Dlg.Form.ShowModal; + finally + Dlg.Form.Free; + Dlg.Free; + end; +end; + +end. diff --git a/src/uIconData.pas b/src/uIconData.pas new file mode 100644 index 0000000..881bffe --- /dev/null +++ b/src/uIconData.pas @@ -0,0 +1,398 @@ +{ + uIconData — значки, вшитые в программу. + + Собран из файлов в icons_online командой: + + python3 tools/make_icons.py + + Правится не он, а исходные картинки: этот файл переписывается целиком. + + Значки взяты у Icons8 и требуют указания авторства — оно есть в окне + «О программе», вкладка «Библиотеки и авторство». Ссылки на каждый значок + лежат в icons_online/attribution.txt. + + Картинки чёрные на прозрачном фоне. Цвет им задаётся при отрисовке: + берётся прозрачность точки, а цвет — тот, каким сейчас рисуется кнопка. + Поэтому один и тот же значок годится и для тёмной кнопки, и для + оранжевой. +} +unit uIconData; + +{$mode objfpc}{$H+} + +interface + +const + { icons8-магнит-30.png, 24 на 24 точек } + IconSnapData: array[0..472] of Byte = ( + $89, $50, $4E, $47, $0D, $0A, $1A, $0A, $00, $00, $00, $0D, $49, $48, $44, $52, + $00, $00, $00, $18, $00, $00, $00, $18, $08, $04, $00, $00, $00, $4A, $7E, $F5, + $73, $00, $00, $00, $20, $63, $48, $52, $4D, $00, $00, $7A, $26, $00, $00, $80, + $84, $00, $00, $FA, $00, $00, $00, $80, $E8, $00, $00, $75, $30, $00, $00, $EA, + $60, $00, $00, $3A, $98, $00, $00, $17, $70, $9C, $BA, $51, $3C, $00, $00, $00, + $02, $62, $4B, $47, $44, $00, $00, $AA, $8D, $23, $32, $00, $00, $00, $09, $70, + $48, $59, $73, $00, $00, $0B, $13, $00, $00, $0B, $13, $01, $00, $9A, $9C, $18, + $00, $00, $00, $07, $74, $49, $4D, $45, $07, $EA, $08, $16, $07, $2D, $16, $EF, + $B8, $28, $FD, $00, $00, $01, $3E, $49, $44, $41, $54, $38, $CB, $BD, $92, $31, + $4B, $C3, $40, $14, $C7, $7F, $97, $44, $29, $68, $03, $5A, $45, $EA, $D0, $A5, + $6B, $41, $44, $5C, $0A, $0E, $3A, $15, $DC, $1D, $DD, $FB, $51, $74, $71, $29, + $F8, $39, $EC, $62, $06, $17, $5D, $EA, $22, $D2, $88, $93, $E0, $22, $68, $A1, + $AD, $14, $AA, $A0, $B6, $E6, $39, $24, $17, $AE, $69, $32, $88, $D4, $77, $4B, + $EE, $DD, $EF, $7F, $EF, $DD, $FB, $07, $66, $1D, $6A, $6A, $EF, $B2, $4D, $85, + $22, $F3, $74, $B9, $E3, $9A, $1E, $92, $2D, $5F, $E0, $80, $0B, $9E, $78, $27, + $40, $F8, $E4, $85, $4B, $0E, $71, $B3, $F0, $35, $4E, $78, $45, $12, $6B, $40, + $83, $62, $1A, $BE, $44, $83, $AF, $29, $5C, $10, $46, $9C, $B2, $9C, $C4, $1D, + $EA, $0C, $53, $71, $41, $78, $A3, $8E, $33, $29, $28, $E1, $67, $E2, $82, $E0, + $53, $0A, $41, $2B, $9A, $CD, $1E, $65, $43, $3E, $C0, $C7, $67, $60, $64, $CA, + $EC, $86, $13, $D5, $82, $2A, $B9, $F8, $B0, $C7, $11, $35, $6A, $1C, $D3, $8F, + $73, $39, $AA, $A6, $05, $16, $9E, $51, $BE, $49, $01, $80, $02, $4D, $23, $EB, + $85, $97, $EB, $0A, $E6, $AC, $3B, $D1, $CD, $7D, $3A, $46, $D6, $35, $5B, $9A, + $74, $5C, $52, $BE, $62, $C2, $E2, $97, $31, $7B, $81, $F6, $4F, $F1, $41, $1B, + $61, $8E, $AD, $04, $71, $C3, $08, $C5, $86, $7E, $83, $16, $D8, $DC, $B3, $C3, + $37, $AB, $3C, $18, $03, $50, $0C, $D9, $A7, $8B, $4D, $0B, $FB, $8F, $2D, $8D, + $D9, $A4, $85, $E0, $90, $27, $88, $4F, $03, $F2, $78, $8C, $51, $54, $B8, $D5, + $AD, $84, $A5, $D7, $59, $C4, $02, $84, $47, $CE, $68, $47, $82, $02, $2B, $11, + $F1, $CC, $39, $57, $88, $B6, $43, $A1, $8C, $CE, $83, $D8, $30, $65, $B4, $1C, + $FE, $20, $FF, $10, $3F, $90, $74, $7D, $D8, $DF, $AB, $6B, $DD, $00, $00, $00, + $00, $49, $45, $4E, $44, $AE, $42, $60, $82 + ); + + { icons8-merge-vertical-64.png, 24 на 24 точек } + IconRippleData: array[0..457] of Byte = ( + $89, $50, $4E, $47, $0D, $0A, $1A, $0A, $00, $00, $00, $0D, $49, $48, $44, $52, + $00, $00, $00, $18, $00, $00, $00, $18, $08, $04, $00, $00, $00, $4A, $7E, $F5, + $73, $00, $00, $00, $20, $63, $48, $52, $4D, $00, $00, $7A, $26, $00, $00, $80, + $84, $00, $00, $FA, $00, $00, $00, $80, $E8, $00, $00, $75, $30, $00, $00, $EA, + $60, $00, $00, $3A, $98, $00, $00, $17, $70, $9C, $BA, $51, $3C, $00, $00, $00, + $02, $62, $4B, $47, $44, $00, $00, $AA, $8D, $23, $32, $00, $00, $00, $09, $70, + $48, $59, $73, $00, $00, $0B, $13, $00, $00, $0B, $13, $01, $00, $9A, $9C, $18, + $00, $00, $00, $07, $74, $49, $4D, $45, $07, $EA, $08, $16, $07, $2D, $16, $EF, + $B8, $28, $FD, $00, $00, $01, $2F, $49, $44, $41, $54, $38, $CB, $CD, $D2, $3D, + $2F, $83, $51, $18, $C6, $F1, $DF, $C3, $63, $31, $34, $11, $B5, $35, $D1, $A9, + $C1, $E0, $25, $4C, $66, $49, $F9, $16, $24, $96, $C6, $37, $A8, $18, $7D, $02, + $31, $98, $18, $99, $25, $44, $F8, $02, $26, $B1, $30, $30, $78, $D9, $90, $18, + $24, $35, $F4, $B4, $8F, $A1, $8A, $7A, $5A, $D2, $45, $FC, $C7, $73, $DF, $D7, + $7D, $AE, $EB, $3E, $87, $2E, $89, $52, $27, $3D, $7A, $50, $43, $2F, $EA, $EA, + $BF, $8D, $28, $3A, $B6, $A9, $5F, $BF, $4D, $C7, $8A, $DF, $CB, $71, $4A, $90, + $33, $27, $2B, $C6, $AC, $49, $BB, $69, $03, $5D, $F2, $77, $82, $A8, $CD, $BE, + $BE, $F2, $51, $6F, $0A, $46, $2D, $E8, $EB, $D8, $1E, $2B, $1A, $69, $15, $0C, + $DB, $B6, $66, $A8, $6D, $7B, $D6, $AA, $1D, $F9, $A6, $B6, $60, $40, $50, $90, + $55, $36, $A3, $FC, $CD, $5A, $64, $C2, $BA, $79, $91, $82, $07, $B1, $67, $F6, + $54, $BC, $78, $95, $48, $24, $AE, $1D, $49, $9C, $C9, $C8, $38, $93, $38, $74, + $F5, $5E, $79, $F5, $A2, $62, $2F, $16, $54, $D5, $BE, $CC, $4C, $3A, $E4, $08, + $AA, $EA, $02, $79, $E3, $C6, $94, $D4, $04, $07, $26, $2D, $B7, $DC, $B0, $6C, + $C2, $BE, $A0, $A6, $64, $CC, $B8, $7C, $EC, $E6, $3D, $F4, $93, $2D, $1B, $1E, + $4D, $B7, $CC, $4D, $9C, $5B, $B2, $A2, $E4, $C6, $45, $23, $74, $83, $5B, $8B, + $4E, $54, $DB, $9A, $79, $B2, $EE, $D4, $5D, $73, $4B, $0D, $2E, $5D, $76, $74, + $4F, $70, $F4, $F9, $24, $3F, $47, $4D, $AD, $E2, $1F, $FF, $D6, $4F, $AA, $2A, + $EE, $05, $C1, $BD, $4A, $87, $BD, $B5, $30, $68, $4A, $4E, $24, $92, $33, $65, + $B0, $5B, $07, $29, $DE, $00, $F6, $77, $56, $B3, $E2, $94, $4B, $80, $00, $00, + $00, $00, $49, $45, $4E, $44, $AE, $42, $60, $82 + ); + + { icons8-property-30.png, 24 на 24 точек } + IconLogData: array[0..425] of Byte = ( + $89, $50, $4E, $47, $0D, $0A, $1A, $0A, $00, $00, $00, $0D, $49, $48, $44, $52, + $00, $00, $00, $18, $00, $00, $00, $18, $08, $04, $00, $00, $00, $4A, $7E, $F5, + $73, $00, $00, $00, $20, $63, $48, $52, $4D, $00, $00, $7A, $26, $00, $00, $80, + $84, $00, $00, $FA, $00, $00, $00, $80, $E8, $00, $00, $75, $30, $00, $00, $EA, + $60, $00, $00, $3A, $98, $00, $00, $17, $70, $9C, $BA, $51, $3C, $00, $00, $00, + $02, $62, $4B, $47, $44, $00, $00, $AA, $8D, $23, $32, $00, $00, $00, $09, $70, + $48, $59, $73, $00, $00, $0B, $13, $00, $00, $0B, $13, $01, $00, $9A, $9C, $18, + $00, $00, $00, $07, $74, $49, $4D, $45, $07, $EA, $08, $16, $07, $2D, $16, $EF, + $B8, $28, $FD, $00, $00, $01, $0F, $49, $44, $41, $54, $38, $CB, $B5, $D3, $BF, + $2E, $83, $51, $18, $C7, $F1, $CF, $5B, $15, $0C, $74, $93, $88, $91, $0B, $E8, + $68, $60, $33, $34, $B1, $1A, $F4, $1E, $0C, $66, $8B, $C5, $05, $B8, $01, $89, + $2B, $30, $18, $24, $4C, $0D, $8B, $41, $13, $46, $62, $90, $18, $A4, $4B, $55, + $3A, $28, $AD, $F7, $18, $AA, $F5, $36, $DA, $B7, $25, $3C, $67, $38, $27, $4F, + $9E, $EF, $79, $FE, $9C, $F3, $E3, $BF, $2D, $42, $24, $12, $8D, $10, $1B, $04, + $21, $8B, $39, $5B, $96, $65, $84, $D4, $8B, $63, $E7, $F6, $3C, $42, $51, $A3, + $4D, $0F, $59, $2F, $36, $C8, $60, $C6, $C4, $48, $E5, $4F, $CA, $B5, $81, $1F, + $59, $F6, $73, $7F, $D6, $1C, $12, $39, $2E, $97, $04, $8A, $2E, $BA, $E7, $7E, + $D6, $B2, $E4, $38, $09, $D4, $3C, $0D, $C9, $50, $EB, $2D, $09, $F2, $0A, $0E, + $B0, $69, $36, $E1, $6D, $3A, $72, $F2, $BD, $07, $98, $B7, $EA, $50, $B0, $66, + $B1, $FB, $26, $91, $86, $DB, $41, $C0, $A9, $92, $86, $60, $A5, $67, $76, $C1, + $5B, $BF, $29, $B5, $33, $E4, $95, $50, $90, $4B, $64, $68, $B9, $74, $DD, $1F, + $C8, $DB, $76, $23, $D8, $B5, $90, $F0, $BE, $DA, $19, $04, $9C, $B9, $73, $8F, + $75, $53, $09, $6F, $EC, $61, $50, $49, $55, $55, $70, $95, $36, $DD, $5F, $7F, + $8D, $08, $63, $29, $71, $EF, $1D, $C5, $74, $80, $7D, $F5, $54, $11, $05, $D3, + $5F, $40, $45, $59, $3C, $44, $73, $91, $BA, $B2, $4A, $47, $A2, $A3, $76, $12, + $A7, $AA, $F2, $8F, $EC, $03, $0F, $C8, $51, $5A, $EC, $EA, $63, $7C, $00, $00, + $00, $00, $49, $45, $4E, $44, $AE, $42, $60, $82 + ); + + { icons8-показ-видеокадров-30.png, значок окна, 32 на 32 точек, формат ico } + IconAppData: array[0..4285] of Byte = ( + $00, $00, $01, $00, $01, $00, $20, $20, $00, $00, $01, $00, $20, $00, $A8, $10, + $00, $00, $16, $00, $00, $00, $28, $00, $00, $00, $20, $00, $00, $00, $40, $00, + $00, $00, $01, $00, $20, $00, $00, $00, $00, $00, $00, $10, $00, $00, $13, $0B, + $00, $00, $13, $0B, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $37, $00, $00, $00, $A1, $00, $00, $00, $BB, $00, $00, + $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, + $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, + $00, $BB, $00, $00, $00, $A1, $00, $00, $00, $37, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $51, $00, $00, $00, $E5, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $E5, $00, $00, $00, $51, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $1E, $00, $00, $00, $58, $00, $00, $00, $66, $00, $00, + $00, $66, $00, $00, $00, $66, $00, $00, $00, $66, $00, $00, $00, $66, $00, $00, + $00, $66, $00, $00, $00, $66, $00, $00, $00, $66, $00, $00, $00, $66, $00, $00, + $00, $66, $00, $00, $00, $58, $00, $00, $00, $1E, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $15, $00, $00, + $00, $54, $00, $00, $00, $74, $00, $00, $00, $77, $00, $00, $00, $77, $00, $00, + $00, $77, $00, $00, $00, $77, $00, $00, $00, $77, $00, $00, $00, $77, $00, $00, + $00, $77, $00, $00, $00, $77, $00, $00, $00, $77, $00, $00, $00, $77, $00, $00, + $00, $77, $00, $00, $00, $77, $00, $00, $00, $77, $00, $00, $00, $77, $00, $00, + $00, $77, $00, $00, $00, $77, $00, $00, $00, $77, $00, $00, $00, $77, $00, $00, + $00, $77, $00, $00, $00, $77, $00, $00, $00, $74, $00, $00, $00, $54, $00, $00, + $00, $15, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $69, $00, $00, + $00, $DB, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $DA, $00, $00, + $00, $68, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $BE, $00, $00, + $00, $FF, $00, $00, $00, $C7, $00, $00, $00, $A4, $00, $00, $00, $D7, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $D7, $00, $00, $00, $A4, $00, $00, $00, $C7, $00, $00, $00, $FF, $00, $00, + $00, $BD, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $55, $00, $00, $00, $00, $00, $00, $00, $88, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $88, $00, $00, $00, $00, $00, $00, $00, $55, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $79, $00, $00, $00, $29, $00, $00, $00, $A1, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $A1, $00, $00, $00, $29, $00, $00, $00, $79, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $EC, $00, $00, $00, $E1, $00, $00, $00, $F2, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $F2, $00, $00, $00, $E1, $00, $00, $00, $EC, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $5C, $00, $00, $00, $00, $00, $00, $00, $8D, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $8D, $00, $00, $00, $00, $00, $00, $00, $5C, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $5C, $00, $00, $00, $00, $00, $00, $00, $8D, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $8D, $00, $00, $00, $00, $00, $00, $00, $5C, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $EC, $00, $00, $00, $E1, $00, $00, $00, $F2, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $F2, $00, $00, $00, $E1, $00, $00, $00, $EC, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $79, $00, $00, $00, $29, $00, $00, $00, $A1, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $A1, $00, $00, $00, $29, $00, $00, $00, $79, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $55, $00, $00, $00, $00, $00, $00, $00, $88, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $88, $00, $00, $00, $00, $00, $00, $00, $55, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $C6, $00, $00, $00, $A4, $00, $00, $00, $D7, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $D7, $00, $00, $00, $A4, $00, $00, $00, $C6, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $A4, $00, $00, $00, $6E, $00, $00, $00, $C0, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $C0, $00, $00, $00, $6E, $00, $00, $00, $A4, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C9, $00, $00, + $00, $FF, $00, $00, $00, $55, $00, $00, $00, $00, $00, $00, $00, $88, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $88, $00, $00, $00, $00, $00, $00, $00, $55, $00, $00, $00, $FF, $00, $00, + $00, $C9, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $C3, $00, $00, + $00, $FF, $00, $00, $00, $99, $00, $00, $00, $5C, $00, $00, $00, $B8, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $B8, $00, $00, $00, $5C, $00, $00, $00, $99, $00, $00, $00, $FF, $00, $00, + $00, $C3, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $8A, $00, $00, + $00, $EA, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, + $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $FF, $00, $00, $00, $EA, $00, $00, + $00, $89, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $26, $00, $00, + $00, $87, $00, $00, $00, $B6, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, + $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, + $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, + $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, + $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $BA, $00, $00, + $00, $BA, $00, $00, $00, $BA, $00, $00, $00, $B6, $00, $00, $00, $86, $00, $00, + $00, $24, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, + $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $FF, $FF, + $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $80, + $01, $FF, $FF, $80, $01, $FF, $FF, $80, $01, $FF, $FF, $FF, $FF, $FF, $E0, $00, + $00, $07, $E0, $00, $00, $07, $E0, $00, $00, $07, $E2, $00, $00, $47, $E0, $00, + $00, $07, $E0, $00, $00, $07, $E0, $00, $00, $07, $E2, $00, $00, $47, $E2, $00, + $00, $47, $E0, $00, $00, $07, $E0, $00, $00, $07, $E0, $00, $00, $07, $E2, $00, + $00, $47, $E0, $00, $00, $07, $E0, $00, $00, $07, $E0, $00, $00, $07, $E2, $00, + $00, $47, $E0, $00, $00, $07, $E0, $00, $00, $07, $E0, $00, $00, $07, $FF, $FF, + $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF + ); + +implementation + +end. diff --git a/src/uMainForm.pas b/src/uMainForm.pas index 834d8d7..376b358 100644 --- a/src/uMainForm.pas +++ b/src/uMainForm.pas @@ -25,10 +25,11 @@ uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, ComCtrls, Menus, Buttons, LCLType, LMessages, uAppTypes, uEdl, uMpvLib, uMpvPlayer, uProject, uMediaProbe, uTimelineCtrl, - uFlatten, uGenerate, uExport, uEncodeForm, uProgressForm, uRemuxForm, - uMismatchForm, + uFlatten, uGenerate, uExport, uEncodeForm, uAboutForm, uProgressForm, + uRemuxForm, uMismatchForm, uFfmpegJob, uSettings, uThumbs, uTransform, uPanCropForm, - uProjectInfoForm, ImgList, uTheme, uLogView, uDepsForm, uWaveform; + uProjectInfoForm, ImgList, uTheme, uLogView, uDepsForm, uWaveform, + uIconData; const { Номера системных сообщений о перерисовке рамки окна. Берём числами, а @@ -207,11 +208,13 @@ type { --- окно и меню --- } procedure BuildMenu; + procedure ApplyWindowIcon; procedure BuildJobIndicator; procedure JobTimerTick(Sender: TObject); procedure AdvanceJobBar; procedure LogButtonClick(Sender: TObject); procedure MenuToggleLog(Sender: TObject); + procedure MenuAbout(Sender: TObject); procedure ApplyLogVisible(AVisible: Boolean); procedure BuildTimeline; procedure StartPlayer; @@ -566,7 +569,7 @@ procedure TMainForm.BuildMenu; end; var - MFile, MEdit, MView, MProject: TMenuItem; + MFile, MEdit, MView, MProject, MHelp: TMenuItem; begin { Подсказки всплывают почти сразу: на кнопке со значком они не украшение, а единственный способ узнать, что она делает. Держатся @@ -575,6 +578,8 @@ begin Application.HintPause := 100; Application.HintHidePause := 15000; + ApplyWindowIcon; + BuildJobIndicator; FMenu := TMainMenu.Create(Self); @@ -635,6 +640,9 @@ begin AddItem(MProject, 'Добавить дорожку', @MenuAddTrack); AddItem(MProject, 'Удалить последнюю дорожку', @MenuRemoveTrack); + MHelp := AddTop('Справка'); + AddItem(MHelp, 'О программе...', @MenuAbout); + { Дважды, и оба раза нужны. До присваивания — чтобы обработчики отрисовки стояли к первому показу. @@ -656,6 +664,28 @@ end; Место справа в нижней полосе отводится сразу и насовсем, а надпись с полоской показываются только когда работа есть. Так строка состояния и показатель не наезжают друг на друга. } +{ Значок окна. Вшит в программу, потому что рядом с ней может ничего не + лежать. Значок самого файла программы под Windows задаётся не здесь, а + ресурсом при сборке — это отдельная история. } +procedure TMainForm.ApplyWindowIcon; +var + Stream: TMemoryStream; +begin + Stream := TMemoryStream.Create; + try + Stream.WriteBuffer(IconAppData[0], Length(IconAppData)); + Stream.Position := 0; + try + Icon.LoadFromStream(Stream); + Application.Icon.Assign(Icon); + except + { Со значком не вышло — работать это не мешает. } + end; + finally + Stream.Free; + end; +end; + procedure TMainForm.BuildJobIndicator; const JobWidth = 330; @@ -724,6 +754,11 @@ begin ApplyLogVisible(not memoLog.Visible); end; +procedure TMainForm.MenuAbout(Sender: TObject); +begin + ShowAboutForm; +end; + procedure TMainForm.MenuToggleLog(Sender: TObject); begin ApplyLogVisible(not memoLog.Visible); diff --git a/src/uTheme.pas b/src/uTheme.pas index 23af205..ac94142 100644 --- a/src/uTheme.pas +++ b/src/uTheme.pas @@ -31,7 +31,8 @@ interface uses Classes, SysUtils, Types, Controls, Graphics, Forms, StdCtrls, ExtCtrls, - ComCtrls, Grids, Menus, Dialogs, Math, LCLType, LCLIntf, LCLProc; + ComCtrls, Grids, Menus, Dialogs, Math, IntfGraphics, FPimage, + LCLType, LCLIntf, LCLProc, uIconData; const { Порядок байт в TColor — $00BBGGRR, а не привычный RGB. У серых цветов @@ -55,10 +56,13 @@ const type { Значок на кнопке. - Рисуется кодом, а не берётся из файла: программа не должна зависеть - от того, лежит ли рядом с ней картинка. Рисунки повторяют icons/*.svg - — там они и придуманы, оттуда их можно перегнать в png для чего - угодно ещё. } + Картинки вшиты в программу (uIconData): зависеть от того, лежит ли + рядом с ней файл, она не должна. Исходники — в icons_online, оттуда + же требование указать авторство, см. окно «О программе». + + Цвет значку задаётся при отрисовке: берётся прозрачность точки, а + цвет — тот, каким сейчас рисуется кнопка. Поэтому один значок годится + и для тёмной кнопки, и для оранжевой, и для недоступной. } TThemedIcon = ( tiNone, tiSnap, // прилипание: края притягиваются к общей линии @@ -296,6 +300,8 @@ type var Painter: TThemePainter; + { Перекрашенные значки: ключ «номер значка : цвет». } + IconCache: TStringList; {$IFDEF WINDOWS} { Кисть под полосу меню. Создаётся один раз: Windows держит на неё ссылку, пока меню живо, и удалять её раньше нельзя. } @@ -383,96 +389,101 @@ begin Invalidate; end; -{ Значки рисуются по клетке 24 на 24 — той же, что в icons/*.svg, — и - переносятся в заданный прямоугольник. Так рисунок один и тот же при - любом размере кнопки, и правится он в одном месте. } +{ Значок в нужном цвете. + + Картинка чёрная с прозрачностью, поэтому перекрашивается прямо по + точкам: прозрачность остаётся своя, цвет ставится наш. Результат + запоминается — цветов ровно три (обычный, на оранжевом, недоступный), и + пересчитывать их на каждую перерисовку незачем. } +function ThemedIconImage(AIcon: TThemedIcon; AColor: TColor): + TPortableNetworkGraphic; +var + Key: string; + Idx, X, Y: Integer; + Stream: TMemoryStream; + Img: TLazIntfImage; + Px: TFPColor; + R, G, B: Byte; +begin + Result := nil; + if AIcon = tiNone then + Exit; + + Key := IntToStr(Ord(AIcon)) + ':' + IntToStr(AColor); + if IconCache = nil then + begin + IconCache := TStringList.Create; + IconCache.Sorted := True; + IconCache.OwnsObjects := True; + end; + Idx := IconCache.IndexOf(Key); + if Idx >= 0 then + Exit(TPortableNetworkGraphic(IconCache.Objects[Idx])); + + Stream := TMemoryStream.Create; + try + case AIcon of + tiSnap: Stream.WriteBuffer(IconSnapData[0], Length(IconSnapData)); + tiRipple: Stream.WriteBuffer(IconRippleData[0], Length(IconRippleData)); + tiLog: Stream.WriteBuffer(IconLogData[0], Length(IconLogData)); + else + Exit; + end; + Stream.Position := 0; + + Result := TPortableNetworkGraphic.Create; + try + Result.LoadFromStream(Stream); + { Порядок байт в TColor обратный привычному. } + R := AColor and $FF; + G := (AColor shr 8) and $FF; + B := (AColor shr 16) and $FF; + + Img := Result.CreateIntfImage; + try + for Y := 0 to Img.Height - 1 do + for X := 0 to Img.Width - 1 do + begin + Px := Img.Colors[X, Y]; + { Прозрачное трогать незачем, а видимое красим целиком. } + if Px.Alpha = 0 then + Continue; + Px.Red := R * 257; + Px.Green := G * 257; + Px.Blue := B * 257; + Img.Colors[X, Y] := Px; + end; + Result.LoadFromIntfImage(Img); + finally + Img.Free; + end; + except + FreeAndNil(Result); + end; + finally + Stream.Free; + end; + + { Неудачу тоже запоминаем: иначе разбирать картинку заново пришлось бы + на каждой перерисовке. } + IconCache.AddObject(Key, Result); +end; + +{ Значок рисуется без растягивания: картинка вшита ровно того размера, под + который сделана кнопка. Если кнопка оказалась крупнее — значок остаётся + своего размера и стоит по центру, а не расплывается. } procedure TThemedButton.DrawIcon(const ARect: TRect; AColor: TColor); var - Side, X0, Y0: Integer; - - function PX(AValue: Integer): Integer; - begin - Result := X0 + Round(AValue * Side / 24); - end; - - function PY(AValue: Integer): Integer; - begin - Result := Y0 + Round(AValue * Side / 24); - end; - - procedure Line(X1, Y1, X2, Y2: Integer); - begin - Canvas.Line(PX(X1), PY(Y1), PX(X2), PY(Y2)); - end; - - procedure Box(X1, Y1, X2, Y2: Integer; AFilled: Boolean); - begin - if AFilled then - Canvas.Brush.Style := bsSolid - else - Canvas.Brush.Style := bsClear; - Canvas.Rectangle(PX(X1), PY(Y1), PX(X2), PY(Y2)); - end; - - { Треугольник остриём влево или вправо. Не Arrow: так называется - свойство самой кнопки. } - procedure Tri(ATipX, ABaseX, ACenterY, AHalf: Integer); - begin - Canvas.Brush.Style := bsSolid; - Canvas.Polygon([Types.Point(PX(ATipX), PY(ACenterY)), - Types.Point(PX(ABaseX), PY(ACenterY - AHalf)), - Types.Point(PX(ABaseX), PY(ACenterY + AHalf))]); - end; - + Img: TPortableNetworkGraphic; + X, Y: Integer; begin - if FIcon = tiNone then + Img := ThemedIconImage(FIcon, AColor); + if (Img = nil) or (Img.Width = 0) then Exit; - Side := Min(ARect.Right - ARect.Left, ARect.Bottom - ARect.Top) - 6; - if Side < 8 then - Exit; - X0 := (ARect.Left + ARect.Right - Side) div 2; - Y0 := (ARect.Top + ARect.Bottom - Side) div 2; - - Canvas.Pen.Color := AColor; - Canvas.Pen.Width := Max(1, Side div 12); - Canvas.Brush.Color := AColor; - - case FIcon of - tiSnap: - begin - { Подкова магнита: дуга сверху, две ноги вниз, полюса закрашены. - Без закрашенных полюсов подкова читается как перевёрнутая - буква U и смысла не передаёт. } - Canvas.Pen.Width := Max(2, Side div 6); - Canvas.Brush.Style := bsClear; - { Дуга по верхней половине окружности с центром в (12,13). } - Canvas.Arc(PX(5), PY(6), PX(19), PY(20), 0, 180 * 16); - Line(5, 13, 5, 19); - Line(19, 13, 19, 19); - Canvas.Pen.Width := 1; - Box(3, 18, 8, 23, True); - Box(16, 18, 21, 23, True); - end; - tiRipple: - begin - { Два куска и дыра между ними; стрелка показывает, что правый - переедет влево. } - Box(1, 7, 8, 17, True); - Box(16, 7, 23, 17, True); - Tri(10, 15, 12, 4); - end; - tiLog: - begin - Box(2, 3, 22, 21, False); - Line(6, 8, 18, 8); - Line(6, 12, 18, 12); - Line(6, 16, 13, 16); - end; - end; - - Canvas.Pen.Width := 1; - Canvas.Brush.Style := bsClear; + X := (ARect.Left + ARect.Right - Img.Width) div 2; + Y := (ARect.Top + ARect.Bottom - Img.Height) div 2; + Canvas.Draw(X, Y, Img); end; procedure TThemedButton.Paint; @@ -1286,5 +1297,6 @@ initialization finalization Painter.Free; + IconCache.Free; end. diff --git a/tools/make_icons.py b/tools/make_icons.py new file mode 100644 index 0000000..b98f26e --- /dev/null +++ b/tools/make_icons.py @@ -0,0 +1,135 @@ +#!/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), +] + +# Значок самой программы: отдельно, потому что окну нужен формат 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())