142 lines
5.1 KiB
C#
142 lines
5.1 KiB
C#
using System.Drawing;
|
|
using System.Text.Json.Serialization;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
|
|
namespace CursorLang.Core.Models;
|
|
|
|
/// <summary>
|
|
/// The settings of one placement mode: where the popup goes and how it looks there.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Every mode keeps a set of its own. The popup next to the caret sits inside a text
|
|
/// being read and is wanted small and quiet; the one in the corner of the monitor is
|
|
/// looked for on purpose and is wanted large. A look shared by the modes meant setting
|
|
/// it up again after every switch — and switching modes to see what they do undid what
|
|
/// had just been set up.
|
|
///
|
|
/// The colours are <see cref="System.Drawing.Color"/> for the same reason as in
|
|
/// <see cref="AppSettings"/>: the agent reads them and must stay clear of WPF.
|
|
/// </remarks>
|
|
public abstract partial class PopupModeSettings : ObservableObject
|
|
{
|
|
/// <summary>The distance from whatever the popup is placed by, in WPF units.</summary>
|
|
[ObservableProperty]
|
|
private double _offset = 16;
|
|
|
|
/// <summary>The size of the layout name in the popup, in WPF units.</summary>
|
|
[ObservableProperty]
|
|
private double _fontSize = 20;
|
|
|
|
/// <summary>The popup opacity: 1.0 is fully opaque.</summary>
|
|
[ObservableProperty]
|
|
private double _opacity = 0.9;
|
|
|
|
/// <summary>The fill of the popup. The opacity is set by <see cref="Opacity"/>.</summary>
|
|
[ObservableProperty]
|
|
private Color _backgroundColor = Color.FromArgb(0xFF, 0x20, 0x20, 0x20);
|
|
|
|
/// <summary>The colour of the layout name in the popup.</summary>
|
|
[ObservableProperty]
|
|
private Color _foregroundColor = Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF);
|
|
|
|
/// <summary>
|
|
/// Takes the offset and the look of another mode over. What tells the modes apart —
|
|
/// the side, the place on the monitor — is copied by the mode itself.
|
|
/// </summary>
|
|
protected void CopyLookFrom(PopupModeSettings other)
|
|
{
|
|
Offset = other.Offset;
|
|
FontSize = other.FontSize;
|
|
Opacity = other.Opacity;
|
|
BackgroundColor = other.BackgroundColor;
|
|
ForegroundColor = other.ForegroundColor;
|
|
}
|
|
}
|
|
|
|
/// <summary>The mode that puts the popup next to the mouse cursor.</summary>
|
|
public sealed partial class CursorModeSettings : PopupModeSettings
|
|
{
|
|
/// <summary>The corner or the side of the cursor the popup is put on.</summary>
|
|
[ObservableProperty]
|
|
private AnchorSide _side = AnchorSide.BottomRight;
|
|
|
|
/// <summary>Takes the values of another mode of the same kind over.</summary>
|
|
public void CopyFrom(CursorModeSettings other)
|
|
{
|
|
CopyLookFrom(other);
|
|
Side = other.Side;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The mode that puts the popup next to the caret of the active input field.
|
|
/// </summary>
|
|
public sealed partial class CaretModeSettings : PopupModeSettings
|
|
{
|
|
/// <summary>The side of the caret the popup is put on: only left or right.</summary>
|
|
[ObservableProperty]
|
|
private CaretSide _side = CaretSide.Right;
|
|
|
|
/// <summary>
|
|
/// The side as the layout arithmetic wants it. Both of them line the popup up with
|
|
/// the caret rather than putting it above or below.
|
|
/// </summary>
|
|
[JsonIgnore]
|
|
public AnchorSide Anchor => Side == CaretSide.Left ? AnchorSide.Left : AnchorSide.Right;
|
|
|
|
/// <summary>Takes the values of another mode of the same kind over.</summary>
|
|
public void CopyFrom(CaretModeSettings other)
|
|
{
|
|
CopyLookFrom(other);
|
|
Side = other.Side;
|
|
}
|
|
|
|
// The side decides what the popup is lined up against, so it is a change of that too
|
|
partial void OnSideChanged(CaretSide value) => OnPropertyChanged(nameof(Anchor));
|
|
}
|
|
|
|
/// <summary>
|
|
/// The mode that puts the popup at a fixed place of the monitor holding the active
|
|
/// window. Here <see cref="PopupModeSettings.Offset"/> is the distance from the edge
|
|
/// of the monitor.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// In the middle of the monitor there is no edge to keep a distance from, so the offset
|
|
/// is zero there and the settings window does not offer it. Choosing the middle puts it
|
|
/// back to zero rather than remembering it for later: a setting that is not shown must
|
|
/// not be one that still applies.
|
|
/// </remarks>
|
|
public sealed partial class FixedPointModeSettings : PopupModeSettings
|
|
{
|
|
/// <summary>The place on the monitor the popup is put at.</summary>
|
|
[ObservableProperty]
|
|
private ScreenPosition _position = ScreenPosition.Center;
|
|
|
|
public FixedPointModeSettings()
|
|
{
|
|
// The middle is the default, and it has no edge to stand off from
|
|
Offset = 0;
|
|
}
|
|
|
|
/// <summary>Whether the popup is put at an edge of the monitor rather than in its middle.</summary>
|
|
[JsonIgnore]
|
|
public bool IsAtAnEdge => Position != ScreenPosition.Center;
|
|
|
|
/// <summary>Takes the values of another mode of the same kind over.</summary>
|
|
public void CopyFrom(FixedPointModeSettings other)
|
|
{
|
|
CopyLookFrom(other);
|
|
Position = other.Position;
|
|
}
|
|
|
|
partial void OnPositionChanged(ScreenPosition value)
|
|
{
|
|
OnPropertyChanged(nameof(IsAtAnEdge));
|
|
|
|
if (value == ScreenPosition.Center)
|
|
{
|
|
Offset = 0;
|
|
}
|
|
}
|
|
}
|