Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Mon, 2 Jul 2018 10:03:56 +0000 (12:03 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 2 Jul 2018 10:03:56 +0000 (12:03 +0200)
166 files changed:
1  2 
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/BKE_screen.h
source/blender/blenkernel/intern/node.c
source/blender/editors/animation/anim_channels_edit.c
source/blender/editors/animation/anim_markers.c
source/blender/editors/animation/anim_ops.c
source/blender/editors/animation/drivers.c
source/blender/editors/animation/keyframing.c
source/blender/editors/animation/keyingsets.c
source/blender/editors/armature/armature_select.c
source/blender/editors/armature/pose_edit.c
source/blender/editors/armature/pose_lib.c
source/blender/editors/armature/pose_select.c
source/blender/editors/curve/editcurve.c
source/blender/editors/gpencil/gpencil_brush.c
source/blender/editors/gpencil/gpencil_convert.c
source/blender/editors/gpencil/gpencil_edit.c
source/blender/editors/gpencil/gpencil_intern.h
source/blender/editors/gpencil/gpencil_interpolate.c
source/blender/editors/gpencil/gpencil_ops.c
source/blender/editors/gpencil/gpencil_paint.c
source/blender/editors/gpencil/gpencil_utils.c
source/blender/editors/include/ED_image.h
source/blender/editors/include/ED_keyframing.h
source/blender/editors/include/ED_outliner.h
source/blender/editors/include/ED_screen.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/include/UI_interface.h
source/blender/editors/interface/interface_eyedropper_color.c
source/blender/editors/interface/interface_eyedropper_datablock.c
source/blender/editors/interface/interface_eyedropper_depth.c
source/blender/editors/interface/interface_eyedropper_driver.c
source/blender/editors/interface/interface_ops.c
source/blender/editors/interface/interface_region_hud.c
source/blender/editors/interface/view2d_ops.c
source/blender/editors/lattice/editlattice_tools.c
source/blender/editors/mask/mask_edit.c
source/blender/editors/mask/mask_ops.c
source/blender/editors/mesh/editmesh_select.c
source/blender/editors/mesh/editmesh_utils.c
source/blender/editors/mesh/mesh_data.c
source/blender/editors/mesh/mesh_intern.h
source/blender/editors/object/object_add.c
source/blender/editors/object/object_constraint.c
source/blender/editors/object/object_data_transfer.c
source/blender/editors/object/object_edit.c
source/blender/editors/object/object_facemap_ops.c
source/blender/editors/object/object_hook.c
source/blender/editors/object/object_intern.h
source/blender/editors/object/object_modifier.c
source/blender/editors/object/object_ops.c
source/blender/editors/object/object_relations.c
source/blender/editors/object/object_select.c
source/blender/editors/object/object_shapekey.c
source/blender/editors/object/object_vgroup.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/physics/particle_object.c
source/blender/editors/physics/physics_pointcache.c
source/blender/editors/physics/rigidbody_constraint.c
source/blender/editors/physics/rigidbody_object.c
source/blender/editors/physics/rigidbody_world.c
source/blender/editors/render/render_shading.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/screen/screendump.c
source/blender/editors/screen/workspace_edit.c
source/blender/editors/sculpt_paint/paint_cursor.c
source/blender/editors/sculpt_paint/paint_curve.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_image_proj.c
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/paint_ops.c
source/blender/editors/sculpt_paint/paint_stroke.c
source/blender/editors/sculpt_paint/paint_utils.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/sculpt_paint/sculpt_intern.h
source/blender/editors/sculpt_paint/sculpt_uv.c
source/blender/editors/sound/sound_ops.c
source/blender/editors/space_action/action_edit.c
source/blender/editors/space_clip/clip_editor.c
source/blender/editors/space_clip/clip_graph_ops.c
source/blender/editors/space_clip/clip_ops.c
source/blender/editors/space_clip/clip_toolbar.c
source/blender/editors/space_clip/space_clip.c
source/blender/editors/space_clip/tracking_ops.c
source/blender/editors/space_clip/tracking_ops_orient.c
source/blender/editors/space_clip/tracking_ops_stabilize.c
source/blender/editors/space_console/space_console.c
source/blender/editors/space_file/file_ops.c
source/blender/editors/space_file/file_panels.c
source/blender/editors/space_file/space_file.c
source/blender/editors/space_graph/graph_buttons.c
source/blender/editors/space_graph/graph_edit.c
source/blender/editors/space_graph/graph_ops.c
source/blender/editors/space_graph/graph_utils.c
source/blender/editors/space_image/image_edit.c
source/blender/editors/space_image/image_intern.h
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_nla/nla_buttons.c
source/blender/editors/space_nla/nla_channels.c
source/blender/editors/space_nla/nla_ops.c
source/blender/editors/space_node/node_add.c
source/blender/editors/space_node/node_buttons.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_node/node_intern.h
source/blender/editors/space_node/space_node.c
source/blender/editors/space_outliner/outliner_collections.c
source/blender/editors/space_outliner/outliner_edit.c
source/blender/editors/space_outliner/outliner_ops.c
source/blender/editors/space_outliner/space_outliner.c
source/blender/editors/space_sequencer/sequencer_edit.c
source/blender/editors/space_sequencer/sequencer_intern.h
source/blender/editors/space_sequencer/sequencer_view.c
source/blender/editors/space_sequencer/space_sequencer.c
source/blender/editors/space_text/space_text.c
source/blender/editors/space_text/text_header.c
source/blender/editors/space_text/text_ops.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_buttons.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/space_view3d/view3d_manipulator_ruler.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform_ops.c
source/blender/editors/undo/ed_undo.c
source/blender/editors/util/ed_transverts.c
source/blender/editors/uvedit/uvedit_buttons.c
source/blender/editors/uvedit/uvedit_ops.c
source/blender/editors/uvedit/uvedit_unwrap_ops.c
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/RNA_enum_types.h
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_action.c
source/blender/makesrna/intern/rna_animation.c
source/blender/makesrna/intern/rna_constraint.c
source/blender/makesrna/intern/rna_curve.c
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_internal_types.h
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_nodetree.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_sculpt_paint.c
source/blender/makesrna/intern/rna_sequencer.c
source/blender/makesrna/intern/rna_space.c
source/blender/makesrna/intern/rna_ui.c
source/blender/makesrna/intern/rna_wm.c
source/blender/nodes/composite/nodes/node_composite_image.c
source/blender/nodes/shader/node_shader_tree.c
source/blender/nodes/shader/node_shader_util.c
source/blender/nodes/shader/node_shader_util.h
source/blender/nodes/texture/node_texture_util.c
source/blender/nodes/texture/node_texture_util.h
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm_dragdrop.c
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_files.c
source/blender/windowmanager/intern/wm_files_link.c
source/blender/windowmanager/intern/wm_operators.c
source/blender/windowmanager/wm.h

Simple merge
index d2c2f9a254f2394bd981c8c6bd7066b91f1ed673,b33b9e455f105c35c32f04af0aae08c093c36011..b6ddb8f57beb19c398e54bc43e33203644ecfe12
@@@ -210,11 -185,9 +210,11 @@@ typedef struct PanelType 
        int flag;
  
        /* verify if the panel should draw or not */
-       int (*poll)(const struct bContext *C, struct PanelType *pt);
+       bool (*poll)(const struct bContext *C, struct PanelType *pt);
        /* draw header (optional) */
        void (*draw_header)(const struct bContext *C, struct Panel *pa);
 +      /* draw header preset (optional) */
 +      void (*draw_header_preset)(const struct bContext *C, struct Panel *pa);
        /* draw entirely, view changes should be handled here */
        void (*draw)(const struct bContext *C, struct Panel *pa);
  
index 4402ca78976dc68fe5ecf55b0662c6dedd5f2e63,8612f5944bb6c4cf9ae370e683b9fdb06c5855ec..5f6b299c617f178faf756bba786c09c4660dacbe
@@@ -276,116 -276,6 +276,116 @@@ static void ANIM_OT_change_frame(wmOper
        RNA_def_property_flag(prop, PROP_SKIP_SAVE);
  }
  
- static int anim_set_end_frames_poll(bContext *C)
 +
 +/* ****************** Start/End Frame Operators *******************************/
 +
++static bool anim_set_end_frames_poll(bContext *C)
 +{
 +      ScrArea *sa = CTX_wm_area(C);
 +
 +      /* XXX temp? prevent changes during render */
 +      if (G.is_rendering) return false;
 +
 +      /* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION,
 +       * this shouldn't show up in 3D editor (or others without 2D timeline view) via search
 +       */
 +      if (sa) {
 +              if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
 +                      return true;
 +              }
 +      }
 +
 +      CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active");
 +      return false;
 +}
 +
 +static int anim_set_sfra_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      int frame;
 +
 +      if (scene == NULL)
 +              return OPERATOR_CANCELLED;
 +
 +      frame = CFRA;
 +
 +      /* if Preview Range is defined, set the 'start' frame for that */
 +      if (PRVRANGEON)
 +              scene->r.psfra = frame;
 +      else
 +              scene->r.sfra = frame;
 +
 +      if (PEFRA < frame) {
 +              if (PRVRANGEON)
 +                      scene->r.pefra = frame;
 +              else
 +                      scene->r.efra = frame;
 +      }
 +
 +      WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +static void ANIM_OT_start_frame_set(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Set Start Frame";
 +      ot->idname = "ANIM_OT_start_frame_set";
 +      ot->description = "Set the current frame as the preview or scene start frame";
 +
 +      /* api callbacks */
 +      ot->exec = anim_set_sfra_exec;
 +      ot->poll = anim_set_end_frames_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +
 +static int anim_set_efra_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      int frame;
 +
 +      if (scene == NULL)
 +              return OPERATOR_CANCELLED;
 +
 +      frame = CFRA;
 +
 +      /* if Preview Range is defined, set the 'end' frame for that */
 +      if (PRVRANGEON)
 +              scene->r.pefra = frame;
 +      else
 +              scene->r.efra = frame;
 +
 +      if (PSFRA > frame) {
 +              if (PRVRANGEON)
 +                      scene->r.psfra = frame;
 +              else
 +                      scene->r.sfra = frame;
 +      }
 +
 +      WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +static void ANIM_OT_end_frame_set(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Set End Frame";
 +      ot->idname = "ANIM_OT_end_frame_set";
 +      ot->description = "Set the current frame as the preview or scene end frame";
 +
 +      /* api callbacks */
 +      ot->exec = anim_set_efra_exec;
 +      ot->poll = anim_set_end_frames_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
  /* ****************** set preview range operator ****************************/
  
  static int previewrange_define_exec(bContext *C, wmOperator *op)
index f303be0dd769527008af926e7942bdb38f422907,3e4e3a551fe3ceec16f6a5f21acbbdf94d8c7266..99725c7da99e05922849fdb38c64874bb1d049eb
@@@ -817,9 -804,9 +817,9 @@@ static const EnumPropertyItem *driver_m
  }
  
  
 -/* Add Driver Button Operator ------------------------ */
 +/* Add Driver (With Menu) Button Operator ------------------------ */
  
- static int add_driver_button_poll(bContext *C)
+ static bool add_driver_button_poll(bContext *C)
  {
        PointerRNA ptr = {{NULL}};
        PropertyRNA *prop = NULL;
index b3775402a4b7d565d51858315d79026b09013402,389a8423f232dcbb629edd7368b458be01026c0c..661492ba05658e8b65f2ee698700351d6021b03a
@@@ -1248,35 -1215,3 +1248,35 @@@ void POSE_OT_quaternions_flip(wmOperato
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
  }
- static int pose_select_linked_poll(bContext *C)
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Toggle Bone selection Overlay Operator
 + * \{ */
 +
 +static int toggle_bone_selection_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      View3D *v3d = CTX_wm_view3d(C);
 +      v3d->overlay.flag ^= V3D_OVERLAY_BONE_SELECTION;
 +      ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C));
 +      WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
 +      return OPERATOR_FINISHED;
 +}
 +
++static bool pose_select_linked_poll(bContext *C)
 +{
 +      return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
 +}
 +
 +void POSE_OT_toggle_bone_selection_overlay(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Toggle Bone Selection Overlay";
 +      ot->description = "Toggle bone selection overlay of the viewport";
 +      ot->idname = "POSE_OT_toggle_bone_selection_overlay";
 +
 +      /* api callbacks */
 +      ot->exec = toggle_bone_selection_exec;
 +      ot->poll = pose_select_linked_poll;
 +}
 +
 +/** \} */
index ed9102a2d8bfd617d6c51ff28f4074466687e56f,e5631c4e1916b941584dfcf003aed217a97ff50c..f8af67b55ffceaaa7737fcc5cb3c5c1842698869
@@@ -75,9 -75,9 +75,9 @@@ bool ED_space_image_show_uvedit(struct 
  
  bool ED_space_image_paint_curve(const struct bContext *C);
  
 -bool ED_space_image_check_show_maskedit(struct Scene *scene, struct SpaceImage *sima);
 +bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct ViewLayer *view_layer);
int ED_space_image_maskedit_poll(struct bContext *C);
int ED_space_image_maskedit_mask_poll(struct bContext *C);
bool ED_space_image_maskedit_poll(struct bContext *C);
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
  
  void ED_image_draw_info(struct Scene *scene, struct ARegion *ar, bool color_manage, bool use_default_view, int channels, int x, int y,
                          const unsigned char cp[4], const float fp[4], const float linearcol[4], int *zp, float *zpf);
index c1b3c3e9e1c7ab5bd74924e84f01304a1bfb4994,73ee254224737b33fd5645fce96e17bd3bf161b5..52fdeb2045c1a5b0a44f4edfcec3960e7b1b1532
  #ifndef __ED_OUTLINER_H__
  #define __ED_OUTLINER_H__
  
- int ED_outliner_collections_editor_poll(struct bContext *C);
 +struct bContext;
 +struct ListBase;
 +
++bool ED_outliner_collections_editor_poll(struct bContext *C);
 +
 +void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects);
 +
  #endif /*  __ED_OUTLINER_H__ */
index 5ff58da735fa43ee499012c31432fb65c83e9dda,b4d9a2629cfedc6f7f3533b21528b16d8a04aa2b..0e335f89fb49c4954726ab86556585c60456cebb
@@@ -261,94 -133,64 +261,94 @@@ bScreen *ED_screen_animation_no_scrub(c
  /* screen keymaps */
  void    ED_operatortypes_screen(void);
  void    ED_keymap_screen(struct wmKeyConfig *keyconf);
 +/* workspace keymaps */
 +void    ED_operatortypes_workspace(void);
  
  /* operators; context poll callbacks */
int     ED_operator_screenactive(struct bContext *C);
int     ED_operator_screen_mainwinactive(struct bContext *C);
int     ED_operator_areaactive(struct bContext *C);
int     ED_operator_regionactive(struct bContext *C);
bool ED_operator_screenactive(struct bContext *C);
bool ED_operator_screen_mainwinactive(struct bContext *C);
bool ED_operator_areaactive(struct bContext *C);
bool ED_operator_regionactive(struct bContext *C);
  
int     ED_operator_scene(struct bContext *C);
int     ED_operator_scene_editable(struct bContext *C);
int     ED_operator_objectmode(struct bContext *C);
bool ED_operator_scene(struct bContext *C);
bool ED_operator_scene_editable(struct bContext *C);
bool ED_operator_objectmode(struct bContext *C);
  
- int     ED_operator_view3d_active(struct bContext *C);
- int     ED_operator_region_view3d_active(struct bContext *C);
- int     ED_operator_animview_active(struct bContext *C);
- int     ED_operator_outliner_active(struct bContext *C);
- int     ED_operator_outliner_active_no_editobject(struct bContext *C);
- int     ED_operator_file_active(struct bContext *C);
- int     ED_operator_action_active(struct bContext *C);
- int     ED_operator_buttons_active(struct bContext *C);
- int     ED_operator_node_active(struct bContext *C);
- int     ED_operator_node_editable(struct bContext *C);
- int     ED_operator_graphedit_active(struct bContext *C);
- int     ED_operator_sequencer_active(struct bContext *C);
- int     ED_operator_sequencer_active_editable(struct bContext *C);
- int     ED_operator_image_active(struct bContext *C);
- int     ED_operator_nla_active(struct bContext *C);
- int     ED_operator_info_active(struct bContext *C);
- int     ED_operator_console_active(struct bContext *C);
+ bool ED_operator_view3d_active(struct bContext *C);
+ bool ED_operator_region_view3d_active(struct bContext *C);
+ bool ED_operator_animview_active(struct bContext *C);
 -bool ED_operator_timeline_active(struct bContext *C);
+ bool ED_operator_outliner_active(struct bContext *C);
+ bool ED_operator_outliner_active_no_editobject(struct bContext *C);
+ bool ED_operator_file_active(struct bContext *C);
+ bool ED_operator_action_active(struct bContext *C);
+ bool ED_operator_buttons_active(struct bContext *C);
+ bool ED_operator_node_active(struct bContext *C);
+ bool ED_operator_node_editable(struct bContext *C);
+ bool ED_operator_graphedit_active(struct bContext *C);
+ bool ED_operator_sequencer_active(struct bContext *C);
+ bool ED_operator_sequencer_active_editable(struct bContext *C);
+ bool ED_operator_image_active(struct bContext *C);
+ bool ED_operator_nla_active(struct bContext *C);
 -bool ED_operator_logic_active(struct bContext *C);
+ bool ED_operator_info_active(struct bContext *C);
+ bool ED_operator_console_active(struct bContext *C);
  
  
- int     ED_operator_object_active(struct bContext *C);
- int     ED_operator_object_active_editable(struct bContext *C);
- int     ED_operator_object_active_editable_mesh(struct bContext *C);
- int     ED_operator_object_active_editable_font(struct bContext *C);
- int     ED_operator_editmesh(struct bContext *C);
- int     ED_operator_editmesh_view3d(struct bContext *C);
- int     ED_operator_editmesh_region_view3d(struct bContext *C);
- int     ED_operator_editarmature(struct bContext *C);
- int     ED_operator_editcurve(struct bContext *C);
- int     ED_operator_editcurve_3d(struct bContext *C);
- int     ED_operator_editsurf(struct bContext *C);
- int     ED_operator_editsurfcurve(struct bContext *C);
- int     ED_operator_editsurfcurve_region_view3d(struct bContext *C);
- int     ED_operator_editfont(struct bContext *C);
- int     ED_operator_editlattice(struct bContext *C);
- int     ED_operator_editmball(struct bContext *C);
- int     ED_operator_uvedit(struct bContext *C);
- int     ED_operator_uvedit_space_image(struct bContext *C);
- int     ED_operator_uvmap(struct bContext *C);
- int     ED_operator_posemode_exclusive(struct bContext *C);
- int     ED_operator_posemode_context(struct bContext *C);
- int     ED_operator_posemode(struct bContext *C);
- int     ED_operator_posemode_local(struct bContext *C);
- int     ED_operator_mask(struct bContext *C);
- int     ED_operator_camera(struct bContext *C);
+ bool ED_operator_object_active(struct bContext *C);
+ bool ED_operator_object_active_editable(struct bContext *C);
+ bool ED_operator_object_active_editable_mesh(struct bContext *C);
+ bool ED_operator_object_active_editable_font(struct bContext *C);
+ bool ED_operator_editmesh(struct bContext *C);
+ bool ED_operator_editmesh_view3d(struct bContext *C);
+ bool ED_operator_editmesh_region_view3d(struct bContext *C);
+ bool ED_operator_editarmature(struct bContext *C);
+ bool ED_operator_editcurve(struct bContext *C);
+ bool ED_operator_editcurve_3d(struct bContext *C);
+ bool ED_operator_editsurf(struct bContext *C);
+ bool ED_operator_editsurfcurve(struct bContext *C);
+ bool ED_operator_editsurfcurve_region_view3d(struct bContext *C);
+ bool ED_operator_editfont(struct bContext *C);
+ bool ED_operator_editlattice(struct bContext *C);
+ bool ED_operator_editmball(struct bContext *C);
+ bool ED_operator_uvedit(struct bContext *C);
+ bool ED_operator_uvedit_space_image(struct bContext *C);
+ bool ED_operator_uvmap(struct bContext *C);
+ bool ED_operator_posemode_exclusive(struct bContext *C);
+ bool ED_operator_posemode_context(struct bContext *C);
+ bool ED_operator_posemode(struct bContext *C);
+ bool ED_operator_posemode_local(struct bContext *C);
+ bool ED_operator_mask(struct bContext *C);
++bool ED_operator_camera(struct bContext *C);
 +
 +/* screen_user_menu.c */
 +
 +struct bUserMenu *ED_screen_user_menu_find(struct bContext *C);
 +struct bUserMenu *ED_screen_user_menu_ensure(struct bContext *C);
  
  
 +struct bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(
 +        struct ListBase *lb,
 +        const struct wmOperatorType *ot, struct IDProperty *prop, short opcontext);
 +struct bUserMenuItem_Menu *ED_screen_user_menu_item_find_menu(
 +        struct ListBase *lb,
 +        const struct MenuType *mt);
 +struct bUserMenuItem_Prop *ED_screen_user_menu_item_find_prop(
 +        struct ListBase *lb,
 +        const char *context_data_path, const char *prop_id, int prop_index);
 +
 +void ED_screen_user_menu_item_add_operator(
 +        struct ListBase *lb, const char *ui_name,
 +        const struct wmOperatorType *ot, const struct IDProperty *prop, short opcontext);
 +void ED_screen_user_menu_item_add_menu(
 +        struct ListBase *lb, const char *ui_name,
 +        const struct MenuType *mt);
 +void ED_screen_user_menu_item_add_prop(
 +        ListBase *lb, const char *ui_name,
 +        const char *context_data_path, const char *prop_id, int prop_index);
 +
 +void ED_screen_user_menu_item_remove(
 +        struct ListBase *lb, struct bUserMenuItem *umi);
 +void ED_screen_user_menu_register(void);
 +
  /* Cache display helpers */
  
  void ED_region_cache_draw_background(const struct ARegion *ar);
index 0f08f8c7ed98a7253d135b400fe74cfa10ca92d4,cd7d2e27d9a3222cedd90ae116644d9b8b7d1b01..3457d2e2eebf8aa10be7867a829a499775648cc2
@@@ -334,217 -328,6 +334,217 @@@ static void UI_OT_unset_property_button
        ot->flag = OPTYPE_UNDO;
  }
  
- static int override_type_set_button_poll(bContext *C)
 +
 +/* Note that we use different values for UI/UX than 'real' override operations, user does not care
 + * whether it's added or removed for the differential operation e.g. */
 +enum {
 +      UIOverride_Type_NOOP = 0,
 +      UIOverride_Type_Replace = 1,
 +      UIOverride_Type_Difference = 2,  /* Add/subtract */
 +      UIOverride_Type_Factor = 3,  /* Multiply */
 +      /* TODO: should/can we expose insert/remove ones for collections? Doubt it... */
 +};
 +
 +static EnumPropertyItem override_type_items[] = {
 +      {UIOverride_Type_NOOP, "NOOP", 0, "NoOp",
 +       "'No-Operation', place holder preventing automatic override to ever affect the property"},
 +      {UIOverride_Type_Replace, "REPLACE", 0, "Replace", "Completely replace value from linked data by local one"},
 +      {UIOverride_Type_Difference, "DIFFERENCE", 0, "Difference", "Store difference to linked data value"},
 +      {UIOverride_Type_Factor, "FACTOR", 0, "Factor", "Store factor to linked data value (useful e.g. for scale)"},
 +      {0, NULL, 0, NULL, NULL}
 +};
 +
 +
- static int override_remove_button_poll(bContext *C)
++static bool override_type_set_button_poll(bContext *C)
 +{
 +      PointerRNA ptr;
 +      PropertyRNA *prop;
 +      int index;
 +
 +      UI_context_active_but_prop_get(C, &ptr, &prop, &index);
 +
 +      const int override_status = RNA_property_static_override_status(&ptr, prop, index);
 +
 +      return (ptr.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE));
 +}
 +
 +static int override_type_set_button_exec(bContext *C, wmOperator *op)
 +{
 +      PointerRNA ptr;
 +      PropertyRNA *prop;
 +      int index;
 +      bool created;
 +      const bool all = RNA_boolean_get(op->ptr, "all");
 +      const int op_type = RNA_enum_get(op->ptr, "type");
 +
 +      short operation;
 +
 +      switch (op_type) {
 +              case UIOverride_Type_NOOP:
 +                      operation = IDOVERRIDESTATIC_OP_NOOP;
 +                      break;
 +              case UIOverride_Type_Replace:
 +                      operation = IDOVERRIDESTATIC_OP_REPLACE;
 +                      break;
 +              case UIOverride_Type_Difference:
 +                      operation = IDOVERRIDESTATIC_OP_ADD;  /* override code will automatically switch to subtract if needed. */
 +                      break;
 +              case UIOverride_Type_Factor:
 +                      operation = IDOVERRIDESTATIC_OP_MULTIPLY;
 +                      break;
 +              default:
 +                      operation = IDOVERRIDESTATIC_OP_REPLACE;
 +                      BLI_assert(0);
 +                      break;
 +      }
 +
 +      /* try to reset the nominated setting to its default value */
 +      UI_context_active_but_prop_get(C, &ptr, &prop, &index);
 +
 +      BLI_assert(ptr.id.data != NULL);
 +
 +      if (all) {
 +              index = -1;
 +      }
 +
 +      IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_get(
 +              &ptr, prop, operation, index, true, NULL, &created);
 +      if (!created) {
 +              opop->operation = operation;
 +      }
 +
 +      return operator_button_property_finish(C, &ptr, prop);
 +}
 +
 +static int override_type_set_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
 +{
 +#if 0  /* Disabled for now */
 +      return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT);
 +#else
 +      RNA_enum_set(op->ptr, "type", IDOVERRIDESTATIC_OP_REPLACE);
 +      return override_type_set_button_exec(C, op);
 +#endif
 +}
 +
 +static void UI_OT_override_type_set_button(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Define Override Type";
 +      ot->idname = "UI_OT_override_type_set_button";
 +      ot->description = "Create an override operation, or set the type of an existing one";
 +
 +      /* callbacks */
 +      ot->poll = override_type_set_button_poll;
 +      ot->exec = override_type_set_button_exec;
 +      ot->invoke = override_type_set_button_invoke;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_UNDO;
 +
 +      /* properties */
 +      RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
 +      ot->prop = RNA_def_enum(
 +              ot->srna, "type", override_type_items, UIOverride_Type_Replace,
 +              "Type", "Type of override operation");
 +      /* TODO: add itemf callback, not all options are available for all data types... */
 +}
 +
 +
