Fix: Remove duplicate image_add operators in the 3D view port

As part of #118623, we discovered that the operator used for adding images in the 3D viewport was not the same when drag and dropping as when adding it from the add menu. This lead to different and potentially confusing behaviour for the user when they use both.

This patch removes the python operator and unifies the functionality into one operator. It also renames the operator to be in line with the other "Add X" object operators.

Pull Request: https://projects.blender.org/blender/blender/pulls/118973
This commit is contained in:
Sebastian Parborg 2024-03-11 16:18:25 +01:00 committed by Sebastian Parborg
parent deb332601c
commit 013cd3d1ba
10 changed files with 153 additions and 180 deletions

@ -904,81 +904,6 @@ class DupliOffsetFromObject(Operator):
return {'FINISHED'}
class LoadImageAsEmpty:
bl_options = {'REGISTER', 'UNDO'}
filepath: StringProperty(
subtype='FILE_PATH'
)
filter_image: BoolProperty(default=True, options={'HIDDEN', 'SKIP_SAVE'})
filter_movie: BoolProperty(default=True, options={'HIDDEN', 'SKIP_SAVE'})
filter_folder: BoolProperty(default=True, options={'HIDDEN', 'SKIP_SAVE'})
view_align: BoolProperty(
name="Align to View",
default=True,
)
@classmethod
def poll(cls, context):
return context.mode == 'OBJECT'
def invoke(self, context, _event):
context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
def execute(self, context):
scene = context.scene
cursor = scene.cursor.location
try:
image = bpy.data.images.load(self.filepath, check_existing=True)
except RuntimeError as ex:
self.report({'ERROR'}, str(ex))
return {'CANCELLED'}
bpy.ops.object.empty_add(
'INVOKE_REGION_WIN',
type='IMAGE',
location=cursor,
align=('VIEW' if self.view_align else 'WORLD'),
)
view_layer = context.view_layer
obj = view_layer.objects.active
obj.data = image
obj.empty_display_size = 5.0
self.set_settings(context, obj)
return {'FINISHED'}
def set_settings(self, context, obj):
pass
class LoadBackgroundImage(LoadImageAsEmpty, Operator):
"""Add a reference image into the background behind objects"""
bl_idname = "object.load_background_image"
bl_label = "Load Background Image"
def set_settings(self, context, obj):
obj.empty_image_depth = 'BACK'
obj.empty_image_side = 'FRONT'
if context.space_data.type == 'VIEW_3D':
if not context.space_data.region_3d.is_perspective:
obj.show_empty_image_perspective = False
class LoadReferenceImage(LoadImageAsEmpty, Operator):
"""Add a reference image into the scene between objects"""
bl_idname = "object.load_reference_image"
bl_label = "Load Reference Image"
def set_settings(self, context, obj):
pass
class OBJECT_OT_assign_property_defaults(Operator):
"""Assign the current values of custom properties as their defaults, """ \
"""for use as part of the rest pose state in NLA track mixing"""
@ -1030,8 +955,6 @@ classes = (
DupliOffsetFromObject,
IsolateTypeRender,
JoinUVs,
LoadBackgroundImage,
LoadReferenceImage,
MakeDupliFace,
SelectCamera,
SelectHierarchy,

@ -307,7 +307,7 @@ class DATA_PT_camera_background_image(CameraButtonsPanel, Panel):
use_multiview = context.scene.render.use_multiview
col = layout.column()
col.operator("view3d.background_image_add", text="Add Image")
col.operator("view3d.camera_background_image_add", text="Add Image")
for i, bg in enumerate(cam.background_images):
layout.active = cam.show_background_images
@ -331,7 +331,7 @@ class DATA_PT_camera_background_image(CameraButtonsPanel, Panel):
icon='RESTRICT_VIEW_OFF' if bg.show_background_image else 'RESTRICT_VIEW_ON',
)
row.operator("view3d.background_image_remove", text="", emboss=False, icon='X').index = i
row.operator("view3d.camera_background_image_remove", text="", emboss=False, icon='X').index = i
if bg.show_expanded:
row = box.row()

