Add a new "shortening process" for UI string drawing, which keeps both right and left parts

of the drawstr and replaces the middle by '...'

Rationnal:
It's usually easier to figure out what a troncated string means if you have both its start and end parts.

Details:
It currently affects all UI items (text fields, buttons, labels...).
Only exceptions are buttons inside menus, text fields & co being edited, and numbuttons/sliders.
Note that some static texts (like panels' titles or items in outliner) do not use usual UI items,
and just draw the whole text, using OpenGL to clip it. Will make another patch to fix this.

Reviewers: campbellbarton, brecht, carter2422, #user_interface

Reviewed by: brecht, carter2422

CC: billrey

Differential Revision: https://developer.blender.org/D114
This commit is contained in:
Bastien Montagne 2014-01-01 11:18:27 +01:00
parent d8f4cb9b69
commit 3c6b5b72a4
Notes: blender-bot 2023-02-14 11:28:45 +01:00
Referenced by issue #37830, UILists text now right align
1 changed files with 67 additions and 4 deletions

View File

@ -33,6 +33,7 @@
#include <string.h>
#include <assert.h>
#include "MEM_guardedalloc.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
@ -967,6 +968,69 @@ static void ui_text_clip_left(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
}
}
/**
* Cut off the middle of the text to fit into the width of \a rect
*/
static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
{
const int border = UI_TEXT_CLIP_MARGIN + 1;
const int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0);
float strwidth;
/* need to set this first */
uiStyleFontSet(fstyle);
if (fstyle->kerning == 1) /* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
but->ofs = 0;
strwidth = BLF_width(fstyle->uifont_id, but->drawstr, sizeof(but->drawstr));
if (strwidth > okwidth) {
const char *sep = "...";
const int sep_len = strlen(sep);
const size_t max_len = sizeof(but->drawstr);
size_t l_end;
const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sizeof(sep));
const float parts_strwidth = ((float)okwidth - sep_strwidth) / 2.0f;
if (parts_strwidth < (float)UI_DPI_ICON_SIZE) {
/* If we really have no place, only show start of string. */
l_end = BLF_width_to_strlen(fstyle->uifont_id, but->drawstr, max_len, okwidth, &strwidth);
but->drawstr[l_end] = '\0';
}
else {
size_t r_offset, r_len;
l_end = BLF_width_to_strlen(fstyle->uifont_id, but->drawstr, max_len, parts_strwidth, &strwidth);
r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, but->drawstr, max_len, parts_strwidth, &strwidth);
r_len = strlen(but->drawstr + r_offset) + 1; /* +1 for the trailing '\0'... */
if (l_end + sep_len + r_len > max_len) {
/* Corner case, the str already takes all available mem, and the ellipsis chars would actually
* add more chars...
* Better to just trim one or two letters to the right in this case...
*/
l_end = BLF_width_to_strlen(fstyle->uifont_id, but->drawstr, max_len, okwidth, &strwidth);
but->drawstr[l_end] = '\0';
}
else {
memmove(but->drawstr + l_end + sep_len, but->drawstr + r_offset, r_len);
memcpy(but->drawstr + l_end, sep, sep_len);
strwidth = BLF_width(fstyle->uifont_id, but->drawstr, max_len);
}
}
}
but->strwidth = strwidth;
if (fstyle->kerning == 1) {
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
}
/**
* Cut off the text, taking into account the cursor location (text display while editing).
*/
@ -1295,18 +1359,17 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
else if (ELEM(but->type, NUM, NUMSLI)) {
ui_text_clip_right_label(fstyle, but, rect);
}
#if 0
/* Special hack for non-embossed TEX buttons in uiList (we want them to behave as much as possible as labels). */
else if ((but->type == TEX) && (but->flag & UI_BUT_LIST_ITEM) && (but->dt & UI_EMBOSSN)) {
but->ofs = 0;
}
else if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
ui_text_clip_left(fstyle, but, rect);
}
#endif
else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == BUT)) {
ui_text_clip_left(fstyle, but, rect);
}
else {
but->ofs = 0;
ui_text_clip_middle(fstyle, but, rect);
}
/* always draw text for textbutton cursor */