++static bool override_remove_button_poll(bContext *C)
 +{
 +      PointerRNA ptr;
 +      PropertyRNA *prop;
 +      int index;
 +
 +      UI_context_active_but_prop_get(C, &ptr, &prop, &index);
 +
 +      const int override_status = RNA_property_static_override_status(&ptr, prop, index);
 +
 +      return (ptr.data && ptr.id.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN));
 +}
 +
 +static int override_remove_button_exec(bContext *C, wmOperator *op)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      PointerRNA ptr, id_refptr, src;
 +      PropertyRNA *prop;
 +      int index;
 +      const bool all = RNA_boolean_get(op->ptr, "all");
 +
 +      /* try to reset the nominated setting to its default value */
 +      UI_context_active_but_prop_get(C, &ptr, &prop, &index);
 +
 +      ID *id = ptr.id.data;
 +      IDOverrideStaticProperty *oprop = RNA_property_override_property_find(&ptr, prop);
 +      BLI_assert(oprop != NULL);
 +      BLI_assert(id != NULL && id->override_static != NULL);
 +
 +      const bool is_template = (id->override_static->reference == NULL);
 +
 +      /* We need source (i.e. linked data) to restore values of deleted overrides...
 +       * If this is an override template, we obviously do not need to restore anything. */
 +      if (!is_template) {
 +              RNA_id_pointer_create(id->override_static->reference, &id_refptr);
 +              if (!RNA_path_resolve(&id_refptr, oprop->rna_path, &src, NULL)) {
 +                      BLI_assert(0 && "Failed to create matching source (linked data) RNA pointer");
 +              }
 +      }
 +
 +      if (!all && index != -1) {
 +              bool is_strict_find;
 +              /* Remove override operation for given item, add singular operations for the other items as needed. */
 +              IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find(
 +                      oprop, NULL, NULL, index, index, false, &is_strict_find);
 +              BLI_assert(opop != NULL);
 +              if (!is_strict_find) {
 +                      /* No specific override operation, we have to get generic one,
 +                       * and create item-specific override operations for all but given index, before removing generic one. */
 +                      for (int idx = RNA_property_array_length(&ptr, prop); idx--; ) {
 +                              if (idx != index) {
 +                                      BKE_override_static_property_operation_get(oprop, opop->operation, NULL, NULL, idx, idx, true, NULL, NULL);
 +                              }
 +                      }
 +              }
 +              BKE_override_static_property_operation_delete(oprop, opop);
 +              if (!is_template) {
 +                      RNA_property_copy(bmain, &ptr, &src, prop, index);
 +              }
 +              if (BLI_listbase_is_empty(&oprop->operations)) {
 +                      BKE_override_static_property_delete(id->override_static, oprop);
 +              }
 +      }
 +      else {
 +              /* Just remove whole generic override operation of this property. */
 +              BKE_override_static_property_delete(id->override_static, oprop);
 +              if (!is_template) {
 +                      RNA_property_copy(bmain, &ptr, &src, prop, -1);
 +              }
 +      }
 +
 +      return operator_button_property_finish(C, &ptr, prop);
 +}
 +
 +static void UI_OT_override_remove_button(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Remove Override";
 +      ot->idname = "UI_OT_override_remove_button";
 +      ot->description = "Remove an override operation";
 +
 +      /* callbacks */
 +      ot->poll = override_remove_button_poll;
 +      ot->exec = override_remove_button_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_UNDO;
 +
 +      /* properties */
 +      RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array");
 +}
 +
 +
 +
 +
  /* Copy To Selected Operator ------------------------ */
  
  bool UI_context_copy_to_selected_list(
index 3ac9932fdc9cc8d4ac7f2d00e3427473aee8a4bf,0000000000000000000000000000000000000000..f3ff6fdf2c0bc0fc1513f93cb8d62544f0adcf19
mode 100644,000000..100644
--- /dev/null
@@@ -1,339 -1,0 +1,339 @@@
- static int hud_panel_operator_redo_poll(const bContext *C, PanelType *UNUSED(pt))
 +/*
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 + *
 + * The Original Code is Copyright (C) 2008 Blender Foundation.
 + * All rights reserved.
 + *
 + * Contributor(s): Blender Foundation
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file blender/editors/interface/interface_region_hud.c
 + *  \ingroup edinterface
 + *
 + * Floating Persistent Region
 + */
 +
 +#include <string.h>
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "DNA_userdef_types.h"
 +
 +#include "BLI_string.h"
 +#include "BLI_rect.h"
 +#include "BLI_listbase.h"
 +#include "BLI_utildefines.h"
 +
 +#include "BKE_context.h"
 +#include "BKE_screen.h"
 +#include "BKE_main.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +
 +#include "RNA_access.h"
 +
 +#include "BIF_gl.h"
 +
 +#include "UI_interface.h"
 +#include "UI_view2d.h"
 +
 +#include "BLT_translation.h"
 +
 +#include "ED_screen.h"
 +#include "ED_undo.h"
 +
 +#include "interface_intern.h"
 +#include "GPU_framebuffer.h"
 +
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Utilities
 + * \{ */
 +
 +static bool last_redo_poll(const bContext *C)
 +{
 +      wmOperator *op = WM_operator_last_redo(C);
 +      if (op == NULL) {
 +              return false;
 +      }
 +      bool success = false;
 +      if (WM_operator_repeat_check(C, op) &&
 +          WM_operator_check_ui_empty(op->type) == false)
 +      {
 +              success = WM_operator_poll((bContext *)C, op->type);
 +      }
 +      return success;
 +}
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Redo Panel
 + * \{ */
 +
++static bool hud_panel_operator_redo_poll(const bContext *C, PanelType *UNUSED(pt))
 +{
 +      return last_redo_poll(C);
 +}
 +
 +static void hud_panel_operator_redo_draw_header(const bContext *C, Panel *pa)
 +{
 +      wmOperator *op = WM_operator_last_redo(C);
 +      BLI_strncpy(pa->drawname, RNA_struct_ui_name(op->type->srna), sizeof(pa->drawname));
 +}
 +
 +static void hud_panel_operator_redo_draw(const bContext *C, Panel *pa)
 +{
 +      wmOperator *op = WM_operator_last_redo(C);
 +      if (op == NULL) {
 +              return;
 +      }
 +      if (!WM_operator_check_ui_enabled(C, op->type->name)) {
 +              uiLayoutSetEnabled(pa->layout, false);
 +      }
 +      uiLayout *col = uiLayoutColumn(pa->layout, false);
 +      uiTemplateOperatorRedoProperties(col, C);
 +}
 +
 +static void hud_panels_register(ARegionType *art, int space_type, int region_type)
 +{
 +      PanelType *pt;
 +
 +      pt = MEM_callocN(sizeof(PanelType), __func__);
 +      strcpy(pt->idname, "OPERATOR_PT_redo");
 +      strcpy(pt->label, N_("Redo"));
 +      strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
 +      pt->draw_header = hud_panel_operator_redo_draw_header;
 +      pt->draw = hud_panel_operator_redo_draw;
 +      pt->poll = hud_panel_operator_redo_poll;
 +      pt->space_type = space_type;
 +      pt->region_type = region_type;
 +      BLI_addtail(&art->paneltypes, pt);
 +}
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Callbacks for Floating Region
 + * \{ */
 +
 +struct HudRegionData {
 +      short regionid;
 +};
 +
 +static void hud_region_init(wmWindowManager *wm, ARegion *ar)
 +{
 +      ED_region_panels_init(wm, ar);
 +      UI_region_handlers_add(&ar->handlers);
 +      ar->flag |= RGN_FLAG_TEMP_REGIONDATA;
 +}
 +
 +static void hud_region_free(ARegion *ar)
 +{
 +      MEM_SAFE_FREE(ar->regiondata);
 +}
 +
 +static void hud_region_layout(const bContext *C, ARegion *ar)
 +{
 +      bool ok = false;
 +
 +      {
 +              struct HudRegionData *hrd = ar->regiondata;
 +              if (hrd != NULL) {
 +                      ScrArea *sa = CTX_wm_area(C);
 +                      ARegion *ar_op = (hrd->regionid != -1) ? BKE_area_find_region_type(sa, hrd->regionid) : NULL;
 +                      ARegion *ar_prev = CTX_wm_region(C);
 +                      CTX_wm_region_set((bContext *)C, ar_op);
 +                      ok = last_redo_poll(C);
 +                      CTX_wm_region_set((bContext *)C, ar_prev);
 +              }
 +      }
 +
 +      if (!ok) {
 +              ED_region_tag_redraw(ar);
 +              ar->flag |= RGN_FLAG_HIDDEN;
 +              return;
 +      }
 +
 +      int size_y = ar->sizey;
 +
 +      ED_region_panels_layout(C, ar);
 +
 +      if (ar->panels.first && (ar->sizey != size_y)) {
 +              View2D *v2d = &ar->v2d;
 +              ar->winx = ar->sizex;
 +              ar->winy = ar->sizey;
 +
 +              ar->winrct.xmax = (ar->winrct.xmin + ar->winx) - 1;
 +              ar->winrct.ymax = (ar->winrct.ymin + ar->winy) - 1;
 +
 +              UI_view2d_region_reinit(v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy);
 +      }
 +
 +      /* restore view matrix */
 +      UI_view2d_view_restore(C);
 +}
 +
 +static void hud_region_draw(const bContext *C, ARegion *ar)
 +{
 +      UI_view2d_view_ortho(&ar->v2d);
 +      wmOrtho2_region_pixelspace(ar);
 +      GPU_clear_color(0, 0, 0, 0.0f);
 +      GPU_clear(GPU_COLOR_BIT);
 +
 +      if ((ar->flag & RGN_FLAG_HIDDEN) == 0) {
 +              float color[4];
 +              UI_GetThemeColor4fv(TH_BUTBACK, color);
 +              if ((U.uiflag2 & USER_REGION_OVERLAP) == 0) {
 +                      color[3] = 1.0f;
 +              }
 +              ui_draw_widget_back_color(UI_WTYPE_BOX, false, &(rcti){.xmax = ar->winx, .ymax = ar->winy}, color);
 +              ED_region_panels_draw(C, ar);
 +      }
 +}
 +
 +ARegionType *ED_area_type_hud(int space_type)
 +{
 +      ARegionType *art = MEM_callocN(sizeof(ARegionType), __func__);
 +      art->regionid = RGN_TYPE_HUD;
 +      art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
 +      art->layout = hud_region_layout;
 +      art->draw = hud_region_draw;
 +      art->init = hud_region_init;
 +      art->free = hud_region_free;
 +
 +      hud_panels_register(art, space_type, art->regionid);
 +
 +      art->lock = 1;   /* can become flag, see BKE_spacedata_draw_locks */
 +      return art;
 +}
 +
 +static ARegion *hud_region_add(ScrArea *sa)
 +{
 +      ARegion *ar = MEM_callocN(sizeof(ARegion), "area region");
 +      ARegion *ar_win = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
 +      if (ar_win) {
 +              BLI_insertlinkbefore(&sa->regionbase, ar_win, ar);
 +      }
 +      else {
 +              BLI_addtail(&sa->regionbase, ar);
 +      }
 +      ar->regiontype = RGN_TYPE_HUD;
 +      ar->alignment = RGN_ALIGN_FLOAT;
 +      ar->overlap = true;
 +      ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
 +
 +      return ar;
 +}
 +
 +void ED_area_type_hud_clear(wmWindowManager *wm, ScrArea *sa_keep)
 +{
 +      for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +              bScreen *screen = WM_window_get_active_screen(win);
 +              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                      if (sa != sa_keep) {
 +                              for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
 +                                      if (ar->regiontype == RGN_TYPE_HUD) {
 +                                              if ((ar->flag & RGN_FLAG_HIDDEN) == 0) {
 +                                                      ar->flag |= RGN_FLAG_HIDDEN;
 +                                                      ED_region_tag_redraw(ar);
 +                                                      ED_area_tag_redraw(sa);
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
 +{
 +      wmWindowManager *wm = CTX_wm_manager(C);
 +      ED_area_type_hud_clear(wm, sa);
 +
 +      ARegionType *art = BKE_regiontype_from_id(sa->type, RGN_TYPE_HUD);
 +      if (art == NULL) {
 +              return;
 +      }
 +
 +      bool init = false;
 +      ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_HUD);
 +      if (!last_redo_poll(C)) {
 +              if (ar) {
 +                      ED_region_tag_redraw(ar);
 +                      ar->flag |= RGN_FLAG_HIDDEN;
 +              }
 +              return;
 +      }
 +
 +      if (ar == NULL) {
 +              init = true;
 +              ar = hud_region_add(sa);
 +              ar->type = art;
 +      }
 +
 +      ED_region_init(ar);
 +      ED_region_tag_redraw(ar);
 +
 +      /* Reset zoom level (not well supported). */
 +      ar->v2d.cur = ar->v2d.tot = (rctf){.xmax = ar->winx, .ymax = ar->winy};
 +      ar->v2d.minzoom = 1.0f;
 +      ar->v2d.maxzoom = 1.0f;
 +
 +      /* Let 'ED_area_update_region_sizes' do the work of placing the region.
 +       * Otherwise we could set the 'ar->winrct' & 'ar->winx/winy' here. */
 +      if (init) {
 +              sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
 +      }
 +      else {
 +              if (ar->flag & RGN_FLAG_HIDDEN) {
 +                      sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
 +              }
 +              ar->flag &= ~RGN_FLAG_HIDDEN;
 +      }
 +
 +      {
 +              ARegion *ar_op = CTX_wm_region(C);
 +              BLI_assert((ar_op == NULL) || (ar_op->regiontype != RGN_TYPE_HUD));
 +              struct HudRegionData *hrd = ar->regiondata;
 +              if (hrd == NULL) {
 +                      hrd = MEM_callocN(sizeof(*hrd), __func__);
 +                      ar->regiondata = hrd;
 +              }
 +              if (ar_op) {
 +                      hrd->regionid = ar_op->regiontype;
 +              }
 +              else {
 +                      hrd->regionid = -1;
 +              }
 +      }
 +
 +      /* XXX, should be handled in more general way. */
 +      ar->visible = !((ar->flag & RGN_FLAG_HIDDEN) || (ar->flag & RGN_FLAG_TOO_SMALL));
 +
 +      /* We shouldn't need to do this every time :S */
 +      /* XXX, this is evil! - it also makes the menu show on first draw. :( */
 +      ARegion *ar_prev = CTX_wm_region(C);
 +      CTX_wm_region_set((bContext *)C, ar);
 +      hud_region_layout(C, ar);
 +      CTX_wm_region_set((bContext *)C, ar_prev);
 +}
 +
 +/** \} */
index 23f8b4c9bc483afe31a64b259782fe492b76e4b7,3cad2167cfa3dd95ae84aee6b7b328aaa1763ace..dfc401c163599ab617204f5334101f19d31cc5d8
@@@ -1678,21 -1668,6 +1678,21 @@@ static short mouse_in_scroller_handle(i
        return SCROLLHANDLE_BAR;
  }
  
- static int scroller_activate_poll(bContext *C)
++static bool scroller_activate_poll(bContext *C)
 +{
 +      if (!view2d_poll(C)) {
 +              return false;
 +      }
 +
 +      wmWindow *win = CTX_wm_window(C);
 +      ARegion *ar = CTX_wm_region(C);
 +      View2D *v2d = &ar->v2d;
 +      wmEvent *event = win->eventstate;
 +
 +      /* check if mouse in scrollbars, if they're enabled */
 +      return (UI_view2d_mouse_in_scrollers(ar, v2d, event->x, event->y) != 0);
 +}
 +
  /* initialize customdata for scroller manipulation operator */
  static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *event, short in_scroller)
  {
index 73e7271abf79464271142ac7d37c707a326e685a,e977dea6140b4e9ce8409d76419b112082a52fde..a8c3c905dd463c1c252e4b53556d053dbc345e0a
@@@ -1661,14 -1578,17 +1661,14 @@@ static void curvetomesh(Main *bmain, De
        }
  }
  
- static int convert_poll(bContext *C)
+ static bool convert_poll(bContext *C)
  {
 -      Object *obact = CTX_data_active_object(C);
        Scene *scene = CTX_data_scene(C);
 +      Base *base_act = CTX_data_active_base(C);
 +      Object *obact = base_act ? base_act->object : NULL;
  
 -      return (!ID_IS_LINKED(scene) && obact && scene->obedit != obact &&
 -              (obact->flag & SELECT) && !ID_IS_LINKED(obact));
 +      return (!ID_IS_LINKED(scene) && obact && (BKE_object_is_in_editmode(obact) == false) &&
 +              (base_act->flag & BASE_SELECTED) && !ID_IS_LINKED(obact));
  }
  
  /* Helper for convert_exec */
index 2ede8caf7de9387214be116e277a0e56e596a660,214c995a26e2836208abfb60b9a3e5f6db2a4867..d7bef459b8228ce849cbea4745b0801b4112c9b3
@@@ -1262,10 -1248,10 +1262,10 @@@ void ED_object_constraint_dependency_ta
        if (ob->pose) {
                object_pose_tag_update(bmain, ob);
        }
 -      DAG_relations_tag_update(bmain);
 +      DEG_relations_tag_update(bmain);
  }
  
- static int constraint_poll(bContext *C)
+ static bool constraint_poll(bContext *C)
  {
        PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint);
        return (ptr.id.data && ptr.data);
index e14842c0daa5491b9471663ec7f02e0238d2dd26,fc967dc424e8a172397df46532ada138eee536b4..0ca797e43b66116595328d18b9a3644b95ce377f
@@@ -146,44 -134,35 +146,44 @@@ Object *ED_object_active_context(bConte
        return ob;
  }
  
- static int object_hide_poll(bContext *C)
 +/* ********************** object hiding *************************** */
 +
++static bool object_hide_poll(bContext *C)
 +{
 +      if (CTX_wm_space_outliner(C) != NULL) {
 +              return ED_outliner_collections_editor_poll(C);
 +      }
 +      else {
 +              return ED_operator_view3d_active(C);
 +      }
 +}
  
 -/* ********* clear/set restrict view *********/
  static int object_hide_view_clear_exec(bContext *C, wmOperator *op)
  {
 -      Main *bmain = CTX_data_main(C);
 -      ScrArea *sa = CTX_wm_area(C);
 -      View3D *v3d = sa->spacedata.first;
        Scene *scene = CTX_data_scene(C);
 -      Base *base;
 -      bool changed = false;
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
        const bool select = RNA_boolean_get(op->ptr, "select");
 +      bool changed = false;
  
 -      /* XXX need a context loop to handle such cases */
 -      for (base = FIRSTBASE; base; base = base->next) {
 -              if ((base->lay & v3d->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) {
 -                      if (!(base->object->restrictflag & OB_RESTRICT_SELECT)) {
 -                              SET_FLAG_FROM_TEST(base->flag, select, SELECT);
 -                      }
 -                      base->object->flag = base->flag;
 -                      base->object->restrictflag &= ~OB_RESTRICT_VIEW;
 +      for (Base *base = view_layer->object_bases.first; base; base = base->next) {
 +              if (base->flag & BASE_HIDDEN) {
 +                      base->flag &= ~BASE_HIDDEN;
                        changed = true;
 +
 +                      if (select) {
 +                              ED_object_base_select(base, BA_SELECT);
 +                      }
                }
        }
 -      if (changed) {
 -              DAG_id_type_tag(bmain, ID_OB);
 -              DAG_relations_tag_update(bmain);
 -              WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
 +
 +      if (!changed) {
 +              return OPERATOR_CANCELLED;
        }
  
 +      BKE_layer_collection_sync(scene, view_layer);
 +      DEG_id_tag_update(&scene->id, DEG_TAG_BASE_FLAGS_UPDATE);
 +      WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
 +
        return OPERATOR_FINISHED;
  }
  
@@@ -1692,372 -1760,388 +1692,372 @@@ void OBJECT_OT_mode_set(wmOperatorType 
        RNA_def_property_flag(prop, PROP_SKIP_SAVE);
  }
  
 -/************************ Game Properties ***********************/
 -
 -static int game_property_new_exec(bContext *C, wmOperator *op)
 +void OBJECT_OT_mode_set_or_submode(wmOperatorType *ot)
  {
 -      Object *ob = CTX_data_active_object(C);
 -      bProperty *prop;
 -      char name[MAX_NAME];
 -      int type = RNA_enum_get(op->ptr, "type");
 -
 -      prop = BKE_bproperty_new(type);
 -      BLI_addtail(&ob->prop, prop);
 -
 -      RNA_string_get(op->ptr, "name", name);
 -      if (name[0] != '\0') {
 -              BLI_strncpy(prop->name, name, sizeof(prop->name));
 -      }
 -
 -      BLI_uniquename(&ob->prop, prop, DATA_("Property"), '.', offsetof(bProperty, name), sizeof(prop->name));
 -
 -      WM_event_add_notifier(C, NC_LOGIC, NULL);
 -      return OPERATOR_FINISHED;
 -}
 -
 +      PropertyRNA *prop;
  
 -void OBJECT_OT_game_property_new(wmOperatorType *ot)
 -{
        /* identifiers */
 -      ot->name = "New Game Property";
 -      ot->description = "Create a new property available to the game engine";
 -      ot->idname = "OBJECT_OT_game_property_new";
 +      ot->name = "Set Object Mode or Submode";
 +      ot->description = "Sets the object interaction mode";
 +      ot->idname = "OBJECT_OT_mode_set_or_submode";
  
        /* api callbacks */
 -      ot->exec = game_property_new_exec;
 -      ot->poll = ED_operator_object_active_editable;
 +      ot->exec = object_mode_set_exec;
 +
 +      ot->poll = object_mode_set_poll; //ED_operator_object_active_editable;
  
        /* flags */
 -      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +      ot->flag = 0; /* no register/undo here, leave it to operators being called */
 +
 +      ot->prop = RNA_def_enum(ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", "");
 +      RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf);
 +      RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
  
 -      RNA_def_enum(ot->srna, "type", rna_enum_gameproperty_type_items, GPROP_FLOAT, "Type", "Type of game property to add");
 -      RNA_def_string(ot->srna, "name", NULL, MAX_NAME, "Name", "Name of the game property to add");
 +      prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
 +      RNA_def_property_flag(prop, PROP_SKIP_SAVE);
  }
  
 -static int game_property_remove_exec(bContext *C, wmOperator *op)
 +bool ED_object_editmode_calc_active_center(Object *obedit, const bool select_only, float r_center[3])
  {
 -      Object *ob = CTX_data_active_object(C);
 -      bProperty *prop;
 -      int index = RNA_int_get(op->ptr, "index");
 -
 -      if (!ob)
 -              return OPERATOR_CANCELLED;
 +      switch (obedit->type) {
 +              case OB_MESH:
 +              {
 +                      BMEditMesh *em = BKE_editmesh_from_object(obedit);
 +                      BMEditSelection ese;
  
 -      prop = BLI_findlink(&ob->prop, index);
 +                      if (BM_select_history_active_get(em->bm, &ese)) {
 +                              BM_editselection_center(&ese, r_center);
 +                              return true;
 +                      }
 +                      break;
 +              }
 +              case OB_ARMATURE:
 +              {
 +                      bArmature *arm = obedit->data;
 +                      EditBone *ebo = arm->act_edbone;
  
 -      if (prop) {
 -              BLI_remlink(&ob->prop, prop);
 -              BKE_bproperty_free(prop);
 +                      if (ebo && (!select_only || (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL)))) {
 +                              copy_v3_v3(r_center, ebo->head);
 +                              return true;
 +                      }
  
 -              WM_event_add_notifier(C, NC_LOGIC, NULL);
 -              return OPERATOR_FINISHED;
 -      }
 -      else {
 -              return OPERATOR_CANCELLED;
 -      }
 -}
 +                      break;
 +              }
 +              case OB_CURVE:
 +              case OB_SURF:
 +              {
 +                      Curve *cu = obedit->data;
  
 -void OBJECT_OT_game_property_remove(wmOperatorType *ot)
 -{
 -      /* identifiers */
 -      ot->name = "Remove Game Property";
 -      ot->description = "Remove game property";
 -      ot->idname = "OBJECT_OT_game_property_remove";
 +                      if (ED_curve_active_center(cu, r_center)) {
 +                              return true;
 +                      }
 +                      break;
 +              }
 +              case OB_MBALL:
 +              {
 +                      MetaBall *mb = obedit->data;
 +                      MetaElem *ml_act = mb->lastelem;
  
 -      /* api callbacks */
 -      ot->exec = game_property_remove_exec;
 -      ot->poll = ED_operator_object_active_editable;
 +                      if (ml_act && (!select_only || (ml_act->flag & SELECT))) {
 +                              copy_v3_v3(r_center, &ml_act->x);
 +                              return true;
 +                      }
 +                      break;
 +              }
 +              case OB_LATTICE:
 +              {
 +                      BPoint *actbp = BKE_lattice_active_point_get(obedit->data);
  
 -      /* flags */
 -      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +                      if (actbp) {
 +                              copy_v3_v3(r_center, actbp->vec);
 +                              return true;
 +                      }
 +                      break;
 +              }
 +      }
  
 -      RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to remove ", 0, INT_MAX);
 +      return false;
  }
  
- static int move_to_collection_poll(bContext *C)
 -#define GAME_PROPERTY_MOVE_UP    1
 -#define GAME_PROPERTY_MOVE_DOWN -1
 -
 -static int game_property_move(bContext *C, wmOperator *op)
++static bool move_to_collection_poll(bContext *C)
  {
 -      Object *ob = CTX_data_active_object(C);
 -      bProperty *prop;
 -      bProperty *otherprop = NULL;
 -      const int index = RNA_int_get(op->ptr, "index");
 -      const int dir = RNA_enum_get(op->ptr, "direction");
 +      if (CTX_wm_space_outliner(C) != NULL) {
 +              return ED_outliner_collections_editor_poll(C);
 +      }
 +      else {
 +              return ED_operator_object_active_editable(C);
 +      }
 +}
  
 -      if (ob == NULL)
 +static int move_to_collection_exec(bContext *C, wmOperator *op)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +      PropertyRNA *prop = RNA_struct_find_property(op->ptr, "collection_index");
 +      const bool is_link = STREQ(op->idname, "OBJECT_OT_link_to_collection");
 +      const bool is_new = RNA_boolean_get(op->ptr, "is_new");
 +      Collection *collection;
 +      ListBase objects = {NULL};
 +
 +      if (!RNA_property_is_set(op->ptr, prop)) {
 +              BKE_report(op->reports, RPT_ERROR, "No collection selected");
                return OPERATOR_CANCELLED;
 +      }
  
 -      prop = BLI_findlink(&ob->prop, index);
 -      /* invalid index */
 -      if (prop == NULL)
 +      int collection_index = RNA_property_int_get(op->ptr, prop);
 +      collection = BKE_collection_from_index(CTX_data_scene(C), collection_index);
 +      if (collection == NULL) {
 +              BKE_report(op->reports, RPT_ERROR, "Unexpected error, collection not found");
                return OPERATOR_CANCELLED;
 -
 -      if (dir == GAME_PROPERTY_MOVE_UP) {
 -              otherprop = prop->prev;
        }
 -      else if (dir == GAME_PROPERTY_MOVE_DOWN) {
 -              otherprop = prop->next;
 +
 +      if (CTX_wm_space_outliner(C) != NULL) {
 +              ED_outliner_selected_objects_get(C, &objects);
        }
        else {
 -              BLI_assert(0);
 +              CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
 +              {
 +                      BLI_addtail(&objects, BLI_genericNodeN(ob));
 +              }
 +              CTX_DATA_END;
        }
  
 -      if (prop && otherprop) {
 -              BLI_listbase_swaplinks(&ob->prop, prop, otherprop);
 -
 -              WM_event_add_notifier(C, NC_LOGIC, NULL);
 -              return OPERATOR_FINISHED;
 +      if (is_new) {
 +              char new_collection_name[MAX_NAME];
 +              RNA_string_get(op->ptr, "new_collection_name", new_collection_name);
 +              collection = BKE_collection_add(bmain, collection, new_collection_name);
        }
 -      else {
 +
 +      Object *single_object = BLI_listbase_is_single(&objects) ?
 +                                  ((LinkData *)objects.first)->data : NULL;
 +
 +      if ((single_object != NULL) &&
 +          is_link &&
 +          BLI_findptr(&collection->gobject, single_object, offsetof(CollectionObject, ob)))
 +      {
 +              BKE_reportf(op->reports, RPT_ERROR, "%s already in %s", single_object->id.name + 2, collection->id.name + 2);
 +              BLI_freelistN(&objects);
                return OPERATOR_CANCELLED;
        }
 -}
  
 -void OBJECT_OT_game_property_move(wmOperatorType *ot)
 -{
 -      static const EnumPropertyItem direction_property_move[] = {
 -              {GAME_PROPERTY_MOVE_UP,   "UP",   0, "Up",   ""},
 -              {GAME_PROPERTY_MOVE_DOWN, "DOWN", 0, "Down", ""},
 -              {0, NULL, 0, NULL, NULL}
 -      };
 -      PropertyRNA *prop;
 -
 -      /* identifiers */
 -      ot->name = "Move Game Property";
 -      ot->description = "Move game property";
 -      ot->idname = "OBJECT_OT_game_property_move";
 +      for (LinkData *link = objects.first; link; link = link->next) {
 +              Object *ob = link->data;
  
 -      /* api callbacks */
 -      ot->exec = game_property_move;
 -      ot->poll = ED_operator_object_active_editable;
 +              if (!is_link) {
 +                      BKE_collection_object_move(bmain, scene, collection, NULL, ob);
 +              }
 +              else {
 +                      BKE_collection_object_add(bmain, collection, ob);
 +              }
 +      }
 +      BLI_freelistN(&objects);
  
 -      /* flags */
 -      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +      BKE_reportf(op->reports,
 +                  RPT_INFO,
 +                  "%s %s to %s",
 +                  (single_object != NULL) ? single_object->id.name + 2 : "Objects",
 +                  is_link ? "linked" : "moved",
 +                  collection->id.name + 2);
  
 -      /* properties */
 -      prop = RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Property index to move", 0, INT_MAX);
 -      RNA_def_property_flag(prop, PROP_HIDDEN);
 -      RNA_def_enum(ot->srna, "direction", direction_property_move, 0, "Direction",
 -                   "Direction for moving the property");
 -}
 +      DEG_relations_tag_update(bmain);
 +      DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE | DEG_TAG_SELECT_UPDATE);
  
 -#undef GAME_PROPERTY_MOVE_UP
 -#undef GAME_PROPERTY_MOVE_DOWN
 +      WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
 +      WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
 +      WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
  
 -#define COPY_PROPERTIES_REPLACE 1
 -#define COPY_PROPERTIES_MERGE   2
 -#define COPY_PROPERTIES_COPY    3
 +      return OPERATOR_FINISHED;
 +}
  
 -static const EnumPropertyItem game_properties_copy_operations[] = {
 -      {COPY_PROPERTIES_REPLACE, "REPLACE", 0, "Replace Properties", ""},
 -      {COPY_PROPERTIES_MERGE, "MERGE", 0, "Merge Properties", ""},
 -      {COPY_PROPERTIES_COPY, "COPY", 0, "Copy a Property", ""},
 -      {0, NULL, 0, NULL, NULL}
 +struct MoveToCollectionData {
 +      struct MoveToCollectionData *next, *prev;
 +      int index;
 +      struct Collection *collection;
 +      struct ListBase submenus;
 +      PointerRNA ptr;
 +      struct wmOperatorType *ot;
  };
  
 -static const EnumPropertyItem *gameprops_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
 +static int move_to_collection_menus_create(wmOperator *op, MoveToCollectionData *menu)
  {
 -      Object *ob = ED_object_active_context(C);
 -      EnumPropertyItem tmp = {0, "", 0, "", ""};
 -      EnumPropertyItem *item = NULL;
 -      bProperty *prop;
 -      int a, totitem = 0;
 -
 -      if (!ob)
 -              return DummyRNA_NULL_items;
 +      int index = menu->index;
 +      for (CollectionChild *child = menu->collection->children.first;
 +           child != NULL;
 +           child = child->next)
 +      {
 +              Collection *collection = child->collection;
 +              MoveToCollectionData *submenu = MEM_callocN(sizeof(MoveToCollectionData),
 +                                                          "MoveToCollectionData submenu - expected memleak");
 +              BLI_addtail(&menu->submenus, submenu);
 +              submenu->collection = collection;
 +              submenu->index = ++index;
 +              index = move_to_collection_menus_create(op, submenu);
 +              submenu->ot = op->type;
 +      }
 +      return index;
 +}
  
 -      for (a = 1, prop = ob->prop.first; prop; prop = prop->next, a++) {
 -              tmp.value = a;
 -              tmp.identifier = prop->name;
 -              tmp.name = prop->name;
 -              RNA_enum_item_add(&item, &totitem, &tmp);
 +static void move_to_collection_menus_free_recursive(MoveToCollectionData *menu)
 +{
 +      for (MoveToCollectionData *submenu = menu->submenus.first;
 +           submenu != NULL;
 +           submenu = submenu->next)
 +      {
 +              move_to_collection_menus_free_recursive(submenu);
        }
 +      BLI_freelistN(&menu->submenus);
 +}
  
 -      RNA_enum_item_end(&item, &totitem);
 -      *r_free = true;
 +static void move_to_collection_menus_free(MoveToCollectionData **menu)
 +{
 +      if (*menu == NULL) {
 +              return;
 +      }
  
 -      return item;
 +      move_to_collection_menus_free_recursive(*menu);
 +      MEM_freeN(*menu);
 +      *menu = NULL;
  }
  
 -static int game_property_copy_exec(bContext *C, wmOperator *op)
 +static void move_to_collection_menu_create(bContext *UNUSED(C), uiLayout *layout, void *menu_v)
  {
 -      Object *ob = ED_object_active_context(C);
 -      bProperty *prop;
 -      int type = RNA_enum_get(op->ptr, "operation");
 -      int propid = RNA_enum_get(op->ptr, "property");
 -
 -      if (propid > 0) { /* copy */
 -              prop = BLI_findlink(&ob->prop, propid - 1);
 +      MoveToCollectionData *menu = menu_v;
 +      const char *name;
  
 -              if (prop) {
 -                      CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
 -                      {
 -                              if (ob != ob_iter)
 -                                      BKE_bproperty_object_set(ob_iter, prop);
 -                      } CTX_DATA_END;
 -              }
 +      if (menu->collection->flag & COLLECTION_IS_MASTER) {
 +              name = IFACE_("Scene Collection");
        }
 -
        else {
 -              CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
 -              {
 -                      if (ob != ob_iter) {
 -                              if (type == COPY_PROPERTIES_REPLACE) {
 -                                      BKE_bproperty_copy_list(&ob_iter->prop, &ob->prop);
 -                              }
 -                              else {
 -                                      /* merge - the default when calling with no argument */
 -                                      for (prop = ob->prop.first; prop; prop = prop->next) {
 -                                              BKE_bproperty_object_set(ob_iter, prop);
 -                                      }
 -                              }
 -                      }
 -              }
 -              CTX_DATA_END;
 +              name = menu->collection->id.name + 2;
        }
  
 -      return OPERATOR_FINISHED;
 -}
 +      uiItemIntO(layout,
 +                 name,
 +                 ICON_NONE,
 +                 menu->ot->idname,
 +                 "collection_index",
 +                 menu->index);
 +      uiItemS(layout);
  
 -void OBJECT_OT_game_property_copy(wmOperatorType *ot)
 -{
 -      PropertyRNA *prop;
 -      /* identifiers */
 -      ot->name = "Copy Game Property";
 -      ot->idname = "OBJECT_OT_game_property_copy";
 -      ot->description = "Copy/merge/replace a game property from active object to all selected objects";
 +      for (MoveToCollectionData *submenu = menu->submenus.first;
 +           submenu != NULL;
 +           submenu = submenu->next)
 +      {
 +              move_to_collection_menus_items(layout, submenu);
 +      }
  
 -      /* api callbacks */
 -      ot->exec = game_property_copy_exec;
 -      ot->poll = ED_operator_object_active_editable;
 +      uiItemS(layout);
  
 -      /* flags */
 -      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +      WM_operator_properties_create_ptr(&menu->ptr, menu->ot);
 +      RNA_int_set(&menu->ptr, "collection_index", menu->index);
 +      RNA_boolean_set(&menu->ptr, "is_new", true);
  
 -      RNA_def_enum(ot->srna, "operation", game_properties_copy_operations, 3, "Operation", "");
 -      prop = RNA_def_enum(ot->srna, "property", DummyRNA_NULL_items, 0, "Property", "Properties to copy");
 -      RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_ENUM_NO_TRANSLATE);
 -      RNA_def_enum_funcs(prop, gameprops_itemf);
 -      ot->prop = prop;
 +      uiItemFullO_ptr(layout,
 +                      menu->ot,
 +                      "New Collection",
 +                      ICON_ZOOMIN,
 +                      menu->ptr.data,
 +                      WM_OP_INVOKE_DEFAULT,
 +                      0,
 +                      NULL);
  }
  
 -static int game_property_clear_exec(bContext *C, wmOperator *UNUSED(op))
 +static void move_to_collection_menus_items(uiLayout *layout, MoveToCollectionData *menu)
  {
 -      CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
 -      {
 -              BKE_bproperty_free_list(&ob_iter->prop);
 +      if (BLI_listbase_is_empty(&menu->submenus)) {
 +              uiItemIntO(layout,
 +                         menu->collection->id.name + 2,
 +                         ICON_NONE,
 +                         menu->ot->idname,
 +                         "collection_index",
 +                         menu->index);
 +      }
 +      else {
 +              uiItemMenuF(layout,
 +                          menu->collection->id.name + 2,
 +                          ICON_NONE,
 +                          move_to_collection_menu_create,
 +                          menu);
        }
 -      CTX_DATA_END;
 -
 -      WM_event_add_notifier(C, NC_LOGIC, NULL);
 -      return OPERATOR_FINISHED;
  }
 -void OBJECT_OT_game_property_clear(wmOperatorType *ot)
 +
 +/* This is allocated statically because we need this available for the menus creation callback. */
 +static MoveToCollectionData *master_collection_menu = NULL;
 +
 +static int move_to_collection_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
  {
 -      /* identifiers */
 -      ot->name = "Clear Game Properties";
 -      ot->idname = "OBJECT_OT_game_property_clear";
 -      ot->description = "Remove all game properties from all selected objects";
 +      Scene *scene = CTX_data_scene(C);
  
 -      /* api callbacks */
 -      ot->exec = game_property_clear_exec;
 -      ot->poll = ED_operator_object_active_editable;
 +      /* Reset the menus data for the current master collection, and free previously allocated data. */
 +      move_to_collection_menus_free(&master_collection_menu);
  
 -      /* flags */
 -      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 -}
 +      PropertyRNA *prop;
 +      prop = RNA_struct_find_property(op->ptr, "collection_index");
 +      if (RNA_property_is_set(op->ptr, prop)) {
 +              int collection_index = RNA_property_int_get(op->ptr, prop);
  
 -/************************ Copy Logic Bricks ***********************/
 +              if (RNA_boolean_get(op->ptr, "is_new")) {
 +                      prop = RNA_struct_find_property(op->ptr, "new_collection_name");
 +                      if (!RNA_property_is_set(op->ptr, prop)) {
 +                              char name[MAX_NAME];
 +                              Collection *collection;
  
 -static int logicbricks_copy_exec(bContext *C, wmOperator *UNUSED(op))
 -{
 -      Object *ob = ED_object_active_context(C);
 +                              collection = BKE_collection_from_index(scene, collection_index);
 +                              BKE_collection_new_name_get(collection, name);
  
 -      CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
 -      {
 -              if (ob != ob_iter) {
 -                      /* first: free all logic */
 -                      free_sensors(&ob_iter->sensors);
 -                      unlink_controllers(&ob_iter->controllers);
 -                      free_controllers(&ob_iter->controllers);
 -                      unlink_actuators(&ob_iter->actuators);
 -                      free_actuators(&ob_iter->actuators);
 -
 -                      /* now copy it, this also works without logicbricks! */
 -                      clear_sca_new_poins_ob(ob);
 -                      copy_sensors(&ob_iter->sensors, &ob->sensors, 0);
 -                      copy_controllers(&ob_iter->controllers, &ob->controllers, 0);
 -                      copy_actuators(&ob_iter->actuators, &ob->actuators, 0);
 -                      set_sca_new_poins_ob(ob_iter);
 -
 -                      /* some menu settings */
 -                      ob_iter->scavisflag = ob->scavisflag;
 -                      ob_iter->scaflag = ob->scaflag;
 -
 -                      /* set the initial state */
 -                      ob_iter->state = ob->state;
 -                      ob_iter->init_state = ob->init_state;
 -
 -                      if (ob_iter->totcol == ob->totcol) {
 -                              ob_iter->actcol = ob->actcol;
 -                              WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_iter);
 +                              RNA_property_string_set(op->ptr, prop, name);
 +                              return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y);
                        }
                }
 +              return move_to_collection_exec(C, op);
        }
 -      CTX_DATA_END;
  
 -      WM_event_add_notifier(C, NC_LOGIC, NULL);
 +      Collection *master_collection = BKE_collection_master(scene);
  
 -      return OPERATOR_FINISHED;
 -}
 +      /* We need the data to be allocated so it's available during menu drawing.
 +       * Technically we could use wmOperator->customdata. However there is no free callback
 +       * called to an operator that exit with OPERATOR_INTERFACE to launch a menu.
 +       *
 +       * So we are left with a memory that will necessarily leak. It's a small leak though.*/
 +      if (master_collection_menu == NULL) {
 +              master_collection_menu = MEM_callocN(sizeof(MoveToCollectionData),
 +                                                   "MoveToCollectionData menu - expected eventual memleak");
 +      }
  
 -void OBJECT_OT_logic_bricks_copy(wmOperatorType *ot)
 -{
 -      /* identifiers */
 -      ot->name = "Copy Logic Bricks to Selected";
 -      ot->description = "Copy logic bricks to other selected objects";
 -      ot->idname = "OBJECT_OT_logic_bricks_copy";
 +      master_collection_menu->collection = master_collection;
 +      master_collection_menu->ot = op->type;
 +      move_to_collection_menus_create(op, master_collection_menu);
  
 -      /* api callbacks */
 -      ot->exec = logicbricks_copy_exec;
 -      ot->poll = ED_operator_object_active_editable;
 +      uiPopupMenu *pup;
 +      uiLayout *layout;
  
 -      /* flags */
 -      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 -}
 +      /* Build the menus. */
 +      const char *title = CTX_IFACE_(op->type->translation_context, op->type->name);
 +      pup = UI_popup_menu_begin(C, title, ICON_NONE);
 +      layout = UI_popup_menu_layout(pup);
  
 -static int game_physics_copy_exec(bContext *C, wmOperator *UNUSED(op))
 -{
 -      Object *ob = ED_object_active_context(C);
 +      uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
  
 -      CTX_DATA_BEGIN(C, Object *, ob_iter, selected_editable_objects)
 -      {
 -              if (ob != ob_iter) {
 -                      ob_iter->gameflag = ob->gameflag;
 -                      ob_iter->gameflag2 = ob->gameflag2;
 -                      ob_iter->inertia = ob->inertia;
 -                      ob_iter->formfactor = ob->formfactor;
 -                      ob_iter->damping = ob->damping;
 -                      ob_iter->rdamping = ob->rdamping;
 -                      ob_iter->min_vel = ob->min_vel;
 -                      ob_iter->max_vel = ob->max_vel;
 -                      ob_iter->min_angvel = ob->min_angvel;
 -                      ob_iter->max_angvel = ob->max_angvel;
 -                      ob_iter->obstacleRad = ob->obstacleRad;
 -                      ob_iter->mass = ob->mass;
 -                      copy_v3_v3(ob_iter->anisotropicFriction, ob->anisotropicFriction);
 -                      ob_iter->collision_boundtype = ob->collision_boundtype;
 -                      ob_iter->margin = ob->margin;
 -                      ob_iter->bsoft = copy_bulletsoftbody(ob->bsoft, 0);
 -                      if (ob->restrictflag & OB_RESTRICT_RENDER)
 -                              ob_iter->restrictflag |= OB_RESTRICT_RENDER;
 -                      else
 -                              ob_iter->restrictflag &= ~OB_RESTRICT_RENDER;
 -
 -                      ob_iter->col_group = ob->col_group;
 -                      ob_iter->col_mask = ob->col_mask;
 -              }
 -      }
 -      CTX_DATA_END;
 +      move_to_collection_menu_create(C, layout, master_collection_menu);
  
 -      return OPERATOR_FINISHED;
 +      UI_popup_menu_end(C, pup);
 +
 +      return OPERATOR_INTERFACE;
  }
  
 -void OBJECT_OT_game_physics_copy(struct wmOperatorType *ot)
 +void OBJECT_OT_move_to_collection(wmOperatorType *ot)
  {
 +      PropertyRNA *prop;
 +
        /* identifiers */
 -      ot->name = "Copy Game Physics Properties to Selected";
 -      ot->description = "Copy game physics properties to other selected objects";
 -      ot->idname = "OBJECT_OT_game_physics_copy";
 +      ot->name = "Move to Collection";
 +      ot->description = "Move objects to a scene collection";
 +      ot->idname = "OBJECT_OT_move_to_collection";
  
        /* api callbacks */
 -      ot->exec = game_physics_copy_exec;
 -      ot->poll = ED_operator_object_active_editable;
 +      ot->exec = move_to_collection_exec;
 +      ot->invoke = move_to_collection_invoke;
 +      ot->poll = move_to_collection_poll;
  
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
index c588256008397773efc02a7c97e3e4c42827b38e,0000000000000000000000000000000000000000..a561556bba0a02b84f0f07b632f5d6f8a7ac6848
mode 100644,000000..100644
--- /dev/null
@@@ -1,498 -1,0 +1,498 @@@
- static int face_map_supported_poll(bContext *C)
 +/*
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 + *
 + * The Original Code is Copyright (C) 2008 Blender Foundation.
 + * All rights reserved.
 + *
 + *
 + * Contributor(s): Blender Foundation
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +#include <string.h>
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_path_util.h"
 +#include "BLI_string.h"
 +#include "BLI_listbase.h"
 +
 +#include "DNA_object_types.h"
 +#include "DNA_mesh_types.h"
 +#include "DNA_workspace_types.h"
 +
 +#include "BKE_context.h"
 +#include "BKE_customdata.h"
 +#include "BKE_editmesh.h"
 +#include "BKE_object.h"
 +#include "BKE_object_facemap.h"
 +#include "BKE_object_deform.h"
 +
 +#include "DEG_depsgraph.h"
 +
 +#include "RNA_define.h"
 +#include "RNA_access.h"
 +
 +#include "WM_types.h"
 +#include "WM_api.h"
 +
 +#include "ED_mesh.h"
 +#include "ED_object.h"
 +
 +#include "object_intern.h"
 +
 +/* called while not in editmode */
 +void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum)
 +{
 +      int fmap_nr;
 +      if (GS(((ID *)ob->data)->name) != ID_ME)
 +              return;
 +
 +      /* get the face map number, exit if it can't be found */
 +      fmap_nr = BLI_findindex(&ob->fmaps, fmap);
 +
 +      if (fmap_nr != -1) {
 +              int *facemap;
 +              Mesh *me = ob->data;
 +
 +              /* if there's is no facemap layer then create one */
 +              if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL)
 +                      facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly);
 +
 +              facemap[facenum] = fmap_nr;
 +      }
 +}
 +
 +/* called while not in editmode */
 +void ED_object_facemap_face_remove(Object *ob, bFaceMap *fmap, int facenum)
 +{
 +      int fmap_nr;
 +      if (GS(((ID *)ob->data)->name) != ID_ME)
 +              return;
 +
 +      /* get the face map number, exit if it can't be found */
 +      fmap_nr = BLI_findindex(&ob->fmaps, fmap);
 +
 +      if (fmap_nr != -1) {
 +              int *facemap;
 +              Mesh *me = ob->data;
 +
 +              /* if there's is no facemap layer then create one */
 +              if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL)
 +                      return;
 +
 +              facemap[facenum] = -1;
 +      }
 +}
 +
 +static void object_fmap_swap_edit_mode(Object *ob, int num1, int num2)
 +{
 +      if (ob->type == OB_MESH) {
 +              Mesh *me = ob->data;
 +
 +              if (me->edit_btmesh) {
 +                      BMEditMesh *em = me->edit_btmesh;
 +                      const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
 +
 +                      if (cd_fmap_offset != -1) {
 +                              BMFace *efa;
 +                              BMIter iter;
 +                              int *map;
 +
 +                              BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 +                                      map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
 +
 +                                      if (map) {
 +                                              if (num1 != -1) {
 +                                                      if (*map == num1)
 +                                                              *map = num2;
 +                                                      else if (*map == num2)
 +                                                              *map = num1;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +static void object_fmap_swap_object_mode(Object *ob, int num1, int num2)
 +{
 +      if (ob->type == OB_MESH) {
 +              Mesh *me = ob->data;
 +
 +              if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
 +                      int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP);
 +                      int i;
 +
 +                      if (map) {
 +                              for (i = 0; i < me->totpoly; i++) {
 +                                      if (num1 != -1) {
 +                                              if (map[i] == num1)
 +                                                      map[i] = num2;
 +                                              else if (map[i] == num2)
 +                                                      map[i] = num1;
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +static void object_facemap_swap(Object *ob, int num1, int num2)
 +{
 +      if (BKE_object_is_in_editmode(ob))
 +              object_fmap_swap_edit_mode(ob, num1, num2);
 +      else
 +              object_fmap_swap_object_mode(ob, num1, num2);
 +}
 +
- static int face_map_supported_edit_mode_poll(bContext *C)
++static bool face_map_supported_poll(bContext *C)
 +{
 +      Object *ob = ED_object_context(C);
 +      ID *data = (ob) ? ob->data : NULL;
 +      return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib);
 +}
 +
++static bool face_map_supported_edit_mode_poll(bContext *C)
 +{
 +      Object *ob = ED_object_context(C);
 +      ID *data = (ob) ? ob->data : NULL;
 +      if (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib) {
 +              if (ob->mode == OB_MODE_EDIT) {
 +                      return true;
 +              }
 +      }
 +      return false;
 +}
 +
 +static int face_map_add_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Object *ob = ED_object_context(C);
 +
 +      BKE_object_facemap_add(ob);
 +      DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
 +      WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OBJECT_OT_face_map_add(struct wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Add Face Map";
 +      ot->idname = "OBJECT_OT_face_map_add";
 +      ot->description = "Add a new face map to the active object";
 +
 +      /* api callbacks */
 +      ot->poll = face_map_supported_poll;
 +      ot->exec = face_map_add_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +static int face_map_remove_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Object *ob = ED_object_context(C);
 +      bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
 +
 +      if (fmap) {
 +              BKE_object_facemap_remove(ob, fmap);
 +              DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +              WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
 +              WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
 +      }
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OBJECT_OT_face_map_remove(struct wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Remove Face Map";
 +      ot->idname = "OBJECT_OT_face_map_remove";
 +      ot->description = "Remove a face map from the active object";
 +
 +      /* api callbacks */
 +      ot->poll = face_map_supported_poll;
 +      ot->exec = face_map_remove_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +static int face_map_assign_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Object *ob = ED_object_context(C);
 +      bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
 +
 +      if (fmap) {
 +              Mesh *me = ob->data;
 +              BMEditMesh *em = me->edit_btmesh;
 +              BMFace *efa;
 +              BMIter iter;
 +              int *map;
 +              int cd_fmap_offset;
 +
 +              if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP))
 +                      BM_data_layer_add(em->bm, &em->bm->pdata, CD_FACEMAP);
 +
 +              cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
 +
 +              BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 +                      map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
 +
 +                      if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
 +                              *map = ob->actfmap - 1;
 +                      }
 +              }
 +
 +              DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +              WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
 +              WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
 +      }
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OBJECT_OT_face_map_assign(struct wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Assign Face Map";
 +      ot->idname = "OBJECT_OT_face_map_assign";
 +      ot->description = "Assign faces to a face map";
 +
 +      /* api callbacks */
 +      ot->poll = face_map_supported_edit_mode_poll;
 +      ot->exec = face_map_assign_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +static int face_map_remove_from_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Object *ob = ED_object_context(C);
 +      bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
 +
 +      if (fmap) {
 +              Mesh *me = ob->data;
 +              BMEditMesh *em = me->edit_btmesh;
 +              BMFace *efa;
 +              BMIter iter;
 +              int *map;
 +              int cd_fmap_offset;
 +              int mapindex = ob->actfmap - 1;
 +
 +              if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP))
 +                      return OPERATOR_CANCELLED;
 +
 +              cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
 +
 +              BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 +                      map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
 +
 +                      if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && *map == mapindex) {
 +                              *map = -1;
 +                      }
 +              }
 +
 +              DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +              WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
 +              WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
 +      }
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OBJECT_OT_face_map_remove_from(struct wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Remove From Face Map";
 +      ot->idname = "OBJECT_OT_face_map_remove_from";
 +      ot->description = "Remove faces from a face map";
 +
 +      /* api callbacks */
 +      ot->poll = face_map_supported_edit_mode_poll;
 +      ot->exec = face_map_remove_from_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +static void fmap_select(Object *ob, bool select)
 +{
 +      Mesh *me = ob->data;
 +      BMEditMesh *em = me->edit_btmesh;
 +      BMFace *efa;
 +      BMIter iter;
 +      int *map;
 +      int cd_fmap_offset;
 +      int mapindex = ob->actfmap - 1;
 +
 +      if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP))
 +              BM_data_layer_add(em->bm, &em->bm->pdata, CD_FACEMAP);
 +
 +      cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
 +
 +      BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 +              map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
 +
 +              if (*map == mapindex) {
 +                      BM_face_select_set(em->bm, efa, select);
 +              }
 +      }
 +}
 +
 +static int face_map_select_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Object *ob = ED_object_context(C);
 +      bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
 +
 +      if (fmap) {
 +              fmap_select(ob, true);
 +
 +              DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +              WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
 +              WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
 +      }
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OBJECT_OT_face_map_select(struct wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Select Face Map Faces";
 +      ot->idname = "OBJECT_OT_face_map_select";
 +      ot->description = "Select faces belonging to a face map";
 +
 +      /* api callbacks */
 +      ot->poll = face_map_supported_edit_mode_poll;
 +      ot->exec = face_map_select_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +static int face_map_deselect_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Object *ob = ED_object_context(C);
 +      bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
 +
 +      if (fmap) {
 +              fmap_select(ob, false);
 +
 +              DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +              WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
 +              WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
 +      }
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OBJECT_OT_face_map_deselect(struct wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Deselect Face Map Faces";
 +      ot->idname = "OBJECT_OT_face_map_deselect";
 +      ot->description = "Deselect faces belonging to a face map";
 +
 +      /* api callbacks */
 +      ot->poll = face_map_supported_edit_mode_poll;
 +      ot->exec = face_map_deselect_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +
 +static int face_map_move_exec(bContext *C, wmOperator *op)
 +{
 +      Object *ob = ED_object_context(C);
 +      bFaceMap *fmap;
 +      int dir = RNA_enum_get(op->ptr, "direction");
 +      int pos1, pos2 = -1, count;
 +
 +      fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
 +      if (!fmap) {
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      count = BLI_listbase_count(&ob->fmaps);
 +      pos1 = BLI_findindex(&ob->fmaps, fmap);
 +
 +      if (dir == 1) { /*up*/
 +              void *prev = fmap->prev;
 +
 +              if (prev) {
 +                      pos2 = pos1 - 1;
 +              }
 +              else {
 +                      pos2 = count - 1;
 +              }
 +
 +              BLI_remlink(&ob->fmaps, fmap);
 +              BLI_insertlinkbefore(&ob->fmaps, prev, fmap);
 +      }
 +      else { /*down*/
 +              void *next = fmap->next;
 +
 +              if (next) {
 +                      pos2 = pos1 + 1;
 +              }
 +              else {
 +                      pos2 = 0;
 +              }
 +
 +              BLI_remlink(&ob->fmaps, fmap);
 +              BLI_insertlinkafter(&ob->fmaps, next, fmap);
 +      }
 +
 +      /* iterate through mesh and substitute the indices as necessary */
 +      object_facemap_swap(ob, pos2, pos1);
 +
 +      ob->actfmap = pos2 + 1;
 +
 +      DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +
 +void OBJECT_OT_face_map_move(wmOperatorType *ot)
 +{
 +      static EnumPropertyItem fmap_slot_move[] = {
 +              {1, "UP", 0, "Up", ""},
 +              {-1, "DOWN", 0, "Down", ""},
 +              {0, NULL, 0, NULL, NULL}
 +      };
 +
 +      /* identifiers */
 +      ot->name = "Move Face Map";
 +      ot->idname = "OBJECT_OT_face_map_move";
 +      ot->description = "Move the active face map up/down in the list";
 +
 +      /* api callbacks */
 +      ot->poll = face_map_supported_poll;
 +      ot->exec = face_map_move_exec;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      RNA_def_enum(ot->srna, "direction", fmap_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
 +}
index ce3d6eff7b40499b2cf97a34aa6f5c0d2c7d1071,f962f83844b6ad14d14b65fc2ee2c5eb9b7d540d..b1ea6d723467981946aa0e6757094cf1ca50ea87
@@@ -138,15 -141,15 +138,15 @@@ void OBJECT_OT_hook_reset(struct wmOper
  void OBJECT_OT_hook_recenter(struct wmOperatorType *ot);
  
  /* object_group.c */
 -void GROUP_OT_create(struct wmOperatorType *ot);
 -void GROUP_OT_objects_remove_all(struct wmOperatorType *ot);
 -void GROUP_OT_objects_remove(struct wmOperatorType *ot);
 -void GROUP_OT_objects_add_active(struct wmOperatorType *ot);
 -void GROUP_OT_objects_remove_active(struct wmOperatorType *ot);
 +void COLLECTION_OT_create(struct wmOperatorType *ot);
 +void COLLECTION_OT_objects_remove_all(struct wmOperatorType *ot);
 +void COLLECTION_OT_objects_remove(struct wmOperatorType *ot);
 +void COLLECTION_OT_objects_add_active(struct wmOperatorType *ot);
 +void COLLECTION_OT_objects_remove_active(struct wmOperatorType *ot);
  
  /* object_modifier.c */
int edit_modifier_poll_generic(struct bContext *C, struct StructRNA *rna_type, int obtype_flag);
int edit_modifier_poll(struct bContext *C);
bool edit_modifier_poll_generic(struct bContext *C, struct StructRNA *rna_type, int obtype_flag);
bool edit_modifier_poll(struct bContext *C);
  void edit_modifier_properties(struct wmOperatorType *ot);
  int edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op);
  struct ModifierData *edit_modifier_property_get(struct wmOperator *op, struct Object *ob, int type);
index 8db58b17520aa53a9b34f1ce1f3e4f8053558648,286a7e095817711ea937efd457e5d956505d05c7..324b6eca34ae92bd8089df7439cac8e8e46df9e7
@@@ -2207,220 -2405,6 +2207,220 @@@ void OBJECT_OT_make_local(wmOperatorTyp
        ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
  }
  
- static int make_override_static_poll(bContext *C)
 +
 +static void make_override_static_tag_object(Object *obact, Object *ob)
 +{
 +      if (ob == obact) {
 +              return;
 +      }
 +
 +      if (!ID_IS_LINKED(ob)) {
 +              return;
 +      }
 +
 +      /* Note: all this is very case-by-case bad handling, ultimately we'll want a real full 'automatic', generic
 +       * handling of all this, will probably require adding some override-aware stuff to library_query code... */
 +
 +      if (obact->type == OB_ARMATURE && ob->modifiers.first != NULL) {
 +              for (ModifierData *md = ob->modifiers.first; md != NULL; md = md->next) {
 +                      if (md->type == eModifierType_Armature) {
 +                              ArmatureModifierData *amd = (ArmatureModifierData *)md;
 +                              if (amd->object == obact) {
 +                                      ob->id.tag |= LIB_TAG_DOIT;
 +                                      break;
 +                              }
 +                      }
 +              }
 +      }
 +      else if (ob->parent == obact) {
 +              ob->id.tag |= LIB_TAG_DOIT;
 +      }
 +
 +      if (ob->id.tag & LIB_TAG_DOIT) {
 +              printf("Indirectly overriding %s for %s\n", ob->id.name, obact->id.name);
 +      }
 +}
 +
 +/* Set the object to override. */
 +static int make_override_static_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obact = ED_object_active_context(C);
 +
 +      /* Sanity checks. */
 +      if (!scene || ID_IS_LINKED(scene) || !obact) {
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      /* Get object to work on - use a menu if we need to... */
 +      if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) {
 +              /* Gives menu with list of objects in group. */
 +              WM_enum_search_invoke(C, op, event);
 +              return OPERATOR_CANCELLED;
 +      }
 +      else if (ID_IS_LINKED(obact)) {
 +              uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION);
 +              uiLayout *layout = UI_popup_menu_layout(pup);
 +
 +              /* Create operator menu item with relevant properties filled in. */
 +              PointerRNA opptr_dummy;
 +              uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL,
 +                              WM_OP_EXEC_REGION_WIN, 0, &opptr_dummy);
 +
 +              /* Present the menu and be done... */
 +              UI_popup_menu_end(C, pup);
 +
 +              /* This invoke just calls another instance of this operator... */
 +              return OPERATOR_INTERFACE;
 +      }
 +      else {
 +              /* Error.. cannot continue. */
 +              BKE_report(op->reports, RPT_ERROR, "Can only make static override for a referenced object or collection");
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +}
 +
 +static int make_override_static_exec(bContext *C, wmOperator *op)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      Object *obact = CTX_data_active_object(C);
 +
 +      bool success = false;
 +
 +      if (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group)) {
 +              const ListBase dup_collection_objects = BKE_collection_object_cache_get(obact->dup_group);
 +              Base *base = BLI_findlink(&dup_collection_objects, RNA_enum_get(op->ptr, "object"));
 +              Object *obcollection = obact;
 +              obact = base->object;
 +              Collection *collection = obcollection->dup_group;
 +
 +              /* First, we make a static override of the linked collection itself. */
 +              collection->id.tag |= LIB_TAG_DOIT;
 +
 +              /* Then, we make static override of the whole set of objects in the Collection. */
 +              FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, ob)
 +              {
 +                      ob->id.tag |= LIB_TAG_DOIT;
 +              }
 +              FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
 +
 +              /* Then, we remove (untag) bone shape objects, you shall never want to override those (hopefully)... */
 +              FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(collection, ob)
 +              {
 +                      if (ob->type == OB_ARMATURE && ob->pose != NULL) {
 +                              for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
 +                                      if (pchan->custom != NULL) {
 +                                              pchan->custom->id.tag &= ~ LIB_TAG_DOIT;
 +                                      }
 +                              }
 +                      }
 +              }
 +              FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
 +
 +              success = BKE_override_static_create_from_tag(bmain);
 +
 +              /* Intantiate our newly overridden objects in scene, if not yet done. */
 +              Scene *scene = CTX_data_scene(C);
 +              ViewLayer *view_layer = CTX_data_view_layer(C);
 +              Collection *new_collection = (Collection *)collection->id.newid;
 +              FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(new_collection, new_ob)
 +              {
 +                      if (new_ob != NULL && new_ob->id.override_static != NULL) {
 +                              if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) {
 +                                      BKE_collection_object_add_from(bmain, scene, obcollection, new_ob);
 +                                      DEG_id_tag_update_ex(bmain, &new_ob->id, DEG_TAG_TRANSFORM | DEG_TAG_BASE_FLAGS_UPDATE);
 +                              }
 +                              /* parent to 'collection' empty */
 +                              if (new_ob->parent == NULL) {
 +                                      new_ob->parent = obcollection;
 +                              }
 +                              if (new_ob == (Object *)obact->id.newid) {
 +                                      BKE_view_layer_base_select(view_layer, base);
 +                              }
 +                              else {
 +                                      /* Disable auto-override tags for non-active objects, will help with performaces... */
 +                                      new_ob->id.override_static->flag &= ~STATICOVERRIDE_AUTO;
 +                              }
 +                              /* We still want to store all objects' current override status (i.e. change of parent). */
 +                              BKE_override_static_operations_create(bmain, &new_ob->id, true);
 +                      }
 +              }
 +              FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
 +
 +              /* obcollection is no more duplicollection-ing, it merely parents whole collection of overriding instantiated objects. */
 +              obcollection->dup_group = NULL;
 +
 +              /* Also, we'd likely want to lock by default things like transformations of implicitly overriden objects? */
 +
 +              DEG_id_tag_update(&scene->id, 0);
 +
 +              /* Cleanup. */
 +              BKE_main_id_clear_newpoins(bmain);
 +              BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false);
 +      }
 +      /* Else, poll func ensures us that ID_IS_LINKED(obact) is true. */
 +      else if (obact->type == OB_ARMATURE) {
 +              BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
 +
 +              obact->id.tag |= LIB_TAG_DOIT;
 +
 +              for (Object *ob = bmain->object.first; ob != NULL; ob = ob->id.next) {
 +                      make_override_static_tag_object(obact, ob);
 +              }
 +
 +              success = BKE_override_static_create_from_tag(bmain);
 +
 +              /* Also, we'd likely want to lock by default things like transformations of implicitly overriden objects? */
 +
 +              /* Cleanup. */
 +              BKE_main_id_clear_newpoins(bmain);
 +              BKE_main_id_tag_listbase(&bmain->object, LIB_TAG_DOIT, false);
 +      }
 +      /* TODO: probably more cases where we want to do automated smart things in the future! */
 +      else {
 +              success = (BKE_override_static_create_from_id(bmain, &obact->id) != NULL);
 +      }
 +
 +      WM_event_add_notifier(C, NC_WINDOW, NULL);
 +
 +      return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 +}
 +
++static bool make_override_static_poll(bContext *C)
 +{
 +      Object *obact = CTX_data_active_object(C);
 +
 +      /* Object must be directly linked to be overridable. */
 +      return (ED_operator_objectmode(C) && obact != NULL &&
 +              ((ID_IS_LINKED(obact) && obact->id.tag & LIB_TAG_EXTERN) ||
 +               (!ID_IS_LINKED(obact) && obact->dup_group != NULL && ID_IS_LINKED(obact->dup_group))));
 +}
 +
 +void OBJECT_OT_make_override_static(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Make Static Override";
 +      ot->description = "Make local override of this library linked data-block";
 +      ot->idname = "OBJECT_OT_make_override_static";
 +
 +      /* api callbacks */
 +      ot->invoke = make_override_static_invoke;
 +      ot->exec = make_override_static_exec;
 +      ot->poll = make_override_static_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      /* properties */
 +      PropertyRNA *prop;
 +      prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Override Object",
 +                          "Name of lib-linked/collection object to make an override from");
 +      RNA_def_enum_funcs(prop, proxy_collection_object_itemf);
 +      RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
 +      ot->prop = prop;
 +}
 +
  enum {
        MAKE_SINGLE_USER_ALL      = 1,
        MAKE_SINGLE_USER_SELECTED = 2,
index f4777eea9996d269abb25cabfb0fd63434eaa761,73ed8b016efd6476fb4f0c6ee7891357e1799daa..e637a58e8c6462aa8d09e599eefa653342b4d5d1
  
  /**************************** utilities *******************************/
  
int PE_poll(bContext *C)
bool PE_poll(bContext *C)
  {
 -      Main *bmain = CTX_data_main(C);
        Scene *scene= CTX_data_scene(C);
        Object *ob= CTX_data_active_object(C);
  
 -      if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
 +      if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) {
                return 0;
 -
 -      return (PE_get_current(bmain, scene, ob) != NULL);
 +      }
 +      return (PE_get_current(scene, ob) != NULL);
  }
  
int PE_hair_poll(bContext *C)
bool PE_hair_poll(bContext *C)
  {
 -      Main *bmain = CTX_data_main(C);
        Scene *scene= CTX_data_scene(C);
        Object *ob= CTX_data_active_object(C);
        PTCacheEdit *edit;
index 3d67095263fb66e654d54f9d8c620b6f679af265,5b198774b715ec16d8a6a8aef52dc1018e3633dc..31f25720f8d07a297a19dd00a028fa7c6aba9240
@@@ -886,11 -893,12 +886,11 @@@ void SCENE_OT_freestyle_lineset_add(wmO
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
  }
  
- static int freestyle_active_lineset_poll(bContext *C)
+ static bool freestyle_active_lineset_poll(bContext *C)
  {
 -      Scene *scene = CTX_data_scene(C);
 -      SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
  
 -      if (!srl) {
 +      if (!view_layer) {
                return false;
        }
  
index ad64018929c463f276ef4a526dde3a080a3c03dd,411469b539bfa53b1148bd127fe720c4ef051a18..c6041d830b1b2d492b54e7f543ab95f3c2651009
@@@ -216,7 -208,12 +216,7 @@@ bool ED_operator_animview_active(bConte
        return 0;
  }
  
- int ED_operator_outliner_active(bContext *C)
 -bool ED_operator_timeline_active(bContext *C)
 -{
 -      return ed_spacetype_test(C, SPACE_TIME);
 -}
 -
+ bool ED_operator_outliner_active(bContext *C)
  {
        return ed_spacetype_test(C, SPACE_OUTLINER);
  }
@@@ -294,7 -291,12 +294,7 @@@ bool ED_operator_nla_active(bContext *C
        return ed_spacetype_test(C, SPACE_NLA);
  }
  
- int ED_operator_info_active(bContext *C)
 -bool ED_operator_logic_active(bContext *C)
 -{
 -      return ed_spacetype_test(C, SPACE_LOGIC);
 -}
 -
+ bool ED_operator_info_active(bContext *C)
  {
        return ed_spacetype_test(C, SPACE_INFO);
  }
@@@ -559,12 -561,6 +559,12 @@@ bool ED_operator_mask(bContext *C
        return false;
  }
  
- int ED_operator_camera(bContext *C)
++bool ED_operator_camera(bContext *C)
 +{
 +      struct Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
 +      return (cam != NULL);
 +}
 +
  /** \} */
  
  /* -------------------------------------------------------------------- */
@@@ -2787,15 -2634,6 +2787,15 @@@ static int screen_maximize_area_exec(bC
        return OPERATOR_FINISHED;
  }
  
- static int screen_maximize_area_poll(bContext *C)
++static bool screen_maximize_area_poll(bContext *C)
 +{
 +      const bScreen *screen = CTX_wm_screen(C);
 +      const ScrArea *area = CTX_wm_area(C);
 +      return ED_operator_areaactive(C) &&
 +              /* Don't allow maximizing global areas but allow minimizing from them. */
 +             ((screen->state != SCREENNORMAL) || !ED_area_is_global(area));
 +}
 +
  static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
  {
        PropertyRNA *prop;
@@@ -3522,18 -3360,6 +3522,18 @@@ static int region_flip_exec(bContext *C
        return OPERATOR_FINISHED;
  }
  
- static int region_flip_poll(bContext *C)
++static bool region_flip_poll(bContext *C)
 +{
 +      ScrArea *area = CTX_wm_area(C);
 +
 +      /* don't flip anything around in topbar */
 +      if (area->spacetype == SPACE_TOPBAR) {
 +              CTX_wm_operator_poll_msg_set(C, "Flipping regions in the Top-bar is not allowed");
 +              return 0;
 +      }
 +
 +      return ED_operator_areaactive(C);
 +}
  
  static void SCREEN_OT_region_flip(wmOperatorType *ot)
  {
index 387cd7df998284f0c175dac25bba688ebf3519fc,dda75877f50a8401a5d3883e92a157d78c918341..afaad3963d577f44c04549380991f5789fab4c01
@@@ -266,10 -266,10 +266,10 @@@ static void screenshot_draw(bContext *U
  
        /* main draw call */
        RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
 -      uiDefAutoButsRNA(layout, &ptr, screenshot_draw_check_prop, '\0');
 +      uiDefAutoButsRNA(layout, &ptr, screenshot_draw_check_prop, UI_BUT_LABEL_ALIGN_NONE, false);
  }
  
- static int screenshot_poll(bContext *C)
+ static bool screenshot_poll(bContext *C)
  {
        if (G.background)
                return false;
index a044a7d377a0619b70a40be376c88a7cd60cd8cd,0000000000000000000000000000000000000000..9d3293555004d68071d3f6b88548fab598f78fa1
mode 100644,000000..100644
--- /dev/null
@@@ -1,508 -1,0 +1,508 @@@
- static int workspace_append_activate_poll(bContext *C)
 +/*
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file blender/editors/screen/workspace_edit.c
 + *  \ingroup edscr
 + */
 +
 +#include <stdlib.h>
 +#include <string.h>
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_fileops.h"
 +#include "BLI_listbase.h"
 +#include "BLI_path_util.h"
 +#include "BLI_string.h"
 +
 +#include "BKE_appdir.h"
 +#include "BKE_blendfile.h"
 +#include "BKE_context.h"
 +#include "BKE_idcode.h"
 +#include "BKE_main.h"
 +#include "BKE_layer.h"
 +#include "BKE_library.h"
 +#include "BKE_report.h"
 +#include "BKE_scene.h"
 +#include "BKE_screen.h"
 +#include "BKE_workspace.h"
 +
 +#include "BLO_readfile.h"
 +
 +#include "DNA_object_types.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_windowmanager_types.h"
 +#include "DNA_workspace_types.h"
 +
 +#include "ED_object.h"
 +#include "ED_screen.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "RNA_access.h"
 +#include "RNA_define.h"
 +
 +#include "DEG_depsgraph.h"
 +
 +#include "UI_interface.h"
 +#include "UI_resources.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +#include "WM_toolsystem.h"
 +
 +#include "screen_intern.h"
 +
 +
 +/** \name Workspace API
 + *
 + * \brief API for managing workspaces and their data.
 + * \{ */
 +
 +WorkSpace *ED_workspace_add(
 +        Main *bmain, const char *name, Scene *scene,
 +        ViewLayer *act_view_layer)
 +{
 +      WorkSpace *workspace = BKE_workspace_add(bmain, name);
 +
 +      BKE_workspace_view_layer_set(workspace, act_view_layer, scene);
 +
 +      return workspace;
 +}
 +
 +/**
 + * Changes the object mode (if needed) to the one set in \a workspace_new.
 + * Object mode is still stored on object level. In future it should all be workspace level instead.
 + */
 +static void workspace_change_update_mode(
 +        const WorkSpace *workspace_old, const WorkSpace *workspace_new,
 +        bContext *C, Object *ob_act, ReportList *reports)
 +{
 +      UNUSED_VARS(workspace_old, workspace_new, C, ob_act, reports);
 +#if 0
 +      eObjectMode mode_old = workspace_old->object_mode;
 +      eObjectMode mode_new = workspace_new->object_mode;
 +
 +      if (mode_old != mode_new) {
 +              ED_object_mode_compat_set(C, ob_act, mode_new, reports);
 +              ED_object_mode_toggle(C, mode_new);
 +      }
 +#endif
 +}
 +
 +static void workspace_change_update_view_layer(
 +        WorkSpace *workspace_new, const WorkSpace *workspace_old,
 +        Scene *scene)
 +{
 +      if (!BKE_workspace_view_layer_exists(workspace_new, scene)) {
 +              BKE_workspace_view_layer_set(workspace_new, BKE_workspace_view_layer_get(workspace_old, scene), scene);
 +      }
 +}
 +
 +static void workspace_change_update(
 +        WorkSpace *workspace_new, const WorkSpace *workspace_old,
 +        bContext *C, wmWindowManager *wm)
 +{
 +      /* needs to be done before changing mode! (to ensure right context) */
 +      workspace_change_update_view_layer(workspace_new, workspace_old, CTX_data_scene(C));
 +      workspace_change_update_mode(workspace_old, workspace_new, C, CTX_data_active_object(C), &wm->reports);
 +}
 +
 +static bool workspace_change_find_new_layout_cb(const WorkSpaceLayout *layout, void *UNUSED(arg))
 +{
 +      /* return false to stop the iterator if we've found a layout that can be activated */
 +      return workspace_layout_set_poll(layout) ? false : true;
 +}
 +
 +static WorkSpaceLayout *workspace_change_get_new_layout(
 +        Main *bmain, WorkSpace *workspace_new, wmWindow *win)
 +{
 +      /* ED_workspace_duplicate may have stored a layout to activate once the workspace gets activated. */
 +      WorkSpaceLayout *layout_new;
 +      bScreen *screen_new;
 +
 +      if (win->workspace_hook->temp_workspace_store) {
 +              layout_new = win->workspace_hook->temp_layout_store;
 +      }
 +      else {
 +              layout_new = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, workspace_new);
 +              if (!layout_new) {
 +                      layout_new = BKE_workspace_layouts_get(workspace_new)->first;
 +              }
 +      }
 +      screen_new = BKE_workspace_layout_screen_get(layout_new);
 +
 +      if (screen_new->winid) {
 +              /* screen is already used, try to find a free one */
 +              WorkSpaceLayout *layout_temp = BKE_workspace_layout_iter_circular(
 +                                                 workspace_new, layout_new, workspace_change_find_new_layout_cb,
 +                                                 NULL, false);
 +              if (!layout_temp) {
 +                      /* fallback solution: duplicate layout */
 +                      layout_temp = ED_workspace_layout_duplicate(bmain, workspace_new, layout_new, win);
 +              }
 +              layout_new = layout_temp;
 +      }
 +
 +      return layout_new;
 +}
 +
 +/**
 + * \brief Change the active workspace.
 + *
 + * Operator call, WM + Window + screen already existed before
 + * Pretty similar to #ED_screen_change since changing workspace also changes screen.
 + *
 + * \warning Do NOT call in area/region queues!
 + * \returns if workspace changing was successful.
 + */
 +bool ED_workspace_change(
 +        WorkSpace *workspace_new, bContext *C, wmWindowManager *wm, wmWindow *win)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      WorkSpace *workspace_old = WM_window_get_active_workspace(win);
 +      WorkSpaceLayout *layout_new = workspace_change_get_new_layout(bmain, workspace_new, win);
 +      bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
 +      bScreen *screen_old = BKE_workspace_active_screen_get(win->workspace_hook);
 +
 +      win->workspace_hook->temp_layout_store = NULL;
 +      if (workspace_old == workspace_new) {
 +              /* Could also return true, everything that needs to be done was done (nothing :P), but nothing changed */
 +              return false;
 +      }
 +
 +      screen_new = screen_change_prepare(screen_old, screen_new, bmain, C, win);
 +      BLI_assert(BKE_workspace_layout_screen_get(layout_new) == screen_new);
 +
 +      if (screen_new) {
 +              WM_window_set_active_layout(win, workspace_new, layout_new);
 +              WM_window_set_active_workspace(win, workspace_new);
 +
 +              /* update screen *after* changing workspace - which also causes the
 +               * actual screen change and updates context (including CTX_wm_workspace) */
 +              screen_change_update(C, win, screen_new);
 +              workspace_change_update(workspace_new, workspace_old, C, wm);
 +
 +              BLI_assert(BKE_workspace_view_layer_exists(workspace_new, CTX_data_scene(C)) != NULL);
 +              BLI_assert(CTX_wm_workspace(C) == workspace_new);
 +
 +              WM_toolsystem_unlink_all(C, workspace_old);
 +              WM_toolsystem_reinit_all(C, win);
 +
 +              return true;
 +      }
 +
 +      return false;
 +}
 +
 +/**
 + * Duplicate a workspace including its layouts. Does not activate the workspace, but
 + * it stores the screen-layout to be activated (BKE_workspace_temp_layout_store)
 + */
 +WorkSpace *ED_workspace_duplicate(
 +        WorkSpace *workspace_old, Main *bmain, wmWindow *win)
 +{
 +      WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook);
 +      ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old);
 +      Scene *scene = WM_window_get_active_scene(win);
 +      WorkSpace *workspace_new = ED_workspace_add(
 +              bmain, workspace_old->id.name + 2, scene,
 +              BKE_workspace_view_layer_get(workspace_old, scene));
 +
 +      /* TODO(campbell): tools */
 +
 +      for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old; layout_old = layout_old->next) {
 +              WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace_new, layout_old, win);
 +
 +              if (layout_active_old == layout_old) {
 +                      win->workspace_hook->temp_layout_store = layout_new;
 +              }
 +      }
 +      return workspace_new;
 +}
 +
 +/**
 + * \return if succeeded.
 + */
 +bool ED_workspace_delete(
 +        WorkSpace *workspace, Main *bmain, bContext *C, wmWindowManager *wm)
 +{
 +      ID *workspace_id = (ID *)workspace;
 +
 +      if (BLI_listbase_is_single(&bmain->workspaces)) {
 +              return false;
 +      }
 +
 +      for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +              WorkSpace *prev = workspace_id->prev;
 +              WorkSpace *next = workspace_id->next;
 +
 +              ED_workspace_change((prev != NULL) ? prev : next, C, wm, win);
 +      }
 +      BKE_libblock_free(bmain, workspace_id);
 +
 +      return true;
 +}
 +
 +/**
 + * Some editor data may need to be synced with scene data (3D View camera and layers).
 + * This function ensures data is synced for editors in active layout of \a workspace.
 + */
 +void ED_workspace_scene_data_sync(
 +        WorkSpaceInstanceHook *hook, Scene *scene)
 +{
 +      bScreen *screen = BKE_workspace_active_screen_get(hook);
 +      BKE_screen_view3d_scene_sync(screen, scene);
 +}
 +
 +void ED_workspace_view_layer_unset(
 +        const Main *bmain, Scene *scene,
 +        const ViewLayer *layer_unset, ViewLayer *layer_new)
 +{
 +      for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
 +              if (BKE_workspace_view_layer_get(workspace, scene) == layer_unset) {
 +                      BKE_workspace_view_layer_set(workspace, layer_new, scene);
 +              }
 +      }
 +}
 +
 +/** \} Workspace API */
 +
 +
 +/** \name Workspace Operators
 + *
 + * \{ */
 +
 +static int workspace_new_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Main *bmain = CTX_data_main(C);
 +      wmWindow *win = CTX_wm_window(C);
 +      WorkSpace *workspace = ED_workspace_duplicate(WM_window_get_active_workspace(win), bmain, win);
 +
 +      WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, workspace);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +static void WORKSPACE_OT_workspace_duplicate(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "New Workspace";
 +      ot->description = "Add a new workspace";
 +      ot->idname = "WORKSPACE_OT_workspace_duplicate";
 +
 +      /* api callbacks */
 +      ot->exec = workspace_new_exec;
 +      ot->poll = WM_operator_winactive;
 +}
 +
 +static int workspace_delete_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      wmWindow *win = CTX_wm_window(C);
 +
 +      WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_DELETE, WM_window_get_active_workspace(win));
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +static void WORKSPACE_OT_workspace_delete(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Delete Workspace";
 +      ot->description = "Delete the active workspace";
 +      ot->idname = "WORKSPACE_OT_workspace_delete";
 +
 +      /* api callbacks */
 +      ot->exec = workspace_delete_exec;
 +}
 +
++static bool workspace_append_activate_poll(bContext *C)
 +{
 +      wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false);
 +      return WM_operator_poll(C, ot);
 +}
 +
 +static int workspace_append(bContext *C, const char *directory, const char *idname)
 +{
 +      wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false);
 +      PointerRNA opptr;
 +      int retval;
 +
 +      WM_operator_properties_create_ptr(&opptr, ot);
 +      RNA_string_set(&opptr, "directory", directory);
 +      RNA_string_set(&opptr, "filename", idname);
 +      RNA_boolean_set(&opptr, "autoselect", false);
 +
 +      retval = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &opptr);
 +
 +      WM_operator_properties_free(&opptr);
 +
 +      return retval;
 +}
 +
 +static int workspace_append_activate_exec(bContext *C, wmOperator *op)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      char idname[MAX_ID_NAME - 2], directory[FILE_MAX];
 +
 +      if (!RNA_struct_property_is_set(op->ptr, "idname") ||
 +          !RNA_struct_property_is_set(op->ptr, "directory"))
 +      {
 +              return OPERATOR_CANCELLED;
 +      }
 +      RNA_string_get(op->ptr, "idname", idname);
 +      RNA_string_get(op->ptr, "directory", directory);
 +
 +      if (workspace_append(C, directory, idname) != OPERATOR_CANCELLED) {
 +              WorkSpace *appended_workspace = BLI_findstring(&bmain->workspaces, idname, offsetof(ID, name) + 2);
 +
 +              BLI_assert(appended_workspace != NULL);
 +              /* Changing workspace changes context. Do delayed! */
 +              WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace);
 +
 +              return OPERATOR_FINISHED;
 +      }
 +
 +      return OPERATOR_CANCELLED;
 +}
 +
 +static void WORKSPACE_OT_append_activate(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Append and Activate Workspace";
 +      ot->description = "Append a workspace and make it the active one in the current window";
 +      ot->idname = "WORKSPACE_OT_append_activate";
 +
 +      /* api callbacks */
 +      ot->exec = workspace_append_activate_exec;
 +      ot->poll = workspace_append_activate_poll;
 +
 +      RNA_def_string(ot->srna, "idname", NULL, MAX_ID_NAME - 2, "Identifier",
 +                     "Name of the workspace to append and activate");
 +      RNA_def_string(ot->srna, "directory", NULL, FILE_MAX, "Directory",
 +                     "Path to the library");
 +}
 +
 +static void workspace_config_file_path_from_folder_id(
 +        const Main *bmain, int folder_id, char *r_path)
 +{
 +      const char *app_template = U.app_template[0] ? U.app_template : NULL;
 +      const char * const cfgdir = BKE_appdir_folder_id(folder_id, app_template);
 +
 +      if (cfgdir) {
 +              BLI_make_file_string(bmain->name, r_path, cfgdir, BLENDER_WORKSPACES_FILE);
 +      }
 +      else {
 +              r_path[0] = '\0';
 +      }
 +}
 +
 +ATTR_NONNULL(1)
 +static WorkspaceConfigFileData *workspace_config_file_read(
 +        const Main *bmain, ReportList *reports)
 +{
 +      char workspace_config_path[FILE_MAX];
 +      bool has_path = false;
 +
 +      workspace_config_file_path_from_folder_id(bmain, BLENDER_USER_CONFIG, workspace_config_path);
 +      if (BLI_exists(workspace_config_path)) {
 +              has_path = true;
 +      }
 +      else {
 +              workspace_config_file_path_from_folder_id(bmain, BLENDER_DATAFILES, workspace_config_path);
 +              if (BLI_exists(workspace_config_path)) {
 +                      has_path = true;
 +              }
 +      }
 +
 +      return has_path ? BKE_blendfile_workspace_config_read(workspace_config_path, reports) : NULL;
 +}
 +
 +static void workspace_append_button(
 +        uiLayout *layout, wmOperatorType *ot_append, const WorkSpace *workspace, const Main *from_main)
 +{
 +      const ID *id = (ID *)workspace;
 +      PointerRNA opptr;
 +      char lib_path[FILE_MAX_LIBEXTRA];
 +
 +      BLI_path_join(
 +              lib_path, sizeof(lib_path), from_main->name, BKE_idcode_to_name(GS(id->name)), NULL);
 +
 +      BLI_assert(STREQ(ot_append->idname, "WORKSPACE_OT_append_activate"));
 +      uiItemFullO_ptr(
 +              layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL,
 +              WM_OP_EXEC_DEFAULT, 0, &opptr);
 +      RNA_string_set(&opptr, "idname", id->name + 2);
 +      RNA_string_set(&opptr, "directory", lib_path);
 +}
 +
 +ATTR_NONNULL(1, 2)
 +static void workspace_config_file_append_buttons(
 +        uiLayout *layout, const Main *bmain, ReportList *reports)
 +{
 +      WorkspaceConfigFileData *workspace_config = workspace_config_file_read(bmain, reports);
 +
 +      if (workspace_config) {
 +              wmOperatorType *ot_append = WM_operatortype_find("WORKSPACE_OT_append_activate", true);
 +
 +              for (WorkSpace *workspace = workspace_config->workspaces.first; workspace; workspace = workspace->id.next) {
 +                      workspace_append_button(layout, ot_append, workspace, workspace_config->main);
 +              }
 +
 +              BKE_blendfile_workspace_config_data_free(workspace_config);
 +      }
 +}
 +
 +static int workspace_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
 +{
 +      const Main *bmain = CTX_data_main(C);
 +
 +      uiPopupMenu *pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE);
 +      uiLayout *layout = UI_popup_menu_layout(pup);
 +
 +      uiItemO(layout, "Duplicate Current", ICON_NONE, "WORKSPACE_OT_workspace_duplicate");
 +      uiItemS(layout);
 +      workspace_config_file_append_buttons(layout, bmain, op->reports);
 +
 +      UI_popup_menu_end(C, pup);
 +
 +      return OPERATOR_INTERFACE;
 +}
 +
 +static void WORKSPACE_OT_workspace_add_menu(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Add Workspace";
 +      ot->description = "Add a new workspace by duplicating the current one or appending one "
 +                        "from the user configuration";
 +      ot->idname = "WORKSPACE_OT_workspace_add_menu";
 +
 +      /* api callbacks */
 +      ot->invoke = workspace_add_invoke;
 +}
 +
 +void ED_operatortypes_workspace(void)
 +{
 +      WM_operatortype_append(WORKSPACE_OT_workspace_duplicate);
 +      WM_operatortype_append(WORKSPACE_OT_workspace_delete);
 +      WM_operatortype_append(WORKSPACE_OT_workspace_add_menu);
 +      WM_operatortype_append(WORKSPACE_OT_append_activate);
 +}
 +
 +/** \} Workspace Operators */
