feat: add channel switcher, settings button, better tooltips
This commit is contained in:
@@ -1,8 +1,7 @@
|
|||||||
namespace ChatTwo.Code;
|
namespace ChatTwo.Code;
|
||||||
|
|
||||||
internal static class InputChannelExt {
|
internal static class InputChannelExt {
|
||||||
internal static ChatType ToChatType(this InputChannel input) {
|
internal static ChatType ToChatType(this InputChannel input) => input switch {
|
||||||
return input switch {
|
|
||||||
InputChannel.Tell => ChatType.TellOutgoing,
|
InputChannel.Tell => ChatType.TellOutgoing,
|
||||||
InputChannel.Say => ChatType.Say,
|
InputChannel.Say => ChatType.Say,
|
||||||
InputChannel.Party => ChatType.Party,
|
InputChannel.Party => ChatType.Party,
|
||||||
@@ -30,5 +29,24 @@ internal static class InputChannelExt {
|
|||||||
InputChannel.Linkshell8 => ChatType.Linkshell8,
|
InputChannel.Linkshell8 => ChatType.Linkshell8,
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(input), input, null),
|
_ => throw new ArgumentOutOfRangeException(nameof(input), input, null),
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
public static uint LinkshellIndex(this InputChannel channel) => channel switch {
|
||||||
|
InputChannel.Linkshell1 => 0,
|
||||||
|
InputChannel.Linkshell2 => 1,
|
||||||
|
InputChannel.Linkshell3 => 2,
|
||||||
|
InputChannel.Linkshell4 => 3,
|
||||||
|
InputChannel.Linkshell5 => 4,
|
||||||
|
InputChannel.Linkshell6 => 5,
|
||||||
|
InputChannel.Linkshell7 => 6,
|
||||||
|
InputChannel.Linkshell8 => 7,
|
||||||
|
InputChannel.CrossLinkshell1 => 0,
|
||||||
|
InputChannel.CrossLinkshell2 => 1,
|
||||||
|
InputChannel.CrossLinkshell3 => 2,
|
||||||
|
InputChannel.CrossLinkshell4 => 3,
|
||||||
|
InputChannel.CrossLinkshell5 => 4,
|
||||||
|
InputChannel.CrossLinkshell6 => 5,
|
||||||
|
InputChannel.CrossLinkshell7 => 6,
|
||||||
|
InputChannel.CrossLinkshell8 => 7,
|
||||||
|
_ => uint.MaxValue,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
using ChatTwo.Code;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using ChatTwo.Code;
|
||||||
|
using ChatTwo.Util;
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
using Dalamud.Memory;
|
using Dalamud.Memory;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.System.String;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI.Shell;
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
|
||||||
namespace ChatTwo;
|
namespace ChatTwo;
|
||||||
@@ -13,21 +18,25 @@ internal unsafe class GameFunctions : IDisposable {
|
|||||||
private static class Signatures {
|
private static class Signatures {
|
||||||
internal const string ChatLogRefresh = "40 53 56 57 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 49 8B F0 8B FA";
|
internal const string ChatLogRefresh = "40 53 56 57 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 49 8B F0 8B FA";
|
||||||
internal const string ChangeChannelName = "E8 ?? ?? ?? ?? BA ?? ?? ?? ?? 48 8D 4D B0 48 8B F8 E8 ?? ?? ?? ?? 41 8B D6";
|
internal const string ChangeChannelName = "E8 ?? ?? ?? ?? BA ?? ?? ?? ?? 48 8D 4D B0 48 8B F8 E8 ?? ?? ?? ?? 41 8B D6";
|
||||||
|
internal const string ChangeChatChannel = "E8 ?? ?? ?? ?? 0F B7 44 37 ??";
|
||||||
}
|
}
|
||||||
|
|
||||||
private delegate byte ChatLogRefreshDelegate(IntPtr log, ushort eventId, AtkValue* value);
|
private delegate byte ChatLogRefreshDelegate(IntPtr log, ushort eventId, AtkValue* value);
|
||||||
|
|
||||||
private delegate IntPtr ChangeChannelNameDelegate(IntPtr agent);
|
private delegate IntPtr ChangeChannelNameDelegate(IntPtr agent);
|
||||||
|
|
||||||
|
private delegate IntPtr ChangeChatChannelDelegate(RaptureShellModule* shell, int channel, uint linkshellIdx, Utf8String* tellTarget, byte one);
|
||||||
|
|
||||||
internal delegate void ChatActivatedEventDelegate(string? input);
|
internal delegate void ChatActivatedEventDelegate(string? input);
|
||||||
|
|
||||||
private Plugin Plugin { get; }
|
private Plugin Plugin { get; }
|
||||||
private Hook<ChatLogRefreshDelegate>? ChatLogRefreshHook { get; }
|
private Hook<ChatLogRefreshDelegate>? ChatLogRefreshHook { get; }
|
||||||
private Hook<ChangeChannelNameDelegate>? ChangeChannelNameHook { get; }
|
private Hook<ChangeChannelNameDelegate>? ChangeChannelNameHook { get; }
|
||||||
|
private readonly ChangeChatChannelDelegate? _changeChatChannel;
|
||||||
|
|
||||||
internal event ChatActivatedEventDelegate? ChatActivated;
|
internal event ChatActivatedEventDelegate? ChatActivated;
|
||||||
|
|
||||||
internal (InputChannel channel, string name) ChatChannel { get; private set; }
|
internal (InputChannel channel, List<Chunk> name) ChatChannel { get; private set; }
|
||||||
|
|
||||||
internal GameFunctions(Plugin plugin) {
|
internal GameFunctions(Plugin plugin) {
|
||||||
this.Plugin = plugin;
|
this.Plugin = plugin;
|
||||||
@@ -42,6 +51,10 @@ internal unsafe class GameFunctions : IDisposable {
|
|||||||
this.ChangeChannelNameHook.Enable();
|
this.ChangeChannelNameHook.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.Plugin.SigScanner.TryScanText(Signatures.ChangeChatChannel, out var changeChannelPtr)) {
|
||||||
|
this._changeChatChannel = Marshal.GetDelegateForFunctionPointer<ChangeChatChannelDelegate>(changeChannelPtr);
|
||||||
|
}
|
||||||
|
|
||||||
this.Plugin.ClientState.Login += this.Login;
|
this.Plugin.ClientState.Login += this.Login;
|
||||||
this.Login(null, null);
|
this.Login(null, null);
|
||||||
}
|
}
|
||||||
@@ -66,6 +79,23 @@ internal unsafe class GameFunctions : IDisposable {
|
|||||||
this.ChangeChannelNameDetour((IntPtr) agent);
|
this.ChangeChannelNameDetour((IntPtr) agent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void SetChatChannel(InputChannel channel, string? tellTarget = null) {
|
||||||
|
if (this._changeChatChannel == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(tellTarget ?? "");
|
||||||
|
var target = new Utf8String();
|
||||||
|
fixed (byte* tellTargetPtr = bytes) {
|
||||||
|
var zero = stackalloc byte[1];
|
||||||
|
zero[0] = 0;
|
||||||
|
|
||||||
|
target.StringPtr = tellTargetPtr == null ? zero : tellTargetPtr;
|
||||||
|
target.StringLength = bytes.Length;
|
||||||
|
this._changeChatChannel(RaptureShellModule.Instance, (int) (channel + 1), channel.LinkshellIndex(), &target, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal static void SetAddonInteractable(string name, bool interactable) {
|
internal static void SetAddonInteractable(string name, bool interactable) {
|
||||||
var unitManager = AtkStage.GetSingleton()->RaptureAtkUnitManager;
|
var unitManager = AtkStage.GetSingleton()->RaptureAtkUnitManager;
|
||||||
|
|
||||||
@@ -217,7 +247,12 @@ internal unsafe class GameFunctions : IDisposable {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ChatChannel = ((InputChannel) channel, name.TextValue.TrimStart('\uE01E').Trim());
|
var nameChunks = ChunkUtil.ToChunks(name, null).ToList();
|
||||||
|
if (nameChunks.Count > 0 && nameChunks[0] is TextChunk text) {
|
||||||
|
text.Content = text.Content.TrimStart('\uE01E').TrimStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ChatChannel = ((InputChannel) channel, nameChunks);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Dalamud.Game.Text.SeStringHandling.Payloads;
|
|||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
using ImGuiScene;
|
||||||
|
|
||||||
namespace ChatTwo;
|
namespace ChatTwo;
|
||||||
|
|
||||||
@@ -109,7 +110,20 @@ internal sealed class PayloadHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void InlineIcon(TextureWrap icon) {
|
||||||
|
var lineHeight = ImGui.CalcTextSize("A").Y;
|
||||||
|
|
||||||
|
var cursor = ImGui.GetCursorPos();
|
||||||
|
ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height));
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.SetCursorPos(cursor + new Vector2(icon.Width + 4, (float) icon.Height / 2 - lineHeight / 2));
|
||||||
|
}
|
||||||
|
|
||||||
private void HoverStatus(StatusPayload status) {
|
private void HoverStatus(StatusPayload status) {
|
||||||
|
if (this.Ui.Plugin.TextureCache.GetStatus(status.Status) is { } icon) {
|
||||||
|
InlineIcon(icon);
|
||||||
|
}
|
||||||
|
|
||||||
var name = ChunkUtil.ToChunks(status.Status.Name.ToDalamudString(), null);
|
var name = ChunkUtil.ToChunks(status.Status.Name.ToDalamudString(), null);
|
||||||
this.Log.DrawChunks(name.ToList());
|
this.Log.DrawChunks(name.ToList());
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
@@ -119,6 +133,10 @@ internal sealed class PayloadHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void HoverItem(ItemPayload item) {
|
private void HoverItem(ItemPayload item) {
|
||||||
|
if (this.Ui.Plugin.TextureCache.GetItem(item.Item) is { } icon) {
|
||||||
|
InlineIcon(icon);
|
||||||
|
}
|
||||||
|
|
||||||
var name = ChunkUtil.ToChunks(item.Item.Name.ToDalamudString(), null);
|
var name = ChunkUtil.ToChunks(item.Item.Name.ToDalamudString(), null);
|
||||||
this.Log.DrawChunks(name.ToList());
|
this.Log.DrawChunks(name.ToList());
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public sealed class Plugin : IDalamudPlugin {
|
|||||||
|
|
||||||
internal Configuration Config { get; }
|
internal Configuration Config { get; }
|
||||||
internal XivCommonBase Common { get; }
|
internal XivCommonBase Common { get; }
|
||||||
|
internal TextureCache TextureCache { get; }
|
||||||
internal GameFunctions Functions { get; }
|
internal GameFunctions Functions { get; }
|
||||||
internal Store Store { get; }
|
internal Store Store { get; }
|
||||||
internal PluginUi Ui { get; }
|
internal PluginUi Ui { get; }
|
||||||
@@ -54,6 +55,7 @@ public sealed class Plugin : IDalamudPlugin {
|
|||||||
public Plugin() {
|
public Plugin() {
|
||||||
this.Config = this.Interface!.GetPluginConfig() as Configuration ?? new Configuration();
|
this.Config = this.Interface!.GetPluginConfig() as Configuration ?? new Configuration();
|
||||||
this.Common = new XivCommonBase();
|
this.Common = new XivCommonBase();
|
||||||
|
this.TextureCache = new TextureCache(this.DataManager!);
|
||||||
this.Functions = new GameFunctions(this);
|
this.Functions = new GameFunctions(this);
|
||||||
this.Store = new Store(this);
|
this.Store = new Store(this);
|
||||||
this.Ui = new PluginUi(this);
|
this.Ui = new PluginUi(this);
|
||||||
@@ -69,6 +71,7 @@ public sealed class Plugin : IDalamudPlugin {
|
|||||||
this.Ui.Dispose();
|
this.Ui.Dispose();
|
||||||
this.Store.Dispose();
|
this.Store.Dispose();
|
||||||
this.Functions.Dispose();
|
this.Functions.Dispose();
|
||||||
|
this.TextureCache.Dispose();
|
||||||
this.Common.Dispose();
|
this.Common.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -9,6 +9,9 @@ namespace ChatTwo;
|
|||||||
|
|
||||||
internal sealed class PluginUi : IDisposable {
|
internal sealed class PluginUi : IDisposable {
|
||||||
internal Plugin Plugin { get; }
|
internal Plugin Plugin { get; }
|
||||||
|
|
||||||
|
internal bool SettingsVisible;
|
||||||
|
|
||||||
internal ImFontPtr? RegularFont { get; private set; }
|
internal ImFontPtr? RegularFont { get; private set; }
|
||||||
internal ImFontPtr? ItalicFont { get; private set; }
|
internal ImFontPtr? ItalicFont { get; private set; }
|
||||||
internal Vector4 DefaultText { get; private set; }
|
internal Vector4 DefaultText { get; private set; }
|
||||||
@@ -55,7 +58,7 @@ internal sealed class PluginUi : IDisposable {
|
|||||||
|
|
||||||
var builder = new ImFontGlyphRangesBuilderPtr(ImGuiNative.ImFontGlyphRangesBuilder_ImFontGlyphRangesBuilder());
|
var builder = new ImFontGlyphRangesBuilderPtr(ImGuiNative.ImFontGlyphRangesBuilder_ImFontGlyphRangesBuilder());
|
||||||
builder.AddRanges(ImGui.GetIO().Fonts.GetGlyphRangesDefault());
|
builder.AddRanges(ImGui.GetIO().Fonts.GetGlyphRangesDefault());
|
||||||
builder.AddText("←→↑↓《》■※☀★★☆♥♡ヅツッシ☀☁☂℃℉°♀♂♠♣♦♣♧®©™€$£♯♭♪✓√◎◆◇♦■□〇●△▽▼▲‹›≤≥<«“”─");
|
builder.AddText("←→↑↓《》■※☀★★☆♥♡ヅツッシ☀☁☂℃℉°♀♂♠♣♦♣♧®©™€$£♯♭♪✓√◎◆◇♦■□〇●△▽▼▲‹›≤≥<«“”─\~");
|
||||||
builder.BuildRanges(out this._ranges);
|
builder.BuildRanges(out this._ranges);
|
||||||
|
|
||||||
var regular = this.GetResource("ChatTwo.fonts.NotoSans-Regular.ttf");
|
var regular = this.GetResource("ChatTwo.fonts.NotoSans-Regular.ttf");
|
||||||
|
|||||||
Executable
+59
@@ -0,0 +1,59 @@
|
|||||||
|
using Dalamud.Data;
|
||||||
|
using ImGuiScene;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
|
namespace ChatTwo;
|
||||||
|
|
||||||
|
internal class TextureCache : IDisposable {
|
||||||
|
private DataManager Data { get; }
|
||||||
|
|
||||||
|
private readonly Dictionary<uint, TextureWrap> _itemIcons = new();
|
||||||
|
private readonly Dictionary<uint, TextureWrap> _statusIcons = new();
|
||||||
|
|
||||||
|
internal IReadOnlyDictionary<uint, TextureWrap> ItemIcons => this._itemIcons;
|
||||||
|
internal IReadOnlyDictionary<uint, TextureWrap> StatusIcons => this._statusIcons;
|
||||||
|
|
||||||
|
internal TextureCache(DataManager data) {
|
||||||
|
this.Data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
var allIcons = this.ItemIcons.Values
|
||||||
|
.Concat(this.StatusIcons.Values);
|
||||||
|
|
||||||
|
foreach (var tex in allIcons) {
|
||||||
|
tex.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddIcon(IDictionary<uint, TextureWrap> dict, uint icon) {
|
||||||
|
if (dict.ContainsKey(icon)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tex = this.Data.GetImGuiTextureIcon(icon);
|
||||||
|
if (tex != null) {
|
||||||
|
dict[icon] = tex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddItem(Item item) {
|
||||||
|
this.AddIcon(this._itemIcons, item.Icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddStatus(Status status) {
|
||||||
|
this.AddIcon(this._statusIcons, status.Icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal TextureWrap? GetItem(Item item) {
|
||||||
|
this.AddItem(item);
|
||||||
|
this.ItemIcons.TryGetValue(item.Icon, out var icon);
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal TextureWrap? GetStatus(Status status) {
|
||||||
|
this.AddStatus(status);
|
||||||
|
this.StatusIcons.TryGetValue(status.Icon, out var icon);
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
-2
@@ -1,12 +1,16 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using ChatTwo.Code;
|
using ChatTwo.Code;
|
||||||
using ChatTwo.Util;
|
using ChatTwo.Util;
|
||||||
|
using Dalamud.Interface;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using ImGuiScene;
|
using ImGuiScene;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
namespace ChatTwo.Ui;
|
namespace ChatTwo.Ui;
|
||||||
|
|
||||||
internal sealed class ChatLog : IUiComponent {
|
internal sealed class ChatLog : IUiComponent {
|
||||||
|
private const string ChatChannelPicker = "chat-channel-picker";
|
||||||
|
|
||||||
private PluginUi Ui { get; }
|
private PluginUi Ui { get; }
|
||||||
|
|
||||||
internal bool Activate;
|
internal bool Activate;
|
||||||
@@ -143,7 +147,39 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
ImGui.SetKeyboardFocusHere();
|
ImGui.SetKeyboardFocusHere();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.TextUnformatted(this.Ui.Plugin.Functions.ChatChannel.name);
|
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
|
||||||
|
try {
|
||||||
|
this.DrawChunks(this.Ui.Plugin.Functions.ChatChannel.name);
|
||||||
|
} finally {
|
||||||
|
ImGui.PopStyleVar();
|
||||||
|
}
|
||||||
|
|
||||||
|
var beforeIcon = ImGui.GetCursorPos();
|
||||||
|
|
||||||
|
if (ImGuiUtil.IconButton(FontAwesomeIcon.Comment)) {
|
||||||
|
ImGui.OpenPopup(ChatChannelPicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginPopup(ChatChannelPicker)) {
|
||||||
|
foreach (var channel in Enum.GetValues<InputChannel>()) {
|
||||||
|
var name = this.Ui.Plugin.DataManager.GetExcelSheet<LogFilter>()!
|
||||||
|
.FirstOrDefault(row => row.LogKind == (byte) channel.ToChatType())
|
||||||
|
?.Name
|
||||||
|
?.RawString ?? channel.ToString();
|
||||||
|
|
||||||
|
if (ImGui.Selectable(name)) {
|
||||||
|
this.Ui.Plugin.Functions.SetChatChannel(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
var afterIcon = ImGui.GetCursorPos();
|
||||||
|
|
||||||
|
var buttonWidth = afterIcon.X - beforeIcon.X;
|
||||||
|
var inputWidth = ImGui.GetContentRegionAvail().X - buttonWidth;
|
||||||
|
|
||||||
var inputType = this.Ui.Plugin.Functions.ChatChannel.channel.ToChatType();
|
var inputType = this.Ui.Plugin.Functions.ChatChannel.channel.ToChatType();
|
||||||
var inputColour = this.Ui.Plugin.Config.ChatColours.TryGetValue(inputType, out var inputCol)
|
var inputColour = this.Ui.Plugin.Config.ChatColours.TryGetValue(inputType, out var inputCol)
|
||||||
@@ -154,7 +190,7 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
ImGui.PushStyleColor(ImGuiCol.Text, ColourUtil.RgbaToAbgr(inputColour.Value));
|
ImGui.PushStyleColor(ImGuiCol.Text, ColourUtil.RgbaToAbgr(inputColour.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SetNextItemWidth(-1);
|
ImGui.SetNextItemWidth(inputWidth);
|
||||||
const ImGuiInputTextFlags inputFlags = ImGuiInputTextFlags.EnterReturnsTrue
|
const ImGuiInputTextFlags inputFlags = ImGuiInputTextFlags.EnterReturnsTrue
|
||||||
| ImGuiInputTextFlags.CallbackAlways
|
| ImGuiInputTextFlags.CallbackAlways
|
||||||
| ImGuiInputTextFlags.CallbackHistory;
|
| ImGuiInputTextFlags.CallbackHistory;
|
||||||
@@ -174,6 +210,12 @@ internal sealed class ChatLog : IUiComponent {
|
|||||||
ImGui.PopStyleColor();
|
ImGui.PopStyleColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGuiUtil.IconButton(FontAwesomeIcon.Cog)) {
|
||||||
|
this.Ui.SettingsVisible ^= true;
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ namespace ChatTwo.Ui;
|
|||||||
internal sealed class Settings : IUiComponent {
|
internal sealed class Settings : IUiComponent {
|
||||||
private PluginUi Ui { get; }
|
private PluginUi Ui { get; }
|
||||||
|
|
||||||
private bool _visible;
|
|
||||||
|
|
||||||
private bool _hideChat;
|
private bool _hideChat;
|
||||||
private bool _nativeItemTooltips;
|
private bool _nativeItemTooltips;
|
||||||
private float _fontSize;
|
private float _fontSize;
|
||||||
@@ -29,7 +27,7 @@ internal sealed class Settings : IUiComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void Command(string command, string args) {
|
private void Command(string command, string args) {
|
||||||
this._visible ^= true;
|
this.Ui.SettingsVisible ^= true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Initialise() {
|
private void Initialise() {
|
||||||
@@ -42,11 +40,11 @@ internal sealed class Settings : IUiComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Draw() {
|
public void Draw() {
|
||||||
if (!this._visible) {
|
if (!this.Ui.SettingsVisible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ImGui.Begin($"{this.Ui.Plugin.Name} settings", ref this._visible)) {
|
if (!ImGui.Begin($"{this.Ui.Plugin.Name} settings", ref this.Ui.SettingsVisible)) {
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -148,13 +146,13 @@ internal sealed class Settings : IUiComponent {
|
|||||||
|
|
||||||
if (ImGui.Button("Save and close")) {
|
if (ImGui.Button("Save and close")) {
|
||||||
save = true;
|
save = true;
|
||||||
this._visible = false;
|
this.Ui.SettingsVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
|
||||||
if (ImGui.Button("Discard")) {
|
if (ImGui.Button("Discard")) {
|
||||||
this._visible = false;
|
this.Ui.SettingsVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.End();
|
ImGui.End();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using Dalamud.Interface;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
namespace ChatTwo.Util;
|
namespace ChatTwo.Util;
|
||||||
@@ -34,14 +35,20 @@ internal static class ImGuiUtil {
|
|||||||
PostPayload(payload, handler);
|
PostPayload(payload, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (csText.Length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var part in csText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)) {
|
foreach (var part in csText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)) {
|
||||||
var bytes = Encoding.UTF8.GetBytes(part);
|
var bytes = Encoding.UTF8.GetBytes(part);
|
||||||
fixed (byte* rawText = bytes) {
|
fixed (byte* rawText = bytes) {
|
||||||
var text = rawText;
|
var text = rawText;
|
||||||
var textEnd = text + bytes.Length;
|
var textEnd = text + bytes.Length;
|
||||||
|
|
||||||
// idk how this is possible, but it is, I guess
|
// empty string
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
|
ImGui.TextUnformatted("");
|
||||||
|
ImGui.TextUnformatted("");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +70,8 @@ internal static class ImGuiUtil {
|
|||||||
|
|
||||||
endPrevLine = ImGuiNative.ImFont_CalcWordWrapPositionA(ImGui.GetFont().NativePtr, scale, text, textEnd, widthLeft);
|
endPrevLine = ImGuiNative.ImFont_CalcWordWrapPositionA(ImGui.GetFont().NativePtr, scale, text, textEnd, widthLeft);
|
||||||
if (endPrevLine == null) {
|
if (endPrevLine == null) {
|
||||||
|
ImGui.TextUnformatted("");
|
||||||
|
ImGui.TextUnformatted("");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,4 +80,19 @@ internal static class ImGuiUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool IconButton(FontAwesomeIcon icon, string? id = null) {
|
||||||
|
ImGui.PushFont(UiBuilder.IconFont);
|
||||||
|
|
||||||
|
var label = icon.ToIconString();
|
||||||
|
if (id != null) {
|
||||||
|
label += $"##{id}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = ImGui.Button(label);
|
||||||
|
|
||||||
|
ImGui.PopFont();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user