UI: Operator Props Dialog Changes #117528

Merged
Harley Acheson merged 9 commits from Harley/blender:OpPropertyDialog into main 2024-01-26 20:52:39 +01:00
5 changed files with 172 additions and 40 deletions

View File

@ -240,6 +240,8 @@ bool rna_AnimaData_override_apply(struct Main *bmain,
void rna_def_animviz_common(struct StructRNA *srna);
void rna_def_motionpath_common(struct StructRNA *srna);
void api_ui_item_common_translation(FunctionRNA *func);
/**
* Settings for curved bbone settings.
*/

View File

@ -973,21 +973,26 @@ static void api_ui_item_common_heading(FunctionRNA *func)
func, "translate", true, "", "Translate the given heading, when UI translation is enabled");
}
void api_ui_item_common_translation(FunctionRNA *func)
{
PropertyRNA *prop = RNA_def_string(func,
"text_ctxt",
nullptr,
0,
"",
"Override automatic translation context of the given text");
RNA_def_property_clear_flag(prop, PROP_NEVER_NULL);
RNA_def_boolean(
func, "translate", true, "", "Translate the given text, when UI translation is enabled");
}
static void api_ui_item_common_text(FunctionRNA *func)
{
PropertyRNA *prop;
prop = RNA_def_string(func, "text", nullptr, 0, "", "Override automatic text of the item");
RNA_def_property_clear_flag(prop, PROP_NEVER_NULL);
prop = RNA_def_string(func,
"text_ctxt",
nullptr,
0,
"",
"Override automatic translation context of the given text");
RNA_def_property_clear_flag(prop, PROP_NEVER_NULL);
RNA_def_boolean(
func, "translate", true, "", "Translate the given text, when UI translation is enabled");
api_ui_item_common_translation(func);
}
static void api_ui_item_common(FunctionRNA *func)

View File

@ -218,6 +218,19 @@ static int rna_Operator_props_popup(bContext *C, wmOperator *op, wmEvent *event)
return WM_operator_props_popup(C, op, event);
}
static int rna_Operator_props_dialog_popup(bContext *C,
wmOperator *op,
const int width,
const char *title,
const char *confirm_text,
const char *text_ctxt,
const bool translate)
{
title = RNA_translate_ui_text(title, text_ctxt, nullptr, nullptr, translate);
confirm_text = RNA_translate_ui_text(confirm_text, text_ctxt, nullptr, nullptr, translate);
return WM_operator_props_dialog_popup(C, op, width, title, confirm_text);
}
Harley marked this conversation as resolved Outdated

Misses nullptr checks in WM_operator_props_dialog_popup string params