index e2dd043c0c3d3a32fc766157c2b3317738a9d8dc,3760dec96d0a2dab56c3a96796d0f38491284f11..02fd685719e72c938094d6f9b38dd96a5907310b
@@@ -268,7 -264,7 +268,7 @@@ static Brush *image_paint_brush(bContex
        return BKE_paint_brush(&settings->imapaint.paint);
  }
  
- static int image_paint_poll_ex(bContext *C, bool check_tool)
 -static bool image_paint_poll(bContext *C)
++static bool image_paint_poll_ex(bContext *C, bool check_tool)
  {
        Object *obact;
  
        return 0;
  }
  
- static int image_paint_poll(bContext *C)
++static bool image_paint_poll(bContext *C)
 +{
 +      return image_paint_poll_ex(C, true);
 +}
 +
- static int image_paint_ignore_tool_poll(bContext *C)
++static bool image_paint_ignore_tool_poll(bContext *C)
 +{
 +      return image_paint_poll_ex(C, false);
 +}
 +
- static int image_paint_2d_clone_poll(bContext *C)
+ static bool image_paint_2d_clone_poll(bContext *C)
  {
        Brush *brush = image_paint_brush(C);
  
index 8d94978f5c6522964baedbc8b870c9b34e28f158,8ba773a2fc838fd64c84a1a8748562d3ad4765a6..a7041a5e9eae33620518f0d9e53c854dc497f9a4
@@@ -93,12 -93,10 +93,12 @@@ void paint_cursor_start_explicit(struc
  void paint_cursor_delete_textures(void);
  
  /* paint_vertex.c */
- int weight_paint_poll(struct bContext *C);
- int weight_paint_poll_ignore_tool(bContext *C);
- int weight_paint_mode_poll(struct bContext *C);
- int vertex_paint_poll(struct bContext *C);
- int vertex_paint_poll_ignore_tool(struct bContext *C);
- int vertex_paint_mode_poll(struct bContext *C);
+ bool weight_paint_poll(struct bContext *C);
++bool weight_paint_poll_ignore_tool(bContext *C);
+ bool weight_paint_mode_poll(struct bContext *C);
+ bool vertex_paint_poll(struct bContext *C);
++bool vertex_paint_poll_ignore_tool(struct bContext *C);
+ bool vertex_paint_mode_poll(struct bContext *C);
  
  typedef void (*VPaintTransform_Callback)(const float col[3], const void *user_data, float r_col[3]);
  
index 47bcbdb4a0859980c0e944dd2de2e2da500b9be7,483c8a77ab549c7c2a8fc3741fb81023af069098..59a9ee8f0d21ab80d1d2087687dc86e998be13ad
@@@ -208,7 -204,7 +208,7 @@@ bool vertex_paint_mode_poll(bContext *C
        return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly;
  }
  
- static int vertex_paint_poll_ex(bContext *C, bool check_tool)
 -bool vertex_paint_poll(bContext *C)
++static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
  {
        if (vertex_paint_mode_poll(C) &&
            BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint))
        return 0;
  }
  
- int vertex_paint_poll(bContext *C)
++bool vertex_paint_poll(bContext *C)
 +{
 +      return vertex_paint_poll_ex(C, true);
 +}
 +
- int vertex_paint_poll_ignore_tool(bContext *C)
++bool vertex_paint_poll_ignore_tool(bContext *C)
 +{
 +      return vertex_paint_poll_ex(C, true);
 +}
 +
int weight_paint_mode_poll(bContext *C)
bool weight_paint_mode_poll(bContext *C)
  {
        Object *ob = CTX_data_active_object(C);
  
        return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totpoly;
  }
  
- static int weight_paint_poll_ex(bContext *C, bool check_tool)
 -bool weight_paint_poll(bContext *C)
++static bool weight_paint_poll_ex(bContext *C, bool check_tool)
  {
        Object *ob = CTX_data_active_object(C);
        ScrArea *sa;
        return 0;
  }
  
- int weight_paint_poll(bContext *C)
++bool weight_paint_poll(bContext *C)
 +{
 +      return weight_paint_poll_ex(C, true);
 +}
 +
- int weight_paint_poll_ignore_tool(bContext *C)
++bool weight_paint_poll_ignore_tool(bContext *C)
 +{
 +      return weight_paint_poll_ex(C, false);
 +}
 +
  static VPaint *new_vpaint(void)
  {
        VPaint *vp = MEM_callocN(sizeof(VPaint), "VPaint");
index 2a0d5baa5c32c6c6a4d773c611e2a27e1a3dc54f,22ca3275ff965c3f88955a4be7f25e460d3f057f..4162e6dec929d5c1ca2ae4739e6ca238c1bfa0ca
@@@ -1013,62 -955,6 +1013,62 @@@ static void graph_panel_drivers(const b
        MEM_freeN(ale);
  }
  
- static int graph_panel_drivers_popover_poll(const bContext *C, PanelType *UNUSED(pt))
 +/* ----------------------------------------------------------------- */
 +
 +/* poll to make this not show up in the graph editor, as this is only to be used as a popup elsewhere */
++static bool graph_panel_drivers_popover_poll(const bContext *C, PanelType *UNUSED(pt))
 +{
 +      return ED_operator_graphedit_active((bContext *)C) == false;
 +}
 +
 +/* popover panel for driver editing anywhere in ui */
 +static void graph_panel_drivers_popover(const bContext *C, Panel *pa)
 +{
 +      uiLayout *layout = pa->layout;
 +
 +      PointerRNA ptr = {{NULL}};
 +      PropertyRNA *prop = NULL;
 +      int index = -1;
 +      uiBut *but = NULL;
 +
 +      /* Get active property to show driver properties for */
 +      but = UI_context_active_but_prop_get((bContext *)C, &ptr, &prop, &index);
 +      if (but) {
 +              FCurve *fcu;
 +              bool driven, special;
 +
 +              fcu = rna_get_fcurve_context_ui((bContext *)C,
 +                                              &ptr, prop, index,
 +                                              NULL, NULL, &driven, &special);
 +
 +              /* Hack: Force all buttons in this panel to be able to know the driver button
 +               * this panel is getting spawned from, so that things like the "Open Drivers Editor"
 +               * button will work.
 +               */
 +              uiLayoutSetContextFromBut(layout, but);
 +
 +              /* Populate Panel - With a combination of the contents of the Driven and Driver panels */
 +              if (fcu) {
 +                      ID *id = ptr.id.data;
 +
 +                      /* Driven Property Settings */
 +                      uiItemL(layout, IFACE_("Driven Property:"), ICON_NONE);
 +                      graph_draw_driven_property_panel(pa->layout, id, fcu);
 +                      /* TODO: All vs Single */
 +
 +                      uiItemS(layout);
 +                      uiItemS(layout);
 +
 +                      /* Drivers Settings */
 +                      uiItemL(layout, IFACE_("Driver Settings:"), ICON_NONE);
 +                      graph_draw_driver_settings_panel(pa->layout, id, fcu, true);
 +              }
 +      }
 +
 +      /* Show drivers editor is always visible */
 +      uiItemO(layout, IFACE_("Show in Drivers Editor"), ICON_DRIVER, "SCREEN_OT_drivers_editor_show");
 +}
 +
  /* ******************* F-Modifiers ******************************** */
  /* All the drawing code is in editors/animation/fmodifier_ui.c */
  
index 4031159451268f03989fded83f9c6ddbefecc351,d9f66ef175adf911b14e43498e3c97f2969a35f6..3efdce3ea6d6492852fc11e6b91b83b55c1cfdcb
@@@ -3487,100 -3482,9 +3487,100 @@@ void IMAGE_OT_cycle_render_slot(wmOpera
        RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
  }
  
 +/********************* clear render slot operator *********************/
 +
 +static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      SpaceImage *sima = CTX_wm_space_image(C);
 +      Image *ima = CTX_data_edit_image(C);
 +
 +      if (!BKE_image_clear_renderslot(ima, &sima->iuser, ima->render_slot)) {
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Clear Render Slot";
 +      ot->idname = "IMAGE_OT_clear_render_slot";
 +      ot->description = "Clear the currently selected render slot";
 +
 +      /* api callbacks */
 +      ot->exec = image_clear_render_slot_exec;
 +      ot->poll = image_cycle_render_slot_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER;
 +}
 +
 +/********************* add render slot operator *********************/
 +
 +static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Image *ima = CTX_data_edit_image(C);
 +
 +      RenderSlot *slot = BKE_image_add_renderslot(ima, NULL);
 +      ima->render_slot = BLI_findindex(&ima->renderslots, slot);
 +
 +      WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void IMAGE_OT_add_render_slot(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Add Render Slot";
 +      ot->idname = "IMAGE_OT_add_render_slot";
 +      ot->description = "Add a new render slot";
 +
 +      /* api callbacks */
 +      ot->exec = image_add_render_slot_exec;
 +      ot->poll = image_cycle_render_slot_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER;
 +}
 +
 +/********************* remove render slot operator *********************/
 +
 +static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      SpaceImage *sima = CTX_wm_space_image(C);
 +      Image *ima = CTX_data_edit_image(C);
 +
 +      if (!BKE_image_remove_renderslot(ima, &sima->iuser, ima->render_slot)) {
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Remove Render Slot";
 +      ot->idname = "IMAGE_OT_remove_render_slot";
 +      ot->description = "Remove the current render slot";
 +
 +      /* api callbacks */
 +      ot->exec = image_remove_render_slot_exec;
 +      ot->poll = image_cycle_render_slot_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER;
 +}
 +
  /********************** change frame operator *********************/
  
- static int change_frame_poll(bContext *C)
+ static bool change_frame_poll(bContext *C)
  {
        /* prevent changes during render */
        if (G.is_rendering)
index b97cc13d71328f6066089d46996c2cdef1ebe5d3,0000000000000000000000000000000000000000..ad94615a0d22306a51312a599236fbdcb41f2e7d
mode 100644,000000..100644
--- /dev/null
@@@ -1,717 -1,0 +1,717 @@@
- int ED_outliner_collections_editor_poll(bContext *C)
 +/*
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 + *
 + * Contributor(s): Blender Foundation, Dalai Felinto
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file blender/editors/space_outliner/outliner_collections.c
 + *  \ingroup spoutliner
 + */
 +
 +#include <string.h>
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_listbase.h"
 +
 +#include "DNA_group_types.h"
 +#include "DNA_object_types.h"
 +
 +#include "BKE_context.h"
 +#include "BKE_collection.h"
 +#include "BKE_layer.h"
 +#include "BKE_main.h"
 +#include "BKE_report.h"
 +
 +#include "DEG_depsgraph.h"
 +#include "DEG_depsgraph_build.h"
 +
 +#include "ED_object.h"
 +#include "ED_outliner.h"
 +#include "ED_screen.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +
 +#include "RNA_access.h"
 +#include "RNA_define.h"
 +#include "RNA_enum_types.h"
 +
 +#include "UI_resources.h"
 +
 +#include "outliner_intern.h" /* own include */
 +
 +/* -------------------------------------------------------------------- */
 +
 +bool outliner_is_collection_tree_element(const TreeElement *te)
 +{
 +      TreeStoreElem *tselem = TREESTORE(te);
 +
 +      if (!tselem) {
 +              return false;
 +      }
 +
 +      if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
 +              return true;
 +      }
 +      else if (tselem->type == 0 && te->idcode == ID_GR) {
 +              return true;
 +      }
 +
 +      return false;
 +}
 +
 +Collection *outliner_collection_from_tree_element(const TreeElement *te)
 +{
 +      TreeStoreElem *tselem = TREESTORE(te);
 +
 +      if (!tselem) {
 +              return false;
 +      }
 +
 +      if (tselem->type == TSE_LAYER_COLLECTION) {
 +              LayerCollection *lc = te->directdata;
 +              return lc->collection;
 +      }
 +      else if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) {
 +              Scene *scene = (Scene *)tselem->id;
 +              return BKE_collection_master(scene);
 +      }
 +      else if (tselem->type == 0 && te->idcode == ID_GR) {
 +              return (Collection *)tselem->id;
 +      }
 +
 +      return NULL;
 +}
 +
 +/* -------------------------------------------------------------------- */
 +/* Poll functions. */
 +
- static int collections_view_layer_poll(bContext *C, bool include)
++bool ED_outliner_collections_editor_poll(bContext *C)
 +{
 +      SpaceOops *so = CTX_wm_space_outliner(C);
 +      return (so != NULL) && ELEM(so->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES);
 +}
 +
 +
 +/********************************* New Collection ****************************/
 +
 +struct CollectionNewData
 +{
 +      bool error;
 +      Collection *collection;
 +};
 +
 +static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata)
 +{
 +      struct CollectionNewData *data = customdata;
 +      Collection *collection = outliner_collection_from_tree_element(te);
 +
 +      if (!collection) {
 +              return TRAVERSE_SKIP_CHILDS;
 +      }
 +
 +      if (data->collection != NULL) {
 +              data->error = true;
 +              return TRAVERSE_BREAK;
 +      }
 +
 +      data->collection = collection;
 +      return TRAVERSE_CONTINUE;
 +}
 +
 +static int collection_new_exec(bContext *C, wmOperator *op)
 +{
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +
 +      struct CollectionNewData data = {
 +              .error = false,
 +              .collection = NULL,
 +      };
 +
 +      if (RNA_boolean_get(op->ptr, "nested")) {
 +              outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data);
 +
 +              if (data.error) {
 +                      BKE_report(op->reports, RPT_ERROR, "More than one collection is selected");
 +                      return OPERATOR_CANCELLED;
 +              }
 +      }
 +
 +      if (!data.collection && (soops->outlinevis == SO_VIEW_LAYER)) {
 +              data.collection = BKE_collection_master(scene);
 +      }
 +
 +      BKE_collection_add(
 +                  bmain,
 +                  data.collection,
 +                  NULL);
 +
 +      DEG_id_tag_update(&data.collection->id, DEG_TAG_COPY_ON_WRITE);
 +      DEG_relations_tag_update(bmain);
 +
 +      outliner_cleanup_tree(soops);
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_new(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "New Collection";
 +      ot->idname = "OUTLINER_OT_collection_new";
 +      ot->description = "Add a new collection inside selected collection";
 +
 +      /* api callbacks */
 +      ot->exec = collection_new_exec;
 +      ot->poll = ED_outliner_collections_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      /* properties */
 +      PropertyRNA *prop = RNA_def_boolean(ot->srna, "nested", true, "Nested", "Add as child of selected collection");;
 +      RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 +}
 +
 +/**************************** Delete Collection ******************************/
 +
 +struct CollectionEditData {
 +      Scene *scene;
 +      SpaceOops *soops;
 +      GSet *collections_to_edit;
 +};
 +
 +static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata)
 +{
 +      struct CollectionEditData *data = customdata;
 +      Collection *collection = outliner_collection_from_tree_element(te);
 +
 +      if (!collection) {
 +              return TRAVERSE_SKIP_CHILDS;
 +      }
 +
 +      if (collection == BKE_collection_master(data->scene)) {
 +              /* skip - showing warning/error message might be missleading
 +               * when deleting multiple collections, so just do nothing */
 +      }
 +      else {
 +              /* Delete, duplicate and link don't edit children, those will come along
 +               * with the parents. */
 +              BLI_gset_add(data->collections_to_edit, collection);
 +              return TRAVERSE_SKIP_CHILDS;
 +      }
 +
 +      return TRAVERSE_CONTINUE;
 +}
 +
 +static int collection_delete_exec(bContext *C, wmOperator *op)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      struct CollectionEditData data = {.scene = scene, .soops = soops};
 +      bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
 +
 +      data.collections_to_edit = BLI_gset_ptr_new(__func__);
 +
 +      /* We first walk over and find the Collections we actually want to delete (ignoring duplicates). */
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
 +
 +      /* Effectively delete the collections. */
 +      GSetIterator collections_to_edit_iter;
 +      GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
 +              Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
 +
 +              /* Test in case collection got deleted as part of another one. */
 +              if (BLI_findindex(&bmain->collection, collection) != -1) {
 +                      BKE_collection_delete(bmain, collection, hierarchy);
 +              }
 +      }
 +
 +      BLI_gset_free(data.collections_to_edit, NULL);
 +
 +      DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
 +      DEG_relations_tag_update(bmain);
 +
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_delete(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Delete Collection";
 +      ot->idname = "OUTLINER_OT_collection_delete";
 +      ot->description = "Delete selected collections";
 +
 +      /* api callbacks */
 +      ot->exec = collection_delete_exec;
 +      ot->poll = ED_outliner_collections_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +
 +      /* properties */
 +      PropertyRNA *prop = RNA_def_boolean(ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections");
 +      RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 +}
 +
 +/****************************** Select Objects *******************************/
 +
 +struct CollectionObjectsSelectData {
 +      bool error;
 +      LayerCollection *layer_collection;
 +};
 +
 +static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, void *customdata)
 +{
 +      struct CollectionObjectsSelectData *data = customdata;
 +      TreeStoreElem *tselem = TREESTORE(te);
 +
 +      switch (tselem->type) {
 +              case TSE_LAYER_COLLECTION:
 +                      data->layer_collection = te->directdata;
 +                      return TRAVERSE_BREAK;
 +              case TSE_R_LAYER:
 +              case TSE_SCENE_COLLECTION_BASE:
 +              case TSE_VIEW_COLLECTION_BASE:
 +                      return TRAVERSE_CONTINUE;
 +              default:
 +                      return TRAVERSE_SKIP_CHILDS;
 +      }
 +}
 +
 +static LayerCollection *outliner_active_layer_collection(bContext *C)
 +{
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +
 +      struct CollectionObjectsSelectData data = {
 +              .layer_collection = NULL,
 +      };
 +
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_layer_collection, &data);
 +      return data.layer_collection;
 +}
 +
 +static int collection_objects_select_exec(bContext *C, wmOperator *op)
 +{
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      LayerCollection *layer_collection = outliner_active_layer_collection(C);
 +      bool deselect = STREQ(op->idname, "OUTLINER_OT_collection_objects_deselect");
 +
 +      if (layer_collection == NULL) {
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      BKE_layer_collection_objects_select(view_layer, layer_collection, deselect);
 +
 +      Scene *scene = CTX_data_scene(C);
 +      DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE);
 +      WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_objects_select(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Select Objects";
 +      ot->idname = "OUTLINER_OT_collection_objects_select";
 +      ot->description = "Select objects in collection";
 +
 +      /* api callbacks */
 +      ot->exec = collection_objects_select_exec;
 +      ot->poll = ED_outliner_collections_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Deselect Objects";
 +      ot->idname = "OUTLINER_OT_collection_objects_deselect";
 +      ot->description = "Deselect objects in collection";
 +
 +      /* api callbacks */
 +      ot->exec = collection_objects_select_exec;
 +      ot->poll = ED_outliner_collections_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +/************************** Duplicate Collection *****************************/
 +
 +struct CollectionDuplicateData {
 +      TreeElement *te;
 +};
 +
 +static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata)
 +{
 +      struct CollectionDuplicateData *data = customdata;
 +      TreeStoreElem *tselem = TREESTORE(te);
 +
 +      switch (tselem->type) {
 +              case TSE_LAYER_COLLECTION:
 +                      data->te = te;
 +                      return TRAVERSE_BREAK;
 +              case TSE_R_LAYER:
 +              case TSE_SCENE_COLLECTION_BASE:
 +              case TSE_VIEW_COLLECTION_BASE:
 +              default:
 +                      return TRAVERSE_CONTINUE;
 +      }
 +}
 +
 +static TreeElement *outliner_active_collection(bContext *C)
 +{
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +
 +      struct CollectionDuplicateData data = {
 +              .te = NULL,
 +      };
 +
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_collection, &data);
 +      return data.te;
 +}
 +
 +static int collection_duplicate_exec(bContext *C, wmOperator *op)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      TreeElement *te = outliner_active_collection(C);
 +      BLI_assert(te != NULL);
 +
 +      Collection *collection = outliner_collection_from_tree_element(te);
 +      Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : NULL;
 +
 +      if (collection->flag & COLLECTION_IS_MASTER) {
 +              BKE_report(op->reports, RPT_ERROR, "Can't duplicate the master collection");
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      switch (soops->outlinevis) {
 +              case SO_SCENES:
 +              case SO_VIEW_LAYER:
 +              case SO_LIBRARIES:
 +                      BKE_collection_copy(bmain, parent, collection);
 +                      break;
 +      }
 +
 +      DEG_relations_tag_update(bmain);
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C));
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_duplicate(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Duplicate Collection";
 +      ot->idname = "OUTLINER_OT_collection_duplicate";
 +      ot->description = "Duplicate selected collections";
 +
 +      /* api callbacks */
 +      ot->exec = collection_duplicate_exec;
 +      ot->poll = ED_outliner_collections_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +/**************************** Link Collection ******************************/
 +
 +static int collection_link_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +      Collection *active_collection = CTX_data_layer_collection(C)->collection;
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      struct CollectionEditData data = {.scene = scene, .soops = soops};
 +
 +      data.collections_to_edit = BLI_gset_ptr_new(__func__);
 +
 +      /* We first walk over and find the Collections we actually want to link (ignoring duplicates). */
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
 +
 +      /* Effectively link the collections. */
 +      GSetIterator collections_to_edit_iter;
 +      GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
 +              Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
 +              BKE_collection_child_add(bmain, active_collection, collection);
 +              id_fake_user_clear(&collection->id);
 +      }
 +
 +      BLI_gset_free(data.collections_to_edit, NULL);
 +
 +      DEG_id_tag_update(&active_collection->id, DEG_TAG_COPY_ON_WRITE);
 +      DEG_relations_tag_update(bmain);
 +
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_link(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Link Collection";
 +      ot->idname = "OUTLINER_OT_collection_link";
 +      ot->description = "Link selected collections to active scene";
 +
 +      /* api callbacks */
 +      ot->exec = collection_link_exec;
 +      ot->poll = ED_outliner_collections_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +/************************** Instance Collection ******************************/
 +
 +static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op))
 +{
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      struct CollectionEditData data = {.scene = scene, .soops = soops};
 +
 +      data.collections_to_edit = BLI_gset_ptr_new(__func__);
 +
 +      /* We first walk over and find the Collections we actually want to instance (ignoring duplicates). */
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data);
 +
 +      /* Find an active collection to add to, that doesn't give dependency cycles. */
 +      LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer);
 +
 +      GSetIterator collections_to_edit_iter;
 +      GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
 +              Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
 +
 +              while (BKE_collection_find_cycle(active_lc->collection, collection)) {
 +                      active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
 +              }
 +      }
 +
 +      /* Effectively instance the collections. */
 +      GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
 +              Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
 +              Object *ob = ED_object_add_type(C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, NULL, false, scene->layact);
 +              ob->dup_group = collection;
 +              ob->transflag |= OB_DUPLICOLLECTION;
 +              id_lib_extern(&collection->id);
 +      }
 +
 +      BLI_gset_free(data.collections_to_edit, NULL);
 +
 +      DEG_relations_tag_update(bmain);
 +
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_instance(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Instance Collection";
 +      ot->idname = "OUTLINER_OT_collection_instance";
 +      ot->description = "Instance selected collections to active scene";
 +
 +      /* api callbacks */
 +      ot->exec = collection_instance_exec;
 +      ot->poll = ED_outliner_collections_editor_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +/************************** Exclude Collection ******************************/
 +
 +static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata)
 +{
 +      struct CollectionEditData *data = customdata;
 +      TreeStoreElem *tselem = TREESTORE(te);
 +
 +      if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) {
 +              return TRAVERSE_CONTINUE;
 +      }
 +
 +      LayerCollection *lc = te->directdata;
 +
 +      if (lc->collection->flag & COLLECTION_IS_MASTER) {
 +              /* skip - showing warning/error message might be missleading
 +               * when deleting multiple collections, so just do nothing */
 +      }
 +      else {
 +              /* Delete, duplicate and link don't edit children, those will come along
 +               * with the parents. */
 +              BLI_gset_add(data->collections_to_edit, lc);
 +      }
 +
 +      return TRAVERSE_CONTINUE;
 +}
 +
