mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Implement new functionality since original PR
This commit is contained in:
parent
660781393e
commit
2b67ebf466
3 changed files with 118 additions and 35 deletions
|
|
@ -118,6 +118,16 @@ public interface IWindow
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool AllowClickthrough { get; set; }
|
bool AllowClickthrough { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this window is pinned.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsPinned { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this window is click-through.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsClickthrough { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a list of available title bar buttons.
|
/// Gets or sets a list of available title bar buttons.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,12 @@ public abstract class Window : IWindow
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool AllowClickthrough { get; set; } = true;
|
public bool AllowClickthrough { get; set; } = true;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool IsPinned { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool IsClickthrough { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public List<TitleBarButton> TitleBarButtons { get; set; } = [];
|
public List<TitleBarButton> TitleBarButtons { get; set; } = [];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,6 @@ public class WindowHost
|
||||||
private static bool wasEscPressedLastFrame = false;
|
private static bool wasEscPressedLastFrame = false;
|
||||||
|
|
||||||
private bool internalLastIsOpen = false;
|
private bool internalLastIsOpen = false;
|
||||||
private bool internalIsOpen = false;
|
|
||||||
private bool internalIsPinned = false;
|
|
||||||
private bool internalIsClickthrough = false;
|
|
||||||
private bool didPushInternalAlpha = false;
|
private bool didPushInternalAlpha = false;
|
||||||
private float? internalAlpha = null;
|
private float? internalAlpha = null;
|
||||||
|
|
||||||
|
|
@ -51,6 +48,9 @@ public class WindowHost
|
||||||
private Vector2 fadeOutSize = Vector2.Zero;
|
private Vector2 fadeOutSize = Vector2.Zero;
|
||||||
private Vector2 fadeOutOrigin = Vector2.Zero;
|
private Vector2 fadeOutOrigin = Vector2.Zero;
|
||||||
|
|
||||||
|
private bool hasError = false;
|
||||||
|
private Exception? lastError;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="WindowHost"/> class.
|
/// Initializes a new instance of the <see cref="WindowHost"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -97,7 +97,7 @@ public class WindowHost
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IWindow Window { get; set; }
|
public IWindow Window { get; set; }
|
||||||
|
|
||||||
private bool CanShowCloseButton => this.Window.ShowCloseButton && !this.internalIsClickthrough;
|
private bool CanShowCloseButton => this.Window.ShowCloseButton && !this.Window.IsClickthrough;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draw the window via ImGui.
|
/// Draw the window via ImGui.
|
||||||
|
|
@ -111,9 +111,9 @@ public class WindowHost
|
||||||
|
|
||||||
if (!this.Window.IsOpen)
|
if (!this.Window.IsOpen)
|
||||||
{
|
{
|
||||||
if (this.internalIsOpen != this.internalLastIsOpen)
|
if (this.Window.IsOpen != this.internalLastIsOpen)
|
||||||
{
|
{
|
||||||
this.internalLastIsOpen = this.internalIsOpen;
|
this.internalLastIsOpen = this.Window.IsOpen;
|
||||||
this.Window.OnClose();
|
this.Window.OnClose();
|
||||||
|
|
||||||
this.Window.IsFocused = false;
|
this.Window.IsFocused = false;
|
||||||
|
|
@ -156,9 +156,9 @@ public class WindowHost
|
||||||
|
|
||||||
this.PreHandlePreset(persistence);
|
this.PreHandlePreset(persistence);
|
||||||
|
|
||||||
if (this.internalLastIsOpen != this.internalIsOpen && this.internalIsOpen)
|
if (this.internalLastIsOpen != this.Window.IsOpen && this.Window.IsOpen)
|
||||||
{
|
{
|
||||||
this.internalLastIsOpen = this.internalIsOpen;
|
this.internalLastIsOpen = this.Window.IsOpen;
|
||||||
this.Window.OnOpen();
|
this.Window.OnOpen();
|
||||||
|
|
||||||
if (internalDrawFlags.HasFlag(WindowDrawFlags.UseSoundEffects) && !this.Window.DisableWindowSounds)
|
if (internalDrawFlags.HasFlag(WindowDrawFlags.UseSoundEffects) && !this.Window.DisableWindowSounds)
|
||||||
|
|
@ -194,38 +194,56 @@ public class WindowHost
|
||||||
|
|
||||||
var flags = this.Window.Flags;
|
var flags = this.Window.Flags;
|
||||||
|
|
||||||
if (this.internalIsPinned || this.internalIsClickthrough)
|
if (this.Window.IsPinned || this.Window.IsClickthrough)
|
||||||
flags |= ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize;
|
flags |= ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize;
|
||||||
|
|
||||||
if (this.internalIsClickthrough)
|
if (this.Window.IsClickthrough)
|
||||||
flags |= ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoNav | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.NoMouseInputs;
|
flags |= ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoNav | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollWithMouse | ImGuiWindowFlags.NoMouseInputs;
|
||||||
|
|
||||||
if (this.CanShowCloseButton ? ImGui.Begin(this.Window.WindowName, ref this.internalIsOpen, flags) : ImGui.Begin(this.Window.WindowName, flags))
|
var isWindowOpen = this.Window.IsOpen;
|
||||||
|
|
||||||
|
if (this.CanShowCloseButton ? ImGui.Begin(this.Window.WindowName, ref isWindowOpen, flags) : ImGui.Begin(this.Window.WindowName, flags))
|
||||||
{
|
{
|
||||||
|
if (this.Window.IsOpen != isWindowOpen)
|
||||||
|
{
|
||||||
|
this.Window.IsOpen = isWindowOpen;
|
||||||
|
}
|
||||||
|
|
||||||
var context = ImGui.GetCurrentContext();
|
var context = ImGui.GetCurrentContext();
|
||||||
if (!context.IsNull)
|
if (!context.IsNull)
|
||||||
{
|
{
|
||||||
ImGuiP.GetCurrentWindow().InheritNoInputs = this.internalIsClickthrough;
|
ImGuiP.GetCurrentWindow().InheritNoInputs = this.Window.IsClickthrough;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not supported yet on non-main viewports
|
// Not supported yet on non-main viewports
|
||||||
if ((this.internalIsPinned || this.internalIsClickthrough || this.internalAlpha.HasValue) &&
|
if ((this.Window.IsPinned || this.Window.IsClickthrough || this.internalAlpha.HasValue) &&
|
||||||
ImGui.GetWindowViewport().ID != ImGui.GetMainViewport().ID)
|
ImGui.GetWindowViewport().ID != ImGui.GetMainViewport().ID)
|
||||||
{
|
{
|
||||||
this.internalAlpha = null;
|
this.internalAlpha = null;
|
||||||
this.internalIsPinned = false;
|
this.Window.IsPinned = false;
|
||||||
this.internalIsClickthrough = false;
|
this.Window.IsClickthrough = false;
|
||||||
this.presetDirty = true;
|
this.presetDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the actual window contents
|
// Draw the actual window contents
|
||||||
try
|
if (this.hasError)
|
||||||
{
|
{
|
||||||
this.Window.Draw();
|
this.DrawErrorMessage();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
else
|
||||||
{
|
{
|
||||||
Log.Error(ex, "Error during Draw(): {WindowName}", this.Window.WindowName);
|
// Draw the actual window contents
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.Window.Draw();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Error during Draw(): {WindowName}", this.Window.WindowName);
|
||||||
|
|
||||||
|
this.hasError = true;
|
||||||
|
this.lastError = ex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -247,15 +265,15 @@ public class WindowHost
|
||||||
if (!isAvailable)
|
if (!isAvailable)
|
||||||
ImGui.BeginDisabled();
|
ImGui.BeginDisabled();
|
||||||
|
|
||||||
if (this.internalIsClickthrough)
|
if (this.Window.IsClickthrough)
|
||||||
ImGui.BeginDisabled();
|
ImGui.BeginDisabled();
|
||||||
|
|
||||||
if (this.Window.AllowPinning)
|
if (this.Window.AllowPinning)
|
||||||
{
|
{
|
||||||
var showAsPinned = this.internalIsPinned || this.internalIsClickthrough;
|
var showAsPinned = this.Window.IsPinned || this.Window.IsClickthrough;
|
||||||
if (ImGui.Checkbox(Loc.Localize("WindowSystemContextActionPin", "Pin Window"), ref showAsPinned))
|
if (ImGui.Checkbox(Loc.Localize("WindowSystemContextActionPin", "Pin Window"), ref showAsPinned))
|
||||||
{
|
{
|
||||||
this.internalIsPinned = showAsPinned;
|
this.Window.IsPinned = showAsPinned;
|
||||||
this.presetDirty = true;
|
this.presetDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -263,15 +281,17 @@ public class WindowHost
|
||||||
Loc.Localize("WindowSystemContextActionPinHint", "Pinned windows will not move or resize when you click and drag them, nor will they close when escape is pressed."));
|
Loc.Localize("WindowSystemContextActionPinHint", "Pinned windows will not move or resize when you click and drag them, nor will they close when escape is pressed."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.internalIsClickthrough)
|
if (this.Window.IsClickthrough)
|
||||||
ImGui.EndDisabled();
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
if (this.Window.AllowClickthrough)
|
if (this.Window.AllowClickthrough)
|
||||||
{
|
{
|
||||||
|
var isClickthrough = this.Window.IsClickthrough;
|
||||||
if (ImGui.Checkbox(
|
if (ImGui.Checkbox(
|
||||||
Loc.Localize("WindowSystemContextActionClickthrough", "Make clickthrough"),
|
Loc.Localize("WindowSystemContextActionClickthrough", "Make clickthrough"),
|
||||||
ref this.internalIsClickthrough))
|
ref isClickthrough))
|
||||||
{
|
{
|
||||||
|
this.Window.IsClickthrough = isClickthrough;
|
||||||
this.presetDirty = true;
|
this.presetDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -283,7 +303,7 @@ public class WindowHost
|
||||||
if (ImGui.SliderFloat(Loc.Localize("WindowSystemContextActionAlpha", "Opacity"), ref alpha, 20f,
|
if (ImGui.SliderFloat(Loc.Localize("WindowSystemContextActionAlpha", "Opacity"), ref alpha, 20f,
|
||||||
100f))
|
100f))
|
||||||
{
|
{
|
||||||
this.internalAlpha = alpha / 100f;
|
this.internalAlpha = Math.Clamp(alpha / 100f, 0.2f, 1f);
|
||||||
this.presetDirty = true;
|
this.presetDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -332,7 +352,7 @@ public class WindowHost
|
||||||
IconOffset = new Vector2(2.5f, 1),
|
IconOffset = new Vector2(2.5f, 1),
|
||||||
Click = _ =>
|
Click = _ =>
|
||||||
{
|
{
|
||||||
this.internalIsClickthrough = false;
|
this.Window.IsClickthrough = false;
|
||||||
this.presetDirty = false;
|
this.presetDirty = false;
|
||||||
ImGui.OpenPopup(additionsPopupName);
|
ImGui.OpenPopup(additionsPopupName);
|
||||||
},
|
},
|
||||||
|
|
@ -356,7 +376,7 @@ public class WindowHost
|
||||||
|
|
||||||
this.Window.IsFocused = ImGui.IsWindowFocused(ImGuiFocusedFlags.RootAndChildWindows);
|
this.Window.IsFocused = ImGui.IsWindowFocused(ImGuiFocusedFlags.RootAndChildWindows);
|
||||||
|
|
||||||
if (internalDrawFlags.HasFlag(WindowDrawFlags.UseFocusManagement) && !this.internalIsPinned)
|
if (internalDrawFlags.HasFlag(WindowDrawFlags.UseFocusManagement) && !this.Window.IsPinned)
|
||||||
{
|
{
|
||||||
var escapeDown = Service<KeyState>.Get()[VirtualKey.ESCAPE];
|
var escapeDown = Service<KeyState>.Get()[VirtualKey.ESCAPE];
|
||||||
if (escapeDown && this.Window.IsFocused && !wasEscPressedLastFrame && this.Window.RespectCloseHotkey)
|
if (escapeDown && this.Window.IsFocused && !wasEscPressedLastFrame && this.Window.RespectCloseHotkey)
|
||||||
|
|
@ -388,10 +408,11 @@ public class WindowHost
|
||||||
// easier with the new bindings.
|
// easier with the new bindings.
|
||||||
// TODO: No fade-out if docking is enabled and the window is docked, since this makes them "unsnap".
|
// TODO: No fade-out if docking is enabled and the window is docked, since this makes them "unsnap".
|
||||||
// Ideally we should get rid of this "fake window" thing and just insert a new drawlist at the correct spot.
|
// Ideally we should get rid of this "fake window" thing and just insert a new drawlist at the correct spot.
|
||||||
if (!this.internalIsOpen && this.fadeOutTexture == null && doFades && !isCollapsed && !isDocked)
|
if (!this.Window.IsOpen && this.fadeOutTexture == null && doFades && !isCollapsed && !isDocked)
|
||||||
{
|
{
|
||||||
this.fadeOutTexture = Service<TextureManager>.Get().CreateDrawListTexture(
|
this.fadeOutTexture = Service<TextureManager>.Get().CreateDrawListTexture(
|
||||||
"WindowFadeOutTexture");
|
"WindowFadeOutTexture");
|
||||||
|
Log.Verbose("Attempting to fade out {WindowName}", this.Window.WindowName);
|
||||||
this.fadeOutTexture.ResizeAndDrawWindow(this.Window.WindowName, Vector2.One);
|
this.fadeOutTexture.ResizeAndDrawWindow(this.Window.WindowName, Vector2.One);
|
||||||
this.fadeOutTimer = FadeInOutTime;
|
this.fadeOutTimer = FadeInOutTime;
|
||||||
}
|
}
|
||||||
|
|
@ -498,8 +519,8 @@ public class WindowHost
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.internalIsPinned = this.presetWindow.IsPinned;
|
this.Window.IsPinned = this.presetWindow.IsPinned;
|
||||||
this.internalIsClickthrough = this.presetWindow.IsClickThrough;
|
this.Window.IsClickthrough = this.presetWindow.IsClickThrough;
|
||||||
this.internalAlpha = this.presetWindow.Alpha;
|
this.internalAlpha = this.presetWindow.Alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -512,8 +533,8 @@ public class WindowHost
|
||||||
|
|
||||||
if (this.presetDirty)
|
if (this.presetDirty)
|
||||||
{
|
{
|
||||||
this.presetWindow.IsPinned = this.internalIsPinned;
|
this.presetWindow.IsPinned = this.Window.IsPinned;
|
||||||
this.presetWindow.IsClickThrough = this.internalIsClickthrough;
|
this.presetWindow.IsClickThrough = this.Window.IsClickthrough;
|
||||||
this.presetWindow.Alpha = this.internalAlpha;
|
this.presetWindow.Alpha = this.internalAlpha;
|
||||||
|
|
||||||
var id = ImGui.GetID(this.Window.WindowName);
|
var id = ImGui.GetID(this.Window.WindowName);
|
||||||
|
|
@ -563,7 +584,7 @@ public class WindowHost
|
||||||
bool hovered, held;
|
bool hovered, held;
|
||||||
var pressed = false;
|
var pressed = false;
|
||||||
|
|
||||||
if (this.internalIsClickthrough)
|
if (this.Window.IsClickthrough)
|
||||||
{
|
{
|
||||||
hovered = false;
|
hovered = false;
|
||||||
held = false;
|
held = false;
|
||||||
|
|
@ -602,7 +623,7 @@ public class WindowHost
|
||||||
button.ShowTooltip?.Invoke();
|
button.ShowTooltip?.Invoke();
|
||||||
|
|
||||||
// Switch to moving the window after mouse is moved beyond the initial drag threshold
|
// Switch to moving the window after mouse is moved beyond the initial drag threshold
|
||||||
if (ImGui.IsItemActive() && ImGui.IsMouseDragging(ImGuiMouseButton.Left) && !this.internalIsClickthrough)
|
if (ImGui.IsItemActive() && ImGui.IsMouseDragging(ImGuiMouseButton.Left) && !this.Window.IsClickthrough)
|
||||||
ImGuiP.StartMouseMovingWindow(window);
|
ImGuiP.StartMouseMovingWindow(window);
|
||||||
|
|
||||||
return pressed;
|
return pressed;
|
||||||
|
|
@ -610,7 +631,7 @@ public class WindowHost
|
||||||
|
|
||||||
foreach (var button in buttons.OrderBy(x => x.Priority))
|
foreach (var button in buttons.OrderBy(x => x.Priority))
|
||||||
{
|
{
|
||||||
if (this.internalIsClickthrough && !button.AvailableClickthrough)
|
if (this.Window.IsClickthrough && !button.AvailableClickthrough)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Vector2 position = new(titleBarRect.Max.X - padR - buttonSize, titleBarRect.Min.Y + style.FramePadding.Y);
|
Vector2 position = new(titleBarRect.Max.X - padR - buttonSize, titleBarRect.Min.Y + style.FramePadding.Y);
|
||||||
|
|
@ -651,4 +672,50 @@ public class WindowHost
|
||||||
|
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawErrorMessage()
|
||||||
|
{
|
||||||
|
// TODO: Once window systems are services, offer to reload the plugin
|
||||||
|
ImGui.TextColoredWrapped(ImGuiColors.DalamudRed,Loc.Localize("WindowSystemErrorOccurred", "An error occurred while rendering this window. Please contact the developer for details."));
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(5);
|
||||||
|
|
||||||
|
if (ImGui.Button(Loc.Localize("WindowSystemErrorRecoverButton", "Attempt to retry")))
|
||||||
|
{
|
||||||
|
this.hasError = false;
|
||||||
|
this.lastError = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGui.Button(Loc.Localize("WindowSystemErrorClose", "Close Window")))
|
||||||
|
{
|
||||||
|
this.Window.IsOpen = false;
|
||||||
|
this.hasError = false;
|
||||||
|
this.lastError = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(10);
|
||||||
|
|
||||||
|
if (this.lastError != null)
|
||||||
|
{
|
||||||
|
using var child = ImRaii.Child("##ErrorDetails", new Vector2(0, 200 * ImGuiHelpers.GlobalScale), true);
|
||||||
|
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudGrey))
|
||||||
|
{
|
||||||
|
ImGui.TextWrapped(Loc.Localize("WindowSystemErrorDetails", "Error Details:"));
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.TextWrapped(this.lastError.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
var childWindowSize = ImGui.GetWindowSize();
|
||||||
|
var copyText = Loc.Localize("WindowSystemErrorCopy", "Copy");
|
||||||
|
var buttonWidth = ImGuiComponents.GetIconButtonWithTextWidth(FontAwesomeIcon.Copy, copyText);
|
||||||
|
ImGui.SetCursorPos(new Vector2(childWindowSize.X - buttonWidth - ImGui.GetStyle().FramePadding.X,
|
||||||
|
ImGui.GetStyle().FramePadding.Y));
|
||||||
|
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Copy, copyText))
|
||||||
|
{
|
||||||
|
ImGui.SetClipboardText(this.lastError.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue