UI: improve widget text cursor position

Use BLF_boundbox_foreach_glyph for more accurate cursor placement.
This commit is contained in:
Harley Acheson 2020-05-03 16:52:41 +10:00 committed by Campbell Barton
parent 0d65520f05
commit 5366eb89c6
2 changed files with 40 additions and 47 deletions

View File

@ -2848,6 +2848,23 @@ static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
return changed;
}
static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str),
const size_t str_step_ofs,
const rcti *glyph_step_bounds,
const int UNUSED(glyph_advance_x),
const rctf *glyph_bounds,
const float UNUSED(glyph_bearing[2]),
void *user_data)
{
int *cursor_data = user_data;
float center = glyph_step_bounds->xmin + (BLI_rctf_size_x(glyph_bounds) / 2.0f);
if (cursor_data[0] < center) {
cursor_data[1] = str_step_ofs;
return false;
}
return true;
}
/**
* \param x: Screen space cursor location - #wmEvent.x
*
@ -2883,8 +2900,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
startx += UI_DPI_ICON_SIZE / aspect;
}
}
/* But this extra .05 makes clicks in between characters feel nicer. */
startx += ((UI_TEXT_MARGIN_X + 0.05f) * U.widget_unit) / aspect;
startx += (UI_TEXT_MARGIN_X * U.widget_unit) / aspect;
/* mouse dragged outside the widget to the left */
if (x < startx) {
@ -2907,48 +2923,24 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
but->pos = but->ofs;
}
/* mouse inside the widget, mouse coords mapped in widget space */
else { /* (x >= startx) */
int pos_i;
/* keep track of previous distance from the cursor to the char */
float cdist, cdist_prev = 0.0f;
short pos_prev;
str_last = &str[strlen(str)];
but->pos = pos_prev = ((str_last - str) - but->ofs);
while (true) {
cdist = startx + BLF_width(fstyle.uifont_id, str + but->ofs, (str_last - str) - but->ofs);
/* check if position is found */
if (cdist < x) {
/* check is previous location was in fact closer */
if ((x - cdist) > (cdist_prev - x)) {
but->pos = pos_prev;
}
break;
}
cdist_prev = cdist;
pos_prev = but->pos;
/* done with tricky distance checks */
pos_i = but->pos;
if (but->pos <= 0) {
break;
}
if (BLI_str_cursor_step_prev_utf8(str + but->ofs, but->ofs, &pos_i)) {
but->pos = pos_i;
str_last = &str[but->pos + but->ofs];
}
else {
break; /* unlikely but possible */
}
}
but->pos += but->ofs;
if (but->pos < 0) {
but->pos = 0;
else {
str_last = &str[but->ofs];
const int str_last_len = strlen(str_last);
int x_pos = (int)(x - startx);
int glyph_data[2] = {
x_pos, /* horizontal position to test. */
-1, /* Write the character offset here. */
};
BLF_boundbox_foreach_glyph(fstyle.uifont_id,
str + but->ofs,
INT_MAX,
ui_textedit_set_cursor_pos_foreach_glyph,
glyph_data);
/* If value untouched then we are to the right. */
if (glyph_data[1] == -1) {
glyph_data[1] = str_last_len;
}
but->pos = glyph_data[1] + but->ofs;
}
if (fstyle.kerning == 1) {

View File

@ -2097,15 +2097,16 @@ static void widget_draw_text_ime_underline(const uiFontStyle *fstyle,
static bool widget_draw_text_underline_calc_center_x(const char *UNUSED(str),
const size_t str_step_ofs,
const rcti *glyph_step_bounds,
const int glyph_advance_x,
const rctf *UNUSED(glyph_bounds),
const float UNUSED(glyph_bearing[2]),
const int UNUSED(glyph_advance_x),
const rctf *glyph_bounds,
const float glyph_bearing[2],
void *user_data)
{
/* The index of the character to get, set to the x-position. */
int *ul_data = user_data;
if (ul_data[0] == (int)str_step_ofs) {
ul_data[1] = glyph_step_bounds->xmin + (glyph_advance_x / 2);
ul_data[1] = glyph_step_bounds->xmin + glyph_bearing[0] +
(BLI_rctf_size_x(glyph_bounds) / 2.0f);
/* Early exit. */
return false;
}