WIP: UI: Wrap Buttons #118579

Draft
Harley Acheson wants to merge 7 commits from Harley/blender:WrapButs into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
5 changed files with 47 additions and 11 deletions

View File

@ -43,6 +43,7 @@ class RENDER_PT_context(Panel):
scene = context.scene
rd = scene.render
layout.label(text="Proin ultricies a velit quis ultricies. Nunc dapibus leo eu quam ullamcorper, sed ultricies justo auctor. Cras ac tortor leo. Suspendisse convallis sem eu ante convallis laoreet. Curabitur suscipit massa mi, vitae porttitor ipsum aliquam ac. Nunc vel massa risus. Ut mauris arcu, sagittis accumsan urna non, viverra lacinia ante. Mauris id risus gravida, volutpat enim in, bibendum nisl.", wrap=True)
if rd.has_multiple_engines:
layout.prop(rd, "engine", text="Render Engine")

View File

@ -314,15 +314,17 @@ enum {
UI_BUT_TEXT_LEFT = 1 << 1,
UI_BUT_ICON_LEFT = 1 << 2,
UI_BUT_TEXT_RIGHT = 1 << 3,
UI_BUT_TEXT_WRAP = 1 << 4,
/** Prevent the button to show any tool-tip. */
UI_BUT_NO_TOOLTIP = 1 << 4,
UI_BUT_NO_TOOLTIP = 1 << 5,
/**
* Show a quick tool-tip label, that is, a short tool-tip that appears faster than the full one
* and only shows the label. After a short delay the full tool-tip is shown if any.
*/
UI_BUT_HAS_TOOLTIP_LABEL = 1 << 5,
UI_BUT_HAS_TOOLTIP_LABEL = 1 << 6,
/** Do not add the usual horizontal padding for text drawing. */
UI_BUT_NO_TEXT_PADDING = 1 << 6,
UI_BUT_NO_TEXT_PADDING = 1 << 7,
/* Button align flag, for drawing groups together.
* Used in 'uiBlock.flag', take care! */
@ -2925,7 +2927,7 @@ struct uiPropertySplitWrapper {
*/
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout);
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
void uiItemL(uiLayout *layout, const char *name, int icon, bool wrap = false); /* label */
uiBut *uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert);
/**
* Helper to add a label and creates a property split layout if needed.

View File

@ -18,6 +18,8 @@
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BLF_api.hh"
#include "BLI_array.hh"
#include "BLI_dynstr.h"
#include "BLI_listbase.h"
@ -3260,8 +3262,28 @@ void uiItemPopoverPanelFromGroup(uiLayout *layout,
}
}
/* Adjust button to allow the text to wrap to multiple lines. */
static void ui_but_wrap(uiBut *but, uiLayout *layout, const uiFontStyle *fstyle)
{
if (!layout || !layout->w) {
return;
}
but->drawflag |= UI_BUT_TEXT_WRAP;
const int max = (but->icon) ? layout->w - int(UI_UNIT_X * ui_text_pad_none.icon) : layout->w;
BLF_size(fstyle->uifont_id, fstyle->points);
blender::Vector<blender::StringRef> wrapped = BLF_string_wrap(fstyle->uifont_id, but->str, max);
if (wrapped.size() > 1) {
float line_height = BLF_height_max(fstyle->uifont_id) * 1.1f;
but->rect.ymax = but->rect.ymin + int(line_height * wrapped.size());
but->rect.xmax = but->rect.xmin;
}
}
/* label item */
static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon, bool wrap = false)
{
uiBlock *block = layout->root->block;
@ -3312,6 +3334,10 @@ static uiBut *uiItemL_(uiLayout *layout, const char *name, int icon)
but->drawflag |= UI_BUT_TEXT_RIGHT;
}
if (wrap) {
ui_but_wrap(but, layout, UI_FSTYLE_WIDGET_LABEL);
}
/* Mark as a label inside a list-box. */
if (block->flag & UI_BLOCK_LIST_ITEM) {
but->flag |= UI_BUT_LIST_ITEM;
@ -3341,9 +3367,9 @@ uiBut *uiItemL_ex(
return but;
}
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemL(uiLayout *layout, const char *name, int icon, bool wrap)
{
uiItemL_(layout, name, icon);
uiItemL_(layout, name, icon, wrap);
}
uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)

View File

@ -1861,6 +1861,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
const char *drawstr_right = nullptr;
bool use_right_only = false;
const char *indeterminate_str = UI_VALUE_INDETERMINATE_CHAR;
const bool wrap = but->drawflag & UI_BUT_TEXT_WRAP;
#ifdef WITH_INPUT_IME
const wmIMEData *ime_data;
@ -2149,8 +2150,12 @@ static void widget_draw_text(const uiFontStyle *fstyle,
(drawstr_left_len - but->ofs);
if (drawlen > 0) {
if (wrap) {
BLF_wordwrap(fstyle->uifont_id, BLI_rcti_size_x(rect));
}
uiFontStyleDraw_Params params{};
params.align = align;
params.word_wrap = wrap;
UI_fontstyle_draw_ex(fstyle,
rect,
drawstr + but->ofs,
@ -2453,8 +2458,8 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
if (but->editstr && but->pos >= 0) {
ui_text_clip_cursor(fstyle, but, rect);
}
else if (but->drawstr[0] == '\0') {
/* bypass text clipping on icon buttons */
else if ((but->drawstr[0] == '\0') || (but->drawflag & UI_BUT_TEXT_WRAP)) {
/* bypass text clipping on icon and multi-line buttons */
but->ofs = 0;
but->strwidth = 0;
}

View File

@ -439,7 +439,8 @@ static void rna_uiItemL(uiLayout *layout,
const char *text_ctxt,
bool translate,
int icon,
int icon_value)
int icon_value,
bool wrap)
{
/* Get translated name (label). */
name = rna_translate_ui_text(name, text_ctxt, nullptr, nullptr, translate);
@ -448,7 +449,7 @@ static void rna_uiItemL(uiLayout *layout,
icon = icon_value;
}
uiItemL(layout, name, icon);
uiItemL(layout, name, icon, wrap);
}
static void rna_uiItemM(uiLayout *layout,
@ -1476,6 +1477,7 @@ void RNA_api_ui_layout(StructRNA *srna)
api_ui_item_common(func);
parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
RNA_def_boolean(func, "wrap", false, "Word Wrap", "Wrap to multiple lines if neccessary");
func = RNA_def_function(srna, "menu", "rna_uiItemM");
parm = RNA_def_string(func, "menu", nullptr, 0, "", "Identifier of the menu");