- static int collections_exclude_poll(bContext *C)
++static bool collections_view_layer_poll(bContext *C, bool include)
 +{
 +      /* Poll function so the right click menu show current state of selected collections. */
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      if (!(soops && soops->outlinevis == SO_VIEW_LAYER)) {
 +              return false;
 +      }
 +
 +      Scene *scene = CTX_data_scene(C);
 +      struct CollectionEditData data = {.scene = scene, .soops = soops};
 +      data.collections_to_edit = BLI_gset_ptr_new(__func__);
 +      bool result = false;
 +
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
 +
 +      GSetIterator collections_to_edit_iter;
 +      GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
 +              LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
 +
 +              if (include && (lc->flag & LAYER_COLLECTION_EXCLUDE)) {
 +                      result = true;
 +              }
 +              else if (!include && !(lc->flag & LAYER_COLLECTION_EXCLUDE)) {
 +                      result = true;
 +              }
 +      }
 +
 +      BLI_gset_free(data.collections_to_edit, NULL);
 +      return result;
 +}
 +
- static int collections_include_poll(bContext *C)
++static bool collections_exclude_poll(bContext *C)
 +{
 +      return collections_view_layer_poll(C, false);
 +}
 +
++static bool collections_include_poll(bContext *C)
 +{
 +      return collections_view_layer_poll(C, true);
 +}
 +
 +static void layer_collection_exclude_recursive_set(LayerCollection *lc)
 +{
 +      for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
 +              if (lc->flag & LAYER_COLLECTION_EXCLUDE) {
 +                      nlc->flag |= LAYER_COLLECTION_EXCLUDE;
 +              }
 +              else {
 +                      nlc->flag &= ~LAYER_COLLECTION_EXCLUDE;
 +              }
 +
 +              layer_collection_exclude_recursive_set(nlc);
 +      }
 +}
 +
 +static int collection_view_layer_exec(bContext *C, wmOperator *op)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      struct CollectionEditData data = {.scene = scene, .soops = soops};
 +      bool include = STREQ(op->idname, "OUTLINER_OT_collection_include_set");
 +
 +      data.collections_to_edit = BLI_gset_ptr_new(__func__);
 +
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data);
 +
 +      GSetIterator collections_to_edit_iter;
 +      GSET_ITER(collections_to_edit_iter, data.collections_to_edit) {
 +              LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
 +
 +              if (!(lc->collection->flag & COLLECTION_IS_MASTER)) {
 +                      if (include) {
 +                              lc->flag &= ~LAYER_COLLECTION_EXCLUDE;
 +                      }
 +                      else {
 +                              lc->flag |= LAYER_COLLECTION_EXCLUDE;
 +                      }
 +
 +                      layer_collection_exclude_recursive_set(lc);
 +              }
 +      }
 +
 +      BLI_gset_free(data.collections_to_edit, NULL);
 +
 +      BKE_layer_collection_sync(scene, view_layer);
 +      DEG_relations_tag_update(bmain);
 +
 +      WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Exclude from View Layer";
 +      ot->idname = "OUTLINER_OT_collection_exclude_set";
 +      ot->description = "Exclude collection from the active view layer";
 +
 +      /* api callbacks */
 +      ot->exec = collection_view_layer_exec;
 +      ot->poll = collections_exclude_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +void OUTLINER_OT_collection_include_set(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Include in View Layer";
 +      ot->idname = "OUTLINER_OT_collection_include_set";
 +      ot->description = "Include collection in the active view layer";
 +
 +      /* api callbacks */
 +      ot->exec = collection_view_layer_exec;
 +      ot->poll = collections_include_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 +}
 +
 +/**
 + * Populates the \param objects ListBase with all the outliner selected objects
 + * We store it as (Object *)LinkData->data
 + * \param objects expected to be empty
 + */
 +void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
 +{
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      struct ObjectsSelectedData data = {{NULL}};
 +      outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data);
 +      LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) {
 +              TreeElement *ten_selected = (TreeElement *)link->data;
 +              Object *ob = (Object *)TREESTORE(ten_selected)->id;
 +              BLI_addtail(objects, BLI_genericNodeN(ob));
 +      }
 +      BLI_freelistN(&data.objects_selected_array);
 +}
