Skip to content

Commit

Permalink
feat: Implement save and restore functionality for dock proportions
Browse files Browse the repository at this point in the history
  • Loading branch information
yuto-trd committed Sep 4, 2024
1 parent d7081ef commit 8cbd5f5
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 23 deletions.
131 changes: 115 additions & 16 deletions src/Beutl/ViewModels/EditViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,18 @@ private void OnSelectedObjectDetachedFromHierarchy(object? sender, HierarchyAtta

public ReactiveProperty<ToolTabViewModel?> SelectedRightLowerBottomTool { get; } = new();

public ReDockSizeProportionViewModel LeftRightProportion { get; } = new();

public ReDockSizeProportionViewModel TopLeftRightProportion { get; } = new();

public SplittedViewSizeProportionViewModel LeftTopBottomProportion { get; } = new();

public SplittedViewSizeProportionViewModel CenterTopBottomProportion { get; } = new();

public SplittedViewSizeProportionViewModel RightTopBottomProportion { get; } = new();

public SplittedViewSizeProportionViewModel BottomLeftRightProportion { get; } = new();

public ReactiveProperty<CoreObject?> SelectedObject { get; }

public ReactivePropertySlim<bool> IsEnabled { get; } = new(true);
Expand Down Expand Up @@ -517,9 +529,24 @@ private void SaveState()
json[placement.ToString()] = jsonObject;
}

json[nameof(LeftRightProportion)] = CreateJson(LeftRightProportion);
json[nameof(TopLeftRightProportion)] = CreateJson(TopLeftRightProportion);
json[nameof(LeftTopBottomProportion)] = CreateJson(LeftTopBottomProportion);
json[nameof(CenterTopBottomProportion)] = CreateJson(CenterTopBottomProportion);
json[nameof(RightTopBottomProportion)] = CreateJson(RightTopBottomProportion);
json[nameof(BottomLeftRightProportion)] = CreateJson(BottomLeftRightProportion);

json["current-time"] = JsonValue.Create(CurrentTime.Value);

json.JsonSave(Path.Combine(viewStateDir, $"{Path.GetFileNameWithoutExtension(EdittingFile)}.config"));
return;

static JsonObject CreateJson(IJsonSerializable serializable)
{
var obj = new JsonObject();
serializable.WriteToJson(obj);
return obj;
}
}

private void RestoreState()
Expand Down Expand Up @@ -565,12 +592,8 @@ private void RestoreState()

if (jsonObject.TryGetPropertyValue("offset", out JsonNode? offsetNode)
&& offsetNode is JsonObject offsetObj
&& offsetObj.TryGetPropertyValue("x", out JsonNode? xNode)
&& offsetObj.TryGetPropertyValue("y", out JsonNode? yNode)
&& xNode is JsonValue xValue
&& yNode is JsonValue yValue
&& xValue.TryGetValue(out float x)
&& yValue.TryGetValue(out float y))
&& offsetObj.TryGetPropertyValueAsJsonValue("x", out float x)
&& offsetObj.TryGetPropertyValueAsJsonValue("y", out float y))
{
timelineOptions = timelineOptions with { Offset = new Vector2(x, y) };
}
Expand Down Expand Up @@ -610,27 +633,53 @@ ToolTabExtension extension
}
}

// Restore proportions safely
void RestoreProportion(IJsonSerializable serializable, string name)
{
if (jsonObject.TryGetPropertyValue(name, out JsonNode? proportionNode)
&& proportionNode is JsonObject proportion)
{
serializable.ReadFromJson(proportion);
}
}
RestoreProportion(LeftRightProportion, nameof(LeftRightProportion));
RestoreProportion(TopLeftRightProportion, nameof(TopLeftRightProportion));
RestoreProportion(LeftTopBottomProportion, nameof(LeftTopBottomProportion));
RestoreProportion(CenterTopBottomProportion, nameof(CenterTopBottomProportion));
RestoreProportion(RightTopBottomProportion, nameof(RightTopBottomProportion));
RestoreProportion(BottomLeftRightProportion, nameof(BottomLeftRightProportion));

