thunderbrew/src/ui/CSimpleEditBox.cpp
2023-01-04 21:00:29 -06:00

1350 lines
35 KiB
C++

#include "ui/CSimpleEditBox.hpp"
#include "gx/Gx.hpp"
#include "gx/Coordinate.hpp"
#include "ui/CSimpleEditBoxScript.hpp"
#include "ui/CSimpleFontedFrameFont.hpp"
#include "ui/CSimpleFontString.hpp"
#include "ui/CSimpleTexture.hpp"
#include "ui/CSimpleTop.hpp"
#include "ui/LoadXML.hpp"
#include "util/Byte.hpp"
#include "util/CStatus.hpp"
#include "util/Lua.hpp"
#include "util/StringTo.hpp"
#include <cstring>
#include <common/XML.hpp>
#include <storm/String.hpp>
#include <storm/Unicode.hpp>
CSimpleEditBox* CSimpleEditBox::s_currentFocus;
int32_t CSimpleEditBox::s_metatable;
int32_t CSimpleEditBox::s_objectType;
void CSimpleEditBox::CreateScriptMetaTable() {
lua_State* L = FrameScript_GetContext();
int32_t ref = FrameScript_Object::CreateScriptMetaTable(L, &CSimpleEditBox::RegisterScriptMethods);
CSimpleEditBox::s_metatable = ref;
}
int32_t CSimpleEditBox::GetObjectType() {
if (!CSimpleEditBox::s_objectType) {
CSimpleEditBox::s_objectType = ++FrameScript_Object::s_objectTypes;
}
return CSimpleEditBox::s_objectType;
}
void CSimpleEditBox::RegisterScriptMethods(lua_State* L) {
CSimpleFrame::RegisterScriptMethods(L);
FrameScript_Object::FillScriptMethodTable(L, SimpleEditBoxMethods, NUM_SIMPLE_EDIT_BOX_SCRIPT_METHODS);
}
void CSimpleEditBox::SetKeyboardFocus(CSimpleEditBox* editBox) {
if (!editBox->m_visible) {
return;
}
if (CSimpleEditBox::s_currentFocus == editBox) {
return;
}
if (CSimpleEditBox::s_currentFocus) {
// TODO
// if (CSimpleEditBox::s_currentFocus->m_password) {
// nullsub_3();
// }
// TODO
// if (!(CSimpleEditBox::s_currentFocus->simpleeditbox_dword4 & 0xC)) {
// CSimpleEditBox::s_currentFocus->Sub963390();
// }
CSimpleEditBox::s_currentFocus->RunOnEditFocusLostScript();
CSimpleEditBox::s_currentFocus->m_dirtyFlags |= 0x4;
}
CSimpleEditBox::s_currentFocus = editBox;
// TODO
// if (editBox->m_password) {
// nullsub_3();
// }
// TODO
// if (!(editBox->simpleeditbox_dword4 & 0xC)) {
// OsIMEEnable(1);
// }
editBox->RunOnEditFocusGainedScript();
editBox->m_dirtyFlags |= 0x4;
}
CSimpleEditBox::CSimpleEditBox(CSimpleFrame* parent) : CSimpleFrame(parent) {
this->m_autoFocus = 1;
this->m_multiline = 0;
this->m_numeric = 0;
this->m_password = 0;
this->m_ignoreArrows = 0;
this->m_countInvisibleLetters = 0;
char* text = static_cast<char*>(SMemAlloc(this->m_textSize, __FILE__, __LINE__, 0));
text[0] = 0;
this->m_text = text;
uint32_t* textInfo = static_cast<uint32_t*>(SMemAlloc(sizeof(uint32_t) * this->m_textSize, __FILE__, __LINE__, 0));
memset(textInfo, 0, sizeof(uint32_t) * this->m_textSize);
this->m_textInfo = textInfo;
auto fontMem = SMemAlloc(sizeof(CSimpleFontedFrameFont), __FILE__, __LINE__, 0x0);
auto font = new (fontMem) CSimpleFontedFrameFont(this);
this->m_font = font;
this->m_font->m_attributes.SetJustifyH(0x1);
// TODO
// auto stringMem = CDataAllocator::GetData(CSimpleFontString::s_allocator, 0, __FILE__, __LINE__);
auto stringMem = SMemAlloc(sizeof(CSimpleFontString), __FILE__, __LINE__, 0x0);
auto string = new (stringMem) CSimpleFontString(this, DRAWLAYER_ARTWORK, 1);
this->m_string = string;
this->m_string->SetFontObject(this->m_font);
this->SetMultiLine(0);
for (int32_t i = 0; i < 3; i++) {
// TODO
// auto highlightMem = CDataAllocator::GetData(CSimpleTexture::s_allocator, 0, __FILE__, __LINE__);
auto highlightMem = SMemAlloc(sizeof(CSimpleTexture), __FILE__, __LINE__, 0x0);
auto highlight = new (highlightMem) CSimpleTexture(this, DRAWLAYER_ARTWORK, 0);
this->m_highlight[i] = highlight;
}
CImVector highlightColor = { 0x60, 0x60, 0x60, 0xFF };
for (int32_t i = 0; i < 3; i++) {
this->m_highlight[i]->SetTexture(highlightColor);
}
// TODO
// auto cursorMem = CDataAllocator::GetData(CSimpleTexture::s_allocator, 0, __FILE__, __LINE__);
auto cursorMem = SMemAlloc(sizeof(CSimpleTexture), __FILE__, __LINE__, 0x0);
auto cursor = new (cursorMem) CSimpleTexture(this, DRAWLAYER_ARTWORK_OVERLAY, 1);
cursor->Hide();
this->m_cursor = cursor;
CImVector cursorColor = { 0xFF, 0xFF, 0xFF, 0xFF };
this->m_cursor->SetTexture(cursorColor);
// TODO
// - initialize actions
this->EnableEvent(SIMPLE_EVENT_CHAR, -1);
this->EnableEvent(SIMPLE_EVENT_KEY, -1);
this->EnableEvent(SIMPLE_EVENT_MOUSE, -1);
}
int32_t CSimpleEditBox::ConvertCoordinateToIndex(float a2, float a3, int32_t& a4) {
// TODO
return 0;
}
void CSimpleEditBox::DeleteBackward(int32_t a2) {
if (this->m_highlightLeft != this->m_highlightRight) {
this->DeleteHighlight(a2);
return;
}
if (this->m_cursorPos > 0) {
int32_t len = this->GetNumToLen(this->m_cursorPos, -1, true);
this->DeleteSubstring(this->m_cursorPos - len, this->m_cursorPos, a2);
}
}
void CSimpleEditBox::DeleteForward(int32_t a2) {
if (this->m_highlightLeft != this->m_highlightRight) {
this->DeleteHighlight(a2);
return;
}
if (this->m_cursorPos < this->m_textLength) {
int32_t len = this->GetNumToLen(this->m_cursorPos, 1, true);
this->DeleteSubstring(this->m_cursorPos, this->m_cursorPos + len, a2);
}
}
void CSimpleEditBox::DeleteHighlight(int32_t a2) {
// TODO
}
void CSimpleEditBox::DeleteSubstring(int32_t left, int32_t right, int32_t a4) {
auto v5 = this->m_textInfo;
auto v6 = left;
if ((v5[left] & 0x80000000) != 0) {
auto v7 = left;
if (left >= 0) {
LABEL_3:
auto v8 = BYTE2(v5[v6]);
auto v9 = &v5[v6];
if (v8 == 1 || v8 == 5 || v8 == 7) {
if (v6 >= 0) {
LABEL_12:
auto v10 = BYTE2(v5[v6]);
auto v11 = &v5[v6];
if (v10 == 1 || v10 == 5 || v10 == 7) {
v7 = v6;
while (1) {
v6--;
v11--;
if (v6 < 0) {
break;
}
if (*v11) {
if (v6 >= 0) {
goto LABEL_12;
}
break;
}
}
}
}
} else {
v7 = v6;
while (1) {
v6--;
v9--;
if (v6 < 0) {
break;
}
if (*v9) {
if (v6 >= 0) {
goto LABEL_3;
}
break;
}
}
}
}
v6 = v7;
}
auto v12 = right;
if ((v5[right] & 0x80000000) != 0) {
auto v13 = this->m_textLength;
if (right < v13) {
do {
auto v14 = BYTE2(v5[v12]);
if (v14 == 2 || v14 == 6 || v14 == 8) {
break;
}
v12 += v5[v12] & 0xFFFF;
} while (v12 < v13);
for (; v12 < v13; v12 += v5[v12] & 0xFFFF) {
auto v15 = BYTE2(v5[v12]);
if (v15 != 2 && v15 != 6 && v15 != 8) {
break;
}
}
}
}
auto v16 = v12 - v6;
auto v17 = &this->m_text[v6];
auto newLength = this->m_textLength - (v12 - v6);
this->m_cursorPos = v6;
auto v19 = &v5[v6];
if (newLength >= 0) {
this->m_textLength = newLength;
memcpy(v17, &v17[v16], newLength - v6);
memcpy(v19, &v19[v16], 4 * (this->m_textLength - this->m_cursorPos));
this->m_text[this->m_textLength] = '\0';
this->m_textInfo[this->m_textLength] = '\0';
if (this->m_highlightLeft != this->m_highlightRight) {
this->m_dirtyFlags |= 0x2;
this->m_highlightRight = 0;
this->m_highlightLeft = 0;
}
this->m_dirtyFlags |= 0x1 | 0x4;
if (!a4) {
this->m_dirtyFlags |= 0x8;
}
if (!this->m_textLength) {
// TODO this->simpleeditbox_dwordC = 0;
}
}
}
void CSimpleEditBox::FontUpdated(CSimpleFontedFrameFont* font, int32_t a3) {
// TODO
}
int32_t CSimpleEditBox::GetNumToLen(int32_t offset, int32_t amount, bool a4) {
uint32_t len = 0;
uint32_t* textInfo = this->m_textInfo + offset;
if (amount > 0) {
for (int32_t i = 0; i < amount; i++) {
if (!*textInfo) {
break;
}
uint32_t v8;
uint32_t v9;
uint32_t v10;
do {
do {
v8 = *((uint8_t*)textInfo + 2);
v9 = (uint16_t)*textInfo;
v10 = *textInfo & 0xFF000000;
len += v9;
textInfo += v9;
} while (v8 == 1);
} while (v8 == 5 || v8 == 7 || (a4 && v10 < 0 && v8 != 6));
uint32_t v11;
uint32_t v12;
while (1) {
v11 = *((uint8_t*)textInfo + 2);
v12 = *textInfo & 0xFFFF;
if (v11 != 2 && v11 != 6 && v11 != 8) {
break;
}
len += v12;
textInfo += v12;
}
}
} else {
for (int32_t i = 0; i < -amount; i++) {
if (textInfo <= this->m_textInfo) {
break;
}
uint32_t v14;
do {
for (--textInfo; textInfo > this->m_textInfo; --textInfo) {
if (*textInfo) {
break;
}
}
v14 = *((uint8_t*)textInfo + 2);
len += (uint16_t)*textInfo;
} while (v14 == 2 || v14 == 6 || v14 == 8 || (a4 && (*textInfo & 0x80000000) != 0 && v14 != 5));
if (textInfo > this->m_textInfo) {
uint32_t v15;
uint32_t v16;
while (1) {
for (--textInfo; textInfo > this->m_textInfo; --textInfo) {
if (*textInfo) {
break;
}
}
v15 = *((uint8_t*)textInfo + 2);
v16 = *textInfo & 0xFFFF;
if (v15 != 1 && v15 != 5 && v15 != 7) {
break;
}
len += v16;
if (textInfo <= this->m_textInfo) {
break;
}
}
if (textInfo > this->m_textInfo) {
textInfo += v16;
}
}
}
}
return len;
}
FrameScript_Object::ScriptIx* CSimpleEditBox::GetScriptByName(const char* name, ScriptData& data) {
auto parentScript = CSimpleFrame::GetScriptByName(name, data);
if (parentScript) {
return parentScript;
}
if (!SStrCmpI(name, "OnEnterPressed", STORM_MAX_STR)) {
return &this->m_onEnterPressed;
}
if (!SStrCmpI(name, "OnEscapePressed", STORM_MAX_STR)) {
return &this->m_onEscapePressed;
}
if (!SStrCmpI(name, "OnSpacePressed", STORM_MAX_STR)) {
return &this->m_onSpacePressed;
}
if (!SStrCmpI(name, "OnTabPressed", STORM_MAX_STR)) {
return &this->m_onTabPressed;
}
if (!SStrCmpI(name, "OnTextChanged", STORM_MAX_STR)) {
data.wrapper = "return function(self, userInput) %s end";
return &this->m_onTextChanged;
}
if (!SStrCmpI(name, "OnTextSet", STORM_MAX_STR)) {
return &this->m_onTextSet;
}
if (!SStrCmpI(name, "OnCursorChanged", STORM_MAX_STR)) {
data.wrapper = "return function(self,x,y,w,h) %s end";
return &this->m_onCursorChanged;
}
if (!SStrCmpI(name, "OnInputLanguageChanged", STORM_MAX_STR)) {
data.wrapper = "return function(self,language) %s end";
return &this->m_onInputLanguageChanged;
}
if (!SStrCmpI(name, "OnEditFocusGained", STORM_MAX_STR)) {
return &this->m_onEditFocusGained;
}
if (!SStrCmpI(name, "OnEditFocusLost", STORM_MAX_STR)) {
return &this->m_onEditFocusLost;
}
if (!SStrCmpI(name, "OnCharComposition", STORM_MAX_STR)) {
data.wrapper = "return function(self,text) %s end";
return &this->m_onCharComposition;
}
return nullptr;
}
int32_t CSimpleEditBox::GetScriptMetaTable() {
return CSimpleEditBox::s_metatable;
}
void CSimpleEditBox::GrowText(int32_t size) {
if (size + 1 <= this->m_textSize) {
return;
}
this->m_textSize = (size + 32) & 0xFFFFFFE0;
this->m_text = static_cast<char*>(
SMemReAlloc(this->m_text, this->m_textSize, __FILE__, __LINE__, 0)
);
this->m_textInfo = static_cast<uint32_t*>(
SMemReAlloc(this->m_textInfo, this->m_textSize * sizeof(uint32_t), __FILE__, __LINE__, 0)
);
}
void CSimpleEditBox::Insert(uint32_t chr) {
if (chr == '\t') {
this->Insert(" ", nullptr, 1, 0, 0);
return;
}
if (chr == '|') {
this->Insert("||", nullptr, 1, 0, 0);
return;
}
if ((this->m_multiline && chr == '\n') || (chr >= ' ' && chr != 127)) {
char charBuf[8];
SUniSPutUTF8(chr, charBuf);
this->Insert(charBuf, nullptr, 1, 0, 0);
return;
}
}
void CSimpleEditBox::Insert(const char* a2, const char* a3, int32_t a4, int32_t a5, int32_t a6) {
if (
(this->m_textInfo[this->m_cursorPos] & 0x80000000)
&& this->m_cursorPos > 0
&& (this->m_textInfo[this->PrevCharOffset(this->m_cursorPos)] & 0x80000000)
) {
return;
}
if (this->m_highlightLeft != this->m_highlightRight) {
this->DeleteHighlight(a6);
}
if (!a2) {
a2 = "";
}
const char* v10 = a2;
if (this->m_numeric && !a5 && *v10) {
while (*v10) {
int32_t v33;
if (SUniSGetUTF8(reinterpret_cast<const uint8_t*>(a2), &v33) - 48 > 9) {
return;
}
v10 += v33;
}
}
int32_t v11 = SStrLen(a2);
this->GrowText(this->m_textLength + v11);
char* v14 = this->m_text + this->m_cursorPos;
if (this->m_cursorPos < this->m_textLength) {
memcpy(v14 + v11, v14, this->m_textLength - this->m_cursorPos);
}
memcpy(v14, a2, v11);
this->m_textLength += v11;
*(this->m_text + this->m_textLength) = 0;
int32_t v31 = this->m_cursorPos;
this->m_cursorPos += v11;
this->UpdateTextInfo();
this->m_dirtyFlags |= (0x1 | 0x4);
a6 ? this->m_dirtyFlags &= ~0x8 : this->m_dirtyFlags |= 0x8;
if (this->m_textLengthMax >= 0 && this->m_textLength > this->m_textLengthMax) {
// TODO
}
if (this->m_textLettersMax) {
// TODO
}
if (a5) {
this->m_highlightLeft = v31;
this->m_highlightRight = std::min(this->m_textLength, this->m_cursorPos);
this->m_dirtyFlags |= 2u;
}
// TODO
// if (!this->m_intC && this->m_textLength > 0) {
// this->m_intC = a3;
// }
if (a4) {
this->RunOnCharScript(a2);
// TODO
// - check for spaces and run onSpacePressed script
}
}
bool CSimpleEditBox::IsA(int32_t type) {
return type == CSimpleEditBox::s_objectType
|| type == CSimpleFrame::s_objectType
|| type == CScriptRegion::s_objectType
|| type == CScriptObject::s_objectType;
}
int32_t CSimpleEditBox::IsCurrentFocus() {
return this == CSimpleEditBox::s_currentFocus;
}
void CSimpleEditBox::LoadXML(XMLNode* node, CStatus* status) {
CSimpleFrame::LoadXML(node, status);
const char* fontAttr = node->GetAttributeByName("font");
if (fontAttr && *fontAttr) {
auto font = CSimpleFont::GetFont(fontAttr, 0);
if (font) {
this->m_font->SetFontObject(font);
} else {
status->Add(
STATUS_WARNING,
"%s %s: Couldn't find font object named %s",
this->GetObjectTypeName(),
this->GetDisplayName(),
fontAttr
);
}
}
// TODO
// - letters
const char* countInvisibleLettersAttr = node->GetAttributeByName("countInvisibleLetters");
if (countInvisibleLettersAttr && *countInvisibleLettersAttr) {
this->m_countInvisibleLetters = StringToBOOL(countInvisibleLettersAttr);
}
const char* blinkSpeedAttr = node->GetAttributeByName("blinkSpeed");
if (blinkSpeedAttr && *blinkSpeedAttr) {
float blinkSpeed = std::max(SStrToFloat(blinkSpeedAttr), 0.0f);
this->m_cursorBlinkSpeed = blinkSpeed;
}
const char* autoFocusAttr = node->GetAttributeByName("autoFocus");
if (autoFocusAttr && *autoFocusAttr) {
this->m_autoFocus = StringToBOOL(autoFocusAttr);
}
const char* multiLineAttr = node->GetAttributeByName("multiLine");
if (multiLineAttr && *multiLineAttr) {
this->m_multiline = StringToBOOL(multiLineAttr);
}
const char* numericAttr = node->GetAttributeByName("numeric");
if (numericAttr && *numericAttr) {
this->m_numeric = StringToBOOL(numericAttr);
}
const char* passwordAttr = node->GetAttributeByName("password");
if (passwordAttr && *passwordAttr) {
this->m_password = StringToBOOL(passwordAttr);
}
const char* ignoreArrowsAttr = node->GetAttributeByName("ignoreArrows");
if (ignoreArrowsAttr && *ignoreArrowsAttr) {
this->m_ignoreArrows = StringToBOOL(ignoreArrowsAttr);
}
const char* historyLinesAttr = node->GetAttributeByName("historyLines");
if (historyLinesAttr && *historyLinesAttr) {
int32_t historyLines = std::max(SStrToInt(historyLinesAttr), 0);
this->SetHistoryLines(historyLines);
}
for (XMLNode* child = node->m_child; child; child = child->m_next) {
if (!SStrCmpI(child->GetName(), "FontString", STORM_MAX_STR)) {
CSimpleFont* font = this->m_font;
if (font->GetFontObject()) {
status->Add(
STATUS_WARNING,
"%s: FontString element overriding font %s",
this->GetDisplayName(),
font->GetFontObject()->GetName()
);
}
this->m_font->LoadXML(child, status);
const char* bytesAttr = child->GetAttributeByName("bytes");
if (bytesAttr && *bytesAttr) {
int32_t bytes = SStrToInt(bytesAttr);
// TODO
// - set some member of CSimpleEditBox
}
} else if (!SStrCmpI(child->GetName(), "HighlightColor", STORM_MAX_STR)) {
// TODO
} else if (!SStrCmpI(child->GetName(), "TextInsets", STORM_MAX_STR)) {
float left, right, top, bottom;
if (LoadXML_Insets(child, left, right, top, bottom, status)) {
this->m_editTextInset.minX = left;
this->m_editTextInset.maxX = right;
this->m_editTextInset.maxY = top;
this->m_editTextInset.minY = bottom;
this->UpdateSizes();
}
}
}
}
void CSimpleEditBox::Move(int32_t distance, int32_t highlight) {
STORM_ASSERT(distance);
auto offset = this->GetNumToLen(this->m_cursorPos, distance, true);
if (distance < 0) {
offset = -offset;
}
if (highlight) {
if (this->m_highlightLeft == this->m_highlightRight) {
this->m_highlightLeft = this->m_cursorPos;
this->m_highlightRight = this->m_cursorPos;
}
// TODO this->Sub9631A0(offset);
this->m_cursorPos += offset;
this->m_dirtyFlags |= 0x4;
} else {
if (this->m_highlightLeft != this->m_highlightRight) {
this->m_dirtyFlags |= 0x2;
this->m_highlightLeft = 0;
this->m_highlightRight = 0;
}
this->m_cursorPos += offset;
this->m_dirtyFlags |= 0x4;
}
}
void CSimpleEditBox::MoveBackward(int32_t highlight) {
if (this->m_cursorPos > 0) {
this->Move(-1, highlight);
}
if (!highlight && this->m_highlightLeft != this->m_highlightRight) {
this->m_dirtyFlags |= 0x2;
this->m_highlightLeft = 0;
this->m_highlightRight = 0;
}
}
void CSimpleEditBox::MoveForward(int32_t highlight) {
if (this->m_cursorPos < this->m_textLength) {
this->Move(1, highlight);
}
if (!highlight && this->m_highlightLeft != this->m_highlightRight) {
this->m_dirtyFlags |= 0x2;
this->m_highlightLeft = 0;
this->m_highlightRight = 0;
}
}
void CSimpleEditBox::OnEnterPressed() {
this->RunOnEnterPressedScript();
// TODO
// - invoke action
}
void CSimpleEditBox::OnEscapePressed() {
// TODO
}
void CSimpleEditBox::OnFrameSizeChanged(float width, float height) {
CSimpleFrame::OnFrameSizeChanged(width, height);
this->UpdateSizes();
}
int32_t CSimpleEditBox::OnLayerChar(const CCharEvent& evt) {
if (!this->m_visible) {
return 0;
}
if (!CSimpleEditBox::s_currentFocus && this->m_autoFocus) {
CSimpleEditBox::SetKeyboardFocus(this);
} else if (!this->IsCurrentFocus()) {
return 0;
}
this->m_imeInputMode = 0;
this->Insert(evt.ch);
return 1;
}
int32_t CSimpleEditBox::OnLayerKeyDown(const CKeyEvent& evt) {
if (!this->m_visible) {
return 0;
}
if (evt.key == KEY_PRINTSCREEN
|| (
this->m_ignoreArrows
&& (evt.key == KEY_LEFT || evt.key == KEY_RIGHT || evt.key == KEY_UP || evt.key == KEY_DOWN)
&& !EventIsKeyDown(KEY_LALT)
&& !EventIsKeyDown(KEY_RALT)
)
) {
return 0;
}
if (!CSimpleEditBox::s_currentFocus && this->m_autoFocus) {
CSimpleEditBox::SetKeyboardFocus(this);
} else if (!this->IsCurrentFocus()) {
return 0;
}
this->UpdateDirtyBits();
switch (evt.key) {
case KEY_ESCAPE: {
this->OnEscapePressed();
return 1;
}
case KEY_ENTER: {
if (!this->m_multiline || this->m_onEnterPressed.luaRef) {
// TODO
// this->m_top->m_int1250 = 1;
this->OnEnterPressed();
// TODO
// this->m_top->m_int1250 = 0;
} else {
this->Insert("\n", 0, 1, 0, 0);
}
return 1;
}
case KEY_BACKSPACE: {
if (EventIsControlKeyDown()) {
// TODO this->DeleteBackwardWord(0);
} else {
this->DeleteBackward(0);
}
return 1;
}
case KEY_LEFT: {
if (EventIsControlKeyDown()) {
// TODO this->MoveBackwardWord(EventIsShiftKeyDown());
} else {
this->MoveBackward(EventIsShiftKeyDown());
}
return 1;
}
case KEY_RIGHT: {
if (EventIsControlKeyDown()) {
// TODO this->MoveForwardWord(EventIsShiftKeyDown());
} else {
this->MoveForward(EventIsShiftKeyDown());
}
return 1;
}
case KEY_DELETE: {
if (EventIsShiftKeyDown()) {
// TODO cut to clipboard
} else if (EventIsControlKeyDown()) {
// TODO this->DeleteForwardWord(0);
} else {
this->DeleteForward(0);
}
return 1;
}
// TODO
// - remaining keys
default:
return 1;
}
}
int32_t CSimpleEditBox::OnLayerMouseDown(const CMouseEvent& evt, const char* btn) {
int32_t eaten = CSimpleFrame::OnLayerMouseDown(evt, btn);
if (!eaten) {
this->UpdateDirtyBits();
int32_t position;
if (!this->m_imeInputMode && this->ConvertCoordinateToIndex(evt.x, evt.y, position)) {
if (this->m_highlightLeft != this->m_highlightRight) {
this->m_dirtyFlags |= 0x2;
this->m_highlightRight = 0;
this->m_highlightLeft = 0;
}
this->SetCursorPosition(position);
this->StartHighlight();
this->m_highlightDrag = 1;
eaten = 1;
}
CSimpleEditBox::SetKeyboardFocus(this);
}
return eaten;
}
int32_t CSimpleEditBox::OnLayerMouseUp(const CMouseEvent& evt, const char* btn) {
int32_t eaten = CSimpleFrame::OnLayerMouseUp(evt, btn);
if (!eaten) {
if (this->m_highlightDrag) {
this->m_highlightDrag = 0;
eaten = 1;
}
}
return eaten;
}
void CSimpleEditBox::OnLayerUpdate(float elapsedSec) {
CSimpleFrame::OnLayerUpdate(elapsedSec);
this->UpdateDirtyBits();
if (!GxCapsWindowHasFocus(-1)) {
this->m_cursor->Hide();
return;
}
if (this->m_cursorBlinkSpeed == 0.0f) {
return;
}
bool cursorVisible = this->m_cursorPos >= this->m_visiblePos
&& this->m_cursorPos <= this->m_visiblePos + this->m_visibleLen;
if (!cursorVisible) {
return;
}
this->m_blinkElapsedTime += elapsedSec;
if (this->IsCurrentFocus() && this->m_blinkElapsedTime > this->m_cursorBlinkSpeed) {
if (this->m_cursor->IsShown()) {
this->m_cursor->Hide();
} else {
this->m_cursor->Show();
}
this->m_blinkElapsedTime = 0.0f;
}
}
void CSimpleEditBox::OnTextChanged() {
this->RunOnTextChangedScript((this->m_dirtyFlags & 0x8) != 0);
// TODO
// - invoke action
}
int32_t CSimpleEditBox::PrevCharOffset(int32_t offset) {
int32_t prevCharOffset = offset;
while (prevCharOffset > 0 && !this->m_textInfo[prevCharOffset - 1]) {
prevCharOffset--;
}
return prevCharOffset;
}
void CSimpleEditBox::RunOnCursorChangedScript(float x, float y, float w, float h) {
// TODO
}
void CSimpleEditBox::RunOnEditFocusGainedScript() {
if (this->m_onEditFocusGained.luaRef) {
this->RunScript(this->m_onEditFocusGained, 0, 0);
}
}
void CSimpleEditBox::RunOnEditFocusLostScript() {
if (this->m_onEditFocusLost.luaRef) {
this->RunScript(this->m_onEditFocusLost, 0, 0);
}
}
void CSimpleEditBox::RunOnEnterPressedScript() {
if (this->m_onEnterPressed.luaRef) {
this->RunScript(this->m_onEnterPressed, 0, 0);
}
}
void CSimpleEditBox::RunOnTextChangedScript(int32_t changed) {
if (this->m_onTextChanged.luaRef) {
auto L = FrameScript_GetContext();
lua_pushboolean(L, changed);
this->RunScript(this->m_onTextChanged, 1, 0);
}
}
void CSimpleEditBox::SetCursorPosition(int32_t position) {
if (position >= 0) {
this->m_cursorPos = std::min(this->m_textLength, position);
} else {
this->m_cursorPos = 0;
}
this->m_dirtyFlags |= 0x4;
}
void CSimpleEditBox::SetHistoryLines(int32_t a2) {
// TODO
}
void CSimpleEditBox::SetMultiLine(int32_t enabled) {
if (enabled) {
this->m_multiline = 1;
} else {
this->m_multiline = 0;
}
this->m_visibleLines.SetCount(2);
if (this->m_multiline) {
this->m_string->SetJustifyV(0x8);
// TODO
// - unknown style change (remove flag 0x4000)
this->m_string->SetNonWordWrap(0);
} else {
this->m_string->SetJustifyV(0x10);
// TODO
// - unknown style change (add flag 0x4000)
this->m_string->SetNonWordWrap(1);
}
this->m_string->SetNonSpaceWrap(1);
this->UpdateSizes();
}
void CSimpleEditBox::StartHighlight() {
// TODO
}
void CSimpleEditBox::UpdateDirtyBits() {
int32_t textChanged = this->m_dirtyFlags & 0x1;
if (this->m_dirtyFlags & 0x4) {
// TODO
}
if (this->m_dirtyFlags & 0x1) {
this->m_dirtyFlags &= ~0x1;
this->UpdateVisibleText();
}
if (this->m_dirtyFlags & 0x2) {
this->m_dirtyFlags &= ~0x2;
this->UpdateVisibleHighlight();
}
if (this->m_dirtyFlags & 0x4) {
this->m_dirtyFlags &= ~0x4;
this->UpdateVisibleCursor();
}
if (textChanged) {
this->OnTextChanged();
this->m_dirtyFlags &= ~0x8;
}
}
void CSimpleEditBox::UpdateSizes() {
if (!(CLayoutFrame::m_flags & 0x1)) {
return;
}
this->m_string->ClearAllPoints();
float stringWidth = ((this->m_rect.maxX - this->m_rect.minX) / this->m_layoutScale)
- (this->m_editTextInset.maxX + this->m_editTextInset.minX);
this->m_string->SetWidth(stringWidth);
float stringHeight = 0.0f;
if (!this->m_multiline) {
stringHeight = ((this->m_rect.maxY - this->m_rect.minY) / this->m_layoutScale)
- (this->m_editTextInset.maxY + this->m_editTextInset.minY);
}
this->m_string->SetHeight(stringHeight);
this->m_string->SetPoint(
FRAMEPOINT_TOPLEFT,
this,
FRAMEPOINT_TOPLEFT,
this->m_editTextInset.minX,
-this->m_editTextInset.maxY,
1
);
float fontHeight = this->m_string->GetFontHeight(1);
for (int32_t i = 0; i < 3; i++) {
// TODO
// - highlight sizing
}
// TODO
// - clause highlight? sizing
float v13 = 4.0f / (CoordinateGetAspectCompensation() * 1024.0f);
float cursorWidth = NDCToDDCWidth(v13);
this->m_cursor->ClearAllPoints();
this->m_cursor->SetWidth(cursorWidth);
this->m_cursor->SetHeight(fontHeight);
this->m_dirtyFlags |= (0x1 | 0x2 | 0x4);
}
void CSimpleEditBox::UpdateTextInfo() {
memset(this->m_textInfo, 0, this->m_textSize * sizeof(uint32_t));
uint32_t i = 0;
uint32_t v9 = 0;
int32_t advance;
uint32_t code;
const char* text = this->m_text;
while (text && *text) {
QUOTEDCODE quotedCode = GxuDetermineQuotedCode(text, advance, nullptr, 0, code);
if (quotedCode == CODE_HYPERLINKSTART) {
v9 |= 0x80000000;
}
this->m_textInfo[i] = v9 | (quotedCode << 16) | static_cast<uint16_t>(advance);
if (quotedCode == CODE_HYPERLINKSTOP) {
v9 &= 0x7FFFFFFF;
}
i += advance;
text += advance;
}
}
void CSimpleEditBox::UpdateVisibleCursor() {
bool cursorVisible = this->m_cursorPos >= this->m_visiblePos
&& this->m_cursorPos <= this->m_visiblePos + this->m_visibleLen;
if (!cursorVisible) {
this->m_cursor->Hide();
return;
}
const char* text = this->m_password
? this->m_textHidden
: this->m_text;
float cursorX = 0.0f;
float cursorY = 0.0f;
float v8 = CSimpleTop::RoundToPixelHeight(this->m_string->GetFontHeight(1) * this->m_layoutScale);
float v10 = CSimpleTop::RoundToPixelHeight(this->m_string->m_spacing * this->m_layoutScale);
float v13 = (v10 + v8) / this->m_layoutScale;
int32_t cursorPos = this->m_cursorPos;
int32_t line = 0;
while (cursorPos >= this->m_visibleLines[line + 1] && line < this->m_visibleLines.Count() - 2) {
line++;
cursorY -= v13;
}
this->m_cursor->ClearAllPoints();
// Left aligned
if (this->m_string->m_styleFlags & 0x1) {
float v36;
if (cursorPos == this->m_visibleLines[line]) {
v36 = 0.0f;
} else {
v36 = this->m_string->GetTextWidth(
text + this->m_visibleLines[line],
cursorPos - this->m_visibleLines[line]
);
}
cursorX = v36;
if (this->m_multiline) {
this->m_cursor->SetPoint(
FRAMEPOINT_TOPLEFT,
this->m_string,
FRAMEPOINT_TOPLEFT,
cursorX,
cursorY,
1
);
} else {
this->m_cursor->SetPoint(
FRAMEPOINT_LEFT,
this->m_string,
FRAMEPOINT_LEFT,
cursorX,
cursorY,
1
);
}
// Center aligned
} else if (this->m_string->m_styleFlags & 0x2) {
float v28;
if (cursorPos == this->m_visibleLines[line]) {
v28 = 0.0f;
} else {
v28 = this->m_string->GetTextWidth(
text + this->m_visibleLines[line],
cursorPos - this->m_visibleLines[line]
);
}
float v29 = this->m_string->GetTextWidth(
text + this->m_visibleLines[line],
this->m_visibleLines[line + 1] - this->m_visibleLines[line]
);
cursorX = (v28 - v29) / 2.0f;
if (this->m_multiline) {
this->m_cursor->SetPoint(
FRAMEPOINT_TOPLEFT,
this->m_string,
FRAMEPOINT_TOP,
cursorX,
cursorY,
1
);
} else {
this->m_cursor->SetPoint(
FRAMEPOINT_LEFT,
this->m_string,
FRAMEPOINT_CENTER,
cursorX,
cursorY,
1
);
}
// Right aligned
} else if (this->m_string->m_styleFlags & 0x4) {
// TODO
}
this->m_blinkElapsedTime = 0.0f;
float cursorWidth = this->m_cursor->GetWidth();
float cursorHeight = this->m_cursor->GetHeight();
this->RunOnCursorChangedScript(cursorX, cursorY, cursorWidth, cursorHeight);
if (this->IsCurrentFocus()) {
this->m_cursor->Show();
} else {
this->m_cursor->Hide();
}
}
void CSimpleEditBox::UpdateVisibleHighlight() {
// TODO
}
void CSimpleEditBox::UpdateVisibleText() {
float stringWidth = this->m_string->GetWidth();
// Update password mask
if (this->m_password) {
int32_t textLen = SStrLen(this->m_text);
this->m_textHidden = static_cast<char*>(
SMemReAlloc(this->m_textHidden, textLen + 1, __FILE__, __LINE__, 0)
);
memset(this->m_textHidden, '*', textLen);
this->m_textHidden[textLen] = '\0';
}
char* text = this->m_password
? this->m_textHidden
: this->m_text;
if (this->m_multiline) {
// TODO
} else {
float v16 = 4.0f / (CoordinateGetAspectCompensation() * 1024.0f);
float v17 = stringWidth - NDCToDDCWidth(v16);
if (v17 <= 0.0) {
v17 = stringWidth;
}
this->m_visibleLen = this->m_string->GetNumCharsWithinWidth(
text + this->m_visiblePos,
0,
v17
);
if (this->m_text == text) {
this->m_visibleLen = this->GetNumToLen(
this->m_visiblePos,
this->m_visibleLen,
0
);
}
this->m_visibleLines[0] = this->m_visiblePos;
this->m_visibleLines[1] = this->m_visiblePos + this->m_visibleLen;
}
if (!this->m_password) {
// TODO
}
int32_t visibleEnd = this->m_visiblePos + this->m_visibleLen;
auto v42 = text[visibleEnd];
text[visibleEnd] = '\0';
this->m_string->SetText(text + this->m_visiblePos, 0);
text[visibleEnd] = v42;
if (this->m_multiline) {
auto height = this->m_string->GetStringHeight();
if (height == 0.0f) {
height = this->m_string->GetFontHeight(1);
}
this->SetHeight(height + this->m_editTextInset.minY + this->m_editTextInset.maxY);
}
}