#nullable enable using ImGuiNET; using T3.Core.DataTypes.Vector; using T3.Core.Utils; using T3.Editor.Gui.Styling; namespace T3.Editor.Gui.Interaction.Snapping; internal sealed class ValueSnapHandler { public ValueSnapHandler(SnapResult.Orientations orientation) { _orientation = orientation; _snapResult.Orientation = orientation; } public void AddSnapAttractor(IValueSnapAttractor sp) { _snapAttractors.Add(sp); } public void RemoveSnapAttractor(IValueSnapAttractor sp) { _snapAttractors.Remove(sp); } /// /// Uses all registered snap providers to test for snapping /// public bool TryCheckForSnapping(double targetValue, out double snappedValue, float canvasScale = 1, IEnumerable? ignoredAttractors = null, IEnumerable? moreAttractors = null) { _snapResult.ResetForTargetValue(targetValue, canvasScale); _snapResult.Orientation = _orientation; foreach (var attractor in _snapAttractors) { if (ignoredAttractors != null && ignoredAttractors.Contains(attractor)) continue; attractor.CheckForSnap(ref _snapResult); } if (moreAttractors != null) { foreach (var attractor in moreAttractors) { if (ignoredAttractors != null && ignoredAttractors.Contains(attractor)) continue; attractor.CheckForSnap(ref _snapResult); } } if (_snapResult.IsValid) { _lastSnapTime = ImGui.GetTime(); _lastSnapValue = _snapResult.BestAnchorValue; snappedValue = _snapResult.BestAnchorValue; return true; } snappedValue = double.NaN; return false; } public void DrawSnapIndicator(ScalableCanvas canvas, Color colorOverride= default) { if (ImGui.GetTime() - _lastSnapTime > SnapIndicatorDuration) return; var opacity = (1 - ((float)(ImGui.GetTime() - _lastSnapTime) / SnapIndicatorDuration).Clamp(0, 1)) * 0.4f; var color = colorOverride == 0 ? UiColors.StatusAnimated : colorOverride; color.Rgba.W *= opacity; switch (_orientation) { case SnapResult.Orientations.Vertical: { var p = new Vector2(0, canvas.TransformY((float)_lastSnapValue)); p.Y = (int)p.Y - 1; //Log.Debug("Drawing " + p); ImGui.GetWindowDrawList().AddRectFilled(p, p + new Vector2(4000, 1), color); break; } case SnapResult.Orientations.Horizontal: { var p = new Vector2(canvas.TransformX((float)_lastSnapValue), 0); ImGui.GetWindowDrawList().AddRectFilled(p, p + new Vector2(1, 2000), color); break; } } } private const float SnapIndicatorDuration = 1; private readonly SnapResult.Orientations _orientation; private readonly HashSet _snapAttractors = []; private double _lastSnapValue; private double _lastSnapTime; private SnapResult _snapResult = new(0); }