index b0478da55b51321b173424fd0855b4bda21c9322,9574e82505fc7d3ba3962f42d2f09339ec92afeb..b6c7e8d608d059288dad804235a8009625665dfb
  #include "WM_api.h"
  #include "WM_types.h"
  
 +#include "ED_screen.h"
 +
  #include "outliner_intern.h"
  
- static int outliner_item_drag_drop_poll(bContext *C)
 +typedef struct OutlinerDragDropTooltip {
 +      TreeElement *te;
 +      void *handle;
 +} OutlinerDragDropTooltip;
 +
 +enum {
 +      OUTLINER_ITEM_DRAG_CANCEL,
 +      OUTLINER_ITEM_DRAG_CONFIRM,
 +};
 +
++static bool outliner_item_drag_drop_poll(bContext *C)
 +{
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      return ED_operator_outliner_active(C) &&
 +             /* Only collection display modes supported for now. Others need more design work */
 +             ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_LIBRARIES);
 +}
 +
 +static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event)
 +{
 +      /* note: using EVT_TWEAK_ events to trigger dragging is fine,
 +       * it sends coordinates from where dragging was started */
 +      const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]);
 +      return outliner_find_item_at_y(soops, &soops->tree, my);
 +}
 +
 +static void outliner_item_drag_end(wmWindow *win, OutlinerDragDropTooltip *data)
 +{
 +      MEM_SAFE_FREE(data->te->drag_data);
 +
 +      if (data->handle) {
 +              WM_draw_cb_exit(win, data->handle);
 +      }
 +
 +      MEM_SAFE_FREE(data);
 +}
 +
 +static void outliner_item_drag_get_insert_data(
 +        const SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged,
 +        TreeElement **r_te_insert_handle, TreeElementInsertType *r_insert_type)
 +{
 +      TreeElement *te_hovered;
 +      float view_mval[2];
 +
 +      UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
 +      te_hovered = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]);
 +
 +      if (te_hovered) {
 +              /* mouse hovers an element (ignoring x-axis), now find out how to insert the dragged item exactly */
 +
 +              if (te_hovered == te_dragged) {
 +                      *r_te_insert_handle = te_dragged;
 +              }
 +              else if (te_hovered != te_dragged) {
 +                      const float margin = UI_UNIT_Y * (1.0f / 4);
 +
 +                      *r_te_insert_handle = te_hovered;
 +                      if (view_mval[1] < (te_hovered->ys + margin)) {
 +                              if (TSELEM_OPEN(TREESTORE(te_hovered), soops)) {
 +                                      /* inserting after a open item means we insert into it, but as first child */
 +                                      if (BLI_listbase_is_empty(&te_hovered->subtree)) {
 +                                              *r_insert_type = TE_INSERT_INTO;
 +                                      }
 +                                      else {
 +                                              *r_insert_type = TE_INSERT_BEFORE;
 +                                              *r_te_insert_handle = te_hovered->subtree.first;
 +                                      }
 +                              }
 +                              else {
 +                                      *r_insert_type = TE_INSERT_AFTER;
 +                              }
 +                      }
 +                      else if (view_mval[1] > (te_hovered->ys + (3 * margin))) {
 +                              *r_insert_type = TE_INSERT_BEFORE;
 +                      }
 +                      else {
 +                              *r_insert_type = TE_INSERT_INTO;
 +                      }
 +              }
 +      }
 +      else {
 +              /* mouse doesn't hover any item (ignoring x-axis), so it's either above list bounds or below. */
 +
 +              TreeElement *first = soops->tree.first;
 +              TreeElement *last = soops->tree.last;
 +
 +              if (view_mval[1] < last->ys) {
 +                      *r_te_insert_handle = last;
 +                      *r_insert_type = TE_INSERT_AFTER;
 +              }
 +              else if (view_mval[1] > (first->ys + UI_UNIT_Y)) {
 +                      *r_te_insert_handle = first;
 +                      *r_insert_type = TE_INSERT_BEFORE;
 +              }
 +              else {
 +                      BLI_assert(0);
 +              }
 +      }
 +}
 +
 +static void outliner_item_drag_handle(
 +        SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged)
 +{
 +      TreeElement *te_insert_handle;
 +      TreeElementInsertType insert_type;
 +
 +      outliner_item_drag_get_insert_data(soops, ar, event, te_dragged, &te_insert_handle, &insert_type);
 +
 +      if (!te_dragged->reinsert_poll &&
 +          /* there is no reinsert_poll, so we do some generic checks (same types and reinsert callback is available) */
 +          (TREESTORE(te_dragged)->type == TREESTORE(te_insert_handle)->type) &&
 +          te_dragged->reinsert)
 +      {
 +              /* pass */
 +      }
 +      else if (te_dragged == te_insert_handle) {
 +              /* nothing will happen anyway, no need to do poll check */
 +      }
 +      else if (!te_dragged->reinsert_poll ||
 +               !te_dragged->reinsert_poll(te_dragged, &te_insert_handle, &insert_type))
 +      {
 +              te_insert_handle = NULL;
 +      }
 +      te_dragged->drag_data->insert_type = insert_type;
 +      te_dragged->drag_data->insert_handle = te_insert_handle;
 +}
 +
 +/**
 + * Returns true if it is a collection and empty.
 + */
 +static bool is_empty_collection(TreeElement *te)
 +{
 +      Collection *collection = outliner_collection_from_tree_element(te);
 +
 +      if (!collection) {
 +              return false;
 +      }
 +
 +      return BLI_listbase_is_empty(&collection->gobject) &&
 +             BLI_listbase_is_empty(&collection->children);
 +}
 +
 +static bool outliner_item_drag_drop_apply(
 +        Main *bmain,
 +        Scene *scene,
 +        SpaceOops *soops,
 +        OutlinerDragDropTooltip *data,
 +        const wmEvent *event)
 +{
 +      TreeElement *dragged_te = data->te;
 +      TreeElement *insert_handle = dragged_te->drag_data->insert_handle;
 +      TreeElementInsertType insert_type = dragged_te->drag_data->insert_type;
 +
 +      if ((insert_handle == dragged_te) || !insert_handle) {
 +              /* No need to do anything */
 +      }
 +      else if (dragged_te->reinsert) {
 +              BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(dragged_te, &insert_handle,
 +                                                                                 &insert_type));
 +              /* call of assert above should not have changed insert_handle and insert_type at this point */
 +              BLI_assert(dragged_te->drag_data->insert_handle == insert_handle &&
 +                         dragged_te->drag_data->insert_type == insert_type);
 +
 +              /* If the collection was just created and you moved objects/collections inside it,
 +               * it is strange to have it closed and we not see the newly dragged elements. */
 +              const bool should_open_collection = (insert_type == TE_INSERT_INTO) && is_empty_collection(insert_handle);
 +
 +              dragged_te->reinsert(bmain, scene, soops, dragged_te, insert_handle, insert_type, event);
 +
 +              if (should_open_collection && !is_empty_collection(insert_handle)) {
 +                      TREESTORE(insert_handle)->flag &= ~TSE_CLOSED;
 +              }
 +              return true;
 +      }
 +
 +      return false;
 +}
 +
 +static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +      ARegion *ar = CTX_wm_region(C);
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      OutlinerDragDropTooltip *data = op->customdata;
 +      TreeElement *te_dragged = data->te;
 +      int retval = OPERATOR_RUNNING_MODAL;
 +      bool redraw = false;
 +      bool skip_rebuild = true;
 +
 +      switch (event->type) {
 +              case EVT_MODAL_MAP:
 +                      if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) {
 +                              if (outliner_item_drag_drop_apply(bmain, scene, soops, data, event)) {
 +                                      skip_rebuild = false;
 +                              }
 +                              retval = OPERATOR_FINISHED;
 +                      }
 +                      else if (event->val == OUTLINER_ITEM_DRAG_CANCEL) {
 +                              retval = OPERATOR_CANCELLED;
 +                      }
 +                      else {
 +                              BLI_assert(0);
 +                      }
 +                      WM_event_add_mousemove(C); /* update highlight */
 +                      outliner_item_drag_end(CTX_wm_window(C), data);
 +                      redraw = true;
 +                      break;
 +              case MOUSEMOVE:
 +                      outliner_item_drag_handle(soops, ar, event, te_dragged);
 +                      redraw = true;
 +                      break;
 +      }
 +
 +      if (redraw) {
 +              if (skip_rebuild) {
 +                      ED_region_tag_redraw_no_rebuild(ar);
 +              }
 +              else {
 +                      ED_region_tag_redraw(ar);
 +              }
 +      }
 +
 +      return retval;
 +}
 +
 +static const char *outliner_drag_drop_tooltip_get(
 +        const TreeElement *te_float)
 +{
 +      const char *name = NULL;
 +
 +      const TreeElement *te_insert = te_float->drag_data->insert_handle;
 +      if (te_float && outliner_is_collection_tree_element(te_float)) {
 +              if (te_insert == NULL) {
 +                      name = TIP_("Move collection");
 +              }
 +              else {
 +                      switch (te_float->drag_data->insert_type) {
 +                              case TE_INSERT_BEFORE:
 +                                      if (te_insert->prev && outliner_is_collection_tree_element(te_insert->prev)) {
 +                                              name = TIP_("Move between collections");
 +                                      }
 +                                      else {
 +                                              name = TIP_("Move before collection");
 +                                      }
 +                                      break;
 +                              case TE_INSERT_AFTER:
 +                                      if (te_insert->next && outliner_is_collection_tree_element(te_insert->next)) {
 +                                              name = TIP_("Move between collections");
 +                                      }
 +                                      else {
 +                                              name = TIP_("Move after collection");
 +                                      }
 +                                      break;
 +                              case TE_INSERT_INTO:
 +                                      name = TIP_("Move inside collection");
 +                                      break;
 +                      }
 +              }
 +      }
 +      else if ((TREESTORE(te_float)->type == 0) && (te_float->idcode == ID_OB)) {
 +              name = TIP_("Move to collection (Ctrl to link)");
 +      }
 +
 +      return name;
 +}
 +
 +static void outliner_drag_drop_tooltip_cb(const wmWindow *win, void *vdata)
 +{
 +      OutlinerDragDropTooltip *data = vdata;
 +      const char *tooltip;
 +
 +      int cursorx, cursory;
 +      int x, y;
 +
 +      tooltip = outliner_drag_drop_tooltip_get(data->te);
 +      if (tooltip == NULL) {
 +              return;
 +      }
 +
 +      cursorx = win->eventstate->x;
 +      cursory = win->eventstate->y;
 +
 +      x = cursorx + U.widget_unit;
 +      y = cursory - U.widget_unit;
 +
 +      /* Drawing. */
 +      const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
 +
 +      const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
 +      const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f};
 +
 +      GPU_blend(true);
 +      UI_fontstyle_draw_simple_backdrop(fstyle, x, y, tooltip, col_fg, col_bg);
 +      GPU_blend(false);
 +}
 +
 +static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 +{
 +      ARegion *ar = CTX_wm_region(C);
 +      SpaceOops *soops = CTX_wm_space_outliner(C);
 +      TreeElement *te_dragged = outliner_item_drag_element_find(soops, ar, event);
 +
 +      if (!te_dragged) {
 +              return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
 +      }
 +
 +      OutlinerDragDropTooltip *data = MEM_mallocN(sizeof(OutlinerDragDropTooltip), __func__);
 +      data->te = te_dragged;
 +
 +      op->customdata = data;
 +      te_dragged->drag_data = MEM_callocN(sizeof(*te_dragged->drag_data), __func__);
 +      /* by default we don't change the item position */
 +      te_dragged->drag_data->insert_handle = te_dragged;
 +      /* unset highlighted tree element, dragged one will be highlighted instead */
 +      outliner_set_flag(&soops->tree, TSE_HIGHLIGHTED, false);
 +
 +      ED_region_tag_redraw_no_rebuild(ar);
 +
 +      WM_event_add_modal_handler(C, op);
 +
 +      data->handle = WM_draw_cb_activate(CTX_wm_window(C), outliner_drag_drop_tooltip_cb, data);
 +
 +      return OPERATOR_RUNNING_MODAL;
 +}
 +
 +/**
 + * Notes about Outliner Item Drag 'n Drop:
 + * Right now only collections display mode is supported. But ideally all/most modes would support this. There are
 + * just some open design questions that have to be answered: do we want to allow mixing order of different data types
 + * (like render-layers and objects)? Would that be a purely visual change or would that have any other effect? ...
 + */
 +static void OUTLINER_OT_item_drag_drop(wmOperatorType *ot)
 +{
 +      ot->name = "Drag and Drop Item";
 +      ot->idname = "OUTLINER_OT_item_drag_drop";
 +      ot->description = "Change the hierarchical position of an item by repositioning it using drag and drop";
 +
 +      ot->invoke = outliner_item_drag_drop_invoke;
 +      ot->modal = outliner_item_drag_drop_modal;
 +
 +      ot->poll = outliner_item_drag_drop_poll;
 +
 +      ot->flag = OPTYPE_UNDO;
 +}
 +
  
  /* ************************** registration **********************************/
  
