UI: Operator Confirm Dialog Changes #117564

Merged
Harley Acheson merged 13 commits from Harley/blender:NewConfirm into main 2024-01-29 18:52:27 +01:00
3 changed files with 41 additions and 34 deletions
Showing only changes of commit d915f4321d - Show all commits

View File

@ -3043,10 +3043,15 @@ void uiItemTabsEnumR_prop(uiLayout *layout,
const char *UI_layout_introspect(uiLayout *layout);
/**
* Helper to add a big icon and create a split layout for alert popups.
* Helpers to add a big icon and create a split layout for alert popups.
* Returns the layout to place further items into the alert box.
*/
uiLayout *uiItemsAlertBox(uiBlock *block, int size, eAlertIcon icon);
uiLayout *uiItemsAlertBox(uiBlock *block,
const int dialog_width,
const eAlertIcon icon,
const int icon_size,
const uiStyle *style);
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon);
/* UI Operators */
struct uiDragColorHandle {

View File

@ -6396,12 +6396,12 @@ const char *UI_layout_introspect(uiLayout *layout)
/** \name Alert Box with Big Icon
* \{ */
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
uiLayout *uiItemsAlertBox(uiBlock *block,
const uiStyle *style,
const int dialog_width,
const eAlertIcon icon,
const int icon_size)
{
const uiStyle *style = UI_style_get_dpi();
const short icon_size = 64 * UI_SCALE_FAC;
const int text_points_max = std::max(style->widget.points, style->widgetlabel.points);
const int dialog_width = icon_size + (text_points_max * size * UI_SCALE_FAC);
/* By default, the space between icon and text/buttons will be equal to the 'columnspace',
* this extra padding will add some space by increasing the left column width,
* making the icon placement more symmetrical, between the block edge and the text. */
@ -6428,4 +6428,13 @@ uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
return layout;
}
uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon)
{
const uiStyle *style = UI_style_get_dpi();
const short icon_size = 64 * UI_SCALE_FAC;
const int text_points_max = std::max(style->widget.points, style->widgetlabel.points);
const int dialog_width = icon_size + (text_points_max * size * UI_SCALE_FAC);
uiItemsAlertBox(block, dialog_width, icon, icon_size, style);
}
/** \} */

View File

@ -1540,43 +1540,35 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
/* Width based on the text lengths. */
int text_width = std::max(
120 * UI_SCALE_FAC,
BLF_width(style->widget.uifont_id, data->title.c_str(), data->title.length()));
BLF_width(style->widget.uifont_id, data->title.c_str(), BLF_DRAW_STR_DUMMY_MAX));
/* Break Message into multiple lines. */
std::vector<std::string> message_lines;
std::istringstream origStream(data->message);
blender::StringRef messaged_trimmed = blender::StringRef(data->message).trim();
Harley marked this conversation as resolved Outdated

origStream -> message_stream

