Files
HSMappy/Mappy/Windows/MinimapWindow.cs
T
2026-02-26 03:54:51 -05:00

128 lines
5.3 KiB
C#

using System;
using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.Utility.Raii;
using KamiLib.Window;
using Mappy.Controllers;
using Mappy.Data;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
namespace Mappy.Windows;
public class MinimapWindow : Window
{
public MinimapWindow() : base("HSMappy Minimap###HSMappyMinimap", new Vector2(200.0f, 200.0f))
{
DisableWindowSounds = true;
Flags |= ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoScrollWithMouse;
}
public override bool DrawConditions() =>
IntegrationsController.ShouldShowMinimap() && System.SystemConfig.ShowMinimap;
public override void PreOpenCheck()
{
if (Service.ClientState is { IsLoggedIn: false } or { IsPvP: true })
IsOpen = false;
}
protected override unsafe void DrawContents()
{
var agent = AgentMap.Instance();
// Try loading from Lumina first so minimap can show without ever opening the area map
if (!System.MapRenderer.HasMinimapCacheFor(agent->CurrentMapId) && agent->SelectedMapId != agent->CurrentMapId)
System.MapRenderer.TryEnsureLuminaCacheFor(agent->CurrentMapId);
var mapLoaded = agent->SelectedMapId == agent->CurrentMapId || System.MapRenderer.HasMinimapCacheFor(agent->CurrentMapId);
if (!mapLoaded)
{
// Map data could not be loaded for this area (no Lumina path matched). Minimap shows automatically when data is available.
const string hint = "Map unavailable for this area.";
var textSize = ImGui.CalcTextSize(hint);
var pos = (ImGui.GetWindowSize() - textSize) * 0.5f;
ImGui.SetCursorPos(new Vector2(Math.Max(0, pos.X), Math.Max(20, pos.Y)));
ImGui.TextColored(new Vector4(0.7f, 0.7f, 0.7f, 0.9f), hint);
UpdateStyle();
UpdateSizePosition();
return;
}
UpdateStyle();
UpdateSizePosition();
// Compensate for window padding: draw the minimap child so it fills the full window (no black bands).
var padding = ImGui.GetStyle().WindowPadding;
var winSize = ImGui.GetWindowSize();
ImGui.SetCursorPos(new Vector2(-padding.X, -padding.Y));
var contentSize = winSize;
if (contentSize.X <= 0 || contentSize.Y <= 0) return;
using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, System.SystemConfig.MinimapOpacity))
using (ImRaii.PushStyle(ImGuiStyleVar.ChildBorderSize, 0f))
using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, Vector2.Zero))
using (var child = ImRaii.Child("minimap_render", contentSize, false, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse))
{
if (child) {
// Use window size so map fills the full window; renderer clamps draw position so map always covers the view.
System.MapRenderer.DrawMinimapContents(contentSize);
// Mouse wheel over minimap: zoom in/out, and consume wheel so the window doesn't scroll
if (ImGui.IsItemHovered()) {
var io = ImGui.GetIO();
var wheel = io.MouseWheel;
if (wheel != 0) {
var zoom = System.SystemConfig.MinimapZoom;
zoom -= wheel * 0.012f; // Small step so zoom is incremental between max out (0.1) and max in (0.03)
System.SystemConfig.MinimapZoom = Math.Clamp(zoom, 0.03f, 0.112f);
SystemConfig.Save();
}
// Consume wheel so the window doesn't scroll when at min/max zoom or when we handled it
io.MouseWheel = 0f;
io.MouseWheelH = 0f;
}
}
}
// Restore default padding for the next window is done in plugin Draw callback (PopStyleVar after all windows).
}
public override void OnOpen()
{
ImGui.SetWindowPos(System.SystemConfig.MinimapPosition);
ImGui.SetWindowSize(new Vector2(System.SystemConfig.MinimapSize, System.SystemConfig.MinimapSize));
}
private void UpdateStyle()
{
if (System.SystemConfig.MinimapLockPosition)
Flags |= ImGuiWindowFlags.NoMove;
else
Flags &= ~ImGuiWindowFlags.NoMove;
}
private void UpdateSizePosition()
{
var config = System.SystemConfig;
var windowPosition = ImGui.GetWindowPos();
var windowSize = ImGui.GetWindowSize();
var configSize = config.MinimapSize;
// Size is config-only (set in Mappy settings); always apply config size to window.
if (Math.Abs(windowSize.X - configSize) > 0.1f || Math.Abs(windowSize.Y - configSize) > 0.1f)
ImGui.SetWindowSize(new Vector2(configSize, configSize));
if (!ImGui.IsWindowFocused(ImGuiFocusedFlags.RootAndChildWindows)) {
// Not focused: apply config position to window
if (windowPosition != config.MinimapPosition)
ImGui.SetWindowPos(config.MinimapPosition);
} else {
// Focused: save window position to config (size is changed only via settings)
if (config.MinimapPosition != windowPosition) {
config.MinimapPosition = windowPosition;
SystemConfig.Save();
}
}
}
}