Initial caret draw/control

This commit is contained in:
w1naenator 2025-04-30 01:47:43 +03:00
parent 020e1d0574
commit bdd2b4d4c9
4 changed files with 87 additions and 11 deletions

View file

@ -379,6 +379,16 @@ void ImeDialogUi::DrawInputText() {
InputTextCallback, this)) {
state->input_changed = true;
}
// CARET: manually render even if not focused
if (!ImGui::IsItemActive()) {
// Calculate input field position
ImVec2 input_pos = ImGui::GetItemRectMin();
// Find where to draw the caret
DrawCaretForInputText(state->current_text.begin(), state->caret_index, input_pos);
}
// ────── replicate keyboards hover→nav focus highlight ──────
if (ImGui::IsItemHovered()) {
ImGui::SetItemCurrentNavFocus();
@ -601,14 +611,25 @@ void ImeDialogUi::OnVirtualKeyEvent(const VirtualKeyEvent* evt) {
case KeyType::Character: {
char utf8[8]{};
int n = c16rtomb(utf8, key->character);
if (n > 0)
state->AppendUtf8(utf8, (size_t)n);
if (n > 0) {
state->InsertUtf8AtCaret(utf8, (size_t)n);
}
break;
}
case KeyType::Function:
switch (key->keycode) {
case KC_LEFT: // Your custom code for ◀ button
if (state->caret_index > 0)
state->caret_index--;
LOG_INFO(Lib_ImeDialog, "Caret index = {}", state->caret_index);
break;
case KC_RIGHT: // Your custom code for ▶ button
if (state->caret_index < (int)state->current_text.size())
state->caret_index++;
LOG_INFO(Lib_ImeDialog, "Caret index = {}", state->caret_index);
break;
case 0x08:
state->BackspaceUtf8();
state->BackspaceUtf8AtCaret();
break; // Backspace
case 0x0D:
*status = OrbisImeDialogStatus::Finished; // Enter

View file

@ -45,6 +45,7 @@ class ImeDialogState final {
// Optional custom keyboard style (from extended params)
bool has_custom_style = false;
KeyboardStyle custom_kb_style{};
int caret_index = 0;
public:
/*──────────────── constructors / ruleoffive ────────────────*/
@ -91,15 +92,23 @@ public:
input_changed = true;
}
// Append raw UTF8 sequence of length 'len'
void AppendUtf8(const char* utf8, std::size_t len) {
void InsertUtf8AtCaret(const char* utf8, std::size_t len) {
if (!utf8 || len == 0)
return;
std::size_t old = std::strlen(current_text.begin());
if (old + len >= current_text.capacity())
return; // full: silently ignore
std::memcpy(current_text.begin() + old, utf8, len);
current_text[old + len] = '\0';
std::size_t old_len = std::strlen(current_text.begin());
if (old_len + len >= current_text.capacity())
return; // full, silently ignore
// Move the text after caret forward
char* text_begin = current_text.begin();
std::memmove(text_begin + caret_index + len, text_begin + caret_index,
old_len - caret_index + 1); // +1 for null-terminator
// Copy the inserted text at caret position
std::memcpy(text_begin + caret_index, utf8, len);
caret_index += (int)len; // Move caret after inserted text
input_changed = true;
}
@ -109,6 +118,29 @@ public:
input_changed = true;
}
void BackspaceUtf8AtCaret() {
char* buf = current_text.begin();
size_t len = std::strlen(buf);
if (caret_index == 0 || len == 0)
return;
// Find byte index just before caret (start of previous codepoint)
int remove_start = caret_index - 1;
while (remove_start > 0 &&
(static_cast<unsigned char>(buf[remove_start]) & 0b11000000) == 0b10000000)
--remove_start;
int remove_len = caret_index - remove_start;
// Shift everything after caret to the left
std::memmove(buf + remove_start, buf + caret_index,
len - caret_index + 1); // +1 to move null terminator
caret_index = remove_start;
input_changed = true;
}
private:
bool CallKeyboardFilter(const OrbisImeKeycode* src_keycode, u16* out_keycode, u32* out_status);

View file

@ -56,4 +56,8 @@ constexpr u16 KC_ACCENTS = 0xF102;
constexpr u16 KC_LETTERS = 0xF103;
constexpr u16 KC_KB = 0xF104;
constexpr u16 KC_GYRO = 0xF105;
constexpr u16 KC_OPT = 0xF106;
constexpr u16 KC_OPT = 0xF106;
constexpr u16 KC_UP = 0xF020;
constexpr u16 KC_DOWN = 0xF021;
constexpr u16 KC_LEFT = 0xF022;
constexpr u16 KC_RIGHT = 0xF023;

View file

@ -88,4 +88,23 @@ static void DrawCenteredText(const char* text, const char* text_end = nullptr,
SetCursorPos(pos + content);
}
inline void DrawCaretForInputText(const char* text, int caret_index, ImVec2 input_pos,
float padding_x = 4.0f, float padding_y = 3.0f) {
ImVec2 text_size = ImGui::CalcTextSize(text, text + caret_index);
float caret_x = input_pos.x + padding_x + text_size.x;
float caret_y = input_pos.y + padding_y;
float caret_height = ImGui::GetTextLineHeight();
// Optional: make caret blink like ImGui does
float time = ImGui::GetTime();
bool visible = (fmodf(time, 1.2f) < 0.8f);
if (!visible)
return;
ImGui::GetWindowDrawList()->AddLine(ImVec2(caret_x, caret_y),
ImVec2(caret_x, caret_y + caret_height),
IM_COL32(255, 255, 255, 255), 1.0f);
}
} // namespace ImGui