if (jsonObject.TryGetPropertyValueAsJsonValue("current-time", out string? currentTimeStr)
&& TimeSpan.TryParse(currentTimeStr, out TimeSpan currentTime))
{
CurrentTime.Value = currentTime;
}

// 何もタブを開いていない場合、デフォルトのタブを開く
if (!GetAllTools().Any())
{
OpenDefaultTabs();
}
}
else
{
if (TimelineTabExtension.Instance.TryCreateContext(this, out IToolContext? tab1))
{
OpenToolTab(tab1);
}
OpenDefaultTabs();
}

if (SourceOperatorsTabExtension.Instance.TryCreateContext(this, out IToolContext? tab2))
{
OpenToolTab(tab2);
}
return;

if (LibraryTabExtension.Instance.TryCreateContext(this, out IToolContext? tab3))
void OpenDefaultTabs()
{
var tabs = new ToolTabExtension[]
{
TimelineTabExtension.Instance,
SourceOperatorsTabExtension.Instance,
LibraryTabExtension.Instance
};
foreach (var ext in tabs)
{
OpenToolTab(tab3);
if (ext.TryCreateContext(this, out IToolContext? tab))
OpenToolTab(tab);
}
}
}
Expand Down Expand Up @@ -937,3 +986,53 @@ public ValueTask<bool> OnRedo()
}
}
}

public sealed class ReDockSizeProportionViewModel : IJsonSerializable
{
public ReactivePropertySlim<double> Left { get; } = new(1 / 4d);

public ReactivePropertySlim<double> Center { get; } = new(1 / 2d);

public ReactivePropertySlim<double> Right { get; } = new(1 / 4d);

public void WriteToJson(JsonObject json)
{
json[nameof(Left)] = Left.Value;
json[nameof(Center)] = Center.Value;
json[nameof(Right)] = Right.Value;
}

public void ReadFromJson(JsonObject json)
{
if (json.TryGetPropertyValueAsJsonValue(nameof(Left), out double left))
Left.Value = left;

if (json.TryGetPropertyValueAsJsonValue(nameof(Center), out double center))
Center.Value = center;

if (json.TryGetPropertyValueAsJsonValue(nameof(Right), out double right))
Right.Value = right;
}
}

public sealed class SplittedViewSizeProportionViewModel : IJsonSerializable
{
public ReactivePropertySlim<double> First { get; } = new(1 / 2d);

public ReactivePropertySlim<double> Second { get; } = new(1 / 2d);

public void WriteToJson(JsonObject json)
{
json[nameof(First)] = First.Value;
json[nameof(Second)] = Second.Value;
}

public void ReadFromJson(JsonObject json)
{
if (json.TryGetPropertyValueAsJsonValue(nameof(First), out double first))
First.Value = first;

if (json.TryGetPropertyValueAsJsonValue(nameof(Second), out double second))
Second.Value = second;
}
}
28 changes: 21 additions & 7 deletions src/Beutl/Views/EditView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
xmlns:vm="using:Beutl.ViewModels"
d:DesignHeight="720"
d:DesignWidth="1280"
x:CompileBindings="True"
x:DataType="vm:EditViewModel"
Focusable="True"
IsEnabled="{CompiledBinding IsEnabled.Value}"
IsEnabled="{Binding IsEnabled.Value}"
mc:Ignorable="d">
<UserControl.Resources>
<DataTemplate x:Key="LeftSideBarButtonDataTemplate" x:DataType="vm:ToolTabViewModel">
Expand Down Expand Up @@ -98,38 +99,51 @@
UpperBottomToolsSource="{Binding LeftUpperBottomTools}"
UpperTopToolsSource="{Binding LeftUpperTopTools}" />