Misses `nullptr` checks in `WM_operator_props_dialog_popup` string params
static int keymap_item_modifier_flag_from_args(bool any, int shift, int ctrl, int alt, int oskey)
{
int modifier = 0;
@ -859,13 +872,22 @@ void RNA_api_wm(StructRNA *srna)
rna_generic_op_invoke(func, WM_GEN_INVOKE_EVENT | WM_GEN_INVOKE_RETURN);
/* invoked dialog opens popup with OK button, does not auto-exec operator. */
func = RNA_def_function(srna, "invoke_props_dialog", "WM_operator_props_dialog_popup");
func = RNA_def_function(srna, "invoke_props_dialog", "rna_Operator_props_dialog_popup");
RNA_def_function_ui_description(
func,
"Operator dialog (non-autoexec popup) invoke "
"(show operator properties and only execute it on click on OK button)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_SIZE | 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, "confirm_text", PROP_STRING, PROP_NONE);
Harley marked this conversation as resolved

title of the tile -> title of the popup

title of the tile -> title of the popup
RNA_def_property_ui_text(
parm,
"Confirm Text",
"Optional text to show instead to the default \"OK\" confirmation button text");
api_ui_item_common_translation(func);
Harley marked this conversation as resolved

I'm not sure it makes sense to have cancel_default without also being able to change the text of the cancel button. Or if we want to have popups that do this at all actually.

Can we leave this out of the Python API until it's more clear if this is something we actually want to recommend people use? I don't mind having it in C++.

I'm not sure it makes sense to have `cancel_default` without also being able to change the text of the cancel button. Or if we want to have popups that do this at all actually. Can we leave this out of the Python API until it's more clear if this is something we actually want to recommend people use? I don't mind having it in C++.
/* invoke enum */
func = RNA_def_function(srna, "invoke_search_popup", "rna_Operator_enum_search_invoke");
RNA_def_function_ui_description(

View File

@ -708,7 +708,13 @@ int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *
*/
int WM_operator_props_popup_call(bContext *C, wmOperator *op, const wmEvent *event);
int WM_operator_props_popup(bContext *C, wmOperator *op, const wmEvent *event);
int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width);
int WM_operator_props_dialog_popup(bContext *C,
wmOperator *op,
int width,
const char *title = nullptr,
const char *confirm_text = nullptr);
int WM_operator_redo_popup(bContext *C, wmOperator *op);
int WM_operator_ui_popup(bContext *C, wmOperator *op, int width);

View File

@ -1642,8 +1642,17 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *region, void *arg_op)
struct wmOpPopUp {
wmOperator *op;
int width;
int height;
int free_op;
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;
bool include_properties;
};
/* Only invoked by OK button in popups created with wm_block_dialog_create() */
@ -1655,7 +1664,7 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
* In this case, wm_operator_ui_popup_cancel won't run. */
wmOpPopUp *data = static_cast<wmOpPopUp *>(arg1);
op = data->op;
MEM_freeN(data);
MEM_delete(data);
}
uiBlock *block = static_cast<uiBlock *>(arg2);
@ -1672,6 +1681,18 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
WM_operator_call_ex(C, op, true);
}
static void wm_operator_ui_popup_cancel(bContext *C, void *user_data);
/* Only invoked by Cancel button in popups created with wm_block_dialog_create() */
static void dialog_cancel_cb(bContext *C, void *arg1, void *arg2)
Harley marked this conversation as resolved

this few lines (1687-1700) duplicates wm_operator_ui_popup_cancel

