Internal: InputText: refactor the flow to easily decorrelate rendering of selection vs cursor, which would allow us to render selection on inactive items, and generally makes the code clearer. + Some renaming.

This commit is contained in:
omar 2019-02-21 19:45:28 +01:00
parent 332f8f2462
commit be593f2c16

View File

@ -3143,6 +3143,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
ImGuiIO& io = g.IO; ImGuiIO& io = g.IO;
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const bool RENDER_SELECTION_WHEN_INACTIVE = true;
const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0; const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0;
const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
@ -3220,8 +3221,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetScrollbarID(draw_window, ImGuiAxis_Y); const bool user_scroll_active = is_multiline && state != NULL && g.ActiveId == GetScrollbarID(draw_window, ImGuiAxis_Y);
bool clear_active_id = false; bool clear_active_id = false;
bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline); bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline);
if (focus_requested || user_clicked || user_scroll_finish || user_nav_input_start) if (focus_requested || user_clicked || user_scroll_finish || user_nav_input_start)
{ {
if (g.ActiveId != id) if (g.ActiveId != id)
@ -3649,7 +3650,12 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size
ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding; ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
ImVec2 text_size(0.0f, 0.0f); ImVec2 text_size(0.0f, 0.0f);
if (g.ActiveId == id || user_scroll_active)
// We currently only render selection when the widget is active or while scrolling.
// FIXME: We could remove the '&& render_cursor' to keep rendering selection when inactive.
const bool render_cursor = (g.ActiveId == id) || user_scroll_active;
const bool render_selection = state && state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor);
if (render_cursor || render_selection)
{ {
// Render text (with cursor and selection) // Render text (with cursor and selection)
// This is going to be messy. We need to: // This is going to be messy. We need to:
@ -3663,16 +3669,20 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
ImVec2 cursor_offset, select_start_offset; ImVec2 cursor_offset, select_start_offset;
{ {
// Count lines + find lines numbers straddling 'cursor' and 'select_start' position. // Find lines numbers straddling 'cursor' (slot 0) and 'select_start' (slot 1) positions.
const ImWchar* searches_input_ptr[2]; const ImWchar* searches_input_ptr[2] = { NULL, NULL };
int searches_result_line_no[2] = { -1000, -1000 };
int searches_remaining = 0;
if (render_cursor)
{
searches_input_ptr[0] = text_begin + state->Stb.cursor; searches_input_ptr[0] = text_begin + state->Stb.cursor;
searches_input_ptr[1] = NULL; searches_result_line_no[0] = -1;
int searches_remaining = 1; searches_remaining++;
int searches_result_line_number[2] = { -1, -999 }; }
if (state->Stb.select_start != state->Stb.select_end) if (render_selection)
{ {
searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
searches_result_line_number[1] = -1; searches_result_line_no[1] = -1;
searches_remaining++; searches_remaining++;
} }
@ -3685,20 +3695,22 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (*s == '\n') if (*s == '\n')
{ {
line_count++; line_count++;
if (searches_result_line_number[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_number[0] = line_count; if (--searches_remaining <= 0) break; } if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count; if (--searches_remaining <= 0) break; }
if (searches_result_line_number[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_number[1] = line_count; if (--searches_remaining <= 0) break; } if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count; if (--searches_remaining <= 0) break; }
} }
line_count++; line_count++;
if (searches_result_line_number[0] == -1) searches_result_line_number[0] = line_count; if (searches_result_line_no[0] == -1)
if (searches_result_line_number[1] == -1) searches_result_line_number[1] = line_count; searches_result_line_no[0] = line_count;
if (searches_result_line_no[1] == -1)
searches_result_line_no[1] = line_count;
// Calculate 2d position by finding the beginning of the line and measuring distance // Calculate 2d position by finding the beginning of the line and measuring distance
cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x; cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
cursor_offset.y = searches_result_line_number[0] * g.FontSize; cursor_offset.y = searches_result_line_no[0] * g.FontSize;
if (searches_result_line_number[1] >= 0) if (searches_result_line_no[1] >= 0)
{ {
select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x; select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
select_start_offset.y = searches_result_line_number[1] * g.FontSize; select_start_offset.y = searches_result_line_no[1] * g.FontSize;
} }
// Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224) // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224)
@ -3707,7 +3719,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
} }
// Scroll // Scroll
if (state->CursorFollow) if (render_cursor && state->CursorFollow)
{ {
// Horizontal scroll in chunks of quarter width // Horizontal scroll in chunks of quarter width
if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll)) if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll))
@ -3735,19 +3747,20 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
draw_window->Scroll.y = scroll_y; draw_window->Scroll.y = scroll_y;
draw_pos.y = draw_window->DC.CursorPos.y; draw_pos.y = draw_window->DC.CursorPos.y;
} }
}
const ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f);
state->CursorFollow = false; state->CursorFollow = false;
}
// Draw selection // Draw selection
if (state->HasSelection()) const ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f);
if (render_selection)
{ {
const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end); const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end); const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end);
ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests.
float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection. float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
float bg_offy_dn = is_multiline ? 0.0f : 2.0f; float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg);
ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll; ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll;
for (const ImWchar* p = text_selected_begin; p < text_selected_end; ) for (const ImWchar* p = text_selected_begin; p < text_selected_end; )
{ {
@ -3781,6 +3794,8 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + buf_display_len, 0.0f, is_multiline ? NULL : &clip_rect); draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + buf_display_len, 0.0f, is_multiline ? NULL : &clip_rect);
// Draw blinking cursor // Draw blinking cursor
if (render_cursor)
{
state->CursorAnim += io.DeltaTime; state->CursorAnim += io.DeltaTime;
bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f; bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f;
ImVec2 cursor_screen_pos = draw_pos + cursor_offset - draw_scroll; ImVec2 cursor_screen_pos = draw_pos + cursor_offset - draw_scroll;
@ -3792,6 +3807,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
if (!is_readonly) if (!is_readonly)
g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize);
} }
}
else else
{ {
// Render text only (no selection, no cursor) // Render text only (no selection, no cursor)