mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-05-17 09:26:50 +08:00
feat(界面): 实现遮罩窗口布局的相对比例定位
添加相对比例定位功能,将遮罩窗口中的状态列表和日志文本框从绝对坐标改为基于窗口宽高的比例坐标 新增OverlayRelativeOrAbsoluteConverter转换器处理坐标转换 修改相关视图模型和配置以支持比例定位
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using OpenCvSharp;
|
||||
using System;
|
||||
|
||||
@@ -80,26 +80,26 @@ public partial class MaskWindowConfig : ObservableObject
|
||||
private bool _overlayLayoutEditEnabled = false;
|
||||
|
||||
[ObservableProperty]
|
||||
private double _logTextBoxLeft = 20;
|
||||
private double _logTextBoxLeftRatio = 20.0 / 1920;
|
||||
|
||||
[ObservableProperty]
|
||||
private double _logTextBoxTop = 832;
|
||||
private double _logTextBoxTopRatio = 832.0 / 1080;
|
||||
|
||||
[ObservableProperty]
|
||||
private double _logTextBoxWidth = 477;
|
||||
private double _logTextBoxWidthRatio = 477.0 / 1920;
|
||||
|
||||
[ObservableProperty]
|
||||
private double _logTextBoxHeight = 188;
|
||||
private double _logTextBoxHeightRatio = 188.0 / 1080;
|
||||
|
||||
[ObservableProperty]
|
||||
private double _statusListLeft = 20;
|
||||
private double _statusListLeftRatio = 20.0 / 1920;
|
||||
|
||||
[ObservableProperty]
|
||||
private double _statusListTop = 807;
|
||||
private double _statusListTopRatio = 807.0 / 1080;
|
||||
|
||||
[ObservableProperty]
|
||||
private double _statusListWidth = 477;
|
||||
private double _statusListWidthRatio = 477.0 / 1920;
|
||||
|
||||
[ObservableProperty]
|
||||
private double _statusListHeight = 24;
|
||||
private double _statusListHeightRatio = 24.0 / 1080;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace BetterGenshinImpact.View.Converters
|
||||
{
|
||||
public class OverlayRelativeOrAbsoluteConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (values.Length < 2)
|
||||
{
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
|
||||
if (values.Length == 2)
|
||||
{
|
||||
var ratio = ToDouble(values[0]);
|
||||
var baseSize = ToDouble(values[1]);
|
||||
|
||||
if (double.IsNaN(ratio) || double.IsNaN(baseSize) || baseSize <= 0)
|
||||
{
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
|
||||
return ratio * baseSize;
|
||||
}
|
||||
|
||||
var ratio3 = ToDouble(values[0]);
|
||||
var absolute = ToDouble(values[1]);
|
||||
var baseSize3 = ToDouble(values[2]);
|
||||
|
||||
if (double.IsNaN(baseSize3) || baseSize3 <= 0)
|
||||
{
|
||||
return absolute;
|
||||
}
|
||||
|
||||
if (!double.IsNaN(ratio3))
|
||||
{
|
||||
return ratio3 * baseSize3;
|
||||
}
|
||||
|
||||
return absolute;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object? parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static double ToDouble(object value)
|
||||
{
|
||||
if (value == DependencyProperty.UnsetValue)
|
||||
{
|
||||
return double.NaN;
|
||||
}
|
||||
|
||||
return value switch
|
||||
{
|
||||
double d => d,
|
||||
float f => f,
|
||||
int i => i,
|
||||
long l => l,
|
||||
_ => double.NaN
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
xmlns:viewModel="clr-namespace:BetterGenshinImpact.ViewModel"
|
||||
xmlns:platform="clr-namespace:BetterGenshinImpact.Platform.Wine"
|
||||
xmlns:overlay="clr-namespace:BetterGenshinImpact.View.Controls.Overlay"
|
||||
xmlns:converters="clr-namespace:BetterGenshinImpact.View.Converters"
|
||||
Title="MaskWindow"
|
||||
Width="500"
|
||||
Height="800"
|
||||
@@ -28,6 +29,9 @@
|
||||
<b:EventTrigger EventName="Loaded">
|
||||
<b:InvokeCommandAction Command="{Binding LoadedCommand}" CommandParameter="{Binding}" />
|
||||
</b:EventTrigger>
|
||||
<b:EventTrigger EventName="SizeChanged">
|
||||
<b:InvokeCommandAction Command="{Binding WindowSizeChangedCommand}" PassEventArgsToCommand="True" />
|
||||
</b:EventTrigger>
|
||||
</b:Interaction.Triggers>
|
||||
|
||||
<Window.Background>
|
||||
@@ -51,6 +55,7 @@
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/View/Controls/Overlay/AdjustableOverlayItemStyles.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<converters:OverlayRelativeOrAbsoluteConverter x:Key="OverlayRelativeOrAbsoluteConverter" />
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
@@ -78,10 +83,6 @@
|
||||
Grid.ColumnSpan="6"
|
||||
ClipToBounds="True">
|
||||
<overlay:AdjustableOverlayItem x:Name="StatusWrapper"
|
||||
Canvas.Left="{Binding Config.MaskWindowConfig.StatusListLeft, Mode=OneWay}"
|
||||
Canvas.Top="{Binding Config.MaskWindowConfig.StatusListTop, Mode=OneWay}"
|
||||
Width="{Binding Config.MaskWindowConfig.StatusListWidth, Mode=OneWay}"
|
||||
Height="{Binding Config.MaskWindowConfig.StatusListHeight, Mode=OneWay}"
|
||||
Padding="4,2"
|
||||
Background="#00000000"
|
||||
BorderBrush="#33000000"
|
||||
@@ -91,6 +92,30 @@
|
||||
IsEditEnabled="{Binding Config.MaskWindowConfig.OverlayLayoutEditEnabled}"
|
||||
LayoutKey="StatusList"
|
||||
Visibility="{Binding Config.MaskWindowConfig.ShowStatus, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<Canvas.Left>
|
||||
<MultiBinding Converter="{StaticResource OverlayRelativeOrAbsoluteConverter}">
|
||||
<Binding Path="Config.MaskWindowConfig.StatusListLeftRatio" />
|
||||
<Binding RelativeSource="{RelativeSource AncestorType=Window}" Path="ActualWidth" />
|
||||
</MultiBinding>
|
||||
</Canvas.Left>
|
||||
<Canvas.Top>
|
||||
<MultiBinding Converter="{StaticResource OverlayRelativeOrAbsoluteConverter}">
|
||||
<Binding Path="Config.MaskWindowConfig.StatusListTopRatio" />
|
||||
<Binding RelativeSource="{RelativeSource AncestorType=Window}" Path="ActualHeight" />
|
||||
</MultiBinding>
|
||||
</Canvas.Top>
|
||||
<overlay:AdjustableOverlayItem.Width>
|
||||
<MultiBinding Converter="{StaticResource OverlayRelativeOrAbsoluteConverter}">
|
||||
<Binding Path="Config.MaskWindowConfig.StatusListWidthRatio" />
|
||||
<Binding RelativeSource="{RelativeSource AncestorType=Window}" Path="ActualWidth" />
|
||||
</MultiBinding>
|
||||
</overlay:AdjustableOverlayItem.Width>
|
||||
<overlay:AdjustableOverlayItem.Height>
|
||||
<MultiBinding Converter="{StaticResource OverlayRelativeOrAbsoluteConverter}">
|
||||
<Binding Path="Config.MaskWindowConfig.StatusListHeightRatio" />
|
||||
<Binding RelativeSource="{RelativeSource AncestorType=Window}" Path="ActualHeight" />
|
||||
</MultiBinding>
|
||||
</overlay:AdjustableOverlayItem.Height>
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="LayoutCommitted">
|
||||
<b:InvokeCommandAction Command="{Binding OverlayLayoutCommittedCommand}" PassEventArgsToCommand="True" />
|
||||
@@ -156,10 +181,6 @@
|
||||
</overlay:AdjustableOverlayItem>
|
||||
|
||||
<overlay:AdjustableOverlayItem x:Name="LogTextBoxWrapper"
|
||||
Canvas.Left="{Binding Config.MaskWindowConfig.LogTextBoxLeft, Mode=OneWay}"
|
||||
Canvas.Top="{Binding Config.MaskWindowConfig.LogTextBoxTop, Mode=OneWay}"
|
||||
Width="{Binding Config.MaskWindowConfig.LogTextBoxWidth, Mode=OneWay}"
|
||||
Height="{Binding Config.MaskWindowConfig.LogTextBoxHeight, Mode=OneWay}"
|
||||
Padding="0"
|
||||
Background="#00000000"
|
||||
BorderBrush="#33000000"
|
||||
@@ -169,6 +190,30 @@
|
||||
IsEditEnabled="{Binding Config.MaskWindowConfig.OverlayLayoutEditEnabled}"
|
||||
LayoutKey="LogTextBox"
|
||||
Visibility="{Binding Config.MaskWindowConfig.ShowLogBox, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<Canvas.Left>
|
||||
<MultiBinding Converter="{StaticResource OverlayRelativeOrAbsoluteConverter}">
|
||||
<Binding Path="Config.MaskWindowConfig.LogTextBoxLeftRatio" />
|
||||
<Binding RelativeSource="{RelativeSource AncestorType=Window}" Path="ActualWidth" />
|
||||
</MultiBinding>
|
||||
</Canvas.Left>
|
||||
<Canvas.Top>
|
||||
<MultiBinding Converter="{StaticResource OverlayRelativeOrAbsoluteConverter}">
|
||||
<Binding Path="Config.MaskWindowConfig.LogTextBoxTopRatio" />
|
||||
<Binding RelativeSource="{RelativeSource AncestorType=Window}" Path="ActualHeight" />
|
||||
</MultiBinding>
|
||||
</Canvas.Top>
|
||||
<overlay:AdjustableOverlayItem.Width>
|
||||
<MultiBinding Converter="{StaticResource OverlayRelativeOrAbsoluteConverter}">
|
||||
<Binding Path="Config.MaskWindowConfig.LogTextBoxWidthRatio" />
|
||||
<Binding RelativeSource="{RelativeSource AncestorType=Window}" Path="ActualWidth" />
|
||||
</MultiBinding>
|
||||
</overlay:AdjustableOverlayItem.Width>
|
||||
<overlay:AdjustableOverlayItem.Height>
|
||||
<MultiBinding Converter="{StaticResource OverlayRelativeOrAbsoluteConverter}">
|
||||
<Binding Path="Config.MaskWindowConfig.LogTextBoxHeightRatio" />
|
||||
<Binding RelativeSource="{RelativeSource AncestorType=Window}" Path="ActualHeight" />
|
||||
</MultiBinding>
|
||||
</overlay:AdjustableOverlayItem.Height>
|
||||
<b:Interaction.Triggers>
|
||||
<b:EventTrigger EventName="LayoutCommitted">
|
||||
<b:InvokeCommandAction Command="{Binding OverlayLayoutCommittedCommand}" PassEventArgsToCommand="True" />
|
||||
|
||||
@@ -27,6 +27,10 @@ namespace BetterGenshinImpact.ViewModel
|
||||
|
||||
[ObservableProperty] private string _fps = "0";
|
||||
|
||||
[ObservableProperty] private double _maskWindowWidth;
|
||||
|
||||
[ObservableProperty] private double _maskWindowHeight;
|
||||
|
||||
public MaskWindowViewModel()
|
||||
{
|
||||
WeakReferenceMessenger.Default.Register<PropertyChangedMessage<object>>(this, (sender, msg) =>
|
||||
@@ -111,23 +115,40 @@ namespace BetterGenshinImpact.ViewModel
|
||||
return;
|
||||
}
|
||||
|
||||
if (MaskWindowWidth <= 0 || MaskWindowHeight <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var leftRatio = ToRatio(args.Left, MaskWindowWidth);
|
||||
var topRatio = ToRatio(args.Top, MaskWindowHeight);
|
||||
var widthRatio = ToRatio(args.Width, MaskWindowWidth);
|
||||
var heightRatio = ToRatio(args.Height, MaskWindowHeight);
|
||||
|
||||
switch (args.LayoutKey)
|
||||
{
|
||||
case "LogTextBox":
|
||||
Config.MaskWindowConfig.LogTextBoxLeft = args.Left;
|
||||
Config.MaskWindowConfig.LogTextBoxTop = args.Top;
|
||||
Config.MaskWindowConfig.LogTextBoxWidth = args.Width;
|
||||
Config.MaskWindowConfig.LogTextBoxHeight = args.Height;
|
||||
Config.MaskWindowConfig.LogTextBoxLeftRatio = leftRatio;
|
||||
Config.MaskWindowConfig.LogTextBoxTopRatio = topRatio;
|
||||
Config.MaskWindowConfig.LogTextBoxWidthRatio = widthRatio;
|
||||
Config.MaskWindowConfig.LogTextBoxHeightRatio = heightRatio;
|
||||
break;
|
||||
case "StatusList":
|
||||
Config.MaskWindowConfig.StatusListLeft = args.Left;
|
||||
Config.MaskWindowConfig.StatusListTop = args.Top;
|
||||
Config.MaskWindowConfig.StatusListWidth = args.Width;
|
||||
Config.MaskWindowConfig.StatusListHeight = args.Height;
|
||||
Config.MaskWindowConfig.StatusListLeftRatio = leftRatio;
|
||||
Config.MaskWindowConfig.StatusListTopRatio = topRatio;
|
||||
Config.MaskWindowConfig.StatusListWidthRatio = widthRatio;
|
||||
Config.MaskWindowConfig.StatusListHeightRatio = heightRatio;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OnWindowSizeChanged(SizeChangedEventArgs args)
|
||||
{
|
||||
MaskWindowWidth = args.NewSize.Width;
|
||||
MaskWindowHeight = args.NewSize.Height;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OnExitOverlayLayoutEditMode()
|
||||
{
|
||||
@@ -139,5 +160,21 @@ namespace BetterGenshinImpact.ViewModel
|
||||
Config.MaskWindowConfig.OverlayLayoutEditEnabled = false;
|
||||
SystemControl.ActivateWindow();
|
||||
}
|
||||
|
||||
private static double ToRatio(double value, double baseSize)
|
||||
{
|
||||
if (double.IsNaN(value) || double.IsNaN(baseSize) || baseSize <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var ratio = value / baseSize;
|
||||
return ratio switch
|
||||
{
|
||||
< 0 => 0,
|
||||
> 1 => 1,
|
||||
_ => ratio
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,15 +213,15 @@ public partial class CommonSettingsPageViewModel : ViewModel
|
||||
private void OnResetMaskOverlayLayout()
|
||||
{
|
||||
var c = Config.MaskWindowConfig;
|
||||
c.StatusListLeft = 20;
|
||||
c.StatusListTop = 807;
|
||||
c.StatusListWidth = 477;
|
||||
c.StatusListHeight = 24;
|
||||
c.StatusListLeftRatio = 20.0 / 1920;
|
||||
c.StatusListTopRatio = 807.0 / 1080;
|
||||
c.StatusListWidthRatio = 477.0 / 1920;
|
||||
c.StatusListHeightRatio = 24.0 / 1080;
|
||||
|
||||
c.LogTextBoxLeft = 20;
|
||||
c.LogTextBoxTop = 832;
|
||||
c.LogTextBoxWidth = 477;
|
||||
c.LogTextBoxHeight = 188;
|
||||
c.LogTextBoxLeftRatio = 20.0 / 1920;
|
||||
c.LogTextBoxTopRatio = 832.0 / 1080;
|
||||
c.LogTextBoxWidthRatio = 477.0 / 1920;
|
||||
c.LogTextBoxHeightRatio = 188.0 / 1080;
|
||||
|
||||
OnRefreshMaskSettings();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user