rodecomp/Source/UI/Edit/EditPainting.cpp
ragnarok-clanker a47d20f8be Reconstruct readable C++ and organize cohesive source subsystems
Administrative source import: native x86 compilation passed for 423 authored units. Source placement and submission states are migrated separately; this commit does not imply peer acceptance.

Previous head: 35d2a8cb36
Payload SHA256: 592f016d2730c5593bb653aa054c1e5f76a6df72c8f5a09e66f74876e2e33dee
2026-10-25 07:42:41 +00:00

128 lines
4.5 KiB
C++

#include "Client/Input/InputCharset.h"
#include "Client/Input/TextInputBuffer.h"
#include "Render/DeviceContext/DeviceContext.h"
#include "Render/Text/TextContext.h"
#include "Resource/Bitmap/BitmapImage.h"
#include "UI/Edit/EditPainting.h"
#include "UI/Edit/EditViewport.h"
#include "UI/Window/UIWindow.h"
#include <algorithm>
#include <cstring>
// OFFSET: 0x00856980
// FUNCTION: fn_10755
void EditPainting::Draw() {
TextContext context(this->surface, this->fonts, this->locale);
context.SetFont(0, 12, 0, 0);
const auto measure = [&](const char* text, int bytes) { return context.Measure(text, bytes ? bytes : static_cast<int>(std::strlen(text))).cx; };
int x = 3;
if (this->invalidatesParent == 0 && this->firstVisible != 0) {
x = (3 - measure(this->text.c_str(), this->firstVisible));
}
const auto draw = [&](const std::string& value) {
const bool placeholder = this->alternate && !this->focused && this->placeholderEnabled && this->secondColor == 0xFFFFFFFFu;
context.SetColor(placeholder ? this->placeholderColor : this->color);
const std::string& displayed = placeholder && value.empty() ? *this->placeholder : value;
context.Draw(x, this->y, displayed.c_str(), static_cast<int>(displayed.size()));
if (this->secondColor != 0xFFFFFFFFu) {
context.SetColor(this->secondColor);
context.Draw((x - 1), this->y, value.c_str(), static_cast<int>(value.size()));
}
};
const auto highlight = [&](int left, int extent) {
const int start = std::max(left, 3);
const int adjusted = left < 3 ? (extent + (left - 3)) : extent;
if (start < this->width && adjusted > 0) {
std::uint32_t pixel = 0x00FF0000u;
if (this->colorChip.width > 6 && this->colorChip.height > 2) {
pixel = this->colorChip.pixels[2 * this->colorChip.width + 6];
}
const std::uint32_t color = ((pixel >> 16) & 255) | (pixel & 0xFF00) | ((pixel & 255) << 16);
RECT rectangle{start, 0, std::min((start + adjusted), this->width), this->height};
this->surface.Fill(&rectangle, color);
}
};
const auto moveCandidate = [&](UIWindow* window, int offset) {
if (!window) {
return;
}
int left = (offset + this->absoluteX);
int top = ((this->height + 6) + this->absoluteY);
if ((window->geometry.width + left) > this->screenWidth) {
left = (this->screenWidth - window->geometry.width);
}
if ((window->geometry.height + top) > this->screenHeight) {
top = (((top - 12) - this->height) - window->geometry.height);
}
window->Move(left, top);
};
std::string display;
if (this->focused) {
this->viewport.Synchronize();
unsigned begin = static_cast<unsigned>(std::min(this->anchor, this->cursor));
unsigned end = static_cast<unsigned>(std::max(this->anchor, this->cursor));
if (this->mask != 0) {
display.assign(this->text.size(), static_cast<char>(this->mask));
} else {
const char* prefix = this->alternate ? this->input.candidate.c_str() : this->charset.Prefix(false);
display = prefix;
display += this->text;
const auto prefixBytes = static_cast<unsigned>(std::strlen(prefix));
begin += prefixBytes;
end += prefixBytes + static_cast<unsigned>(this->candidateCursor);
}
const int left = begin == 0 ? 0 : measure(display.c_str(), static_cast<int>(begin));
const int right = end == 0 ? 0 : measure(display.c_str(), static_cast<int>(end));
if (this->input.cursor != this->input.anchor) {
highlight((x + left), (right - left));
draw(display);
} else if (this->candidateCursor != 0) {
moveCandidate(this->candidateWindow, left);
moveCandidate(this->readingWindow, right);
if (((this->tick / 500u) & 1u) == 0) {
highlight((x + left), std::max((right - left), 2));
}
draw(display);
} else {
draw(display);
if (((this->tick / 500u) & 1u) == 0 && (this->alternate ? this->caretEnabled : (!this->chatInputFocused || this->caretEnabled))) {
context.SetColor(this->color);
context.Draw(((x + left) - 2), this->y, "|", 1);
}
}
} else {
if (this->mask != 0) {
display.assign(this->text.size(), static_cast<char>(this->mask));
} else {
display = this->text;
}
draw(display);
if (this->invalidatesParent != 0 && this->parent) {
this->parent->Invalidate();
}
}
if (std::any_of(this->linkWindows.begin(), this->linkWindows.end(), [](const UIWindow* window) { return window->geometry.id == 438; })) {
this->links.Update();
}
}