index cfd658eea6cc2291643381d014bb682131171fed,413ea8cc3a7016ceebfb6c5ad1f554aac584ce27..e1baaf5416398f0a601c5a47c88d14833bd29fe2
@@@ -247,7 -230,7 +247,7 @@@ static void outliner_material_drop_copy
        RNA_string_set(drop->ptr, "material", id->name + 2);
  }
  
- static int outliner_collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
 -static bool outliner_group_link_poll(bContext *C, wmDrag *drag, const wmEvent *event)
++static bool outliner_collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
  {
        ARegion *ar = CTX_wm_region(C);
        SpaceOops *soops = CTX_wm_space_outliner(C);
index cb7066d218c769079939cdb7dd7e11dd07d6ffc3,63ae3bbb657c351c2fd5a26eadee29c4fc207dcc..4660255cc6c46c6f245acb0e8ed9f30cd77625dd
@@@ -550,9 -572,14 +550,9 @@@ static void view3d_main_region_exit(wmW
                GPU_offscreen_free(rv3d->gpuoffscreen);
                rv3d->gpuoffscreen = NULL;
        }
 -
 -      if (rv3d->compositor) {
 -              GPU_fx_compositor_destroy(rv3d->compositor);
 -              rv3d->compositor = NULL;
 -      }
  }
  
