InputText: Word-Wrap: attempt to track cursor while resizing frame/parent.

This commit is contained in:
ocornut
2025-09-02 15:37:27 +02:00
parent 6db17055f5
commit df018e07b0
2 changed files with 27 additions and 7 deletions

View File

@@ -1260,6 +1260,7 @@ struct IMGUI_API ImGuiInputTextState
float WrapWidth; // word-wrapping width
float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately
bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!)
bool CursorCenterY; // set when we want scrolling to be centered over the cursor position (while resizing a word-wrapping field)
bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
bool Edited; // edited this frame
bool WantReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version.

View File

@@ -4827,6 +4827,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_password && !is_displaying_hint)
PushPasswordFont();
// Word-wrapping: attempt to keep cursor in view while resizing frame/parent
// FIXME-WORDWRAP: It would be better to preserve same relative offset.
if (is_wordwrap && state != NULL && state->ID == id && state->WrapWidth != wrap_width)
{
state->CursorCenterY = true;
state->WrapWidth = wrap_width;
render_cursor = true;
}
// Process mouse inputs and character inputs
if (g.ActiveId == id)
{
@@ -5420,6 +5429,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
// Scroll
float new_scroll_y = scroll_y;
if (render_cursor && state->CursorFollow)
{
// Horizontal scroll in chunks of quarter width
@@ -5442,18 +5452,27 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
{
// Test if cursor is vertically visible
if (cursor_offset.y - g.FontSize < scroll_y)
scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
new_scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
else if (cursor_offset.y - (inner_size.y - style.FramePadding.y * 2.0f) >= scroll_y)
scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f;
new_scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f;
}
state->CursorFollow = false;
}
if (state->CursorCenterY)
{
if (is_multiline)
new_scroll_y = cursor_offset.y - g.FontSize - (inner_size.y * 0.5f - style.FramePadding.y);
state->CursorCenterY = false;
render_cursor = false;
}
if (new_scroll_y != scroll_y)
{
const float scroll_max_y = ImMax((text_size.y + style.FramePadding.y * 2.0f) - inner_size.y, 0.0f);
scroll_y = ImClamp(scroll_y, 0.0f, scroll_max_y);
scroll_y = ImClamp(new_scroll_y, 0.0f, scroll_max_y);
draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag
draw_window->Scroll.y = scroll_y;
}
state->CursorFollow = false;
}
// Draw selection
const ImVec2 draw_scroll = ImVec2(state->Scroll.x, 0.0f);
if (render_selection)