135
src/ImGui.cpp
135
src/ImGui.cpp
@@ -19,67 +19,52 @@ struct CodepointSpan {
|
||||
usize end {};
|
||||
};
|
||||
|
||||
auto decode_utf8(std::string_view text) -> std::vector<CodepointSpan>
|
||||
constexpr auto utf8_rune_from_first(char const *s) -> u32
|
||||
{
|
||||
u8 b0 = static_cast<u8>(s[0]);
|
||||
if (b0 < 0x80)
|
||||
return b0;
|
||||
|
||||
if ((b0 & 0xE0) == 0xC0)
|
||||
return ((b0 & 0x1F) << 6) | (static_cast<u8>(s[1]) & 0x3F);
|
||||
|
||||
if ((b0 & 0xF0) == 0xE0)
|
||||
return ((b0 & 0x0F) << 12) | ((static_cast<u8>(s[1]) & 0x3F) << 6)
|
||||
| (static_cast<u8>(s[2]) & 0x3F);
|
||||
|
||||
if ((b0 & 0xF8) == 0xF0)
|
||||
return ((b0 & 0x07) << 18) | ((static_cast<u8>(s[1]) & 0x3F) << 12)
|
||||
| ((static_cast<u8>(s[2]) & 0x3F) << 6)
|
||||
| (static_cast<u8>(s[3]) & 0x3F);
|
||||
|
||||
return 0xFFFD;
|
||||
}
|
||||
|
||||
constexpr auto decode_utf8(std::string_view text) -> std::vector<CodepointSpan>
|
||||
{
|
||||
std::vector<CodepointSpan> spans;
|
||||
usize i = 0;
|
||||
spans.reserve(text.size());
|
||||
|
||||
while (i < text.size()) {
|
||||
u8 const byte = static_cast<u8>(text[i]);
|
||||
usize const start = i;
|
||||
usize length = 1;
|
||||
u32 cp = 0xFFFD;
|
||||
u8 b = static_cast<u8>(text[i]);
|
||||
usize len = 1;
|
||||
|
||||
if (byte < 0x80) {
|
||||
cp = byte;
|
||||
} else if ((byte & 0xE0) == 0xC0) {
|
||||
if (i + 1 < text.size()) {
|
||||
u8 const b1 = static_cast<u8>(text[i + 1]);
|
||||
if ((b1 & 0xC0) == 0x80) {
|
||||
u32 const t = ((static_cast<u32>(byte) & 0x1F) << 6)
|
||||
| (static_cast<u32>(b1) & 0x3F);
|
||||
if (t >= 0x80) {
|
||||
cp = t;
|
||||
length = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ((byte & 0xF0) == 0xE0) {
|
||||
if (i + 2 < text.size()) {
|
||||
u8 const b1 = static_cast<u8>(text[i + 1]);
|
||||
u8 const b2 = static_cast<u8>(text[i + 2]);
|
||||
if ((b1 & 0xC0) == 0x80 && (b2 & 0xC0) == 0x80) {
|
||||
u32 const t = ((static_cast<u32>(byte) & 0x0F) << 12)
|
||||
| ((static_cast<u32>(b1) & 0x3F) << 6)
|
||||
| (static_cast<u32>(b2) & 0x3F);
|
||||
if (t >= 0x800 && (t < 0xD800 || t > 0xDFFF)) {
|
||||
cp = t;
|
||||
length = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ((byte & 0xF8) == 0xF0) {
|
||||
if (i + 3 < text.size()) {
|
||||
u8 const b1 = static_cast<u8>(text[i + 1]);
|
||||
u8 const b2 = static_cast<u8>(text[i + 2]);
|
||||
u8 const b3 = static_cast<u8>(text[i + 3]);
|
||||
if ((b1 & 0xC0) == 0x80 && (b2 & 0xC0) == 0x80
|
||||
&& (b3 & 0xC0) == 0x80) {
|
||||
u32 const t = ((static_cast<u32>(byte) & 0x07) << 18)
|
||||
| ((static_cast<u32>(b1) & 0x3F) << 12)
|
||||
| ((static_cast<u32>(b2) & 0x3F) << 6)
|
||||
| (static_cast<u32>(b3) & 0x3F);
|
||||
if (t >= 0x10000 && t <= 0x10FFFF) {
|
||||
cp = t;
|
||||
length = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (b < 0x80)
|
||||
len = 1;
|
||||
else if ((b & 0xE0) == 0xC0)
|
||||
len = 2;
|
||||
else if ((b & 0xF0) == 0xE0)
|
||||
len = 3;
|
||||
else if ((b & 0xF8) == 0xF0)
|
||||
len = 4;
|
||||
|
||||
spans.push_back(CodepointSpan { cp, start, start + length });
|
||||
i += length;
|
||||
if (i + len > text.size())
|
||||
len = 1; // avoid overflow
|
||||
|
||||
u32 cp = utf8_rune_from_first(text.data() + i);
|
||||
spans.push_back({ cp, i, i + len });
|
||||
i += len;
|
||||
}
|
||||
|
||||
return spans;
|
||||
@@ -158,14 +143,25 @@ ImGui::ImGui(std::shared_ptr<TextRenderer> text_renderer)
|
||||
{
|
||||
}
|
||||
|
||||
void ImGui::begin(u32 const rune, bool ctrl, bool shift)
|
||||
void ImGui::begin(u32 const rune, bool ctrl, bool shift,
|
||||
std::string_view const clipboard,
|
||||
std::function<void(std::string_view const &)> clipboard_set)
|
||||
{
|
||||
m_rune = rune;
|
||||
m_ctrl = ctrl;
|
||||
m_shift = shift;
|
||||
m_clipboard = clipboard;
|
||||
m_clipboard_set = clipboard_set;
|
||||
}
|
||||
|
||||
void ImGui::end() { }
|
||||
void ImGui::end()
|
||||
{
|
||||
m_rune = false;
|
||||
m_ctrl = false;
|
||||
m_shift = false;
|
||||
m_clipboard = {};
|
||||
m_clipboard_set = nullptr;
|
||||
}
|
||||
|
||||
void ImGui::set_font(FontHandle font) { m_font = font; }
|
||||
|
||||
@@ -289,6 +285,15 @@ void ImGui::ime_clear_preedit()
|
||||
state.caret_timer = 0.0;
|
||||
}
|
||||
|
||||
size_t utf8_length(std::string_view const &s)
|
||||
{
|
||||
size_t count = 0;
|
||||
for (unsigned char c : s)
|
||||
if ((c & 0xC0) != 0x80) // continuation bytes
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
auto ImGui::text_input(usize id, std::pmr::string &str, Rectangle rec,
|
||||
TextInputOptions options) -> std::bitset<2>
|
||||
{
|
||||
@@ -479,6 +484,26 @@ auto ImGui::text_input(usize id, std::pmr::string &str, Rectangle rec,
|
||||
submitted = true;
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
if (m_ctrl && !m_clipboard.empty()) {
|
||||
if (!options.multiline) {
|
||||
std::string clipboard_no_newlines;
|
||||
for (auto const &ch : m_clipboard) {
|
||||
if (ch == '\n' || ch == '\r')
|
||||
continue;
|
||||
clipboard_no_newlines.push_back(ch);
|
||||
}
|
||||
str.insert(caret_byte, clipboard_no_newlines);
|
||||
state.current_rune_idx
|
||||
+= utf8_length(clipboard_no_newlines);
|
||||
} else {
|
||||
str.insert(caret_byte, m_clipboard);
|
||||
state.current_rune_idx += utf8_length(m_clipboard);
|
||||
}
|
||||
changed = true;
|
||||
request_refresh = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (m_rune >= 0x20) {
|
||||
auto encoded { encode_utf8(m_rune) };
|
||||
|
||||
Reference in New Issue
Block a user