fix:调色盘导致的按钮高光显示错位

This commit is contained in:
2025-08-13 11:54:36 +08:00
parent a4d3d3ff9c
commit 5c0ca841d7
4 changed files with 298 additions and 21 deletions
+7
View File
@@ -629,6 +629,13 @@
IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchNoFocusMode_Toggled" />
</ui:SimpleStackPanel>
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="窗口置顶" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchAlwaysOnTop"
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchAlwaysOnTop_Toggled" />
</ui:SimpleStackPanel>
<ui:ToggleSwitch OnContent="" OffContent=""
Name="ToggleSwitchIsAutoUpdate" Header="自动检查更新"
FontFamily="Microsoft YaHei UI"
+57
View File
@@ -222,6 +222,9 @@ namespace Ink_Canvas
// 初始化无焦点模式开关
ToggleSwitchNoFocusMode.IsOn = Settings.Advanced.IsNoFocusMode;
ApplyNoFocusMode();
// 初始化窗口置顶开关
ToggleSwitchAlwaysOnTop.IsOn = Settings.Advanced.IsAlwaysOnTop;
ApplyAlwaysOnTop();
}
@@ -480,6 +483,8 @@ namespace Ink_Canvas
// 确保开关和设置同步
ToggleSwitchNoFocusMode.IsOn = Settings.Advanced.IsNoFocusMode;
ApplyNoFocusMode();
ToggleSwitchAlwaysOnTop.IsOn = Settings.Advanced.IsAlwaysOnTop;
ApplyAlwaysOnTop();
// 初始化UIElement选择系统
InitializeUIElementSelection();
@@ -1623,8 +1628,15 @@ namespace Ink_Canvas
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
private const int GWL_EXSTYLE = -20;
private const int WS_EX_NOACTIVATE = 0x08000000;
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
private const uint SWP_NOMOVE = 0x0002;
private const uint SWP_NOSIZE = 0x0001;
private const uint SWP_NOACTIVATE = 0x0010;
private void ApplyNoFocusMode()
{
@@ -1640,6 +1652,42 @@ namespace Ink_Canvas
}
}
private void ApplyAlwaysOnTop()
{
var hwnd = new WindowInteropHelper(this).Handle;
if (Settings.Advanced.IsAlwaysOnTop)
{
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
else
{
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
}
/// <summary>
/// 根据窗口置顶设置和当前模式设置窗口的Topmost属性
/// </summary>
/// <param name="shouldBeTopmost">当前模式是否需要窗口置顶</param>
public void SetTopmostBasedOnSettings(bool shouldBeTopmost)
{
if (Settings.Advanced.IsAlwaysOnTop)
{
// 如果启用了窗口置顶设置,则始终置顶
Topmost = true;
ApplyAlwaysOnTop();
}
else
{
// 如果未启用窗口置顶设置,则根据当前模式决定
Topmost = shouldBeTopmost;
if (!shouldBeTopmost)
{
ApplyAlwaysOnTop(); // 确保取消置顶
}
}
}
private void ToggleSwitchNoFocusMode_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
@@ -1649,6 +1697,15 @@ namespace Ink_Canvas
ApplyNoFocusMode();
}
private void ToggleSwitchAlwaysOnTop_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
var toggle = sender as ToggleSwitch;
Settings.Advanced.IsAlwaysOnTop = toggle != null && toggle.IsOn;
SaveSettingsToFile();
ApplyAlwaysOnTop();
}
#region Image Toolbar Event Handlers
private void BorderImageClone_MouseUp(object sender, MouseButtonEventArgs e)
+231 -21
View File
@@ -383,8 +383,7 @@ namespace Ink_Canvas
BoardEraser.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
BoardPen.BorderBrush = new SolidColorBrush(Color.FromRgb(161, 161, 170));
FloatingbarSelectionBG.Visibility = Visibility.Hidden;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 0);
HideFloatingBarHighlight();
}
switch (mode)
@@ -399,8 +398,7 @@ namespace Ink_Canvas
BoardPenGeometry.Brush = new SolidColorBrush(Colors.GhostWhite);
BoardPenLabel.Foreground = new SolidColorBrush(Colors.GhostWhite);
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 28);
SetFloatingBarHighlightPosition("pen");
break;
}
case "eraser":
@@ -413,8 +411,7 @@ namespace Ink_Canvas
BoardEraserGeometry.Brush = new SolidColorBrush(Colors.GhostWhite);
BoardEraserLabel.Foreground = new SolidColorBrush(Colors.GhostWhite);
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 28 * 3);
SetFloatingBarHighlightPosition("eraser");
break;
}
case "eraserByStrokes":
@@ -427,8 +424,7 @@ namespace Ink_Canvas
BoardEraserGeometry.Brush = new SolidColorBrush(Colors.GhostWhite);
BoardEraserLabel.Foreground = new SolidColorBrush(Colors.GhostWhite);
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 28 * 4);
SetFloatingBarHighlightPosition("eraserByStrokes");
break;
}
case "select":
@@ -441,8 +437,7 @@ namespace Ink_Canvas
BoardSelectGeometry.Brush = new SolidColorBrush(Colors.GhostWhite);
BoardSelectLabel.Foreground = new SolidColorBrush(Colors.GhostWhite);
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 28 * 5);
SetFloatingBarHighlightPosition("select");
break;
}
case "cursor":
@@ -455,8 +450,7 @@ namespace Ink_Canvas
BoardPenGeometry.Brush = new SolidColorBrush(Color.FromRgb(24, 24, 27));
BoardPenLabel.Foreground = new SolidColorBrush(Color.FromRgb(24, 24, 27));
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 0);
SetFloatingBarHighlightPosition("cursor");
break;
}
case "shape":
@@ -775,8 +769,6 @@ namespace Ink_Canvas
((Panel)lastBorderMouseDownObject).Background = new SolidColorBrush(Colors.Transparent);
if (sender == SymbolIconSelect && lastBorderMouseDownObject != SymbolIconSelect) return;
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 140);
BtnSelect_Click(null, null);
HideSubPanels("select");
}
@@ -1537,8 +1529,7 @@ namespace Ink_Canvas
DisableAdvancedEraserSystem();
// 隱藏高亮
FloatingbarSelectionBG.Visibility = Visibility.Hidden;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 0);
HideFloatingBarHighlight();
// 切换前自动截图保存墨迹
if (inkCanvas.Strokes.Count > 0 &&
@@ -1648,8 +1639,7 @@ namespace Ink_Canvas
// 这解决了从橡皮擦切换为批注时被锁定为多指书写的问题
ExitMultiTouchModeIfNeeded();
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 28);
SetFloatingBarHighlightPosition("pen");
// 记录当前是否已经是批注模式且是否为高光显示模式
bool wasInInkMode = inkCanvas.EditingMode == InkCanvasEditingMode.Ink;
@@ -1898,9 +1888,6 @@ namespace Ink_Canvas
((Panel)lastBorderMouseDownObject).Background = new SolidColorBrush(Colors.Transparent);
if (sender == EraserByStrokes_Icon && lastBorderMouseDownObject != EraserByStrokes_Icon) return;
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 112);
// 禁用高级橡皮擦系统
DisableAdvancedEraserSystem();
@@ -2710,5 +2697,228 @@ namespace Ink_Canvas
}
}
#region
/// <summary>
/// 获取浮动栏中指定按钮的位置
/// </summary>
/// <param name="buttonName">按钮的名称</param>
/// <returns>按钮在浮动栏中的相对位置</returns>
private double GetFloatingBarButtonPosition(string buttonName)
{
try
{
// 获取浮动栏容器
var floatingBarPanel = StackPanelFloatingBar;
if (floatingBarPanel == null) return 0;
double currentPosition = 0;
// 遍历浮动栏中的所有子元素
foreach (var child in floatingBarPanel.Children)
{
if (child is UIElement element)
{
// 检查是否是我们要找的按钮
if (IsTargetButton(element, buttonName))
{
return currentPosition;
}
// 累加当前元素的位置
currentPosition += GetElementWidth(element);
}
}
return 0;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"获取按钮位置失败: {ex.Message}", LogHelper.LogType.Error);
return 0;
}
}
/// <summary>
/// 检查元素是否是目标按钮
/// </summary>
private bool IsTargetButton(UIElement element, string buttonName)
{
if (element is FrameworkElement fe)
{
return fe.Name == buttonName;
}
return false;
}
/// <summary>
/// 获取元素的宽度
/// </summary>
private double GetElementWidth(UIElement element)
{
if (element is FrameworkElement fe)
{
// 对于SimpleStackPanel,使用其实际宽度
if (fe.GetType().Name == "SimpleStackPanel")
{
return fe.ActualWidth > 0 ? fe.ActualWidth : 28; // 默认宽度28
}
// 对于其他元素,使用其宽度或默认宽度
return fe.ActualWidth > 0 ? fe.ActualWidth : 28;
}
return 28; // 默认宽度
}
/// <summary>
/// 设置浮动栏高光显示位置
/// </summary>
/// <param name="mode">模式名称</param>
private void SetFloatingBarHighlightPosition(string mode)
{
try
{
if (FloatingbarSelectionBG == null) return;
double position = 0;
double buttonWidth = 28; // 每个按钮的默认宽度
double highlightWidth = 28; // 高光的默认宽度
// 检查快捷调色盘是否显示及其实际宽度
bool isQuickColorPaletteVisible = false;
double quickColorPaletteWidth = 0;
string quickColorPaletteMode = "none";
if (QuickColorPalettePanel != null && QuickColorPalettePanel.Visibility == Visibility.Visible)
{
isQuickColorPaletteVisible = true;
quickColorPaletteWidth = QuickColorPalettePanel.ActualWidth > 0 ? QuickColorPalettePanel.ActualWidth : 60;
quickColorPaletteMode = "double";
}
else if (QuickColorPaletteSingleRowPanel != null && QuickColorPaletteSingleRowPanel.Visibility == Visibility.Visible)
{
isQuickColorPaletteVisible = true;
quickColorPaletteWidth = QuickColorPaletteSingleRowPanel.ActualWidth > 0 ? QuickColorPaletteSingleRowPanel.ActualWidth : 120;
quickColorPaletteMode = "single";
}
// 获取实际按钮宽度,如果获取不到则使用默认值
double cursorWidth = Cursor_Icon?.ActualWidth > 0 ? Cursor_Icon.ActualWidth : buttonWidth;
double penWidth = Pen_Icon?.ActualWidth > 0 ? Pen_Icon.ActualWidth : buttonWidth;
double deleteWidth = SymbolIconDelete?.ActualWidth > 0 ? SymbolIconDelete.ActualWidth : buttonWidth;
double eraserWidth = Eraser_Icon?.ActualWidth > 0 ? Eraser_Icon.ActualWidth : buttonWidth;
double eraserByStrokesWidth = EraserByStrokes_Icon?.ActualWidth > 0 ? EraserByStrokes_Icon.ActualWidth : buttonWidth;
double selectWidth = SymbolIconSelect?.ActualWidth > 0 ? SymbolIconSelect.ActualWidth : buttonWidth;
// 获取高光的实际宽度
double actualHighlightWidth = FloatingbarSelectionBG.ActualWidth > 0 ? FloatingbarSelectionBG.ActualWidth : highlightWidth;
// 计算位置偏移,考虑Canvas和StackPanel的Margin差异
// Canvas: Margin="2,0,2,0", StackPanel: Margin="2,0"
// 所以Canvas相对于StackPanel的偏移是:Canvas.Left(2) - StackPanel.Left(2) = 0
// 但是高光元素本身有Margin="0,-2,0,-2",需要补偿这个偏移
double marginOffset = 0; // Canvas和StackPanel的Margin已经对齐
// 快捷调色盘的MarginMargin="4,0,4,0",所以总宽度需要加上8像素
double quickColorPaletteTotalWidth = isQuickColorPaletteVisible ? quickColorPaletteWidth + 8 : 0;
// 根据模式计算位置,确保高光居中对齐按钮
switch (mode)
{
case "cursor":
// 鼠标按钮位置:marginOffset + (cursorWidth - actualHighlightWidth) / 2
position = marginOffset + (cursorWidth - actualHighlightWidth) / 2;
break;
case "pen":
case "color":
// 批注按钮位置:marginOffset + cursorWidth + (penWidth - actualHighlightWidth) / 2
position = marginOffset + cursorWidth + (penWidth - actualHighlightWidth) / 2;
break;
case "eraser":
if (isQuickColorPaletteVisible)
{
// 有快捷调色盘时:鼠标 + 批注 + 快捷调色盘(包含Margin) + 清空 + (面积擦 - 高光) / 2
position = marginOffset + cursorWidth + penWidth + quickColorPaletteTotalWidth + deleteWidth + (eraserWidth - actualHighlightWidth) / 2;
}
else
{
// 没有快捷调色盘时:鼠标 + 批注 + 清空 + (面积擦 - 高光) / 2
position = marginOffset + cursorWidth + penWidth + deleteWidth + (eraserWidth - actualHighlightWidth) / 2;
}
break;
case "eraserByStrokes":
if (isQuickColorPaletteVisible)
{
// 有快捷调色盘时:鼠标 + 批注 + 快捷调色盘(包含Margin) + 清空 + 面积擦 + (线擦 - 高光) / 2
position = marginOffset + cursorWidth + penWidth + quickColorPaletteTotalWidth + deleteWidth + eraserWidth + (eraserByStrokesWidth - actualHighlightWidth) / 2;
}
else
{
// 没有快捷调色盘时:鼠标 + 批注 + 清空 + 面积擦 + (线擦 - 高光) / 2
position = marginOffset + cursorWidth + penWidth + deleteWidth + eraserWidth + (eraserByStrokesWidth - actualHighlightWidth) / 2;
}
break;
case "select":
if (isQuickColorPaletteVisible)
{
// 有快捷调色盘时:鼠标 + 批注 + 快捷调色盘(包含Margin) + 清空 + 面积擦 + 线擦 + (套索选 - 高光) / 2
position = marginOffset + cursorWidth + penWidth + quickColorPaletteTotalWidth + deleteWidth + eraserWidth + eraserByStrokesWidth + (selectWidth - actualHighlightWidth) / 2;
}
else
{
// 没有快捷调色盘时:鼠标 + 批注 + 清空 + 面积擦 + 线擦 + (套索选 - 高光) / 2
position = marginOffset + cursorWidth + penWidth + deleteWidth + eraserWidth + eraserByStrokesWidth + (selectWidth - actualHighlightWidth) / 2;
}
break;
case "shape":
if (isQuickColorPaletteVisible)
{
// 有快捷调色盘时:鼠标 + 批注 + 快捷调色盘(包含Margin) + 清空 + 面积擦 + 线擦 + 套索选 + (几何 - 高光) / 2
position = marginOffset + cursorWidth + penWidth + quickColorPaletteTotalWidth + deleteWidth + eraserWidth + eraserByStrokesWidth + selectWidth + (buttonWidth - actualHighlightWidth) / 2;
}
else
{
// 没有快捷调色盘时:鼠标 + 批注 + 清空 + 面积擦 + 线擦 + 套索选 + (几何 - 高光) / 2
position = marginOffset + cursorWidth + penWidth + deleteWidth + eraserWidth + eraserByStrokesWidth + selectWidth + (buttonWidth - actualHighlightWidth) / 2;
}
break;
default:
position = marginOffset;
break;
}
// 设置高光位置
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, position);
// 详细的调试信息
string debugInfo = $"设置高光位置: {mode} -> {position:F2}, " +
$"高光宽度: {actualHighlightWidth:F2}, " +
$"快捷调色盘: {quickColorPaletteMode}, 宽度: {quickColorPaletteWidth:F2}, 总宽度: {quickColorPaletteTotalWidth:F2}, " +
$"按钮宽度: cursor={cursorWidth:F2}, pen={penWidth:F2}, delete={deleteWidth:F2}, " +
$"eraser={eraserWidth:F2}, eraserByStrokes={eraserByStrokesWidth:F2}, select={selectWidth:F2}";
LogHelper.WriteLogToFile(debugInfo, LogHelper.LogType.Trace);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"设置高光位置失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 隐藏浮动栏高光显示
/// </summary>
private void HideFloatingBarHighlight()
{
if (FloatingbarSelectionBG != null)
{
FloatingbarSelectionBG.Visibility = Visibility.Hidden;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, 0);
}
}
#endregion
}
}
+3
View File
@@ -481,6 +481,9 @@ namespace Ink_Canvas
[JsonProperty("isNoFocusMode")]
public bool IsNoFocusMode { get; set; } = true;
[JsonProperty("isAlwaysOnTop")]
public bool IsAlwaysOnTop { get; set; } = true;
}
public class InkToShape