@ -2671,8 +2671,10 @@ class VIEW3D_MT_image_add(Menu):
def draw(self, _context):
layout = self.layout
layout.operator("object.load_reference_image", text="Reference", icon='IMAGE_REFERENCE')
layout.operator("object.load_background_image", text="Background", icon='IMAGE_BACKGROUND')
# Expliclitly set background mode on/off as operator will try to
# auto detect which mode to use otherwise.
layout.operator("object.empty_image_add", text="Reference", icon='IMAGE_REFERENCE').background = False
layout.operator("object.empty_image_add", text="Background", icon='IMAGE_BACKGROUND').background = True
class VIEW3D_MT_object_relations(Menu):

@ -222,7 +222,7 @@ static void object_add_drop_xy_props(wmOperatorType *ot)
"X-coordinate (screen space) to place the new object under",
INT_MIN,
INT_MAX);
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE));
prop = RNA_def_int(ot->srna,
"drop_y",
0,
@ -232,7 +232,7 @@ static void object_add_drop_xy_props(wmOperatorType *ot)
"Y-coordinate (screen space) to place the new object under",
INT_MIN,
INT_MAX);
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE));
}
static bool object_add_drop_xy_is_set(const wmOperator *op)
@ -418,7 +418,7 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
false,
"Enter Edit Mode",
"Enter edit mode when adding this object");
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE));
}
/* NOTE: this property gets hidden for add-camera operator. */
prop = RNA_def_enum(
@ -458,7 +458,7 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
"Scale for the newly added object",
-1000.0f,
1000.0f);
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE));
}
void ED_object_add_mesh_props(wmOperatorType *ot)
@ -1234,10 +1234,82 @@ void OBJECT_OT_empty_add(wmOperatorType *ot)
ED_object_add_generic_props(ot, false);
}
static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int object_image_add_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Image *ima = nullptr;
ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
if (!ima) {
return OPERATOR_CANCELLED;
}
/* add new empty */
ushort local_view_bits;
float loc[3], rot[3];
if (!ED_object_add_generic_get_opts(
C, op, 'Z', loc, rot, nullptr, nullptr, &local_view_bits, nullptr))
{
return OPERATOR_CANCELLED;
}
Object *ob = ED_object_add_type(C, OB_EMPTY, nullptr, loc, rot, false, local_view_bits);
ob->empty_drawsize = 5.0f;
if (RNA_boolean_get(op->ptr, "background")) {
/* "background" has been set to "true", set image to render in the background. */
ob->empty_image_depth = OB_EMPTY_IMAGE_DEPTH_BACK;
ob->empty_image_visibility_flag = OB_EMPTY_IMAGE_HIDE_BACK;
RegionView3D *rv3d = CTX_wm_region_view3d(C);
if (rv3d->persp != RV3D_PERSP) {
ob->empty_image_visibility_flag |= OB_EMPTY_IMAGE_HIDE_PERSPECTIVE;
}
}
BKE_object_empty_draw_type_set(ob, OB_EMPTY_IMAGE);
ob->data = ima;
return OPERATOR_FINISHED;
}
static int object_image_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
if (!RNA_struct_property_is_set(op->ptr, "align")) {
/* Default to Aligned unless something else was explicitly passed */
RNA_enum_set(op->ptr, "align", ALIGN_VIEW);
}
/* Check if the user has not specified the image to load.
* If they have not, assume this is a drag an drop operation.
*/
if (!RNA_struct_property_is_set(op->ptr, "filepath") &&
!WM_operator_properties_id_lookup_is_set(op->ptr))
{
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
}
if (!RNA_struct_property_is_set(op->ptr, "background")) {
/* Check if we should switch to "background" mode. */
RegionView3D *rv3d = CTX_wm_region_view3d(C);
if (rv3d->persp != RV3D_PERSP) {
RNA_boolean_set(op->ptr, "background", true);
}
}
float loc[3];
ED_object_location_from_view(C, loc);
ED_view3d_cursor3d_position(C, event->mval, false, loc);
RNA_float_set_array(op->ptr, "location", loc);
Object *ob_cursor = ED_view3d_give_object_under_cursor(C, event->mval);
/* Either change empty under cursor or create a new empty */
if (!ob_cursor || ob_cursor->type != OB_EMPTY) {
return object_image_add_exec(C, op);
}
/* User dropped an image on an existing image */
Image *ima = nullptr;
ima = (Image *)WM_operator_drop_load_path(C, op, ID_IM);
@ -1247,71 +1319,56 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
/* handled below */
id_us_min(&ima->id);
Object *ob = nullptr;
Object *ob_cursor = ED_view3d_give_object_under_cursor(C, event->mval);
Scene *scene = CTX_data_scene(C);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
DEG_id_tag_update((ID *)ob_cursor, ID_RECALC_TRANSFORM);
/* either change empty under cursor or create a new empty */
if (ob_cursor && ob_cursor->type == OB_EMPTY) {
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
DEG_id_tag_update((ID *)ob_cursor, ID_RECALC_TRANSFORM);
ob = ob_cursor;
}
else {
/* add new empty */
ushort local_view_bits;
float rot[3];
if (!ED_object_add_generic_get_opts(
C, op, 'Z', nullptr, rot, nullptr, nullptr, &local_view_bits, nullptr))
{
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_EMPTY, nullptr, nullptr, rot, false, local_view_bits);
ED_object_location_from_view(C, ob->loc);
ED_view3d_cursor3d_position(C, event->mval, false, ob->loc);
ED_object_rotation_from_view(C, ob->rot, 'Z');
ob->empty_drawsize = 5.0f;
}
BKE_object_empty_draw_type_set(ob, OB_EMPTY_IMAGE);
id_us_min(static_cast<ID *>(ob->data));
ob->data = ima;
id_us_plus(static_cast<ID *>(ob->data));
BKE_object_empty_draw_type_set(ob_cursor, OB_EMPTY_IMAGE);
id_us_min(static_cast<ID *>(ob_cursor->data));
ob_cursor->data = ima;
id_us_plus(static_cast<ID *>(ob_cursor->data));
return OPERATOR_FINISHED;
}
void OBJECT_OT_drop_named_image(wmOperatorType *ot)
void OBJECT_OT_empty_image_add(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Add Empty Image/Drop Image to Empty";
ot->description = "Add an empty image type to scene with data";
ot->idname = "OBJECT_OT_drop_named_image";
ot->idname = "OBJECT_OT_empty_image_add";
/* api callbacks */
ot->invoke = empty_drop_named_image_invoke;
ot->invoke = object_image_add_invoke;
ot->exec = object_image_add_exec;
ot->poll = ED_operator_objectmode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
prop = RNA_def_string(ot->srna, "filepath", nullptr, FILE_MAX, "Filepath", "Path to image file");
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
RNA_def_boolean(ot->srna,
"relative_path",
true,
"Relative Path",
"Select the file relative to the blend file");
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
WM_operator_properties_id_lookup(ot, true);
ED_object_add_generic_props(ot, false);
PropertyRNA *prop;
prop = RNA_def_boolean(ot->srna,
"background",
false,
"Put in Background",
"Make the image render behind all objects");
RNA_def_property_flag(prop, PropertyFlag(PROP_SKIP_SAVE));
/* Hide the filepath and relative path prop */
prop = RNA_struct_type_find_property(ot->srna, "filepath");
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_PRESET));
prop = RNA_struct_type_find_property(ot->srna, "relative_path");
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN));
}
/** \} */
@ -2112,8 +2169,7 @@ void OBJECT_OT_collection_external_asset_drop(wmOperatorType *ot)
prop = RNA_def_enum(ot->srna, "collection", rna_enum_dummy_NULL_items, 0, "Collection", "");
RNA_def_enum_funcs(prop, RNA_collection_itemf);
RNA_def_property_flag(prop,
(PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE));
RNA_def_property_flag(prop, PropertyFlag(PROP_SKIP_SAVE | PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE));
ot->prop = prop;
}
@ -2574,7 +2630,7 @@ void OBJECT_OT_delete(wmOperatorType *ot)
PropertyRNA *prop;
prop = RNA_def_boolean(
ot->srna, "use_global", false, "Delete Globally", "Remove object from all scenes");
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE));
WM_operator_properties_confirm_or_exec(ot);
}
@ -4218,7 +4274,7 @@ void OBJECT_OT_add_named(wmOperatorType *ot)
prop = RNA_def_float_matrix(
ot->srna, "matrix", 4, 4, nullptr, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE));
object_add_drop_xy_props(ot);
}
@ -4325,7 +4381,7 @@ void OBJECT_OT_transform_to_mouse(wmOperatorType *ot)
MAX_ID_NAME - 2,
"Name",
"Object name to place (uses the active object when this and 'session_uid' are unset)");
RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
RNA_def_property_flag(prop, PropertyFlag(PROP_SKIP_SAVE | PROP_HIDDEN));
prop = RNA_def_int(ot->srna,
"session_uid",
0,
@ -4336,11 +4392,11 @@ void OBJECT_OT_transform_to_mouse(wmOperatorType *ot)
"'name' are unset)",
INT32_MIN,
INT32_MAX);
RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN));
RNA_def_property_flag(prop, PropertyFlag(PROP_SKIP_SAVE | PROP_HIDDEN));
prop = RNA_def_float_matrix(
ot->srna, "matrix", 4, 4, nullptr, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE));
object_add_drop_xy_props(ot);
}

