mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-28 12:29:43 +00:00
imgui: Clamp mouse y-coordinate in multi-line click/drag to text bounds (#15052)
* imgui: Clamp mouse y-coordinate in multi-line click/drag to text bounds In single-line mode, click and drag already clamped y to the line's y-coordinate so the cursor would continue to follow the x-position when the mouse went off the top or bottom of the text. Multi-line mode did not clamp, so stb_text_locate_coord() would return 0 (above) or n (below), snapping the cursor to the very start or end of text and ignoring the x-coordinate entirely. Now both modes walk the row layout to compute the top of the first row (y_min) and bottom of the last row (y_max, minus half a line height to add tolerance for rounding), then clamp y to that range before passing it to stb_text_locate_coord(). This means dragging or clicking above the text now places the cursor on the first line at the x-coordinate, and dragging/clicking below places it on the last line at the x-coordinate, matching the single-line precedent. * Fix issue that cursor cannot be placed at the last empty line
This commit is contained in:
@@ -465,6 +465,57 @@ static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
|
|||||||
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||||
y = r.ymin;
|
y = r.ymin;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// In multi-line mode, clamp y to stay within the text vertical bounds.
|
||||||
|
// This lets the click still land at a valid location if the mouse is slightly
|
||||||
|
// above or below the text.
|
||||||
|
StbTexteditRow r;
|
||||||
|
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||||
|
int i = 0;
|
||||||
|
float base_y = 0, y_min, y_max;
|
||||||
|
|
||||||
|
// Get the first row to establish y_min and start the iteration
|
||||||
|
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||||
|
if (r.num_chars <= 0)
|
||||||
|
{
|
||||||
|
state->cursor = 0;
|
||||||
|
state->select_start = state->cursor;
|
||||||
|
state->select_end = state->cursor;
|
||||||
|
state->has_preferred_x = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
y_min = r.ymin;
|
||||||
|
y_max = base_y + r.ymax;
|
||||||
|
i = r.num_chars;
|
||||||
|
base_y += r.baseline_y_delta;
|
||||||
|
|
||||||
|
// Walk the remaining rows to find the bottom of the last row
|
||||||
|
while (i < n)
|
||||||
|
{
|
||||||
|
STB_TEXTEDIT_LAYOUTROW(&r, str, i);
|
||||||
|
if (r.num_chars <= 0)
|
||||||
|
break;
|
||||||
|
y_max = base_y + r.ymax;
|
||||||
|
i += r.num_chars;
|
||||||
|
base_y += r.baseline_y_delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the text ends with a newline, account for the empty trailing line
|
||||||
|
// so the cursor can be placed on it
|
||||||
|
if (n > 0 && STB_TEXTEDIT_GETCHAR(str, n - 1) == STB_TEXTEDIT_NEWLINE)
|
||||||
|
{
|
||||||
|
STB_TEXTEDIT_LAYOUTROW(&r, str, n);
|
||||||
|
y_max = base_y + r.ymax;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract half the last line height to avoid rounding issues when the mouse
|
||||||
|
// is just barely below the last line (keep cursor on the last line, not after the text)
|
||||||
|
y_max -= (r.ymax - r.ymin) * 0.5f;
|
||||||
|
|
||||||
|
if (y < y_min) y = y_min;
|
||||||
|
if (y > y_max) y = y_max;
|
||||||
|
}
|
||||||
|
|
||||||
state->cursor = stb_text_locate_coord(str, x, y);
|
state->cursor = stb_text_locate_coord(str, x, y);
|
||||||
state->select_start = state->cursor;
|
state->select_start = state->cursor;
|
||||||
@@ -485,6 +536,50 @@ static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state
|
|||||||
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||||
y = r.ymin;
|
y = r.ymin;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// In multi-line mode, clamp y to stay within the text vertical bounds.
|
||||||
|
// This lets the drag keep working if the mouse goes off the top or bottom of the text.
|
||||||
|
StbTexteditRow r;
|
||||||
|
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||||
|
int i = 0;
|
||||||
|
float base_y = 0, y_min, y_max;
|
||||||
|
|
||||||
|
// Get the first row to establish y_min and start the iteration
|
||||||
|
STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
|
||||||
|
if (r.num_chars <= 0)
|
||||||
|
return;
|
||||||
|
y_min = r.ymin;
|
||||||
|
y_max = base_y + r.ymax;
|
||||||
|
i = r.num_chars;
|
||||||
|
base_y += r.baseline_y_delta;
|
||||||
|
|
||||||
|
// Walk the remaining rows to find the bottom of the last row
|
||||||
|
while (i < n)
|
||||||
|
{
|
||||||
|
STB_TEXTEDIT_LAYOUTROW(&r, str, i);
|
||||||
|
if (r.num_chars <= 0)
|
||||||
|
break;
|
||||||
|
y_max = base_y + r.ymax;
|
||||||
|
i += r.num_chars;
|
||||||
|
base_y += r.baseline_y_delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the text ends with a newline, account for the empty trailing line
|
||||||
|
// so the cursor can be placed on it
|
||||||
|
if (n > 0 && STB_TEXTEDIT_GETCHAR(str, n - 1) == STB_TEXTEDIT_NEWLINE)
|
||||||
|
{
|
||||||
|
STB_TEXTEDIT_LAYOUTROW(&r, str, n);
|
||||||
|
y_max = base_y + r.ymax;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract half the last line height to avoid rounding issues when the mouse
|
||||||
|
// is just barely below the last line (keep cursor on the last line, not after the text)
|
||||||
|
y_max -= (r.ymax - r.ymin) * 0.5f;
|
||||||
|
|
||||||
|
if (y < y_min) y = y_min;
|
||||||
|
if (y > y_max) y = y_max;
|
||||||
|
}
|
||||||
|
|
||||||
if (state->select_start == state->select_end)
|
if (state->select_start == state->select_end)
|
||||||
state->select_start = state->cursor;
|
state->select_start = state->cursor;
|
||||||
|
|||||||
Reference in New Issue
Block a user