- static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
+ static bool view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
  {
        if (drag->type == WM_DRAG_ID) {
                ID *id = drag->poin;
        return 0;
  }
  
- static int view3d_collection_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
 -static bool view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
++static bool view3d_collection_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
  {
        if (drag->type == WM_DRAG_ID) {
                ID *id = drag->poin;
index 6ebed88728ea0f3d7f11b66fc9c979931a11da37,63786e87b1f3fba6653b7147fedc20c49f205005..f5e8bf10817839c0fe7a99841c557cc849e282e5
@@@ -786,10 -784,10 +786,10 @@@ static void do_view3d_vgroup_buttons(bC
        }
  }
  
- static int view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt))
+ static bool view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt))
  {
 -      Scene *scene = CTX_data_scene(C);
 -      Object *ob = OBACT;
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      Object *ob = OBACT(view_layer);
        if (ob && (BKE_object_is_in_editmode_vgroup(ob) ||
                   BKE_object_is_in_wpaint_select_vert(ob)))
        {
@@@ -1120,10 -1117,10 +1120,10 @@@ static void do_view3d_region_buttons(bC
        WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
  }
  
- static int view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt))
+ static bool view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt))
  {
 -      Scene *scene = CTX_data_scene(C);
 -      return (scene->basact != NULL);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      return (view_layer->basact != NULL);
  }
  
  static void view3d_panel_transform(const bContext *C, Panel *pa)
index 4f81fa7585c83919cf9e7d62ecd939731494d234,27dda99e71506b2bcc27e4ae144c00d5b9091e27..eeddacee8085a7e6fb74c5c9712479837b516bee
@@@ -221,72 -225,6 +221,72 @@@ void VIEW3D_OT_layers(wmOperatorType *o
        RNA_def_boolean(ot->srna, "toggle", 1, "Toggle", "Toggle the layer");
  }
  
- static int toggle_show_xray_poll(bContext *C)
 +/* -------------------------------------------------------------------- */
 +/** \name Toggle Bone selection Overlay Operator
 + * \{ */
 +
 +static int toggle_show_xray(bContext *C, wmOperator *UNUSED(op))
 +{
 +      View3D *v3d = CTX_wm_view3d(C);
 +      v3d->shading.flag ^= V3D_SHADING_XRAY;
 +      ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C));
 +      WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
 +      return OPERATOR_FINISHED;
 +}
 +
++static bool toggle_show_xray_poll(bContext *C)
 +{
 +      bool result = (ED_operator_view3d_active(C) && !ED_operator_posemode(C) && !ED_operator_editmesh(C));
 +      if (result) {
 +              // Additional test for SOLID or TEXTURE mode
 +              View3D *v3d = CTX_wm_view3d(C);
 +              result = (v3d->drawtype & (OB_SOLID | OB_TEXTURE)) > 0;
 +      }
 +      return result;
 +}
 +
 +void VIEW3D_OT_toggle_xray_draw_option(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Toggle Show X-Ray";
 +      ot->description = "Toggle show X-Ray";
 +      ot->idname = "VIEW3D_OT_toggle_xray_draw_option";
 +
 +      /* api callbacks */
 +      ot->exec = toggle_show_xray;
 +      ot->poll = toggle_show_xray_poll;
 +}
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Toggle Bone selection Overlay Operator
 + * \{ */
 +
 +static int toggle_matcap_flip(bContext *C, wmOperator *UNUSED(op))
 +{
 +      View3D *v3d = CTX_wm_view3d(C);
 +      v3d->shading.flag ^= V3D_SHADING_MATCAP_FLIP_X;
 +      ED_view3d_shade_update(CTX_data_main(C), v3d, CTX_wm_area(C));
 +      WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
 +      return OPERATOR_FINISHED;
 +}
 +
 +void VIEW3D_OT_toggle_matcap_flip(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Flip MatCap";
 +      ot->description = "Flip MatCap";
 +      ot->idname = "VIEW3D_OT_toggle_matcap_flip";
 +
 +      /* api callbacks */
 +      ot->exec = toggle_matcap_flip;
 +      // ot->poll = toggle_show_xray_poll;
 +}
 +
 +/** \} */
 +
 +
  static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
  {
        wmWindow *win = CTX_wm_window(C);
index 55bf568d7294d4833e151fb3401f0239aa1f9055,0000000000000000000000000000000000000000..d8a6a4c0c5238425582fc3ae76bda3111369530d
mode 100644,000000..100644
--- /dev/null
@@@ -1,1101 -1,0 +1,1101 @@@
- static int view3d_ruler_poll(bContext *C)
 +/*
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/** \file blender/editors/space_view3d/view3d_manipulator_ruler.c
 + *  \ingroup spview3d
 + */
 +
 +#include "BLI_listbase.h"
 +#include "BLI_string.h"
 +#include "BLI_rect.h"
 +#include "BLI_math.h"
 +#include "BLI_utildefines.h"
 +
 +#include "BLT_translation.h"
 +
 +#include "BKE_context.h"
 +#include "BKE_gpencil.h"
 +#include "BKE_main.h"
 +
 +#include "BKE_object.h"
 +#include "BKE_unit.h"
 +
 +#include "DNA_object_types.h"
 +#include "DNA_gpencil_types.h"
 +#include "DNA_view3d_types.h"
 +
 +#include "BIF_gl.h"
 +
 +#include "ED_screen.h"
 +#include "ED_transform_snap_object_context.h"
 +#include "ED_view3d.h"
 +
 +#include "UI_resources.h"
 +#include "UI_interface.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "RNA_access.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +#include "WM_toolsystem.h"
 +
 +#include "view3d_intern.h"  /* own include */
 +
 +#include "GPU_immediate.h"
 +#include "GPU_immediate_util.h"
 +#include "GPU_select.h"
 +#include "GPU_state.h"
 +
 +#include "BLF_api.h"
 +
 +
 +static const char *view3d_wgt_ruler_id = "VIEW3D_WGT_ruler";
 +
 +
 +#define MVAL_MAX_PX_DIST 12.0f
 +
 +/* -------------------------------------------------------------------- */
 +/* Ruler Item (we can have many) */
 +enum {
 +      RULERITEM_USE_ANGLE = (1 << 0),  /* use protractor */
 +      RULERITEM_USE_RAYCAST = (1 << 1)
 +};
 +
 +enum {
 +      RULERITEM_DIRECTION_IN = 0,
 +      RULERITEM_DIRECTION_OUT
 +};
 +
 +/* keep smaller then selection, since we may want click elsewhere without selecting a ruler */
 +#define RULER_PICK_DIST 12.0f
 +#define RULER_PICK_DIST_SQ (RULER_PICK_DIST * RULER_PICK_DIST)
 +
 +/* not clicking on a point */
 +#define PART_LINE 0xff
 +
 +/* -------------------------------------------------------------------- */
 +/* Ruler Info (wmManipulatorGroup customdata) */
 +
 +enum {
 +      RULER_STATE_NORMAL = 0,
 +      RULER_STATE_DRAG
 +};
 +
 +enum {
 +      RULER_SNAP_OK = (1 << 0),
 +};
 +
 +typedef struct RulerInfo {
 +      // ListBase items;
 +      int      item_active;
 +      int flag;
 +      int snap_flag;
 +      int state;
 +
 +      struct SnapObjectContext *snap_context;
 +
 +      /* wm state */
 +      wmWindow *win;
 +      ScrArea *sa;
 +      ARegion *ar;  /* re-assigned every modal update */
 +} RulerInfo;
 +
 +/* -------------------------------------------------------------------- */
 +/* Ruler Item (two or three points) */
 +
 +typedef struct RulerItem {
 +      wmManipulator mpr;
 +
 +      /* worldspace coords, middle being optional */
 +      float co[3][3];
 +
 +      int   flag;
 +      int   raycast_dir;  /* RULER_DIRECTION_* */
 +} RulerItem;
 +
 +typedef struct RulerInteraction {
 +      /* selected coord */
 +      char  co_index; /* 0 -> 2 */
 +      float drag_start_co[3];
 +      uint inside_region : 1;
 +} RulerInteraction;
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Internal Ruler Utilities
 + * \{ */
 +
 +static RulerItem *ruler_item_add(wmManipulatorGroup *mgroup)
 +{
 +      /* could pass this as an arg */
 +      const wmManipulatorType *wt_ruler = WM_manipulatortype_find("VIEW3D_WT_ruler_item", true);
 +      RulerItem *ruler_item = (RulerItem *)WM_manipulator_new_ptr(wt_ruler, mgroup, NULL);
 +      WM_manipulator_set_flag(&ruler_item->mpr, WM_MANIPULATOR_DRAW_MODAL, true);
 +      return ruler_item;
 +}
 +
 +static void ruler_item_remove(bContext *C, wmManipulatorGroup *mgroup, RulerItem *ruler_item)
 +{
 +      WM_manipulator_unlink(&mgroup->manipulators, mgroup->parent_mmap, &ruler_item->mpr, C);
 +}
 +
 +static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit,
 +                                 char *numstr, size_t numstr_size, int prec)
 +{
 +      const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
 +
 +      if (ruler_item->flag & RULERITEM_USE_ANGLE) {
 +              const float ruler_angle = angle_v3v3v3(ruler_item->co[0],
 +                                                     ruler_item->co[1],
 +                                                     ruler_item->co[2]);
 +
 +              if (unit->system == USER_UNIT_NONE) {
 +                      BLI_snprintf(numstr, numstr_size, "%.*f°", prec, RAD2DEGF(ruler_angle));
 +              }
 +              else {
 +                      bUnit_AsString(numstr, numstr_size,
 +                                     (double)ruler_angle,
 +                                     prec, unit->system, B_UNIT_ROTATION, do_split, false);
 +              }
 +      }
 +      else {
 +              const float ruler_len = len_v3v3(ruler_item->co[0],
 +                                               ruler_item->co[2]);
 +
 +              if (unit->system == USER_UNIT_NONE) {
 +                      BLI_snprintf(numstr, numstr_size, "%.*f", prec, ruler_len);
 +              }
 +              else {
 +                      bUnit_AsString(numstr, numstr_size,
 +                                     (double)(ruler_len * unit->scale_length),
 +                                     prec, unit->system, B_UNIT_LENGTH, do_split, false);
 +              }
 +      }
 +}
 +
 +static bool view3d_ruler_pick(
 +        wmManipulatorGroup *mgroup, RulerItem *ruler_item, const float mval[2],
 +        int *r_co_index)
 +{
 +      RulerInfo *ruler_info = mgroup->customdata;
 +      ARegion *ar = ruler_info->ar;
 +      bool found = false;
 +
 +      float dist_best = RULER_PICK_DIST_SQ;
 +      int co_index_best = -1;
 +
 +      {
 +              float co_ss[3][2];
 +              float dist;
 +              int j;
 +
 +              /* should these be checked? - ok for now not to */
 +              for (j = 0; j < 3; j++) {
 +                      ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
 +              }
 +
 +              if (ruler_item->flag & RULERITEM_USE_ANGLE) {
 +                      dist = min_ff(dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[1]),
 +                                    dist_squared_to_line_segment_v2(mval, co_ss[1], co_ss[2]));
 +                      if (dist < dist_best) {
 +                              dist_best = dist;
 +                              found = true;
 +
 +                              {
 +                                      const float dist_points[3] = {
 +                                          len_squared_v2v2(co_ss[0], mval),
 +                                          len_squared_v2v2(co_ss[1], mval),
 +                                          len_squared_v2v2(co_ss[2], mval),
 +                                      };
 +                                      if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) {
 +                                              co_index_best = min_axis_v3(dist_points);
 +                                      }
 +                                      else {
 +                                              co_index_best = -1;
 +                                      }
 +                              }
 +                      }
 +              }
 +              else {
 +                      dist = dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[2]);
 +                      if (dist < dist_best) {
 +                              dist_best = dist;
 +                              found = true;
 +
 +                              {
 +                                      const float dist_points[2] = {
 +                                          len_squared_v2v2(co_ss[0], mval),
 +                                          len_squared_v2v2(co_ss[2], mval),
 +                                      };
 +                                      if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) {
 +                                              co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2;
 +                                      }
 +                                      else {
 +                                              co_index_best = -1;
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      *r_co_index = co_index_best;
 +      return found;
 +}
 +
 +/**
 + * Ensure the 'snap_context' is only cached while dragging,
 + * needed since the user may toggle modes between tool use.
 + */
 +static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
 +{
 +      Main *bmain = CTX_data_main(C);
 +      if (state == ruler_info->state) {
 +              return;
 +      }
 +
 +      /* always remove */
 +      if (ruler_info->snap_context) {
 +              ED_transform_snap_object_context_destroy(ruler_info->snap_context);
 +              ruler_info->snap_context = NULL;
 +      }
 +
 +      if (state == RULER_STATE_NORMAL) {
 +              /* pass */
 +      }
 +      else if (state == RULER_STATE_DRAG) {
 +              ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
 +                      bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0,
 +                      ruler_info->ar, CTX_wm_view3d(C));
 +      }
 +      else {
 +              BLI_assert(0);
 +      }
 +
 +      ruler_info->state = state;
 +}
 +
 +static void view3d_ruler_item_project(
 +        RulerInfo *ruler_info, float r_co[3],
 +        const int xy[2])
 +{
 +      ED_view3d_win_to_3d_int(ruler_info->sa->spacedata.first, ruler_info->ar, r_co, xy, r_co);
 +}
 +
 +/* use for mousemove events */
 +static bool view3d_ruler_item_mousemove(
 +        RulerInfo *ruler_info, RulerItem *ruler_item, const int mval[2],
 +        const bool do_thickness, const bool do_snap)
 +{
 +      RulerInteraction *inter = ruler_item->mpr.interaction_data;
 +      const float eps_bias = 0.0002f;
 +      float dist_px = MVAL_MAX_PX_DIST * U.pixelsize;  /* snap dist */
 +
 +      ruler_info->snap_flag &= ~RULER_SNAP_OK;
 +
 +      if (ruler_item) {
 +              float *co = ruler_item->co[inter->co_index];
 +              /* restore the initial depth */
 +              copy_v3_v3(co, inter->drag_start_co);
 +              view3d_ruler_item_project(ruler_info, co, mval);
 +              if (do_thickness && inter->co_index != 1) {
 +                      // Scene *scene = CTX_data_scene(C);
 +                      // View3D *v3d = ruler_info->sa->spacedata.first;
 +                      const float mval_fl[2] = {UNPACK2(mval)};
 +                      float ray_normal[3];
 +                      float ray_start[3];
 +                      float *co_other;
 +
 +                      co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0];
 +
 +                      if (ED_transform_snap_object_project_view3d(
 +                              ruler_info->snap_context,
 +                              SCE_SNAP_MODE_FACE,
 +                              &(const struct SnapObjectParams){
 +                                  .snap_select = SNAP_ALL,
 +                                  .use_object_edit_cage = true,
 +                              },
 +                              mval_fl, &dist_px,
 +                              co, ray_normal))
 +                      {
 +                              negate_v3(ray_normal);
 +                              /* add some bias */
 +                              madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias);
 +                              ED_transform_snap_object_project_ray(
 +                                      ruler_info->snap_context,
 +                                      &(const struct SnapObjectParams){
 +                                          .snap_select = SNAP_ALL,
 +                                          .use_object_edit_cage = true,
 +                                      },
 +                                      ray_start, ray_normal, NULL,
 +                                      co_other, NULL);
 +                      }
 +              }
 +              else if (do_snap) {
 +                      const float mval_fl[2] = {UNPACK2(mval)};
 +
 +                      if (ED_transform_snap_object_project_view3d(
 +                              ruler_info->snap_context,
 +                              (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
 +                              &(const struct SnapObjectParams){
 +                                  .snap_select = SNAP_ALL,
 +                                  .use_object_edit_cage = true,
 +                                  .use_occlusion_test = true,
 +                              },
 +                              mval_fl, &dist_px,
 +                              co, NULL))
 +                      {
 +                              ruler_info->snap_flag |= RULER_SNAP_OK;
 +                      }
 +              }
 +              return true;
 +      }
 +      else {
 +              return false;
 +      }
 +}
 +
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Ruler/Grease Pencil Conversion
 + * \{ */
 +
 +#define RULER_ID "RulerData3D"
 +static bool view3d_ruler_to_gpencil(bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      // RulerInfo *ruler_info = mgroup->customdata;
 +      Main *bmain = CTX_data_main(C);
 +      Scene *scene = CTX_data_scene(C);
 +      bGPDlayer *gpl;
 +      bGPDframe *gpf;
 +      bGPDstroke *gps;
 +      bGPDpalette *palette;
 +      bGPDpalettecolor *palcolor;
 +      RulerItem *ruler_item;
 +      const char *ruler_name = RULER_ID;
 +      bool changed = false;
 +
 +      if (scene->gpd == NULL) {
 +              scene->gpd = BKE_gpencil_data_addnew(bmain, "GPencil");
 +      }
 +
 +      gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
 +      if (gpl == NULL) {
 +              gpl = BKE_gpencil_layer_addnew(scene->gpd, ruler_name, false);
 +              gpl->thickness = 1;
 +              gpl->flag |= GP_LAYER_HIDE;
 +      }
 +
 +      /* try to get active palette or create a new one */
 +      palette = BKE_gpencil_palette_getactive(scene->gpd);
 +      if (palette == NULL) {
 +              palette = BKE_gpencil_palette_addnew(scene->gpd, DATA_("GP_Palette"), true);
 +      }
 +      /* try to get color with the ruler name or create a new one */
 +      palcolor = BKE_gpencil_palettecolor_getbyname(palette, (char *)ruler_name);
 +      if (palcolor == NULL) {
 +              palcolor = BKE_gpencil_palettecolor_addnew(palette, (char *)ruler_name, true);
 +      }
 +
 +      gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
 +      BKE_gpencil_free_strokes(gpf);
 +
 +      for (ruler_item = mgroup->manipulators.first; ruler_item; ruler_item = (RulerItem *)ruler_item->mpr.next) {
 +              bGPDspoint *pt;
 +              int j;
 +
 +              /* allocate memory for a new stroke */
 +              gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
 +              if (ruler_item->flag & RULERITEM_USE_ANGLE) {
 +                      gps->totpoints = 3;
 +                      pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
 +                      for (j = 0; j < 3; j++) {
 +                              copy_v3_v3(&pt->x, ruler_item->co[j]);
 +                              pt->pressure = 1.0f;
 +                              pt->strength = 1.0f;
 +                              pt++;
 +                      }
 +              }
 +              else {
 +                      gps->totpoints = 2;
 +                      pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
 +                      for (j = 0; j < 3; j += 2) {
 +                              copy_v3_v3(&pt->x, ruler_item->co[j]);
 +                              pt->pressure = 1.0f;
 +                              pt->strength = 1.0f;
 +                              pt++;
 +                      }
 +              }
 +              gps->flag = GP_STROKE_3DSPACE;
 +              gps->thickness = 3;
 +              /* assign color to stroke */
 +              BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname));
 +              gps->palcolor = palcolor;
 +              BLI_addtail(&gpf->strokes, gps);
 +              changed = true;
 +      }
 +
 +      return changed;
 +}
 +
 +static bool view3d_ruler_from_gpencil(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      bool changed = false;
 +
 +      if (scene->gpd) {
 +              bGPDlayer *gpl;
 +              const char *ruler_name = RULER_ID;
 +              gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
 +              if (gpl) {
 +                      bGPDframe *gpf;
 +                      gpf = BKE_gpencil_layer_getframe(gpl, CFRA, false);
 +                      if (gpf) {
 +                              bGPDstroke *gps;
 +                              for (gps = gpf->strokes.first; gps; gps = gps->next) {
 +                                      bGPDspoint *pt = gps->points;
 +                                      int j;
 +                                      RulerItem *ruler_item = NULL;
 +                                      if (gps->totpoints == 3) {
 +                                              ruler_item = ruler_item_add(mgroup);
 +                                              for (j = 0; j < 3; j++) {
 +                                                      copy_v3_v3(ruler_item->co[j], &pt->x);
 +                                                      pt++;
 +                                              }
 +                                              ruler_item->flag |= RULERITEM_USE_ANGLE;
 +                                              changed = true;
 +                                      }
 +                                      else if (gps->totpoints == 2) {
 +                                              ruler_item = ruler_item_add(mgroup);
 +                                              for (j = 0; j < 3; j += 2) {
 +                                                      copy_v3_v3(ruler_item->co[j], &pt->x);
 +                                                      pt++;
 +                                              }
 +                                              changed = true;
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      return changed;
 +}
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Ruler Item Manipulator Type
 + * \{ */
 +
 +static void manipulator_ruler_draw(const bContext *C, wmManipulator *mpr)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      UnitSettings *unit = &scene->unit;
 +      RulerInfo *ruler_info = mpr->parent_mgroup->customdata;
 +      RulerItem *ruler_item = (RulerItem *)mpr;
 +      ARegion *ar = ruler_info->ar;
 +      RegionView3D *rv3d = ar->regiondata;
 +      const float cap_size = 4.0f;
 +      const float bg_margin = 4.0f * U.pixelsize;
 +      const float bg_radius = 4.0f * U.pixelsize;
 +      const float arc_size = 64.0f * U.pixelsize;
 +#define ARC_STEPS 24
 +      const int arc_steps = ARC_STEPS;
 +      const float color_act[4] = {1.0f, 1.0f, 1.0f, 1.0f};
 +      const float color_base[4] = {0.0f, 0.0f, 0.0f, 1.0f};
 +      unsigned char color_text[3];
 +      unsigned char color_wire[3];
 +      float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f};
 +
 +      /* anti-aliased lines for more consistent appearance */
 +      GPU_line_smooth(true);
 +
 +      BLF_enable(blf_mono_font, BLF_ROTATION);
 +      BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi);
 +      BLF_rotation(blf_mono_font, 0.0f);
 +
 +      UI_GetThemeColor3ubv(TH_TEXT, color_text);
 +      UI_GetThemeColor3ubv(TH_WIRE, color_wire);
 +
 +      const bool is_act = (mpr->flag & WM_MANIPULATOR_DRAW_HOVER);
 +      float dir_ruler[2];
 +      float co_ss[3][2];
 +      int j;
 +
 +      /* should these be checked? - ok for now not to */
 +      for (j = 0; j < 3; j++) {
 +              ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
 +      }
 +
 +      GPU_blend(true);
 +
 +      const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +
 +      if (ruler_item->flag & RULERITEM_USE_ANGLE) {
 +              immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
 +
 +              float viewport_size[4];
 +              GPU_viewport_size_getf(viewport_size);
 +              immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
 +
 +              immUniform1i("colors_len", 2);  /* "advanced" mode */
 +              const float *col = is_act ? color_act : color_base;
 +              immUniformArray4fv("colors", (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, 2);
 +              immUniform1f("dash_width", 6.0f);
 +
 +              immBegin(GWN_PRIM_LINE_STRIP, 3);
 +
 +              immVertex2fv(shdr_pos, co_ss[0]);
 +              immVertex2fv(shdr_pos, co_ss[1]);
 +              immVertex2fv(shdr_pos, co_ss[2]);
 +
 +              immEnd();
 +
 +              immUnbindProgram();
 +
 +              immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
 +
 +              /* arc */
 +              {
 +                      float dir_tmp[3];
 +                      float co_tmp[3];
 +                      float arc_ss_coord[2];
 +
 +                      float dir_a[3];
 +                      float dir_b[3];
 +                      float quat[4];
 +                      float axis[3];
 +                      float angle;
 +                      const float px_scale = (ED_view3d_pixel_size(rv3d, ruler_item->co[1]) *
 +                                              min_fff(arc_size,
 +                                                      len_v2v2(co_ss[0], co_ss[1]) / 2.0f,
 +                                                      len_v2v2(co_ss[2], co_ss[1]) / 2.0f));
 +
 +                      sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]);
 +                      sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]);
 +                      normalize_v3(dir_a);
 +                      normalize_v3(dir_b);
 +
 +                      cross_v3_v3v3(axis, dir_a, dir_b);
 +                      angle = angle_normalized_v3v3(dir_a, dir_b);
 +
 +                      axis_angle_to_quat(quat, axis, angle / arc_steps);
 +
 +                      copy_v3_v3(dir_tmp, dir_a);
 +
 +                      immUniformColor3ubv(color_wire);
 +
 +                      immBegin(GWN_PRIM_LINE_STRIP, arc_steps + 1);
 +
 +                      for (j = 0; j <= arc_steps; j++) {
 +                              madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale);
 +                              ED_view3d_project_float_global(ar, co_tmp, arc_ss_coord, V3D_PROJ_TEST_NOP);
 +                              mul_qt_v3(quat, dir_tmp);
 +
 +                              immVertex2fv(shdr_pos, arc_ss_coord);
 +                      }
 +
 +                      immEnd();
 +              }
 +
 +              /* capping */
 +              {
 +                      float rot_90_vec_a[2];
 +                      float rot_90_vec_b[2];
 +                      float cap[2];
 +
 +                      sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]);
 +                      rot_90_vec_a[0] = -dir_ruler[1];
 +                      rot_90_vec_a[1] =  dir_ruler[0];
 +                      normalize_v2(rot_90_vec_a);
 +
 +                      sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]);
 +                      rot_90_vec_b[0] = -dir_ruler[1];
 +                      rot_90_vec_b[1] =  dir_ruler[0];
 +                      normalize_v2(rot_90_vec_b);
 +
 +                      GPU_blend(true);
 +
 +                      immUniformColor3ubv(color_wire);
 +
 +                      immBegin(GWN_PRIM_LINES, 8);
 +
 +                      madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
 +                      immVertex2fv(shdr_pos, cap);
 +                      madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
 +                      immVertex2fv(shdr_pos, cap);
 +
 +                      madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
 +                      immVertex2fv(shdr_pos, cap);
 +                      madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
 +                      immVertex2fv(shdr_pos, cap);
 +
 +                      /* angle vertex */
 +                      immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
 +                      immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
 +                      immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
 +                      immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
 +
 +                      immEnd();
 +
 +                      GPU_blend(false);
 +              }
 +
 +              immUnbindProgram();
 +
 +              /* text */
 +              {
 +                      char numstr[256];
 +                      float numstr_size[2];
 +                      float posit[2];
 +                      const int prec = 2;  /* XXX, todo, make optional */
 +
 +                      ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
 +
 +                      BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
 +
 +                      posit[0] = co_ss[1][0] + (cap_size * 2.0f);
 +                      posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
 +
 +                      /* draw text (bg) */
 +                      UI_draw_roundbox_corner_set(UI_CNR_ALL);
 +                      UI_draw_roundbox_aa(
 +                              true,
 +                              posit[0] - bg_margin,                  posit[1] - bg_margin,
 +                              posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1],
 +                              bg_radius, color_back);
 +                      /* draw text */
 +                      BLF_color3ubv(blf_mono_font, color_text);
 +                      BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
 +                      BLF_rotation(blf_mono_font, 0.0f);
 +                      BLF_draw(blf_mono_font, numstr, sizeof(numstr));
 +              }
 +      }
 +      else {
 +              immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
 +
 +              float viewport_size[4];
 +              GPU_viewport_size_getf(viewport_size);
 +              immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
 +
 +              immUniform1i("colors_len", 2);  /* "advanced" mode */
 +              const float *col = is_act ? color_act : color_base;
 +              immUniformArray4fv("colors", (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}}, 2);
 +              immUniform1f("dash_width", 6.0f);
 +
 +              immBegin(GWN_PRIM_LINES, 2);
 +
 +              immVertex2fv(shdr_pos, co_ss[0]);
 +              immVertex2fv(shdr_pos, co_ss[2]);
 +
 +              immEnd();
 +
 +              immUnbindProgram();
 +
 +              immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
 +
 +              sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);
 +
 +              /* capping */
 +              {
 +                      float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]};
 +                      float cap[2];
 +
 +                      normalize_v2(rot_90_vec);
 +
 +                      GPU_blend(true);
 +
 +                      immUniformColor3ubv(color_wire);
 +
 +                      immBegin(GWN_PRIM_LINES, 4);
 +
 +                      madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
 +                      immVertex2fv(shdr_pos, cap);
 +                      madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
 +                      immVertex2fv(shdr_pos, cap);
 +
 +                      madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
 +                      immVertex2fv(shdr_pos, cap);
 +                      madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
 +                      immVertex2fv(shdr_pos, cap);
 +
 +                      immEnd();
 +
 +                      GPU_blend(false);
 +              }
 +
 +              immUnbindProgram();
 +
 +              /* text */
 +              {
 +                      char numstr[256];
 +                      float numstr_size[2];
 +                      const int prec = 6;  /* XXX, todo, make optional */
 +                      float posit[2];
 +
 +                      ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
 +
 +                      BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);
 +
 +                      mid_v2_v2v2(posit, co_ss[0], co_ss[2]);
 +
 +                      /* center text */
 +                      posit[0] -= numstr_size[0] / 2.0f;
 +                      posit[1] -= numstr_size[1] / 2.0f;
 +
 +                      /* draw text (bg) */
 +                      UI_draw_roundbox_corner_set(UI_CNR_ALL);
 +                      UI_draw_roundbox_aa(
 +                              true,
 +                              posit[0] - bg_margin,                  posit[1] - bg_margin,
 +                              posit[0] + bg_margin + numstr_size[0], posit[1] + bg_margin + numstr_size[1],
 +                              bg_radius, color_back);
 +                      /* draw text */
 +                      BLF_color3ubv(blf_mono_font, color_text);
 +                      BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
 +                      BLF_draw(blf_mono_font, numstr, sizeof(numstr));
 +              }
 +      }
 +
 +      GPU_line_smooth(false);
 +
 +      BLF_disable(blf_mono_font, BLF_ROTATION);
 +
 +#undef ARC_STEPS
 +
 +      /* draw snap */
 +      if ((ruler_info->snap_flag & RULER_SNAP_OK) &&
 +          (ruler_info->state == RULER_STATE_DRAG) &&
 +          (ruler_item->mpr.interaction_data != NULL))
 +      {
 +              RulerInteraction *inter = ruler_item->mpr.interaction_data;
 +              /* size from drawSnapping */
 +              const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
 +              float co_ss_snap[3];
 +              ED_view3d_project_float_global(ar, ruler_item->co[inter->co_index], co_ss_snap, V3D_PROJ_TEST_NOP);
 +
 +              unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
 +
 +              immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
 +              immUniformColor4fv(color_act);
 +
 +              imm_draw_circle_wire_2d(pos, co_ss_snap[0], co_ss_snap[1], size * U.pixelsize, 32);
 +
 +              immUnbindProgram();
 +      }
 +}
 +
 +static int manipulator_ruler_test_select(
 +        bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event)
 +{
 +      RulerItem *ruler_item_pick = (RulerItem *)mpr;
 +      float mval_fl[2] = {UNPACK2(event->mval)};
 +      int co_index;
 +
 +      /* select and drag */
 +      if (view3d_ruler_pick(mpr->parent_mgroup, ruler_item_pick, mval_fl, &co_index)) {
 +              if (co_index == -1) {
 +                      if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) {
 +                              return PART_LINE;
 +                      }
 +              }
 +              else {
 +                      return co_index;
 +              }
 +      }
 +      return -1;
 +}
 +
 +static int manipulator_ruler_modal(
 +        bContext *C, wmManipulator *mpr, const wmEvent *event,
 +        eWM_ManipulatorTweak UNUSED(tweak_flag))
 +{
 +      bool do_draw = false;
 +      int exit_code = OPERATOR_RUNNING_MODAL;
 +      RulerInfo *ruler_info = mpr->parent_mgroup->customdata;
 +      RulerItem *ruler_item = (RulerItem *)mpr;
 +      RulerInteraction *inter = ruler_item->mpr.interaction_data;
 +      ARegion *ar = CTX_wm_region(C);
 +
 +      ruler_info->ar = ar;
 +
 +      switch (event->type) {
 +              case MOUSEMOVE:
 +              {
 +                      if (ruler_info->state == RULER_STATE_DRAG) {
 +                              if (view3d_ruler_item_mousemove(
 +                                      ruler_info, ruler_item, event->mval,
 +                                      event->shift != 0, event->ctrl != 0))
 +                              {
 +                                      do_draw = true;
 +                              }
 +                              inter->inside_region = BLI_rcti_isect_pt_v(&ar->winrct, &event->x);
 +                      }
 +                      break;
 +              }
 +      }
 +      if (do_draw) {
 +              ED_region_tag_redraw(ar);
 +      }
 +      return exit_code;
 +}
 +
 +static int manipulator_ruler_invoke(
 +        bContext *C, wmManipulator *mpr, const wmEvent *event)
 +{
 +      wmManipulatorGroup *mgroup = mpr->parent_mgroup;
 +      RulerInfo *ruler_info = mgroup->customdata;
 +      RulerItem *ruler_item_pick = (RulerItem *)mpr;
 +      RulerInteraction *inter = MEM_callocN(sizeof(RulerInteraction), __func__);
 +      mpr->interaction_data = inter;
 +
 +      ARegion *ar = ruler_info->ar;
 +
 +      const float mval_fl[2] = {UNPACK2(event->mval)};
 +
 +      /* select and drag */
 +      if (mpr->highlight_part == PART_LINE) {
 +              if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) {
 +                      /* Add Center Point */
 +                      ruler_item_pick->flag |= RULERITEM_USE_ANGLE;
 +                      inter->co_index = 1;
 +                      ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
 +
 +                      /* find the factor */
 +                      {
 +                              float co_ss[2][2];
 +                              float fac;
 +
 +                              ED_view3d_project_float_global(ar, ruler_item_pick->co[0], co_ss[0], V3D_PROJ_TEST_NOP);
 +                              ED_view3d_project_float_global(ar, ruler_item_pick->co[2], co_ss[1], V3D_PROJ_TEST_NOP);
 +
 +                              fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]);
 +                              CLAMP(fac, 0.0f, 1.0f);
 +
 +                              interp_v3_v3v3(ruler_item_pick->co[1],
 +                                             ruler_item_pick->co[0],
 +                                             ruler_item_pick->co[2], fac);
 +                      }
 +
 +                      /* update the new location */
 +                      view3d_ruler_item_mousemove(
 +                              ruler_info, ruler_item_pick, event->mval,
 +                              event->shift != 0, event->ctrl != 0);
 +              }
 +      }
 +      else {
 +              inter->co_index = mpr->highlight_part;
 +              ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
 +
 +              /* store the initial depth */
 +              copy_v3_v3(inter->drag_start_co, ruler_item_pick->co[inter->co_index]);
 +      }
 +
 +      return OPERATOR_RUNNING_MODAL;
 +}
 +
 +static void manipulator_ruler_exit(bContext *C, wmManipulator *mpr, const bool cancel)
 +{
 +      wmManipulatorGroup *mgroup = mpr->parent_mgroup;
 +      RulerInfo *ruler_info = mgroup->customdata;
 +
 +      if (!cancel) {
 +              if (ruler_info->state == RULER_STATE_DRAG) {
 +                      RulerItem *ruler_item = (RulerItem *)mpr;
 +                      RulerInteraction *inter = mpr->interaction_data;
 +                      /* rubber-band angle removal */
 +                      if (!inter->inside_region) {
 +                              if ((inter->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) {
 +                                      ruler_item->flag &= ~RULERITEM_USE_ANGLE;
 +                              }
 +                              else {
 +                                      /* Not ideal, since the ruler isn't a mode and we don't want to override delete key
 +                                       * use dragging out of the view for removal. */
 +                                      ruler_item_remove(C, mgroup, ruler_item);
 +                                      ruler_item = NULL;
 +                                      mpr = NULL;
 +                                      inter = NULL;
 +                              }
 +                      }
 +                      if (ruler_info->snap_flag & RULER_SNAP_OK) {
 +                              ruler_info->snap_flag &= ~RULER_SNAP_OK;
 +                      }
 +                      ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
 +              }
 +              /* We could convert only the current manipulator, for now just re-generate. */
 +              view3d_ruler_to_gpencil(C, mgroup);
 +      }
 +
 +      if (mpr) {
 +              MEM_SAFE_FREE(mpr->interaction_data);
 +      }
 +
 +      ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
 +}
 +
 +static int manipulator_ruler_cursor_get(wmManipulator *mpr)
 +{
 +      if (mpr->highlight_part == PART_LINE) {
 +              return BC_CROSSCURSOR;
 +      }
 +      return BC_NSEW_SCROLLCURSOR;
 +}
 +
 +void VIEW3D_WT_ruler_item(wmManipulatorType *wt)
 +{
 +      /* identifiers */
 +      wt->idname = "VIEW3D_WT_ruler_item";
 +
 +      /* api callbacks */
 +      wt->draw = manipulator_ruler_draw;
 +      wt->test_select = manipulator_ruler_test_select;
 +      wt->modal = manipulator_ruler_modal;
 +      wt->invoke = manipulator_ruler_invoke;
 +      wt->exit = manipulator_ruler_exit;
 +      wt->cursor_get = manipulator_ruler_cursor_get;
 +
 +      wt->struct_size = sizeof(RulerItem);
 +}
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Ruler Manipulator Group
 + * \{ */
 +
 +static bool WIDGETGROUP_ruler_poll(const bContext *C, wmManipulatorGroupType *wgt)
 +{
 +      bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
 +      if ((tref_rt == NULL) ||
 +          !STREQ(wgt->idname, tref_rt->manipulator_group))
 +      {
 +              WM_manipulator_group_type_unlink_delayed_ptr(wgt);
 +              return false;
 +      }
 +      return true;
 +}
 +
 +static void WIDGETGROUP_ruler_setup(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__);
 +
 +      if (view3d_ruler_from_gpencil(C, mgroup)) {
 +              /* nop */
 +      }
 +
 +      wmWindow *win = CTX_wm_window(C);
 +      ScrArea *sa = CTX_wm_area(C);
 +      ARegion *ar = CTX_wm_region(C);
 +      ruler_info->win = win;
 +      ruler_info->sa = sa;
 +      ruler_info->ar = ar;
 +
 +      mgroup->customdata = ruler_info;
 +}
 +
 +void VIEW3D_WGT_ruler(wmManipulatorGroupType *wgt)
 +{
 +      wgt->name = "Ruler Widgets";
 +      wgt->idname = view3d_wgt_ruler_id;
 +
 +      wgt->flag |= WM_MANIPULATORGROUPTYPE_SCALE | WM_MANIPULATORGROUPTYPE_DRAW_MODAL_ALL;
 +
 +      wgt->mmap_params.spaceid = SPACE_VIEW3D;
 +      wgt->mmap_params.regionid = RGN_TYPE_WINDOW;
 +
 +      wgt->poll = WIDGETGROUP_ruler_poll;
 +      wgt->setup = WIDGETGROUP_ruler_setup;
 +}
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Add Ruler Operator
 + * \{ */
 +
++static bool view3d_ruler_poll(bContext *C)
 +{
 +      bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
 +      if ((tref_rt == NULL) ||
 +          !STREQ(view3d_wgt_ruler_id, tref_rt->manipulator_group) ||
 +          CTX_wm_region_view3d(C) == NULL)
 +      {
 +              return false;
 +      }
 +      return true;
 +}
 +
 +static int view3d_ruler_add_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
 +{
 +      ARegion *ar = CTX_wm_region(C);
 +      View3D *v3d = CTX_wm_view3d(C);
 +      RegionView3D *rv3d = ar->regiondata;
 +
 +      wmManipulatorMap *mmap = ar->manipulator_map;
 +      wmManipulatorGroup *mgroup = WM_manipulatormap_group_find(mmap, view3d_wgt_ruler_id);
 +      const bool use_depth = (v3d->drawtype >= OB_SOLID);
 +
 +      /* Create new line */
 +      RulerItem *ruler_item;
 +      ruler_item = ruler_item_add(mgroup);
 +
 +      /* This is a little weak, but there is no real good way to tweak directly. */
 +      WM_manipulator_highlight_set(mmap, &ruler_item->mpr);
 +      if (WM_operator_name_call(
 +              C, "MANIPULATORGROUP_OT_manipulator_tweak",
 +              WM_OP_INVOKE_REGION_WIN, NULL) == OPERATOR_RUNNING_MODAL)
 +      {
 +              RulerInfo *ruler_info = mgroup->customdata;
 +              RulerInteraction *inter = ruler_item->mpr.interaction_data;
 +              if (use_depth) {
 +                      /* snap the first point added, not essential but handy */
 +                      inter->co_index = 0;
 +                      view3d_ruler_item_mousemove(ruler_info, ruler_item, event->mval, false, true);
 +                      copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]);
 +              }
 +              else {
 +                      negate_v3_v3(inter->drag_start_co, rv3d->ofs);
 +                      copy_v3_v3(ruler_item->co[0], inter->drag_start_co);
 +                      view3d_ruler_item_project(ruler_info, ruler_item->co[0], event->mval);
 +              }
 +
 +              copy_v3_v3(ruler_item->co[2], ruler_item->co[0]);
 +              ruler_item->mpr.highlight_part = inter->co_index = 2;
 +      }
 +      return OPERATOR_FINISHED;
 +}
 +
 +void VIEW3D_OT_ruler_add(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name = "Ruler Add";
 +      ot->idname = "VIEW3D_OT_ruler_add";
 +      ot->description = "";
 +
 +      ot->invoke = view3d_ruler_add_invoke;
 +      ot->poll = view3d_ruler_poll;
 +
 +      /* flags */
 +      ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
 +}
 +
 +/** \} */
