UI: Add UILayout.operator_menu_hold
This is an operator button that opens a menu when the button is held.
This commit is contained in:
@@ -136,6 +136,7 @@ enum {
|
||||
|
||||
/* block->flag bits 14-17 are identical to but->drawflag bits */
|
||||
|
||||
#define UI_BLOCK_POPUP_HOLD (1 << 18)
|
||||
#define UI_BLOCK_LIST_ITEM (1 << 19)
|
||||
#define UI_BLOCK_RADIAL (1 << 20)
|
||||
|
||||
@@ -354,6 +355,7 @@ typedef struct uiSearchItems uiSearchItems;
|
||||
typedef void (*uiButHandleFunc)(struct bContext *C, void *arg1, void *arg2);
|
||||
typedef void (*uiButHandleRenameFunc)(struct bContext *C, void *arg, char *origstr);
|
||||
typedef void (*uiButHandleNFunc)(struct bContext *C, void *argN, void *arg2);
|
||||
typedef void (*uiButHandleHoldFunc)(struct bContext *C, struct ARegion *butregion, uiBut *but);
|
||||
typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg);
|
||||
typedef struct ARegion *(*uiButSearchCreateFunc)(struct bContext *C, struct ARegion *butregion, uiBut *but);
|
||||
typedef void (*uiButSearchFunc)(const struct bContext *C, void *arg, const char *str, uiSearchItems *items);
|
||||
@@ -395,6 +397,7 @@ void UI_popup_menu_reports(struct bContext *C, struct ReportList *reports) ATTR_
|
||||
int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportList *reports) ATTR_NONNULL(1, 2);
|
||||
|
||||
void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable);
|
||||
void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *but);
|
||||
|
||||
/* Pie menus */
|
||||
typedef struct uiPieMenu uiPieMenu;
|
||||
@@ -726,6 +729,8 @@ bool UI_textbutton_activate_but(const struct bContext *C, uiBut *but);
|
||||
|
||||
void UI_but_focus_on_enter_event(struct wmWindow *win, uiBut *but);
|
||||
|
||||
void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN);
|
||||
|
||||
/* Autocomplete
|
||||
*
|
||||
* Tab complete helper functions, for use in uiButCompleteFunc callbacks.
|
||||
@@ -988,6 +993,11 @@ void uiItemFullO(
|
||||
uiLayout *layout, const char *idname, const char *name, int icon,
|
||||
struct IDProperty *properties, int context, int flag,
|
||||
PointerRNA *r_opptr);
|
||||
void uiItemFullOMenuHold_ptr(
|
||||
uiLayout *layout, struct wmOperatorType *ot, const char *name, int icon,
|
||||
struct IDProperty *properties, int context, int flag,
|
||||
const char *menu_id, /* extra menu arg. */
|
||||
PointerRNA *r_opptr);
|
||||
|
||||
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon);
|
||||
void uiItemFullR(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, int value, int flag, const char *name, int icon);
|
||||
|
||||
@@ -2672,6 +2672,10 @@ static void ui_but_free(const bContext *C, uiBut *but)
|
||||
MEM_freeN(but->tip_argN);
|
||||
}
|
||||
|
||||
if (but->hold_argN) {
|
||||
MEM_freeN(but->hold_argN);
|
||||
}
|
||||
|
||||
if (but->active) {
|
||||
/* XXX solve later, buttons should be free-able without context ideally,
|
||||
* however they may have open tooltips or popup windows, which need to
|
||||
@@ -4520,6 +4524,12 @@ void UI_but_focus_on_enter_event(wmWindow *win, uiBut *but)
|
||||
wm_event_add(win, &event);
|
||||
}
|
||||
|
||||
void UI_but_func_hold_set(uiBut *but, uiButHandleHoldFunc func, void *argN)
|
||||
{
|
||||
but->hold_func = func;
|
||||
but->hold_argN = argN;
|
||||
}
|
||||
|
||||
void UI_but_string_info_get(bContext *C, uiBut *but, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
@@ -304,6 +304,9 @@ typedef struct uiHandleButtonData {
|
||||
bool used_mouse;
|
||||
wmTimer *autoopentimer;
|
||||
|
||||
/* auto open (hold) */
|
||||
wmTimer *hold_action_timer;
|
||||
|
||||
/* text selection/editing */
|
||||
/* size of 'str' (including terminator) */
|
||||
int maxlen;
|
||||
@@ -7808,6 +7811,15 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s
|
||||
data->flashtimer = NULL;
|
||||
}
|
||||
|
||||
/* add hold timer if it's used */
|
||||
if (state == BUTTON_STATE_WAIT_RELEASE && (but->hold_func != NULL)) {
|
||||
data->hold_action_timer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_AUTO_OPEN_THRESH);
|
||||
}
|
||||
else if (data->hold_action_timer) {
|
||||
WM_event_remove_timer(data->wm, data->window, data->hold_action_timer);
|
||||
data->hold_action_timer = NULL;
|
||||
}
|
||||
|
||||
/* add a blocking ui handler at the window handler for blocking, modal states
|
||||
* but not for popups, because we already have a window level handler*/
|
||||
if (!(but->block->handle && but->block->handle->popup)) {
|
||||
@@ -8422,6 +8434,25 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
|
||||
button_activate_state(C, but, BUTTON_STATE_EXIT);
|
||||
break;
|
||||
|
||||
case TIMER:
|
||||
{
|
||||
if (event->customdata == data->hold_action_timer) {
|
||||
if (true) {
|
||||
data->cancel = true;
|
||||
button_activate_state(C, but, BUTTON_STATE_EXIT);
|
||||
}
|
||||
else {
|
||||
/* Do this so we can still mouse-up, closing the menu and running the button.
|
||||
* This is nice to support but there are times when the button gets left pressed.
|
||||
* Keep disavled for now. */
|
||||
WM_event_remove_timer(data->wm, data->window, data->hold_action_timer);
|
||||
data->hold_action_timer = NULL;
|
||||
}
|
||||
retval = WM_UI_HANDLER_CONTINUE;
|
||||
but->hold_func(C, data->region, but);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MOUSEMOVE:
|
||||
if (ELEM(but->type, UI_BTYPE_LINK, UI_BTYPE_INLINK)) {
|
||||
but->flag |= UI_SELECT;
|
||||
@@ -9348,21 +9379,29 @@ static int ui_handle_menu_event(
|
||||
if (inside == 0) {
|
||||
uiSafetyRct *saferct = block->saferct.first;
|
||||
|
||||
if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) &&
|
||||
ELEM(event->val, KM_PRESS, KM_DBL_CLICK))
|
||||
{
|
||||
if ((is_parent_menu == false) && (U.uiflag & USER_MENUOPENAUTO) == 0) {
|
||||
/* for root menus, allow clicking to close */
|
||||
if (block->flag & (UI_BLOCK_OUT_1))
|
||||
menu->menuretval = UI_RETURN_OK;
|
||||
else
|
||||
menu->menuretval = UI_RETURN_OUT;
|
||||
if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
|
||||
if (ELEM(event->val, KM_PRESS, KM_DBL_CLICK)) {
|
||||
if ((is_parent_menu == false) && (U.uiflag & USER_MENUOPENAUTO) == 0) {
|
||||
/* for root menus, allow clicking to close */
|
||||
if (block->flag & (UI_BLOCK_OUT_1))
|
||||
menu->menuretval = UI_RETURN_OK;
|
||||
else
|
||||
menu->menuretval = UI_RETURN_OUT;
|
||||
}
|
||||
else if (saferct && !BLI_rctf_isect_pt(&saferct->parent, event->x, event->y)) {
|
||||
if (block->flag & (UI_BLOCK_OUT_1))
|
||||
menu->menuretval = UI_RETURN_OK;
|
||||
else
|
||||
menu->menuretval = UI_RETURN_OUT;
|
||||
}
|
||||
}
|
||||
else if (saferct && !BLI_rctf_isect_pt(&saferct->parent, event->x, event->y)) {
|
||||
if (block->flag & (UI_BLOCK_OUT_1))
|
||||
menu->menuretval = UI_RETURN_OK;
|
||||
else
|
||||
menu->menuretval = UI_RETURN_OUT;
|
||||
else if (ELEM(event->val, KM_RELEASE, KM_CLICK)) {
|
||||
/* For buttons that use a hold function, exit when mouse-up outside the menu. */
|
||||
if (block->flag & UI_BLOCK_POPUP_HOLD) {
|
||||
/* Note, we could check the cursor is over the parent button. */
|
||||
menu->menuretval = UI_RETURN_CANCEL;
|
||||
retval = WM_UI_HANDLER_CONTINUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +264,10 @@ struct uiBut {
|
||||
void *rename_arg1;
|
||||
void *rename_orig;
|
||||
|
||||
/* Run an action when holding the button down. */
|
||||
uiButHandleHoldFunc hold_func;
|
||||
void *hold_argN;
|
||||
|
||||
uiLink *link;
|
||||
short linkto[2]; /* region relative coords */
|
||||
|
||||
|
||||
@@ -795,7 +795,7 @@ static void ui_item_disabled(uiLayout *layout, const char *name)
|
||||
* \param r_opptr: Optional, initialize with operator properties when not NULL.
|
||||
* Will always be written to even in the case of errors.
|
||||
*/
|
||||
void uiItemFullO_ptr(
|
||||
static uiBut *uiItemFullO_ptr_ex(
|
||||
uiLayout *layout, wmOperatorType *ot,
|
||||
const char *name, int icon, IDProperty *properties, int context, int flag,
|
||||
PointerRNA *r_opptr)
|
||||
@@ -862,6 +862,50 @@ void uiItemFullO_ptr(
|
||||
*r_opptr = *opptr;
|
||||
}
|
||||
}
|
||||
|
||||
return but;
|
||||
}
|
||||
|
||||
static void ui_item_hold_menu(struct bContext *C, ARegion *butregion, uiBut *but)
|
||||
{
|
||||
uiPopupMenu *pup = UI_popup_menu_begin(C, "", ICON_NONE);
|
||||
uiLayout *layout = UI_popup_menu_layout(pup);
|
||||
uiBlock *block = layout->root->block;
|
||||
UI_popup_menu_but_set(pup, butregion, but);
|
||||
|
||||
block->flag |= UI_BLOCK_POPUP_HOLD;
|
||||
|
||||
const char *menu_id = but->hold_argN;
|
||||
MenuType *mt = WM_menutype_find(menu_id, true);
|
||||
if (mt) {
|
||||
Menu menu = {NULL};
|
||||
menu.layout = layout;
|
||||
menu.type = mt;
|
||||
mt->draw(C, &menu);
|
||||
}
|
||||
else {
|
||||
uiItemL(layout, "Menu Missing:", ICON_NONE);
|
||||
uiItemL(layout, menu_id, ICON_NONE);
|
||||
}
|
||||
UI_popup_menu_end(C, pup);
|
||||
}
|
||||
|
||||
void uiItemFullO_ptr(
|
||||
uiLayout *layout, wmOperatorType *ot,
|
||||
const char *name, int icon, IDProperty *properties, int context, int flag,
|
||||
PointerRNA *r_opptr)
|
||||
{
|
||||
uiItemFullO_ptr_ex(layout, ot, name, icon, properties, context, flag, r_opptr);
|
||||
}
|
||||
|
||||
void uiItemFullOMenuHold_ptr(
|
||||
uiLayout *layout, wmOperatorType *ot,
|
||||
const char *name, int icon, IDProperty *properties, int context, int flag,
|
||||
const char *menu_id,
|
||||
PointerRNA *r_opptr)
|
||||
{
|
||||
uiBut *but = uiItemFullO_ptr_ex(layout, ot, name, icon, properties, context, flag, r_opptr);
|
||||
UI_but_func_hold_set(but, ui_item_hold_menu, BLI_strdup(menu_id));
|
||||
}
|
||||
|
||||
void uiItemFullO(
|
||||
|
||||
@@ -2627,6 +2627,7 @@ struct uiPopupMenu {
|
||||
uiBlock *block;
|
||||
uiLayout *layout;
|
||||
uiBut *but;
|
||||
ARegion *butregion;
|
||||
|
||||
int mx, my;
|
||||
bool popup, slideout;
|
||||
@@ -2873,17 +2874,33 @@ uiPopupMenu *UI_popup_menu_begin(bContext *C, const char *title, int icon)
|
||||
return UI_popup_menu_begin_ex(C, title, __func__, icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting the button makes the popup open from the button instead of the cursor.
|
||||
*/
|
||||
void UI_popup_menu_but_set(uiPopupMenu *pup, struct ARegion *butregion, uiBut *but)
|
||||
{
|
||||
pup->but = but;
|
||||
pup->butregion = butregion;
|
||||
}
|
||||
|
||||
/* set the whole structure to work */
|
||||
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
|
||||
{
|
||||
wmWindow *window = CTX_wm_window(C);
|
||||
uiPopupBlockHandle *menu;
|
||||
uiBut *but = NULL;
|
||||
ARegion *butregion = NULL;
|
||||
|
||||
pup->popup = true;
|
||||
pup->mx = window->eventstate->x;
|
||||
pup->my = window->eventstate->y;
|
||||
|
||||
menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup);
|
||||
|
||||
if (pup->but) {
|
||||
but = pup->but;
|
||||
butregion = pup->butregion;
|
||||
}
|
||||
|
||||
menu = ui_popup_block_create(C, butregion, but, NULL, ui_block_func_POPUP, pup);
|
||||
menu->popup = true;
|
||||
|
||||
UI_popup_handlers_add(C, &window->modalhandlers, menu, 0);
|
||||
|
||||
@@ -66,6 +66,15 @@
|
||||
/* icons are 80% of height of button (16 pixels inside 20 height) */
|
||||
#define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect))
|
||||
|
||||
#define UI_BUT_FLAGS_PUBLIC \
|
||||
(UI_SELECT | UI_SCROLLED | UI_ACTIVE | UI_HAS_ICON | UI_TEXTINPUT | UI_HIDDEN)
|
||||
|
||||
/* Bits 0..5 are from UI_SELECT .. etc */
|
||||
enum {
|
||||
/* Show that holding the button opens a menu. */
|
||||
UI_STATE_HOLD_ACTION = (1 << 6),
|
||||
};
|
||||
|
||||
/* ************** widget base functions ************** */
|
||||
/**
|
||||
* - in: roundbox codes for corner types and radius
|
||||
@@ -184,6 +193,15 @@ static const unsigned int check_tria_face[4][3] = {
|
||||
{3, 2, 4}, {3, 4, 5}, {1, 0, 3}, {0, 2, 3}
|
||||
};
|
||||
|
||||
#define OY -0.2
|
||||
#define SC 0.35
|
||||
static const unsigned int hold_action_tri_face[2][3] = {{2, 0, 1}, {3, 5, 4}};
|
||||
static const float hold_action_tri_vert[6][2] = {
|
||||
{-0.5 + SC, 1.0 + OY}, {0.5, 1.0 + OY}, {0.5, 0.0 + OY + SC},
|
||||
};
|
||||
#undef OY
|
||||
#undef SC
|
||||
|
||||
/* ************************************************* */
|
||||
|
||||
void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3)
|
||||
@@ -529,6 +547,14 @@ static void widget_num_tria(uiWidgetTrias *tria, const rcti *rect, float triasiz
|
||||
num_tria_face, ARRAY_SIZE(num_tria_face));
|
||||
}
|
||||
|
||||
static void widget_hold_action_tria(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
|
||||
{
|
||||
widget_draw_tria_ex(
|
||||
tria, rect, triasize, where,
|
||||
hold_action_tri_vert, ARRAY_SIZE(hold_action_tri_vert),
|
||||
hold_action_tri_face, ARRAY_SIZE(hold_action_tri_face));
|
||||
}
|
||||
|
||||
static void widget_scroll_circle(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
|
||||
{
|
||||
widget_draw_tria_ex(
|
||||
@@ -3347,6 +3373,7 @@ static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int
|
||||
widgetbase_draw(&wtb, wcol);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
|
||||
{
|
||||
uiWidgetBase wtb;
|
||||
@@ -3359,6 +3386,25 @@ static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state),
|
||||
|
||||
widgetbase_draw(&wtb, wcol);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void widget_roundbut_exec(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
|
||||
{
|
||||
uiWidgetBase wtb;
|
||||
const float rad = 0.25f * U.widget_unit;
|
||||
|
||||
widget_init(&wtb);
|
||||
|
||||
if (state & UI_STATE_HOLD_ACTION) {
|
||||
/* Show that keeping pressed performs another action (typically a menu). */
|
||||
widget_hold_action_tria(&wtb.tria1, rect, 0.75f, 'r');
|
||||
}
|
||||
|
||||
/* half rounded */
|
||||
round_box_edges(&wtb, roundboxalign, rect, rad);
|
||||
|
||||
widgetbase_draw(&wtb, wcol);
|
||||
}
|
||||
|
||||
static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
|
||||
{
|
||||
@@ -3439,7 +3485,7 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
|
||||
|
||||
case UI_WTYPE_EXEC:
|
||||
wt.wcol_theme = &btheme->tui.wcol_tool;
|
||||
wt.draw = widget_roundbut;
|
||||
wt.draw = widget_roundbut_exec;
|
||||
break;
|
||||
|
||||
case UI_WTYPE_TOOLTIP:
|
||||
@@ -3849,7 +3895,7 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
|
||||
|
||||
roundboxalign = widget_roundbox_set(but, rect);
|
||||
|
||||
state = but->flag;
|
||||
state = but->flag & UI_BUT_FLAGS_PUBLIC;
|
||||
|
||||
if ((but->editstr) ||
|
||||
(UNLIKELY(but->flag & UI_BUT_DRAG_MULTI) && ui_but_drag_multi_edit_get(but)))
|
||||
@@ -3857,6 +3903,10 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
|
||||
state |= UI_TEXTINPUT;
|
||||
}
|
||||
|
||||
if (but->hold_func) {
|
||||
state |= UI_STATE_HOLD_ACTION;
|
||||
}
|
||||
|
||||
if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE))
|
||||
if (but->dt != UI_EMBOSS_PULLDOWN)
|
||||
disabled = true;
|
||||
|
||||
@@ -202,6 +202,30 @@ static PointerRNA rna_uiItemO(uiLayout *layout, const char *opname, const char *
|
||||
return opptr;
|
||||
}
|
||||
|
||||
static PointerRNA rna_uiItemOMenuHold(
|
||||
uiLayout *layout, const char *opname, const char *name, const char *text_ctxt,
|
||||
int translate, int icon, int emboss, int icon_value,
|
||||
const char *menu)
|
||||
{
|
||||
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
|
||||
if (!ot || !ot->srna) {
|
||||
RNA_warning("%s '%s'", ot ? "unknown operator" : "operator missing srna", opname);
|
||||
return PointerRNA_NULL;
|
||||
}
|
||||
|
||||
/* Get translated name (label). */
|
||||
name = rna_translate_ui_text(name, text_ctxt, ot->srna, NULL, translate);
|
||||
if (icon_value && !icon) {
|
||||
icon = icon_value;
|
||||
}
|
||||
int flag = (emboss) ? 0 : UI_ITEM_R_NO_BG;
|
||||
|
||||
PointerRNA opptr;
|
||||
uiItemFullOMenuHold_ptr(layout, ot, name, icon, NULL, uiLayoutGetOperatorContext(layout), flag, menu, &opptr);
|
||||
return opptr;
|
||||
}
|
||||
|
||||
|
||||
static void rna_uiItemMenuEnumO(uiLayout *layout, bContext *C, const char *opname, const char *propname, const char *name,
|
||||
const char *text_ctxt, int translate, int icon)
|
||||
{
|
||||
@@ -553,15 +577,23 @@ void RNA_api_ui_layout(StructRNA *srna)
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
api_ui_item_common(func);
|
||||
|
||||
func = RNA_def_function(srna, "operator", "rna_uiItemO");
|
||||
api_ui_item_op_common(func);
|
||||
RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, just the icon/text");
|
||||
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");
|
||||
parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "Operator properties to fill in");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
|
||||
RNA_def_function_return(func, parm);
|
||||
RNA_def_function_ui_description(func, "Item. Places a button into the layout to call an Operator");
|
||||
for (int is_menu_hold = 0; is_menu_hold < 2; is_menu_hold++) {
|
||||
func = (is_menu_hold) ?
|
||||
RNA_def_function(srna, "operator_menu_hold", "rna_uiItemOMenuHold") :
|
||||
RNA_def_function(srna, "operator", "rna_uiItemO");
|
||||
api_ui_item_op_common(func);
|
||||
RNA_def_boolean(func, "emboss", true, "", "Draw the button itself, just the icon/text");
|
||||
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");
|
||||
if (is_menu_hold) {
|
||||
parm = RNA_def_string(func, "menu", NULL, 0, "", "Identifier of the menu");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
}
|
||||
parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "Operator properties to fill in");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
|
||||
RNA_def_function_return(func, parm);
|
||||
RNA_def_function_ui_description(func, "Item. Places a button into the layout to call an Operator");
|
||||
}
|
||||
|
||||
func = RNA_def_function(srna, "operator_enum", "uiItemsEnumO");
|
||||
parm = RNA_def_string(func, "operator", NULL, 0, "", "Identifier of the operator");
|
||||
|
||||
Reference in New Issue
Block a user