this few lines (1687-1700) duplicates `wm_operator_ui_popup_cancel`
{
wm_operator_ui_popup_cancel(C, arg1);
uiBlock *block = static_cast<uiBlock *>(arg2);
UI_popup_menu_retval_set(block, UI_RETURN_CANCEL, true);
wmWindow *win = CTX_wm_window(C);
UI_popup_block_close(C, win, block);
}
/* Dialogs are popups that require user verification (click OK) before exec */
static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_data)
{
@ -1681,17 +1702,25 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
UI_block_flag_disable(block, UI_BLOCK_LOOP);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_REGULAR);
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
if (data->mouse_move_quit) {
UI_block_flag_enable(block, UI_BLOCK_MOVEMOUSE_QUIT);
}
/* Intentionally don't use #UI_BLOCK_MOVEMOUSE_QUIT, some dialogs have many items
* where quitting by accident is very annoying. */
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, data->height, 0, style);
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, 0, 0, style);
uiTemplateOperatorPropertyButs(
C, layout, op, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN, UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
uiItemL_ex(layout, data->title.c_str(), ICON_NONE, true, false);
uiItemS_ex(layout, 0.3f);
if (data->include_properties) {
uiTemplateOperatorPropertyButs(C, layout, op, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN, 0);
}
uiItemS_ex(layout, 0.6f);
/* clear so the OK button is left alone */
UI_block_func_set(block, nullptr, nullptr, nullptr);
@ -1700,16 +1729,83 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *user_
{
uiLayout *col = uiLayoutColumn(layout, false);
uiBlock *col_block = uiLayoutGetBlock(col);
/* Create OK button, the callback of which will execute op */
uiBut *but = uiDefBut(
col_block, UI_BTYPE_BUT, 0, IFACE_("OK"), 0, -30, 0, UI_UNIT_Y, nullptr, 0, 0, 0, 0, "");
UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
UI_but_func_set(but, dialog_exec_cb, data, col_block);
uiBut *confirm_but;
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
if (windows_layout) {
confirm_but = uiDefBut(col_block,
UI_BTYPE_BUT,
0,
data->confirm_text.c_str(),
0,
-30,
0,
UI_UNIT_Y,
nullptr,
0,
0,
0,
0,
"");
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,
"");
if (!windows_layout) {
uiLayoutColumn(col, false);
confirm_but = uiDefBut(col_block,
UI_BTYPE_BUT,
0,
data->confirm_text.c_str(),
0,
-30,
0,
UI_UNIT_Y,
nullptr,
0,
0,
0,
0,
"");
}
UI_but_func_set(confirm_but, dialog_exec_cb, data, col_block);
UI_but_func_set(cancel_but, dialog_cancel_cb, data, col_block);
UI_but_flag_enable((data->cancel_default) ? cancel_but : confirm_but, UI_BUT_ACTIVE_DEFAULT);
}
/* center around the mouse */
UI_block_bounds_set_popup(
block, 6 * UI_SCALE_FAC, blender::int2{data->width / -2, data->height / 2});
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);
}
else if (data->position == WM_WARNING_POSITION_CENTER) {
UI_block_bounds_set_centered(block, 10 * UI_SCALE_FAC);
}
return block;
}
@ -1726,7 +1822,7 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *region, void *user_d
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_REGULAR);
uiLayout *layout = UI_block_layout(
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, 0, 0, style);
/* since ui is defined the auto-layout args are not used */
uiTemplateOperatorPropertyButs(C, layout, op, UI_BUT_LABEL_ALIGN_COLUMN, 0);
@ -1753,7 +1849,7 @@ static void wm_operator_ui_popup_cancel(bContext *C, void *user_data)
}
}
MEM_freeN(data);
MEM_delete(data);
}
static void wm_operator_ui_popup_ok(bContext *C, void *arg, int retval)
@ -1765,17 +1861,14 @@ static void wm_operator_ui_popup_ok(bContext *C, void *arg, int retval)
WM_operator_call_ex(C, op, true);
}
MEM_freeN(data);
MEM_delete(data);
}
int WM_operator_ui_popup(bContext *C, wmOperator *op, int width)
{
wmOpPopUp *data = static_cast<wmOpPopUp *>(
MEM_callocN(sizeof(wmOpPopUp), "WM_operator_ui_popup"));
wmOpPopUp *data = MEM_new<wmOpPopUp>(__func__);
data->op = op;
data->width = width * UI_SCALE_FAC;
/* Actual used height depends on the content. */
data->height = 0;
data->free_op = true; /* if this runs and gets registered we may want not to free it */
UI_popup_block_ex(C, wm_operator_ui_create, nullptr, wm_operator_ui_popup_cancel, data, op);
return OPERATOR_RUNNING_MODAL;
@ -1839,16 +1932,20 @@ int WM_operator_props_popup(bContext *C, wmOperator *op, const wmEvent * /*event
return wm_operator_props_popup_ex(C, op, false, true);
}
int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width)
int WM_operator_props_dialog_popup(
bContext *C, wmOperator *op, int width, const char *title, const char *confirm_text)
{
wmOpPopUp *data = static_cast<wmOpPopUp *>(
MEM_callocN(sizeof(wmOpPopUp), "WM_operator_props_dialog_popup"));
wmOpPopUp *data = MEM_new<wmOpPopUp>(__func__);
data->op = op;
data->width = width * UI_SCALE_FAC;
/* Actual height depends on the content. */
data->height = 0;
data->free_op = true; /* if this runs and gets registered we may want not to free it */
data->title = (title == nullptr) ? WM_operatortype_description(C, op->type, op->ptr) : title;
data->confirm_text = (confirm_text == nullptr) ? WM_operatortype_name(op->type, op->ptr) :
confirm_text;
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(