add:放大镜
This commit is contained in:
@@ -2,23 +2,23 @@ using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace Ink_Canvas.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// 可拖动、可调整大小的屏幕放大镜窗口。
|
||||
/// 底层使用 Win32 Magnification API (Magnification.dll) 将窗口当前所在区域下方的屏幕内容放大显示。
|
||||
/// 使用 Win32 Magnification API (Magnification.dll)。
|
||||
/// </summary>
|
||||
internal class MagnifierWindow : Window
|
||||
{
|
||||
#region P/Invoke
|
||||
|
||||
private const string MagnifierClassName = "Magnifier";
|
||||
|
||||
private const int WS_CHILD = 0x40000000;
|
||||
private const int WS_VISIBLE = 0x10000000;
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Ink_Canvas.Windows
|
||||
int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam);
|
||||
|
||||
[DllImport("user32.dll")] private static extern bool DestroyWindow(IntPtr hWnd);
|
||||
[DllImport("user32.dll")] private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
|
||||
[DllImport("user32.dll")] private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
|
||||
[DllImport("user32.dll")] private static extern bool InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase);
|
||||
|
||||
[DllImport("Magnification.dll")] private static extern bool MagInitialize();
|
||||
@@ -50,8 +50,45 @@ namespace Ink_Canvas.Windows
|
||||
|
||||
#endregion
|
||||
|
||||
#region 单例
|
||||
|
||||
private static MagnifierWindow _instance;
|
||||
public static bool HasInstance => _instance != null;
|
||||
public static event EventHandler Closed2;
|
||||
|
||||
public static void Show(float zoom)
|
||||
{
|
||||
if (_instance != null) { _instance.Activate(); _instance.Zoom = zoom; return; }
|
||||
_instance = new MagnifierWindow { Zoom = zoom };
|
||||
_instance.Closed += (s, e) =>
|
||||
{
|
||||
_instance = null;
|
||||
Closed2?.Invoke(null, EventArgs.Empty);
|
||||
};
|
||||
_instance.Show();
|
||||
}
|
||||
|
||||
public static void HideInstance() => _instance?.Close();
|
||||
public static void SetZoom(float zoom) { if (_instance != null) _instance.Zoom = zoom; }
|
||||
|
||||
#endregion
|
||||
|
||||
// 选择框(放大区域)在 Canvas 中的几何属性 (DIP)
|
||||
private double _boxLeft = 200;
|
||||
private double _boxTop = 150;
|
||||
private double _boxWidth = 520;
|
||||
private double _boxHeight = 360;
|
||||
private const double MinBoxW = 200;
|
||||
private const double MinBoxH = 140;
|
||||
|
||||
private System.Windows.Controls.Canvas _canvas;
|
||||
private Rectangle _overlay; // 半透明遮罩
|
||||
private Border _selectionBorder; // 白色边框选择框
|
||||
private MagnifierHost _magHost;
|
||||
private System.Windows.Controls.Border _toolbar;
|
||||
private Ellipse[] _handles; // 8 个控点
|
||||
private ToggleButton _blackoutButton;
|
||||
private bool _blackoutOn;
|
||||
|
||||
private IntPtr _magHwnd;
|
||||
private HwndSource _hwndSource;
|
||||
@@ -69,116 +106,334 @@ namespace Ink_Canvas.Windows
|
||||
}
|
||||
}
|
||||
|
||||
public static void Show(float zoom)
|
||||
{
|
||||
if (_instance != null)
|
||||
{
|
||||
_instance.Activate();
|
||||
_instance.Zoom = zoom;
|
||||
return;
|
||||
}
|
||||
_instance = new MagnifierWindow { Zoom = zoom };
|
||||
_instance.Closed += (s, e) => _instance = null;
|
||||
_instance.Show();
|
||||
}
|
||||
|
||||
public static void HideInstance()
|
||||
{
|
||||
_instance?.Close();
|
||||
}
|
||||
|
||||
public static void SetZoom(float zoom)
|
||||
{
|
||||
if (_instance != null) _instance.Zoom = zoom;
|
||||
}
|
||||
|
||||
private MagnifierWindow()
|
||||
{
|
||||
Title = "聚焦放大镜";
|
||||
Width = 420;
|
||||
Height = 280;
|
||||
MinWidth = 160;
|
||||
MinHeight = 120;
|
||||
WindowStyle = WindowStyle.None;
|
||||
ResizeMode = ResizeMode.CanResizeWithGrip;
|
||||
ResizeMode = ResizeMode.NoResize;
|
||||
AllowsTransparency = true;
|
||||
Background = Brushes.Transparent;
|
||||
Topmost = true;
|
||||
ShowInTaskbar = false;
|
||||
AllowsTransparency = false;
|
||||
Background = new SolidColorBrush(Color.FromRgb(31, 31, 31));
|
||||
WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
||||
WindowState = WindowState.Maximized;
|
||||
|
||||
BuildChrome();
|
||||
}
|
||||
_canvas = new System.Windows.Controls.Canvas { Background = Brushes.Transparent };
|
||||
|
||||
private void BuildChrome()
|
||||
{
|
||||
var root = new DockPanel { LastChildFill = true };
|
||||
|
||||
// 标题栏
|
||||
var titleBar = new Border
|
||||
// 半透明遮罩:固定浅色,挖空选择框
|
||||
_overlay = new Rectangle
|
||||
{
|
||||
Height = 28,
|
||||
Background = new SolidColorBrush(Color.FromArgb(0xEE, 0x2A, 0x2A, 0x2A)),
|
||||
Cursor = Cursors.SizeAll
|
||||
Fill = new SolidColorBrush(Color.FromArgb(102, 0, 0, 0)),
|
||||
IsHitTestVisible = false
|
||||
};
|
||||
DockPanel.SetDock(titleBar, Dock.Top);
|
||||
titleBar.MouseLeftButtonDown += (s, e) => { if (e.ButtonState == MouseButtonState.Pressed) DragMove(); };
|
||||
_canvas.Children.Add(_overlay);
|
||||
|
||||
var titleGrid = new Grid();
|
||||
titleGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
|
||||
titleGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
|
||||
|
||||
var titleText = new TextBlock
|
||||
// 选择框
|
||||
_selectionBorder = new Border
|
||||
{
|
||||
Text = "聚焦放大镜",
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Margin = new Thickness(10, 0, 0, 0),
|
||||
Foreground = Brushes.White,
|
||||
FontSize = 12
|
||||
BorderBrush = Brushes.White,
|
||||
BorderThickness = new Thickness(1.5),
|
||||
Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)), // 几乎透明,可命中
|
||||
Cursor = Cursors.SizeAll,
|
||||
SnapsToDevicePixels = true
|
||||
};
|
||||
Grid.SetColumn(titleText, 0);
|
||||
titleGrid.Children.Add(titleText);
|
||||
|
||||
var closeBtn = new Button
|
||||
{
|
||||
Content = "✕",
|
||||
Width = 40,
|
||||
Height = 28,
|
||||
Foreground = Brushes.White,
|
||||
Background = Brushes.Transparent,
|
||||
BorderThickness = new Thickness(0),
|
||||
FontSize = 12,
|
||||
Cursor = Cursors.Arrow
|
||||
};
|
||||
closeBtn.Click += (s, e) => Close();
|
||||
Grid.SetColumn(closeBtn, 1);
|
||||
titleGrid.Children.Add(closeBtn);
|
||||
|
||||
titleBar.Child = titleGrid;
|
||||
root.Children.Add(titleBar);
|
||||
|
||||
// 放大镜承载区(由 Win32 子窗口填充)
|
||||
_selectionBorder.MouseLeftButtonDown += SelectionBorder_MouseDown;
|
||||
_selectionBorder.MouseMove += SelectionBorder_MouseMove;
|
||||
_selectionBorder.MouseLeftButtonUp += SelectionBorder_MouseUp;
|
||||
_magHost = new MagnifierHost(this);
|
||||
root.Children.Add(_magHost);
|
||||
_selectionBorder.Child = _magHost;
|
||||
_canvas.Children.Add(_selectionBorder);
|
||||
|
||||
Content = root;
|
||||
// 8 个控点
|
||||
_handles = new Ellipse[8];
|
||||
string[] tags = { "NW", "N", "NE", "E", "SE", "S", "SW", "W" };
|
||||
Cursor[] cursors = { Cursors.SizeNWSE, Cursors.SizeNS, Cursors.SizeNESW, Cursors.SizeWE,
|
||||
Cursors.SizeNWSE, Cursors.SizeNS, Cursors.SizeNESW, Cursors.SizeWE };
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
var h = new Ellipse
|
||||
{
|
||||
Width = 12,
|
||||
Height = 12,
|
||||
Fill = Brushes.White,
|
||||
Stroke = new SolidColorBrush(Color.FromArgb(220, 0, 0, 0)),
|
||||
StrokeThickness = 1,
|
||||
Cursor = cursors[i],
|
||||
Tag = tags[i]
|
||||
};
|
||||
h.MouseLeftButtonDown += Handle_MouseDown;
|
||||
h.MouseMove += Handle_MouseMove;
|
||||
h.MouseLeftButtonUp += Handle_MouseUp;
|
||||
_handles[i] = h;
|
||||
_canvas.Children.Add(h);
|
||||
}
|
||||
|
||||
_toolbar = BuildToolbar();
|
||||
_canvas.Children.Add(_toolbar);
|
||||
|
||||
Content = _canvas;
|
||||
|
||||
Loaded += (s, e) =>
|
||||
{
|
||||
LayoutAll();
|
||||
};
|
||||
SizeChanged += (s, e) => LayoutAll();
|
||||
KeyDown += (s, e) => { if (e.Key == Key.Escape) Close(); };
|
||||
}
|
||||
|
||||
private MagnifierHost _magHost;
|
||||
private System.Windows.Controls.Border BuildToolbar()
|
||||
{
|
||||
var bar = new System.Windows.Controls.Border
|
||||
{
|
||||
Background = new SolidColorBrush(Color.FromArgb(245, 26, 26, 26)),
|
||||
CornerRadius = new CornerRadius(8),
|
||||
Padding = new Thickness(8, 4, 8, 4),
|
||||
SnapsToDevicePixels = true
|
||||
};
|
||||
var sp = new StackPanel { Orientation = Orientation.Horizontal };
|
||||
|
||||
_blackoutButton = new ToggleButton { Content = MakeBtnContent("💡", "关灯") };
|
||||
StyleToolButton(_blackoutButton);
|
||||
_blackoutButton.Checked += (s, e) => SetBlackout(true);
|
||||
_blackoutButton.Unchecked += (s, e) => SetBlackout(false);
|
||||
|
||||
var closeBtn = new System.Windows.Controls.Button { Content = MakeBtnContent("✕", "关闭") };
|
||||
StyleToolButton(closeBtn);
|
||||
closeBtn.Click += (s, e) => Close();
|
||||
|
||||
sp.Children.Add(_blackoutButton);
|
||||
sp.Children.Add(closeBtn);
|
||||
bar.Child = sp;
|
||||
return bar;
|
||||
}
|
||||
|
||||
private static FrameworkElement MakeBtnContent(string icon, string text)
|
||||
{
|
||||
var sp = new StackPanel { Orientation = Orientation.Vertical, HorizontalAlignment = HorizontalAlignment.Center };
|
||||
sp.Children.Add(new TextBlock { Text = icon, FontSize = 16, Foreground = Brushes.White, HorizontalAlignment = HorizontalAlignment.Center });
|
||||
sp.Children.Add(new TextBlock { Text = text, FontSize = 11, Foreground = Brushes.White, HorizontalAlignment = HorizontalAlignment.Center, Margin = new Thickness(0, 1, 0, 0) });
|
||||
return sp;
|
||||
}
|
||||
|
||||
private static void StyleToolButton(ButtonBase b)
|
||||
{
|
||||
b.Width = 56;
|
||||
b.Height = 46;
|
||||
b.Margin = new Thickness(3, 0, 3, 0);
|
||||
b.Background = Brushes.Transparent;
|
||||
b.BorderThickness = new Thickness(0);
|
||||
b.Foreground = Brushes.White;
|
||||
b.Cursor = Cursors.Hand;
|
||||
b.Padding = new Thickness(0);
|
||||
b.Template = BuildToolButtonTemplate();
|
||||
}
|
||||
|
||||
private static ControlTemplate BuildToolButtonTemplate()
|
||||
{
|
||||
var t = new ControlTemplate(typeof(ButtonBase));
|
||||
var border = new FrameworkElementFactory(typeof(System.Windows.Controls.Border));
|
||||
border.Name = "Bd";
|
||||
border.SetValue(System.Windows.Controls.Border.BackgroundProperty, new TemplateBindingExtension(System.Windows.Controls.Control.BackgroundProperty));
|
||||
border.SetValue(System.Windows.Controls.Border.CornerRadiusProperty, new CornerRadius(6));
|
||||
var cp = new FrameworkElementFactory(typeof(ContentPresenter));
|
||||
cp.SetValue(ContentPresenter.HorizontalAlignmentProperty, HorizontalAlignment.Center);
|
||||
cp.SetValue(ContentPresenter.VerticalAlignmentProperty, VerticalAlignment.Center);
|
||||
border.AppendChild(cp);
|
||||
t.VisualTree = border;
|
||||
|
||||
var hover = new Trigger { Property = UIElement.IsMouseOverProperty, Value = true };
|
||||
hover.Setters.Add(new Setter(System.Windows.Controls.Border.BackgroundProperty, new SolidColorBrush(Color.FromArgb(60, 255, 255, 255)), "Bd"));
|
||||
t.Triggers.Add(hover);
|
||||
|
||||
var checkedT = new Trigger { Property = ToggleButton.IsCheckedProperty, Value = true };
|
||||
checkedT.Setters.Add(new Setter(System.Windows.Controls.Border.BackgroundProperty, new SolidColorBrush(Color.FromRgb(0x05, 0x96, 0x69)), "Bd"));
|
||||
t.Triggers.Add(checkedT);
|
||||
return t;
|
||||
}
|
||||
|
||||
#region 布局
|
||||
|
||||
private void LayoutAll()
|
||||
{
|
||||
double w = _canvas.ActualWidth;
|
||||
double h = _canvas.ActualHeight;
|
||||
if (w <= 0 || h <= 0) return;
|
||||
|
||||
// 首次居中
|
||||
if (_boxLeft + _boxWidth > w) _boxLeft = Math.Max(0, w - _boxWidth);
|
||||
if (_boxTop + _boxHeight > h) _boxTop = Math.Max(0, h - _boxHeight);
|
||||
|
||||
// 遮罩占满
|
||||
_overlay.Width = w;
|
||||
_overlay.Height = h;
|
||||
System.Windows.Controls.Canvas.SetLeft(_overlay, 0);
|
||||
System.Windows.Controls.Canvas.SetTop(_overlay, 0);
|
||||
UpdateOverlayClip();
|
||||
|
||||
// 选择框
|
||||
_selectionBorder.Width = _boxWidth;
|
||||
_selectionBorder.Height = _boxHeight;
|
||||
System.Windows.Controls.Canvas.SetLeft(_selectionBorder, _boxLeft);
|
||||
System.Windows.Controls.Canvas.SetTop(_selectionBorder, _boxTop);
|
||||
|
||||
// 8 个控点(中心定位)
|
||||
PositionHandle(0, _boxLeft, _boxTop); // NW
|
||||
PositionHandle(1, _boxLeft + _boxWidth / 2, _boxTop); // N
|
||||
PositionHandle(2, _boxLeft + _boxWidth, _boxTop); // NE
|
||||
PositionHandle(3, _boxLeft + _boxWidth, _boxTop + _boxHeight / 2); // E
|
||||
PositionHandle(4, _boxLeft + _boxWidth, _boxTop + _boxHeight); // SE
|
||||
PositionHandle(5, _boxLeft + _boxWidth / 2, _boxTop + _boxHeight); // S
|
||||
PositionHandle(6, _boxLeft, _boxTop + _boxHeight); // SW
|
||||
PositionHandle(7, _boxLeft, _boxTop + _boxHeight / 2); // W
|
||||
|
||||
// 工具栏:选择框正下方居中;若超出则放上方
|
||||
_toolbar.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
double tw = _toolbar.DesiredSize.Width, th = _toolbar.DesiredSize.Height;
|
||||
double tx = _boxLeft + _boxWidth / 2 - tw / 2;
|
||||
double ty = _boxTop + _boxHeight + 12;
|
||||
if (ty + th > h) ty = _boxTop - th - 12;
|
||||
tx = Math.Max(8, Math.Min(w - tw - 8, tx));
|
||||
System.Windows.Controls.Canvas.SetLeft(_toolbar, tx);
|
||||
System.Windows.Controls.Canvas.SetTop(_toolbar, ty);
|
||||
}
|
||||
|
||||
private void PositionHandle(int i, double cx, double cy)
|
||||
{
|
||||
var dot = _handles[i];
|
||||
System.Windows.Controls.Canvas.SetLeft(dot, cx - dot.Width / 2);
|
||||
System.Windows.Controls.Canvas.SetTop(dot, cy - dot.Height / 2);
|
||||
}
|
||||
|
||||
private void UpdateOverlayClip()
|
||||
{
|
||||
// 用 EvenOdd Geometry 在 overlay 上挖空选择框区域
|
||||
double w = _canvas.ActualWidth;
|
||||
double h = _canvas.ActualHeight;
|
||||
if (w <= 0 || h <= 0) { _overlay.Clip = null; return; }
|
||||
|
||||
var outer = new RectangleGeometry(new Rect(0, 0, w, h));
|
||||
var inner = new RectangleGeometry(new Rect(_boxLeft, _boxTop, _boxWidth, _boxHeight));
|
||||
var combined = new CombinedGeometry(GeometryCombineMode.Exclude, outer, inner);
|
||||
_overlay.Clip = combined;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 拖动
|
||||
|
||||
private bool _draggingBox;
|
||||
private Point _dragStart;
|
||||
private double _dragBoxLeft, _dragBoxTop;
|
||||
|
||||
private void SelectionBorder_MouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
_draggingBox = true;
|
||||
_dragStart = e.GetPosition(_canvas);
|
||||
_dragBoxLeft = _boxLeft;
|
||||
_dragBoxTop = _boxTop;
|
||||
_selectionBorder.CaptureMouse();
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void SelectionBorder_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (!_draggingBox) return;
|
||||
var p = e.GetPosition(_canvas);
|
||||
_boxLeft = Math.Max(0, Math.Min(_canvas.ActualWidth - _boxWidth, _dragBoxLeft + p.X - _dragStart.X));
|
||||
_boxTop = Math.Max(0, Math.Min(_canvas.ActualHeight - _boxHeight, _dragBoxTop + p.Y - _dragStart.Y));
|
||||
LayoutAll();
|
||||
}
|
||||
|
||||
private void SelectionBorder_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (!_draggingBox) return;
|
||||
_draggingBox = false;
|
||||
_selectionBorder.ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 缩放
|
||||
|
||||
private bool _resizing;
|
||||
private string _resizeTag;
|
||||
private Point _resizeStart;
|
||||
private double _rL, _rT, _rW, _rH;
|
||||
|
||||
private void Handle_MouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
var el = (FrameworkElement)sender;
|
||||
_resizing = true;
|
||||
_resizeTag = (string)el.Tag;
|
||||
_resizeStart = e.GetPosition(_canvas);
|
||||
_rL = _boxLeft; _rT = _boxTop; _rW = _boxWidth; _rH = _boxHeight;
|
||||
el.CaptureMouse();
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void Handle_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (!_resizing) return;
|
||||
var p = e.GetPosition(_canvas);
|
||||
double dx = p.X - _resizeStart.X;
|
||||
double dy = p.Y - _resizeStart.Y;
|
||||
|
||||
double nL = _rL, nT = _rT, nW = _rW, nH = _rH;
|
||||
switch (_resizeTag)
|
||||
{
|
||||
case "NW": nL = _rL + dx; nT = _rT + dy; nW = _rW - dx; nH = _rH - dy; break;
|
||||
case "N": nT = _rT + dy; nH = _rH - dy; break;
|
||||
case "NE": nT = _rT + dy; nW = _rW + dx; nH = _rH - dy; break;
|
||||
case "E": nW = _rW + dx; break;
|
||||
case "SE": nW = _rW + dx; nH = _rH + dy; break;
|
||||
case "S": nH = _rH + dy; break;
|
||||
case "SW": nL = _rL + dx; nW = _rW - dx; nH = _rH + dy; break;
|
||||
case "W": nL = _rL + dx; nW = _rW - dx; break;
|
||||
}
|
||||
if (nW < MinBoxW) { if (_resizeTag.Contains("W")) nL -= MinBoxW - nW; nW = MinBoxW; }
|
||||
if (nH < MinBoxH) { if (_resizeTag.Contains("N")) nT -= MinBoxH - nH; nH = MinBoxH; }
|
||||
|
||||
// 限制在窗口内
|
||||
nL = Math.Max(0, nL);
|
||||
nT = Math.Max(0, nT);
|
||||
if (nL + nW > _canvas.ActualWidth) nW = _canvas.ActualWidth - nL;
|
||||
if (nT + nH > _canvas.ActualHeight) nH = _canvas.ActualHeight - nT;
|
||||
|
||||
_boxLeft = nL; _boxTop = nT; _boxWidth = nW; _boxHeight = nH;
|
||||
LayoutAll();
|
||||
}
|
||||
|
||||
private void Handle_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (!_resizing) return;
|
||||
_resizing = false;
|
||||
((FrameworkElement)sender).ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 关灯
|
||||
|
||||
private void SetBlackout(bool on)
|
||||
{
|
||||
_blackoutOn = on;
|
||||
_overlay.Fill = new SolidColorBrush(on
|
||||
? Color.FromArgb(245, 0, 0, 0)
|
||||
: Color.FromArgb(102, 0, 0, 0));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Magnifier 子窗口
|
||||
|
||||
private class MagnifierHost : HwndHost
|
||||
{
|
||||
private readonly MagnifierWindow _owner;
|
||||
public IntPtr MagHwnd { get; private set; }
|
||||
|
||||
public MagnifierHost(MagnifierWindow owner) { _owner = owner; }
|
||||
|
||||
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
|
||||
{
|
||||
if (!MagInitialize())
|
||||
{
|
||||
throw new InvalidOperationException("MagInitialize 失败");
|
||||
}
|
||||
if (!MagInitialize()) throw new InvalidOperationException("MagInitialize 失败");
|
||||
_owner._magInitialized = true;
|
||||
|
||||
MagHwnd = CreateWindowEx(
|
||||
@@ -186,17 +441,13 @@ namespace Ink_Canvas.Windows
|
||||
WS_CHILD | WS_VISIBLE,
|
||||
0, 0, 100, 100,
|
||||
hwndParent.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||
|
||||
_owner._magHwnd = MagHwnd;
|
||||
return new HandleRef(this, MagHwnd);
|
||||
}
|
||||
|
||||
protected override void DestroyWindowCore(HandleRef hwnd)
|
||||
{
|
||||
if (hwnd.Handle != IntPtr.Zero)
|
||||
{
|
||||
DestroyWindow(hwnd.Handle);
|
||||
}
|
||||
if (hwnd.Handle != IntPtr.Zero) DestroyWindow(hwnd.Handle);
|
||||
MagHwnd = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
@@ -205,14 +456,9 @@ namespace Ink_Canvas.Windows
|
||||
{
|
||||
base.OnSourceInitialized(e);
|
||||
_hwndSource = (HwndSource)PresentationSource.FromVisual(this);
|
||||
|
||||
ApplyTransform();
|
||||
|
||||
// 把本窗口排除在采样源外,避免自我递归
|
||||
if (_hwndSource != null && _magHwnd != IntPtr.Zero)
|
||||
{
|
||||
MagSetWindowFilterList(_magHwnd, MW_FILTERMODE_EXCLUDE, 1, new[] { _hwndSource.Handle });
|
||||
}
|
||||
|
||||
_timer = new DispatcherTimer(DispatcherPriority.Render) { Interval = TimeSpan.FromMilliseconds(33) };
|
||||
_timer.Tick += OnTick;
|
||||
@@ -233,45 +479,34 @@ namespace Ink_Canvas.Windows
|
||||
|
||||
private void OnTick(object sender, EventArgs e)
|
||||
{
|
||||
if (_magHwnd == IntPtr.Zero || _hwndSource == null) return;
|
||||
if (_magHwnd == IntPtr.Zero || _magHost == null) return;
|
||||
if (_magHost.RenderSize.Width <= 0) return;
|
||||
|
||||
// 当前放大区域 = 放大镜承载控件在屏幕上的位置/尺寸
|
||||
var hostSize = _magHost.RenderSize;
|
||||
if (hostSize.Width <= 0 || hostSize.Height <= 0) return;
|
||||
|
||||
// 承载控件相对窗口的位置
|
||||
// 选择框在屏幕物理像素坐标
|
||||
var hostOffset = _magHost.TransformToAncestor(this).Transform(new Point(0, 0));
|
||||
var screenTopLeft = PointToScreen(hostOffset);
|
||||
var screenBottomRight = PointToScreen(new Point(hostOffset.X + hostSize.Width, hostOffset.Y + hostSize.Height));
|
||||
|
||||
int viewW = (int)(screenBottomRight.X - screenTopLeft.X);
|
||||
int viewH = (int)(screenBottomRight.Y - screenTopLeft.Y);
|
||||
var tl = PointToScreen(hostOffset);
|
||||
var br = PointToScreen(new Point(hostOffset.X + _magHost.RenderSize.Width,
|
||||
hostOffset.Y + _magHost.RenderSize.Height));
|
||||
int viewW = (int)(br.X - tl.X);
|
||||
int viewH = (int)(br.Y - tl.Y);
|
||||
if (viewW <= 0 || viewH <= 0) return;
|
||||
|
||||
int srcW = Math.Max(1, (int)(viewW / _zoom));
|
||||
int srcH = Math.Max(1, (int)(viewH / _zoom));
|
||||
int srcCx = (int)((screenTopLeft.X + screenBottomRight.X) / 2);
|
||||
int srcCy = (int)((screenTopLeft.Y + screenBottomRight.Y) / 2);
|
||||
|
||||
var src = new RECT(srcCx - srcW / 2, srcCy - srcH / 2,
|
||||
srcCx - srcW / 2 + srcW, srcCy - srcH / 2 + srcH);
|
||||
int cx = (int)((tl.X + br.X) / 2);
|
||||
int cy = (int)((tl.Y + br.Y) / 2);
|
||||
var src = new RECT(cx - srcW / 2, cy - srcH / 2,
|
||||
cx - srcW / 2 + srcW, cy - srcH / 2 + srcH);
|
||||
MagSetWindowSource(_magHwnd, src);
|
||||
InvalidateRect(_magHwnd, IntPtr.Zero, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
if (_timer != null)
|
||||
{
|
||||
_timer.Stop();
|
||||
_timer.Tick -= OnTick;
|
||||
_timer = null;
|
||||
}
|
||||
if (_magInitialized)
|
||||
{
|
||||
MagUninitialize();
|
||||
_magInitialized = false;
|
||||
}
|
||||
if (_timer != null) { _timer.Stop(); _timer.Tick -= OnTick; _timer = null; }
|
||||
if (_magInitialized) { MagUninitialize(); _magInitialized = false; }
|
||||
base.OnClosed(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +118,19 @@ namespace Ink_Canvas.Windows
|
||||
Loaded += PPTQuickPanel_Loaded;
|
||||
Unloaded += PPTQuickPanel_Unloaded;
|
||||
IsVisibleChanged += PPTQuickPanel_IsVisibleChanged;
|
||||
|
||||
MagnifierWindow.Closed2 += OnMagnifierClosed;
|
||||
}
|
||||
|
||||
private void OnMagnifierClosed(object sender, EventArgs e)
|
||||
{
|
||||
Dispatcher.BeginInvoke(new Action(SyncMagnifierButtonState));
|
||||
}
|
||||
|
||||
private void SyncMagnifierButtonState()
|
||||
{
|
||||
if (MagnifierToggleButton == null) return;
|
||||
MagnifierToggleButton.Content = MagnifierWindow.HasInstance ? "关闭放大镜" : "开启放大镜";
|
||||
}
|
||||
|
||||
private void PPTQuickPanel_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
@@ -125,6 +138,7 @@ namespace Ink_Canvas.Windows
|
||||
if (Visibility == Visibility.Visible)
|
||||
{
|
||||
ApplyTheme();
|
||||
SyncMagnifierButtonState();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user