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
5 changed files with 43 additions and 127 deletions
Showing only changes of commit c8db9246c7 - Show all commits

View File

@ -214,31 +214,15 @@ static int rna_Operator_confirm(bContext *C,
wmEvent * /*event*/,
const char *title,
const char *message,
const char *message2,
const char *confirm_text,
Harley marked this conversation as resolved

This shouldn't be necessary, especially not in the public API. The message can be split by newline characters?

This shouldn't be necessary, especially not in the public API. The message can be split by newline characters?
const int icon,
const int size,
const int position,
const bool cancel_default,
const bool mouse_move_quit,
const char *text_ctxt,
const bool translate)
{
title = RNA_translate_ui_text(title, text_ctxt, nullptr, nullptr, translate);
message = RNA_translate_ui_text(message, text_ctxt, nullptr, nullptr, translate);
brecht marked this conversation as resolved

I'm not sure about having size, position and cancel_default and mouse_move_quit as parameters. Maybe even icon.

It's leaving a lot of choice to each operator, which is not going to give consistency. I would prefer there rather to be an enum for different types of confirmation dialogs that we can style consistently.

At the moment I can only think of:

  • "quick" confirmation under the mouse cursor, relatively small, dismissed with mousemove, question icon.
  • "important" confirmation, center of the window, relatively wide, no quit on mouse move, warning icon.

Does that make sense? Can you think of other types?

I'm not sure about having `size`, `position` and `cancel_default` and `mouse_move_quit` as parameters. Maybe even `icon`. It's leaving a lot of choice to each operator, which is not going to give consistency. I would prefer there rather to be an enum for different types of confirmation dialogs that we can style consistently. At the moment I can only think of: * "quick" confirmation under the mouse cursor, relatively small, dismissed with mousemove, question icon. * "important" confirmation, center of the window, relatively wide, no quit on mouse move, warning icon. Does that make sense? Can you think of other types?
message2 = RNA_translate_ui_text(message2, text_ctxt, nullptr, nullptr, translate);
confirm_text = RNA_translate_ui_text(confirm_text, text_ctxt, nullptr, nullptr, translate);
return WM_operator_confirm_ex(C,
op,
title,
message,
message2,
confirm_text,
icon,
wmPopupSize(size),
wmPopupPosition(position),
cancel_default,
mouse_move_quit);
return WM_operator_confirm_ex(C, op, title, message, confirm_text, icon);
}
static int rna_Operator_props_popup(bContext *C, wmOperator *op, wmEvent *event)
@ -826,17 +810,6 @@ const EnumPropertyItem rna_operator_popup_icon_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
const EnumPropertyItem rna_operator_popup_size_items[] = {
{WM_POPUP_POSITION_MOUSE, "MOUSE", 0, "Mouse", "Pop up at mouse position"},
{WM_POPUP_POSITION_CENTER, "CENTER", 0, "Large", "Pop up at window center"},
{0, nullptr, 0, nullptr, nullptr},
};
const EnumPropertyItem rna_operator_popup_position_items[] = {
{WM_CURSOR_DEFAULT, "DEFAULT", 0, "Default", ""},
{0, nullptr, 0, nullptr, nullptr},
};
void RNA_api_wm(StructRNA *srna)
{
FunctionRNA *func;
@ -966,9 +939,6 @@ void RNA_api_wm(StructRNA *srna)
parm = RNA_def_property(func, "message", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(parm, "Message", "Optional first line of content text");
parm = RNA_def_property(func, "message2", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(parm, "Message2", "Optional second line of content text");
parm = RNA_def_property(func, "confirm_text", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(
parm,
@ -979,22 +949,6 @@ void RNA_api_wm(StructRNA *srna)
RNA_def_property_enum_items(parm, rna_operator_popup_icon_items);
RNA_def_property_ui_text(parm, "Icon", "Optional icon displayed in the dialog");
parm = RNA_def_property(func, "size", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, rna_operator_popup_size_items);
RNA_def_property_ui_text(parm, "Size", "Size of the popup");
parm = RNA_def_property(func, "position", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(parm, rna_operator_popup_position_items);
RNA_def_property_ui_text(parm, "Position", "Position of the popup");
parm = RNA_def_property(func, "cancel_default", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
parm, "Cancel Default", "Set to true to make the Cancel button the default action");
parm = RNA_def_property(func, "mouse_move_quit", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_ui_text(
parm, "Mouse Move Quit", "Set to true close the popup by moving your mouse out of range");
api_ui_item_common_translation(func);
/* wrap UI_popup_menu_begin */

View File

@ -693,13 +693,9 @@ int WM_operator_confirm_ex(bContext *C,
wmOperator *op,
const char *title = nullptr,
const char *message = nullptr,
const char *message2 = nullptr,
const char *confirm_text = nullptr,
int icon = 0, /* ALERT_ICON_WARNING. */
wmPopupSize size = WM_POPUP_SIZE_SMALL,
wmPopupPosition position = WM_POPUP_POSITION_MOUSE,
bool cancel_default = false,
bool mouse_move_quit = false);
bool cancel_default = false);
/**
* Invoke callback, file selector "filepath" unset + exec.

View File

@ -929,18 +929,6 @@ enum wmPopupPosition {
WM_POPUP_POSITION_CENTER,
};
struct wmConfirmDetails {
std::string title;
std::string message;
std::string message2;
std::string confirm_text;
int icon;
wmPopupSize size;
wmPopupPosition position;
bool cancel_default;
bool mouse_move_quit;
};
/**
* Communication/status data owned by the wmJob, and passed to the worker code when calling
* `startjob` callback.

View File

@ -3586,12 +3586,8 @@ static int wm_clear_recent_files_invoke(bContext *C, wmOperator *op, const wmEve
op,
nullptr,
IFACE_("Remove all items from the recent files list"),
nullptr,
IFACE_("Remove All"),
ALERT_ICON_WARNING,
WM_POPUP_SIZE_LARGE,
WM_POPUP_POSITION_CENTER,
false,
false);
}

View File

@ -16,6 +16,8 @@
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <sstream>
#ifdef WIN32
# include "GHOST_C-api.h"
@ -1466,7 +1468,6 @@ struct wmOpPopUp {
int free_op;
std::string title;
std::string message;
std::string message2;
std::string confirm_text;
int icon;
wmPopupSize size;
@ -1520,6 +1521,8 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
wmOpPopUp *data = static_cast<wmOpPopUp *>(user_data);
wmOperator *op = data->op;
const uiStyle *style = UI_style_get_dpi();
const bool small = data->size == WM_POPUP_SIZE_SMALL;
const short icon_size = (small ? 32 : 64) * UI_SCALE_FAC;
uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
UI_block_flag_disable(block, UI_BLOCK_LOOP);
@ -1534,34 +1537,34 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NUMSELECT);
/* 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()));
if (!data->message.empty()) {
text_width = std::max(
text_width,
int(BLF_width(style->widget.uifont_id, data->message.c_str(), data->message.length())));
}
if (!data->message2.empty()) {
text_width = std::max(
text_width,
int(BLF_width(style->widget.uifont_id, data->message2.c_str(), data->message2.length())));
/* Break Message into multiple lines. */
std::vector<std::string> message_lines;
std::istringstream origStream(data->message);
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())));
}
}
const bool small = data->size == WM_POPUP_SIZE_SMALL;
const short icon_size = (small ? (data->message.empty() ? 32 : 48) : 64) * UI_SCALE_FAC;
int dialog_width = text_width + (style->columnspace * 2.5);
int dialog_width = std::max(text_width + int(style->columnspace * 2.5), data->width);
dialog_width += (data->icon == ALERT_ICON_NONE) ? 0 : icon_size;
uiLayout *layout = UI_block_layout(block,
UI_LAYOUT_VERTICAL,
UI_LAYOUT_PANEL,
0,
0,
std::max(dialog_width, data->width),
0,
0,
style);
/* 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()),
BLF_width(style->widget.uifont_id, IFACE_("Cancel"), BLF_DRAW_STR_DUMMY_MAX));
dialog_width = std::max(dialog_width, 3 * longest_button_text);
uiLayout *layout = UI_block_layout(
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style);
if (data->icon != ALERT_ICON_NONE) {
/* Split layout to put alert icon on left side. */
@ -1576,18 +1579,14 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
layout = uiLayoutColumn(split_block, true);
}
/* Title. */
if (!data->title.empty()) {
if (data->message.empty() && !small) {
uiItemS(layout);
}
uiItemL_ex(layout, data->title.c_str(), ICON_NONE, true, false);
}
if (!data->message.empty()) {
uiItemL(layout, data->message.c_str(), ICON_NONE);
}
if (!data->message2.empty()) {
uiItemL(layout, data->message2.c_str(), ICON_NONE);
/* Message lines. */
for (auto &st : message_lines) {
uiItemL(layout, st.c_str(), ICON_NONE);
}
if (data->include_properties) {
@ -1613,7 +1612,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
uiBut *cancel_but;
col = uiLayoutSplit(col, 0.0f, true);
uiLayoutSetScaleY(col, small ? 1.1f : 1.2f);
uiLayoutSetScaleY(col, small ? 1.0f : 1.2f);
if (windows_layout) {
confirm_but = uiDefBut(col_block,
@ -1621,7 +1620,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
0,
data->confirm_text.c_str(),
0,
-30,
0,
0,
UI_UNIT_Y,
nullptr,
@ -1633,20 +1632,8 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
uiLayoutColumn(col, false);
}
cancel_but = uiDefBut(col_block,
UI_BTYPE_BUT,
0,
IFACE_("Cancel"),
0,
-30,
0,
UI_UNIT_Y,
nullptr,
0,
0,
0,
0,
"");
cancel_but = uiDefBut(
col_block, UI_BTYPE_BUT, 0, IFACE_("Cancel"), 0, 0, 0, UI_UNIT_Y, nullptr, 0, 0, 0, 0, "");
if (!windows_layout) {
uiLayoutColumn(col, false);
@ -1655,7 +1642,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
0,
data->confirm_text.c_str(),
0,
-30,
0,
0,
UI_UNIT_Y,
nullptr,
@ -1676,7 +1663,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
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] = UI_UNIT_Y * (!data->message.empty() ? 3.1 : 2.5);
bounds_offset[1] = int(UI_UNIT_Y * (small ? 1.8 : 3.1));
UI_block_bounds_set_popup(block, padding, bounds_offset);
}
else if (data->position == WM_POPUP_POSITION_CENTER) {
@ -1744,29 +1731,24 @@ int WM_operator_confirm_ex(bContext *C,
wmOperator *op,
const char *title,
const char *message,
const char *message2,
const char *confirm_text,
int icon,
wmPopupSize size,
wmPopupPosition position,
bool cancel_default,
bool mouse_move_quit)
bool cancel_default)
{
wmOpPopUp *data = MEM_new<wmOpPopUp>(__func__);
data->op = op;
data->width = 400;
data->width = 180 * UI_SCALE_FAC;
data->free_op = true;
data->title = (title == nullptr) ? WM_operatortype_description(C, op->type, op->ptr) : title;
data->message = (message == nullptr) ? std::string() : message;
data->message2 = (message2 == nullptr) ? std::string() : message2;
data->confirm_text = (confirm_text == nullptr) ? WM_operatortype_name(op->type, op->ptr) :
confirm_text;
data->icon = icon;
data->cancel_default = cancel_default;
data->mouse_move_quit = mouse_move_quit;
data->include_properties = false;
data->size = size;
data->position = position;
data->cancel_default = cancel_default;
data->mouse_move_quit = (message == nullptr) ? true : false;
data->size = (message == nullptr) ? WM_POPUP_SIZE_SMALL : WM_POPUP_SIZE_LARGE;
data->position = (message == nullptr) ? WM_POPUP_POSITION_MOUSE : WM_POPUP_POSITION_CENTER;
UI_popup_block_ex(
C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data, op);