181
src/ImGui.cpp
181
src/ImGui.cpp
@@ -15,20 +15,20 @@ namespace {
|
||||
|
||||
struct CodepointSpan {
|
||||
u32 codepoint {};
|
||||
std::size_t start {};
|
||||
std::size_t end {};
|
||||
usize start {};
|
||||
usize end {};
|
||||
};
|
||||
|
||||
auto decode_utf8(std::string_view text) -> std::vector<CodepointSpan>
|
||||
{
|
||||
std::vector<CodepointSpan> spans;
|
||||
std::size_t i = 0;
|
||||
usize i = 0;
|
||||
spans.reserve(text.size());
|
||||
|
||||
while (i < text.size()) {
|
||||
u8 const byte = static_cast<u8>(text[i]);
|
||||
std::size_t const start = i;
|
||||
std::size_t length = 1;
|
||||
usize const start = i;
|
||||
usize length = 1;
|
||||
u32 cp = 0xFFFD;
|
||||
|
||||
if (byte < 0x80) {
|
||||
@@ -111,9 +111,9 @@ auto encode_utf8(u32 cp) -> std::string
|
||||
return std::string(buf, len);
|
||||
}
|
||||
|
||||
auto rune_index_for_byte(std::string_view text, std::size_t byte_offset) -> int
|
||||
auto rune_index_for_byte(std::string_view text, usize byte_offset) -> int
|
||||
{
|
||||
auto spans = decode_utf8(text);
|
||||
auto spans { decode_utf8(text) };
|
||||
int idx = 0;
|
||||
for (auto const &span : spans) {
|
||||
if (span.start >= byte_offset)
|
||||
@@ -125,15 +125,15 @@ auto rune_index_for_byte(std::string_view text, std::size_t byte_offset) -> int
|
||||
return idx;
|
||||
}
|
||||
|
||||
auto clamp_preedit_index(int value, std::size_t text_size) -> std::size_t
|
||||
auto clamp_preedit_index(int value, usize text_size) -> usize
|
||||
{
|
||||
if (value < 0)
|
||||
return 0;
|
||||
auto const as_size = static_cast<std::size_t>(value);
|
||||
auto const as_size { static_cast<usize>(value) };
|
||||
return std::min(as_size, text_size);
|
||||
}
|
||||
|
||||
auto slice_bytes(std::string_view text, std::size_t begin, std::size_t end)
|
||||
auto slice_bytes(std::string_view text, usize begin, usize end)
|
||||
-> std::string_view
|
||||
{
|
||||
if (begin > text.size())
|
||||
@@ -169,17 +169,17 @@ void ImGui::end() { }
|
||||
|
||||
void ImGui::set_font(FontHandle font) { m_font = font; }
|
||||
|
||||
auto ImGui::focused_text_input() const -> std::optional<std::size_t>
|
||||
auto ImGui::focused_text_input() const -> std::optional<usize>
|
||||
{
|
||||
if (m_focused_id == 0)
|
||||
return std::nullopt;
|
||||
return m_focused_id;
|
||||
}
|
||||
|
||||
auto ImGui::text_input_surrounding(std::size_t id,
|
||||
std::pmr::string const &str) const -> std::optional<TextInputSurrounding>
|
||||
auto ImGui::text_input_surrounding(usize id, std::pmr::string const &str) const
|
||||
-> std::optional<TextInputSurrounding>
|
||||
{
|
||||
auto it = m_ti_states.find(id);
|
||||
auto it { m_ti_states.find(id) };
|
||||
if (it == m_ti_states.end())
|
||||
return std::nullopt;
|
||||
TextInputSurrounding info;
|
||||
@@ -190,10 +190,9 @@ auto ImGui::text_input_surrounding(std::size_t id,
|
||||
return info;
|
||||
}
|
||||
|
||||
auto ImGui::text_input_cursor(std::size_t id) const
|
||||
-> std::optional<TextInputCursor>
|
||||
auto ImGui::text_input_cursor(usize id) const -> std::optional<TextInputCursor>
|
||||
{
|
||||
auto it = m_ti_states.find(id);
|
||||
auto it { m_ti_states.find(id) };
|
||||
if (it == m_ti_states.end())
|
||||
return std::nullopt;
|
||||
TextInputCursor cursor;
|
||||
@@ -207,11 +206,11 @@ void ImGui::ime_commit_text(std::pmr::string &str, std::string_view text)
|
||||
{
|
||||
if (m_focused_id == 0)
|
||||
return;
|
||||
auto it = m_ti_states.find(m_focused_id);
|
||||
auto it { m_ti_states.find(m_focused_id) };
|
||||
if (it == m_ti_states.end())
|
||||
return;
|
||||
auto &state = it->second;
|
||||
std::size_t insert_pos = std::min(state.caret_byte, str.size());
|
||||
auto &state { it->second };
|
||||
usize insert_pos = std::min(state.caret_byte, str.size());
|
||||
if (!text.empty())
|
||||
str.insert(insert_pos, text);
|
||||
state.caret_byte = insert_pos + text.size();
|
||||
@@ -223,17 +222,17 @@ void ImGui::ime_commit_text(std::pmr::string &str, std::string_view text)
|
||||
}
|
||||
|
||||
void ImGui::ime_delete_surrounding(
|
||||
std::pmr::string &str, std::size_t before, std::size_t after)
|
||||
std::pmr::string &str, usize before, usize after)
|
||||
{
|
||||
if (m_focused_id == 0)
|
||||
return;
|
||||
auto it = m_ti_states.find(m_focused_id);
|
||||
auto it { m_ti_states.find(m_focused_id) };
|
||||
if (it == m_ti_states.end())
|
||||
return;
|
||||
auto &state = it->second;
|
||||
std::size_t caret_byte = std::min(state.caret_byte, str.size());
|
||||
std::size_t start = before > caret_byte ? 0 : caret_byte - before;
|
||||
std::size_t end = std::min(caret_byte + after, str.size());
|
||||
auto &state { it->second };
|
||||
usize caret_byte = std::min(state.caret_byte, str.size());
|
||||
usize start = before > caret_byte ? 0 : caret_byte - before;
|
||||
usize end = std::min(caret_byte + after, str.size());
|
||||
if (end > start) {
|
||||
str.erase(start, end - start);
|
||||
state.caret_byte = start;
|
||||
@@ -249,19 +248,19 @@ void ImGui::ime_set_preedit(std::string text, int cursor_begin, int cursor_end)
|
||||
{
|
||||
if (m_focused_id == 0)
|
||||
return;
|
||||
auto it = m_ti_states.find(m_focused_id);
|
||||
auto it { m_ti_states.find(m_focused_id) };
|
||||
if (it == m_ti_states.end())
|
||||
return;
|
||||
auto &state = it->second;
|
||||
auto &state { it->second };
|
||||
state.preedit_text = std::move(text);
|
||||
state.preedit_cursor_hidden = (cursor_begin == -1 && cursor_end == -1);
|
||||
std::size_t const size = state.preedit_text.size();
|
||||
usize const size = state.preedit_text.size();
|
||||
if (state.preedit_cursor_hidden) {
|
||||
state.preedit_cursor_begin = 0;
|
||||
state.preedit_cursor_end = 0;
|
||||
} else {
|
||||
auto begin_clamped = clamp_preedit_index(cursor_begin, size);
|
||||
auto end_clamped = clamp_preedit_index(cursor_end, size);
|
||||
auto begin_clamped { clamp_preedit_index(cursor_begin, size) };
|
||||
auto end_clamped { clamp_preedit_index(cursor_end, size) };
|
||||
state.preedit_cursor_begin = static_cast<int>(begin_clamped);
|
||||
state.preedit_cursor_end = static_cast<int>(end_clamped);
|
||||
}
|
||||
@@ -277,10 +276,10 @@ void ImGui::ime_clear_preedit()
|
||||
{
|
||||
if (m_focused_id == 0)
|
||||
return;
|
||||
auto it = m_ti_states.find(m_focused_id);
|
||||
auto it { m_ti_states.find(m_focused_id) };
|
||||
if (it == m_ti_states.end())
|
||||
return;
|
||||
auto &state = it->second;
|
||||
auto &state { it->second };
|
||||
state.preedit_text.clear();
|
||||
state.preedit_cursor_begin = 0;
|
||||
state.preedit_cursor_end = 0;
|
||||
@@ -290,7 +289,7 @@ void ImGui::ime_clear_preedit()
|
||||
state.caret_timer = 0.0;
|
||||
}
|
||||
|
||||
auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec,
|
||||
auto ImGui::text_input(usize id, std::pmr::string &str, Rectangle rec,
|
||||
TextInputOptions options) -> std::bitset<2>
|
||||
{
|
||||
assert(id != 0);
|
||||
@@ -300,7 +299,7 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec,
|
||||
bool submitted { false };
|
||||
bool changed { false };
|
||||
|
||||
auto &state = m_ti_states[id];
|
||||
auto &state { m_ti_states[id] };
|
||||
|
||||
assert(!options.multiline && "Multiline not yet implemented.");
|
||||
|
||||
@@ -316,44 +315,44 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec,
|
||||
}
|
||||
|
||||
std::string_view str_view(str.data(), str.size());
|
||||
auto spans = decode_utf8(str_view);
|
||||
auto spans { decode_utf8(str_view) };
|
||||
|
||||
auto is_space = [](u32 cp) -> bool {
|
||||
auto is_space { [](u32 cp) -> bool {
|
||||
if (cp == '\n' || cp == '\r' || cp == '\t' || cp == '\v' || cp == '\f')
|
||||
return true;
|
||||
if (cp <= 0x7F)
|
||||
return std::isspace(static_cast<unsigned char>(cp)) != 0;
|
||||
return false;
|
||||
};
|
||||
} };
|
||||
|
||||
auto clamp_cursor = [&]() -> std::size_t {
|
||||
auto clamp_cursor { [&]() -> usize {
|
||||
int const max_idx = static_cast<int>(spans.size());
|
||||
state.current_rune_idx = std::clamp(state.current_rune_idx, 0, max_idx);
|
||||
if (state.current_rune_idx == max_idx)
|
||||
return str.size();
|
||||
return spans[state.current_rune_idx].start;
|
||||
};
|
||||
} };
|
||||
|
||||
std::size_t caret_byte = clamp_cursor();
|
||||
usize caret_byte = clamp_cursor();
|
||||
|
||||
auto refresh_spans = [&]() {
|
||||
auto refresh_spans { [&]() {
|
||||
str_view = std::string_view(str.data(), str.size());
|
||||
spans = decode_utf8(str_view);
|
||||
caret_byte = clamp_cursor();
|
||||
};
|
||||
} };
|
||||
|
||||
auto erase_range = [&](std::size_t byte_begin, std::size_t byte_end) {
|
||||
auto erase_range { [&](usize byte_begin, usize byte_end) {
|
||||
if (byte_end > byte_begin && byte_begin < str.size()) {
|
||||
str.erase(byte_begin, byte_end - byte_begin);
|
||||
changed = true;
|
||||
}
|
||||
};
|
||||
} };
|
||||
|
||||
bool caret_activity = false;
|
||||
|
||||
if (m_focused_id == id && m_rune != 0) {
|
||||
bool request_refresh = false;
|
||||
auto handle_backspace = [&]() {
|
||||
auto handle_backspace { [&]() {
|
||||
if (state.current_rune_idx <= 0
|
||||
|| state.current_rune_idx > static_cast<int>(spans.size()))
|
||||
return;
|
||||
@@ -362,31 +361,28 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec,
|
||||
int idx = state.current_rune_idx;
|
||||
int scan = idx - 1;
|
||||
while (scan >= 0
|
||||
&& is_space(
|
||||
spans[static_cast<std::size_t>(scan)].codepoint))
|
||||
&& is_space(spans[static_cast<usize>(scan)].codepoint))
|
||||
scan--;
|
||||
while (scan >= 0
|
||||
&& !is_space(
|
||||
spans[static_cast<std::size_t>(scan)].codepoint))
|
||||
&& !is_space(spans[static_cast<usize>(scan)].codepoint))
|
||||
scan--;
|
||||
int start_idx = std::max(scan + 1, 0);
|
||||
std::size_t byte_begin
|
||||
= spans[static_cast<std::size_t>(start_idx)].start;
|
||||
std::size_t byte_end = (idx >= static_cast<int>(spans.size()))
|
||||
usize byte_begin = spans[static_cast<usize>(start_idx)].start;
|
||||
usize byte_end = (idx >= static_cast<int>(spans.size()))
|
||||
? str.size()
|
||||
: spans[static_cast<std::size_t>(idx)].start;
|
||||
: spans[static_cast<usize>(idx)].start;
|
||||
erase_range(byte_begin, byte_end);
|
||||
state.current_rune_idx = start_idx;
|
||||
} else {
|
||||
auto const &prev = spans[static_cast<std::size_t>(
|
||||
state.current_rune_idx - 1)];
|
||||
auto const &prev
|
||||
= spans[static_cast<usize>(state.current_rune_idx - 1)];
|
||||
erase_range(prev.start, prev.end);
|
||||
state.current_rune_idx--;
|
||||
}
|
||||
request_refresh = true;
|
||||
};
|
||||
} };
|
||||
|
||||
auto handle_delete = [&]() {
|
||||
auto handle_delete { [&]() {
|
||||
if (state.current_rune_idx < 0
|
||||
|| state.current_rune_idx >= static_cast<int>(spans.size())) {
|
||||
if (!m_ctrl)
|
||||
@@ -397,26 +393,24 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec,
|
||||
if (m_ctrl) {
|
||||
int scan = idx;
|
||||
while (scan < static_cast<int>(spans.size())
|
||||
&& is_space(
|
||||
spans[static_cast<std::size_t>(scan)].codepoint))
|
||||
&& is_space(spans[static_cast<usize>(scan)].codepoint))
|
||||
scan++;
|
||||
while (scan < static_cast<int>(spans.size())
|
||||
&& !is_space(
|
||||
spans[static_cast<std::size_t>(scan)].codepoint))
|
||||
&& !is_space(spans[static_cast<usize>(scan)].codepoint))
|
||||
scan++;
|
||||
std::size_t byte_begin = (idx < static_cast<int>(spans.size()))
|
||||
? spans[static_cast<std::size_t>(idx)].start
|
||||
usize byte_begin = (idx < static_cast<int>(spans.size()))
|
||||
? spans[static_cast<usize>(idx)].start
|
||||
: str.size();
|
||||
std::size_t byte_end = (scan < static_cast<int>(spans.size()))
|
||||
? spans[static_cast<std::size_t>(scan)].start
|
||||
usize byte_end = (scan < static_cast<int>(spans.size()))
|
||||
? spans[static_cast<usize>(scan)].start
|
||||
: str.size();
|
||||
erase_range(byte_begin, byte_end);
|
||||
} else if (idx < static_cast<int>(spans.size())) {
|
||||
auto const &curr = spans[static_cast<std::size_t>(idx)];
|
||||
auto const &curr { spans[static_cast<usize>(idx)] };
|
||||
erase_range(curr.start, curr.end);
|
||||
}
|
||||
request_refresh = true;
|
||||
};
|
||||
} };
|
||||
|
||||
switch (m_rune) {
|
||||
case 1: // Left (H)
|
||||
@@ -424,13 +418,13 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec,
|
||||
state.current_rune_idx--;
|
||||
if (m_ctrl) {
|
||||
while (state.current_rune_idx > 0
|
||||
&& is_space(spans[static_cast<std::size_t>(
|
||||
state.current_rune_idx)]
|
||||
&& is_space(
|
||||
spans[static_cast<usize>(state.current_rune_idx)]
|
||||
.codepoint))
|
||||
state.current_rune_idx--;
|
||||
while (state.current_rune_idx > 0
|
||||
&& !is_space(spans[static_cast<std::size_t>(
|
||||
state.current_rune_idx)]
|
||||
&& !is_space(
|
||||
spans[static_cast<usize>(state.current_rune_idx)]
|
||||
.codepoint))
|
||||
state.current_rune_idx--;
|
||||
}
|
||||
@@ -443,13 +437,13 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec,
|
||||
if (m_ctrl) {
|
||||
while (
|
||||
state.current_rune_idx < static_cast<int>(spans.size())
|
||||
&& is_space(spans[static_cast<std::size_t>(
|
||||
&& is_space(spans[static_cast<usize>(
|
||||
state.current_rune_idx - 1)]
|
||||
.codepoint))
|
||||
state.current_rune_idx++;
|
||||
while (
|
||||
state.current_rune_idx < static_cast<int>(spans.size())
|
||||
&& !is_space(spans[static_cast<std::size_t>(
|
||||
&& !is_space(spans[static_cast<usize>(
|
||||
state.current_rune_idx - 1)]
|
||||
.codepoint))
|
||||
state.current_rune_idx++;
|
||||
@@ -474,7 +468,7 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec,
|
||||
case '\r':
|
||||
case '\n':
|
||||
if (options.multiline) {
|
||||
auto encoded = encode_utf8('\n');
|
||||
auto encoded { encode_utf8('\n') };
|
||||
if (!encoded.empty()) {
|
||||
str.insert(caret_byte, encoded);
|
||||
state.current_rune_idx++;
|
||||
@@ -487,7 +481,7 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec,
|
||||
break;
|
||||
default:
|
||||
if (m_rune >= 0x20) {
|
||||
auto encoded = encode_utf8(m_rune);
|
||||
auto encoded { encode_utf8(m_rune) };
|
||||
if (!encoded.empty()) {
|
||||
str.insert(caret_byte, encoded);
|
||||
state.current_rune_idx++;
|
||||
@@ -556,13 +550,15 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec,
|
||||
preedit_metrics
|
||||
= m_text_renderer->measure_text(*m_font, preedit_view, font_px);
|
||||
|
||||
auto caret_idx = clamp_preedit_index(
|
||||
state.preedit_cursor_end, preedit_view.size());
|
||||
auto caret_idx { clamp_preedit_index(
|
||||
state.preedit_cursor_end, preedit_view.size()) };
|
||||
caret_preedit_metrics = m_text_renderer->measure_text(
|
||||
*m_font, slice_bytes(preedit_view, 0, caret_idx), font_px);
|
||||
*m_font, slice_bytes(preedit_view, 0, caret_idx), font_px)
|
||||
|
||||
if (!state.preedit_cursor_hidden
|
||||
&& state.preedit_cursor_begin != state.preedit_cursor_end) {
|
||||
if (!state.preedit_cursor_hidden
|
||||
&& state.preedit_cursor_begin
|
||||
!= state.preedit_cursor_end)
|
||||
{
|
||||
auto sel_begin
|
||||
= clamp_preedit_index(std::min(state.preedit_cursor_begin,
|
||||
state.preedit_cursor_end),
|
||||
@@ -717,3 +713,26 @@ auto ImGui::text_input(std::size_t id, std::pmr::string &str, Rectangle rec,
|
||||
return std::bitset<2> { static_cast<unsigned long long>(
|
||||
(submitted ? 1 : 0) | (changed ? 2 : 0)) };
|
||||
}
|
||||
|
||||
auto ImGui::list_view(usize id, Rectangle bounds, usize elements,
|
||||
std::function<Vector2(usize i)> draw_cb, ListViewOptions options) -> bool
|
||||
{
|
||||
auto &state { m_lv_states[id] };
|
||||
|
||||
bool submitted { false };
|
||||
|
||||
bool select_next = m_next_lv_next;
|
||||
m_next_lv_next = false;
|
||||
bool select_previous = m_next_lv_previous;
|
||||
m_next_lv_previous = false;
|
||||
bool select_clear = m_next_lv_clear;
|
||||
m_next_lv_clear = false;
|
||||
|
||||
BeginScissorMode(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
|
||||
EndScissorMode();
|
||||
|
||||
m_prev_lv_selected_item = state.selected_item;
|
||||
|
||||
return submitted;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user