Fix #113154: Hang double-clicking on UI elements outside a text field
The logic to handle word selection from double clicking ran even when the event wasn't inside the button. This would pass an invalid position to BLI_str_cursor_step_bounds_utf8 which hung. Resolve by limiting word-selection to when the event is inside the text editing field as well as clamping the position to ensure it's within the allowed range.
This commit is contained in:
parent
779239f5e1
commit
26bb029ad8
|
@ -345,6 +345,7 @@ void BLI_str_cursor_step_bounds_utf8(
|
|||
const char *str, const int str_maxlen, const int pos, int *r_start, int *r_end)
|
||||
{
|
||||
BLI_assert(str_maxlen >= 0);
|
||||
BLI_assert(pos >= 0 && pos <= str_maxlen);
|
||||
/* Identify the type of characters are on either side of the current cursor position. */
|
||||
const eStrCursorDelimType prev = (pos > 0) ? cursor_delim_type_utf8(str, str_maxlen, pos - 1) :
|
||||
STRCUR_DELIM_NONE;
|
||||
|
@ -373,6 +374,7 @@ void BLI_str_cursor_step_bounds_utf32(
|
|||
const char32_t *str, const int str_maxlen, const int pos, int *r_start, int *r_end)
|
||||
{
|
||||
BLI_assert(str_maxlen >= 0);
|
||||
BLI_assert(pos >= 0 && pos <= str_maxlen);
|
||||
/* Identify the type of characters are on either side of the current cursor position. */
|
||||
const eStrCursorDelimType prev = (pos > 0) ? cursor_delim_type_unicode(str[pos - 1]) :
|
||||
STRCUR_DELIM_NONE;
|
||||
|
|
|
@ -3771,14 +3771,21 @@ static void ui_do_but_textedit(
|
|||
inbox = ui_searchbox_inside(data->searchbox, event->xy);
|
||||
}
|
||||
|
||||
/* for double click: we do a press again for when you first click on button
|
||||
* (selects all text, no cursor pos) */
|
||||
bool is_press_in_button = false;
|
||||
if (ELEM(event->val, KM_PRESS, KM_DBL_CLICK)) {
|
||||
float mx = event->xy[0];
|
||||
float my = event->xy[1];
|
||||
ui_window_to_block_fl(data->region, block, &mx, &my);
|
||||
|
||||
if (ui_but_contains_pt(but, mx, my)) {
|
||||
is_press_in_button = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* for double click: we do a press again for when you first click on button
|
||||
* (selects all text, no cursor pos) */
|
||||
if (ELEM(event->val, KM_PRESS, KM_DBL_CLICK)) {
|
||||
if (is_press_in_button) {
|
||||
ui_textedit_set_cursor_pos(but, data, event->xy[0]);
|
||||
but->selsta = but->selend = but->pos;
|
||||
data->sel_pos_init = but->pos;
|
||||
|
@ -3798,15 +3805,22 @@ static void ui_do_but_textedit(
|
|||
|
||||
/* only select a word in button if there was no selection before */
|
||||
if (event->val == KM_DBL_CLICK && had_selection == false) {
|
||||
int selsta, selend;
|
||||
BLI_str_cursor_step_bounds_utf8(data->str, strlen(data->str), but->pos, &selsta, &selend);
|
||||
but->pos = short(selend);
|
||||
but->selsta = short(selsta);
|
||||
but->selend = short(selend);
|
||||
/* Anchor selection to the left side unless the last word. */
|
||||
data->sel_pos_init = ((selend == strlen(data->str)) && (selsta != 0)) ? selend : selsta;
|
||||
retval = WM_UI_HANDLER_BREAK;
|
||||
changed = true;
|
||||
if (is_press_in_button) {
|
||||
const int str_len = strlen(data->str);
|
||||
/* This may not be necessary, additional check to ensure `pos` is never out of range,
|
||||
* since negative values aren't acceptable, see: #113154. */
|
||||
CLAMP(but->pos, 0, str_len);
|
||||
|
||||
int selsta, selend;
|
||||
BLI_str_cursor_step_bounds_utf8(data->str, str_len, but->pos, &selsta, &selend);
|
||||
but->pos = short(selend);
|
||||
but->selsta = short(selsta);
|
||||
but->selend = short(selend);
|
||||
/* Anchor selection to the left side unless the last word. */
|
||||
data->sel_pos_init = ((selend == str_len) && (selsta != 0)) ? selend : selsta;
|
||||
retval = WM_UI_HANDLER_BREAK;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else if (inbox) {
|
||||
/* if we allow activation on key press,
|
||||
|
|
Loading…
Reference in New Issue