diff --git a/scripts/startup/bl_ui/space_node.py b/scripts/startup/bl_ui/space_node.py index 807f09e5677..8e190fe9f64 100644 --- a/scripts/startup/bl_ui/space_node.py +++ b/scripts/startup/bl_ui/space_node.py @@ -208,6 +208,13 @@ class NODE_HT_header(Header): sub.active = snode.show_backdrop sub.prop(snode, "backdrop_channels", icon_only=True, text="", expand=True) + # Navigate + row = layout.row(align=True) + row.prop(snode, "show_gizmo", icon='GIZMO', text="") + sub = row.row(align=True) + sub.active = snode.show_gizmo + sub.popover(panel="NODE_PT_gizmo_display", text="") + # Snap row = layout.row(align=True) row.prop(tool_settings, "use_snap_node", text="") @@ -223,6 +230,26 @@ class NODE_HT_header(Header): sub.popover(panel="NODE_PT_overlay", text="") +class NODE_PT_gizmo_display(Panel): + bl_space_type = 'NODE_EDITOR' + bl_region_type = 'HEADER' + bl_label = 'Gizmos' + bl_ui_units_x = 8 + + def draw(self, context): + layout = self.layout + + snode = context.space_data + + col = layout.column() + col.label(text="Viewport Gizmos") + col.separator() + + col.active = snode.show_gizmo + colsub = col.column() + colsub.prop(snode, "show_gizmo_navigate", text="Navigate") + + class NODE_MT_editor_menus(Menu): bl_idname = "NODE_MT_editor_menus" bl_label = "" @@ -810,7 +837,6 @@ class NODE_PT_backdrop(Panel): col.separator() - col.operator("node.backimage_move", text="Move") col.operator("node.backimage_fit", text="Fit") @@ -1072,6 +1098,7 @@ classes = ( NODE_PT_annotation, NODE_PT_overlay, NODE_PT_active_node_properties, + NODE_PT_gizmo_display, node_panel(EEVEE_MATERIAL_PT_settings), node_panel(EEVEE_NEXT_MATERIAL_PT_settings), diff --git a/source/blender/editors/include/ED_node_c.hh b/source/blender/editors/include/ED_node_c.hh index 1bb4faf474d..e4f2d3efbcb 100644 --- a/source/blender/editors/include/ED_node_c.hh +++ b/source/blender/editors/include/ED_node_c.hh @@ -154,3 +154,8 @@ bool ED_space_node_get_position( */ bool ED_space_node_color_sample( Main *bmain, SpaceNode *snode, ARegion *region, const int mval[2], float r_col[3]); + +/** + * Returns the size of the compositor backdrop image. + */ +void ED_space_node_get_backdrop_size(Main *bmain, int *r_width, int *r_height); diff --git a/source/blender/editors/include/UI_view2d.hh b/source/blender/editors/include/UI_view2d.hh index 4221e69ece9..fc92d99ebcb 100644 --- a/source/blender/editors/include/UI_view2d.hh +++ b/source/blender/editors/include/UI_view2d.hh @@ -483,6 +483,7 @@ void UI_view2d_smooth_view(const bContext *C, ARegion *region, const rctf *cur, * Caller defines the name for gizmo group. */ void VIEW2D_GGT_navigate_impl(wmGizmoGroupType *gzgt, const char *idname); +void VIEW2D_GGT_navigate_backdrop_impl(wmGizmoGroupType *gzgt, const char *idname); /** \} */ diff --git a/source/blender/editors/interface/view2d_gizmo_navigate.cc b/source/blender/editors/interface/view2d_gizmo_navigate.cc index 3a13616a0e2..3e0566d8b7e 100644 --- a/source/blender/editors/interface/view2d_gizmo_navigate.cc +++ b/source/blender/editors/interface/view2d_gizmo_navigate.cc @@ -91,6 +91,19 @@ static NavigateGizmoInfo g_navigate_params_for_view2d[GZ_INDEX_TOTAL] = { }, }; +static NavigateGizmoInfo g_navigate_params_for_space_node_backdrop[GZ_INDEX_TOTAL] = { + { + "NODE_OT_backimage_move", + "GIZMO_GT_button_2d", + ICON_VIEW_PAN, + }, + { + "NODE_OT_backimage_zoom", + "GIZMO_GT_button_2d", + ICON_VIEW_ZOOM, + }, +}; + static NavigateGizmoInfo *navigate_params_from_space_type(short space_type) { switch (space_type) { @@ -99,60 +112,27 @@ static NavigateGizmoInfo *navigate_params_from_space_type(short space_type) case SPACE_CLIP: return g_navigate_params_for_space_clip; default: - /* Used for sequencer. */ + /* Used for sequencer and node editors. */ return g_navigate_params_for_view2d; } } struct NavigateWidgetGroup { wmGizmo *gz_array[GZ_INDEX_TOTAL]; + /* Sets position of first gizmo in group. Needed to avoid overlap with other gizmo groups. */ + int slot_offset; /* Store the view state to check for changes. */ struct { rcti rect_visible; } state; }; -static bool WIDGETGROUP_navigate_poll(const bContext *C, wmGizmoGroupType * /*gzgt*/) +static void navigate_setup(const NavigateGizmoInfo *navigate_params, + NavigateWidgetGroup *navgroup, + wmGizmoGroup *gzgroup) { - if ((U.uiflag & USER_SHOW_GIZMO_NAVIGATE) == 0) { - return false; - } - ScrArea *area = CTX_wm_area(C); - if (area == nullptr) { - return false; - } - switch (area->spacetype) { - case SPACE_SEQ: { - const SpaceSeq *sseq = static_cast(area->spacedata.first); - if (sseq->gizmo_flag & (SEQ_GIZMO_HIDE | SEQ_GIZMO_HIDE_NAVIGATE)) { - return false; - } - break; - } - case SPACE_IMAGE: { - const SpaceImage *sima = static_cast(area->spacedata.first); - if (sima->gizmo_flag & (SI_GIZMO_HIDE | SI_GIZMO_HIDE_NAVIGATE)) { - return false; - } - break; - } - case SPACE_CLIP: { - const SpaceClip *sc = static_cast(area->spacedata.first); - if (sc->gizmo_flag & (SCLIP_GIZMO_HIDE | SCLIP_GIZMO_HIDE_NAVIGATE)) { - return false; - } - break; - } - } - return true; -} - -static void WIDGETGROUP_navigate_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup) -{ - NavigateWidgetGroup *navgroup = MEM_cnew(__func__); - - const NavigateGizmoInfo *navigate_params = navigate_params_from_space_type( - gzgroup->type->gzmap_params.spaceid); + BLI_assert(navigate_params != nullptr); + BLI_assert(navgroup != nullptr); for (int i = 0; i < GZ_INDEX_TOTAL; i++) { const NavigateGizmoInfo *info = &navigate_params[i]; @@ -206,6 +186,57 @@ static void WIDGETGROUP_navigate_setup(const bContext * /*C*/, wmGizmoGroup *gzg gzgroup->customdata = navgroup; } +static bool WIDGETGROUP_navigate_poll(const bContext *C, wmGizmoGroupType * /*gzgt*/) +{ + if ((U.uiflag & USER_SHOW_GIZMO_NAVIGATE) == 0) { + return false; + } + ScrArea *area = CTX_wm_area(C); + if (area == nullptr) { + return false; + } + switch (area->spacetype) { + case SPACE_SEQ: { + const SpaceSeq *sseq = static_cast(area->spacedata.first); + if (sseq->gizmo_flag & (SEQ_GIZMO_HIDE | SEQ_GIZMO_HIDE_NAVIGATE)) { + return false; + } + break; + } + case SPACE_IMAGE: { + const SpaceImage *sima = static_cast(area->spacedata.first); + if (sima->gizmo_flag & (SI_GIZMO_HIDE | SI_GIZMO_HIDE_NAVIGATE)) { + return false; + } + break; + } + case SPACE_CLIP: { + const SpaceClip *sc = static_cast(area->spacedata.first); + if (sc->gizmo_flag & (SCLIP_GIZMO_HIDE | SCLIP_GIZMO_HIDE_NAVIGATE)) { + return false; + } + break; + } + case SPACE_NODE: { + const SpaceNode *snode = static_cast(area->spacedata.first); + if (snode->gizmo_flag & (SNODE_GIZMO_HIDE | SNODE_GIZMO_HIDE_NAVIGATE)) + return false; + } break; + } + return true; +} + +static void WIDGETGROUP_navigate_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup) +{ + NavigateWidgetGroup *navgroup = MEM_cnew(__func__); + navgroup->slot_offset = 0; + + const NavigateGizmoInfo *navigate_params = navigate_params_from_space_type( + gzgroup->type->gzmap_params.spaceid); + + navigate_setup(navigate_params, navgroup, gzgroup); +} + static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { NavigateWidgetGroup *navgroup = static_cast(gzgroup->customdata); @@ -235,7 +266,7 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true); } - int icon_mini_slot = 0; + int icon_mini_slot = navgroup->slot_offset; gz = navgroup->gz_array[GZ_INDEX_ZOOM]; gz->matrix_basis[3][0] = roundf(co[0]); @@ -262,3 +293,46 @@ void VIEW2D_GGT_navigate_impl(wmGizmoGroupType *gzgt, const char *idname) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Compositor Backdrop Navigation Gizmo Group + * \{ */ + +static bool WIDGETGROUP_navigate_backdrop_poll(const bContext *C, wmGizmoGroupType * /*gzgt*/) +{ + ScrArea *area = CTX_wm_area(C); + + const SpaceNode *snode = static_cast(area->spacedata.first); + if (snode->gizmo_flag & (SNODE_GIZMO_HIDE | SNODE_GIZMO_HIDE_NAVIGATE) || + (snode->flag & SNODE_BACKDRAW) == 0) + { + return false; + } + + return true; +} + +static void WIDGETGROUP_navigate_backdrop_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup) +{ + NavigateWidgetGroup *navgroup = MEM_cnew(__func__); + /* 2D views occupy 2 Gizmos for pan and zoom. Backdrop gizmos come right after. */ + navgroup->slot_offset = 3; + + const NavigateGizmoInfo *navigate_params = g_navigate_params_for_space_node_backdrop; + navigate_setup(navigate_params, navgroup, gzgroup); +} + +void VIEW2D_GGT_navigate_backdrop_impl(wmGizmoGroupType *gzgt, const char *idname) +{ + gzgt->name = "2D View Backdrop Navigate"; + gzgt->idname = idname; + + gzgt->flag |= (WM_GIZMOGROUPTYPE_PERSISTENT | WM_GIZMOGROUPTYPE_SCALE | + WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL); + + gzgt->poll = WIDGETGROUP_navigate_backdrop_poll; + gzgt->setup = WIDGETGROUP_navigate_backdrop_setup; + gzgt->draw_prepare = WIDGETGROUP_navigate_draw_prepare; +} + +/** \} */ diff --git a/source/blender/editors/space_node/node_gizmo.cc b/source/blender/editors/space_node/node_gizmo.cc index 1239c642a51..642f6f24c3e 100644 --- a/source/blender/editors/space_node/node_gizmo.cc +++ b/source/blender/editors/space_node/node_gizmo.cc @@ -626,4 +626,26 @@ void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Navigate + * \{ */ + +void NODE_GGT_navigate(wmGizmoGroupType *gzgt) +{ + VIEW2D_GGT_navigate_impl(gzgt, "NODE_GGT_navigate"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Compositor backdrop navigate + * \{ */ + +void VIEW2D_GGT_navigate_backdrop(wmGizmoGroupType *gzgt) +{ + VIEW2D_GGT_navigate_backdrop_impl(gzgt, "VIEW2D_GGT_navigate_backdrop"); +} + +/** \} */ + } // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index b2209884079..f039c4f095f 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -400,6 +400,8 @@ void NODE_GGT_backdrop_transform(wmGizmoGroupType *gzgt); void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt); void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt); void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt); +void NODE_GGT_navigate(wmGizmoGroupType *gzgt); +void VIEW2D_GGT_navigate_backdrop(wmGizmoGroupType *gzgt); /* `node_geometry_attribute_search.cc` */ diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc index fe66eb64870..6d5b8047ca5 100644 --- a/source/blender/editors/space_node/node_view.cc +++ b/source/blender/editors/space_node/node_view.cc @@ -10,6 +10,7 @@ #include "BLI_rect.h" #include "BLI_string_ref.hh" +#include "BLI_time.h" #include "BLI_utildefines.h" #include "BKE_context.hh" @@ -330,20 +331,174 @@ void NODE_OT_backimage_move(wmOperatorType *ot) /** \name Background Image Zoom * \{ */ -static int backimage_zoom_exec(bContext *C, wmOperator *op) +static void snode_zoom_set( + SpaceNode *snode, ARegion *region, float zoom, const int width, const int height) { - SpaceNode *snode = CTX_wm_space_node(C); - ARegion *region = CTX_wm_region(C); - float fac = RNA_float_get(op->ptr, "factor"); + float oldzoom = snode->zoom; + snode->zoom = zoom; - snode->zoom *= fac; - ED_region_tag_redraw(region); - WM_main_add_notifier(NC_NODE | ND_DISPLAY, nullptr); - WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, nullptr); + if (snode->zoom < 0.1f || snode->zoom > 4.0f) { - return OPERATOR_FINISHED; + /* Multiply with width and height to get the same zoom speed for all image sizes. */ + int width_fac = width * snode->zoom; + int height_fac = height * snode->zoom; + + if ((width_fac < 4) && (height_fac < 4) && snode->zoom < oldzoom) { + snode->zoom = oldzoom; + } + else if (BLI_rcti_size_x(®ion->winrct) <= snode->zoom) { + snode->zoom = oldzoom; + } + else if (BLI_rcti_size_y(®ion->winrct) <= snode->zoom) { + snode->zoom = oldzoom; + } + } } +struct ViewZoomData { + float origx, origy; + float zoom; + int launch_event; + float location[2]; + + /* Needed for continuous zoom. */ + wmTimer *timer; + double timer_lastdraw; + bool own_cursor; + + SpaceNode *snode; + ARegion *region; +}; + +static void snode_bg_viewzoom_init(bContext *C, wmOperator *op, const wmEvent *event) +{ + wmWindow *win = CTX_wm_window(C); + SpaceNode *snode = CTX_wm_space_node(C); + ARegion *region = CTX_wm_region(C); + ViewZoomData *vpd; + + op->customdata = vpd = static_cast( + MEM_callocN(sizeof(ViewZoomData), "ImageViewZoomData")); + + /* Grab will be set when running from gizmo. */ + vpd->own_cursor = (win->grabcursor == 0); + if (vpd->own_cursor) { + WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL); + } + + vpd->origx = event->xy[0]; + vpd->origy = event->xy[1]; + vpd->zoom = snode->zoom; + + vpd->launch_event = WM_userdef_event_type_from_keymap_type(event->type); + + if (U.viewzoom == USER_ZOOM_CONTINUE) { + /* needs a timer to continue redrawing */ + vpd->timer = WM_event_timer_add(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); + vpd->timer_lastdraw = BLI_time_now_seconds(); + } + + vpd->snode = snode; + vpd->region = region; + + WM_event_add_modal_handler(C, op); +} + +static int snode_bg_viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + snode_bg_viewzoom_init(C, op, event); + return OPERATOR_RUNNING_MODAL; +} + +static void snode_bg_viewzoom_apply( + ViewZoomData *vpd, wmOperator *op, const int x, const int y, const int width, const int height) +{ + float delta, factor; + + delta = x - vpd->origx + y - vpd->origy; + delta /= U.pixelsize; + + factor = 1.0f + delta / 300.0f; + + RNA_float_set(op->ptr, "factor", factor); + snode_zoom_set(vpd->snode, vpd->region, vpd->zoom * factor, width, height); + ED_region_tag_redraw(vpd->region); + WM_main_add_notifier(NC_NODE | ND_DISPLAY, nullptr); + WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, nullptr); +} + +enum { + VIEW_PASS = 0, + VIEW_APPLY, + VIEW_CONFIRM, +}; + +static void snode_bg_viewzoom_exit(bContext *C, wmOperator *op, bool cancel) +{ + SpaceNode *snode = CTX_wm_space_node(C); + ViewZoomData *vpd = static_cast(op->customdata); + + if (cancel) { + snode->zoom = vpd->zoom; + ED_region_tag_redraw(CTX_wm_region(C)); + } + + if (vpd->timer) { + WM_event_timer_remove(CTX_wm_manager(C), vpd->timer->win, vpd->timer); + } + + if (vpd->own_cursor) { + WM_cursor_modal_restore(CTX_wm_window(C)); + } + MEM_freeN(op->customdata); +} + +static int snode_bg_viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + Main *bmain = CTX_data_main(C); + + ViewZoomData *vpd = static_cast(op->customdata); + short event_code = VIEW_PASS; + int ret = OPERATOR_RUNNING_MODAL; + + /* Execute the events. */ + if (event->type == MOUSEMOVE) { + event_code = VIEW_APPLY; + } + else if (event->type == TIMER) { + /* Continuous zoom. */ + if (event->customdata == vpd->timer) { + event_code = VIEW_APPLY; + } + } + else if (event->type == vpd->launch_event) { + if (event->val == KM_RELEASE) { + event_code = VIEW_CONFIRM; + } + } + + int width, height; + ED_space_node_get_backdrop_size(bmain, &width, &height); + + switch (event_code) { + case VIEW_APPLY: { + snode_bg_viewzoom_apply(vpd, op, event->xy[0], event->xy[1], width, height); + break; + } + case VIEW_CONFIRM: { + ret = OPERATOR_FINISHED; + break; + } + } + + if ((ret & OPERATOR_RUNNING_MODAL) == 0) { + snode_bg_viewzoom_exit(C, op, false); + } + + return ret; +} + +/* Similar in functionality to IMAGE_OT_view_zoom. */ void NODE_OT_backimage_zoom(wmOperatorType *ot) { @@ -353,11 +508,12 @@ void NODE_OT_backimage_zoom(wmOperatorType *ot) ot->description = "Zoom in/out the background image"; /* api callbacks */ - ot->exec = backimage_zoom_exec; ot->poll = space_node_composite_active_view_poll; + ot->invoke = snode_bg_viewzoom_invoke; + ot->modal = snode_bg_viewzoom_modal; /* flags */ - ot->flag = OPTYPE_BLOCKING; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_LOCK_BYPASS; /* internal */ RNA_def_float(ot->srna, "factor", 1.2f, 0.0f, 10.0f, "Factor", "", 0.0f, 10.0f); @@ -548,6 +704,26 @@ bool ED_space_node_color_sample( return ret; } +void ED_space_node_get_backdrop_size(Main *bmain, int *r_width, int *r_height) +{ + Image *ima; + ImBuf *ibuf; + + void *lock; + + ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); + ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); + + if (ibuf == nullptr) { + BKE_image_release_ibuf(ima, ibuf, lock); + return; + } + + BKE_image_release_ibuf(ima, ibuf, lock); + *r_width = ibuf->x; + *r_height = ibuf->y; +} + namespace blender::ed::space_node { static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event) diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index ea02b268bf9..f9260d99e1f 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -1137,6 +1137,8 @@ static void node_widgets() WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_crop); WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_sun_beams); WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_corner_pin); + WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_navigate); + WM_gizmogrouptype_append_and_link(gzmap_type, VIEW2D_GGT_navigate_backdrop); } static void node_id_remap(ID *old_id, ID *new_id, SpaceNode *snode) diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index d03a50a7197..06bf1d94115 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1627,6 +1627,9 @@ typedef struct SpaceNode { /** Grease-pencil data. */ struct bGPdata *gpd; + char gizmo_flag; + char _pad2[7]; + SpaceNodeOverlay overlay; SpaceNode_Runtime *runtime; @@ -1649,6 +1652,13 @@ typedef enum eSpaceNode_Flag { SNODE_FLAG_UNUSED_12 = (1 << 13), } eSpaceNode_Flag; +/** #SpaceNode.gizmo_flag */ +enum { + /** All gizmos. */ + SNODE_GIZMO_HIDE = (1 << 0), + SNODE_GIZMO_HIDE_NAVIGATE = (1 << 1), +}; + /** #SpaceNode.texfrom */ typedef enum eSpaceNode_TexFrom { /* SNODE_TEX_OBJECT = 0, */ diff --git a/source/blender/makesrna/intern/rna_space.cc b/source/blender/makesrna/intern/rna_space.cc index 16daae47fd5..4bd0c5e9dc2 100644 --- a/source/blender/makesrna/intern/rna_space.cc +++ b/source/blender/makesrna/intern/rna_space.cc @@ -7810,6 +7810,17 @@ static void rna_def_space_node(BlenderRNA *brna) prop, "Auto-offset Direction", "Direction to offset nodes on insertion"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, nullptr); + /* Gizmo Toggles. */ + prop = RNA_def_property(srna, "show_gizmo", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, nullptr, "gizmo_flag", SNODE_GIZMO_HIDE); + RNA_def_property_ui_text(prop, "Show Gizmo", "Show gizmos of all types"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, nullptr); + + prop = RNA_def_property(srna, "show_gizmo_navigate", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, nullptr, "gizmo_flag", SNODE_GIZMO_HIDE_NAVIGATE); + RNA_def_property_ui_text(prop, "Navigate Gizmo", "Viewport navigation gizmo"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, nullptr); + /* Overlays */ prop = RNA_def_property(srna, "overlay", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL);