Выделение по времени, рез по краям промежутка, курсор идёт за резом
Режимов выделения стало два, переключаются клавишей D и кнопкой внизу, режим показан её значком. Рамкой по клипам — как было. По времени — протяжка отмечает промежуток по всем дорожкам сразу, он остаётся виден пунктиром, и S режет все дорожки по обоим его краям. Выделенной после этого остаётся ровно середина: следующим действием её обычно удаляют, а выделение на старых клипах убрало бы не то. Курсор теперь идёт за резом: после S встаёт на место реза (в режиме по времени — на начало промежутка), после удаления куска — на место стыка, после схлопывания дыры — туда же. Раньше в это место приходилось попадать мышью заново. Рез кладётся на кадровую сетку: между кадрами времени нет, и рез на доле кадра оставлял бы в монтаже время, которого не бывает. Выделение рамкой требует настоящего перекрытия, а не касания краями: сосед, кончающийся ровно на краю рамки, попадал в выделение из-за разницы в последнем знаке дробей. Кнопка журнала и строка состояния сдвинуты вправо: переключатель выделения встал в один ряд с прилипанием и схлопыванием. Значки — icons8, набор ios-glyphs, авторство дописано в attribution.txt. Набора «ios26» на их раздаче нет (404), взят ближайший по виду к нынешним. Проверки: рез по курсору и по краям промежутка, кадровая сетка, выделение середины, курсор после удаления и после схлопывания.
This commit is contained in:
parent
37787ce96c
commit
6617e29514
11 changed files with 538 additions and 31 deletions
|
|
@ -631,6 +631,128 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
{ Рез и курсор: где режет S и куда после этого встаёт курсор.
|
||||
|
||||
Раньше курсор оставался там, где был, а рез мог попасть на долю кадра.
|
||||
Теперь рез кладётся на кадровую сетку, а курсор встаёт ровно на место
|
||||
реза — с ним и работают дальше. }
|
||||
procedure CheckSplitAndPlayhead;
|
||||
var
|
||||
Proj: TProject;
|
||||
Info: TMediaInfo;
|
||||
Media: TMediaItem;
|
||||
Timeline: TTimelineControl;
|
||||
Step: Double;
|
||||
I, N: Integer;
|
||||
begin
|
||||
WriteLn;
|
||||
WriteLn('Рез, промежуток и курсор');
|
||||
WriteLn;
|
||||
|
||||
Info := TestInfo;
|
||||
Info.FpsNum := 60000;
|
||||
Info.FpsDen := 1001;
|
||||
Step := Info.FpsDen / Info.FpsNum;
|
||||
|
||||
Proj := TProject.Create;
|
||||
Timeline := TTimelineControl.Create(nil);
|
||||
try
|
||||
Proj.Clear;
|
||||
Proj.AddTrack('V1');
|
||||
Proj.AddTrack('A1');
|
||||
Media := Proj.AddMedia('/несуществующий/видео.mp4', Info);
|
||||
Proj.Master := Info;
|
||||
{ По два клипа на каждой дорожке, встык: 0..10 и 10..20. }
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 0, 10, 0);
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 20, 10, 10);
|
||||
Proj.AddClip(Proj.Tracks[1], Media, 0, 10, 0);
|
||||
Proj.AddClip(Proj.Tracks[1], Media, 20, 10, 10);
|
||||
|
||||
Timeline.Project := Proj;
|
||||
Timeline.PixelsPerSecond := 100;
|
||||
|
||||
{ Рез по курсору: место кладётся на кадр, курсор встаёт на него. }
|
||||
Timeline.Playhead := 3.3177;
|
||||
CheckTrue('разрезаны обе дорожки', Timeline.SplitAtPlayhead(False) = 2);
|
||||
CheckTrue('курсор встал на место реза',
|
||||
Abs(Timeline.Playhead - Round(3.3177 / Step) * Step) < 0.0001);
|
||||
CheckTrue('курсор на кадровой сетке',
|
||||
Abs(Timeline.Playhead / Step - Round(Timeline.Playhead / Step)) < 0.001);
|
||||
N := 0;
|
||||
for I := 0 to Proj.Tracks[0].Count - 1 do
|
||||
if Abs(Proj.Tracks[0][I].TlStart - Timeline.Playhead) < 0.0001 then
|
||||
Inc(N);
|
||||
CheckTrue('рез пришёлся ровно туда, где курсор', N = 1);
|
||||
|
||||
{ Промежуток по времени: рез по обоим краям, курсор — на начало. }
|
||||
Timeline.SelectionMode := smRange;
|
||||
Timeline.SetSelectionRange(12.13, 16.77);
|
||||
CheckTrue('промежуток отмечен', Timeline.HasSelectionRange);
|
||||
CheckTrue('разрезано по два клипа на дорожке',
|
||||
Timeline.SplitAtPlayhead(False) = 4);
|
||||
CheckTrue('курсор — на начале промежутка',
|
||||
Abs(Timeline.Playhead - Timeline.RangeFrom) < 0.0001);
|
||||
|
||||
N := 0;
|
||||
for I := 0 to Proj.Tracks[1].Count - 1 do
|
||||
if (Abs(Proj.Tracks[1][I].TlStart - Timeline.RangeFrom) < 0.0001) or
|
||||
(Abs(Proj.Tracks[1][I].TlStart - Timeline.RangeTo) < 0.0001) then
|
||||
Inc(N);
|
||||
CheckTrue('на звуковой дорожке резы по обоим краям', N = 2);
|
||||
|
||||
{ После реза выделена середина — то, что между краями: следующим
|
||||
действием её обычно удаляют. }
|
||||
N := 0;
|
||||
for I := 0 to Proj.Tracks[0].Count - 1 do
|
||||
if Proj.Tracks[0][I].Selected then
|
||||
begin
|
||||
Inc(N);
|
||||
CheckTrue('выделенное лежит внутри промежутка',
|
||||
(Proj.Tracks[0][I].TlStart >= Timeline.RangeFrom - 0.0001) and
|
||||
(Proj.Tracks[0][I].TlEnd <= Timeline.RangeTo + 0.0001));
|
||||
end;
|
||||
CheckTrue('на дорожке картинки выделена одна середина', N = 1);
|
||||
|
||||
{ Смена режима снимает промежуток: резать по невидимой метке нельзя. }
|
||||
Timeline.SelectionMode := smClips;
|
||||
CheckTrue('смена режима сняла промежуток',
|
||||
not Timeline.HasSelectionRange);
|
||||
|
||||
{ Удаление со схлопыванием: курсор встаёт на место стыка. }
|
||||
Proj.Clear;
|
||||
Proj.AddTrack('V1');
|
||||
Media := Proj.AddMedia('/несуществующий/видео.mp4', Info);
|
||||
Proj.Master := Info;
|
||||
Proj.RippleEnabled := True;
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 0, 5, 0);
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 10, 5, 5);
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 20, 5, 10);
|
||||
Timeline.Playhead := 0;
|
||||
Proj.Tracks[0][1].Selected := True;
|
||||
Timeline.DeleteSelected;
|
||||
CheckTrue('после удаления клипов стало два', Proj.Tracks[0].Count = 2);
|
||||
CheckTrue('курсор — на месте вырезанного куска',
|
||||
Abs(Timeline.Playhead - 5) < 0.0001);
|
||||
CheckTrue('хвост придвинут к стыку',
|
||||
Abs(Proj.Tracks[0][1].TlStart - 5) < 0.0001);
|
||||
|
||||
{ Схлопывание дыры с клавиатуры: курсор тоже на стык. }
|
||||
Proj.Clear;
|
||||
Proj.AddTrack('V1');
|
||||
Media := Proj.AddMedia('/несуществующий/видео.mp4', Info);
|
||||
Proj.Master := Info;
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 0, 5, 0);
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 20, 5, 12);
|
||||
Timeline.ActiveTrack := 0;
|
||||
Timeline.Playhead := 8;
|
||||
CheckTrue('дыра схлопнута', Timeline.RippleCloseGap);
|
||||
CheckTrue('курсор — на стыке', Abs(Timeline.Playhead - 5) < 0.0001);
|
||||
finally
|
||||
Timeline.Free;
|
||||
Proj.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
WriteLn('Свойства из файлов форм');
|
||||
WriteLn;
|
||||
|
|
@ -663,6 +785,7 @@ begin
|
|||
CheckClipCopy;
|
||||
CheckRubberBand;
|
||||
CheckFrameGridRepair;
|
||||
CheckSplitAndPlayhead;
|
||||
CheckSplitAllTracks;
|
||||
CheckGapTolerance;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue