From 2af494d2f6c4acbdfd25d69235c7d4d7779fc5c5 Mon Sep 17 00:00:00 2001 From: Aleksandr Neychev Date: Sat, 8 Aug 2026 23:27:28 +0500 Subject: [PATCH] modified each other mode has own side and offset --- CursorLang/Models/AppSettings.cs | 12 ++++- CursorLang/Models/PopupPlacement.cs | 11 ++-- CursorLang/Resources/Strings.resx | 14 +++-- CursorLang/Resources/Strings.ru.resx | 14 +++-- CursorLang/ViewModels/SettingsViewModel.cs | 6 +-- CursorLang/Views/LayoutPopupWindow.xaml.cs | 25 +++++++-- CursorLang/Views/MainWindow.xaml | 63 +++++++++++++++++----- 7 files changed, 110 insertions(+), 35 deletions(-) diff --git a/CursorLang/Models/AppSettings.cs b/CursorLang/Models/AppSettings.cs index 6fc73ef..97d02eb 100644 --- a/CursorLang/Models/AppSettings.cs +++ b/CursorLang/Models/AppSettings.cs @@ -17,13 +17,23 @@ public sealed partial class AppSettings : ObservableObject [ObservableProperty] private PopupPlacementMode _placementMode = PopupPlacementMode.AtCursor; + // Сторона и отступ хранятся отдельно для каждого режима: у курсора и у + // каретки удобны разные настройки, и переключение режима их не сбрасывает + [ObservableProperty] - private CursorCorner _cursorCorner = CursorCorner.BottomRight; + private AnchorSide _cursorSide = AnchorSide.BottomRight; /// Отступ от курсора в единицах WPF. [ObservableProperty] private double _cursorOffset = 16; + [ObservableProperty] + private AnchorSide _caretSide = AnchorSide.BottomRight; + + /// Отступ от каретки в единицах WPF. + [ObservableProperty] + private double _caretOffset = 16; + [ObservableProperty] private ScreenPosition _screenPosition = ScreenPosition.BottomRight; diff --git a/CursorLang/Models/PopupPlacement.cs b/CursorLang/Models/PopupPlacement.cs index 973aff0..0dfc1e6 100644 --- a/CursorLang/Models/PopupPlacement.cs +++ b/CursorLang/Models/PopupPlacement.cs @@ -21,13 +21,14 @@ public enum PopupPlacementMode /// /// С какой стороны от курсора или каретки показывать подсказку. /// - -public enum CursorCorner +public enum AnchorSide { - BottomRight, - BottomLeft, - TopRight, TopLeft, + TopRight, + Left, + Right, + BottomLeft, + BottomRight, } /// diff --git a/CursorLang/Resources/Strings.resx b/CursorLang/Resources/Strings.resx index ae4740a..c9d1eb8 100644 --- a/CursorLang/Resources/Strings.resx +++ b/CursorLang/Resources/Strings.resx @@ -85,18 +85,24 @@ Side - + Bottom right - + Bottom left - + Top right - + Top left + + Left + + + Right + Offset diff --git a/CursorLang/Resources/Strings.ru.resx b/CursorLang/Resources/Strings.ru.resx index 19f561a..c5dcffd 100644 --- a/CursorLang/Resources/Strings.ru.resx +++ b/CursorLang/Resources/Strings.ru.resx @@ -85,18 +85,24 @@ Сторона - + Справа снизу - + Слева снизу - + Справа сверху - + Слева сверху + + Слева + + + Справа + Отступ diff --git a/CursorLang/ViewModels/SettingsViewModel.cs b/CursorLang/ViewModels/SettingsViewModel.cs index 97506ed..9aff458 100644 --- a/CursorLang/ViewModels/SettingsViewModel.cs +++ b/CursorLang/ViewModels/SettingsViewModel.cs @@ -63,7 +63,7 @@ public sealed partial class SettingsViewModel : ObservableObject, IDisposable Localization.PropertyChanged += OnLocalizationChanged; PlacementModes = CreateOptions(); - CursorCorners = CreateOptions(); + AnchorSides = CreateOptions(); ScreenPositions = CreateOptions(); } @@ -75,7 +75,7 @@ public sealed partial class SettingsViewModel : ObservableObject, IDisposable public IReadOnlyList> PlacementModes { get; } - public IReadOnlyList> CursorCorners { get; } + public IReadOnlyList> AnchorSides { get; } public IReadOnlyList> ScreenPositions { get; } @@ -103,7 +103,7 @@ public sealed partial class SettingsViewModel : ObservableObject, IDisposable } Translate(PlacementModes); - Translate(CursorCorners); + Translate(AnchorSides); Translate(ScreenPositions); } diff --git a/CursorLang/Views/LayoutPopupWindow.xaml.cs b/CursorLang/Views/LayoutPopupWindow.xaml.cs index 872951f..5c78302 100644 --- a/CursorLang/Views/LayoutPopupWindow.xaml.cs +++ b/CursorLang/Views/LayoutPopupWindow.xaml.cs @@ -109,15 +109,30 @@ public partial class LayoutPopupWindow : Window var anchorPoint = new PopupWindowNative.Point { X = anchor.Left, Y = anchor.Top }; double scale = PopupWindowNative.GetScaleAt(anchorPoint); + // У каждого режима привязки своя сторона и свой отступ + bool atCaret = _settings.PlacementMode == PopupPlacementMode.AtCaret; + AnchorSide side = atCaret ? _settings.CaretSide : _settings.CursorSide; + int offset = ToPixels(atCaret ? _settings.CaretOffset : _settings.CursorOffset, scale); + int width = ToPixels(_contentSize.Width, scale); int height = ToPixels(_contentSize.Height, scale); - int offset = ToPixels(_settings.CursorOffset, scale); - bool toRight = _settings.CursorCorner is CursorCorner.BottomRight or CursorCorner.TopRight; - bool toBottom = _settings.CursorCorner is CursorCorner.BottomRight or CursorCorner.BottomLeft; + int toLeftOf = anchor.Left - offset - width; + int toRightOf = anchor.Right + offset; + int above = anchor.Top - offset - height; + int below = anchor.Bottom + offset; + // Для сторон «слева» и «справа» подсказка встаёт вровень с точкой привязки + int middle = anchor.Top + (((anchor.Bottom - anchor.Top) - height) / 2); - int x = toRight ? anchor.Right + offset : anchor.Left - offset - width; - int y = toBottom ? anchor.Bottom + offset : anchor.Top - offset - height; + (int x, int y) = side switch + { + AnchorSide.TopLeft => (toLeftOf, above), + AnchorSide.TopRight => (toRightOf, above), + AnchorSide.Left => (toLeftOf, middle), + AnchorSide.Right => (toRightOf, middle), + AnchorSide.BottomLeft => (toLeftOf, below), + _ => (toRightOf, below), + }; PopupWindowNative.SetBounds(handle, x, y, width, height); } diff --git a/CursorLang/Views/MainWindow.xaml b/CursorLang/Views/MainWindow.xaml index 555cf37..5426081 100644 --- a/CursorLang/Views/MainWindow.xaml +++ b/CursorLang/Views/MainWindow.xaml @@ -71,6 +71,8 @@ + + - + + ConverterParameter=AtCursor}" /> + ConverterParameter=AtCursor}" /> + ConverterParameter=AtCursor}" /> + ConverterParameter=AtCursor}" /> + ConverterParameter=AtCursor}" /> + + + + + + + + - - - - -