Skip to content

Commit

Permalink
Merge pull request #719 from b-editor/improve-element-split
Browse files Browse the repository at this point in the history
要素の分割を改善
  • Loading branch information
yuto-trd authored Sep 12, 2023
2 parents 8c297e9 + 991de5b commit 937b1cf
Show file tree
Hide file tree
Showing 12 changed files with 112 additions and 9 deletions.
9 changes: 9 additions & 0 deletions src/Beutl.Language/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Beutl.Language/Strings.ja.resx
Original file line number Diff line number Diff line change
Expand Up @@ -949,4 +949,7 @@ b-editorがダウンロードURLを管理します。</value>
<data name="ChangeToOriginalLength" xml:space="preserve">
<value>オリジナルの長さに変更</value>
</data>
<data name="SplitByCurrentFrame" xml:space="preserve">
<value>現在のフレームで分割</value>
</data>
</root>
3 changes: 3 additions & 0 deletions src/Beutl.Language/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -949,4 +949,7 @@ and b-editor maintains the download URL.</value>
<data name="ChangeToOriginalLength" xml:space="preserve">
<value>Change to original length</value>
</data>
<data name="SplitByCurrentFrame" xml:space="preserve">
<value>Split by current frame</value>
</data>
</root>
12 changes: 12 additions & 0 deletions src/Beutl.Operators/Source/SourceSoundOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,16 @@ public override bool TryGetOriginalLength(out TimeSpan timeSpan)
return false;
}
}

public override IRecordableCommand? OnSplit(bool backward, TimeSpan startDelta, TimeSpan lengthDelta)
{
if (backward)
{
return new ChangeSetterValueCommand<TimeSpan>(OffsetPosition, OffsetPosition.Value, OffsetPosition.Value + startDelta);
}
else
{
return base.OnSplit(backward, startDelta, lengthDelta);
}
}
}
12 changes: 12 additions & 0 deletions src/Beutl.Operators/Source/SourceVideoOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,16 @@ public override bool TryGetOriginalLength(out TimeSpan timeSpan)
return false;
}
}

public override IRecordableCommand? OnSplit(bool backward, TimeSpan startDelta, TimeSpan lengthDelta)
{
if (backward)
{
return new ChangeSetterValueCommand<TimeSpan>(OffsetPosition, OffsetPosition.Value, OffsetPosition.Value + startDelta);
}
else
{
return base.OnSplit(backward, startDelta, lengthDelta);
}
}
}
29 changes: 29 additions & 0 deletions src/Beutl.ProjectSystem/ChangeSetterValueCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Beutl.Styling;

namespace Beutl;

public sealed class ChangeSetterValueCommand<T> : IRecordableCommand
{
private readonly Setter<T> _setter;
private readonly T _oldValue;
private readonly T _newValue;

public ChangeSetterValueCommand(Setter<T> setter, T oldValue, T newValue)
{
_setter = setter;
_oldValue = oldValue;
_newValue = newValue;
}

public void Do()
{
_setter.Value = _newValue;
}

public void Redo() => Do();

public void Undo()
{
_setter.Value = _oldValue;
}
}
8 changes: 8 additions & 0 deletions src/Beutl.ProjectSystem/Operation/SourceOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ public SourceOperation()
[NotAutoSerialized]
public ICoreList<SourceOperator> Children => _children;

public IRecordableCommand OnSplit(bool backward, TimeSpan startDelta,TimeSpan lengthDelta)
{
return _children.Select(v => v.OnSplit(backward, startDelta, lengthDelta))
.Where(v => v != null)
.ToArray()!
.ToCommand();
}

public override void ReadFromJson(JsonObject json)
{
base.ReadFromJson(json);
Expand Down
5 changes: 5 additions & 0 deletions src/Beutl.ProjectSystem/Operation/SourceOperator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ public virtual bool TryGetOriginalLength(out TimeSpan timeSpan)
return false;
}

public virtual IRecordableCommand? OnSplit(bool backward, TimeSpan startDelta, TimeSpan lengthDelta)
{
return null;
}

protected void RaiseInvalidated(RenderInvalidatedEventArgs args)
{
Invalidated?.Invoke(this, args);
Expand Down
1 change: 1 addition & 0 deletions src/Beutl/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<KeyGesture x:Key="CutKeyGesture">Ctrl+X</KeyGesture>
<KeyGesture x:Key="CopyKeyGesture">Ctrl+C</KeyGesture>
<KeyGesture x:Key="PasteKeyGesture">Ctrl+V</KeyGesture>
<KeyGesture x:Key="SplitKeyGesture">Ctrl+K</KeyGesture>
<KeyGesture x:Key="PlayPauseKeyGesture">Space</KeyGesture>
<KeyGesture x:Key="NextKeyGesture">Right</KeyGesture>
<KeyGesture x:Key="PreviousKeyGesture">Left</KeyGesture>
Expand Down
26 changes: 22 additions & 4 deletions src/Beutl/ViewModels/ElementViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@ public ElementViewModel(Element element, TimelineViewModel timeline)
.AddTo(_disposables);

// コマンドを構成
Split.Where(func => func != null)
.Subscribe(func => OnSplit(func!()))
Split.Where(_ => GetClickedTime != null)
.Subscribe(_ => OnSplit(GetClickedTime!()))
.AddTo(_disposables);

SplitByCurrentFrame
.Subscribe(_ => OnSplit(Scene.CurrentFrame))
.AddTo(_disposables);

Cut.Subscribe(OnCut)
Expand Down Expand Up @@ -130,6 +134,8 @@ public ElementViewModel(Element element, TimelineViewModel timeline)

public Func<(Thickness Margin, Thickness BorderMargin, double Width), CancellationToken, Task> AnimationRequested { get; set; } = (_, _) => Task.CompletedTask;

public Func<TimeSpan>? GetClickedTime { get; set; }

public TimelineViewModel Timeline { get; private set; }

public Element Model { get; private set; }
Expand Down Expand Up @@ -160,7 +166,9 @@ public ElementViewModel(Element element, TimelineViewModel timeline)

public ReadOnlyReactivePropertySlim<Avalonia.Media.Color> TextColor { get; }

public ReactiveCommand<Func<TimeSpan>?> Split { get; } = new();
public ReactiveCommand Split { get; } = new();

public ReactiveCommand SplitByCurrentFrame { get; } = new();

public AsyncReactiveCommand Cut { get; } = new();

Expand Down Expand Up @@ -189,6 +197,7 @@ public void Dispose()
Model = null!;
Scope = null!;
AnimationRequested = (_, _) => Task.CompletedTask;
GetClickedTime = null;
GC.SuppressFinalize(this);
}

