diff --git a/Source/UI/Edit/ItemTagRetirement.cpp b/Source/UI/Edit/ItemTagRetirement.cpp index 6c74c6d9..2c987408 100644 --- a/Source/UI/Edit/ItemTagRetirement.cpp +++ b/Source/UI/Edit/ItemTagRetirement.cpp @@ -1,3 +1,4 @@ +#include "Client/Input/Language.h" #include "Contents/Items/ItemInfo.h" #include "Contents/Items/ItemNaming.h" #include "UI/Buttons/UIItemTagButton.h" @@ -26,21 +27,18 @@ struct ItemLinkOption { }; #pragma pack(pop) -// INLINED -FocusedItemTagRemoval::FocusedItemTagRemoval(InputFocus& focus) : m_focus(focus) { -} - // OFFSET: 0x00896EB0 // FUNCTION: fn_11519 -void FocusedItemTagRemoval::Remove(UIWindow* child) { - if (this->m_focus.window) { - this->m_focus.window->RemoveChild(child, 1); +void UIItemTagCtrl::RemoveTagChild(UIWindow* child) { + UIWindow* hoverWindow = g_windowMgr.GetHoverWindow(); + if (hoverWindow) { + hoverWindow->RemoveChild(child, 1); } } // OFFSET: 0x00896EE0 // FUNCTION: fn_11520 -void ChatItemTagRemoval::Remove(UIWindow* child) { +void UIItemTagOnChat::RemoveTagChild(UIWindow* child) { if (g_inputSuggestionsEnabled == 1 && g_chatSuggestions->unknown_00BC != nullptr && g_chatSuggestions->unknown_00BC->Contains(child)) { g_chatSuggestions->unknown_00BC->RemoveChild(child, 1); return; @@ -156,27 +154,19 @@ bool UIItemTagCtrl::SyncTagsWithText() { return true; } -// INLINED -MailItemTagRemoval::MailItemTagRemoval(UIWindow* const& owner) : m_owner(owner) { -} - // OFFSET: 0x00896F60 // FUNCTION: fn_11521 -void MailItemTagRemoval::Remove(UIWindow* child) { - if (this->m_owner) { - this->m_owner->RemoveChild(child, 1); +void UIItemTagOnMail::RemoveTagChild(UIWindow* child) { + if (g_windowMgr.unknown_0458) { + g_windowMgr.unknown_0458->RemoveChild(child, 1); } } -// INLINED -MegaPhoneItemTagRemoval::MegaPhoneItemTagRemoval(UIWindow* const& owner) : m_owner(owner) { -} - // OFFSET: 0x00896F80 // FUNCTION: fn_11522 -void MegaPhoneItemTagRemoval::Remove(UIWindow* child) { - if (this->m_owner) { - this->m_owner->RemoveChild(child, 1); +void UIItemTagOnMegaPhone::RemoveTagChild(UIWindow* child) { + if (g_windowMgr.unknown_0318) { + g_windowMgr.unknown_0318->RemoveChild(child, 1); } } @@ -344,3 +334,79 @@ bool UIItemTagOnMegaPhone::CanInsertTag(const std::string& name, int width) { std::string text = this->taggedText += tag; return text.size() <= maximum; } + +// OFFSET: 0x008962C0 +void UIItemTagCtrl::sub_8962C0() { + this->unknown_0140.clear(); + if (this->unknown_011C != static_cast(this->tags.size()) && this->SyncTagsWithText()) { + this->unknown_011C = static_cast(this->tags.size()); + } + + std::string prefix; + std::string remaining = this->taggedText; + if (!this->tags.empty()) { + for (auto entry = this->tags.begin(); entry != this->tags.end();) { + if (this->RemoveInvalidTag(entry)) { + break; + } + + const std::string fitted = FitText(*this->geometry.surface, entry->name, this->tagWidth / 2); + std::string display = "<"; + display += fitted; + display += ">"; + + const std::size_t found = remaining.find(display); + if (found != std::string::npos) { + const std::string head = remaining.substr(0, found); + prefix += head; + + std::string visible = head; + std::size_t firstVisible = 0; + int x = 0; + UIWindow* hover = g_windowMgr.GetHoverWindow(); + if (hover != nullptr) { + switch (hover->geometry.id) { + case 0x1EA: + case 0x1EC: + case 0x1ED: + case 0x1EE: + firstVisible = static_cast(hover)->firstVisible; + break; + } + + if (firstVisible <= prefix.size()) { + visible = prefix.substr(firstVisible); + } + + if (firstVisible != 0 && prefix.size() <= firstVisible) { + x = 1000; + } + } + + this->PlaceTagButton(entry->child, visible, x, 0); + + const int bytes = static_cast(std::strlen(fitted.c_str())); + if (!g_windowMgr.unknown_0458 || static_cast(g_windowMgr.unknown_0458)->m_contents == g_windowMgr.GetHoverWindow()) { + const int cursor = this->m_edit->input.cursor; + const int start = static_cast(prefix.size()); + const int end = start + bytes + 2; + if (cursor > start && cursor < end) { + const int target = start + bytes / 2 + 1 > cursor ? end : start; + this->m_edit->input.Select(target, target); + } + } + + this->unknown_0140 += head; + this->unknown_0140 += itemLinkTagOpening; + this->unknown_0140 += entry->link; + this->unknown_0140 += itemLinkTagClosing; + remaining = remaining.substr(found + display.size()); + prefix += display; + } + + ++entry; + } + } + + this->unknown_0140 += remaining; +} diff --git a/Source/UI/Edit/ItemTagRetirement.h b/Source/UI/Edit/ItemTagRetirement.h index 75675438..00f449fd 100644 --- a/Source/UI/Edit/ItemTagRetirement.h +++ b/Source/UI/Edit/ItemTagRetirement.h @@ -24,34 +24,6 @@ protected: ~ItemTagRemoval() = default; }; -struct FocusedItemTagRemoval final : ItemTagRemoval { - explicit FocusedItemTagRemoval(InputFocus& focus); - void Remove(UIWindow* child) override; - -private: - InputFocus& m_focus; -}; - -struct ChatItemTagRemoval final : ItemTagRemoval { - void Remove(UIWindow* child) override; -}; - -struct MailItemTagRemoval final : ItemTagRemoval { - explicit MailItemTagRemoval(UIWindow* const& owner); - void Remove(UIWindow* child) override; - -private: - UIWindow* const& m_owner; -}; - -struct MegaPhoneItemTagRemoval final : ItemTagRemoval { - explicit MegaPhoneItemTagRemoval(UIWindow* const& owner); - void Remove(UIWindow* child) override; - -private: - UIWindow* const& m_owner; -}; - struct ItemTagRetirement { std::list& records; ItemTagRemoval& removal; diff --git a/Source/UI/Edit/UIItemTagCtrl.h b/Source/UI/Edit/UIItemTagCtrl.h index f9fdd7ae..989c292c 100644 --- a/Source/UI/Edit/UIItemTagCtrl.h +++ b/Source/UI/Edit/UIItemTagCtrl.h @@ -3,6 +3,7 @@ #include "UI/Edit/ItemTagRetirement.h" #include "UI/Edit/UIEditCtrl.h" +#include "UI/TextTags.h" #include #include @@ -16,10 +17,13 @@ public: ~UIItemTagCtrl() override; virtual bool CanInsertTag(const std::string& name, int width); virtual void AddTagButton(UIWindow* button); + virtual void RemoveTagChild(UIWindow* child); + virtual void PlaceTagButton(UIWindow* button, const std::string& name, const int& x, int unused) = 0; std::string AppendTag(const std::string& name); int MeasureText(const std::string& text, const unsigned& bytes); bool SyncTagsWithText(); + bool RemoveInvalidTag(std::list::iterator& entry); void SetTaggedText(const std::string& text, int width); void sub_8962C0(); void sub_89CFE0(const ITEM_INFO& item, unsigned int color); @@ -36,7 +40,8 @@ class UIItemTagOnChat : public UIItemTagCtrl { public: UIItemTagOnChat(); bool CanInsertTag(const std::string& name, int width) override; - void PlaceTagButton(UIWindow* button, const std::string& name, const int& x, int unused); + void RemoveTagChild(UIWindow* child) override; + void PlaceTagButton(UIWindow* button, const std::string& name, const int& x, int unused) override; }; class UIItemTagOnMail : public UIItemTagCtrl { @@ -45,7 +50,8 @@ public: bool CanInsertTag(const std::string& name, int width) override; void AddTagButton(UIWindow* button) override; void SetLines(const std::vector& lines); - void PlaceTagButton(UIWindow* button, const std::string& name, const int& x, int unused); + void RemoveTagChild(UIWindow* child) override; + void PlaceTagButton(UIWindow* button, const std::string& name, const int& x, int unused) override; /* 015C */ std::vector m_lines; }; @@ -55,7 +61,8 @@ public: UIItemTagOnMegaPhone(); bool CanInsertTag(const std::string& name, int width) override; void AddTagButton(UIWindow* button) override; - void PlaceTagButton(UIWindow* button, const std::string& name, const int& x, int unused); + void RemoveTagChild(UIWindow* child) override; + void PlaceTagButton(UIWindow* button, const std::string& name, const int& x, int unused) override; /* 015C */ int textWidth; }; diff --git a/Source/UI/Lists/UIScrollBar.cpp b/Source/UI/Lists/UIScrollBar.cpp index 8c9b28c9..f7f1371e 100644 --- a/Source/UI/Lists/UIScrollBar.cpp +++ b/Source/UI/Lists/UIScrollBar.cpp @@ -44,6 +44,9 @@ #include #include #include +#include "UI/Edit/UIItemTagCtrl.h" +#include "UI/Rodex/UIRodexComposeWnd.h" +#include "UI/Text/TextFitting.h" // OFFSET: 0x0086DDA0 // FUNCTION: fn_11059 UIListBoxTitle::UIListBoxTitle() : titleColor(0x92C0FA) { @@ -1762,3 +1765,79 @@ void UITabControl::Configure( this->edit->Move(-100, -100); this->AddChild(this->edit); } + +// OFFSET: 0x0087D240 +bool UIItemTagCtrl::RemoveInvalidTag(std::list::iterator& entry) { + const std::string fitted = FitText(*this->geometry.surface, entry->name, this->tagWidth / 2); + std::string remaining = this->taggedText; + const int bytes = static_cast(std::strlen(fitted.c_str())); + int found = static_cast(remaining.find(fitted)); + + if (found == -1) { + this->RemoveTagChild(entry->child); + entry = this->tags.erase(entry); + return true; + } + + int absolute = found; + int count = 0; + + do { + std::string before; + if (found > 0) { + before = remaining.substr(found - 1, 1); + } + + std::string after; + if (found + bytes >= 0) { + after = remaining.substr(found + bytes, 1); + } + + bool atCursor; + if (before.find("<") != std::string::npos && after.find(">") == std::string::npos) { + atCursor = (!g_windowMgr.unknown_0458 || static_cast(g_windowMgr.unknown_0458)->m_contents == g_windowMgr.GetHoverWindow()) && + absolute + bytes == this->m_edit->input.cursor; + } else if (before.find("<") == std::string::npos && after.find(">") != std::string::npos) { + atCursor = (!g_windowMgr.unknown_0458 || static_cast(g_windowMgr.unknown_0458)->m_contents == g_windowMgr.GetHoverWindow()) && + absolute == this->m_edit->input.cursor; + } else if (before.find("<") != std::string::npos && after.find(">") != std::string::npos) { + ++count; + if (count > entry->index) { + return false; + } + atCursor = false; + } else { + remaining = remaining.substr(found + bytes); + absolute = (absolute == found ? absolute : absolute + found) + bytes; + found = static_cast(remaining.find(fitted)); + continue; + } + + if (atCursor) { + remaining = before.find("<") != std::string::npos ? this->taggedText.substr(0, absolute - 1) : this->taggedText.substr(0, absolute); + int end = absolute; + if (after.find(">") != std::string::npos) { + ++end; + } + remaining += this->taggedText.substr(end + bytes); + this->m_edit->input.ResetInput(); + this->m_edit->input.Insert(remaining.c_str()); + this->RemoveTagChild(entry->child); + entry = this->tags.erase(entry); + return true; + } + + if (entry->index == 0) { + break; + } + + remaining = remaining.substr(found + bytes); + found = static_cast(remaining.find(fitted)); + if (found == -1) { + return false; + } + absolute += found + bytes; + } while (found != -1); + + return false; +}