diff --git a/source/blender/editors/include/UI_interface_c.hh b/source/blender/editors/include/UI_interface_c.hh index a3b4f02eca3..7a06acec564 100644 --- a/source/blender/editors/include/UI_interface_c.hh +++ b/source/blender/editors/include/UI_interface_c.hh @@ -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 uiStyle *style, + const int dialog_width, + const eAlertIcon icon, + const int icon_size); +uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon); /* UI Operators */ struct uiDragColorHandle { diff --git a/source/blender/editors/include/UI_interface_icons.hh b/source/blender/editors/include/UI_interface_icons.hh index 8e7b10e45ee..903eee50de4 100644 --- a/source/blender/editors/include/UI_interface_icons.hh +++ b/source/blender/editors/include/UI_interface_icons.hh @@ -45,6 +45,7 @@ struct IconTextOverlay { #define PREVIEW_DEFAULT_HEIGHT 128 enum eAlertIcon { + ALERT_ICON_NONE = -1, ALERT_ICON_WARNING = 0, ALERT_ICON_QUESTION = 1, ALERT_ICON_ERROR = 2, diff --git a/source/blender/editors/interface/interface_layout.cc b/source/blender/editors/interface/interface_layout.cc index dbbdc4356bd..12fac86d713 100644 --- a/source/blender/editors/interface/interface_layout.cc +++ b/source/blender/editors/interface/interface_layout.cc @@ -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); + return uiItemsAlertBox(block, style, dialog_width, icon, icon_size); +} + /** \} */ diff --git a/source/blender/makesrna/intern/rna_wm_api.cc b/source/blender/makesrna/intern/rna_wm_api.cc index 94b500b589f..c3172c24724 100644 --- a/source/blender/makesrna/intern/rna_wm_api.cc +++ b/source/blender/makesrna/intern/rna_wm_api.cc @@ -209,10 +209,22 @@ static void rna_progress_end(wmWindowManager *wm) } /* wrap these because of 'const wmEvent *' */ -static int rna_Operator_confirm(bContext *C, wmOperator *op, wmEvent *event) +static int rna_Operator_confirm(bContext *C, + wmOperator *op, + wmEvent * /*event*/, + const char *title, + const char *message, + const char *confirm_text, + const int icon, + const char *text_ctxt, + const bool translate) { - return WM_operator_confirm(C, op, event); + title = RNA_translate_ui_text(title, text_ctxt, nullptr, nullptr, translate); + message = RNA_translate_ui_text(message, 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, confirm_text, icon); } + static int rna_Operator_props_popup(bContext *C, wmOperator *op, wmEvent *event) { return WM_operator_props_popup(C, op, event); @@ -788,6 +800,16 @@ void RNA_api_window(StructRNA *srna) RNA_def_function_return(func, parm); } +const EnumPropertyItem rna_operator_popup_icon_items[] = { + {ALERT_ICON_NONE, "NONE", 0, "None", ""}, + {ALERT_ICON_WARNING, "WARNING", 0, "Warning", ""}, + {ALERT_ICON_QUESTION, "QUESTION", 0, "Question", ""}, + {ALERT_ICON_ERROR, "ERROR", 0, "Error", ""}, + {ALERT_ICON_INFO, "INFO", 0, "Info", ""}, + {ALERT_ICON_BLENDER, "BLENDER", 0, "Blender", ""}, + {0, nullptr, 0, nullptr, nullptr}, +}; + void RNA_api_wm(StructRNA *srna) { FunctionRNA *func; @@ -911,6 +933,24 @@ void RNA_api_wm(StructRNA *srna) "(only to let user confirm the execution, no operator properties shown)"); rna_generic_op_invoke(func, WM_GEN_INVOKE_EVENT | WM_GEN_INVOKE_RETURN); + parm = RNA_def_property(func, "title", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text(parm, "Title", "Optional text to show as title of the popup"); + + 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, "confirm_text", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text( + parm, + "Confirm Text", + "Optional text to show instead to the default \"OK\" confirmation button text"); + + parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(parm, rna_operator_popup_icon_items); + RNA_def_property_ui_text(parm, "Icon", "Optional icon displayed in the dialog"); + + api_ui_item_common_translation(func); + /* wrap UI_popup_menu_begin */ func = RNA_def_function(srna, "popmenu_begin__internal", "rna_PopMenuBegin"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); diff --git a/source/blender/windowmanager/WM_api.hh b/source/blender/windowmanager/WM_api.hh index f276dae18eb..bf6c7ccd56a 100644 --- a/source/blender/windowmanager/WM_api.hh +++ b/source/blender/windowmanager/WM_api.hh @@ -685,6 +685,18 @@ int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *event); */ int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *event); int WM_operator_confirm_or_exec(bContext *C, wmOperator *op, const wmEvent *event); + +/** + * Like WM_operator_confirm, but with more options and can't be used as an invoke directly. + */ +int WM_operator_confirm_ex(bContext *C, + wmOperator *op, + const char *title = nullptr, + const char *message = nullptr, + const char *confirm_text = nullptr, + int icon = 0, /* ALERT_ICON_WARNING. */ + bool cancel_default = false); + /** * Invoke callback, file selector "filepath" unset + exec. * diff --git a/source/blender/windowmanager/WM_types.hh b/source/blender/windowmanager/WM_types.hh index fafe369c275..3bd132a83ec 100644 --- a/source/blender/windowmanager/WM_types.hh +++ b/source/blender/windowmanager/WM_types.hh @@ -919,26 +919,14 @@ struct wmTimer { bool sleep; }; -enum wmConfirmSize { - WM_WARNING_SIZE_SMALL = 0, - WM_WARNING_SIZE_LARGE, +enum wmPopupSize { + WM_POPUP_SIZE_SMALL = 0, + WM_POPUP_SIZE_LARGE, }; -enum wmConfirmPosition { - WM_WARNING_POSITION_MOUSE = 0, - WM_WARNING_POSITION_CENTER, -}; - -struct wmConfirmDetails { - std::string title; - std::string message; - std::string message2; - std::string confirm_text; - int icon; - wmConfirmSize size; - wmConfirmPosition position; - bool cancel_default; - bool mouse_move_quit; +enum wmPopupPosition { + WM_POPUP_POSITION_MOUSE = 0, + WM_POPUP_POSITION_CENTER, }; /** @@ -1068,11 +1056,6 @@ struct wmOperatorType { */ std::string (*get_description)(bContext *C, wmOperatorType *ot, PointerRNA *ptr); - /** - * If using WM_operator_confirm the following can override all parts of the dialog. - */ - void (*confirm)(bContext *C, wmOperator *, wmConfirmDetails *details); - /** RNA for properties */ StructRNA *srna; diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc index 2bf297ca7a4..8ad3f5eb9ae 100644 --- a/source/blender/windowmanager/intern/wm_files.cc +++ b/source/blender/windowmanager/intern/wm_files.cc @@ -3581,15 +3581,15 @@ void WM_OT_save_mainfile(wmOperatorType *ot) /** \name Clear Recent Files List Operator * \{ */ -static void wm_clear_recent_files_confirm(bContext * /*C*/, - wmOperator * /*op*/, - wmConfirmDetails *confirm) +static int wm_clear_recent_files_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) { - confirm->message = IFACE_("Remove all items from the recent files list"); - confirm->confirm_text = IFACE_("Remove All"); - confirm->position = WM_WARNING_POSITION_CENTER; - confirm->size = WM_WARNING_SIZE_LARGE; - confirm->cancel_default = true; + return WM_operator_confirm_ex(C, + op, + nullptr, + IFACE_("Remove all items from the recent files list"), + IFACE_("Remove All"), + ALERT_ICON_WARNING, + false); } static int wm_clear_recent_files_exec(bContext * /*C*/, wmOperator * /*op*/) @@ -3606,9 +3606,8 @@ void WM_OT_clear_recent_files(wmOperatorType *ot) ot->idname = "WM_OT_clear_recent_files"; ot->description = "Clear the recent files list"; - ot->invoke = WM_operator_confirm; + ot->invoke = wm_clear_recent_files_invoke; ot->exec = wm_clear_recent_files_exec; - ot->confirm = wm_clear_recent_files_confirm; } /** \} */ diff --git a/source/blender/windowmanager/intern/wm_operators.cc b/source/blender/windowmanager/intern/wm_operators.cc index b0cd57737db..a6b47705607 100644 --- a/source/blender/windowmanager/intern/wm_operators.cc +++ b/source/blender/windowmanager/intern/wm_operators.cc @@ -16,6 +16,8 @@ #include #include #include +#include +#include #ifdef WIN32 # include "GHOST_C-api.h" @@ -1186,205 +1188,6 @@ int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/ return OPERATOR_INTERFACE; } -static void wm_operator_block_cancel(bContext *C, void *arg_op, void *arg_block) -{ - wmOperator *op = static_cast(arg_op); - uiBlock *block = static_cast(arg_block); - UI_popup_block_close(C, CTX_wm_window(C), block); - WM_redraw_windows(C); - if (op) { - if (op->type->cancel) { - op->type->cancel(C, op); - } - WM_operator_free(op); - } -} - -static void wm_operator_block_confirm(bContext *C, void *arg_op, void *arg_block) -{ - wmOperator *op = static_cast(arg_op); - uiBlock *block = static_cast(arg_block); - UI_popup_block_close(C, CTX_wm_window(C), block); - WM_redraw_windows(C); - if (op) { - WM_operator_call_ex(C, op, true); - } -} - -static uiBlock *wm_block_confirm_create(bContext *C, ARegion *region, void *arg_op) -{ - wmOperator *op = static_cast(arg_op); - - wmConfirmDetails confirm = {{0}}; - - confirm.title = WM_operatortype_description(C, op->type, op->ptr); - confirm.confirm_text = WM_operatortype_name(op->type, op->ptr); - confirm.icon = ALERT_ICON_WARNING; - confirm.size = WM_WARNING_SIZE_SMALL; - confirm.position = WM_WARNING_POSITION_MOUSE; - confirm.cancel_default = false; - confirm.mouse_move_quit = false; - - /* uiBlock.flag */ - int block_flags = UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT; - - if (op->type->confirm) { - op->type->confirm(C, op, &confirm); - } - if (confirm.mouse_move_quit) { - block_flags |= UI_BLOCK_MOVEMOUSE_QUIT; - } - if (confirm.icon < ALERT_ICON_WARNING || confirm.icon >= ALERT_ICON_MAX) { - confirm.icon = ALERT_ICON_QUESTION; - } - - uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS); - UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); - UI_block_flag_enable(block, block_flags); - - const uiStyle *style = UI_style_get_dpi(); - int text_width = std::max( - 120 * UI_SCALE_FAC, - BLF_width(style->widget.uifont_id, confirm.title.c_str(), confirm.title.length())); - if (!confirm.message.empty()) { - text_width = std::max(text_width, - int(BLF_width(style->widget.uifont_id, - confirm.message.c_str(), - confirm.message.length()))); - } - if (!confirm.message2.empty()) { - text_width = std::max(text_width, - int(BLF_width(style->widget.uifont_id, - confirm.message2.c_str(), - confirm.message2.length()))); - } - - const bool small = confirm.size == WM_WARNING_SIZE_SMALL; - const int padding = (small ? 7 : 14) * UI_SCALE_FAC; - const short icon_size = (small ? (confirm.message.empty() ? 32 : 48) : 64) * UI_SCALE_FAC; - const int dialog_width = icon_size + text_width + (style->columnspace * 2.5); - const float split_factor = (float)icon_size / (float)(dialog_width - style->columnspace); - - uiLayout *block_layout = UI_block_layout( - block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, UI_UNIT_Y, 0, style); - - /* Split layout to put alert icon on left side. */ - uiLayout *split_block = uiLayoutSplit(block_layout, split_factor, false); - - /* Alert icon on the left. */ - uiLayout *layout = uiLayoutRow(split_block, true); - /* Using 'align_left' with 'row' avoids stretching the icon along the width of column. */ - uiLayoutSetAlignment(layout, UI_LAYOUT_ALIGN_LEFT); - uiDefButAlert(block, confirm.icon, 0, 0, icon_size, icon_size); - - /* The rest of the content on the right. */ - layout = uiLayoutColumn(split_block, true); - - if (!confirm.title.empty()) { - if (confirm.message.empty()) { - uiItemS(layout); - } - uiItemL_ex(layout, confirm.title.c_str(), ICON_NONE, true, false); - } - - if (!confirm.message.empty()) { - uiItemL(layout, confirm.message.c_str(), ICON_NONE); - } - - if (!confirm.message2.empty()) { - uiItemL(layout, confirm.message2.c_str(), ICON_NONE); - } - - uiItemS_ex(layout, small ? 0.5f : 4.0f); - - /* Buttons. */ - -#ifdef _WIN32 - const bool windows_layout = true; -#else - const bool windows_layout = false; -#endif - - uiBut *confirm_but = nullptr; - uiBut *cancel_but = nullptr; - uiLayout *split = uiLayoutSplit(small ? block_layout : layout, 0.0f, true); - uiLayoutSetScaleY(split, small ? 1.1f : 1.2f); - uiLayoutColumn(split, false); - - if (windows_layout) { - confirm_but = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - 0, - confirm.confirm_text.c_str(), - 0, - 0, - 0, - UI_UNIT_Y, - nullptr, - 0, - 0, - 0, - 0, - nullptr); - uiLayoutColumn(split, false); - } - - cancel_but = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - 0, - IFACE_("Cancel"), - 0, - 0, - 0, - UI_UNIT_Y, - nullptr, - 0, - 0, - 0, - 0, - nullptr); - - if (!windows_layout) { - uiLayoutColumn(split, false); - confirm_but = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - 0, - confirm.confirm_text.c_str(), - 0, - 0, - 0, - UI_UNIT_Y, - nullptr, - 0, - 0, - 0, - 0, - nullptr); - } - - UI_block_func_set(block, nullptr, nullptr, nullptr); - UI_but_func_set(confirm_but, wm_operator_block_confirm, op, block); - UI_but_func_set(cancel_but, wm_operator_block_cancel, op, block); - UI_but_drawflag_disable(confirm_but, UI_BUT_TEXT_LEFT); - UI_but_drawflag_disable(cancel_but, UI_BUT_TEXT_LEFT); - UI_but_flag_enable(confirm.cancel_default ? cancel_but : confirm_but, UI_BUT_ACTIVE_DEFAULT); - - if (confirm.position == WM_WARNING_POSITION_MOUSE) { - int bounds_offset[2]; - bounds_offset[0] = uiLayoutGetWidth(layout) * (windows_layout ? -0.33f : -0.66f); - bounds_offset[1] = UI_UNIT_Y * (confirm.message[0] ? 3.1 : 2.5); - UI_block_bounds_set_popup(block, padding, bounds_offset); - } - else if (confirm.position == WM_WARNING_POSITION_CENTER) { - UI_block_bounds_set_centered(block, padding); - } - - return block; -} - int WM_operator_confirm_message_ex(bContext *C, wmOperator *op, const char *title, @@ -1412,11 +1215,6 @@ int WM_operator_confirm_message_ex(bContext *C, int WM_operator_confirm_message(bContext *C, wmOperator *op, const char *message) { - if (op->type->confirm) { - UI_popup_block_invoke(C, wm_block_confirm_create, op, nullptr); - return OPERATOR_RUNNING_MODAL; - } - return WM_operator_confirm_message_ex( C, op, IFACE_("OK?"), ICON_QUESTION, message, WM_OP_EXEC_REGION_WIN); } @@ -1645,11 +1443,10 @@ struct wmOpPopUp { int free_op; std::string title; std::string message; - std::string message2; std::string confirm_text; - int icon; - wmConfirmSize size; - wmConfirmPosition position; + eAlertIcon icon; + wmPopupSize size; + wmPopupPosition position; bool cancel_default; bool mouse_move_quit; bool include_properties; @@ -1699,6 +1496,8 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_ wmOpPopUp *data = static_cast(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); @@ -1707,24 +1506,71 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_ if (data->mouse_move_quit) { UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT); } + if (data->icon < ALERT_ICON_NONE || data->icon >= ALERT_ICON_MAX) { + data->icon = ALERT_ICON_QUESTION; + } UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NUMSELECT); - uiLayout *layout = UI_block_layout( - block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, 0, 0, style); + /* 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(), BLF_DRAW_STR_DUMMY_MAX)); - uiItemL_ex(layout, data->title.c_str(), ICON_NONE, true, false); - uiItemS_ex(layout, 0.3f); + /* Break Message into multiple lines. */ + std::vector message_lines; + blender::StringRef messaged_trimmed = blender::StringRef(data->message).trim(); + std::istringstream message_stream(messaged_trimmed); + std::string line; + while (std::getline(message_stream, line)) { + message_lines.push_back(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); + + /* Adjust width if the button text is long. */ + 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)); + dialog_width = std::max(dialog_width, 3 * longest_button_text); + + uiLayout *layout; + if (data->icon != ALERT_ICON_NONE) { + layout = uiItemsAlertBox( + block, style, dialog_width + icon_size, eAlertIcon(data->icon), icon_size); + } + else { + layout = UI_block_layout( + block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style); + } + + /* Title. */ + if (!data->title.empty()) { + uiItemL_ex(layout, data->title.c_str(), ICON_NONE, true, false); + } + + /* Message lines. */ + for (auto &st : message_lines) { + uiItemL(layout, st.c_str(), ICON_NONE); + } if (data->include_properties) { uiTemplateOperatorPropertyButs(C, layout, op, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN, 0); } - uiItemS_ex(layout, 0.6f); + uiItemS_ex(layout, small ? 0.4f : 2.0f); /* clear so the OK button is left alone */ UI_block_func_set(block, nullptr, nullptr, nullptr); +#ifdef _WIN32 + const bool windows_layout = true; +#else + const bool windows_layout = false; +#endif + /* new column so as not to interfere with custom layouts #26436. */ { uiLayout *col = uiLayoutColumn(layout, false); @@ -1733,13 +1579,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_ uiBut *cancel_but; col = uiLayoutSplit(col, 0.0f, true); - uiLayoutSetScaleY(col, 1.2f); - -#ifdef _WIN32 - const bool windows_layout = true; -#else - const bool windows_layout = false; -#endif + uiLayoutSetScaleY(col, small ? 1.0f : 1.2f); if (windows_layout) { confirm_but = uiDefBut(col_block, @@ -1747,7 +1587,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, @@ -1759,20 +1599,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); @@ -1781,7 +1609,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, @@ -1797,14 +1625,17 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_ UI_but_flag_enable((data->cancel_default) ? cancel_but : confirm_but, UI_BUT_ACTIVE_DEFAULT); } - if (data->position == WM_WARNING_POSITION_MOUSE) { - int bounds_offset[2]; - bounds_offset[0] = uiLayoutGetWidth(layout) * -0.66f; - bounds_offset[1] = UI_UNIT_Y * 2; - UI_block_bounds_set_popup(block, 10 * UI_SCALE_FAC, bounds_offset); + const int padding = (small ? 7 : 14) * UI_SCALE_FAC; + + if (data->position == WM_POPUP_POSITION_MOUSE) { + const float button_center_x = windows_layout ? -0.33f : -0.66f; + const float button_center_y = small ? 1.9f : 3.1f; + 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_WARNING_POSITION_CENTER) { - UI_block_bounds_set_centered(block, 10 * UI_SCALE_FAC); + else if (data->position == WM_POPUP_POSITION_CENTER) { + UI_block_bounds_set_centered(block, padding); } return block; @@ -1864,6 +1695,35 @@ static void wm_operator_ui_popup_ok(bContext *C, void *arg, int retval) MEM_delete(data); } +int WM_operator_confirm_ex(bContext *C, + wmOperator *op, + const char *title, + const char *message, + const char *confirm_text, + int icon, + bool cancel_default) +{ + wmOpPopUp *data = MEM_new(__func__); + data->op = op; + data->width = int(180.0f * UI_SCALE_FAC * UI_style_get()->widgetlabel.points / + UI_DEFAULT_TEXT_POINTS); + data->free_op = true; + data->title = (title == nullptr) ? WM_operatortype_name(op->type, op->ptr) : title; + data->message = (message == nullptr) ? std::string() : message; + data->confirm_text = (confirm_text == nullptr) ? IFACE_("OK") : confirm_text; + data->icon = eAlertIcon(icon); + data->size = (message == nullptr) ? WM_POPUP_SIZE_SMALL : WM_POPUP_SIZE_LARGE; + data->position = (message == nullptr) ? WM_POPUP_POSITION_MOUSE : WM_POPUP_POSITION_CENTER; + data->cancel_default = cancel_default; + data->mouse_move_quit = (message == nullptr) ? true : false; + data->include_properties = false; + + UI_popup_block_ex( + C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data, op); + + return OPERATOR_RUNNING_MODAL; +} + int WM_operator_ui_popup(bContext *C, wmOperator *op, int width) { wmOpPopUp *data = MEM_new(__func__); @@ -1937,14 +1797,17 @@ int WM_operator_props_dialog_popup( { wmOpPopUp *data = MEM_new(__func__); data->op = op; - data->width = width * UI_SCALE_FAC; + data->width = int(float(width) * UI_SCALE_FAC * UI_style_get()->widgetlabel.points / + UI_DEFAULT_TEXT_POINTS); data->free_op = true; /* if this runs and gets registered we may want not to free it */ data->title = (title == nullptr) ? WM_operatortype_name(op->type, op->ptr) : title; data->confirm_text = (confirm_text == nullptr) ? IFACE_("OK") : confirm_text; + data->icon = ALERT_ICON_NONE; + data->size = WM_POPUP_SIZE_SMALL; + data->position = WM_POPUP_POSITION_MOUSE; data->cancel_default = false; data->mouse_move_quit = false; data->include_properties = true; - data->position = WM_WARNING_POSITION_MOUSE; /* op is not executed until popup OK but is clicked */ UI_popup_block_ex(