From 22e63efe05ec7684e2440d5437feba7d44e93ae1 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Sat, 31 Oct 2026 01:25:43 +0000 Subject: [PATCH] Decompile 2 functions in Source/UI/Lists/UITagListBox.cpp, Source/UI/Lists/UITagListBox.h Batch #6608 by pedrao: 0 byte-identical, 2 confirmed by peer review. - fn_13877 UITagListBox::Paint: logic confirmed by peer review - fn_13881 UITagListBox::sub_9B9EA0: logic confirmed by peer review Peer-reviewed-by: ragnarok-clanker, alisonrag, superintelligence, KWDev, SapitoSucio, eAthena Accepted without human review: peers confirmed the logic ("same" ahead by at least 3, with 70% of the votes). --- Source/UI/Lists/UITagListBox.cpp | 130 +++++++++++++++++++++++++++++++ Source/UI/Lists/UITagListBox.h | 13 ++++ 2 files changed, 143 insertions(+) diff --git a/Source/UI/Lists/UITagListBox.cpp b/Source/UI/Lists/UITagListBox.cpp index 2f8122a5..632f5bb9 100644 --- a/Source/UI/Lists/UITagListBox.cpp +++ b/Source/UI/Lists/UITagListBox.cpp @@ -5,9 +5,43 @@ #include "Network/TextEncoding.h" #include "UI/Buttons/UITagButton.h" #include "UI/Lists/UIScrollBar.h" +#include "UI/Text/ColoredText.h" +#include "UI/Text/PixelTextWrapping.h" +#include "UI/Text/TextWrapping.h" +#include #include #include +#include + +namespace { +// INLINED +const char* SegmentEnd(const char* text, const char* end, unsigned short codePage) { + const char* current = text; + + while (current < end) { + if (*current == '^' && end - current >= 6) { + bool color = true; + + for (int index = 1; index <= 6; ++index) { + const unsigned char digit = static_cast(current[index]); + if (!((digit >= '0' && digit <= '9') || (digit >= 'a' && digit <= 'f') || (digit >= 'A' && digit <= 'F'))) { + color = false; + break; + } + } + + if (color) { + return current; + } + } + + current = CharNextExA(codePage, current, 0); + } + + return current; +} +} // OFFSET: 0x009B7A10 // FUNCTION: fn_13869 @@ -31,6 +65,63 @@ void UITagListBox::Clear() { void UITagListBox::Slot25(int, int) { } +// OFFSET: 0x009B9CB0 +// FUNCTION: fn_13877 +void UITagListBox::Paint() { + if (this->transparent != 0) { + this->ClearSurface(0xFFFF00FF); + + if (this->parent) { + this->parent->Invalidate(); + } + } else { + this->ClearSurface( + (this->backgroundRed & 255) | ((this->backgroundGreen & 255) << 8) | ((this->backgroundBlue & 255) << 16) + ); + } + + const int first = this->topLine; + int divisor = this->lineHeight - this->bottomMargin; + if (divisor == 0) { + divisor = 1; + } + const int limit = (this->geometry.height / divisor + first); + const int end = + static_cast(std::min(static_cast(this->lines.size()), static_cast(limit))); + std::uint32_t color = 0; + auto& owner = *this->m_listContext; + + for (int index = 0; index < first; ++index) { + const std::string& line = this->lines[index]; + const char* text = line.c_str(); + const char* endText = text + line.size(); + + while (text < endText) { + text = ParseColorCode(SegmentEnd(text, endText, owner.codePage), color); + } + } + + if (first < end) { + if ((this->unknown_00BC & 255) == 0) { + for (int index = first; index < end; ++index) { + const std::string& line = this->lines[index]; + const int y = (index - first) * this->lineHeight + 4; + DrawColoredText( + *this, owner.codePage, 3, y, line.c_str(), static_cast(line.size()), color, 0, 12, false + ); + } + } else { + for (int index = first; index < end; ++index) { + const std::string& line = this->lines[index]; + const int y = (index - first) * this->lineHeight + 4; + DrawOutlinedText( + *this, 3, y, line.c_str(), static_cast(line.size()), 0, 0xFFFFFF, 0, 12, 0, 0 + ); + } + } + } +} + // OFFSET: 0x009B9E70 // FUNCTION: fn_13878 void UITagListBox::Slot26(int, int) { @@ -221,3 +312,42 @@ int UITagListBox::SendMsg(UIWindow* sender, int message, std::intptr_t argument1 return 0; } + +// OFFSET: 0x009B9EA0 +// FUNCTION: fn_13881 +void UITagListBox::sub_9B9EA0(std::intptr_t argument1, std::intptr_t argument2, std::intptr_t argument3, std::intptr_t argument4) { + char* text = reinterpret_cast(argument1); + const int width = static_cast(argument2); + auto& owner = *this->m_listContext; + std::vector lines; + + if (width == 138) { + WrapPlainText(text, lines, 38, owner.codePage); + + for (const std::string& line : lines) { + this->AddLine(line.c_str()); + } + + this->unknown_00BC = (this->unknown_00BC & ~255) | 1; + } else { + if (argument4 != 0) { + int extra = 0; + if (argument3 != 0) { + extra = this->verticalBar->geometry.width + 2; + } + WrapPixelText(*this->geometry.surface, owner.codePage, text, lines, this->geometry.width - extra - 4); + + for (const std::string& line : lines) { + this->AddLine(line.c_str()); + } + } else { + std::vector tags; + const std::string parsed = this->sub_9B8AA0(std::string(text)); + this->sub_9BB8E0(parsed, tags, width == 0 ? 35 : width); + } + + this->unknown_00BC &= ~255; + } + + this->Invalidate(); +} diff --git a/Source/UI/Lists/UITagListBox.h b/Source/UI/Lists/UITagListBox.h index 8edae0a0..e684a1c4 100644 --- a/Source/UI/Lists/UITagListBox.h +++ b/Source/UI/Lists/UITagListBox.h @@ -11,8 +11,19 @@ class UITagButton; class UITagListBox : public UIListBox { public: + struct STagInfoV2 { + /* 0004 */ int unknown_0004; + /* 0008 */ int unknown_0008; + /* 000C */ int unknown_000C; + /* 0010 */ std::string unknown_0010; + /* 0028 */ std::string unknown_0028; + + virtual ~STagInfoV2(); + }; + void AddLine(const char* text) override; void Clear() override; + void Paint() override; void Slot25(int x, int y) override; void Slot26(int x, int y) override; void Slot31(int x, int y) override; @@ -20,6 +31,8 @@ public: void sub_9B9EA0(std::intptr_t argument1, std::intptr_t argument2, std::intptr_t argument3, std::intptr_t argument4); void sub_9BC0A0(std::intptr_t type, UIWindow* sender); + std::string sub_9B8AA0(std::string text); + void sub_9BB8E0(std::string text, std::vector& tags, int width); int DecodeNumber(std::string text); bool ItemFromFields(const std::vector& fields, ITEM_INFO& item); void DecodeValues(std::vector& values, const char* text, int& position, const int& end, const char& separator, const char& alternate);