Refactor: Add BLF Function to determine input selection boxes

Add a separate function that calculates text selection box positioning
given a string's selection start and end offsets. Moves this to a
better place and allows to have more complex boxes in future when we
might have multi-line and/or multi-directional text input.

Pull Request: https://projects.blender.org/blender/blender/pulls/121448
This commit is contained in:
Harley Acheson 2024-05-18 00:13:32 +02:00 committed by Harley Acheson
parent 31560ca26a
commit ba36c69c9f
5 changed files with 59 additions and 41 deletions

@ -8,6 +8,7 @@
#pragma once
#include "BLI_bounds_types.hh"
#include "BLI_compiler_attrs.h"
#include "BLI_string_ref.hh"
#include "BLI_sys_types.h"
@ -179,6 +180,13 @@ bool BLF_str_offset_to_glyph_bounds(int fontid,
int BLF_str_offset_to_cursor(
int fontid, const char *str, size_t str_len, size_t str_offset, float cursor_width);
/**
* Return bounds of selection boxes. There is just one normally but there could
* be more for multi-line and when containing text of differing directions.
*/
blender::Vector<blender::Bounds<int>> BLF_str_selection_boxes(
int fontid, const char *str, size_t str_len, size_t sel_start, size_t sel_length);
/**
* Get the string byte offset that fits within a given width.
*/

@ -638,6 +638,16 @@ int BLF_str_offset_to_cursor(
return 0;
}
blender::Vector<blender::Bounds<int>> BLF_str_selection_boxes(
int fontid, const char *str, size_t str_len, size_t sel_start, size_t sel_length)
{
FontBLF *font = blf_get(fontid);
if (font) {
return blf_str_selection_boxes(font, str, str_len, sel_start, sel_length);
}
return {};
}
size_t BLF_width_to_strlen(
int fontid, const char *str, const size_t str_len, float width, float *r_width)
{

@ -1119,6 +1119,16 @@ int blf_str_offset_to_cursor(
return int(blf_font_width(font, str, str_len, nullptr));
}
blender::Vector<blender::Bounds<int>> blf_str_selection_boxes(
FontBLF *font, const char *str, size_t str_len, size_t sel_start, size_t sel_length)
{
blender::Vector<blender::Bounds<int>> boxes;
const int start = blf_str_offset_to_cursor(font, str, str_len, sel_start, 0.0f);
const int end = blf_str_offset_to_cursor(font, str, str_len, sel_start + sel_length, 0.0f);
boxes.append(blender::Bounds(start, end));
return boxes;
}
/** \} */
/* -------------------------------------------------------------------- */

@ -8,6 +8,7 @@
#pragma once
#include "BLI_bounds_types.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
@ -144,6 +145,9 @@ void blf_str_offset_to_glyph_bounds(FontBLF *font,
size_t str_offset,
rcti *glyph_bounds);
blender::Vector<blender::Bounds<int>> blf_str_selection_boxes(
FontBLF *font, const char *str, size_t str_len, size_t sel_start, size_t sel_length);
int blf_str_offset_to_cursor(
FontBLF *font, const char *str, size_t str_len, size_t str_offset, float cursor_width);

@ -1937,51 +1937,37 @@ static void widget_draw_text(const uiFontStyle *fstyle,
#endif
/* text button selection */
if ((but->selend - but->selsta) > 0) {
int selsta_draw, selwidth_draw;
if (drawstr[0] != 0) {
/* We are drawing on top of widget bases. Flush cache. */
GPU_blend(GPU_BLEND_ALPHA);
UI_widgetbase_draw_cache_flush();
if (but->selsta >= but->ofs) {
selsta_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->selsta - but->ofs);
}
else {
selsta_draw = 0;
}
selwidth_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->selend - but->ofs);
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
rcti selection_shape;
selection_shape.xmin = rect->xmin + selsta_draw;
selection_shape.xmax = min_ii(rect->xmin + selwidth_draw, rect->xmax - 2);
selection_shape.ymin = rect->ymin + U.pixelsize;
selection_shape.ymax = rect->ymax - U.pixelsize;
immUniformColor4ubv(wcol->item);
if ((but->selend - but->selsta) != 0 && drawstr[0] != 0) {
/* We are drawing on top of widget bases. Flush cache. */
GPU_blend(GPU_BLEND_ALPHA);
UI_widgetbase_draw_cache_flush();
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4ubv(wcol->item);
const auto boxes = BLF_str_selection_boxes(fstyle->uifont_id,
drawstr,
strlen(drawstr),
but->ofs + but->selsta,
but->selend - but->selsta);
for (auto bounds : boxes) {
immRecti(pos,
selection_shape.xmin,
selection_shape.ymin,
selection_shape.xmax,
selection_shape.ymax);
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
rect->xmin + bounds.min,
rect->ymin + U.pixelsize,
std::min(rect->xmin + bounds.max, rect->xmax - 2),
rect->ymax - U.pixelsize);
}
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
#ifdef WITH_INPUT_IME
/* IME candidate window uses selection position. */
if (!ime_reposition_window) {
ime_reposition_window = true;
ime_win_x = selection_shape.xmin;
ime_win_y = selection_shape.ymin;
}
#endif
/* IME candidate window uses selection position. */
if (!ime_reposition_window && boxes.size() > 0) {
ime_reposition_window = true;
ime_win_x = rect->xmin + boxes[0].min;
ime_win_y = rect->ymin + U.pixelsize;
}
#endif
}
/* Text cursor position. */