113 lines
2.9 KiB
C++
113 lines
2.9 KiB
C++
|
/**
|
||
|
* @file InputField.cpp
|
||
|
* @author apio (cloudapio.eu)
|
||
|
* @brief Single line text input widget.
|
||
|
*
|
||
|
* @copyright Copyright (c) 2024, the Luna authors.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <ctype.h>
|
||
|
#include <luna/String.h>
|
||
|
#include <luna/StringView.h>
|
||
|
#include <luna/Utf8.h>
|
||
|
#include <ui/InputField.h>
|
||
|
|
||
|
namespace ui
|
||
|
{
|
||
|
InputField::InputField(SharedPtr<ui::Font> font) : ui::TextInput(), m_font(font)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
Result<ui::EventResult> InputField::handle_key_event(const ui::KeyEventRequest& request)
|
||
|
{
|
||
|
// Avoid handling "key released" events
|
||
|
if (!request.pressed) return ui::EventResult::DidNotHandle;
|
||
|
|
||
|
if (request.code == moon::K_LeftArrow)
|
||
|
{
|
||
|
if (m_cursor > 0) m_cursor--;
|
||
|
else
|
||
|
return ui::EventResult::DidNotHandle;
|
||
|
update_cursor();
|
||
|
return ui::EventResult::DidHandle;
|
||
|
}
|
||
|
|
||
|
if (request.code == moon::K_RightArrow)
|
||
|
{
|
||
|
if (m_cursor < m_data.size()) m_cursor++;
|
||
|
else
|
||
|
return ui::EventResult::DidNotHandle;
|
||
|
update_cursor();
|
||
|
return ui::EventResult::DidHandle;
|
||
|
}
|
||
|
|
||
|
if (request.code == moon::K_Backspace)
|
||
|
{
|
||
|
if (m_cursor == 0) return ui::EventResult::DidNotHandle;
|
||
|
m_cursor--;
|
||
|
|
||
|
delete_current_character();
|
||
|
|
||
|
update_cursor();
|
||
|
|
||
|
return ui::EventResult::DidHandle;
|
||
|
}
|
||
|
|
||
|
if (request.letter == '\n')
|
||
|
{
|
||
|
if (m_has_on_submit_action)
|
||
|
{
|
||
|
m_on_submit_action(data());
|
||
|
return ui::EventResult::DidHandle;
|
||
|
}
|
||
|
|
||
|
return ui::EventResult::DidNotHandle;
|
||
|
}
|
||
|
|
||
|
if (iscntrl(request.letter)) return ui::EventResult::DidNotHandle;
|
||
|
|
||
|
if (m_cursor == m_data.size()) TRY(m_data.append_data((const u8*)&request.letter, 1));
|
||
|
else
|
||
|
TRY(insert_character(request.letter));
|
||
|
|
||
|
m_cursor++;
|
||
|
|
||
|
update_cursor();
|
||
|
|
||
|
return ui::EventResult::DidHandle;
|
||
|
}
|
||
|
|
||
|
Result<void> InputField::draw(ui::Canvas& canvas)
|
||
|
{
|
||
|
int visible_characters = canvas.width / m_font->width();
|
||
|
|
||
|
auto string = data();
|
||
|
|
||
|
Utf8StringDecoder decoder(string.chars());
|
||
|
wchar_t buf[4096];
|
||
|
decoder.decode(buf, sizeof(buf)).release_value();
|
||
|
|
||
|
int characters_to_render = (int)wcslen(buf);
|
||
|
|
||
|
for (int j = 0; j < visible_characters && j < characters_to_render; j++)
|
||
|
{
|
||
|
auto subcanvas = canvas.subcanvas({ j * m_font->width(), 0, m_font->width(), m_font->height() });
|
||
|
m_font->render(buf[j], ui::WHITE, subcanvas);
|
||
|
}
|
||
|
|
||
|
// Draw the cursor
|
||
|
if ((int)m_cursor < visible_characters && m_cursor_activated)
|
||
|
{
|
||
|
canvas.subcanvas({ (int)m_cursor * m_font->width(), 0, 1, m_font->height() }).fill(ui::WHITE);
|
||
|
}
|
||
|
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
StringView InputField::data()
|
||
|
{
|
||
|
return StringView { (const char*)m_data.data(), m_data.size() };
|
||
|
}
|
||
|
}
|