v1.0.0.13: User-placed map notes with Title/Description; custom icon; notes on minimap

Made-with: Cursor
This commit is contained in:
2026-03-01 00:12:37 -05:00
parent b1c833ebcf
commit 542da3a71b
12 changed files with 383 additions and 17 deletions
+105
View File
@@ -0,0 +1,105 @@
using System.Collections.Immutable;
using System.Drawing;
using System.Linq;
using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using KamiLib.Window;
using Mappy.Data;
namespace Mappy.Windows;
public class MapNoteListWindow : Window
{
private static float NoteElementHeight => 95.0f * ImGuiHelpers.GlobalScale;
public MapNoteListWindow() : base("HSMappy Note List Window", new Vector2(400.0f, 400.0f))
{
AdditionalInfoTooltip = "Shows user-placed map notes for the current map";
}
protected override unsafe void DrawContents()
{
var agent = AgentMap.Instance();
var territoryId = agent->SelectedTerritoryId;
var mapId = agent->SelectedMapId;
var notesForMap = System.MapNoteConfig.Notes
.Where(n => n.Territory == territoryId && n.Map == mapId)
.ToImmutableList();
ImGuiClip.ClippedDraw(notesForMap, DrawNote, NoteElementHeight);
}
private void DrawNote(MapNote note)
{
using var id = ImRaii.PushId(note.GetIdString());
using (ImRaii.Child("note_container", new Vector2(ImGui.GetContentRegionAvail().X, NoteElementHeight - ImGui.GetStyle().FramePadding.Y * 2.0f))) {
using (ImRaii.Child("note_image_container", new Vector2(155.0f * ImGuiHelpers.GlobalScale, ImGui.GetContentRegionAvail().Y))) {
DrawNoteImage(note);
}
ImGui.SameLine();
using (ImRaii.Child("note_contents_container", ImGui.GetContentRegionAvail())) {
var buttonHeight = 28f * ImGuiHelpers.GlobalScale;
var textHeight = ImGui.GetContentRegionAvail().Y - buttonHeight;
using (ImRaii.Child("note_text_area", new Vector2(ImGui.GetContentRegionAvail().X, textHeight))) {
DrawNoteData(note);
}
DrawButtons(note);
}
}
ImGui.Spacing();
}
private void DrawNoteImage(MapNote note)
{
var texture = note.GetMapTexture();
if (texture is not null) {
ImGui.Image(texture.Handle, ImGui.GetContentRegionAvail(), new Vector2(0.15f, 0.15f), new Vector2(0.85f, 0.85f));
}
else {
ImGuiHelpers.ScaledDummy(ImGui.GetContentRegionAvail());
}
}
private void DrawNoteData(MapNote note)
{
ImGui.TextUnformatted(note.Title ?? "");
if (!string.IsNullOrWhiteSpace(note.Description)) {
ImGui.TextColored(KnownColor.Gray.Vector().Lighten(0.20f), note.Description);
}
ImGui.TextColored(KnownColor.Gray.Vector().Lighten(0.20f), note.GetMap().PlaceName.Value.Name.ExtractText());
var coord = note.GetMapCoordinate();
var zoneName = note.GetTerritoryType().PlaceNameZone.Value.Name.ExtractText();
ImGui.TextColored(KnownColor.Gray.Vector(), $"{zoneName} • {coord.X:F1}, {coord.Y:F1}");
}
private void DrawButtons(MapNote note)
{
var buttonSize = ImGuiHelpers.ScaledVector2(80.0f, 24.0f);
ImGui.SetCursorPos(new Vector2(0.0f, ImGui.GetContentRegionMax().Y - buttonSize.Y));
if (ImGui.Button("Focus", buttonSize)) {
note.Focus();
}
ImGui.SameLine();
if (ImGui.Button("Remove", buttonSize)) {
System.MapNoteConfig.Notes.Remove(note);
System.MapNoteConfig.Save();
}
}
public override void OnClose()
{
System.WindowManager.RemoveWindow(this);
}
}
+50
View File
@@ -22,6 +22,13 @@ namespace Mappy.Windows;
public class MapWindow : Window
{
public static (uint Territory, uint Map, float X, float Y)? PendingMapNotePosition;
private static string _pendingNoteTitle = string.Empty;
private static string _pendingNoteDescription = string.Empty;
private static bool _requestOpenAddNotePopup;
public static void RequestOpenAddNotePopup() => _requestOpenAddNotePopup = true;
public Vector2 MapDrawOffset { get; private set; }
public HoverFlags HoveredFlags { get; private set; }
public bool ProcessingCommand { get; set; }
@@ -243,6 +250,49 @@ public class MapWindow : Window
// Draw Context Menu
mapContextMenu.Draw(MapDrawOffset);
DrawAddMapNotePopup();
}
private static void DrawAddMapNotePopup()
{
if (_requestOpenAddNotePopup) {
ImGui.OpenPopup("AddMapNote");
_requestOpenAddNotePopup = false;
}
if (!ImGui.BeginPopup("AddMapNote")) return;
ImGui.Text("Note Title:");
ImGui.SetNextItemWidth(250f * ImGuiHelpers.GlobalScale);
ImGui.InputText("##notetitle", ref _pendingNoteTitle, 256);
ImGui.Text("Note Description:");
ImGui.SetNextItemWidth(250f * ImGuiHelpers.GlobalScale);
ImGui.InputText("##notedesc", ref _pendingNoteDescription, 512);
if (ImGui.Button("Cancel")) {
PendingMapNotePosition = null;
_pendingNoteTitle = string.Empty;
_pendingNoteDescription = string.Empty;
ImGui.CloseCurrentPopup();
}
ImGui.SameLine();
if (ImGui.Button("Add")) {
if (PendingMapNotePosition is { } pos && !string.IsNullOrWhiteSpace(_pendingNoteTitle)) {
System.MapNoteConfig.Notes.Add(new MapNote(pos.Territory, pos.Map, pos.X, pos.Y, _pendingNoteTitle.Trim(), _pendingNoteDescription?.Trim() ?? ""));
if (System.MapNoteConfig.Notes.Count > System.MapNoteConfig.MaxNotes) {
System.MapNoteConfig.Notes.RemoveAt(0);
}
System.MapNoteConfig.Save();
}
PendingMapNotePosition = null;
_pendingNoteTitle = string.Empty;
_pendingNoteDescription = string.Empty;
ImGui.CloseCurrentPopup();
}
ImGui.EndPopup();
}
private unsafe void UpdateStyle()