diff --git a/Mappy/Classes/DrawHelpers.cs b/Mappy/Classes/DrawHelpers.cs
index f79acf4..9b3fb36 100644
--- a/Mappy/Classes/DrawHelpers.cs
+++ b/Mappy/Classes/DrawHelpers.cs
@@ -38,6 +38,9 @@ public static class DrawHelpers
public const uint QuestionMarkIcon = 60071;
+ /// Sentinel IconId for user-placed map notes (custom-drawn white page with writing).
+ public const uint MapNoteIconId = 65000;
+
///
/// Offset Vector of SelectedX, SelectedY, scaled with SelectedSizeFactor
///
@@ -143,9 +146,7 @@ public static class DrawHelpers
private static void DrawIcon(MarkerInfo markerInfo)
{
- var texture = Service.TextureProvider.GetFromGameIcon(markerInfo.IconId).GetWrapOrEmpty();
var scale = System.SystemConfig.ScaleWithZoom ? markerInfo.Scale : 1.0f;
-
var iconScale = System.SystemConfig.IconScale;
if (markerInfo.IconId is 60401 or 60402) {
@@ -158,11 +159,27 @@ public static class DrawHelpers
iconScale = 0.42f;
}
- ImGui.SetCursorPos(markerInfo.Position + markerInfo.Offset - texture.Size * iconScale / 2.0f * scale * System.IconConfig.IconSettingMap[markerInfo.IconId].Scale);
- var cursorScreenPos = ImGui.GetCursorScreenPos();
- var iconSize = texture.Size * scale * iconScale * System.IconConfig.IconSettingMap[markerInfo.IconId].Scale;
+ var setting = System.IconConfig.IconSettingMap[markerInfo.IconId];
+ var sizeMultiplier = scale * iconScale * setting.Scale;
- ImGui.Image(texture.Handle, iconSize, Vector2.Zero, Vector2.One, System.IconConfig.IconSettingMap[markerInfo.IconId].Color);
+ Vector2 iconSize;
+ Vector2 cursorScreenPos;
+
+ if (markerInfo.IconId == MapNoteIconId) {
+ // Custom-drawn white page with writing icon (roughly 24x30 aspect)
+ iconSize = new Vector2(20f, 26f) * sizeMultiplier;
+ ImGui.SetCursorPos(markerInfo.Position + markerInfo.Offset - iconSize / 2f);
+ cursorScreenPos = ImGui.GetCursorScreenPos();
+ ImGui.InvisibleButton($"mapnote_{markerInfo.Position.X}_{markerInfo.Position.Y}", iconSize);
+ DrawMapNoteIcon(cursorScreenPos, iconSize, setting.Color);
+ }
+ else {
+ var texture = Service.TextureProvider.GetFromGameIcon(markerInfo.IconId).GetWrapOrEmpty();
+ iconSize = texture.Size * sizeMultiplier;
+ ImGui.SetCursorPos(markerInfo.Position + markerInfo.Offset - iconSize / 2f);
+ cursorScreenPos = ImGui.GetCursorScreenPos();
+ ImGui.Image(texture.Handle, iconSize, Vector2.Zero, Vector2.One, setting.Color);
+ }
if (DebugMode) {
foreach (var x in Enumerable.Range(-1, 3)) {
@@ -241,7 +258,14 @@ public static class DrawHelpers
if (markerInfo.PrimaryText?.Invoke() is { Length: > 0 } primaryText) {
using var tooltip = ImRaii.Tooltip();
- ImGui.Image(Service.TextureProvider.GetFromGameIcon(markerInfo.IconId).GetWrapOrEmpty().Handle, ImGuiHelpers.ScaledVector2(32.0f, 32.0f));
+ if (markerInfo.IconId == MapNoteIconId) {
+ var iconSize = ImGuiHelpers.ScaledVector2(24f, 31f);
+ DrawMapNoteIcon(ImGui.GetCursorScreenPos(), iconSize, Vector4.One);
+ ImGui.Dummy(iconSize);
+ }
+ else {
+ ImGui.Image(Service.TextureProvider.GetFromGameIcon(markerInfo.IconId).GetWrapOrEmpty().Handle, ImGuiHelpers.ScaledVector2(32.0f, 32.0f));
+ }
ImGui.SameLine();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 7.5f * ImGuiHelpers.GlobalScale);
@@ -257,6 +281,34 @@ public static class DrawHelpers
}
}
+ /// Draw a custom "white page with writing" icon for map notes, centered at the given position.
+ public static void DrawMapNoteIconCentered(Vector2 center, Vector2 size, Vector4 tint) =>
+ DrawMapNoteIcon(center - size * 0.5f, size, tint);
+
+ /// Draw a custom "white page with writing" icon for map notes.
+ private static void DrawMapNoteIcon(Vector2 topLeft, Vector2 size, Vector4 tint)
+ {
+ var drawList = ImGui.GetWindowDrawList();
+ var p1 = topLeft;
+ var p2 = topLeft + size;
+ var rounding = MathF.Min(size.X * 0.15f, size.Y * 0.12f);
+ var white = ImGui.GetColorU32(new Vector4(0.98f, 0.98f, 0.96f, tint.W));
+ var border = ImGui.GetColorU32(new Vector4(0.7f, 0.7f, 0.65f, tint.W));
+ var writing = ImGui.GetColorU32(new Vector4(0.25f, 0.22f, 0.2f, tint.W));
+ var padding = size * 0.12f;
+ var lineHeight = (size.Y - padding.Y * 2f) / 4f;
+ var lineLeft = p1.X + padding.X;
+ var lineRight = p2.X - padding.X;
+
+ drawList.AddRectFilled(p1, p2, white, rounding);
+ drawList.AddRect(p1, p2, border, rounding, 0, 1.2f);
+ for (var i = 0; i < 3; i++) {
+ var y = p1.Y + padding.Y + lineHeight * (i + 0.5f);
+ var w = (i == 1 ? 0.9f : 0.7f) * (lineRight - lineLeft);
+ drawList.AddLine(new Vector2(lineLeft, y), new Vector2(lineLeft + w, y), writing, 1.5f);
+ }
+ }
+
public static bool IsDisallowedIcon(uint iconId) =>
iconId switch
{
diff --git a/Mappy/Classes/MapWindowComponents/MapContextMenu.cs b/Mappy/Classes/MapWindowComponents/MapContextMenu.cs
index 6b5e7a0..e368804 100644
--- a/Mappy/Classes/MapWindowComponents/MapContextMenu.cs
+++ b/Mappy/Classes/MapWindowComponents/MapContextMenu.cs
@@ -1,4 +1,4 @@
-using System.Numerics;
+using System.Numerics;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
@@ -17,14 +17,26 @@ public unsafe class MapContextMenu
if (!contextMenu) return;
- if (ImGui.MenuItem("Place Flag")) {
- var cursorPosition = ImGui.GetMousePosOnOpeningCurrentPopup(); // Get initial cursor position (screen relative)
- var mapChildOffset = mapDrawOffset; // Get the screen position we started drawing the map at
- var mapDrawPositionOffset = System.MapRenderer.DrawPosition; // Get the map texture top left offset vector
- var textureClickLocation = (cursorPosition - mapChildOffset - mapDrawPositionOffset) / MapRenderer.MapRenderer.Scale; // Math
- var result = textureClickLocation - new Vector2(1024.0f, 1024.0f); // One of our vectors made the map centered, undo it.
- var scaledResult = result / DrawHelpers.GetMapScaleFactor() + DrawHelpers.GetRawMapOffsetVector(); // Apply offset x/y and scalefactor
+ var cursorPosition = ImGui.GetMousePosOnOpeningCurrentPopup();
+ var textureClickLocation = (cursorPosition - mapDrawOffset - System.MapRenderer.DrawPosition) / MapRenderer.MapRenderer.Scale;
+ var result = textureClickLocation - new Vector2(1024.0f, 1024.0f);
+ var scaledResult = result / DrawHelpers.GetMapScaleFactor() + DrawHelpers.GetRawMapOffsetVector();
+ var noteAtCursor = System.MapNoteConfig.FindNoteAt(
+ AgentMap.Instance()->SelectedTerritoryId, AgentMap.Instance()->SelectedMapId, scaledResult.X, scaledResult.Y);
+ if (ImGui.MenuItem("Place Note")) {
+ MapWindow.PendingMapNotePosition = (AgentMap.Instance()->SelectedTerritoryId, AgentMap.Instance()->SelectedMapId, scaledResult.X, scaledResult.Y);
+ MapWindow.RequestOpenAddNotePopup();
+ }
+
+ if (ImGui.MenuItem("Remove Note", false, noteAtCursor is not null)) {
+ if (noteAtCursor is { } note) {
+ System.MapNoteConfig.Notes.Remove(note);
+ System.MapNoteConfig.Save();
+ }
+ }
+
+ if (ImGui.MenuItem("Place Flag")) {
AgentMap.Instance()->FlagMarkerCount = 0;
AgentMap.Instance()->SetFlagMapMarker(AgentMap.Instance()->SelectedTerritoryId, AgentMap.Instance()->SelectedMapId, scaledResult.X, scaledResult.Y);
AgentChatLog.Instance()->InsertTextCommandParam(1048, false);
@@ -65,5 +77,9 @@ public unsafe class MapContextMenu
if (ImGui.MenuItem("Open Flag List", false, System.WindowManager.GetWindow() is null)) {
System.WindowManager.AddWindow(new FlagHistoryWindow(), WindowFlags.OpenImmediately | WindowFlags.RequireLoggedIn);
}
+
+ if (ImGui.MenuItem("Open Note List", false, System.WindowManager.GetWindow() is null)) {
+ System.WindowManager.AddWindow(new MapNoteListWindow(), WindowFlags.OpenImmediately | WindowFlags.RequireLoggedIn);
+ }
}
}
\ No newline at end of file
diff --git a/Mappy/Data/MapNoteConfig.cs b/Mappy/Data/MapNoteConfig.cs
new file mode 100644
index 0000000..0ba073c
--- /dev/null
+++ b/Mappy/Data/MapNoteConfig.cs
@@ -0,0 +1,70 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using Dalamud.Interface.Textures.TextureWraps;
+using FFXIVClientStructs.FFXIV.Client.UI.Agent;
+using KamiLib.Configuration;
+using Lumina.Excel.Sheets;
+using Mappy.Classes.SelectionWindowComponents;
+
+namespace Mappy.Data;
+
+public unsafe record MapNote(uint Territory, uint Map, float X, float Y, string Title, string Description)
+{
+ public IDalamudTextureWrap? GetMapTexture() => MapDrawableOption.GetMapTexture(Map);
+
+ public Map GetMap() => Service.DataManager.GetExcelSheet