Skip to content

Commit

Permalink
Create a separate InputSystem for each OS-level window.
Browse files Browse the repository at this point in the history
Also, we now have to tell each ImGui which InputSystem it should talk to.
  • Loading branch information
DaleStan committed Jun 14, 2024
1 parent 1a90fd2 commit 5676ce7
Show file tree
Hide file tree
Showing 33 changed files with 116 additions and 95 deletions.
2 changes: 1 addition & 1 deletion Yafc.Model/Blueprints/Blueprint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class BlueprintString(string blueprintName) {
private static readonly byte[] header = { 0x78, 0xDA };

public string ToBpString() {
if (InputSystem.Instance.control) {
if (Ui.ActiveInputSystem?.control ?? false) {
return ToJson();
}

Expand Down
6 changes: 4 additions & 2 deletions Yafc.Model/Serialization/UndoSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ private static void MakeUndoBatch(object? state) {
}

private void Schedule() {
InputSystem.Instance.DispatchOnGestureFinish(MakeUndoBatch, this);
scheduled = true;
if (Ui.ActiveInputSystem != null) {
Ui.ActiveInputSystem.DispatchOnGestureFinish(MakeUndoBatch, this);
scheduled = true;
}
}

public void Suspend() {
Expand Down
4 changes: 0 additions & 4 deletions Yafc.UI/Core/InputSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ public interface IMouseFocus {
}

public sealed class InputSystem {
public static readonly InputSystem Instance = new InputSystem();

private InputSystem() { }

public Window? mouseOverWindow { get; private set; }
private IPanel? hoveringPanel;
private IPanel? mouseDownPanel;
Expand Down
23 changes: 19 additions & 4 deletions Yafc.UI/Core/Ui.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
Expand Down Expand Up @@ -34,6 +36,15 @@ public static void Start() {
mainThreadId = Thread.CurrentThread.ManagedThreadId;
}

/// <summary>
/// The <see cref="InputSystem"/> belonging to the active window, if such a window exists. Failing that, it is the input system for the only window,
/// if there is exactly one window. This is the *current* active input system, and may be about to change if a new (OS-level) window is being
/// constructed or if the focus is changing. For this reason, try to get your InputSystem from a source that reflects the new value,
/// rather than the current value.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public static InputSystem? ActiveInputSystem => windows.Values.FirstOrDefault(w => w.active)?.InputSystem ?? (windows.Count == 1 ? windows.Values.First().InputSystem : null);

public static long time { get; private set; }
private static readonly Stopwatch timeWatch = Stopwatch.StartNew();

Expand All @@ -55,7 +66,8 @@ public static void MainLoop() {

public static void ProcessEvents() {
try {
var inputSystem = InputSystem.Instance;
InputSystem? inputSystem = ActiveInputSystem;
if (inputSystem == null) { return; }
long minNextEvent = long.MaxValue - 1;
foreach (var (_, window) in windows) {
minNextEvent = Math.Min(minNextEvent, window.nextRepaintTime);
Expand Down Expand Up @@ -123,18 +135,21 @@ public static void ProcessEvents() {

switch (evt.window.windowEvent) {
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_ENTER:
inputSystem.MouseEnterWindow(window);
window.InputSystem.MouseEnterWindow(window);
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_LEAVE:
inputSystem.MouseExitWindow(window);
window.InputSystem.MouseExitWindow(window);
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE:
window.Close();
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST:
inputSystem.SetKeyboardFocus(null);
window.FocusLost();
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED:
window.FocusGained();
window.Rebuild();
break;
case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_MINIMIZED:
window.Minimized();
break;
Expand Down
18 changes: 11 additions & 7 deletions Yafc.UI/Core/Window.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using SDL2;

Expand All @@ -14,6 +13,7 @@ public abstract class Window : IDisposable {
internal bool repaintRequired = true;
internal bool visible;
internal bool closed;
internal bool active;
internal long nextRepaintTime = long.MaxValue;
internal float pixelsPerUnit;
public virtual SchemeColor backgroundColor => SchemeColor.Background;
Expand All @@ -28,10 +28,13 @@ public abstract class Window : IDisposable {
public int displayIndex => SDL.SDL_GetWindowDisplayIndex(window);
public int repaintCount { get; private set; }

public InputSystem InputSystem { get; } = new();

public Vector2 size => contentSize;

public virtual bool preventQuit => false;
internal Window(Padding padding) => rootGui = new ImGui(Build, padding);

internal Window(Padding padding) => rootGui = new ImGui(Build, padding, InputSystem);

internal void Create() {
if (surface is null) { throw new InvalidOperationException($"surface must be set by a derived class before calling {nameof(Create)}."); }
Expand Down Expand Up @@ -142,6 +145,7 @@ public void Repaint() {

protected internal virtual void Close() {
visible = false;
active = false;
closed = true;
surface?.Dispose();
SDL.SDL_DestroyWindow(window);
Expand All @@ -158,8 +162,8 @@ private void Focus() {
}
}


public virtual void FocusLost() { }
public virtual void FocusLost() => active = false;
public void FocusGained() => active = true;
public virtual void Minimized() { }

public void SetNextRepaint(long nextRepaintTime) {
Expand All @@ -174,7 +178,7 @@ public void ShowTooltip(Tooltip tooltip) {
}

public void ShowTooltip(ImGui targetGui, Rect target, GuiBuilder builder, float width = 20f) {
simpleTooltip ??= new SimpleTooltip();
simpleTooltip ??= new SimpleTooltip(InputSystem);
simpleTooltip.Show(builder, targetGui, target, width);
ShowTooltip(simpleTooltip);

Expand All @@ -186,7 +190,7 @@ public void ShowDropDown(DropDownPanel dropDown) {
}

public void ShowDropDown(ImGui targetGui, Rect target, GuiBuilder builder, Padding padding, float width = 20f) {
simpleDropDown ??= new SimpleDropDown();
simpleDropDown ??= new SimpleDropDown(InputSystem);
simpleDropDown.SetPadding(padding);
simpleDropDown.SetFocus(targetGui, target, builder, width);
ShowDropDown(simpleDropDown);
Expand Down Expand Up @@ -216,6 +220,6 @@ private void Build(ImGui gui) {
protected abstract void BuildContents(ImGui gui);
public virtual void Dispose() => rootGui.Dispose();

internal ImGui.DragOverlay GetDragOverlay() => draggingOverlay ??= new ImGui.DragOverlay();
internal ImGui.DragOverlay GetDragOverlay() => draggingOverlay ??= new ImGui.DragOverlay(InputSystem);
}
}
25 changes: 14 additions & 11 deletions Yafc.UI/ImGui/DropDownPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ public abstract class AttachedPanel {
protected float width;
protected virtual SchemeColor background => SchemeColor.PureBackground;

protected AttachedPanel(Padding padding, float width) {
contents = new ImGui(BuildContents, padding) { boxColor = background, boxShadow = RectangleBorder.Thin };
protected AttachedPanel(Padding padding, float width, InputSystem inputSystem) {
contents = new ImGui(BuildContents, padding, inputSystem) { boxColor = background, boxShadow = RectangleBorder.Thin };
this.width = width;
}

Expand Down Expand Up @@ -49,13 +49,13 @@ public void Build(ImGui gui) {
protected abstract void BuildContents(ImGui gui);
}

public abstract class DropDownPanel : AttachedPanel, IMouseFocus {
public abstract class DropDownPanel(Padding padding, float width, InputSystem inputSystem) : AttachedPanel(padding, width, inputSystem), IMouseFocus {
private bool focused;
protected DropDownPanel(Padding padding, float width) : base(padding, width) { }

protected override bool ShouldBuild(ImGui source, Rect sourceRect, ImGui parent, Rect parentRect) => focused;

public override void SetFocus(ImGui source, Rect rect) {
InputSystem.Instance.SetMouseFocus(this);
source.inputSystem.SetMouseFocus(this);
base.SetFocus(source, rect);
}

Expand All @@ -80,7 +80,7 @@ public void FocusChanged(bool focused) {
public class SimpleDropDown : DropDownPanel {
private GuiBuilder? builder;

public SimpleDropDown() : base(new Padding(1f), 20f) => contents.AddMessageHandler<ImGuiUtils.CloseDropdownEvent>(HandleDropdownClosed);
public SimpleDropDown(InputSystem inputSystem) : base(new Padding(1f), 20f, inputSystem) => contents.AddMessageHandler<ImGuiUtils.CloseDropdownEvent>(HandleDropdownClosed);

private bool HandleDropdownClosed(ImGuiUtils.CloseDropdownEvent _) {
Close();
Expand Down Expand Up @@ -118,10 +118,15 @@ protected override void BuildContents(ImGui gui) {
}

public abstract class Tooltip : AttachedPanel {
protected Tooltip(Padding padding, float width) : base(padding, width) => contents.mouseCapture = false;
private readonly InputSystem inputSystem;
protected Tooltip(Padding padding, float width, InputSystem inputSystem) : base(padding, width, inputSystem) {
contents.mouseCapture = false;
this.inputSystem = inputSystem;
}

protected override bool ShouldBuild(ImGui source, Rect sourceRect, ImGui parent, Rect parentRect) {
var window = source.window;
if (InputSystem.Instance.mouseOverWindow != window) {
if (inputSystem.mouseOverWindow != window) {
return false;
}

Expand All @@ -143,16 +148,14 @@ protected override Vector2 CalculatePosition(ImGui gui, Rect targetRect, Vector2
}
}

public class SimpleTooltip : Tooltip {
public class SimpleTooltip(InputSystem inputSystem) : Tooltip(new Padding(0.5f), 30f, inputSystem) {
private GuiBuilder? builder;
public void Show(GuiBuilder builder, ImGui gui, Rect rect, float width = 30f) {
this.width = width;
this.builder = builder;
base.SetFocus(gui, rect);
}

public SimpleTooltip() : base(new Padding(0.5f), 30f) { }

protected override void BuildContents(ImGui gui) {
gui.boxColor = SchemeColor.PureBackground;
gui.textColor = SchemeColor.BackgroundText;
Expand Down
5 changes: 3 additions & 2 deletions Yafc.UI/ImGui/ImGui.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public enum RectAllocator {
public delegate void GuiBuilder(ImGui gui);

public sealed partial class ImGui : IDisposable, IPanel {
public ImGui(GuiBuilder? guiBuilder, Padding padding, RectAllocator defaultAllocator = RectAllocator.Stretch, bool clip = false) {
public ImGui(GuiBuilder? guiBuilder, Padding padding, InputSystem inputSystem, RectAllocator defaultAllocator = RectAllocator.Stretch, bool clip = false) {
this.guiBuilder = guiBuilder;
if (guiBuilder == null) {
action = ImGuiAction.Build;
Expand All @@ -59,6 +59,7 @@ public ImGui(GuiBuilder? guiBuilder, Padding padding, RectAllocator defaultAlloc
this.defaultAllocator = defaultAllocator;
this.clip = clip;
initialPadding = padding;
this.inputSystem = inputSystem ?? throw new ArgumentNullException(nameof(inputSystem));
}

public readonly GuiBuilder? guiBuilder;
Expand Down Expand Up @@ -94,7 +95,7 @@ public Vector2 offset {
screenRect -= (_offset - value);
_offset = value;
if (mousePresent) {
MouseMove(InputSystem.Instance.mouseDownButton);
MouseMove(inputSystem.mouseDownButton);
}
else {
Repaint();
Expand Down
5 changes: 3 additions & 2 deletions Yafc.UI/ImGui/ImGuiBuilding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public void Deconstruct(out Rect rect, out T data, out SchemeColor color) {
public SchemeColor boxColor { get; set; } = SchemeColor.None;
public RectangleBorder boxShadow { get; set; } = RectangleBorder.None;
public Padding initialPadding { get; set; }
internal readonly InputSystem inputSystem;

public void DrawRectangle(Rect rect, SchemeColor color, RectangleBorder border = RectangleBorder.None) {
if (action != ImGuiAction.Build) {
Expand Down Expand Up @@ -154,7 +155,7 @@ public void BuildIcon(Icon icon, float size = 1.5f, SchemeColor color = SchemeCo
}
}

public Vector2 mousePosition => InputSystem.Instance.mousePosition - screenRect.Position;
public Vector2 mousePosition => inputSystem.mousePosition - screenRect.Position;
public bool mousePresent { get; private set; }
public Rect mouseDownRect { get; private set; }
public Rect mouseOverRect { get; private set; } = Rect.VeryBig;
Expand Down Expand Up @@ -348,7 +349,7 @@ public void SetFocus(Rect rect) {
}

public void SetTextInputFocus(Rect rect, string text) {
if (textInputHelper != null && InputSystem.Instance.currentKeyboardFocus != textInputHelper) {
if (textInputHelper != null && inputSystem.currentKeyboardFocus != textInputHelper) {
SetFocus(rect);
textInputHelper.SetFocus(rect, text);
}
Expand Down
9 changes: 4 additions & 5 deletions Yafc.UI/ImGui/ImGuiDrag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,13 @@ public bool DoListReordering<T>(Rect moveHandle, Rect contents, T index, out T m
}


internal class DragOverlay {
private readonly ImGui contents = new ImGui(null, default) { mouseCapture = false };
internal class DragOverlay(InputSystem inputSystem) {
private readonly ImGui contents = new ImGui(null, default, inputSystem) { mouseCapture = false };

private ImGui? currentSource;
private Vector2 mouseOffset;
private Rect realPosition;


public bool ShouldConsumeDrag(ImGui source, Vector2 point) => currentSource == source && realPosition.Contains(source.ToWindowPosition(point));

private void ExtractDrawCommandsFrom<T>(List<DrawCommand<T>> sourceList, List<DrawCommand<T>> targetList, Rect rect) {
Expand Down Expand Up @@ -117,7 +116,7 @@ public void Build(ImGui screenGui) {
return;
}

if (InputSystem.Instance.mouseDownButton == -1) {
if (inputSystem.mouseDownButton == -1) {
currentSource = null;
realPosition = default;
return;
Expand All @@ -134,7 +133,7 @@ public void Build(ImGui screenGui) {
}

public bool ShouldEnterDrag(Rect moveHandle) {
if (action != ImGuiAction.MouseMove || !IsMouseDown(moveHandle) || isDragging || Vector2.DistanceSquared(InputSystem.Instance.mousePosition, InputSystem.Instance.mouseDownPosition) < 1f) {
if (action != ImGuiAction.MouseMove || !IsMouseDown(moveHandle) || isDragging || Vector2.DistanceSquared(inputSystem.mousePosition, inputSystem.mouseDownPosition) < 1f) {
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions Yafc.UI/ImGui/ImGuiTextInputHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public void SetFocus(Rect boundingRect, string setText) {
editHistory.Clear();
text = setText;
}
InputSystem.Instance.SetKeyboardFocus(this);
gui.inputSystem.SetKeyboardFocus(this);
rect = boundingRect;
caret = selectionAnchor = setText.Length;
}
Expand Down Expand Up @@ -251,7 +251,7 @@ public bool KeyDown(SDL.SDL_Keysym key) {
case SDL.SDL_Scancode.SDL_SCANCODE_RETURN2:
case SDL.SDL_Scancode.SDL_SCANCODE_KP_ENTER:
case SDL.SDL_Scancode.SDL_SCANCODE_ESCAPE:
InputSystem.Instance.SetKeyboardFocus(null);
gui.inputSystem.SetKeyboardFocus(null);
break;
case SDL.SDL_Scancode.SDL_SCANCODE_LEFT:
if (shift) {
Expand Down
2 changes: 1 addition & 1 deletion Yafc.UI/ImGui/ImGuiUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static class ImGuiUtils {

public static ButtonEvent BuildButton(this ImGui gui, Rect rect, SchemeColor normal, SchemeColor over, SchemeColor down = SchemeColor.None, uint button = SDL.SDL_BUTTON_LEFT) {
if (button == 0) {
button = (uint)InputSystem.Instance.mouseDownButton;
button = (uint)gui.inputSystem.mouseDownButton;
}

switch (gui.action) {
Expand Down
Loading

0 comments on commit 5676ce7

Please sign in to comment.