<dock:ReDock Name="LeftRightArea" Grid.Column="1">
<dock:ReDock Name="LeftRightArea"
Grid.Column="1"
LeftWidthProportion="{Binding LeftRightProportion.Left.Value, Mode=TwoWay}"
RightWidthProportion="{Binding LeftRightProportion.Right.Value, Mode=TwoWay}"
WidthProportion="{Binding LeftRightProportion.Center.Value, Mode=TwoWay}">
<dock:ReDock.LeftContent>
<dock:VerticallySplittedView Name="LeftTopBottomArea"
BottomContent="{Binding SelectedLeftLowerTopTool.Value}"
BottomContentTemplate="{StaticResource ToolTabContentDataTemplate}"
BottomHeightProportion="{Binding LeftTopBottomProportion.Second.Value, Mode=TwoWay}"
TopContent="{Binding SelectedLeftUpperBottomTool.Value}"
TopContentTemplate="{StaticResource ToolTabContentDataTemplate}" />
TopContentTemplate="{StaticResource ToolTabContentDataTemplate}"
TopHeightProportion="{Binding LeftTopBottomProportion.First.Value, Mode=TwoWay}" />
</dock:ReDock.LeftContent>
<dock:VerticallySplittedView>
<dock:VerticallySplittedView BottomHeightProportion="{Binding CenterTopBottomProportion.Second.Value, Mode=TwoWay}" TopHeightProportion="{Binding CenterTopBottomProportion.First.Value, Mode=TwoWay}">
<dock:VerticallySplittedView.TopContent>
<dock:ReDock Name="TopLeftRightArea"
LeftContent="{Binding SelectedLeftUpperTopTool.Value}"
LeftContentTemplate="{StaticResource ToolTabContentDataTemplate}"
LeftWidthProportion="{Binding TopLeftRightProportion.Left.Value, Mode=TwoWay}"
RightContent="{Binding SelectedRightUpperTopTool.Value}"
RightContentTemplate="{StaticResource ToolTabContentDataTemplate}">
RightContentTemplate="{StaticResource ToolTabContentDataTemplate}"
RightWidthProportion="{Binding TopLeftRightProportion.Right.Value, Mode=TwoWay}"
WidthProportion="{Binding TopLeftRightProportion.Center.Value, Mode=TwoWay}">
<local:PlayerView x:Name="Player" DataContext="{Binding Player}" />
</dock:ReDock>
</dock:VerticallySplittedView.TopContent>
<dock:VerticallySplittedView.BottomContent>
<dock:HorizontallySplittedView Name="BottomLeftRightArea"
LeftContent="{Binding SelectedLeftLowerBottomTool.Value}"
LeftContentTemplate="{StaticResource ToolTabContentDataTemplate}"
LeftWidthProportion="{Binding BottomLeftRightProportion.First.Value, Mode=TwoWay}"
RightContent="{Binding SelectedRightLowerBottomTool.Value}"
RightContentTemplate="{StaticResource ToolTabContentDataTemplate}" />
RightContentTemplate="{StaticResource ToolTabContentDataTemplate}"
RightWidthProportion="{Binding BottomLeftRightProportion.Second.Value, Mode=TwoWay}" />
</dock:VerticallySplittedView.BottomContent>
</dock:VerticallySplittedView>
<dock:ReDock.RightContent>
<dock:VerticallySplittedView Name="RightTopBottomArea"
BottomContent="{Binding SelectedRightLowerTopTool.Value}"
BottomContentTemplate="{StaticResource ToolTabContentDataTemplate}"
BottomHeightProportion="{Binding RightTopBottomProportion.Second.Value, Mode=TwoWay}"
TopContent="{Binding SelectedRightUpperBottomTool.Value}"
TopContentTemplate="{StaticResource ToolTabContentDataTemplate}" />
TopContentTemplate="{StaticResource ToolTabContentDataTemplate}"
TopHeightProportion="{Binding RightTopBottomProportion.First.Value, Mode=TwoWay}" />
</dock:ReDock.RightContent>
</dock:ReDock>
<dock:SideBar Name="RightSideBar"
Expand Down

0 comments on commit 8cbd5f5

Please sign in to comment.