mirror of
https://github.com/sourcegit-scm/sourcegit.git
synced 2024-12-24 20:57:19 -08:00
feature: add two view mode for image diff - side-by-side and blend
This commit is contained in:
parent
d3d6889e25
commit
8e88df92b3
10 changed files with 490 additions and 231 deletions
19
src/Converters/DoubleConverters.cs
Normal file
19
src/Converters/DoubleConverters.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
using Avalonia.Data.Converters;
|
||||||
|
|
||||||
|
namespace SourceGit.Converters
|
||||||
|
{
|
||||||
|
public static class DoubleConverters
|
||||||
|
{
|
||||||
|
public static readonly FuncValueConverter<double, double> Increase =
|
||||||
|
new FuncValueConverter<double, double>(v => v + 1.0);
|
||||||
|
|
||||||
|
public static readonly FuncValueConverter<double, double> Decrease =
|
||||||
|
new FuncValueConverter<double, double>(v => v - 1.0);
|
||||||
|
|
||||||
|
public static readonly FuncValueConverter<double, string> ToPercentage =
|
||||||
|
new FuncValueConverter<double, string>(v => (v * 100).ToString("F3") + "%");
|
||||||
|
|
||||||
|
public static readonly FuncValueConverter<double, string> OneMinusToPercentage =
|
||||||
|
new FuncValueConverter<double, string>(v => ((1.0 - v) * 100).ToString("F3") + "%");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +0,0 @@
|
||||||
using Avalonia.Data.Converters;
|
|
||||||
|
|
||||||
namespace SourceGit.Converters
|
|
||||||
{
|
|
||||||
public static class FontSizeModifyConverters
|
|
||||||
{
|
|
||||||
public static readonly FuncValueConverter<double, double> Increase =
|
|
||||||
new FuncValueConverter<double, double>(v => v + 1.0);
|
|
||||||
|
|
||||||
public static readonly FuncValueConverter<double, double> Decrease =
|
|
||||||
new FuncValueConverter<double, double>(v => v - 1.0);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -25,7 +25,7 @@
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<SelectableTextBlock Text="{Binding AuthorTimeStr}"
|
<SelectableTextBlock Text="{Binding AuthorTimeStr}"
|
||||||
Margin="2,0,0,0"
|
Margin="2,0,0,0"
|
||||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Decrease}}"
|
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
|
||||||
Foreground="{DynamicResource Brush.FG2}"/>
|
Foreground="{DynamicResource Brush.FG2}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<SelectableTextBlock Text="{Binding CommitterTimeStr}"
|
<SelectableTextBlock Text="{Binding CommitterTimeStr}"
|
||||||
Margin="2,0,0,0"
|
Margin="2,0,0,0"
|
||||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Decrease}}"
|
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
|
||||||
Foreground="{DynamicResource Brush.FG2}"/>
|
Foreground="{DynamicResource Brush.FG2}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -184,60 +184,7 @@
|
||||||
|
|
||||||
<!-- Image Diff -->
|
<!-- Image Diff -->
|
||||||
<DataTemplate DataType="m:ImageDiff">
|
<DataTemplate DataType="m:ImageDiff">
|
||||||
<Grid RowDefinitions="Auto,*" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="8,16,8,0">
|
<v:ImageDiffView/>
|
||||||
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto" HorizontalAlignment="Center">
|
|
||||||
<Border Grid.Column="0" Height="16" Background="{DynamicResource Brush.Badge}" CornerRadius="8" VerticalAlignment="Center">
|
|
||||||
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.Old}" Margin="8,0" FontSize="10"/>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<TextBlock Grid.Column="1" Classes="monospace" Text="{Binding OldImageSize}" Margin="8,0,0,0"/>
|
|
||||||
<TextBlock Grid.Column="2" Classes="monospace" Text="{Binding OldFileSize}" Foreground="{DynamicResource Brush.FG2}" Margin="16,0,0,0" HorizontalAlignment="Right"/>
|
|
||||||
<TextBlock Grid.Column="3" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
|
||||||
|
|
||||||
<Border Grid.Column="4" Height="16" Background="Green" CornerRadius="8" VerticalAlignment="Center" Margin="32,0,0,0">
|
|
||||||
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.New}" Margin="8,0" FontSize="10"/>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<TextBlock Grid.Column="5" Classes="monospace" Text="{Binding NewImageSize}" Margin="8,0,0,0"/>
|
|
||||||
<TextBlock Grid.Column="6" Classes="monospace" Text="{Binding NewFileSize}" Foreground="{DynamicResource Brush.FG2}" Margin="16,0,0,0" HorizontalAlignment="Right"/>
|
|
||||||
<TextBlock Grid.Column="7" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid Grid.Row="1" RowDefinitions="*,Auto,Auto" Margin="0,16,0,0" HorizontalAlignment="Center">
|
|
||||||
<Border Grid.Row="0" Background="{DynamicResource Brush.Window}" Effect="drop-shadow(0 0 8 #A0000000)">
|
|
||||||
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
|
|
||||||
<v:ImageDiffView Alpha="{Binding #ImageDiffSlider.Value}"
|
|
||||||
OldImage="{Binding Old}"
|
|
||||||
NewImage="{Binding New}"
|
|
||||||
RenderOptions.BitmapInterpolationMode="HighQuality"/>
|
|
||||||
</Border>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<Grid Grid.Row="1" ColumnDefinitions="*,*" Margin="0,8,0,0">
|
|
||||||
<TextBlock Grid.Column="0" Classes="monospace" Text="{DynamicResource Text.Diff.Binary.Old}" Foreground="{DynamicResource Brush.FG2}" FontSize="10"/>
|
|
||||||
<TextBlock Grid.Column="1" Classes="monospace" Text="{DynamicResource Text.Diff.Binary.New}" Foreground="{DynamicResource Brush.FG2}" HorizontalAlignment="Right" FontSize="10"/>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Slider Grid.Row="2"
|
|
||||||
x:Name="ImageDiffSlider"
|
|
||||||
Minimum="0" Maximum="1"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
TickPlacement="None"
|
|
||||||
Margin="8,4,8,0"
|
|
||||||
MinHeight="0"
|
|
||||||
Foreground="{DynamicResource Brush.Border1}"
|
|
||||||
Value="0.5">
|
|
||||||
<Slider.Resources>
|
|
||||||
<Thickness x:Key="SliderTopHeaderMargin">0,0,0,4</Thickness>
|
|
||||||
<GridLength x:Key="SliderPreContentMargin">0</GridLength>
|
|
||||||
<GridLength x:Key="SliderPostContentMargin">0</GridLength>
|
|
||||||
<CornerRadius x:Key="SliderThumbCornerRadius">8</CornerRadius>
|
|
||||||
<x:Double x:Key="SliderHorizontalThumbWidth">16</x:Double>
|
|
||||||
<x:Double x:Key="SliderHorizontalThumbHeight">16</x:Double>
|
|
||||||
</Slider.Resources>
|
|
||||||
</Slider>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<!-- Text Diff -->
|
<!-- Text Diff -->
|
||||||
|
|
|
@ -1,164 +1,7 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Media;
|
|
||||||
using Avalonia.Media.Imaging;
|
|
||||||
using Avalonia.Styling;
|
|
||||||
|
|
||||||
namespace SourceGit.Views
|
namespace SourceGit.Views
|
||||||
{
|
{
|
||||||
public class ImageDiffView : Control
|
|
||||||
{
|
|
||||||
public static readonly StyledProperty<double> AlphaProperty =
|
|
||||||
AvaloniaProperty.Register<ImageDiffView, double>(nameof(Alpha), 0.5);
|
|
||||||
|
|
||||||
public double Alpha
|
|
||||||
{
|
|
||||||
get => GetValue(AlphaProperty);
|
|
||||||
set => SetValue(AlphaProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly StyledProperty<Bitmap> OldImageProperty =
|
|
||||||
AvaloniaProperty.Register<ImageDiffView, Bitmap>(nameof(OldImage), null);
|
|
||||||
|
|
||||||
public Bitmap OldImage
|
|
||||||
{
|
|
||||||
get => GetValue(OldImageProperty);
|
|
||||||
set => SetValue(OldImageProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly StyledProperty<Bitmap> NewImageProperty =
|
|
||||||
AvaloniaProperty.Register<ImageDiffView, Bitmap>(nameof(NewImage), null);
|
|
||||||
|
|
||||||
public Bitmap NewImage
|
|
||||||
{
|
|
||||||
get => GetValue(NewImageProperty);
|
|
||||||
set => SetValue(NewImageProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ImageDiffView()
|
|
||||||
{
|
|
||||||
AffectsMeasure<ImageDiffView>(OldImageProperty, NewImageProperty);
|
|
||||||
AffectsRender<ImageDiffView>(AlphaProperty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Render(DrawingContext context)
|
|
||||||
{
|
|
||||||
if (_bgBrush == null)
|
|
||||||
{
|
|
||||||
var maskBrush = new SolidColorBrush(ActualThemeVariant == ThemeVariant.Dark ? 0xFF404040 : 0xFFBBBBBB);
|
|
||||||
var bg = new DrawingGroup()
|
|
||||||
{
|
|
||||||
Children =
|
|
||||||
{
|
|
||||||
new GeometryDrawing() { Brush = maskBrush, Geometry = new RectangleGeometry(new Rect(0, 0, 12, 12)) },
|
|
||||||
new GeometryDrawing() { Brush = maskBrush, Geometry = new RectangleGeometry(new Rect(12, 12, 12, 12)) },
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_bgBrush = new DrawingBrush(bg)
|
|
||||||
{
|
|
||||||
AlignmentX = AlignmentX.Left,
|
|
||||||
AlignmentY = AlignmentY.Top,
|
|
||||||
DestinationRect = new RelativeRect(new Size(24, 24), RelativeUnit.Absolute),
|
|
||||||
Stretch = Stretch.None,
|
|
||||||
TileMode = TileMode.Tile,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
context.FillRectangle(_bgBrush, new Rect(Bounds.Size));
|
|
||||||
|
|
||||||
var alpha = Alpha;
|
|
||||||
var w = Bounds.Width - 16;
|
|
||||||
var h = Bounds.Height - 16;
|
|
||||||
var x = w * alpha;
|
|
||||||
var left = OldImage;
|
|
||||||
if (left != null && alpha > 0)
|
|
||||||
{
|
|
||||||
var src = new Rect(0, 0, left.Size.Width * alpha, left.Size.Height);
|
|
||||||
var dst = new Rect(8, 8, x, h);
|
|
||||||
context.DrawImage(left, src, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
var right = NewImage;
|
|
||||||
if (right != null && alpha < 1)
|
|
||||||
{
|
|
||||||
var src = new Rect(right.Size.Width * alpha, 0, right.Size.Width * (1 - alpha), right.Size.Height);
|
|
||||||
var dst = new Rect(x + 8, 8, w - x, h);
|
|
||||||
context.DrawImage(right, src, dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.DrawLine(new Pen(Brushes.DarkGreen, 2), new Point(x + 8, 0), new Point(x + 8, Bounds.Height));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
|
||||||
{
|
|
||||||
base.OnPropertyChanged(change);
|
|
||||||
|
|
||||||
if (change.Property.Name == "ActualThemeVariant")
|
|
||||||
{
|
|
||||||
_bgBrush = null;
|
|
||||||
InvalidateVisual();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Size MeasureOverride(Size availableSize)
|
|
||||||
{
|
|
||||||
var left = OldImage;
|
|
||||||
var right = NewImage;
|
|
||||||
|
|
||||||
if (left != null)
|
|
||||||
{
|
|
||||||
var lSize = GetDesiredSize(left.Size, availableSize);
|
|
||||||
if (right != null)
|
|
||||||
{
|
|
||||||
var rSize = GetDesiredSize(right.Size, availableSize);
|
|
||||||
if (rSize.Width > lSize.Width)
|
|
||||||
return rSize;
|
|
||||||
return lSize;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return lSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (right != null)
|
|
||||||
{
|
|
||||||
return GetDesiredSize(right.Size, availableSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return availableSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Size GetDesiredSize(Size img, Size available)
|
|
||||||
{
|
|
||||||
var w = available.Width - 16;
|
|
||||||
var h = available.Height - 16;
|
|
||||||
|
|
||||||
if (img.Width <= w)
|
|
||||||
{
|
|
||||||
if (img.Height <= h)
|
|
||||||
{
|
|
||||||
return new Size(img.Width + 16, img.Height + 16);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new Size(h * img.Width / img.Height + 16, available.Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var s = Math.Max(img.Width / w, img.Height / h);
|
|
||||||
return new Size(img.Width / s + 16, img.Height / s + 16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DrawingBrush _bgBrush = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public partial class DiffView : UserControl
|
public partial class DiffView : UserControl
|
||||||
{
|
{
|
||||||
public DiffView()
|
public DiffView()
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
<TextBlock Text="{DynamicResource Text.Hotkeys.Global}"
|
<TextBlock Text="{DynamicResource Text.Hotkeys.Global}"
|
||||||
Foreground="{DynamicResource Brush.FG2}"
|
Foreground="{DynamicResource Brush.FG2}"
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}"
|
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Increase}}"
|
||||||
Margin="0,0,0,8"/>
|
Margin="0,0,0,8"/>
|
||||||
|
|
||||||
<Grid RowDefinitions="20,20,20,20,20,20" ColumnDefinitions="150,*">
|
<Grid RowDefinitions="20,20,20,20,20,20" ColumnDefinitions="150,*">
|
||||||
|
@ -81,7 +81,7 @@
|
||||||
<TextBlock Text="{DynamicResource Text.Hotkeys.Repo}"
|
<TextBlock Text="{DynamicResource Text.Hotkeys.Repo}"
|
||||||
Foreground="{DynamicResource Brush.FG2}"
|
Foreground="{DynamicResource Brush.FG2}"
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}"
|
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Increase}}"
|
||||||
Margin="0,8"/>
|
Margin="0,8"/>
|
||||||
|
|
||||||
<Grid RowDefinitions="20,20,20,20,20,20,20,20" ColumnDefinitions="150,*">
|
<Grid RowDefinitions="20,20,20,20,20,20,20,20" ColumnDefinitions="150,*">
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
<TextBlock Text="{DynamicResource Text.Hotkeys.TextEditor}"
|
<TextBlock Text="{DynamicResource Text.Hotkeys.TextEditor}"
|
||||||
Foreground="{DynamicResource Brush.FG2}"
|
Foreground="{DynamicResource Brush.FG2}"
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Increase}}"
|
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Increase}}"
|
||||||
Margin="0,8"/>
|
Margin="0,8"/>
|
||||||
|
|
||||||
<Grid RowDefinitions="20,20,20,20" ColumnDefinitions="150,*">
|
<Grid RowDefinitions="20,20,20,20" ColumnDefinitions="150,*">
|
||||||
|
|
169
src/Views/ImageDiffView.axaml
Normal file
169
src/Views/ImageDiffView.axaml
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:m="using:SourceGit.Models"
|
||||||
|
xmlns:vm="using:SourceGit.ViewModels"
|
||||||
|
xmlns:v="using:SourceGit.Views"
|
||||||
|
xmlns:c="using:SourceGit.Converters"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="SourceGit.Views.ImageDiffView"
|
||||||
|
x:DataType="m:ImageDiff">
|
||||||
|
<TabControl Margin="0,0,0,8" TabStripPlacement="Bottom">
|
||||||
|
<TabControl.Styles>
|
||||||
|
<Style Selector="TabControl /template/ ItemsPresenter#PART_ItemsPresenter > WrapPanel">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Center"/>
|
||||||
|
</Style>
|
||||||
|
</TabControl.Styles>
|
||||||
|
|
||||||
|
<TabItem Header="SIDE-BY-SIDE">
|
||||||
|
<Grid ColumnDefinitions="*,32,*" RowDefinitions="Auto,*" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="8,16">
|
||||||
|
<StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||||
|
<Border Height="16" Background="{DynamicResource Brush.Badge}" CornerRadius="8" VerticalAlignment="Center">
|
||||||
|
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.Old}" Margin="8,0" FontSize="10"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1" Classes="monospace" Text="{Binding OldImageSize}" Margin="8,0,0,0"/>
|
||||||
|
<TextBlock Grid.Column="2" Classes="monospace" Text="{Binding OldFileSize}" Foreground="{DynamicResource Brush.FG2}" Margin="16,0,0,0" HorizontalAlignment="Right"/>
|
||||||
|
<TextBlock Grid.Column="3" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Border Grid.Row="1" Grid.Column="0" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
|
||||||
|
<Border Background="{DynamicResource Brush.Popup}" HorizontalAlignment="Center" Padding="8">
|
||||||
|
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}">
|
||||||
|
<v:ImageContainer>
|
||||||
|
<Image Source="{Binding Old}" Stretch="Uniform" VerticalAlignment="Center"/>
|
||||||
|
</v:ImageContainer>
|
||||||
|
</Border>
|
||||||
|
</Border>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="0" Grid.Column="2" Orientation="Horizontal" HorizontalAlignment="Center">
|
||||||
|
<Border Height="16" Background="Green" CornerRadius="8" VerticalAlignment="Center">
|
||||||
|
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.New}" Margin="8,0" FontSize="10"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1" Classes="monospace" Text="{Binding NewImageSize}" Margin="8,0,0,0"/>
|
||||||
|
<TextBlock Grid.Column="2" Classes="monospace" Text="{Binding NewFileSize}" Foreground="{DynamicResource Brush.FG2}" Margin="16,0,0,0" HorizontalAlignment="Right"/>
|
||||||
|
<TextBlock Grid.Column="3" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Border Grid.Row="1" Grid.Column="2" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
|
||||||
|
<Border Background="{DynamicResource Brush.Popup}" HorizontalAlignment="Center" Padding="8">
|
||||||
|
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}">
|
||||||
|
<v:ImageContainer>
|
||||||
|
<Image Source="{Binding New}" Stretch="Uniform"/>
|
||||||
|
</v:ImageContainer>
|
||||||
|
</Border>
|
||||||
|
</Border>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
|
<TabItem Header="SWIPE">
|
||||||
|
<Grid RowDefinitions="Auto,*" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="8,16">
|
||||||
|
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto" HorizontalAlignment="Center">
|
||||||
|
<Border Grid.Column="0" Height="16" Background="{DynamicResource Brush.Badge}" CornerRadius="8" VerticalAlignment="Center">
|
||||||
|
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.Old}" Margin="8,0" FontSize="10"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1" Classes="monospace" Text="{Binding OldImageSize}" Margin="8,0,0,0"/>
|
||||||
|
<TextBlock Grid.Column="2" Classes="monospace" Text="{Binding OldFileSize}" Foreground="{DynamicResource Brush.FG2}" Margin="16,0,0,0" HorizontalAlignment="Right"/>
|
||||||
|
<TextBlock Grid.Column="3" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
||||||
|
|
||||||
|
<Border Grid.Column="4" Height="16" Background="Green" CornerRadius="8" VerticalAlignment="Center" Margin="32,0,0,0">
|
||||||
|
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.New}" Margin="8,0" FontSize="10"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="5" Classes="monospace" Text="{Binding NewImageSize}" Margin="8,0,0,0"/>
|
||||||
|
<TextBlock Grid.Column="6" Classes="monospace" Text="{Binding NewFileSize}" Foreground="{DynamicResource Brush.FG2}" Margin="16,0,0,0" HorizontalAlignment="Right"/>
|
||||||
|
<TextBlock Grid.Column="7" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
|
||||||
|
<Border HorizontalAlignment="Center" Background="{DynamicResource Brush.Window}">
|
||||||
|
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
|
||||||
|
<v:ImageContainer>
|
||||||
|
<v:ImagesSwipeControl OldImage="{Binding Old}"
|
||||||
|
NewImage="{Binding New}"
|
||||||
|
RenderOptions.BitmapInterpolationMode="HighQuality"/>
|
||||||
|
</v:ImageContainer>
|
||||||
|
</Border>
|
||||||
|
</Border>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
|
<TabItem Header="BLEND">
|
||||||
|
<Grid RowDefinitions="Auto,*,Auto" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="8,16,8,0">
|
||||||
|
<Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto" HorizontalAlignment="Center">
|
||||||
|
<Border Grid.Column="0" Height="16" Background="{DynamicResource Brush.Badge}" CornerRadius="8" VerticalAlignment="Center">
|
||||||
|
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.Old}" Margin="8,0" FontSize="10"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="1" Classes="monospace" Text="{Binding OldImageSize}" Margin="8,0,0,0"/>
|
||||||
|
<TextBlock Grid.Column="2" Classes="monospace" Text="{Binding OldFileSize}" Foreground="{DynamicResource Brush.FG2}" Margin="16,0,0,0" HorizontalAlignment="Right"/>
|
||||||
|
<TextBlock Grid.Column="3" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
||||||
|
|
||||||
|
<Border Grid.Column="4" Height="16" Background="Green" CornerRadius="8" VerticalAlignment="Center" Margin="32,0,0,0">
|
||||||
|
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.New}" Margin="8,0" FontSize="10"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock Grid.Column="5" Classes="monospace" Text="{Binding NewImageSize}" Margin="8,0,0,0"/>
|
||||||
|
<TextBlock Grid.Column="6" Classes="monospace" Text="{Binding NewFileSize}" Foreground="{DynamicResource Brush.FG2}" Margin="16,0,0,0" HorizontalAlignment="Right"/>
|
||||||
|
<TextBlock Grid.Column="7" Classes="monospace" Text="{DynamicResource Text.Bytes}" Foreground="{DynamicResource Brush.FG2}" Margin="2,0,0,0"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Border Grid.Row="1" Margin="0,12,0,0" Effect="drop-shadow(0 0 8 #A0000000)">
|
||||||
|
<Border HorizontalAlignment="Center" Background="{DynamicResource Brush.Window}">
|
||||||
|
<Border BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}" Margin="8">
|
||||||
|
<v:ImageContainer>
|
||||||
|
<v:ImageBlendControl Alpha="{Binding #ImageBlendSlider.Value}"
|
||||||
|
OldImage="{Binding Old}"
|
||||||
|
NewImage="{Binding New}"
|
||||||
|
RenderOptions.BitmapInterpolationMode="HighQuality"/>
|
||||||
|
</v:ImageContainer>
|
||||||
|
</Border>
|
||||||
|
</Border>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Grid Grid.Row="2" ColumnDefinitions="100,200,100" Margin="0,12,0,0" HorizontalAlignment="Center">
|
||||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,0,8,0">
|
||||||
|
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.Old}"/>
|
||||||
|
<TextBlock Classes="monospace"
|
||||||
|
Margin="8,0,0,0"
|
||||||
|
Text="{Binding #ImageBlendSlider.Value, Converter={x:Static c:DoubleConverters.ToPercentage}}"
|
||||||
|
Foreground="{DynamicResource Brush.FG2}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Slider Grid.Column="1"
|
||||||
|
x:Name="ImageBlendSlider"
|
||||||
|
Minimum="0" Maximum="1"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
TickPlacement="None"
|
||||||
|
Margin="0"
|
||||||
|
MinHeight="0"
|
||||||
|
Foreground="{DynamicResource Brush.Border1}"
|
||||||
|
Value="0.5">
|
||||||
|
<Slider.Resources>
|
||||||
|
<Thickness x:Key="SliderTopHeaderMargin">0,0,0,4</Thickness>
|
||||||
|
<GridLength x:Key="SliderPreContentMargin">0</GridLength>
|
||||||
|
<GridLength x:Key="SliderPostContentMargin">0</GridLength>
|
||||||
|
<CornerRadius x:Key="SliderThumbCornerRadius">8</CornerRadius>
|
||||||
|
<x:Double x:Key="SliderHorizontalThumbWidth">16</x:Double>
|
||||||
|
<x:Double x:Key="SliderHorizontalThumbHeight">16</x:Double>
|
||||||
|
</Slider.Resources>
|
||||||
|
</Slider>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="2" Orientation="Horizontal" VerticalAlignment="Top" Margin="8,0,0,0">
|
||||||
|
<TextBlock Classes="monospace" Text="{DynamicResource Text.Diff.Binary.New}"/>
|
||||||
|
<TextBlock Classes="monospace"
|
||||||
|
Margin="8,0,0,0"
|
||||||
|
Text="{Binding #ImageBlendSlider.Value, Converter={x:Static c:DoubleConverters.OneMinusToPercentage}}"
|
||||||
|
Foreground="{DynamicResource Brush.FG2}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</TabItem>
|
||||||
|
</TabControl>
|
||||||
|
</UserControl>
|
294
src/Views/ImageDiffView.axaml.cs
Normal file
294
src/Views/ImageDiffView.axaml.cs
Normal file
|
@ -0,0 +1,294 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using Avalonia.Styling;
|
||||||
|
|
||||||
|
namespace SourceGit.Views
|
||||||
|
{
|
||||||
|
public class ImageContainer : ContentControl
|
||||||
|
{
|
||||||
|
protected override Type StyleKeyOverride => typeof(ContentControl);
|
||||||
|
|
||||||
|
public override void Render(DrawingContext context)
|
||||||
|
{
|
||||||
|
if (_bgBrush == null)
|
||||||
|
{
|
||||||
|
var maskBrush = new SolidColorBrush(ActualThemeVariant == ThemeVariant.Dark ? 0xFF404040 : 0xFFBBBBBB);
|
||||||
|
var bg = new DrawingGroup()
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new GeometryDrawing() { Brush = maskBrush, Geometry = new RectangleGeometry(new Rect(0, 0, 12, 12)) },
|
||||||
|
new GeometryDrawing() { Brush = maskBrush, Geometry = new RectangleGeometry(new Rect(12, 12, 12, 12)) },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_bgBrush = new DrawingBrush(bg)
|
||||||
|
{
|
||||||
|
AlignmentX = AlignmentX.Left,
|
||||||
|
AlignmentY = AlignmentY.Top,
|
||||||
|
DestinationRect = new RelativeRect(new Size(24, 24), RelativeUnit.Absolute),
|
||||||
|
Stretch = Stretch.None,
|
||||||
|
TileMode = TileMode.Tile,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
context.FillRectangle(_bgBrush, new Rect(Bounds.Size));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
|
||||||
|
{
|
||||||
|
base.OnPropertyChanged(change);
|
||||||
|
|
||||||
|
if (change.Property.Name == "ActualThemeVariant")
|
||||||
|
{
|
||||||
|
_bgBrush = null;
|
||||||
|
InvalidateVisual();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DrawingBrush _bgBrush = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ImagesSwipeControl : Control
|
||||||
|
{
|
||||||
|
public static readonly StyledProperty<double> AlphaProperty =
|
||||||
|
AvaloniaProperty.Register<ImagesSwipeControl, double>(nameof(Alpha), 0.5);
|
||||||
|
|
||||||
|
public double Alpha
|
||||||
|
{
|
||||||
|
get => GetValue(AlphaProperty);
|
||||||
|
set => SetValue(AlphaProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<Bitmap> OldImageProperty =
|
||||||
|
AvaloniaProperty.Register<ImagesSwipeControl, Bitmap>(nameof(OldImage), null);
|
||||||
|
|
||||||
|
public Bitmap OldImage
|
||||||
|
{
|
||||||
|
get => GetValue(OldImageProperty);
|
||||||
|
set => SetValue(OldImageProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<Bitmap> NewImageProperty =
|
||||||
|
AvaloniaProperty.Register<ImagesSwipeControl, Bitmap>(nameof(NewImage), null);
|
||||||
|
|
||||||
|
public Bitmap NewImage
|
||||||
|
{
|
||||||
|
get => GetValue(NewImageProperty);
|
||||||
|
set => SetValue(NewImageProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImagesSwipeControl()
|
||||||
|
{
|
||||||
|
AffectsMeasure<ImagesSwipeControl>(OldImageProperty, NewImageProperty);
|
||||||
|
AffectsRender<ImagesSwipeControl>(AlphaProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Render(DrawingContext context)
|
||||||
|
{
|
||||||
|
var alpha = Alpha;
|
||||||
|
var w = Bounds.Width;
|
||||||
|
var h = Bounds.Height;
|
||||||
|
var x = w * alpha;
|
||||||
|
var left = OldImage;
|
||||||
|
if (left != null && alpha > 0)
|
||||||
|
{
|
||||||
|
var src = new Rect(0, 0, left.Size.Width * alpha, left.Size.Height);
|
||||||
|
var dst = new Rect(0, 0, x, h);
|
||||||
|
context.DrawImage(left, src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
var right = NewImage;
|
||||||
|
if (right != null && alpha < 1)
|
||||||
|
{
|
||||||
|
var src = new Rect(right.Size.Width * alpha, 0, right.Size.Width * (1 - alpha), right.Size.Height);
|
||||||
|
var dst = new Rect(x, 0, w - x, h);
|
||||||
|
context.DrawImage(right, src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.DrawLine(new Pen(Brushes.DarkGreen, 2), new Point(x, 0), new Point(x, Bounds.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPointerPressed(PointerPressedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnPointerPressed(e);
|
||||||
|
|
||||||
|
var p = e.GetPosition(this);
|
||||||
|
var hitbox = new Rect(Math.Max(Bounds.Width * Alpha - 2, 0), 0, 4, Bounds.Height);
|
||||||
|
var pointer = e.GetCurrentPoint(this);
|
||||||
|
if (pointer.Properties.IsLeftButtonPressed && hitbox.Contains(p))
|
||||||
|
{
|
||||||
|
_pressedOnSlider = true;
|
||||||
|
Cursor = new Cursor(StandardCursorType.SizeWestEast);
|
||||||
|
e.Pointer.Capture(this);
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnPointerReleased(e);
|
||||||
|
_pressedOnSlider = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPointerMoved(PointerEventArgs e)
|
||||||
|
{
|
||||||
|
var w = Bounds.Width;
|
||||||
|
var p = e.GetPosition(this);
|
||||||
|
|
||||||
|
if (_pressedOnSlider)
|
||||||
|
{
|
||||||
|
SetCurrentValue(AlphaProperty, Math.Clamp(p.X, 0, w) / w);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var hitbox = new Rect(Math.Max(w * Alpha - 2, 0), 0, 4, Bounds.Height);
|
||||||
|
if (hitbox.Contains(p))
|
||||||
|
{
|
||||||
|
if (!_lastInSlider)
|
||||||
|
{
|
||||||
|
_lastInSlider = true;
|
||||||
|
Cursor = new Cursor(StandardCursorType.SizeWestEast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_lastInSlider)
|
||||||
|
{
|
||||||
|
_lastInSlider = false;
|
||||||
|
Cursor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
|
{
|
||||||
|
var left = OldImage;
|
||||||
|
var right = NewImage;
|
||||||
|
|
||||||
|
if (left == null)
|
||||||
|
return right == null ? availableSize : GetDesiredSize(right.Size, availableSize);
|
||||||
|
|
||||||
|
if (right == null)
|
||||||
|
return GetDesiredSize(left.Size, availableSize);
|
||||||
|
|
||||||
|
var ls = GetDesiredSize(left.Size, availableSize);
|
||||||
|
var rs = GetDesiredSize(right.Size, availableSize);
|
||||||
|
return ls.Width > rs.Width ? ls : rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Size GetDesiredSize(Size img, Size available)
|
||||||
|
{
|
||||||
|
var w = available.Width;
|
||||||
|
var h = available.Height;
|
||||||
|
|
||||||
|
var sw = available.Width / img.Width;
|
||||||
|
var sh = available.Height / img.Height;
|
||||||
|
var scale = Math.Min(sw, sh);
|
||||||
|
|
||||||
|
return new Size(scale * img.Width, scale * img.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _pressedOnSlider = false;
|
||||||
|
private bool _lastInSlider = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ImageBlendControl : Control
|
||||||
|
{
|
||||||
|
public static readonly StyledProperty<double> AlphaProperty =
|
||||||
|
AvaloniaProperty.Register<ImageBlendControl, double>(nameof(Alpha), 1.0);
|
||||||
|
|
||||||
|
public double Alpha
|
||||||
|
{
|
||||||
|
get => GetValue(AlphaProperty);
|
||||||
|
set => SetValue(AlphaProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<Bitmap> OldImageProperty =
|
||||||
|
AvaloniaProperty.Register<ImageBlendControl, Bitmap>(nameof(OldImage), null);
|
||||||
|
|
||||||
|
public Bitmap OldImage
|
||||||
|
{
|
||||||
|
get => GetValue(OldImageProperty);
|
||||||
|
set => SetValue(OldImageProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<Bitmap> NewImageProperty =
|
||||||
|
AvaloniaProperty.Register<ImageBlendControl, Bitmap>(nameof(NewImage), null);
|
||||||
|
|
||||||
|
public Bitmap NewImage
|
||||||
|
{
|
||||||
|
get => GetValue(NewImageProperty);
|
||||||
|
set => SetValue(NewImageProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImageBlendControl()
|
||||||
|
{
|
||||||
|
AffectsMeasure<ImageBlendControl>(OldImageProperty, NewImageProperty);
|
||||||
|
AffectsRender<ImageBlendControl>(AlphaProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Render(DrawingContext context)
|
||||||
|
{
|
||||||
|
var rect = new Rect(0, 0, Bounds.Width, Bounds.Height);
|
||||||
|
var alpha = Alpha;
|
||||||
|
var left = OldImage;
|
||||||
|
if (left != null && alpha < 1)
|
||||||
|
{
|
||||||
|
var state = context.PushOpacity(1- alpha);
|
||||||
|
context.DrawImage(left, rect);
|
||||||
|
state.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
var right = NewImage;
|
||||||
|
if (right != null && alpha > 0)
|
||||||
|
{
|
||||||
|
var state = context.PushOpacity(alpha);
|
||||||
|
context.DrawImage(right, rect);
|
||||||
|
state.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
|
{
|
||||||
|
var left = OldImage;
|
||||||
|
var right = NewImage;
|
||||||
|
|
||||||
|
if (left == null)
|
||||||
|
return right == null ? availableSize : GetDesiredSize(right.Size, availableSize);
|
||||||
|
|
||||||
|
if (right == null)
|
||||||
|
return GetDesiredSize(left.Size, availableSize);
|
||||||
|
|
||||||
|
var ls = GetDesiredSize(left.Size, availableSize);
|
||||||
|
var rs = GetDesiredSize(right.Size, availableSize);
|
||||||
|
return ls.Width > rs.Width ? ls : rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Size GetDesiredSize(Size img, Size available)
|
||||||
|
{
|
||||||
|
var w = available.Width;
|
||||||
|
var h = available.Height;
|
||||||
|
|
||||||
|
var sw = available.Width / img.Width;
|
||||||
|
var sh = available.Height / img.Height;
|
||||||
|
var scale = Math.Min(sw, sh);
|
||||||
|
|
||||||
|
return new Size(scale * img.Width, scale * img.Height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class ImageDiffView : UserControl
|
||||||
|
{
|
||||||
|
public ImageDiffView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,7 +18,7 @@
|
||||||
<TextBlock x:Name="txtDesc"
|
<TextBlock x:Name="txtDesc"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Decrease}}"
|
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
|
||||||
FontStyle="Italic"
|
FontStyle="Italic"
|
||||||
Text="{Binding #me.Description}"/>
|
Text="{Binding #me.Description}"/>
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@
|
||||||
Classes="italic"
|
Classes="italic"
|
||||||
Margin="0,0,8,0"
|
Margin="0,0,8,0"
|
||||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||||
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:FontSizeModifyConverters.Decrease}}"
|
FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
|
||||||
Text="{DynamicResource Text.Welcome.DragDropTip}"
|
Text="{DynamicResource Text.Welcome.DragDropTip}"
|
||||||
Foreground="{DynamicResource Brush.FG2}"/>
|
Foreground="{DynamicResource Brush.FG2}"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
Loading…
Reference in a new issue