Expand Down Expand Up @@ -339,10 +348,14 @@ private async Task OnCut()
private void OnSplit(TimeSpan timeSpan)
{
int rate = Scene.FindHierarchicalParent<Project>() is { } proj ? proj.GetFrameRate() : 30;
TimeSpan minLength = TimeSpan.FromSeconds(1d / rate);
TimeSpan absTime = timeSpan.RoundToRate(rate);
TimeSpan forwardLength = absTime - Model.Start;
TimeSpan backwardLength = Model.Length - forwardLength;

if (forwardLength < minLength || backwardLength < minLength)
return;

CoreObjectReborn.Reborn(Model, out Element backwardLayer);

IRecordableCommand command1 = Scene.MoveChild(Model.ZIndex, Model.Start, forwardLength, Model);
Expand All @@ -351,8 +364,12 @@ private void OnSplit(TimeSpan timeSpan)

backwardLayer.Save(RandomFileNameGenerator.Generate(Path.GetDirectoryName(Scene.FileName)!, Constants.ElementFileExtension));
IRecordableCommand command2 = Scene.AddChild(backwardLayer);
IRecordableCommand command3 = backwardLayer.Operation.OnSplit(true, forwardLength, -forwardLength);
IRecordableCommand command4 = Model.Operation.OnSplit(false, TimeSpan.Zero, -backwardLength);

command1.Append(command2)
.Append(command3)
.Append(command4)
.DoAndRecord(CommandRecorder.Default);
}

Expand Down Expand Up @@ -391,7 +408,8 @@ private List<KeyBinding> CreateKeyBinding()
var list = new List<KeyBinding>
{
new KeyBinding { Gesture = new(Key.Delete), Command = Exclude },
new KeyBinding { Gesture = new(Key.Delete, modifier), Command = Delete }
new KeyBinding { Gesture = new(Key.Delete, modifier), Command = Delete },
new KeyBinding { Gesture = new(Key.K, modifier), Command = SplitByCurrentFrame }
};

if (config != null)
Expand Down
8 changes: 5 additions & 3 deletions src/Beutl/Views/ElementView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@
</Border.Resources>
<Border.ContextFlyout>
<ui:FAMenuFlyout>
<ui:MenuFlyoutItem Command="{Binding Split}"
CommandParameter="{Binding #root.GetClickedTime, Mode=OneTime}"
Text="{x:Static lang:Strings.Split}">
<ui:MenuFlyoutItem Command="{Binding Split}" Text="{x:Static lang:Strings.Split}">
<ui:MenuFlyoutItem.IconSource>
<icons:SymbolIconSource Symbol="SplitVertical" />
</ui:MenuFlyoutItem.IconSource>
</ui:MenuFlyoutItem>
<ui:MenuFlyoutItem x:Name="splitByCurrent"
Command="{Binding SplitByCurrentFrame}"
InputGesture="{DynamicResource SplitKeyGesture}"
Text="{x:Static lang:Strings.SplitByCurrentFrame}" />
<ui:MenuFlyoutItem Command="{Binding Cut}"
InputGesture="{DynamicResource CutKeyGesture}"
Text="{x:Static lang:Strings.Cut}">
Expand Down
5 changes: 3 additions & 2 deletions src/Beutl/Views/ElementView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ public ElementView()
this.SubscribeDataContextChange<ElementViewModel>(OnDataContextAttached, OnDataContextDetached);
}

public Func<TimeSpan> GetClickedTime => () => _pointerPosition;

private ElementViewModel ViewModel => (ElementViewModel)DataContext!;

protected override void OnKeyDown(KeyEventArgs e)
Expand Down Expand Up @@ -82,12 +80,14 @@ private void OnContextFlyoutOpening(object? sender, EventArgs e)
if (DataContext is ElementViewModel viewModel)
{
change2OriginalLength.IsEnabled = viewModel.HasOriginalLength();
splitByCurrent.IsEnabled = viewModel.Model.Range.Contains(viewModel.Scene.CurrentFrame);
}
}

private void OnDataContextDetached(ElementViewModel obj)
{
obj.AnimationRequested = (_, _) => Task.CompletedTask;
obj.GetClickedTime = null;
_disposables.Clear();
}

Expand Down Expand Up @@ -155,6 +155,7 @@ await Dispatcher.UIThread.InvokeAsync(async () =>
await Task.WhenAll(task1, task2);
});
};
obj.GetClickedTime = () => _pointerPosition;

obj.Model.GetObservable(Element.IsEnabledProperty)
.ObserveOnUIDispatcher()
Expand Down

0 comments on commit 937b1cf

Please sign in to comment.