`origStream` -> `message_stream`
std::istringstream message_stream(messaged_trimmed);
std::string line;
while (std::getline(origStream, line)) {
if (!line.empty()) {
message_lines.push_back(line);
text_width = std::max(text_width,
int(BLF_width(style->widget.uifont_id, line.c_str(), line.length())));
}
while (std::getline(message_stream, line)) {
Harley marked this conversation as resolved Outdated

Might as well keep empty lines if someone wants paragraphs.

You could trim whitespace at the start and end still:

StringRef messaged_trimmed = StringRef(data->message).trim();
std::istringstream message_stream(messaged_trimmed);
...
Might as well keep empty lines if someone wants paragraphs. You could trim whitespace at the start and end still: ``` StringRef messaged_trimmed = StringRef(data->message).trim(); std::istringstream message_stream(messaged_trimmed); ... ```
message_lines.push_back(line);

This could also break long lines to prevent popups from being too wide (like tooltips do)

Long tool-tip message Long confirm message
image image
This could also break long lines to prevent popups from being too wide (like tooltips do) | Long tool-tip message | Long confirm message | | -------- | -------- | |![image](/attachments/4192bc32-4111-4cdd-a6ac-3aeefdcda686)|![image](/attachments/0e82b141-f935-40a5-8462-82869c16d780)|

@guishe - This could also break long lines to prevent popups from being too wide (like tooltips do)

Okay, I could be wrong about this, but I think that would require a feature that we are missing but need...

Tooltips do that wrapping within BLF. As in the FontBLF has a BLF_WORD_WRAP flag and wrap_width member and when measuring the string or printing it out we run a callback that does wrapping.

I don't think we have anything that helps with wrapping outside of text output. As in give it a string and fontid and get back info on where to break. Or breaks it up into a string vector. Or array of breaking points? That way we could then add labels to the layout for each substring, rather than printing out.

Haven't thought it through much, but I think such a thing could look like blf_font_draw_buffer__wrap but would pass an integer vector or array for the userdata and a callback that would populate it with wrapping points?

Edit: This is probably a perfect use case for this. I'll try to get to this over this weekend.

> @guishe - This could also break long lines to prevent popups from being too wide (like tooltips do) Okay, I could be wrong about this, but I _think_ that would require a feature that we are missing but _need_... Tooltips do that wrapping within BLF. As in the FontBLF has a `BLF_WORD_WRAP` flag and `wrap_width` member and when measuring the string or printing it out we run a callback that does wrapping. I don't think we have anything that helps with wrapping outside of text output. As in give it a string and fontid and get back info on where to break. Or breaks it up into a string vector. Or array of breaking points? That way we could then add labels to the layout for each substring, rather than printing out. Haven't thought it through much, but I think such a thing could look like `blf_font_draw_buffer__wrap` but would pass an integer vector or array for the userdata and a callback that would populate it with wrapping points? Edit: This is probably a perfect use case for this. I'll try to get to this over this weekend.

I think BLF_width_to_strlen may be useful

I think `BLF_width_to_strlen` may be useful

I think BLF_width_to_strlen may be useful

Yes, that gives the string byte index that fits within a pixel width. So you could iterate through the string looking for word delimiters and line breaks.

That is basically what the existing blf_font_wrap_apply does for us, and has a callback at each wrapping location, and can return the numbers of wrapped lines and the width of the last orphan line.

> I think BLF_width_to_strlen may be useful Yes, that gives the string byte index that fits within a pixel width. So you could iterate through the string looking for word delimiters and line breaks. That is basically what the existing `blf_font_wrap_apply` does for us, and has a callback at each wrapping location, and can return the numbers of wrapped lines and the width of the last orphan line.
text_width = std::max(
text_width, int(BLF_width(style->widget.uifont_id, line.c_str(), BLF_DRAW_STR_DUMMY_MAX)));
}
int dialog_width = std::max(text_width + int(style->columnspace * 2.5), data->width);
dialog_width += (data->icon == ALERT_ICON_NONE) ? 0 : icon_size;
/* Adjust width if the button text is long. */
int longest_button_text = std::max(
BLF_width(style->widget.uifont_id, data->confirm_text.c_str(), data->confirm_text.length()),
const int longest_button_text = std::max(
BLF_width(style->widget.uifont_id, data->confirm_text.c_str(), BLF_DRAW_STR_DUMMY_MAX),
BLF_width(style->widget.uifont_id, IFACE_("Cancel"), BLF_DRAW_STR_DUMMY_MAX));
Harley marked this conversation as resolved Outdated

const int

`const int`
dialog_width = std::max(dialog_width, 3 * longest_button_text);
Harley marked this conversation as resolved Outdated

Use BLF_DRAW_STR_DUMMY_MAX for BLF_width calls?

Then it will be a more obvious step to port the BLF API to C++ and make BLF_DRAW_STR_DUMMY_MAX the default or use StringRef to simplify this.

Use `BLF_DRAW_STR_DUMMY_MAX` for `BLF_width` calls? Then it will be a more obvious step to port the BLF API to C++ and make `BLF_DRAW_STR_DUMMY_MAX` the default or use `StringRef` to simplify this.
uiLayout *layout = UI_block_layout(
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style);
uiLayout *layout;

It's a bit unfortunate that all this logic is needed here. Maybe one day this can become a feature of the layout engine instead, but seems ok for now.

It's a bit unfortunate that all this logic is needed here. Maybe one day this can become a feature of the layout engine instead, but seems ok for now.

Actually we did have a uiItemsAlertBox routine in layout that's close, so made an overloaded variation that shares code with it.

Actually we did have a `uiItemsAlertBox` routine in layout that's close, so made an overloaded variation that shares code with it.
if (data->icon != ALERT_ICON_NONE) {
/* Split layout to put alert icon on left side. */
const float split_factor = (float)icon_size / (float)(dialog_width - style->columnspace);
uiLayout *split_block = uiLayoutSplit(layout, split_factor, false);
/* Alert icon on the left. */
uiLayout *left = uiLayoutRow(split_block, true);
/* Using 'align_left' with 'row' avoids stretching the icon along the width of column. */
uiLayoutSetAlignment(left, UI_LAYOUT_ALIGN_LEFT);
uiDefButAlert(block, data->icon, 0, 0, icon_size, icon_size);
/* The rest of the content on the right. */
layout = uiLayoutColumn(split_block, true);
layout = uiItemsAlertBox(
block, dialog_width + icon_size, eAlertIcon(data->icon), icon_size, style);
}
else {
layout = UI_block_layout(
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style);
}
/* Title. */
@ -1661,9 +1653,10 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
const int padding = (small ? 7 : 14) * UI_SCALE_FAC;
if (data->position == WM_POPUP_POSITION_MOUSE) {
int bounds_offset[2];
bounds_offset[0] = uiLayoutGetWidth(layout) * (windows_layout ? -0.33f : -0.66f);
bounds_offset[1] = int(UI_UNIT_Y * (small ? 1.8 : 3.1));
const float button_center_x = windows_layout ? -0.33f : -0.66f;
const float button_center_y = small ? 1.8f : 3.1f;
const int bounds_offset[2] = {button_center_x * uiLayoutGetWidth(layout),
button_center_y * UI_UNIT_X};
Harley marked this conversation as resolved Outdated

Clang needs casts to compile this.

   const int bounds_offset[2] = {int(button_center_x * uiLayoutGetWidth(layout)),
                                 int(button_center_y * UI_UNIT_X)};
Clang needs casts to compile this. ``` const int bounds_offset[2] = {int(button_center_x * uiLayoutGetWidth(layout)), int(button_center_y * UI_UNIT_X)}; ```
UI_block_bounds_set_popup(block, padding, bounds_offset);
}
else if (data->position == WM_POPUP_POSITION_CENTER) {