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).
This commit is contained in:
ragnarok-clanker 2026-10-31 01:25:43 +00:00
commit 22e63efe05
2 changed files with 143 additions and 0 deletions

View file

@ -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 <algorithm>
#include <cstdint>
#include <cstring>
#include <windows.h>
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<unsigned char>(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<int>(std::min(static_cast<unsigned>(this->lines.size()), static_cast<unsigned>(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<unsigned>(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<unsigned>(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<char*>(argument1);
const int width = static_cast<int>(argument2);
auto& owner = *this->m_listContext;
std::vector<std::string> 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<STagInfoV2> 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();
}

View file

@ -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<STagInfoV2>& tags, int width);
int DecodeNumber(std::string text);
bool ItemFromFields(const std::vector<int>& fields, ITEM_INFO& item);
void DecodeValues(std::vector<int>& values, const char* text, int& position, const int& end, const char& separator, const char& alternate);