@ -118,7 +118,7 @@ void OBJECT_OT_text_add(struct wmOperatorType *ot);
void OBJECT_OT_armature_add(struct wmOperatorType *ot);
void OBJECT_OT_empty_add(struct wmOperatorType *ot);
void OBJECT_OT_lightprobe_add(struct wmOperatorType *ot);
void OBJECT_OT_drop_named_image(struct wmOperatorType *ot);
void OBJECT_OT_empty_image_add(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_add(struct wmOperatorType *ot);
void OBJECT_OT_grease_pencil_add(struct wmOperatorType *ot);
void OBJECT_OT_light_add(struct wmOperatorType *ot);

@ -91,7 +91,7 @@ void ED_operatortypes_object()
WM_operatortype_append(OBJECT_OT_armature_add);
WM_operatortype_append(OBJECT_OT_empty_add);
WM_operatortype_append(OBJECT_OT_lightprobe_add);
WM_operatortype_append(OBJECT_OT_drop_named_image);
WM_operatortype_append(OBJECT_OT_empty_image_add);
WM_operatortype_append(OBJECT_OT_gpencil_add);
WM_operatortype_append(OBJECT_OT_grease_pencil_add);
WM_operatortype_append(OBJECT_OT_light_add);

@ -969,13 +969,13 @@ static void view3d_dropboxes()
WM_drag_free_imported_drag_ID,
view3d_geometry_nodes_drop_tooltip);
WM_dropbox_add(lb,
"VIEW3D_OT_background_image_add",
"VIEW3D_OT_camera_background_image_add",
view3d_ima_bg_drop_poll,
view3d_id_path_drop_copy,
WM_drag_free_imported_drag_ID,
nullptr);
WM_dropbox_add(lb,
"OBJECT_OT_drop_named_image",
"OBJECT_OT_empty_image_add",
view3d_ima_empty_drop_poll,
view3d_id_path_drop_copy,
WM_drag_free_imported_drag_ID,

@ -562,15 +562,7 @@ static Camera *background_image_camera_from_context(bContext *C)
return static_cast<Camera *>(CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data);
}
static int background_image_add_exec(bContext *C, wmOperator * /*op*/)
{
Camera *cam = background_image_camera_from_context(C);
BKE_camera_background_image_new(cam);
return OPERATOR_FINISHED;
}
static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
static int camera_background_image_add_exec(bContext *C, wmOperator *op)
{
Camera *cam = background_image_camera_from_context(C);
Image *ima;
@ -590,37 +582,37 @@ static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEven
return OPERATOR_FINISHED;
}
static bool background_image_add_poll(bContext *C)
static bool camera_background_image_add_poll(bContext *C)
{
return background_image_camera_from_context(C) != nullptr;
}
void VIEW3D_OT_background_image_add(wmOperatorType *ot)
void VIEW3D_OT_camera_background_image_add(wmOperatorType *ot)
{
/* identifiers */
/* NOTE: having key shortcut here is bad practice,
* but for now keep because this displays when dragging an image over the 3D viewport */
ot->name = "Add Background Image";
ot->description = "Add a new background image";
ot->idname = "VIEW3D_OT_background_image_add";
ot->name = "Add Camera Background Image";
ot->description = "Add a new background image to the active camera";
ot->idname = "VIEW3D_OT_camera_background_image_add";
/* api callbacks */
ot->invoke = background_image_add_invoke;
ot->exec = background_image_add_exec;
ot->poll = background_image_add_poll;
ot->exec = camera_background_image_add_exec;
ot->poll = camera_background_image_add_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
/* properties */
PropertyRNA *prop = RNA_def_string(
ot->srna, "filepath", nullptr, FILE_MAX, "Filepath", "Path to image file");
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE));
prop = RNA_def_boolean(ot->srna,
"relative_path",
true,
"Relative Path",
"Select the file relative to the blend file");
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE));
WM_operator_properties_id_lookup(ot, true);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
}
/** \} */
@ -629,7 +621,7 @@ void VIEW3D_OT_background_image_add(wmOperatorType *ot)
/** \name Background Image Remove Operator
* \{ */
static int background_image_remove_exec(bContext *C, wmOperator *op)
static int camera_background_image_remove_exec(bContext *C, wmOperator *op)
{
Camera *cam = static_cast<Camera *>(CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data);
const int index = RNA_int_get(op->ptr, "index");
@ -661,15 +653,15 @@ static int background_image_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
void VIEW3D_OT_background_image_remove(wmOperatorType *ot)
void VIEW3D_OT_camera_background_image_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Background Image";
ot->description = "Remove a background image from the 3D view";
ot->idname = "VIEW3D_OT_background_image_remove";
ot->name = "Remove Camera Background Image";
ot->description = "Remove a background image from the camera";
ot->idname = "VIEW3D_OT_camera_background_image_remove";
/* api callbacks */
ot->exec = background_image_remove_exec;
ot->exec = camera_background_image_remove_exec;
ot->poll = ED_operator_camera_poll;
/* flags */

@ -52,8 +52,8 @@ void VIEW3D_OT_view_center_camera(struct wmOperatorType *ot);
void VIEW3D_OT_view_center_lock(struct wmOperatorType *ot);
void VIEW3D_OT_view_persportho(struct wmOperatorType *ot);
void VIEW3D_OT_navigate(struct wmOperatorType *ot);
void VIEW3D_OT_background_image_add(struct wmOperatorType *ot);
void VIEW3D_OT_background_image_remove(struct wmOperatorType *ot);
void VIEW3D_OT_camera_background_image_add(struct wmOperatorType *ot);
void VIEW3D_OT_camera_background_image_remove(struct wmOperatorType *ot);
void VIEW3D_OT_drop_world(struct wmOperatorType *ot);
void VIEW3D_OT_clip_border(struct wmOperatorType *ot);
void VIEW3D_OT_cursor3d(struct wmOperatorType *ot);

@ -174,8 +174,8 @@ void view3d_operatortypes()
WM_operatortype_append(VIEW3D_OT_view_roll);
WM_operatortype_append(VIEW3D_OT_view_pan);
WM_operatortype_append(VIEW3D_OT_view_persportho);
WM_operatortype_append(VIEW3D_OT_background_image_add);
WM_operatortype_append(VIEW3D_OT_background_image_remove);
WM_operatortype_append(VIEW3D_OT_camera_background_image_add);
WM_operatortype_append(VIEW3D_OT_camera_background_image_remove);
WM_operatortype_append(VIEW3D_OT_drop_world);
WM_operatortype_append(VIEW3D_OT_view_selected);
WM_operatortype_append(VIEW3D_OT_view_lock_clear);