76 lines
3.0 KiB
C#
76 lines
3.0 KiB
C#
using System.Windows;
|
|
using System.Windows.Interop;
|
|
using CursorLang.Interop;
|
|
using CursorLang.Services;
|
|
using CursorLang.ViewModels;
|
|
|
|
namespace CursorLang.Views;
|
|
|
|
/// <summary>
|
|
/// Всплывающая подсказка у курсора с коротким именем раскладки.
|
|
/// Отвечает только за показ: когда её убрать, решает <see cref="LayoutPopupService"/>.
|
|
/// </summary>
|
|
public partial class LayoutPopupWindow : Window
|
|
{
|
|
private readonly double _cursorOffset;
|
|
private PopupWindowNative.Point _cursor;
|
|
|
|
public LayoutPopupWindow(LayoutPopupViewModel viewModel, PopupOptions options)
|
|
{
|
|
InitializeComponent();
|
|
|
|
DataContext = viewModel;
|
|
_cursorOffset = options.CursorOffset;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Показывает подсказку у текущего положения курсора.
|
|
/// </summary>
|
|
public void ShowAtCursor()
|
|
{
|
|
ResizeToContent();
|
|
_cursor = PopupWindowNative.GetCursorPosition();
|
|
|
|
// Для уже созданного окна двигаем до показа; при самом первом вызове
|
|
// хэндла ещё нет, и позиционирование выполнит OnSourceInitialized
|
|
MoveToCursor();
|
|
Show();
|
|
}
|
|
|
|
// Хэндл создан, но окно ещё не отрисовано: здесь и настраиваем стили,
|
|
// и ставим окно на место, чтобы первый показ прошёл уже на нужном мониторе
|
|
protected override void OnSourceInitialized(EventArgs e)
|
|
{
|
|
base.OnSourceInitialized(e);
|
|
|
|
PopupWindowNative.MakePassive(new WindowInteropHelper(this).Handle);
|
|
MoveToCursor();
|
|
}
|
|
|
|
// Размер считаем сами, а не через SizeToContent: тот вычисляет его при создании
|
|
// окна, когда содержимое ещё не измерено, и первый показ выходит шире текста.
|
|
// Рамок у окна нет, поэтому его размер равен размеру содержимого
|
|
private void ResizeToContent()
|
|
{
|
|
var content = (FrameworkElement)Content;
|
|
content.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
|
|
|
Width = content.DesiredSize.Width;
|
|
Height = content.DesiredSize.Height;
|
|
}
|
|
|
|
private void MoveToCursor()
|
|
{
|
|
IntPtr handle = new WindowInteropHelper(this).Handle;
|
|
if (handle == IntPtr.Zero)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Отступ задан в единицах WPF, а двигаем окно в пикселях: пересчитываем
|
|
// его по масштабу монитора, на котором сейчас курсор
|
|
int offset = (int)Math.Round(_cursorOffset * PopupWindowNative.GetScaleAt(_cursor));
|
|
PopupWindowNative.MoveTo(handle, _cursor.X + offset, _cursor.Y + offset);
|
|
}
|
|
}
|