Files
tooll3--t3/Editor/Gui/UiHelpers/KeyboardAndMouseOverlay.cs
2026-07-13 13:13:17 +08:00

335 lines
17 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using ImGuiNET;
using T3.Core.Animation;
using T3.Core.Utils;
using T3.Editor.Gui.Styling;
using T3.SystemUi;
namespace T3.Editor.Gui.UiHelpers;
public static class KeyboardAndMouseOverlay
{
public static void Draw()
{
if (!UserSettings.Config.ShowInteractionOverlay)
{
return;
}
_widgetFade = 1-(float)((Playback.RunTimeInSecs - _lastInteractionTime) / FadeoutDuration).Clamp(0, 1);
var dl = ImGui.GetForegroundDrawList();
var pos = ImGui.GetMousePos() + new Vector2(30, -100) * T3Ui.UiScaleFactor;
if(pos.X + 120 > ImGui.GetIO().DisplaySize.X)
pos.X = ImGui.GetIO().DisplaySize.X - 120;
if (pos.Y + 90 > ImGui.GetIO().DisplaySize.Y)
{
var dy = 90 + pos.Y - ImGui.GetIO().DisplaySize.Y;
pos.Y -= dy;
pos.X += dy/2;
}
var panelSize = new Vector2(120, 90) * T3Ui.UiScaleFactor;
dl.AddRectFilled(pos, pos + panelSize, UiColors.BackgroundFull.Fade(0.7f * _widgetFade), 10);
UpdatePressedKeys();
DrawKeys(pos, dl);
var radius = 20f * T3Ui.UiScaleFactor;
var thickness = 26f * T3Ui.UiScaleFactor;
var center = pos + new Vector2(panelSize.X / 2, 65 * T3Ui.UiScaleFactor);
var spacing = 2f * T3Ui.UiScaleFactor;
var halfspace = spacing * 0.5f;
const float radspace = 22f;
const int segments = 12;
if (ImGui.IsMouseDown(ImGuiMouseButton.Left)
|| ImGui.IsMouseDown(ImGuiMouseButton.Middle)
|| ImGui.IsMouseDown(ImGuiMouseButton.Right))
{
_lastInteractionTime = Playback.RunTimeInSecs;
}
// Left mouse
{
var color = ImGui.IsMouseDown(ImGuiMouseButton.Left) ? UiColors.ForegroundFull.Fade(_widgetFade) : UiColors.ForegroundFull.Fade(0.1f * _widgetFade);
dl.PathClear();
dl.PathLineTo(center + new Vector2(-halfspace, -radius));
dl.PathArcTo(center - new Vector2(spacing, 0), radius, -MathF.PI / 2, -MathF.PI, segments);
dl.PathLineTo(center + new Vector2(-radspace, 15) * T3Ui.UiScaleFactor);
dl.PathStroke(color, ImDrawFlags.None, thickness);
// Check for double click
if (ImGui.IsMouseDoubleClicked(ImGuiMouseButton.Left))
{
_lastDoubleClickTime = Playback.RunTimeInSecs;
}
else if (ImGui.IsMouseClicked(ImGuiMouseButton.Left) && _lastDoubleClickTime >= 0)
{
_lastDoubleClickTime = 0;
}
}
DrawDoubleClickIndicator(center + new Vector2(-radspace - 12, -11) * T3Ui.UiScaleFactor, dl);
// right mouse
{
var color = ImGui.IsMouseDown(ImGuiMouseButton.Right) ? UiColors.ForegroundFull.Fade(_widgetFade) : UiColors.ForegroundFull.Fade(0.1f * _widgetFade);
dl.PathClear();
dl.PathLineTo(center + new Vector2(halfspace, -radius));
dl.PathArcTo(center + new Vector2(spacing, 0), radius, -MathF.PI / 2, 0, segments);
dl.PathLineTo(center + new Vector2(radspace, 15) * T3Ui.UiScaleFactor);
dl.PathStroke(color, ImDrawFlags.None, thickness);
}
// middle mouse
{
var color = ImGui.IsMouseDown(ImGuiMouseButton.Middle) ? UiColors.ForegroundFull.Fade(_widgetFade) : UiColors.ForegroundFull.Fade(0.1f * _widgetFade);
var size = new Vector2(14, 24) * T3Ui.UiScaleFactor;
var min = center - size * 0.5f + new Vector2(0, 7) * T3Ui.UiScaleFactor;
dl.AddRectFilled(min, min + size, color, 4 * T3Ui.UiScaleFactor);
}
// mouse wheel
{
var fadeFromTime = 1-(float)((Playback.RunTimeInSecs - _lastMouseWheelInteractionTime) / FadeoutDuration).Clamp(0, 1);
var mouseDelta = ImGui.GetIO().MouseWheel;
if (mouseDelta != 0)
{
_lastMouseWheelInteractionTime = Playback.RunTimeInSecs;
_lastInteractionTime = Playback.RunTimeInSecs;
_wheelSpin -= mouseDelta;
}
_dampedWheelSpin = DampFunctions.DampenFloat(_wheelSpin, _dampedWheelSpin, 0.001f, ref _dampedWheelSpinVelocity, DampFunctions.Methods.DampedSpring);
if (double.IsInfinity(_dampedWheelSpin) || double.IsNaN(_dampedWheelSpin))
{
_dampedWheelSpin = 0;
}
const int lineCount = 5;
var height = 34 * T3Ui.UiScaleFactor;
var size = new Vector2(12, 1) * T3Ui.UiScaleFactor;
var min = center - size * 0.5f + new Vector2(0, -10) * T3Ui.UiScaleFactor;
float step = height / (lineCount + 1);
for (int i = 0; i < lineCount; i++)
{
var f = (float)i / lineCount;
var fadeEdge =1- MathF.Abs((f - 0.5f) * 2).Clamp(0, 1);
var offset = new Vector2(0, step * i + step * MathUtils.Fmod(_dampedWheelSpin + 0.5f, 1));
var color = UiColors.ForegroundFull.Fade(fadeFromTime * fadeEdge);
dl.AddRectFilled(min + offset, min + size + offset, color, 10);
}
}
}
private static void DrawKeys(Vector2 pos, ImDrawListPtr dl)
{
var keyPos = pos + new Vector2(4, 4);
foreach (var k in _previousKeys)
{
var label = k.Label;
var labelSize = ImGui.CalcTextSize(label);
var rectMin = keyPos;
var size = labelSize + new Vector2(8, 2);
var fade = MathF.Pow((1 - k.FadeProgress).Clamp(0f, 1f), 4);
dl.AddRectFilled(rectMin,
rectMin + size,
UiColors.ForegroundFull.Fade(fade * _widgetFade),
3);
dl.AddText(rectMin + new Vector2(4, 0), UiColors.BackgroundFull.Fade(_widgetFade), label);
keyPos.X += (size.X + 3);
}
}
private static void UpdatePressedKeys()
{
var time = Playback.RunTimeInSecs;
for (var index = 0; index < KeyHandler.PressedKeys.Count; index++)
{
var pressed = KeyHandler.PressedKeys[index];
var status = _keyStates[index];
if (status == null)
continue;
if (pressed != status.IsPressed)
{
if (pressed)
{
_previousKeys.Remove(status);
_previousKeys.Add(status);
}
status.IsPressed = pressed;
}
if (pressed)
{
status.ReleaseTime = time;
_lastInteractionTime = time;
}
else
{
if(status.FadeProgress > 1 )
_previousKeys.Remove(status);
}
}
}
private static void DrawDoubleClickIndicator(Vector2 position, ImDrawListPtr dl)
{
var timeSince = (float)(Playback.RunTimeInSecs - _lastDoubleClickTime);
if (timeSince > FadeoutDuration)
return;
var textColor = UiColors.ForegroundFull.Fade(_widgetFade);
dl.AddText(Fonts.FontLarge, Fonts.FontLarge.FontSize, position, textColor, "×2");
}
private static readonly List<KeyStatus> _previousKeys = new();
private static double _lastInteractionTime = double.NegativeInfinity;
private static float _widgetFade = 0;
private static double _lastMouseWheelInteractionTime;
private static double _lastDoubleClickTime = double.NegativeInfinity;
private sealed class KeyStatus
{
public KeyStatus(int keyIndex, string label, Icon icon = Icon.None )
{
if (keyIndex >= KeyLookupCount)
return;
Icon = icon;
Label = label;
_keyStates[keyIndex] = this;
}
public float FadeProgress
{
get
{
var timeSinceRelease = (float)(Playback.RunTimeInSecs - ReleaseTime);
return timeSinceRelease / FadeoutDuration;
}
}
public bool IsPressed;
public readonly string Label;
public Icon Icon;
public double ReleaseTime = double.NegativeInfinity;
}
private const float FadeoutDuration = 2;
private const int KeyLookupCount = 512;
private static float _wheelSpin;
private static float _dampedWheelSpin;
private static float _dampedWheelSpinVelocity;
private static readonly KeyStatus[] _keyStates = new KeyStatus[KeyLookupCount];
// ReSharper disable once UnusedMember.Local
private static readonly KeyStatus[] _keyDefinitions = {
new(8, "Backspace"),
new(9, "Tab"),
new(13, "Return"),
new(16, "Shift"),
new(17, "Ctrl"),
new(18, "Alt"),
new(20, "Caps"),
new(27, "Esc"),
new(32, "Space"),
new(33, "PageUp"),
new(34, "PageDown"),
new(35, "End"),
new(36, "Home"),
new(37, "Left", Icon.ChevronLeft),
new(38, "Up", Icon.ChevronUp),
new(39, "Right", Icon.ChevronRight),
new(40, "Down", Icon.ChevronDown),
new(45, "Ins"),
new(46, "Del"),
new(48, "0"),
new(49, "1"),
new(50, "2"),
new(51, "3"),
new(52, "4"),
new(53, "5"),
new(54, "6"),
new(55, "7"),
new(56, "8"),
new(57, "9"),
new(65, "A"),
new(66, "B"),
new(67, "C"),
new(68, "D"),
new(69, "E"),
new(70, "F"),
new(71, "G"),
new(72, "H"),
new(73, "I"),
new(74, "J"),
new(75, "K"),
new(76, "L"),
new(77, "M"),
new(78, "N"),
new(79, "O"),
new(80, "P"),
new(81, "Q"),
new(82, "R"),
new(83, "S"),
new(84, "T"),
new(85, "U"),
new(86, "V"),
new(87, "W"),
new(88, "X"),
new(89, "Y"),
new(90, "Z"),
new(112, "F1"),
new(113, "F2"),
new(114, "F3"),
new(115, "F4"),
new(116, "F5"),
new(117, "F6"),
new(118, "F7"),
new(119, "F8"),
new(120, "F9"),
new(121, "F10"),
new(122, "F11"),
new(123, "F12"),
new(124, "F13"),
new(125, "F14"),
new(126, "F15"),
new(127, "F16"),
new(128, "F17"),
new(129, "F18"),
new(130, "F19"),
new(131, "F20"),
new(132, "F21"),
new(133, "F22"),
new(134, "F23"),
new(135, "F24"),
new(187, "+"),
new(187, "="),
new(189, "-"),
new(219, "["),
new(221, "]"),
new(188, ","),
new(190, "."),
new(191, "/"),
new(192, "|"),
new(186, ";"),
new(226, "`"),
new(220, "#"),
};
}