index 53ac3bdd45a22399df7d33f0b65357b6ef896873,3f9534751c1fc3860c27655e0fa8ced20517193d..721c5f2d3fa169b364be8b23f0f85e6b0132b8c4
@@@ -1695,17 -1670,17 +1695,17 @@@ static void drawArc(float size, float a
        float angle;
        int a;
  
 -      glBegin(GL_LINE_STRIP);
 +      immBegin(GWN_PRIM_LINE_STRIP, segments + 1);
  
        for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
 -              glVertex2f(cosf(angle) * size, sinf(angle) * size);
 +              immVertex2f(POS_INDEX, cosf(angle) * size, sinf(angle) * size);
        }
 -      glVertex2f(cosf(angle_end) * size, sinf(angle_end) * size);
 +      immVertex2f(POS_INDEX, cosf(angle_end) * size, sinf(angle_end) * size);
  
 -      glEnd();
 +      immEnd();
  }
  
- static int helpline_poll(bContext *C)
+ static bool helpline_poll(bContext *C)
  {
        ARegion *ar = CTX_wm_region(C);
  
index 89e210ca7a2d23067d91edeaff13c9ccfdd33f92,7505a0ba7fef79709ee0199025bfba70b4148215..a8853743a57f7e4e725ced1e4846fd6a9bf49ae4
@@@ -223,9 -221,10 +223,9 @@@ static int delete_orientation_invoke(bC
        return delete_orientation_exec(C, op);
  }
  
- static int delete_orientation_poll(bContext *C)
+ static bool delete_orientation_poll(bContext *C)
  {
 -      int selected_index = -1;
 -      View3D *v3d = CTX_wm_view3d(C);
 +      Scene *scene = CTX_data_scene(C);
  
        if (ED_operator_areaactive(C) == 0)
                return 0;
Simple merge
index eb14ca9ae2d636589bed69369fc4921a5023e74d,06eae0ee63db9a9f6194835fb858a69fa32b892f..52409dc2a1f889987200b1cfabfd9038d0529efd
@@@ -1565,21 -1390,15 +1565,21 @@@ static int uv_from_view_exec(bContext *
                }
        }
  
 -      uv_map_clip_correct(scene, obedit, em, op);
 +      if (changed_multi) {
 +              uv_map_clip_correct_multi(scene, objects, objects_len, op);
 +      }
  
 -      DAG_id_tag_update(obedit->data, 0);
 -      WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
 +      MEM_freeN(objects);
  
 -      return OPERATOR_FINISHED;
 +      if (changed_multi) {
 +              return OPERATOR_FINISHED;
 +      }
 +      else {
 +              return OPERATOR_CANCELLED;
 +      }
  }
  
- static int uv_from_view_poll(bContext *C)
+ static bool uv_from_view_poll(bContext *C)
  {
        RegionView3D *rv3d = CTX_wm_region_view3d(C);
  
Simple merge
index e263ca76f61432e5e2d874fd3e49494966486a13,fac0f39b11c1bf4daf527b6a0365435ab724d694..5784b2a489a1be9e786f0c36fb48721114111d16
@@@ -277,19 -237,19 +277,19 @@@ void rna_ViewLayer_pass_update(struct M
  /* named internal so as not to conflict with obj.update() rna func */
  void rna_Object_internal_update_data(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
  void rna_Mesh_update_draw(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
 -void rna_TextureSlot_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
 +void rna_TextureSlot_update(struct bContext *C, struct PointerRNA *ptr);
  
  /* basic poll functions for object types */
int rna_Armature_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
int rna_Camera_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
int rna_Curve_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
int rna_Lamp_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
int rna_Lattice_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
int rna_Mesh_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Armature_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Camera_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Curve_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Lamp_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Lattice_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Mesh_object_poll(struct PointerRNA *ptr, struct PointerRNA value);
  
  /* basic poll functions for actions (to prevent actions getting set in wrong places) */
int rna_Action_id_poll(struct PointerRNA *ptr, struct PointerRNA value);
int rna_Action_actedit_assign_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Action_id_poll(struct PointerRNA *ptr, struct PointerRNA value);
bool rna_Action_actedit_assign_poll(struct PointerRNA *ptr, struct PointerRNA value);
  
  char *rna_TextureSlot_path(struct PointerRNA *ptr);
  char *rna_Node_ImageUser_path(struct PointerRNA *ptr);
index e75a03edac1b6c7bbd1b95b112b96f718f9ce8d3,9b741cf044acfdc80f716609c3975b3e20dc5fe9..04f4c41659ddeed19c9bb7e079267233380da6b0
@@@ -1357,71 -1476,8 +1357,71 @@@ static float rna_VertexGroup_weight(ID 
        return weight;
  }
  
 +static bFaceMap *rna_Object_fmap_new(Object *ob, const char *name)
 +{
 +      bFaceMap *fmap = BKE_object_facemap_add_name(ob, name);
 +
 +      WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
 +
 +      return fmap;
 +}
 +
 +static void rna_Object_fmap_remove(Object *ob, ReportList *reports, PointerRNA *fmap_ptr)
 +{
 +      bFaceMap *fmap = fmap_ptr->data;
 +      if (BLI_findindex(&ob->fmaps, fmap) == -1) {
 +              BKE_reportf(reports, RPT_ERROR, "FaceMap '%s' not in object '%s'", fmap->name, ob->id.name + 2);
 +              return;
 +      }
 +
 +      BKE_object_facemap_remove(ob, fmap);
 +      RNA_POINTER_INVALIDATE(fmap_ptr);
 +
 +      WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
 +}
 +
 +
 +static void rna_Object_fmap_clear(Object *ob)
 +{
 +      BKE_object_facemap_clear(ob);
 +
 +      WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
 +}
 +
 +
 +static void rna_FaceMap_face_add(ID *id, bFaceMap *fmap, ReportList *reports, int index_len,
 +                                 int *index)
 +{
 +      Object *ob = (Object *)id;
 +
 +      if (BKE_object_is_in_editmode(ob)) {
 +              BKE_report(reports, RPT_ERROR, "FaceMap.add(): cannot be called while object is in edit mode");
 +              return;
 +      }
 +
 +      while (index_len--)
 +              ED_object_facemap_face_add(ob, fmap, *index++);
 +
 +      WM_main_add_notifier(NC_GEOM | ND_DATA, (ID *)ob->data);
 +}
 +
 +static void rna_FaceMap_face_remove(ID *id, bFaceMap *fmap, ReportList *reports, int index_len, int *index)
 +{
 +      Object *ob = (Object *)id;
 +
 +      if (BKE_object_is_in_editmode(ob)) {
 +              BKE_report(reports, RPT_ERROR, "FaceMap.add(): cannot be called while object is in edit mode");
 +              return;
 +      }
 +
 +      while (index_len--)
 +              ED_object_facemap_face_remove(ob, fmap, *index++);
 +
 +      WM_main_add_notifier(NC_GEOM | ND_DATA, (ID *)ob->data);
 +}
 +
  /* generic poll functions */
int rna_Lattice_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
bool rna_Lattice_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
  {
        return ((Object *)value.id.data)->type == OB_LATTICE;
  }
diff --cc