#include "Client/TextInputBuffer.h" #include "Network/TextEncoding.h" #include "Render/DeviceContext.h" #include "UI/EditPainting.h" #include "UI/EditTextState.h" #include "UI/EditViewport.h" #include "UI/InputFocus.h" #include "UI/UIButton.h" #include "UI/UIEditCtrl.h" #include "UI/WindowManagerWindows.h" #include #include #include #include namespace { int Add(int left, int right) { return std::bit_cast(static_cast(left) + static_cast(right)); } class LinkLayout : public EditLinkLayout { public: explicit LinkLayout(UIEditCtrl& control) : m_control(control) { } void Update() override { this->m_control.UpdateLinks(); } private: UIEditCtrl& m_control; }; } // OFFSET: 0x0084FAE0 // FUNCTION: fn_10663 UIEditCtrl::UIEditCtrl(UIWindowContext& windows, UIEditContext& edit) : UIWindow(windows, 0), anchor(0), cursor(0), mask(0), maximum(255), flat(1), red(255), green(255), blue(255), borderRed(0), borderGreen(0), borderBlue(0), textColor(0), secondColor(0xFFFFFFFF), firstVisible(0), textY(0), invalidatesParent(0), disabled(0), unknown_00F0(0), topPadding(0), preserveInput(0), m_edit(&edit) { this->text.reserve(255); } // OFFSET: 0x008517E0 // OFFSET: 0x00852980 // FUNCTION: fn_10718 UIEditCtrl::~UIEditCtrl() = default; // OFFSET: 0x005C3210 // FUNCTION: fn_03552 bool UIEditCtrl::Slot05() { return this->disabled == 0; } // OFFSET: 0x0085CCA0 // FUNCTION: fn_10807 void UIEditCtrl::Paint() { const auto component = [&](int value) { return static_cast(this->disabled != 0 && value > 30 ? Add(value, -30) : value); }; const unsigned color = component(this->red) | (component(this->green) << 8) | (component(this->blue) << 16); this->textY = 0; if (this->geometry.surface) { if (this->flat == 0) { RECT rectangle{0, 0, this->geometry.width, this->geometry.height}; const unsigned border = static_cast(this->borderRed) | (static_cast(this->borderGreen) << 8) | (static_cast(this->borderBlue) << 16); this->geometry.surface->Fill(&rectangle, border); rectangle = {1, 1, Add(this->geometry.width, -1), Add(this->geometry.height, -1)}; this->geometry.surface->Fill(&rectangle, color); } else { this->geometry.surface->Fill(nullptr, color); } } this->textY = Add(this->topPadding, 2); this->PaintText(); } // OFFSET: 0x0085AAB0 // FUNCTION: fn_10783 void UIEditCtrl::Slot23() { this->m_edit->input.CancelComposition(); this->m_edit->input.CancelComposition(); this->m_edit->input.Insert(this->text.c_str()); this->m_edit->password = this->mask != 0; this->SelectAll(); } // OFFSET: 0x0085E3B0 // FUNCTION: fn_10826 void UIEditCtrl::Slot24(int) { this->Synchronize(); this->Invalidate(); } // OFFSET: 0x0085EC20 // FUNCTION: fn_10842 void UIEditCtrl::Slot25(int, int) { if (this->disabled == 0) { this->m_edit->focus.Set(this); } } // OFFSET: 0x0085F390 // FUNCTION: fn_10860 void UIEditCtrl::Slot28(int x, int y) { if (this->disabled != 0) { return; } this->Slot27(x, y); if (!this->tooltip.empty()) { int left = 10, top = -20; for (const UIWindow* window = this; window; window = static_cast(window->parent)) { left = Add(left, window->geometry.x); top = Add(top, window->geometry.y); } this->m_edit->buttons.services.Tooltip(this->tooltip.c_str(), left, top, -1, false, true); } } // OFFSET: 0x008641C0 // FUNCTION: fn_10914 int UIEditCtrl::SendMsg( UIWindow* sender, int message, std::intptr_t a, std::intptr_t b, std::intptr_t c, std::intptr_t d ) { if (message == 153) { this->InsertLink(reinterpret_cast(a)); } else if (message == 98 && c > 0) { UIWindow* window = this->m_edit->windows.EnsureWindow(12); if (window) { window->SendMsg(nullptr, 24, c, 0, 0, 0); } } UIWindow::SendMsg(sender, message, a, b, c, d); if (message == 0 && this->preserveInput == 0) { this->m_edit->input.CancelComposition(); } return 0; } // OFFSET: 0x005C44E0 int UIEditCtrl::Slot46() { return 2; } // OFFSET: 0x008680D0 // FUNCTION: fn_10952 void UIEditCtrl::SetText(const char* value) { this->text.assign(value, std::strlen(value)); this->Trim(); if (this->m_edit->focus.window == this) { this->m_edit->input.CancelComposition(); this->m_edit->input.CancelComposition(); this->m_edit->input.Insert(this->text.c_str()); } this->SelectAll(); if (this->parent) { static_cast(this->parent)->Invalidate(); } } // OFFSET: 0x0085A590 // FUNCTION: fn_10778 void UIEditCtrl::SelectAll() { const bool focused = this->m_edit->focus.window == this; EditTextState state{this->text, this->anchor, this->cursor, this->maximum, focused, this->m_edit->input, g_textCodePage}; state.SelectAll(); } // OFFSET: 0x00856980 // FUNCTION: fn_10755 void UIEditCtrl::PaintText() { this->PaintTextWithPolicy(false, nullptr, 0, false); } void UIEditCtrl::PaintTextWithPolicy( bool alternate, const std::string* placeholder, std::uint32_t placeholderColor, bool placeholderEnabled ) { const bool focused = this->m_edit->focus.window == this; EditTextState state{this->text, this->anchor, this->cursor, this->maximum, focused, this->m_edit->input, g_textCodePage}; EditViewport viewport{ this->text, this->anchor, this->cursor, this->firstVisible, this->geometry.width, g_textCodePage, this->m_edit->input, state, *this->geometry.surface, this->m_edit->buttons.fonts, this->m_edit->buttons.locale }; UIWindow* parent = static_cast(this->parent); int left = 0, top = 0; for (const UIWindow* window = this; window; window = static_cast(window->parent)) { left = Add(left, window->geometry.x); top = Add(top, window->geometry.y); } const bool chat = this->m_edit->input.chatInput == this || this->m_edit->otherChatInput == this; const DWORD tick = timeGetTime(); LinkLayout layout(*this); EditPainting painting{ this->text, this->anchor, this->cursor, this->mask, this->firstVisible, this->textY, this->invalidatesParent, this->textColor, this->secondColor, focused, chat, this->m_edit->input.suggestionsEnabled, tick, this->m_edit->candidateCursor, this->geometry.width, this->geometry.height, this->m_edit->screenWidth, this->m_edit->screenHeight, this->m_edit->input, this->m_edit->charset, viewport, *this->geometry.surface, this->m_edit->buttons.fonts, this->m_edit->buttons.locale, this->m_edit->colorChip, parent, this->m_edit->candidateWindow, this->m_edit->readingWindow, left, top, this->links, layout }; painting.alternate = alternate; painting.placeholder = placeholder; painting.placeholderColor = placeholderColor; painting.placeholderEnabled = placeholderEnabled; painting.Draw(); } // OFFSET: 0x00862FB0 // FUNCTION: fn_10905 void UIEditCtrl::Synchronize() { const bool focused = this->m_edit->focus.window == this; EditTextState state{this->text, this->anchor, this->cursor, this->maximum, focused, this->m_edit->input, g_textCodePage}; EditViewport viewport{ this->text, this->anchor, this->cursor, this->firstVisible, this->geometry.width, g_textCodePage, this->m_edit->input, state, *this->geometry.surface, this->m_edit->buttons.fonts, this->m_edit->buttons.locale }; viewport.Synchronize(); } // OFFSET: 0x00868450 // FUNCTION: fn_10959 void UIEditCtrl::Trim() { const bool focused = this->m_edit->focus.window == this; EditTextState state{this->text, this->anchor, this->cursor, this->maximum, focused, this->m_edit->input, g_textCodePage}; state.Trim(); } // OFFSET: 0x00858D50 // FUNCTION: fn_10768 int UIEditCtrl::Length() const { return static_cast(this->m_edit->focus.window == this ? this->m_edit->input.text.size() : this->text.size()); } // OFFSET: 0x00858D20 // FUNCTION: fn_10767 const char* UIEditCtrl::Text() { if (this->m_edit->focus.window == this) { this->Synchronize(); } return this->text.c_str(); } // OFFSET: 0x00865DD0 // FUNCTION: fn_10937 void UIEditCtrl::Background(int red, int green, int blue) { this->red = red; this->green = green; this->blue = blue; this->Invalidate(); } // OFFSET: 0x00868570 // FUNCTION: fn_10960 void UIEditCtrl::TextColor(std::uint32_t primary, std::uint32_t secondary) { this->secondColor = secondary; this->textColor = primary; this->Invalidate(); } // OFFSET: 0x0097C230 // FUNCTION: fn_13324 UIEditCtrlWheel::UIEditCtrlWheel(UIWindowContext& windows, UIEditContext& edit) : UIEditCtrl(windows, edit) { } // OFFSET: 0x009701B0 // FUNCTION: fn_13241 UIEditCtrlWheel::~UIEditCtrlWheel() = default; // OFFSET: 0x0098A240 // FUNCTION: fn_13408 void UIEditCtrlWheel::Slot35(int value) { if (this->parent) { static_cast(this->parent)->Slot35(value); } }