This commit is contained in:
2026-03-04 11:42:22 +08:00
parent 0bdf8ea81b
commit ad921dcfe7
2 changed files with 177 additions and 37 deletions
+135 -10
View File
@@ -3,6 +3,7 @@ using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Threading;
@@ -65,6 +66,16 @@ namespace Ink_Canvas.Helpers
private static void SetIsAdjusting(DependencyObject element, bool value) => element.SetValue(IsAdjustingProperty, value);
private static bool GetIsAdjusting(DependencyObject element) => (bool)element.GetValue(IsAdjustingProperty);
private static readonly DependencyProperty OriginalFontSizeProperty =
DependencyProperty.RegisterAttached(
"OriginalFontSize",
typeof(double),
typeof(AutoFontSizeHelper),
new PropertyMetadata(double.NaN));
private static void SetOriginalFontSize(DependencyObject element, double value) => element.SetValue(OriginalFontSizeProperty, value);
private static double GetOriginalFontSize(DependencyObject element) => (double)element.GetValue(OriginalFontSizeProperty);
private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is FrameworkElement fe)) return;
@@ -72,6 +83,12 @@ namespace Ink_Canvas.Helpers
if ((bool)e.NewValue)
{
var originalFontSize = GetElementFontSize(fe);
if (!double.IsNaN(originalFontSize) && originalFontSize > 0)
{
SetOriginalFontSize(fe, originalFontSize);
}
fe.SizeChanged += Element_OnSizeChanged;
fe.Loaded += Element_OnLoaded;
fe.Unloaded += Element_OnUnloaded;
@@ -155,6 +172,12 @@ namespace Ink_Canvas.Helpers
var text = GetElementText(fe);
if (string.IsNullOrEmpty(text)) return;
if (!ShouldAutoScaleForCurrentCulture(text))
{
RestoreOriginalFontSize(fe);
return;
}
var availableWidth = GetAvailableWidth(fe);
if (double.IsNaN(availableWidth) || availableWidth <= 1) return;
@@ -169,6 +192,8 @@ namespace Ink_Canvas.Helpers
var max = GetMaxFontSize(fe);
if (double.IsNaN(max) || max <= 0) max = current;
// Never enlarge: auto-fit should only reduce font size when needed.
if (max > current) max = current;
var startFont = Math.Min(current, max);
if (startFont < min) startFont = min;
@@ -176,13 +201,6 @@ namespace Ink_Canvas.Helpers
SetIsAdjusting(fe, true);
try
{
var desiredAtMax = MeasureTextWidth(fe, text, max);
if (desiredAtMax > 0 && desiredAtMax <= availableWidth + 0.5)
{
if (Math.Abs(current - max) > 0.01) SetElementFontSize(fe, max);
return;
}
var font = startFont;
var desired = MeasureTextWidth(fe, text, font);
if (desired <= 0) return;
@@ -194,6 +212,22 @@ namespace Ink_Canvas.Helpers
if (desired <= 0) break;
}
// Hard-fit fallback: when very narrow slots (e.g., 28px) still overflow at MinFontSize,
// keep shrinking proportionally so text always fits in the available width.
if (desired > availableWidth + 0.5)
{
var hardFont = font;
for (var i = 0; i < 6 && desired > availableWidth + 0.5; i++)
{
var ratio = availableWidth / Math.Max(1.0, desired);
hardFont = Math.Max(1.0, hardFont * ratio);
desired = MeasureTextWidth(fe, text, hardFont);
if (desired <= 0) break;
}
font = hardFont;
}
if (!double.IsNaN(font) && font > 0 && Math.Abs(current - font) > 0.01)
{
SetElementFontSize(fe, font);
@@ -212,6 +246,44 @@ namespace Ink_Canvas.Helpers
return null;
}
private static bool ShouldAutoScaleForCurrentCulture(string text)
{
// Requirement: auto-scale for English UI only, keep Chinese font size unchanged.
var culture = CultureInfo.CurrentUICulture;
var name = culture?.Name ?? string.Empty;
if (name.StartsWith("en", StringComparison.OrdinalIgnoreCase))
{
return true;
}
// Fallback: if actual rendered text is Latin-heavy, still auto-scale.
// This avoids clipping when culture detection is out of sync.
if (string.IsNullOrWhiteSpace(text)) return false;
foreach (var ch in text)
{
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
{
return true;
}
}
return false;
}
private static void RestoreOriginalFontSize(FrameworkElement fe)
{
var original = GetOriginalFontSize(fe);
if (double.IsNaN(original) || original <= 0) return;
var current = GetElementFontSize(fe);
if (double.IsNaN(current) || current <= 0) return;
if (Math.Abs(current - original) > 0.01)
{
SetElementFontSize(fe, original);
}
}
private static double GetElementFontSize(FrameworkElement fe)
{
if (fe is TextBlock tb) return tb.FontSize;
@@ -229,12 +301,65 @@ namespace Ink_Canvas.Helpers
{
double width = double.PositiveInfinity;
// Explicit width on the element itself should be a hard cap.
if (!double.IsNaN(fe.Width) && !double.IsInfinity(fe.Width) && fe.Width > 1)
{
width = Math.Min(width, fe.Width - fe.Margin.Left - fe.Margin.Right);
}
if (!double.IsNaN(fe.MaxWidth) && !double.IsInfinity(fe.MaxWidth) && fe.MaxWidth > 1)
{
width = Math.Min(width, fe.MaxWidth - fe.Margin.Left - fe.Margin.Right);
}
// Prefer the real layout slot first. This is usually the most accurate
// "space actually assigned by layout" for the element.
var slot = LayoutInformation.GetLayoutSlot(fe);
if (!double.IsNaN(slot.Width) && !double.IsInfinity(slot.Width))
{
var slotWidth = slot.Width - fe.Margin.Left - fe.Margin.Right;
if (slotWidth > 1) width = Math.Min(width, slotWidth);
}
if (fe.ActualWidth > 1) width = Math.Min(width, fe.ActualWidth);
if (fe.Parent is FrameworkElement parent && parent.ActualWidth > 1)
// Immediate parent may be a StackPanel that does not constrain width.
// Walk a few ancestors and take the tightest finite width as fallback.
DependencyObject ancestor = fe.Parent ?? VisualTreeHelper.GetParent(fe);
var depth = 0;
while (ancestor != null && depth < 8)
{
var parentWidth = parent.ActualWidth - fe.Margin.Left - fe.Margin.Right;
if (parentWidth > 1) width = Math.Min(width, parentWidth);
if (ancestor is FrameworkElement af && af.ActualWidth > 1)
{
var candidate = af.ActualWidth;
// If ancestor sets explicit width, treat it as a stronger cap.
if (!double.IsNaN(af.Width) && !double.IsInfinity(af.Width) && af.Width > 1)
{
candidate = Math.Min(candidate, af.Width);
}
if (!double.IsNaN(af.MaxWidth) && !double.IsInfinity(af.MaxWidth) && af.MaxWidth > 1)
{
candidate = Math.Min(candidate, af.MaxWidth);
}
if (ancestor is Control ac)
{
candidate -= ac.Padding.Left + ac.Padding.Right;
candidate -= ac.BorderThickness.Left + ac.BorderThickness.Right;
}
else if (ancestor is Border ab)
{
candidate -= ab.Padding.Left + ab.Padding.Right;
candidate -= ab.BorderThickness.Left + ab.BorderThickness.Right;
}
if (candidate > 1) width = Math.Min(width, candidate);
}
ancestor = (ancestor as FrameworkElement)?.Parent ?? VisualTreeHelper.GetParent(ancestor);
depth++;
}
if (double.IsInfinity(width) || double.IsNaN(width) || width <= 1) return -1;
+42 -27
View File
@@ -71,7 +71,7 @@
<Setter Property="TextWrapping" Value="NoWrap" />
<Setter Property="TextAlignment" Value="Center" />
<Setter Property="helpers:AutoFontSizeHelper.IsEnabled" Value="True" />
<Setter Property="helpers:AutoFontSizeHelper.MinFontSize" Value="6" />
<Setter Property="helpers:AutoFontSizeHelper.MinFontSize" Value="3.5" />
<Setter Property="helpers:AutoFontSizeHelper.MaxFontSize" Value="8" />
<Setter Property="helpers:AutoFontSizeHelper.Step" Value="0.25" />
</Style>
@@ -80,6 +80,17 @@
<Setter Property="Height" Value="10" />
<Setter Property="LineStackingStrategy" Value="BlockLineHeight" />
<Setter Property="LineHeight" Value="10" />
<Setter Property="helpers:AutoFontSizeHelper.MinFontSize" Value="2.5" />
<Setter Property="helpers:AutoFontSizeHelper.Step" Value="0.1" />
</Style>
<Style x:Key="AutoFitPenTabLabel9" TargetType="TextBlock">
<Setter Property="TextWrapping" Value="NoWrap" />
<Setter Property="TextAlignment" Value="Center" />
<Setter Property="helpers:AutoFontSizeHelper.IsEnabled" Value="True" />
<Setter Property="helpers:AutoFontSizeHelper.MinFontSize" Value="3.5" />
<Setter Property="helpers:AutoFontSizeHelper.MaxFontSize" Value="9" />
<Setter Property="helpers:AutoFontSizeHelper.Step" Value="0.1" />
</Style>
<Style x:Key="AutoFitToolPopupLabel8" TargetType="Label">
@@ -5174,7 +5185,7 @@
</Border>
<Viewbox Margin="8,0,8,0">
<ui:SimpleStackPanel Margin="0">
<ui:SimpleStackPanel Orientation="Horizontal" Spacing="4"
<ui:SimpleStackPanel Orientation="Horizontal" Spacing="2"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="0,3,0,0">
@@ -5183,9 +5194,9 @@
Height="16"
Width="16" />
<Label Content="{i18n:I18n Key=Board_MultiTouchWriting}" FontSize="8"
VerticalAlignment="Center" Width="64"
VerticalAlignment="Center" Width="56"
Style="{StaticResource AutoFitGestureOptionLabel10}" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
<Viewbox Width="36" Height="18" Margin="2,0,0,0">
<ui:ToggleSwitch MinWidth="0" Margin="0,-6,0,-6"
x:Name="BoardToggleSwitchEnableMultiTouchMode"
FontFamily="Microsoft YaHei UI"
@@ -5207,7 +5218,7 @@
</ui:SimpleStackPanel>
<ui:SimpleStackPanel
Opacity="{Binding Opacity, ElementName=TwoFingerGestureSimpleStackPanel}"
Orientation="Horizontal" Spacing="4"
Orientation="Horizontal" Spacing="2"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="{DynamicResource HandMoveIcon}"
@@ -5215,9 +5226,9 @@
Height="16"
Width="16" />
<Label Content="{i18n:I18n Key=Board_TwoFingerMove}" FontSize="8"
VerticalAlignment="Center" Width="64"
VerticalAlignment="Center" Width="56"
Style="{StaticResource AutoFitGestureOptionLabel10}" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
<Viewbox Width="36" Height="18" Margin="2,0,0,0">
<ui:ToggleSwitch MinWidth="0" Margin="0,-6,0,-6"
x:Name="BoardToggleSwitchEnableTwoFingerTranslate"
FontFamily="Microsoft YaHei UI"
@@ -5239,7 +5250,7 @@
</ui:SimpleStackPanel>
<ui:SimpleStackPanel
Opacity="{Binding Opacity, ElementName=TwoFingerGestureSimpleStackPanel}"
Orientation="Horizontal" Spacing="4"
Orientation="Horizontal" Spacing="2"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="{DynamicResource ZoomIcon}"
@@ -5247,9 +5258,9 @@
Height="16"
Width="16" />
<Label Content="{i18n:I18n Key=Board_TwoFingerZoom}" FontSize="8"
VerticalAlignment="Center" Width="64"
VerticalAlignment="Center" Width="56"
Style="{StaticResource AutoFitGestureOptionLabel10}" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
<Viewbox Width="36" Height="18" Margin="2,0,0,0">
<ui:ToggleSwitch MinWidth="0" Margin="0,-6,0,-6"
FontFamily="Microsoft YaHei UI"
IsOn="False" OnContent="" OffContent=""
@@ -5269,7 +5280,7 @@
</ui:SimpleStackPanel>
<ui:SimpleStackPanel
Opacity="{Binding Opacity, ElementName=TwoFingerGestureSimpleStackPanel}"
Orientation="Horizontal" Spacing="4"
Orientation="Horizontal" Spacing="2"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="{DynamicResource RotateIcon}"
@@ -5277,9 +5288,9 @@
Height="16"
Width="16" />
<Label Content="{i18n:I18n Key=Board_TwoFingerRotate}" FontSize="8"
VerticalAlignment="Center" Width="64"
VerticalAlignment="Center" Width="56"
Style="{StaticResource AutoFitGestureOptionLabel10}" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
<Viewbox Width="36" Height="18" Margin="2,0,0,0">
<ui:ToggleSwitch MinWidth="0" Margin="0,-6,0,-6"
FontFamily="Microsoft YaHei UI"
IsOn="False" OnContent="" OffContent=""
@@ -5476,7 +5487,9 @@
FontWeight="Medium"
FontSize="9"
TextAlignment="Center"
Text="{i18n:I18n Key=Board_Highlighter}" Margin="2,1,0,0" />
Text="{i18n:I18n Key=Board_Highlighter}" Margin="2,1,0,0"
Width="35"
Style="{StaticResource AutoFitPenTabLabel9}" />
</ui:SimpleStackPanel>
</ui:SimpleStackPanel>
</Canvas>
@@ -8524,7 +8537,9 @@
Foreground="White"
FontWeight="Medium"
FontSize="9" TextAlignment="Center"
Text="{i18n:I18n Key=Board_Highlighter}" Margin="2,1,0,0" />
Text="{i18n:I18n Key=Board_Highlighter}" Margin="2,1,0,0"
Width="35"
Style="{StaticResource AutoFitPenTabLabel9}" />
</ui:SimpleStackPanel>
</ui:SimpleStackPanel>
</Canvas>
@@ -10144,14 +10159,14 @@
MouseUp="CloseBordertools_MouseUp" />
</Canvas>
</Border>
<ui:SimpleStackPanel Orientation="Horizontal" Spacing="4" VerticalAlignment="Center"
<ui:SimpleStackPanel Orientation="Horizontal" Spacing="2" VerticalAlignment="Center"
HorizontalAlignment="Center" Margin="0,3,0,0">
<Image Source="{DynamicResource MultiTouchIcon}"
RenderOptions.BitmapScalingMode="HighQuality" Height="16" Width="16" />
<Label Content="{i18n:I18n Key=FloatingBar_Gesture_MultiTouchWriting}" FontSize="8"
VerticalAlignment="Center" Width="64"
VerticalAlignment="Center" Width="56"
Style="{StaticResource AutoFitGestureOptionLabel10}" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
<Viewbox Width="36" Height="18" Margin="2,0,0,0">
<ui:ToggleSwitch MinWidth="0" Margin="0,-6,0,-6"
Name="ToggleSwitchEnableMultiTouchMode"
FontFamily="Microsoft YaHei UI" IsOn="False" OnContent=""
@@ -10170,14 +10185,14 @@
</Viewbox>
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Opacity="1" x:Name="TwoFingerGestureSimpleStackPanel"
Orientation="Horizontal" Spacing="4" VerticalAlignment="Center"
Orientation="Horizontal" Spacing="2" VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="{DynamicResource HandMoveIcon}"
RenderOptions.BitmapScalingMode="HighQuality" Height="16" Width="16" />
<Label Content="{i18n:I18n Key=FloatingBar_Gesture_TwoFingerMove}" FontSize="8"
VerticalAlignment="Center" Width="64"
VerticalAlignment="Center" Width="56"
Style="{StaticResource AutoFitGestureOptionLabel10}" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
<Viewbox Width="36" Height="18" Margin="2,0,0,0">
<ui:ToggleSwitch MinWidth="0" Margin="0,-6,0,-6"
Name="ToggleSwitchEnableTwoFingerTranslate"
FontFamily="Microsoft YaHei UI" IsOn="False" OnContent=""
@@ -10197,14 +10212,14 @@
</ui:SimpleStackPanel>
<ui:SimpleStackPanel
Opacity="{Binding ElementName=TwoFingerGestureSimpleStackPanel, Path=Opacity}"
Orientation="Horizontal" Spacing="4" VerticalAlignment="Center"
Orientation="Horizontal" Spacing="2" VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="{DynamicResource ZoomIcon}"
RenderOptions.BitmapScalingMode="HighQuality" Height="16" Width="16" />
<Label Content="{i18n:I18n Key=FloatingBar_Gesture_TwoFingerZoom}" FontSize="8"
VerticalAlignment="Center" Width="64"
VerticalAlignment="Center" Width="56"
Style="{StaticResource AutoFitGestureOptionLabel10}" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
<Viewbox Width="36" Height="18" Margin="2,0,0,0">
<ui:ToggleSwitch MinWidth="0" Margin="0,-6,0,-6"
FontFamily="Microsoft YaHei UI"
IsOn="False" OnContent="" OffContent=""
@@ -10224,14 +10239,14 @@
</ui:SimpleStackPanel>
<ui:SimpleStackPanel
Opacity="{Binding ElementName=TwoFingerGestureSimpleStackPanel, Path=Opacity}"
Orientation="Horizontal" Spacing="4" VerticalAlignment="Center"
Orientation="Horizontal" Spacing="2" VerticalAlignment="Center"
HorizontalAlignment="Center">
<Image Source="{DynamicResource RotateIcon}"
RenderOptions.BitmapScalingMode="HighQuality" Height="16" Width="16" />
<Label Content="{i18n:I18n Key=FloatingBar_Gesture_TwoFingerRotate}" FontSize="8"
VerticalAlignment="Center" Width="64"
VerticalAlignment="Center" Width="56"
Style="{StaticResource AutoFitGestureOptionLabel10}" />
<Viewbox Width="36" Height="18" Margin="4,0,0,0">
<Viewbox Width="36" Height="18" Margin="2,0,0,0">
<ui:ToggleSwitch MinWidth="0" Margin="0,-6,0,-6"
FontFamily="Microsoft YaHei UI"
IsOn="False" OnContent="" OffContent=""