Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Sun, 1 Jul 2018 14:22:06 +0000 (16:22 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 1 Jul 2018 14:22:06 +0000 (16:22 +0200)
65 files changed:
1  2 
intern/cycles/blender/blender_util.h
source/blender/blenkernel/BKE_curve.h
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/mesh_validate.c
source/blender/editors/armature/pose_edit.c
source/blender/editors/include/ED_mesh.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/include/UI_interface.h
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_layout.c
source/blender/editors/interface/interface_templates.c
source/blender/editors/mesh/editmesh_extrude.c
source/blender/editors/mesh/editmesh_loopcut.c
source/blender/editors/mesh/mesh_data.c
source/blender/editors/object/object_add.c
source/blender/editors/space_clip/clip_buttons.c
source/blender/editors/space_image/image_buttons.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform_manipulator_2d.c
source/blender/editors/transform/transform_manipulator_3d.c
source/blender/editors/transform/transform_ops.c
source/blender/makesrna/RNA_access.h
source/blender/makesrna/RNA_define.h
source/blender/makesrna/RNA_types.h
source/blender/makesrna/intern/makesrna.c
source/blender/makesrna/intern/rna_ID.c
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_animation.c
source/blender/makesrna/intern/rna_armature.c
source/blender/makesrna/intern/rna_curve_api.c
source/blender/makesrna/intern/rna_define.c
source/blender/makesrna/intern/rna_depsgraph.c
source/blender/makesrna/intern/rna_dynamicpaint.c
source/blender/makesrna/intern/rna_fcurve.c
source/blender/makesrna/intern/rna_gpencil.c
source/blender/makesrna/intern/rna_image_api.c
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_internal_types.h
source/blender/makesrna/intern/rna_lattice_api.c
source/blender/makesrna/intern/rna_main_api.c
source/blender/makesrna/intern/rna_mesh_api.c
source/blender/makesrna/intern/rna_nodetree.c
source/blender/makesrna/intern/rna_object_api.c
source/blender/makesrna/intern/rna_render.c
source/blender/makesrna/intern/rna_rigidbody.c
source/blender/makesrna/intern/rna_rna.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_scene_api.c
source/blender/makesrna/intern/rna_screen.c
source/blender/makesrna/intern/rna_sculpt_paint.c
source/blender/makesrna/intern/rna_space.c
source/blender/makesrna/intern/rna_tracking.c
source/blender/makesrna/intern/rna_ui.c
source/blender/makesrna/intern/rna_ui_api.c
source/blender/makesrna/intern/rna_wm.c
source/blender/makesrna/intern/rna_wm_api.c
source/blender/makesrna/intern/rna_wm_manipulator_api.c
source/blender/makesrna/intern/rna_workspace.c
source/blender/python/intern/bpy_rna.c
source/blender/render/extern/include/RE_engine.h
source/blender/render/intern/source/external_engine.c
source/blender/windowmanager/WM_keymap.h
source/blender/windowmanager/intern/wm_keymap.c

@@@ -304,10 -304,10 +304,10 @@@ static inline uint get_layer(const BL::
        return layer;
  }
  
- static inline uint get_layer(const BL::Array<int, 20>& array,
-                              const BL::Array<int, 8>& local_array,
+ static inline uint get_layer(const BL::Array<bool, 20>& array,
+                              const BL::Array<bool, 8>& local_array,
                               bool is_light = false,
 -                             uint scene_layers = (1 << 20) - 1)
 +                             uint view_layers = (1 << 20) - 1)
  {
        uint layer = 0;
  
Simple merge
@@@ -467,9 -409,9 +467,9 @@@ void BKE_mesh_calc_relative_deform
  
  /* *** mesh_validate.c *** */
  
int BKE_mesh_validate(struct Mesh *me, const int do_verbose, const int cddata_check_mask);
bool BKE_mesh_validate(struct Mesh *me, const bool do_verbose, const bool cddata_check_mask);
 -void BKE_mesh_cd_validate(struct Mesh *me);
 +bool BKE_mesh_is_valid(struct Mesh *me);
int BKE_mesh_validate_material_indices(struct Mesh *me);
bool BKE_mesh_validate_material_indices(struct Mesh *me);
  
  bool BKE_mesh_validate_arrays(
          struct Mesh *me,
@@@ -923,7 -908,7 +923,7 @@@ void ARMATURE_OT_armature_layers(wmOper
  /* Present a popup to get the layers that should be used */
  static int pose_bone_layers_invoke(bContext *C, wmOperator *op, const wmEvent *event)
  {
-       int layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
 -      bool layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
++      bool layers[32] = {0}; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
  
        /* get layers that are active already */
        CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
@@@ -1025,8 -1009,9 +1025,8 @@@ static int armature_bone_layers_invoke(
  static int armature_bone_layers_exec(bContext *C, wmOperator *op)
  {
        Object *ob = CTX_data_edit_object(C);
 -      bArmature *arm = (ob) ? ob->data : NULL;
        PointerRNA ptr;
-       int layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
+       bool layers[32]; /* hardcoded for now - we can only have 32 armature layers, so this should be fine... */
  
        /* get the values set in the operator properties */
        RNA_boolean_get_array(op->ptr, "layers", layers);
@@@ -407,7 -354,7 +407,7 @@@ void ED_view3d_check_mats_rv3d(struct R
  #  define ED_view3d_clear_mats_rv3d(rv3d) (void)(rv3d)
  #  define ED_view3d_check_mats_rv3d(rv3d) (void)(rv3d)
  #endif
- int ED_view3d_view_layer_set(int lay, const int *values, int *active);
 -int ED_view3d_scene_layer_set(int lay, const bool *values, int *active);
++int ED_view3d_view_layer_set(int lay, const bool *values, int *active);
  
  struct RV3DMatrixStore *ED_view3d_mats_rv3d_backup(struct RegionView3D *rv3d);
  void                    ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixStore *rv3dmat);
@@@ -985,16 -916,11 +985,16 @@@ bool uiLayoutGetKeepAspect(uiLayout *la
  int uiLayoutGetWidth(uiLayout *layout);
  float uiLayoutGetScaleX(uiLayout *layout);
  float uiLayoutGetScaleY(uiLayout *layout);
 +int uiLayoutGetEmboss(uiLayout *layout);
 +bool uiLayoutGetPropSep(uiLayout *layout);
 +bool uiLayoutGetPropDecorate(uiLayout *layout);
  
  /* layout specifiers */
- uiLayout *uiLayoutRow(uiLayout *layout, int align);
- uiLayout *uiLayoutColumn(uiLayout *layout, int align);
- uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align);
+ uiLayout *uiLayoutRow(uiLayout *layout, bool align);
+ uiLayout *uiLayoutColumn(uiLayout *layout, bool align);
+ uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align);
 +uiLayout *uiLayoutGridFlow(
-         uiLayout *layout, int row_major, int num_columns, int even_columns, int even_rows, int align);
++        uiLayout *layout, bool row_major, int columns_len, bool even_columns, bool even_rows, bool align);
  uiLayout *uiLayoutBox(uiLayout *layout);
  uiLayout *uiLayoutListBox(uiLayout *layout, struct uiList *ui_list, struct PointerRNA *ptr, struct PropertyRNA *prop,
                            struct PointerRNA *actptr, struct PropertyRNA *actprop);
@@@ -1036,26 -946,24 +1036,26 @@@ void uiTemplateSearchPreview
  void uiTemplatePathBuilder(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
                             struct PointerRNA *root_ptr, const char *text);
  uiLayout *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
 +
 +void uiTemplateOperatorRedoProperties(uiLayout *layout, const struct bContext *C);
 +
  uiLayout *uiTemplateConstraint(uiLayout *layout, struct PointerRNA *ptr);
- void uiTemplatePreview(uiLayout *layout, struct bContext *C, struct ID *id, int show_buttons, struct ID *parent,
+ void uiTemplatePreview(uiLayout *layout, struct bContext *C, struct ID *id, bool show_buttons, struct ID *parent,
                         struct MTex *slot, const char *preview_id);
- void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int expand);
+ void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool expand);
 +void uiTemplateIcon(uiLayout *layout, int icon_value, float icon_scale);
- void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int show_labels, float icon_scale);
+ void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool show_labels, float icon_scale);
  void uiTemplateHistogram(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
  void uiTemplateWaveform(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
  void uiTemplateVectorscope(uiLayout *layout, struct PointerRNA *ptr, const char *propname);
  void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type,
-                             int levels, int brush, int neg_slope);
- void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic);
- void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color);
+                             bool levels, bool brush, bool neg_slope);
+ void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool value_slider, bool lock, bool lock_luminosity, bool cubic);
+ void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool color);
  void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
                        PointerRNA *used_ptr, const char *used_propname, int active_layer);
- void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, int compact, int multiview);
- void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, int color_management);
 -void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
 -                      PointerRNA *used_ptr, const char *used_propname, int active_state);
+ void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, bool compact, bool multiview);
+ void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, bool color_management);
  void uiTemplateImageStereo3d(uiLayout *layout, struct PointerRNA *stereo3d_format_ptr);
  void uiTemplateImageViews(uiLayout *layout, struct PointerRNA *imaptr);
  void uiTemplateImageFormatViews(uiLayout *layout, PointerRNA *imfptr, PointerRNA *ptr);
@@@ -3525,23 -2870,10 +3525,23 @@@ static void ui_litem_init_from_parent(u
        litem->active = true;
        litem->enabled = true;
        litem->context = layout->context;
 -      litem->space = (align) ? 0 : layout->root->style->buttonspacex;
        litem->redalert = layout->redalert;
        litem->w = layout->w;
 +      litem->emboss = layout->emboss;
 +      litem->item.flag = (layout->item.flag & (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE));
        BLI_addtail(&layout->items, litem);
- uiLayout *uiLayoutRow(uiLayout *layout, int align)
 +}
 +
 +/* layout create functions */
++uiLayout *uiLayoutRow(uiLayout *layout, bool align)
 +{
 +      uiLayout *litem;
 +
 +      litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRow");
 +      ui_litem_init_from_parent(litem, layout, align);
 +
 +      litem->item.type = ITEM_LAYOUT_ROW;
 +      litem->space = (align) ? 0 : layout->root->style->buttonspacex;
  
        UI_block_layout_set_current(layout->root->block, litem);
  
@@@ -3568,31 -2906,17 +3568,31 @@@ uiLayout *uiLayoutColumnFlow(uiLayout *
        uiLayoutItemFlow *flow;
  
        flow = MEM_callocN(sizeof(uiLayoutItemFlow), "uiLayoutItemFlow");
 +      ui_litem_init_from_parent(&flow->litem, layout, align);
 +
        flow->litem.item.type = ITEM_LAYOUT_COLUMN_FLOW;
 -      flow->litem.root = layout->root;
 -      flow->litem.align = align;
 -      flow->litem.active = true;
 -      flow->litem.enabled = true;
 -      flow->litem.context = layout->context;
        flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
 -      flow->litem.redalert = layout->redalert;
 -      flow->litem.w = layout->w;
        flow->number = number;
 -      BLI_addtail(&layout->items, flow);
 +
 +      UI_block_layout_set_current(layout->root->block, &flow->litem);
 +
 +      return &flow->litem;
 +}
 +
 +uiLayout *uiLayoutGridFlow(
-         uiLayout *layout, int row_major, int columns_len, int even_columns, int even_rows, int align)
++        uiLayout *layout, bool row_major, int columns_len, bool even_columns, bool even_rows, bool align)
 +{
 +      uiLayoutItemGridFlow *flow;
 +
 +      flow = MEM_callocN(sizeof(uiLayoutItemGridFlow), __func__);
 +      flow->litem.item.type = ITEM_LAYOUT_GRID_FLOW;
 +      ui_litem_init_from_parent(&flow->litem, layout, align);
 +
 +      flow->litem.space = (flow->litem.align) ? 0 : layout->root->style->columnspace;
 +      flow->row_major = row_major;
 +      flow->columns_len = columns_len;
 +      flow->even_columns = even_columns;
 +      flow->even_rows = even_rows;
  
        UI_block_layout_set_current(layout->root->block, &flow->litem);
  
@@@ -358,326 -338,6 +358,326 @@@ void MESH_OT_extrude_repeat(wmOperatorT
  
  /** \} */
  
-                       int constraint[3] = {0, 0, 0};
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Extrude Manipulator
 + * \{ */
 +
 +#ifdef USE_MANIPULATOR
 +
 +const float extrude_button_scale = 0.15f;
 +const float extrude_button_offset_scale = 1.5f;
 +const float extrude_arrow_scale = 1.0f;
 +const float extrude_arrow_xyz_axis_scale = 1.0f;
 +const float extrude_arrow_normal_axis_scale = 1.75f;
 +
 +static const uchar shape_plus[] = {
 +      0x5f, 0xfb, 0x40, 0xee, 0x25, 0xda, 0x11, 0xbf, 0x4, 0xa0, 0x0, 0x80, 0x4, 0x5f, 0x11,
 +      0x40, 0x25, 0x25, 0x40, 0x11, 0x5f, 0x4, 0x7f, 0x0, 0xa0, 0x4, 0xbf, 0x11, 0xda, 0x25,
 +      0xee, 0x40, 0xfb, 0x5f, 0xff, 0x7f, 0xfb, 0xa0, 0xee, 0xbf, 0xda, 0xda, 0xbf, 0xee,
 +      0xa0, 0xfb, 0x80, 0xff, 0x6e, 0xd7, 0x92, 0xd7, 0x92, 0x90, 0xd8, 0x90, 0xd8, 0x6d,
 +      0x92, 0x6d, 0x92, 0x27, 0x6e, 0x27, 0x6e, 0x6d, 0x28, 0x6d, 0x28, 0x90, 0x6e,
 +      0x90, 0x6e, 0xd7, 0x80, 0xff, 0x5f, 0xfb, 0x5f, 0xfb,
 +};
 +
 +typedef struct ManipulatorExtrudeGroup {
 +
 +      /* XYZ & normal. */
 +      struct wmManipulator *invoke_xyz_no[4];
 +      struct wmManipulator *adjust_xyz_no[5];
 +
 +      struct {
 +              float normal_mat3[3][3];  /* use Z axis for normal. */
 +              int orientation_type;
 +      } data;
 +
 +      wmOperatorType *ot_extrude;
 +} ManipulatorExtrudeGroup;
 +
 +static void manipulator_mesh_extrude_orientation_matrix_set(
 +        struct ManipulatorExtrudeGroup *man, const float mat[3][3])
 +{
 +      for (int i = 0; i < 3; i++) {
 +              /* Set orientation without location. */
 +              for (int j = 0; j < 3; j++) {
 +                      copy_v3_v3(man->adjust_xyz_no[i]->matrix_basis[j], mat[j]);
 +              }
 +              /* nop when (i == 2). */
 +              swap_v3_v3(man->adjust_xyz_no[i]->matrix_basis[i], man->adjust_xyz_no[i]->matrix_basis[2]);
 +              /* Orient to normal gives generally less awkward results. */
 +              if (man->data.orientation_type != V3D_MANIP_NORMAL) {
 +                      if (dot_v3v3(man->adjust_xyz_no[i]->matrix_basis[2], man->data.normal_mat3[2]) < 0.0f) {
 +                              negate_v3(man->adjust_xyz_no[i]->matrix_basis[2]);
 +                      }
 +              }
 +              mul_v3_v3fl(
 +                      man->invoke_xyz_no[i]->matrix_offset[3],
 +                      man->adjust_xyz_no[i]->matrix_basis[2],
 +                      (extrude_arrow_xyz_axis_scale * extrude_button_offset_scale) / extrude_button_scale);
 +      }
 +}
 +
 +static bool manipulator_mesh_extrude_poll(const bContext *C, wmManipulatorGroupType *wgt)
 +{
 +      ScrArea *sa = CTX_wm_area(C);
 +      bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL;
 +      if ((tref_rt == NULL) ||
 +          !STREQ(wgt->idname, tref_rt->manipulator_group) ||
 +          !ED_operator_editmesh_view3d((bContext *)C))
 +      {
 +              WM_manipulator_group_type_unlink_delayed_ptr(wgt);
 +              return false;
 +      }
 +      return true;
 +}
 +
 +static void manipulator_mesh_extrude_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
 +{
 +      struct ManipulatorExtrudeGroup *man = MEM_callocN(sizeof(ManipulatorExtrudeGroup), __func__);
 +      mgroup->customdata = man;
 +
 +      const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true);
 +      const wmManipulatorType *wt_grab = WM_manipulatortype_find("MANIPULATOR_WT_button_2d", true);
 +
 +      for (int i = 0; i < 4; i++) {
 +              man->adjust_xyz_no[i] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL);
 +              man->invoke_xyz_no[i] = WM_manipulator_new_ptr(wt_grab, mgroup, NULL);
 +              man->invoke_xyz_no[i]->flag |= WM_MANIPULATOR_DRAW_OFFSET_SCALE;
 +      }
 +
 +      {
 +              PropertyRNA *prop = RNA_struct_find_property(man->invoke_xyz_no[3]->ptr, "shape");
 +              for (int i = 0; i < 4; i++) {
 +                      RNA_property_string_set_bytes(
 +                              man->invoke_xyz_no[i]->ptr, prop,
 +                              (const char *)shape_plus, ARRAY_SIZE(shape_plus));
 +              }
 +      }
 +
 +      man->ot_extrude = WM_operatortype_find("MESH_OT_extrude_context_move", true);
 +
 +      for (int i = 0; i < 3; i++) {
 +              UI_GetThemeColor3fv(TH_AXIS_X + i, man->invoke_xyz_no[i]->color);
 +              UI_GetThemeColor3fv(TH_AXIS_X + i, man->adjust_xyz_no[i]->color);
 +      }
 +      UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->invoke_xyz_no[3]->color);
 +      UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->adjust_xyz_no[3]->color);
 +
 +      for (int i = 0; i < 4; i++) {
 +              WM_manipulator_set_scale(man->invoke_xyz_no[i], extrude_button_scale);
 +              WM_manipulator_set_scale(man->adjust_xyz_no[i], extrude_arrow_scale);
 +      }
 +      WM_manipulator_set_scale(man->adjust_xyz_no[3], extrude_arrow_normal_axis_scale);
 +
 +      for (int i = 0; i < 4; i++) {
 +      }
 +
 +      for (int i = 0; i < 4; i++) {
 +              WM_manipulator_set_flag(man->adjust_xyz_no[i], WM_MANIPULATOR_DRAW_VALUE, true);
 +      }
 +
 +      /* XYZ & normal axis extrude. */
 +      for (int i = 0; i < 4; i++) {
 +              PointerRNA *ptr = WM_manipulator_operator_set(man->invoke_xyz_no[i], 0, man->ot_extrude, NULL);
 +              {
-                       int constraint[3] = {0, 0, 0};
++                      bool constraint[3] = {0, 0, 0};
 +                      constraint[MIN2(i, 2)] = 1;
 +                      PointerRNA macroptr = RNA_pointer_get(ptr, "TRANSFORM_OT_translate");
 +                      RNA_boolean_set(&macroptr, "release_confirm", true);
 +                      RNA_boolean_set_array(&macroptr, "constraint_axis", constraint);
 +              }
 +      }
 +
 +      /* Adjust extrude. */
 +      for (int i = 0; i < 4; i++) {
 +              PointerRNA *ptr = WM_manipulator_operator_set(man->adjust_xyz_no[i], 0, man->ot_extrude, NULL);
 +              {
-               int constraint_axis[3];
++                      bool constraint[3] = {0, 0, 0};
 +                      constraint[MIN2(i, 2)] = 1;
 +                      PointerRNA macroptr = RNA_pointer_get(ptr, "TRANSFORM_OT_translate");
 +                      RNA_boolean_set(&macroptr, "release_confirm", true);
 +                      RNA_boolean_set_array(&macroptr, "constraint_axis", constraint);
 +              }
 +              wmManipulatorOpElem *mpop = WM_manipulator_operator_get(man->adjust_xyz_no[i], 0);
 +              mpop->is_redo = true;
 +      }
 +}
 +
 +static void manipulator_mesh_extrude_refresh(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      ManipulatorExtrudeGroup *man = mgroup->customdata;
 +
 +      for (int i = 0; i < 4; i++) {
 +              WM_manipulator_set_flag(man->invoke_xyz_no[i], WM_MANIPULATOR_HIDDEN, true);
 +              WM_manipulator_set_flag(man->adjust_xyz_no[i], WM_MANIPULATOR_HIDDEN, true);
 +      }
 +
 +      if (G.moving) {
 +              return;
 +      }
 +
 +      Scene *scene = CTX_data_scene(C);
 +      man->data.orientation_type = scene->orientation_type;
 +      bool use_normal = (man->data.orientation_type != V3D_MANIP_NORMAL);
 +      const int axis_len_used = use_normal ? 4 : 3;
 +
 +      struct TransformBounds tbounds;
 +
 +      if (use_normal) {
 +              struct TransformBounds tbounds_normal;
 +              if (!ED_transform_calc_manipulator_stats(
 +                          C, &(struct TransformCalcParams){
 +                              .orientation_type = V3D_MANIP_NORMAL + 1,
 +                          }, &tbounds_normal))
 +              {
 +                      unit_m3(tbounds_normal.axis);
 +              }
 +              copy_m3_m3(man->data.normal_mat3, tbounds_normal.axis);
 +      }
 +
 +      /* TODO(campbell): run second since this modifies the 3D view, it should not. */
 +      if (!ED_transform_calc_manipulator_stats(
 +                  C, &(struct TransformCalcParams){
 +                      .orientation_type = man->data.orientation_type + 1,
 +                  }, &tbounds))
 +      {
 +              return;
 +      }
 +
 +      /* Main axis is normal. */
 +      if (!use_normal) {
 +              copy_m3_m3(man->data.normal_mat3, tbounds.axis);
 +      }
 +
 +      /* Offset the add icon. */
 +      mul_v3_v3fl(
 +              man->invoke_xyz_no[3]->matrix_offset[3],
 +              man->data.normal_mat3[2],
 +              (extrude_arrow_normal_axis_scale * extrude_button_offset_scale) / extrude_button_scale);
 +
 +      /* Needed for normal orientation. */
 +      manipulator_mesh_extrude_orientation_matrix_set(man, tbounds.axis);
 +      if (use_normal) {
 +              copy_m4_m3(man->adjust_xyz_no[3]->matrix_basis, man->data.normal_mat3);
 +      }
 +
 +      /* Location. */
 +      for (int i = 0; i < axis_len_used; i++) {
 +              WM_manipulator_set_matrix_location(man->invoke_xyz_no[i], tbounds.center);
 +              WM_manipulator_set_matrix_location(man->adjust_xyz_no[i], tbounds.center);
 +      }
 +
 +      wmOperator *op = WM_operator_last_redo(C);
 +      bool has_redo = (op && op->type == man->ot_extrude);
 +
 +      /* Un-hide. */
 +      for (int i = 0; i < axis_len_used; i++) {
 +              WM_manipulator_set_flag(man->invoke_xyz_no[i], WM_MANIPULATOR_HIDDEN, false);
 +              WM_manipulator_set_flag(man->adjust_xyz_no[i], WM_MANIPULATOR_HIDDEN, !has_redo);
 +      }
 +
 +      /* Operator properties. */
 +      if (use_normal) {
 +              wmManipulatorOpElem *mpop = WM_manipulator_operator_get(man->invoke_xyz_no[3], 0);
 +              PointerRNA macroptr = RNA_pointer_get(&mpop->ptr, "TRANSFORM_OT_translate");
 +              RNA_enum_set(&macroptr, "constraint_orientation", V3D_MANIP_NORMAL);
 +      }
 +
 +      /* Redo with current settings. */
 +      if (has_redo) {
 +              wmOperator *op_transform = op->macro.last;
 +              float value[4];
 +              RNA_float_get_array(op_transform->ptr, "value", value);
++              bool constraint_axis[3];
 +              RNA_boolean_get_array(op_transform->ptr, "constraint_axis", constraint_axis);
 +              int orientation_type = RNA_enum_get(op_transform->ptr, "constraint_orientation");
 +
 +              /* We could also access this from 'ot->last_properties' */
 +              for (int i = 0; i < 4; i++) {
 +                      if ((i != 3) ?
 +                          (orientation_type == man->data.orientation_type && constraint_axis[i]) :
 +                          (orientation_type == V3D_MANIP_NORMAL && constraint_axis[2]))
 +                      {
 +                              wmManipulatorOpElem *mpop = WM_manipulator_operator_get(man->adjust_xyz_no[i], 0);
 +
 +                              PointerRNA macroptr = RNA_pointer_get(&mpop->ptr, "TRANSFORM_OT_translate");
 +
 +                              RNA_float_set_array(&macroptr, "value", value);
 +                              RNA_boolean_set_array(&macroptr, "constraint_axis", constraint_axis);
 +                              RNA_enum_set(&macroptr, "constraint_orientation", orientation_type);
 +                      }
 +                      else {
 +                              /* TODO(campbell): ideally we could adjust all,
 +                               * this is complicated by how operator redo and the transform macro works. */
 +                              WM_manipulator_set_flag(man->adjust_xyz_no[i], WM_MANIPULATOR_HIDDEN, true);
 +                      }
 +              }
 +      }
 +
 +      for (int i = 0; i < 4; i++) {
 +              RNA_enum_set(
 +                      man->invoke_xyz_no[i]->ptr,
 +                      "draw_options",
 +                      (man->adjust_xyz_no[i]->flag & WM_MANIPULATOR_HIDDEN) ?
 +                      ED_MANIPULATOR_BUTTON_SHOW_HELPLINE : 0);
 +      }
 +}
 +
 +static void manipulator_mesh_extrude_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      ManipulatorExtrudeGroup *man = mgroup->customdata;
 +      switch (man->data.orientation_type) {
 +              case V3D_MANIP_VIEW:
 +              {
 +                      RegionView3D *rv3d = CTX_wm_region_view3d(C);
 +                      float mat[3][3];
 +                      copy_m3_m4(mat, rv3d->viewinv);
 +                      normalize_m3(mat);
 +                      manipulator_mesh_extrude_orientation_matrix_set(man, mat);
 +                      break;
 +              }
 +      }
 +}
 +
 +static void manipulator_mesh_extrude_message_subscribe(
 +        const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus)
 +{
 +      ARegion *ar = CTX_wm_region(C);
 +
 +      /* Subscribe to view properties */
 +      wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = {
 +              .owner = ar,
 +              .user_data = mgroup->parent_mmap,
 +              .notify = WM_manipulator_do_msg_notify_tag_refresh,
 +      };
 +
 +      {
 +              WM_msg_subscribe_rna_anon_prop(mbus, Scene, transform_orientation, &msg_sub_value_mpr_tag_refresh);
 +      }
 +
 +}
 +
 +static void MESH_WGT_extrude(struct wmManipulatorGroupType *wgt)
 +{
 +      wgt->name = "Mesh Extrude";
 +      wgt->idname = "MESH_WGT_extrude";
 +
 +      wgt->flag = WM_MANIPULATORGROUPTYPE_3D;
 +
 +      wgt->mmap_params.spaceid = SPACE_VIEW3D;
 +      wgt->mmap_params.regionid = RGN_TYPE_WINDOW;
 +
 +      wgt->poll = manipulator_mesh_extrude_poll;
 +      wgt->setup = manipulator_mesh_extrude_setup;
 +      wgt->refresh = manipulator_mesh_extrude_refresh;
 +      wgt->draw_prepare = manipulator_mesh_extrude_draw_prepare;
 +      wgt->message_subscribe = manipulator_mesh_extrude_message_subscribe;
 +}
 +
 +#endif  /* USE_MANIPULATOR */
 +
 +/** \} */
 +
  /* -------------------------------------------------------------------- */
  /** \name Extrude Operator
   * \{ */
@@@ -1073,10 -970,44 +1073,10 @@@ finally
  /** \} */
  
  /* -------------------------------------------------------------------- */
 -/** \name Local View Operators
 +/** \name View Layer Utilities
   * \{ */
  
- int ED_view3d_view_layer_set(int lay, const int *values, int *active)
 -static unsigned int free_localbit(Main *bmain)
 -{
 -      unsigned int lay;
 -      ScrArea *sa;
 -      bScreen *sc;
 -
 -      lay = 0;
 -
 -      /* sometimes we loose a localview: when an area is closed */
 -      /* check all areas: which localviews are in use? */
 -      for (sc = bmain->screen.first; sc; sc = sc->id.next) {
 -              for (sa = sc->areabase.first; sa; sa = sa->next) {
 -                      SpaceLink *sl = sa->spacedata.first;
 -                      for (; sl; sl = sl->next) {
 -                              if (sl->spacetype == SPACE_VIEW3D) {
 -                                      View3D *v3d = (View3D *) sl;
 -                                      lay |= v3d->lay;
 -                              }
 -                      }
 -              }
 -      }
 -
 -      if ((lay & 0x01000000) == 0) return 0x01000000;
 -      if ((lay & 0x02000000) == 0) return 0x02000000;
 -      if ((lay & 0x04000000) == 0) return 0x04000000;
 -      if ((lay & 0x08000000) == 0) return 0x08000000;
 -      if ((lay & 0x10000000) == 0) return 0x10000000;
 -      if ((lay & 0x20000000) == 0) return 0x20000000;
 -      if ((lay & 0x40000000) == 0) return 0x40000000;
 -      if ((lay & 0x80000000) == 0) return 0x80000000;
 -
 -      return 0;
 -}
 -
 -int ED_view3d_scene_layer_set(int lay, const bool *values, int *active)
++int ED_view3d_view_layer_set(int lay, const bool *values, int *active)
  {
        int i, tot = 0;
  
@@@ -2233,63 -2158,6 +2233,63 @@@ bool initTransform(bContext *C, TransIn
        calculatePropRatio(t);
        calculateCenter(t);
  
-               int constraint_axis[3];
 +      /* Overwrite initial values if operator supplied a non-null vector.
 +       *
 +       * Run before init functions so 'values_modal_offset' can be applied on mouse input.
 +       */
 +      BLI_assert(is_zero_v4(t->values_modal_offset));
 +      if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
 +              float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory  */
 +
 +              if (RNA_property_array_check(prop)) {
 +                      RNA_float_get_array(op->ptr, "value", values);
 +              }
 +              else {
 +                      values[0] = RNA_float_get(op->ptr, "value");
 +              }
 +
 +              copy_v4_v4(t->values, values);
 +
 +              if (t->flag & T_MODAL) {
 +                      copy_v4_v4(t->values_modal_offset, values);
 +                      t->redraw = TREDRAW_HARD;
 +              }
 +              else {
 +                      copy_v4_v4(t->auto_values, values);
 +                      t->flag |= T_AUTOVALUES;
 +              }
 +      }
 +
 +      /* Transformation axis from operator */
 +      if ((prop = RNA_struct_find_property(op->ptr, "axis")) && RNA_property_is_set(op->ptr, prop)) {
 +              RNA_property_float_get_array(op->ptr, prop, t->axis);
 +              normalize_v3(t->axis);
 +              copy_v3_v3(t->axis_orig, t->axis);
 +      }
 +
 +      /* Constraint init from operator */
 +      if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && RNA_property_is_set(op->ptr, prop)) {
++              bool constraint_axis[3];
 +
 +              RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
 +
 +              if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
 +                      t->con.mode |= CON_APPLY;
 +
 +                      if (constraint_axis[0]) {
 +                              t->con.mode |= CON_AXIS0;
 +                      }
 +                      if (constraint_axis[1]) {
 +                              t->con.mode |= CON_AXIS1;
 +                      }
 +                      if (constraint_axis[2]) {
 +                              t->con.mode |= CON_AXIS2;
 +                      }
 +
 +                      setUserConstraint(t, t->current_orientation, t->con.mode, "%s");
 +              }
 +      }
 +
        if (event) {
                /* Initialize accurate transform to settings requested by keymap. */
                bool use_accurate = false;
index d2743f4,0000000..fd6e7ed
mode 100644,000000..100644
--- /dev/null
@@@ -1,382 -1,0 +1,382 @@@
-               int constraint[3] = {0};
 +/*
 + * ***** 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/transform/transform_manipulator_2d.c
 + *  \ingroup edtransform
 + *
 + * \name 2D Transform Manipulator
 + *
 + * Used for UV/Image Editor
 + */
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "BLI_listbase.h"
 +#include "BLI_math.h"
 +
 +#include "DNA_meshdata_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_space_types.h"
 +#include "DNA_view3d_types.h"
 +
 +#include "BKE_context.h"
 +#include "BKE_editmesh.h"
 +
 +#include "RNA_access.h"
 +
 +#include "UI_resources.h"
 +#include "UI_view2d.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +#include "wm.h" /* XXX */
 +
 +#include "ED_image.h"
 +#include "ED_screen.h"
 +#include "ED_uvedit.h"
 +#include "ED_manipulator_library.h"
 +
 +#include "transform.h" /* own include */
 +
 +/* axes as index */
 +enum {
 +      MAN2D_AXIS_TRANS_X = 0,
 +      MAN2D_AXIS_TRANS_Y,
 +
 +      MAN2D_AXIS_LAST,
 +};
 +
 +typedef struct ManipulatorGroup2D {
 +      wmManipulator *translate_x,
 +               *translate_y;
 +
 +      wmManipulator *cage;
 +
 +      /* Current origin in view space, used to update widget origin for possible view changes */
 +      float origin[2];
 +      float min[2];
 +      float max[2];
 +
 +} ManipulatorGroup2D;
 +
 +
 +/* **************** Utilities **************** */
 +
 +/* loop over axes */
 +#define MAN2D_ITER_AXES_BEGIN(axis, axis_idx) \
 +      { \
 +              wmManipulator *axis; \
 +              int axis_idx; \
 +              for (axis_idx = 0; axis_idx < MAN2D_AXIS_LAST; axis_idx++) { \
 +                      axis = manipulator2d_get_axis_from_index(man, axis_idx);
 +
 +#define MAN2D_ITER_AXES_END \
 +              } \
 +      } ((void)0)
 +
 +static wmManipulator *manipulator2d_get_axis_from_index(const ManipulatorGroup2D *man, const short axis_idx)
 +{
 +      BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN2D_AXIS_TRANS_X, (float)MAN2D_AXIS_TRANS_Y));
 +
 +      switch (axis_idx) {
 +              case MAN2D_AXIS_TRANS_X:
 +                      return man->translate_x;
 +              case MAN2D_AXIS_TRANS_Y:
 +                      return man->translate_y;
 +      }
 +
 +      return NULL;
 +}
 +
 +static void manipulator2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi)
 +{
 +      const float alpha = 0.6f;
 +      const float alpha_hi = 1.0f;
 +      int col_id;
 +
 +      switch (axis_idx) {
 +              case MAN2D_AXIS_TRANS_X:
 +                      col_id = TH_AXIS_X;
 +                      break;
 +              case MAN2D_AXIS_TRANS_Y:
 +                      col_id = TH_AXIS_Y;
 +                      break;
 +      }
 +
 +      UI_GetThemeColor4fv(col_id, r_col);
 +
 +      copy_v4_v4(r_col_hi, r_col);
 +      r_col[3] *= alpha;
 +      r_col_hi[3] *= alpha_hi;
 +}
 +
 +static ManipulatorGroup2D *manipulatorgroup2d_init(wmManipulatorGroup *mgroup)
 +{
 +      const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_2d", true);
 +      const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_2d", true);
 +
 +      ManipulatorGroup2D *man = MEM_callocN(sizeof(ManipulatorGroup2D), __func__);
 +
 +      man->translate_x = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL);
 +      man->translate_y = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL);
 +      man->cage = WM_manipulator_new_ptr(wt_cage, mgroup, NULL);
 +
 +      RNA_enum_set(man->cage->ptr, "transform",
 +                   ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE |
 +                   ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE |
 +                   ED_MANIPULATOR_CAGE2D_XFORM_FLAG_ROTATE);
 +
 +      return man;
 +}
 +
 +/**
 + * Calculates origin in view space, use with #manipulator2d_origin_to_region.
 + */
 +static void manipulator2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max)
 +{
 +      SpaceImage *sima = CTX_wm_space_image(C);
 +      Image *ima = ED_space_image(sima);
 +
 +      float min_buf[2], max_buf[2];
 +      if (r_min == NULL) {
 +              r_min = min_buf;
 +      }
 +      if (r_max == NULL) {
 +              r_max = max_buf;
 +      }
 +
 +      if (!ED_uvedit_minmax(CTX_data_scene(C), ima, CTX_data_edit_object(C), r_min, r_max)) {
 +              zero_v2(r_min);
 +              zero_v2(r_max);
 +      }
 +      mid_v2_v2v2(r_center, r_min, r_max);
 +}
 +
 +/**
 + * Convert origin (or any other point) from view to region space.
 + */
 +BLI_INLINE void manipulator2d_origin_to_region(ARegion *ar, float *r_origin)
 +{
 +      UI_view2d_view_to_region_fl(&ar->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]);
 +}
 +
 +/**
 + * Custom handler for manipulator widgets
 + */
 +static int manipulator2d_modal(
 +        bContext *C, wmManipulator *widget, const wmEvent *UNUSED(event),
 +        eWM_ManipulatorTweak UNUSED(tweak_flag))
 +{
 +      ARegion *ar = CTX_wm_region(C);
 +      float origin[3];
 +
 +      manipulator2d_calc_bounds(C, origin, NULL, NULL);
 +      manipulator2d_origin_to_region(ar, origin);
 +      WM_manipulator_set_matrix_location(widget, origin);
 +
 +      ED_region_tag_redraw(ar);
 +
 +      return OPERATOR_RUNNING_MODAL;
 +}
 +
 +void ED_widgetgroup_manipulator2d_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
 +{
 +      wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
 +      ManipulatorGroup2D *man = manipulatorgroup2d_init(mgroup);
 +      mgroup->customdata = man;
 +
 +      MAN2D_ITER_AXES_BEGIN(axis, axis_idx)
 +      {
 +              const float offset[3] = {0.0f, 0.2f};
 +
 +              float color[4], color_hi[4];
 +              manipulator2d_get_axis_color(axis_idx, color, color_hi);
 +
 +              /* custom handler! */
 +              WM_manipulator_set_fn_custom_modal(axis, manipulator2d_modal);
 +              /* set up widget data */
 +              RNA_float_set(axis->ptr, "angle", -M_PI_2 * axis_idx);
 +              RNA_float_set(axis->ptr, "length", 0.8f);
 +              WM_manipulator_set_matrix_offset_location(axis, offset);
 +              WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH);
 +              WM_manipulator_set_scale(axis, U.manipulator_size);
 +              WM_manipulator_set_color(axis, color);
 +              WM_manipulator_set_color_highlight(axis, color_hi);
 +
 +              /* assign operator */
 +              PointerRNA *ptr = WM_manipulator_operator_set(axis, 0, ot_translate, NULL);
-               int constraint_x[3] = {1, 0, 0};
-               int constraint_y[3] = {0, 1, 0};
++              bool constraint[3] = {0};
 +              constraint[(axis_idx + 1) % 2] = 1;
 +              if (RNA_struct_find_property(ptr, "constraint_axis"))
 +                      RNA_boolean_set_array(ptr, "constraint_axis", constraint);
 +              RNA_boolean_set(ptr, "release_confirm", 1);
 +      }
 +      MAN2D_ITER_AXES_END;
 +
 +      {
 +              wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
 +              wmOperatorType *ot_rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
 +              PointerRNA *ptr;
 +
 +              /* assign operator */
 +              ptr = WM_manipulator_operator_set(man->cage, 0, ot_translate, NULL);
 +              RNA_boolean_set(ptr, "release_confirm", 1);
 +
++              bool constraint_x[3] = {1, 0, 0};
++              bool constraint_y[3] = {0, 1, 0};
 +
 +              ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X, ot_resize, NULL);
 +              PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
 +              PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
 +              RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
 +              RNA_property_boolean_set(ptr, prop_release_confirm, true);
 +              ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL);
 +              RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
 +              RNA_property_boolean_set(ptr, prop_release_confirm, true);
 +              ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y, ot_resize, NULL);
 +              RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
 +              RNA_property_boolean_set(ptr, prop_release_confirm, true);
 +              ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL);
 +              RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
 +              RNA_property_boolean_set(ptr, prop_release_confirm, true);
 +
 +              ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, NULL);
 +              RNA_property_boolean_set(ptr, prop_release_confirm, true);
 +              ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y, ot_resize, NULL);
 +              RNA_property_boolean_set(ptr, prop_release_confirm, true);
 +              ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y, ot_resize, NULL);
 +              RNA_property_boolean_set(ptr, prop_release_confirm, true);
 +              ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y, ot_resize, NULL);
 +              RNA_property_boolean_set(ptr, prop_release_confirm, true);
 +              ptr = WM_manipulator_operator_set(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE, ot_rotate, NULL);
 +              RNA_property_boolean_set(ptr, prop_release_confirm, true);
 +      }
 +}
 +
 +void ED_widgetgroup_manipulator2d_refresh(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      ManipulatorGroup2D *man = mgroup->customdata;
 +      float origin[3];
 +      manipulator2d_calc_bounds(C, origin, man->min, man->max);
 +      copy_v2_v2(man->origin, origin);
 +      bool show_cage = !equals_v2v2(man->min, man->max);
 +
 +      if (show_cage) {
 +              man->cage->flag &= ~WM_MANIPULATOR_HIDDEN;
 +              man->translate_x->flag |= WM_MANIPULATOR_HIDDEN;
 +              man->translate_y->flag |= WM_MANIPULATOR_HIDDEN;
 +      }
 +      else {
 +              man->cage->flag |= WM_MANIPULATOR_HIDDEN;
 +              man->translate_x->flag &= ~WM_MANIPULATOR_HIDDEN;
 +              man->translate_y->flag &= ~WM_MANIPULATOR_HIDDEN;
 +      }
 +
 +      if (show_cage) {
 +              wmManipulatorOpElem *mpop;
 +              float mid[2];
 +              const float *min = man->min;
 +              const float *max = man->max;
 +              mid_v2_v2v2(mid, min, max);
 +
 +              mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X);
 +              PropertyRNA *prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override");
 +              RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f});
 +              mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X);
 +              RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f});
 +              mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_Y);
 +              RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f});
 +              mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_Y);
 +              RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f});
 +
 +              mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MIN_Y);
 +              RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f});
 +              mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MIN_X_MAX_Y);
 +              RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f});
 +              mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MIN_Y);
 +              RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f});
 +              mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_SCALE_MAX_X_MAX_Y);
 +              RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f});
 +
 +              mpop = WM_manipulator_operator_get(man->cage, ED_MANIPULATOR_CAGE2D_PART_ROTATE);
 +              RNA_property_float_set_array(&mpop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f});
 +      }
 +}
 +
 +void ED_widgetgroup_manipulator2d_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      ARegion *ar = CTX_wm_region(C);
 +      ManipulatorGroup2D *man = mgroup->customdata;
 +      float origin[3] = {UNPACK2(man->origin), 0.0f};
 +      float origin_aa[3] = {UNPACK2(man->origin), 0.0f};
 +
 +      manipulator2d_origin_to_region(ar, origin);
 +
 +      MAN2D_ITER_AXES_BEGIN(axis, axis_idx)
 +      {
 +              WM_manipulator_set_matrix_location(axis, origin);
 +      }
 +      MAN2D_ITER_AXES_END;
 +
 +      UI_view2d_view_to_region_m4(&ar->v2d, man->cage->matrix_space);
 +      WM_manipulator_set_matrix_offset_location(man->cage, origin_aa);
 +      man->cage->matrix_offset[0][0] = (man->max[0] - man->min[0]);
 +      man->cage->matrix_offset[1][1] = (man->max[1] - man->min[1]);
 +}
 +
 +/* TODO (Julian)
 + * - Called on every redraw, better to do a more simple poll and check for selection in _refresh
 + * - UV editing only, could be expanded for other things.
 + */
 +bool ED_widgetgroup_manipulator2d_poll(const bContext *C, wmManipulatorGroupType *UNUSED(wgt))
 +{
 +      if ((U.manipulator_flag & USER_MANIPULATOR_DRAW) == 0) {
 +              return false;
 +      }
 +
 +      SpaceImage *sima = CTX_wm_space_image(C);
 +      Object *obedit = CTX_data_edit_object(C);
 +
 +      if (ED_space_image_show_uvedit(sima, obedit)) {
 +              Image *ima = ED_space_image(sima);
 +              Scene *scene = CTX_data_scene(C);
 +              BMEditMesh *em = BKE_editmesh_from_object(obedit);
 +              BMFace *efa;
 +              BMLoop *l;
 +              BMIter iter, liter;
 +
 +              const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
 +
 +              /* check if there's a selected poly */
 +              BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 +                      if (!uvedit_face_visible_test(scene, obedit, ima, efa))
 +                              continue;
 +
 +                      BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
 +                              if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
 +                                      return true;
 +                              }
 +                      }
 +              }
 +      }
 +
 +      return false;
 +}
index f584a7c,0000000..8f547fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,1783 -1,0 +1,1783 @@@
- static void manipulator_get_axis_constraint(const int axis_idx, int r_axis[3])
 +/*
 + * ***** 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/transform/transform_manipulator_3d.c
 + *  \ingroup edtransform
 + *
 + * \name 3D Transform Manipulator
 + *
 + * Used for 3D View
 + */
 +
 +#include <stdlib.h>
 +#include <string.h>
 +#include <math.h>
 +#include <float.h>
 +
 +#include "DNA_armature_types.h"
 +#include "DNA_curve_types.h"
 +#include "DNA_gpencil_types.h"
 +#include "DNA_lattice_types.h"
 +#include "DNA_meta_types.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_scene_types.h"
 +#include "DNA_view3d_types.h"
 +
 +#include "BLI_listbase.h"
 +#include "BLI_math.h"
 +#include "BLI_utildefines.h"
 +
 +#include "RNA_access.h"
 +
 +#include "BKE_action.h"
 +#include "BKE_context.h"
 +#include "BKE_curve.h"
 +#include "BKE_global.h"
 +#include "BKE_particle.h"
 +#include "BKE_pointcache.h"
 +#include "BKE_editmesh.h"
 +#include "BKE_lattice.h"
 +#include "BKE_gpencil.h"
 +#include "BKE_scene.h"
 +#include "BKE_workspace.h"
 +
 +#include "BIF_gl.h"
 +
 +#include "DEG_depsgraph.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +#include "WM_message.h"
 +#include "WM_toolsystem.h"
 +
 +#include "ED_armature.h"
 +#include "ED_curve.h"
 +#include "ED_object.h"
 +#include "ED_particle.h"
 +#include "ED_view3d.h"
 +#include "ED_gpencil.h"
 +#include "ED_screen.h"
 +#include "ED_manipulator_library.h"
 +
 +#include "UI_resources.h"
 +
 +/* local module include */
 +#include "transform.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "GPU_select.h"
 +#include "GPU_immediate.h"
 +#include "GPU_matrix.h"
 +
 +#include "DEG_depsgraph_query.h"
 +
 +/* return codes for select, and drawing flags */
 +
 +#define MAN_TRANS_X           (1 << 0)
 +#define MAN_TRANS_Y           (1 << 1)
 +#define MAN_TRANS_Z           (1 << 2)
 +#define MAN_TRANS_C           (MAN_TRANS_X | MAN_TRANS_Y | MAN_TRANS_Z)
 +
 +#define MAN_ROT_X             (1 << 3)
 +#define MAN_ROT_Y             (1 << 4)
 +#define MAN_ROT_Z             (1 << 5)
 +#define MAN_ROT_C             (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z)
 +
 +#define MAN_SCALE_X           (1 << 8)
 +#define MAN_SCALE_Y           (1 << 9)
 +#define MAN_SCALE_Z           (1 << 10)
 +#define MAN_SCALE_C           (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z)
 +
 +/* threshold for testing view aligned manipulator axis */
 +struct {
 +      float min, max;
 +} g_tw_axis_range[2] = {
 +      /* Regular range */
 +      {0.02f, 0.1f},
 +      /* Use a different range because we flip the dot product,
 +       * also the view aligned planes are harder to see so hiding early is preferred. */
 +      {0.175f,  0.25f},
 +};
 +
 +/* axes as index */
 +enum {
 +      MAN_AXIS_TRANS_X = 0,
 +      MAN_AXIS_TRANS_Y,
 +      MAN_AXIS_TRANS_Z,
 +      MAN_AXIS_TRANS_C,
 +
 +      MAN_AXIS_TRANS_XY,
 +      MAN_AXIS_TRANS_YZ,
 +      MAN_AXIS_TRANS_ZX,
 +#define MAN_AXIS_RANGE_TRANS_START MAN_AXIS_TRANS_X
 +#define MAN_AXIS_RANGE_TRANS_END (MAN_AXIS_TRANS_ZX + 1)
 +
 +      MAN_AXIS_ROT_X,
 +      MAN_AXIS_ROT_Y,
 +      MAN_AXIS_ROT_Z,
 +      MAN_AXIS_ROT_C,
 +      MAN_AXIS_ROT_T, /* trackball rotation */
 +#define MAN_AXIS_RANGE_ROT_START MAN_AXIS_ROT_X
 +#define MAN_AXIS_RANGE_ROT_END (MAN_AXIS_ROT_T + 1)
 +
 +      MAN_AXIS_SCALE_X,
 +      MAN_AXIS_SCALE_Y,
 +      MAN_AXIS_SCALE_Z,
 +      MAN_AXIS_SCALE_C,
 +      MAN_AXIS_SCALE_XY,
 +      MAN_AXIS_SCALE_YZ,
 +      MAN_AXIS_SCALE_ZX,
 +#define MAN_AXIS_RANGE_SCALE_START MAN_AXIS_SCALE_X
 +#define MAN_AXIS_RANGE_SCALE_END (MAN_AXIS_SCALE_ZX + 1)
 +
 +      MAN_AXIS_LAST = MAN_AXIS_RANGE_SCALE_END,
 +};
 +
 +/* axis types */
 +enum {
 +      MAN_AXES_ALL = 0,
 +      MAN_AXES_TRANSLATE,
 +      MAN_AXES_ROTATE,
 +      MAN_AXES_SCALE,
 +};
 +
 +typedef struct ManipulatorGroup {
 +      bool all_hidden;
 +      int twtype;
 +
 +      /* Users may change the twtype, detect changes to re-setup manipulator options. */
 +      int twtype_init;
 +      int twtype_prev;
 +      int use_twtype_refresh;
 +
 +      struct wmManipulator *manipulators[MAN_AXIS_LAST];
 +} ManipulatorGroup;
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Utilities
 + * \{ */
 +
 +/* loop over axes */
 +#define MAN_ITER_AXES_BEGIN(axis, axis_idx) \
 +      { \
 +              wmManipulator *axis; \
 +              int axis_idx; \
 +              for (axis_idx = 0; axis_idx < MAN_AXIS_LAST; axis_idx++) { \
 +                      axis = manipulator_get_axis_from_index(man, axis_idx);
 +
 +#define MAN_ITER_AXES_END \
 +              } \
 +      } ((void)0)
 +
 +static wmManipulator *manipulator_get_axis_from_index(const ManipulatorGroup *man, const short axis_idx)
 +{
 +      BLI_assert(IN_RANGE_INCL(axis_idx, (float)MAN_AXIS_TRANS_X, (float)MAN_AXIS_LAST));
 +      return man->manipulators[axis_idx];
 +}
 +
 +static short manipulator_get_axis_type(const int axis_idx)
 +{
 +      if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
 +              return MAN_AXES_TRANSLATE;
 +      }
 +      if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) {
 +              return MAN_AXES_ROTATE;
 +      }
 +      if (axis_idx >= MAN_AXIS_RANGE_SCALE_START && axis_idx < MAN_AXIS_RANGE_SCALE_END) {
 +              return MAN_AXES_SCALE;
 +      }
 +      BLI_assert(0);
 +      return -1;
 +}
 +
 +static uint manipulator_orientation_axis(const int axis_idx, bool *r_is_plane)
 +{
 +      switch (axis_idx) {
 +              case MAN_AXIS_TRANS_YZ:
 +              case MAN_AXIS_SCALE_YZ:
 +                      if (r_is_plane) {
 +                              *r_is_plane = true;
 +                      }
 +                      ATTR_FALLTHROUGH;
 +              case MAN_AXIS_TRANS_X:
 +              case MAN_AXIS_ROT_X:
 +              case MAN_AXIS_SCALE_X:
 +                      return 0;
 +
 +              case MAN_AXIS_TRANS_ZX:
 +              case MAN_AXIS_SCALE_ZX:
 +                      if (r_is_plane) {
 +                              *r_is_plane = true;
 +                      }
 +                      ATTR_FALLTHROUGH;
 +              case MAN_AXIS_TRANS_Y:
 +              case MAN_AXIS_ROT_Y:
 +              case MAN_AXIS_SCALE_Y:
 +                      return 1;
 +
 +              case MAN_AXIS_TRANS_XY:
 +              case MAN_AXIS_SCALE_XY:
 +                      if (r_is_plane) {
 +                              *r_is_plane = true;
 +                      }
 +                      ATTR_FALLTHROUGH;
 +              case MAN_AXIS_TRANS_Z:
 +              case MAN_AXIS_ROT_Z:
 +              case MAN_AXIS_SCALE_Z:
 +                      return 2;
 +      }
 +      return 3;
 +}
 +
 +static bool manipulator_is_axis_visible(
 +        const RegionView3D *rv3d, const int twtype,
 +        const float idot[3], const int axis_type, const int axis_idx)
 +{
 +      if ((axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) == 0) {
 +              bool is_plane = false;
 +              const uint aidx_norm = manipulator_orientation_axis(axis_idx, &is_plane);
 +              /* don't draw axis perpendicular to the view */
 +              if (aidx_norm < 3) {
 +                      float idot_axis = idot[aidx_norm];
 +                      if (is_plane) {
 +                              idot_axis = 1.0f - idot_axis;
 +                      }
 +                      if (idot_axis < g_tw_axis_range[is_plane].min) {
 +                              return false;
 +                      }
 +              }
 +      }
 +
 +      if ((axis_type == MAN_AXES_TRANSLATE && !(twtype & SCE_MANIP_TRANSLATE)) ||
 +          (axis_type == MAN_AXES_ROTATE && !(twtype & SCE_MANIP_ROTATE)) ||
 +          (axis_type == MAN_AXES_SCALE && !(twtype & SCE_MANIP_SCALE)))
 +      {
 +              return false;
 +      }
 +
 +      switch (axis_idx) {
 +              case MAN_AXIS_TRANS_X:
 +                      return (rv3d->twdrawflag & MAN_TRANS_X);
 +              case MAN_AXIS_TRANS_Y:
 +                      return (rv3d->twdrawflag & MAN_TRANS_Y);
 +              case MAN_AXIS_TRANS_Z:
 +                      return (rv3d->twdrawflag & MAN_TRANS_Z);
 +              case MAN_AXIS_TRANS_C:
 +                      return (rv3d->twdrawflag & MAN_TRANS_C);
 +              case MAN_AXIS_ROT_X:
 +                      return (rv3d->twdrawflag & MAN_ROT_X);
 +              case MAN_AXIS_ROT_Y:
 +                      return (rv3d->twdrawflag & MAN_ROT_Y);
 +              case MAN_AXIS_ROT_Z:
 +                      return (rv3d->twdrawflag & MAN_ROT_Z);
 +              case MAN_AXIS_ROT_C:
 +              case MAN_AXIS_ROT_T:
 +                      return (rv3d->twdrawflag & MAN_ROT_C);
 +              case MAN_AXIS_SCALE_X:
 +                      return (rv3d->twdrawflag & MAN_SCALE_X);
 +              case MAN_AXIS_SCALE_Y:
 +                      return (rv3d->twdrawflag & MAN_SCALE_Y);
 +              case MAN_AXIS_SCALE_Z:
 +                      return (rv3d->twdrawflag & MAN_SCALE_Z);
 +              case MAN_AXIS_SCALE_C:
 +                      return (rv3d->twdrawflag & MAN_SCALE_C && (twtype & SCE_MANIP_TRANSLATE) == 0);
 +              case MAN_AXIS_TRANS_XY:
 +                      return (rv3d->twdrawflag & MAN_TRANS_X &&
 +                              rv3d->twdrawflag & MAN_TRANS_Y &&
 +                              (twtype & SCE_MANIP_ROTATE) == 0);
 +              case MAN_AXIS_TRANS_YZ:
 +                      return (rv3d->twdrawflag & MAN_TRANS_Y &&
 +                              rv3d->twdrawflag & MAN_TRANS_Z &&
 +                              (twtype & SCE_MANIP_ROTATE) == 0);
 +              case MAN_AXIS_TRANS_ZX:
 +                      return (rv3d->twdrawflag & MAN_TRANS_Z &&
 +                              rv3d->twdrawflag & MAN_TRANS_X &&
 +                              (twtype & SCE_MANIP_ROTATE) == 0);
 +              case MAN_AXIS_SCALE_XY:
 +                      return (rv3d->twdrawflag & MAN_SCALE_X &&
 +                              rv3d->twdrawflag & MAN_SCALE_Y &&
 +                              (twtype & SCE_MANIP_TRANSLATE) == 0 &&
 +                              (twtype & SCE_MANIP_ROTATE) == 0);
 +              case MAN_AXIS_SCALE_YZ:
 +                      return (rv3d->twdrawflag & MAN_SCALE_Y &&
 +                              rv3d->twdrawflag & MAN_SCALE_Z &&
 +                              (twtype & SCE_MANIP_TRANSLATE) == 0 &&
 +                              (twtype & SCE_MANIP_ROTATE) == 0);
 +              case MAN_AXIS_SCALE_ZX:
 +                      return (rv3d->twdrawflag & MAN_SCALE_Z &&
 +                              rv3d->twdrawflag & MAN_SCALE_X &&
 +                              (twtype & SCE_MANIP_TRANSLATE) == 0 &&
 +                              (twtype & SCE_MANIP_ROTATE) == 0);
 +      }
 +      return false;
 +}
 +
 +static void manipulator_get_axis_color(
 +        const int axis_idx, const float idot[3],
 +        float r_col[4], float r_col_hi[4])
 +{
 +      /* alpha values for normal/highlighted states */
 +      const float alpha = 0.6f;
 +      const float alpha_hi = 1.0f;
 +      float alpha_fac;
 +
 +      if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) {
 +              /* Never fade rotation rings. */
 +              /* trackball rotation axis is a special case, we only draw a slight overlay */
 +              alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f;
 +      }
 +      else {
 +              bool is_plane = false;
 +              const int axis_idx_norm = manipulator_orientation_axis(axis_idx, &is_plane);
 +              /* get alpha fac based on axis angle, to fade axis out when hiding it because it points towards view */
 +              if (axis_idx_norm < 3) {
 +                      const float idot_min = g_tw_axis_range[is_plane].min;
 +                      const float idot_max = g_tw_axis_range[is_plane].max;
 +                      float idot_axis = idot[axis_idx_norm];
 +                      if (is_plane) {
 +                              idot_axis = 1.0f - idot_axis;
 +                      }
 +                      alpha_fac = (
 +                              (idot_axis > idot_max) ?
 +                              1.0f : (idot_axis < idot_min) ?
 +                              0.0f : ((idot_axis - idot_min) / (idot_max - idot_min)));
 +              }
 +              else {
 +                      alpha_fac = 1.0f;
 +              }
 +      }
 +
 +      switch (axis_idx) {
 +              case MAN_AXIS_TRANS_X:
 +              case MAN_AXIS_ROT_X:
 +              case MAN_AXIS_SCALE_X:
 +              case MAN_AXIS_TRANS_YZ:
 +              case MAN_AXIS_SCALE_YZ:
 +                      UI_GetThemeColor4fv(TH_AXIS_X, r_col);
 +                      break;
 +              case MAN_AXIS_TRANS_Y:
 +              case MAN_AXIS_ROT_Y:
 +              case MAN_AXIS_SCALE_Y:
 +              case MAN_AXIS_TRANS_ZX:
 +              case MAN_AXIS_SCALE_ZX:
 +                      UI_GetThemeColor4fv(TH_AXIS_Y, r_col);
 +                      break;
 +              case MAN_AXIS_TRANS_Z:
 +              case MAN_AXIS_ROT_Z:
 +              case MAN_AXIS_SCALE_Z:
 +              case MAN_AXIS_TRANS_XY:
 +              case MAN_AXIS_SCALE_XY:
 +                      UI_GetThemeColor4fv(TH_AXIS_Z, r_col);
 +                      break;
 +              case MAN_AXIS_TRANS_C:
 +              case MAN_AXIS_ROT_C:
 +              case MAN_AXIS_SCALE_C:
 +              case MAN_AXIS_ROT_T:
 +                      copy_v4_fl(r_col, 1.0f);
 +                      break;
 +      }
 +
 +      copy_v4_v4(r_col_hi, r_col);
 +
 +      r_col[3] = alpha * alpha_fac;
 +      r_col_hi[3] = alpha_hi * alpha_fac;
 +}
 +
-       zero_v3_int(r_axis);
++static void manipulator_get_axis_constraint(const int axis_idx, bool r_axis[3])
 +{
-               int constraint_axis[3] = {1, 0, 0};
++      ARRAY_SET_ITEMS(r_axis, 0, 0, 0);
 +
 +      switch (axis_idx) {
 +              case MAN_AXIS_TRANS_X:
 +              case MAN_AXIS_ROT_X:
 +              case MAN_AXIS_SCALE_X:
 +                      r_axis[0] = 1;
 +                      break;
 +              case MAN_AXIS_TRANS_Y:
 +              case MAN_AXIS_ROT_Y:
 +              case MAN_AXIS_SCALE_Y:
 +                      r_axis[1] = 1;
 +                      break;
 +              case MAN_AXIS_TRANS_Z:
 +              case MAN_AXIS_ROT_Z:
 +              case MAN_AXIS_SCALE_Z:
 +                      r_axis[2] = 1;
 +                      break;
 +              case MAN_AXIS_TRANS_XY:
 +              case MAN_AXIS_SCALE_XY:
 +                      r_axis[0] = r_axis[1] = 1;
 +                      break;
 +              case MAN_AXIS_TRANS_YZ:
 +              case MAN_AXIS_SCALE_YZ:
 +                      r_axis[1] = r_axis[2] = 1;
 +                      break;
 +              case MAN_AXIS_TRANS_ZX:
 +              case MAN_AXIS_SCALE_ZX:
 +                      r_axis[2] = r_axis[0] = 1;
 +                      break;
 +              default:
 +                      break;
 +      }
 +}
 +
 +
 +/* **************** Preparation Stuff **************** */
 +
 +/* transform widget center calc helper for below */
 +static void calc_tw_center(struct TransformBounds *tbounds, const float co[3])
 +{
 +      minmax_v3v3_v3(tbounds->min, tbounds->max, co);
 +      add_v3_v3(tbounds->center, co);
 +
 +      for (int i = 0; i < 3; i++) {
 +              const float d = dot_v3v3(tbounds->axis[i], co);
 +              tbounds->axis_min[i] = min_ff(d, tbounds->axis_min[i]);
 +              tbounds->axis_max[i] = max_ff(d, tbounds->axis_max[i]);
 +      }
 +}
 +
 +static void protectflag_to_drawflags(short protectflag, short *drawflags)
 +{
 +      if (protectflag & OB_LOCK_LOCX)
 +              *drawflags &= ~MAN_TRANS_X;
 +      if (protectflag & OB_LOCK_LOCY)
 +              *drawflags &= ~MAN_TRANS_Y;
 +      if (protectflag & OB_LOCK_LOCZ)
 +              *drawflags &= ~MAN_TRANS_Z;
 +
 +      if (protectflag & OB_LOCK_ROTX)
 +              *drawflags &= ~MAN_ROT_X;
 +      if (protectflag & OB_LOCK_ROTY)
 +              *drawflags &= ~MAN_ROT_Y;
 +      if (protectflag & OB_LOCK_ROTZ)
 +              *drawflags &= ~MAN_ROT_Z;
 +
 +      if (protectflag & OB_LOCK_SCALEX)
 +              *drawflags &= ~MAN_SCALE_X;
 +      if (protectflag & OB_LOCK_SCALEY)
 +              *drawflags &= ~MAN_SCALE_Y;
 +      if (protectflag & OB_LOCK_SCALEZ)
 +              *drawflags &= ~MAN_SCALE_Z;
 +}
 +
 +/* for pose mode */
 +static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan)
 +{
 +      protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
 +}
 +
 +/* for editmode*/
 +static void protectflag_to_drawflags_ebone(RegionView3D *rv3d, const EditBone *ebo)
 +{
 +      if (ebo->flag & BONE_EDITMODE_LOCKED) {
 +              protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag);
 +      }
 +}
 +
 +/* could move into BLI_math however this is only useful for display/editing purposes */
 +static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle)
 +{
 +      /* X/Y are arbitrary axies, most importantly Z is the axis of rotation */
 +
 +      float cross_vec[3];
 +      float quat[4];
 +
 +      /* this is an un-scientific method to get a vector to cross with
 +       * XYZ intentionally YZX */
 +      cross_vec[0] = axis[1];
 +      cross_vec[1] = axis[2];
 +      cross_vec[2] = axis[0];
 +
 +      /* X-axis */
 +      cross_v3_v3v3(gmat[0], cross_vec, axis);
 +      normalize_v3(gmat[0]);
 +      axis_angle_to_quat(quat, axis, angle);
 +      mul_qt_v3(quat, gmat[0]);
 +
 +      /* Y-axis */
 +      axis_angle_to_quat(quat, axis, M_PI_2);
 +      copy_v3_v3(gmat[1], gmat[0]);
 +      mul_qt_v3(quat, gmat[1]);
 +
 +      /* Z-axis */
 +      copy_v3_v3(gmat[2], axis);
 +
 +      normalize_m3(gmat);
 +}
 +
 +
 +static bool test_rotmode_euler(short rotmode)
 +{
 +      return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1;
 +}
 +
 +bool gimbal_axis(Object *ob, float gmat[3][3])
 +{
 +      if (ob->mode & OB_MODE_POSE) {
 +              bPoseChannel *pchan = BKE_pose_channel_active(ob);
 +
 +              if (pchan) {
 +                      float mat[3][3], tmat[3][3], obmat[3][3];
 +                      if (test_rotmode_euler(pchan->rotmode)) {
 +                              eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
 +                      }
 +                      else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
 +                              axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
 +                      }
 +                      else { /* quat */
 +                              return 0;
 +                      }
 +
 +
 +                      /* apply bone transformation */
 +                      mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
 +
 +                      if (pchan->parent) {
 +                              float parent_mat[3][3];
 +
 +                              copy_m3_m4(parent_mat, pchan->parent->pose_mat);
 +                              mul_m3_m3m3(mat, parent_mat, tmat);
 +
 +                              /* needed if object transformation isn't identity */
 +                              copy_m3_m4(obmat, ob->obmat);
 +                              mul_m3_m3m3(gmat, obmat, mat);
 +                      }
 +                      else {
 +                              /* needed if object transformation isn't identity */
 +                              copy_m3_m4(obmat, ob->obmat);
 +                              mul_m3_m3m3(gmat, obmat, tmat);
 +                      }
 +
 +                      normalize_m3(gmat);
 +                      return 1;
 +              }
 +      }
 +      else {
 +              if (test_rotmode_euler(ob->rotmode)) {
 +                      eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
 +              }
 +              else if (ob->rotmode == ROT_MODE_AXISANGLE) {
 +                      axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
 +              }
 +              else { /* quat */
 +                      return 0;
 +              }
 +
 +              if (ob->parent) {
 +                      float parent_mat[3][3];
 +                      copy_m3_m4(parent_mat, ob->parent->obmat);
 +                      normalize_m3(parent_mat);
 +                      mul_m3_m3m3(gmat, parent_mat, gmat);
 +              }
 +              return 1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +/* centroid, boundbox, of selection */
 +/* returns total items selected */
 +int ED_transform_calc_manipulator_stats(
 +        const bContext *C,
 +        const struct TransformCalcParams *params,
 +        struct TransformBounds *tbounds)
 +{
 +      ScrArea *sa = CTX_wm_area(C);
 +      ARegion *ar = CTX_wm_region(C);
 +      Scene *scene = CTX_data_scene(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      Object *obedit = CTX_data_edit_object(C);
 +      View3D *v3d = sa->spacedata.first;
 +      RegionView3D *rv3d = ar->regiondata;
 +      Base *base;
 +      Object *ob = OBACT(view_layer);
 +      bGPdata *gpd = CTX_data_gpencil_data(C);
 +      const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
 +      int a, totsel = 0;
 +      const int pivot_point = scene->toolsettings->transform_pivot_point;
 +
 +      /* transform widget matrix */
 +      unit_m4(rv3d->twmat);
 +
 +      unit_m3(rv3d->tw_axis_matrix);
 +      zero_v3(rv3d->tw_axis_min);
 +      zero_v3(rv3d->tw_axis_max);
 +
 +      rv3d->twdrawflag = 0xFFFF;
 +
 +      /* global, local or normal orientation?
 +       * if we could check 'totsel' now, this should be skipped with no selection. */
 +      if (ob && !is_gp_edit) {
 +              const short orientation_type = params->orientation_type ? (params->orientation_type - 1) : scene->orientation_type;
 +
 +              switch (orientation_type) {
 +
 +                      case V3D_MANIP_GLOBAL:
 +                      {
 +                              break; /* nothing to do */
 +                      }
 +                      case V3D_MANIP_GIMBAL:
 +                      {
 +                              float mat[3][3];
 +                              if (gimbal_axis(ob, mat)) {
 +                                      copy_m4_m3(rv3d->twmat, mat);
 +                                      break;
 +                              }
 +                              /* if not gimbal, fall through to normal */
 +                              ATTR_FALLTHROUGH;
 +                      }
 +                      case V3D_MANIP_NORMAL:
 +                      {
 +                              if (obedit || ob->mode & OB_MODE_POSE) {
 +                                      float mat[3][3];
 +                                      ED_getTransformOrientationMatrix(C, mat, pivot_point);
 +                                      copy_m4_m3(rv3d->twmat, mat);
 +                                      break;
 +                              }
 +                              /* no break we define 'normal' as 'local' in Object mode */
 +                              ATTR_FALLTHROUGH;
 +                      }
 +                      case V3D_MANIP_LOCAL:
 +                      {
 +                              if (ob->mode & OB_MODE_POSE) {
 +                                      /* each bone moves on its own local axis, but  to avoid confusion,
 +                                       * use the active pones axis for display [#33575], this works as expected on a single bone
 +                                       * and users who select many bones will understand whats going on and what local means
 +                                       * when they start transforming */
 +                                      float mat[3][3];
 +                                      ED_getTransformOrientationMatrix(C, mat, pivot_point);
 +                                      copy_m4_m3(rv3d->twmat, mat);
 +                                      break;
 +                              }
 +                              copy_m4_m4(rv3d->twmat, ob->obmat);
 +                              normalize_m4(rv3d->twmat);
 +                              break;
 +                      }
 +                      case V3D_MANIP_VIEW:
 +                      {
 +                              float mat[3][3];
 +                              copy_m3_m4(mat, rv3d->viewinv);
 +                              normalize_m3(mat);
 +                              copy_m4_m3(rv3d->twmat, mat);
 +                              break;
 +                      }
 +                      case V3D_MANIP_CURSOR:
 +                      {
 +                              float mat[3][3];
 +                              ED_view3d_cursor3d_calc_mat3(scene, v3d, mat);
 +                              copy_m4_m3(rv3d->twmat, mat);
 +                              break;
 +                      }
 +                      case V3D_MANIP_CUSTOM:
 +                      {
 +                              TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find(
 +                                      scene, scene->orientation_index_custom);
 +                              float mat[3][3];
 +
 +                              if (applyTransformOrientation(custom_orientation, mat, NULL)) {
 +                                      copy_m4_m3(rv3d->twmat, mat);
 +                              }
 +                              break;
 +                      }
 +              }
 +      }
 +
 +      /* transform widget centroid/center */
 +      INIT_MINMAX(tbounds->min, tbounds->max);
 +      zero_v3(tbounds->center);
 +
 +      copy_m3_m4(tbounds->axis, rv3d->twmat);
 +      if (params->use_local_axis && (ob && ob->mode & OB_MODE_EDIT)) {
 +              float diff_mat[3][3];
 +              copy_m3_m4(diff_mat, ob->obmat);
 +              normalize_m3(diff_mat);
 +              invert_m3(diff_mat);
 +              mul_m3_m3m3(tbounds->axis, tbounds->axis, diff_mat);
 +              normalize_m3(tbounds->axis);
 +      }
 +
 +      for (int i = 0; i < 3; i++) {
 +              tbounds->axis_min[i] = +FLT_MAX;
 +              tbounds->axis_max[i] = -FLT_MAX;
 +      }
 +
 +      if (is_gp_edit) {
 +              float diff_mat[4][4];
 +              float fpt[3];
 +
 +              for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
 +                      /* only editable and visible layers are considered */
 +                      if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
 +
 +                              /* calculate difference matrix if parent object */
 +                              if (gpl->parent != NULL) {
 +                                      ED_gpencil_parent_location(gpl, diff_mat);
 +                              }
 +
 +                              for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
 +                                      /* skip strokes that are invalid for current view */
 +                                      if (ED_gpencil_stroke_can_use(C, gps) == false) {
 +                                              continue;
 +                                      }
 +
 +                                      /* we're only interested in selected points here... */
 +                                      if (gps->flag & GP_STROKE_SELECT) {
 +                                              bGPDspoint *pt;
 +                                              int i;
 +
 +                                              /* Change selection status of all points, then make the stroke match */
 +                                              for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
 +                                                      if (pt->flag & GP_SPOINT_SELECT) {
 +                                                              if (gpl->parent == NULL) {
 +                                                                      calc_tw_center(tbounds, &pt->x);
 +                                                                      totsel++;
 +                                                              }
 +                                                              else {
 +                                                                      mul_v3_m4v3(fpt, diff_mat, &pt->x);
 +                                                                      calc_tw_center(tbounds, fpt);
 +                                                                      totsel++;
 +                                                              }
 +                                                      }
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
 +
 +              /* selection center */
 +              if (totsel) {
 +                      mul_v3_fl(tbounds->center, 1.0f / (float)totsel);   /* centroid! */
 +              }
 +      }
 +      else if (obedit) {
 +              ob = obedit;
 +              if (obedit->type == OB_MESH) {
 +                      BMEditMesh *em = BKE_editmesh_from_object(obedit);
 +                      BMEditSelection ese;
 +                      float vec[3] = {0, 0, 0};
 +
 +                      /* USE LAST SELECTE WITH ACTIVE */
 +                      if ((pivot_point == V3D_AROUND_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
 +                              BM_editselection_center(&ese, vec);
 +                              calc_tw_center(tbounds, vec);
 +                              totsel = 1;
 +                      }
 +                      else {
 +                              BMesh *bm = em->bm;
 +                              BMVert *eve;
 +
 +                              BMIter iter;
 +
 +                              BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
 +                                      if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
 +                                              if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
 +                                                      totsel++;
 +                                                      calc_tw_center(tbounds, eve->co);
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              } /* end editmesh */
 +              else if (obedit->type == OB_ARMATURE) {
 +                      bArmature *arm = obedit->data;
 +                      EditBone *ebo;
 +
 +                      if ((pivot_point == V3D_AROUND_ACTIVE) && (ebo = arm->act_edbone)) {
 +                              /* doesn't check selection or visibility intentionally */
 +                              if (ebo->flag & BONE_TIPSEL) {
 +                                      calc_tw_center(tbounds, ebo->tail);
 +                                      totsel++;
 +                              }
 +                              if ((ebo->flag & BONE_ROOTSEL) ||
 +                                  ((ebo->flag & BONE_TIPSEL) == false))  /* ensure we get at least one point */
 +                              {
 +                                      calc_tw_center(tbounds, ebo->head);
 +                                      totsel++;
 +                              }
 +                              protectflag_to_drawflags_ebone(rv3d, ebo);
 +                      }
 +                      else {
 +                              for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
 +                                      if (EBONE_VISIBLE(arm, ebo)) {
 +                                              if (ebo->flag & BONE_TIPSEL) {
 +                                                      calc_tw_center(tbounds, ebo->tail);
 +                                                      totsel++;
 +                                              }
 +                                              if ((ebo->flag & BONE_ROOTSEL) &&
 +                                                  /* don't include same point multiple times */
 +                                                  ((ebo->flag & BONE_CONNECTED) &&
 +                                                   (ebo->parent != NULL) &&
 +                                                   (ebo->parent->flag & BONE_TIPSEL) &&
 +                                                   EBONE_VISIBLE(arm, ebo->parent)) == 0)
 +                                              {
 +                                                      calc_tw_center(tbounds, ebo->head);
 +                                                      totsel++;
 +                                              }
 +                                              if (ebo->flag & BONE_SELECTED) {
 +                                                      protectflag_to_drawflags_ebone(rv3d, ebo);
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +              else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
 +                      Curve *cu = obedit->data;
 +                      float center[3];
 +
 +                      if ((pivot_point == V3D_AROUND_ACTIVE) && ED_curve_active_center(cu, center)) {
 +                              calc_tw_center(tbounds, center);
 +                              totsel++;
 +                      }
 +                      else {
 +                              Nurb *nu;
 +                              BezTriple *bezt;
 +                              BPoint *bp;
 +                              ListBase *nurbs = BKE_curve_editNurbs_get(cu);
 +
 +                              nu = nurbs->first;
 +                              while (nu) {
 +                                      if (nu->type == CU_BEZIER) {
 +                                              bezt = nu->bezt;
 +                                              a = nu->pntsu;
 +                                              while (a--) {
 +                                                      /* exceptions
 +                                                       * if handles are hidden then only check the center points.
 +                                                       * If the center knot is selected then only use this as the center point.
 +                                                       */
 +                                                      if (cu->drawflag & CU_HIDE_HANDLES) {
 +                                                              if (bezt->f2 & SELECT) {
 +                                                                      calc_tw_center(tbounds, bezt->vec[1]);
 +                                                                      totsel++;
 +                                                              }
 +                                                      }
 +                                                      else if (bezt->f2 & SELECT) {
 +                                                              calc_tw_center(tbounds, bezt->vec[1]);
 +                                                              totsel++;
 +                                                      }
 +                                                      else {
 +                                                              if (bezt->f1 & SELECT) {
 +                                                                      calc_tw_center(
 +                                                                              tbounds, bezt->vec[(pivot_point == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 0]);
 +                                                                      totsel++;
 +                                                              }
 +                                                              if (bezt->f3 & SELECT) {
 +                                                                      calc_tw_center(
 +                                                                              tbounds, bezt->vec[(pivot_point == V3D_AROUND_LOCAL_ORIGINS) ? 1 : 2]);
 +                                                                      totsel++;
 +                                                              }
 +                                                      }
 +                                                      bezt++;
 +                                              }
 +                                      }
 +                                      else {
 +                                              bp = nu->bp;
 +                                              a = nu->pntsu * nu->pntsv;
 +                                              while (a--) {
 +                                                      if (bp->f1 & SELECT) {
 +                                                              calc_tw_center(tbounds, bp->vec);
 +                                                              totsel++;
 +                                                      }
 +                                                      bp++;
 +                                              }
 +                                      }
 +                                      nu = nu->next;
 +                              }
 +                      }
 +              }
 +              else if (obedit->type == OB_MBALL) {
 +                      MetaBall *mb = (MetaBall *)obedit->data;
 +                      MetaElem *ml;
 +
 +                      if ((pivot_point == V3D_AROUND_ACTIVE) && (ml = mb->lastelem)) {
 +                              calc_tw_center(tbounds, &ml->x);
 +                              totsel++;
 +                      }
 +                      else {
 +                              for (ml = mb->editelems->first; ml; ml = ml->next) {
 +                                      if (ml->flag & SELECT) {
 +                                              calc_tw_center(tbounds, &ml->x);
 +                                              totsel++;
 +                                      }
 +                              }
 +                      }
 +              }
 +              else if (obedit->type == OB_LATTICE) {
 +                      Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
 +                      BPoint *bp;
 +
 +                      if ((pivot_point == V3D_AROUND_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) {
 +                              calc_tw_center(tbounds, bp->vec);
 +                              totsel++;
 +                      }
 +                      else {
 +                              bp = lt->def;
 +                              a = lt->pntsu * lt->pntsv * lt->pntsw;
 +                              while (a--) {
 +                                      if (bp->f1 & SELECT) {
 +                                              calc_tw_center(tbounds, bp->vec);
 +                                              totsel++;
 +                                      }
 +                                      bp++;
 +                              }
 +                      }
 +              }
 +
 +              /* selection center */
 +              if (totsel) {
 +                      mul_v3_fl(tbounds->center, 1.0f / (float)totsel);   // centroid!
 +                      mul_m4_v3(obedit->obmat, tbounds->center);
 +                      mul_m4_v3(obedit->obmat, tbounds->min);
 +                      mul_m4_v3(obedit->obmat, tbounds->max);
 +              }
 +      }
 +      else if (ob && (ob->mode & OB_MODE_POSE)) {
 +              bPoseChannel *pchan;
 +              int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed
 +              bool ok = false;
 +
 +              if ((pivot_point == V3D_AROUND_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) {
 +                      /* doesn't check selection or visibility intentionally */
 +                      Bone *bone = pchan->bone;
 +                      if (bone) {
 +                              calc_tw_center(tbounds, pchan->pose_head);
 +                              protectflag_to_drawflags_pchan(rv3d, pchan);
 +                              totsel = 1;
 +                              ok = true;
 +                      }
 +              }
 +              else {
 +                      totsel = count_set_pose_transflags(ob, mode, V3D_AROUND_CENTER_BOUNDS, NULL);
 +
 +                      if (totsel) {
 +                              /* use channels to get stats */
 +                              for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
 +                                      Bone *bone = pchan->bone;
 +                                      if (bone && (bone->flag & BONE_TRANSFORM)) {
 +                                              calc_tw_center(tbounds, pchan->pose_head);
 +                                              protectflag_to_drawflags_pchan(rv3d, pchan);
 +                                      }
 +                              }
 +                              ok = true;
 +                      }
 +              }
 +
 +              if (ok) {
 +                      mul_v3_fl(tbounds->center, 1.0f / (float)totsel);   // centroid!
 +                      mul_m4_v3(ob->obmat, tbounds->center);
 +                      mul_m4_v3(ob->obmat, tbounds->min);
 +                      mul_m4_v3(ob->obmat, tbounds->max);
 +              }
 +      }
 +      else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
 +              /* pass */
 +      }
 +      else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
 +              PTCacheEdit *edit = PE_get_current(scene, ob);
 +              PTCacheEditPoint *point;
 +              PTCacheEditKey *ek;
 +              int k;
 +
 +              if (edit) {
 +                      point = edit->points;
 +                      for (a = 0; a < edit->totpoint; a++, point++) {
 +                              if (point->flag & PEP_HIDE) continue;
 +
 +                              for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) {
 +                                      if (ek->flag & PEK_SELECT) {
 +                                              calc_tw_center(tbounds, (ek->flag & PEK_USE_WCO) ? ek->world_co : ek->co);
 +                                              totsel++;
 +                                      }
 +                              }
 +                      }
 +
 +                      /* selection center */
 +                      if (totsel)
 +                              mul_v3_fl(tbounds->center, 1.0f / (float)totsel);  // centroid!
 +              }
 +      }
 +      else {
 +
 +              /* we need the one selected object, if its not active */
 +              base = BASACT(view_layer);
 +              ob = OBACT(view_layer);
 +              if (base && ((base->flag & BASE_SELECTED) == 0)) ob = NULL;
 +
 +              for (base = view_layer->object_bases.first; base; base = base->next) {
 +                      if (!TESTBASELIB(base)) {
 +                              continue;
 +                      }
 +                      if (ob == NULL) {
 +                              ob = base->object;
 +                      }
 +                      if (params->use_only_center || base->object->bb == NULL) {
 +                              calc_tw_center(tbounds, base->object->obmat[3]);
 +                      }
 +                      else {
 +                              for (uint j = 0; j < 8; j++) {
 +                                      float co[3];
 +                                      mul_v3_m4v3(co, base->object->obmat, base->object->bb->vec[j]);
 +                                      calc_tw_center(tbounds, co);
 +                              }
 +                      }
 +                      protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
 +                      totsel++;
 +              }
 +
 +              /* selection center */
 +              if (totsel) {
 +                      mul_v3_fl(tbounds->center, 1.0f / (float)totsel);   // centroid!
 +              }
 +      }
 +
 +      if (totsel == 0) {
 +              unit_m4(rv3d->twmat);
 +      }
 +      else {
 +              copy_v3_v3(rv3d->tw_axis_min, tbounds->axis_min);
 +              copy_v3_v3(rv3d->tw_axis_max, tbounds->axis_max);
 +              copy_m3_m3(rv3d->tw_axis_matrix, tbounds->axis);
 +      }
 +
 +      return totsel;
 +}
 +
 +static void manipulator_get_idot(RegionView3D *rv3d, float r_idot[3])
 +{
 +      float view_vec[3], axis_vec[3];
 +      ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec);
 +      for (int i = 0; i < 3; i++) {
 +              normalize_v3_v3(axis_vec, rv3d->twmat[i]);
 +              r_idot[i] = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec));
 +      }
 +}
 +
 +static void manipulator_prepare_mat(
 +        const bContext *C, View3D *v3d, RegionView3D *rv3d, const struct TransformBounds *tbounds)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +
 +      switch (scene->toolsettings->transform_pivot_point) {
 +              case V3D_AROUND_CENTER_BOUNDS:
 +              case V3D_AROUND_ACTIVE:
 +              {
 +                      bGPdata *gpd = CTX_data_gpencil_data(C);
 +                      Object *ob = OBACT(view_layer);
 +
 +                      if (((scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) &&
 +                           (OBEDIT_FROM_OBACT(ob) == NULL)) &&
 +                          ((gpd == NULL) || !(gpd->flag & GP_DATA_STROKE_EDITMODE)) &&
 +                          (!(ob->mode & OB_MODE_POSE)))
 +                      {
 +                              copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
 +                      }
 +                      else {
 +                              mid_v3_v3v3(rv3d->twmat[3], tbounds->min, tbounds->max);
 +                      }
 +                      break;
 +              }
 +              case V3D_AROUND_LOCAL_ORIGINS:
 +              case V3D_AROUND_CENTER_MEAN:
 +                      copy_v3_v3(rv3d->twmat[3], tbounds->center);
 +                      break;
 +              case V3D_AROUND_CURSOR:
 +                      copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d)->location);
 +                      break;
 +      }
 +}
 +
 +/**
 + * Sets up \a r_start and \a r_len to define arrow line range.
 + * Needed to adjust line drawing for combined manipulator axis types.
 + */
 +static void manipulator_line_range(const int twtype, const short axis_type, float *r_start, float *r_len)
 +{
 +      const float ofs = 0.2f;
 +
 +      *r_start = 0.2f;
 +      *r_len = 1.0f;
 +
 +      switch (axis_type) {
 +              case MAN_AXES_TRANSLATE:
 +                      if (twtype & SCE_MANIP_SCALE) {
 +                              *r_start = *r_len - ofs + 0.075f;
 +                      }
 +                      if (twtype & SCE_MANIP_ROTATE) {
 +                              *r_len += ofs;
 +                      }
 +                      break;
 +              case MAN_AXES_SCALE:
 +                      if (twtype & (SCE_MANIP_TRANSLATE | SCE_MANIP_ROTATE)) {
 +                              *r_len -= ofs + 0.025f;
 +                      }
 +                      break;
 +      }
 +
 +      *r_len -= *r_start;
 +}
 +
 +static void manipulator_xform_message_subscribe(
 +        wmManipulatorGroup *mgroup, struct wmMsgBus *mbus,
 +        Scene *scene, bScreen *UNUSED(screen), ScrArea *UNUSED(sa), ARegion *ar, const void *type_fn)
 +{
 +      /* Subscribe to view properties */
 +      wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = {
 +              .owner = ar,
 +              .user_data = mgroup->parent_mmap,
 +              .notify = WM_manipulator_do_msg_notify_tag_refresh,
 +      };
 +
 +      PointerRNA scene_ptr;
 +      RNA_id_pointer_create(&scene->id, &scene_ptr);
 +
 +      {
 +              extern PropertyRNA rna_Scene_transform_orientation;
 +              extern PropertyRNA rna_Scene_cursor_location;
 +              const PropertyRNA *props[] = {
 +                      &rna_Scene_transform_orientation,
 +                      (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) ? &rna_Scene_cursor_location : NULL,
 +              };
 +              for (int i = 0; i < ARRAY_SIZE(props); i++) {
 +                      if (props[i]) {
 +                              WM_msg_subscribe_rna(mbus, &scene_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__);
 +                      }
 +              }
 +      }
 +
 +      PointerRNA toolsettings_ptr;
 +      RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
 +
 +      if (type_fn == TRANSFORM_WGT_manipulator) {
 +              extern PropertyRNA rna_ToolSettings_transform_pivot_point;
 +              extern PropertyRNA rna_ToolSettings_use_manipulator_mode;
 +              const PropertyRNA *props[] = {
 +                      &rna_ToolSettings_transform_pivot_point,
 +                      &rna_ToolSettings_use_manipulator_mode,
 +              };
 +              for (int i = 0; i < ARRAY_SIZE(props); i++) {
 +                      WM_msg_subscribe_rna(mbus, &toolsettings_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__);
 +              }
 +      }
 +      else if (type_fn == VIEW3D_WGT_xform_cage) {
 +              /* pass */
 +      }
 +      else {
 +              BLI_assert(0);
 +      }
 +
 +      WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_mpr_tag_refresh);
 +}
 +
 +/** \} */
 +
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Transform Manipulator
 + * \{ */
 +
 +static ManipulatorGroup *manipulatorgroup_init(wmManipulatorGroup *mgroup)
 +{
 +      ManipulatorGroup *man;
 +
 +      man = MEM_callocN(sizeof(ManipulatorGroup), "manipulator_data");
 +
 +      const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true);
 +      const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true);
 +      const wmManipulatorType *wt_prim = WM_manipulatortype_find("MANIPULATOR_WT_primitive_3d", true);
 +
 +#define MANIPULATOR_NEW_ARROW(v, draw_style) { \
 +      man->manipulators[v] = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL); \
 +      RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \
 +} ((void)0)
 +#define MANIPULATOR_NEW_DIAL(v, draw_options) { \
 +      man->manipulators[v] = WM_manipulator_new_ptr(wt_dial, mgroup, NULL); \
 +      RNA_enum_set(man->manipulators[v]->ptr, "draw_options", draw_options); \
 +} ((void)0)
 +#define MANIPULATOR_NEW_PRIM(v, draw_style) { \
 +      man->manipulators[v] = WM_manipulator_new_ptr(wt_prim, mgroup, NULL); \
 +      RNA_enum_set(man->manipulators[v]->ptr, "draw_style", draw_style); \
 +} ((void)0)
 +
 +      /* add/init widgets - order matters! */
 +      MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_T, ED_MANIPULATOR_DIAL_DRAW_FLAG_FILL);
 +
 +      MANIPULATOR_NEW_DIAL(MAN_AXIS_SCALE_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
 +
 +      MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_X, ED_MANIPULATOR_ARROW_STYLE_BOX);
 +      MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Y, ED_MANIPULATOR_ARROW_STYLE_BOX);
 +      MANIPULATOR_NEW_ARROW(MAN_AXIS_SCALE_Z, ED_MANIPULATOR_ARROW_STYLE_BOX);
 +
 +      MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
 +      MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
 +      MANIPULATOR_NEW_PRIM(MAN_AXIS_SCALE_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
 +
 +      MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_X, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
 +      MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Y, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
 +      MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_Z, ED_MANIPULATOR_DIAL_DRAW_FLAG_CLIP);
 +
 +      /* init screen aligned widget last here, looks better, behaves better */
 +      MANIPULATOR_NEW_DIAL(MAN_AXIS_ROT_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
 +
 +      MANIPULATOR_NEW_DIAL(MAN_AXIS_TRANS_C, ED_MANIPULATOR_DIAL_DRAW_FLAG_NOP);
 +
 +      MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_X, ED_MANIPULATOR_ARROW_STYLE_NORMAL);
 +      MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Y, ED_MANIPULATOR_ARROW_STYLE_NORMAL);
 +      MANIPULATOR_NEW_ARROW(MAN_AXIS_TRANS_Z, ED_MANIPULATOR_ARROW_STYLE_NORMAL);
 +
 +      MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_XY, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
 +      MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_YZ, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
 +      MANIPULATOR_NEW_PRIM(MAN_AXIS_TRANS_ZX, ED_MANIPULATOR_PRIMITIVE_STYLE_PLANE);
 +
 +      return man;
 +}
 +
 +/**
 + * Custom handler for manipulator widgets
 + */
 +static int manipulator_modal(
 +        bContext *C, wmManipulator *widget, const wmEvent *event,
 +        eWM_ManipulatorTweak UNUSED(tweak_flag))
 +{
 +      /* Avoid unnecessary updates, partially address: T55458. */
 +      if (ELEM(event->type, TIMER, INBETWEEN_MOUSEMOVE)) {
 +              return OPERATOR_RUNNING_MODAL;
 +      }
 +
 +      const ScrArea *sa = CTX_wm_area(C);
 +      ARegion *ar = CTX_wm_region(C);
 +      View3D *v3d = sa->spacedata.first;
 +      RegionView3D *rv3d = ar->regiondata;
 +      struct TransformBounds tbounds;
 +
 +
 +      if (ED_transform_calc_manipulator_stats(
 +                  C, &(struct TransformCalcParams){
 +                      .use_only_center = true,
 +                  }, &tbounds))
 +      {
 +              manipulator_prepare_mat(C, v3d, rv3d, &tbounds);
 +              WM_manipulator_set_matrix_location(widget, rv3d->twmat[3]);
 +      }
 +
 +      ED_region_tag_redraw(ar);
 +
 +      return OPERATOR_RUNNING_MODAL;
 +}
 +
 +static void manipulatorgroup_init_properties_from_twtype(wmManipulatorGroup *mgroup)
 +{
 +      struct {
 +              wmOperatorType *translate, *rotate, *trackball, *resize;
 +      } ot_store = {NULL};
 +      ManipulatorGroup *man = mgroup->customdata;
 +      MAN_ITER_AXES_BEGIN(axis, axis_idx)
 +      {
 +              const short axis_type = manipulator_get_axis_type(axis_idx);
-                                       int constraint[3] = {x != 1, y != 1, z != 1};
++              bool constraint_axis[3] = {1, 0, 0};
 +              PointerRNA *ptr;
 +
 +              manipulator_get_axis_constraint(axis_idx, constraint_axis);
 +
 +              /* custom handler! */
 +              WM_manipulator_set_fn_custom_modal(axis, manipulator_modal);
 +
 +              switch (axis_idx) {
 +                      case MAN_AXIS_TRANS_X:
 +                      case MAN_AXIS_TRANS_Y:
 +                      case MAN_AXIS_TRANS_Z:
 +                      case MAN_AXIS_SCALE_X:
 +                      case MAN_AXIS_SCALE_Y:
 +                      case MAN_AXIS_SCALE_Z:
 +                              if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
 +                                      int draw_options = 0;
 +                                      if ((man->twtype & (SCE_MANIP_ROTATE | SCE_MANIP_SCALE)) == 0) {
 +                                              draw_options |= ED_MANIPULATOR_ARROW_DRAW_FLAG_STEM;
 +                                      }
 +                                      RNA_enum_set(axis->ptr, "draw_options", draw_options);
 +                              }
 +
 +                              WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH);
 +                              break;
 +                      case MAN_AXIS_ROT_X:
 +                      case MAN_AXIS_ROT_Y:
 +                      case MAN_AXIS_ROT_Z:
 +                              /* increased line width for better display */
 +                              WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH + 1.0f);
 +                              WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true);
 +                              break;
 +                      case MAN_AXIS_TRANS_XY:
 +                      case MAN_AXIS_TRANS_YZ:
 +                      case MAN_AXIS_TRANS_ZX:
 +                      case MAN_AXIS_SCALE_XY:
 +                      case MAN_AXIS_SCALE_YZ:
 +                      case MAN_AXIS_SCALE_ZX:
 +                      {
 +                              const float ofs_ax = 7.0f;
 +                              const float ofs[3] = {ofs_ax, ofs_ax, 0.0f};
 +                              WM_manipulator_set_scale(axis, 0.07f);
 +                              WM_manipulator_set_matrix_offset_location(axis, ofs);
 +                              WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true);
 +                              break;
 +                      }
 +                      case MAN_AXIS_TRANS_C:
 +                      case MAN_AXIS_ROT_C:
 +                      case MAN_AXIS_SCALE_C:
 +                      case MAN_AXIS_ROT_T:
 +                              WM_manipulator_set_line_width(axis, MANIPULATOR_AXIS_LINE_WIDTH);
 +                              if (axis_idx == MAN_AXIS_ROT_T) {
 +                                      WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_HOVER, true);
 +                              }
 +                              else if (axis_idx == MAN_AXIS_ROT_C) {
 +                                      WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_VALUE, true);
 +                                      WM_manipulator_set_scale(axis, 1.2f);
 +                              }
 +                              else {
 +                                      WM_manipulator_set_scale(axis, 0.2f);
 +                              }
 +                              break;
 +              }
 +
 +              switch (axis_type) {
 +                      case MAN_AXES_TRANSLATE:
 +                              if (ot_store.translate == NULL) {
 +                                      ot_store.translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
 +                              }
 +                              ptr = WM_manipulator_operator_set(axis, 0, ot_store.translate, NULL);
 +                              break;
 +                      case MAN_AXES_ROTATE:
 +                      {
 +                              wmOperatorType *ot_rotate;
 +                              if (axis_idx == MAN_AXIS_ROT_T) {
 +                                      if (ot_store.trackball == NULL) {
 +                                              ot_store.trackball = WM_operatortype_find("TRANSFORM_OT_trackball", true);
 +                                      }
 +                                      ot_rotate = ot_store.trackball;
 +                              }
 +                              else {
 +                                      if (ot_store.rotate == NULL) {
 +                                              ot_store.rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
 +                                      }
 +                                      ot_rotate = ot_store.rotate;
 +                              }
 +                              ptr = WM_manipulator_operator_set(axis, 0, ot_rotate, NULL);
 +                              break;
 +                      }
 +                      case MAN_AXES_SCALE:
 +                      {
 +                              if (ot_store.resize == NULL) {
 +                                      ot_store.resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
 +                              }
 +                              ptr = WM_manipulator_operator_set(axis, 0, ot_store.resize, NULL);
 +                              break;
 +                      }
 +              }
 +
 +              {
 +                      PropertyRNA *prop;
 +                      if ((prop = RNA_struct_find_property(ptr, "constraint_axis"))) {
 +                              RNA_property_boolean_set_array(ptr, prop, constraint_axis);
 +                      }
 +              }
 +
 +              RNA_boolean_set(ptr, "release_confirm", 1);
 +      }
 +      MAN_ITER_AXES_END;
 +}
 +
 +static void WIDGETGROUP_manipulator_setup(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      ManipulatorGroup *man = manipulatorgroup_init(mgroup);
 +
 +      mgroup->customdata = man;
 +
 +      {
 +              man->twtype = 0;
 +              ScrArea *sa = CTX_wm_area(C);
 +              const bToolRef *tref = sa->runtime.tool;
 +
 +              if (tref == NULL || STREQ(tref->idname, "Transform")) {
 +                      /* Setup all manipulators, they can be toggled via 'ToolSettings.manipulator_flag' */
 +                      man->twtype = SCE_MANIP_TRANSLATE | SCE_MANIP_ROTATE | SCE_MANIP_SCALE;
 +                      man->use_twtype_refresh = true;
 +              }
 +              else if (STREQ(tref->idname, "Move")) {
 +                      man->twtype |= SCE_MANIP_TRANSLATE;
 +              }
 +              else if (STREQ(tref->idname, "Rotate")) {
 +                      man->twtype |= SCE_MANIP_ROTATE;
 +              }
 +              else if (STREQ(tref->idname, "Scale")) {
 +                      man->twtype |= SCE_MANIP_SCALE;
 +              }
 +              BLI_assert(man->twtype != 0);
 +              man->twtype_init = man->twtype;
 +      }
 +
 +      /* *** set properties for axes *** */
 +      manipulatorgroup_init_properties_from_twtype(mgroup);
 +}
 +
 +static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      ManipulatorGroup *man = mgroup->customdata;
 +      ScrArea *sa = CTX_wm_area(C);
 +      ARegion *ar = CTX_wm_region(C);
 +      View3D *v3d = sa->spacedata.first;
 +      RegionView3D *rv3d = ar->regiondata;
 +      struct TransformBounds tbounds;
 +
 +      if (man->use_twtype_refresh) {
 +              Scene *scene = CTX_data_scene(C);
 +              man->twtype = scene->toolsettings->manipulator_flag & man->twtype_init;
 +              if (man->twtype != man->twtype_prev) {
 +                      man->twtype_prev = man->twtype;
 +                      manipulatorgroup_init_properties_from_twtype(mgroup);
 +              }
 +      }
 +
 +      /* skip, we don't draw anything anyway */
 +      if ((man->all_hidden =
 +           (ED_transform_calc_manipulator_stats(
 +                   C, &(struct TransformCalcParams){
 +                       .use_only_center = true,
 +                   }, &tbounds) == 0)))
 +      {
 +              return;
 +      }
 +
 +      manipulator_prepare_mat(C, v3d, rv3d, &tbounds);
 +
 +      /* *** set properties for axes *** */
 +
 +      MAN_ITER_AXES_BEGIN(axis, axis_idx)
 +      {
 +              const short axis_type = manipulator_get_axis_type(axis_idx);
 +              const int aidx_norm = manipulator_orientation_axis(axis_idx, NULL);
 +
 +              WM_manipulator_set_matrix_location(axis, rv3d->twmat[3]);
 +
 +              switch (axis_idx) {
 +                      case MAN_AXIS_TRANS_X:
 +                      case MAN_AXIS_TRANS_Y:
 +                      case MAN_AXIS_TRANS_Z:
 +                      case MAN_AXIS_SCALE_X:
 +                      case MAN_AXIS_SCALE_Y:
 +                      case MAN_AXIS_SCALE_Z:
 +                      {
 +                              float start_co[3] = {0.0f, 0.0f, 0.0f};
 +                              float len;
 +
 +                              manipulator_line_range(man->twtype, axis_type, &start_co[2], &len);
 +
 +                              WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
 +                              RNA_float_set(axis->ptr, "length", len);
 +
 +                              if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
 +                                      if (man->twtype & SCE_MANIP_ROTATE) {
 +                                              /* Avoid rotate and translate arrows overlap. */
 +                                              start_co[2] += 0.215f;
 +                                      }
 +                              }
 +                              WM_manipulator_set_matrix_offset_location(axis, start_co);
 +                              WM_manipulator_set_flag(axis, WM_MANIPULATOR_DRAW_OFFSET_SCALE, true);
 +                              break;
 +                      }
 +                      case MAN_AXIS_ROT_X:
 +                      case MAN_AXIS_ROT_Y:
 +                      case MAN_AXIS_ROT_Z:
 +                              WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
 +                              break;
 +                      case MAN_AXIS_TRANS_XY:
 +                      case MAN_AXIS_TRANS_YZ:
 +                      case MAN_AXIS_TRANS_ZX:
 +                      case MAN_AXIS_SCALE_XY:
 +                      case MAN_AXIS_SCALE_YZ:
 +                      case MAN_AXIS_SCALE_ZX:
 +                      {
 +                              const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1];
 +                              const float *z_axis = rv3d->twmat[aidx_norm];
 +                              WM_manipulator_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
 +                              break;
 +                      }
 +              }
 +      }
 +      MAN_ITER_AXES_END;
 +}
 +
 +static void WIDGETGROUP_manipulator_message_subscribe(
 +        const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      bScreen *screen = CTX_wm_screen(C);
 +      ScrArea *sa = CTX_wm_area(C);
 +      ARegion *ar = CTX_wm_region(C);
 +      manipulator_xform_message_subscribe(mgroup, mbus, scene, screen, sa, ar, TRANSFORM_WGT_manipulator);
 +}
 +
 +static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      ManipulatorGroup *man = mgroup->customdata;
 +      // ScrArea *sa = CTX_wm_area(C);
 +      ARegion *ar = CTX_wm_region(C);
 +      // View3D *v3d = sa->spacedata.first;
 +      RegionView3D *rv3d = ar->regiondata;
 +      float idot[3];
 +
 +      /* when looking through a selected camera, the manipulator can be at the
 +       * exact same position as the view, skip so we don't break selection */
 +      if (man->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 1e-6f) {
 +              MAN_ITER_AXES_BEGIN(axis, axis_idx)
 +              {
 +                      WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true);
 +              }
 +              MAN_ITER_AXES_END;
 +              return;
 +      }
 +      manipulator_get_idot(rv3d, idot);
 +
 +      /* *** set properties for axes *** */
 +
 +      MAN_ITER_AXES_BEGIN(axis, axis_idx)
 +      {
 +              const short axis_type = manipulator_get_axis_type(axis_idx);
 +              /* XXX maybe unset _HIDDEN flag on redraw? */
 +              if (manipulator_is_axis_visible(rv3d, man->twtype, idot, axis_type, axis_idx)) {
 +                      WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, false);
 +              }
 +              else {
 +                      WM_manipulator_set_flag(axis, WM_MANIPULATOR_HIDDEN, true);
 +                      continue;
 +              }
 +
 +              float color[4], color_hi[4];
 +              manipulator_get_axis_color(axis_idx, idot, color, color_hi);
 +              WM_manipulator_set_color(axis, color);
 +              WM_manipulator_set_color_highlight(axis, color_hi);
 +
 +              switch (axis_idx) {
 +                      case MAN_AXIS_TRANS_C:
 +                      case MAN_AXIS_ROT_C:
 +                      case MAN_AXIS_SCALE_C:
 +                      case MAN_AXIS_ROT_T:
 +                              WM_manipulator_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
 +                              break;
 +              }
 +      }
 +      MAN_ITER_AXES_END;
 +}
 +
 +static bool WIDGETGROUP_manipulator_poll(const struct bContext *C, struct wmManipulatorGroupType *wgt)
 +{
 +      /* it's a given we only use this in 3D view */
 +      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;
 +}
 +
 +void TRANSFORM_WGT_manipulator(wmManipulatorGroupType *wgt)
 +{
 +      wgt->name = "Transform Manipulator";
 +      wgt->idname = "TRANSFORM_WGT_manipulator";
 +
 +      wgt->flag |= WM_MANIPULATORGROUPTYPE_3D;
 +
 +      wgt->mmap_params.spaceid = SPACE_VIEW3D;
 +      wgt->mmap_params.regionid = RGN_TYPE_WINDOW;
 +
 +      wgt->poll = WIDGETGROUP_manipulator_poll;
 +      wgt->setup = WIDGETGROUP_manipulator_setup;
 +      wgt->refresh = WIDGETGROUP_manipulator_refresh;
 +      wgt->message_subscribe = WIDGETGROUP_manipulator_message_subscribe;
 +      wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare;
 +}
 +
 +/** \} */
 +
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Scale Cage Manipulator
 + * \{ */
 +
 +struct XFormCageWidgetGroup {
 +      wmManipulator *manipulator;
 +};
 +
 +static bool WIDGETGROUP_xform_cage_poll(const bContext *C, wmManipulatorGroupType *wgt)
 +{
 +      bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
 +      if (!STREQ(wgt->idname, tref_rt->manipulator_group)) {
 +              WM_manipulator_group_type_unlink_delayed_ptr(wgt);
 +              return false;
 +      }
 +      return true;
 +}
 +
 +static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
 +{
 +      struct XFormCageWidgetGroup *xmgroup = MEM_mallocN(sizeof(struct XFormCageWidgetGroup), __func__);
 +      const wmManipulatorType *wt_cage = WM_manipulatortype_find("MANIPULATOR_WT_cage_3d", true);
 +      xmgroup->manipulator = WM_manipulator_new_ptr(wt_cage, mgroup, NULL);
 +      wmManipulator *mpr = xmgroup->manipulator;
 +
 +      RNA_enum_set(mpr->ptr, "transform",
 +                   ED_MANIPULATOR_CAGE2D_XFORM_FLAG_SCALE |
 +                   ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE);
 +
 +      mpr->color[0] = 1;
 +      mpr->color_hi[0] = 1;
 +
 +      mgroup->customdata = xmgroup;
 +
 +      {
 +              wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
 +              PointerRNA *ptr;
 +
 +              /* assign operator */
 +              PropertyRNA *prop_release_confirm = NULL;
 +              PropertyRNA *prop_constraint_axis = NULL;
 +
 +              int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
 +              for (int x = 0; x < 3; x++) {
 +                      for (int y = 0; y < 3; y++) {
 +                              for (int z = 0; z < 3; z++) {
++                                      bool constraint[3] = {x != 1, y != 1, z != 1};
 +                                      ptr = WM_manipulator_operator_set(mpr, i, ot_resize, NULL);
 +                                      if (prop_release_confirm == NULL) {
 +                                              prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
 +                                              prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
 +                                      }
 +                                      RNA_property_boolean_set(ptr, prop_release_confirm, true);
 +                                      RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint);
 +                                      i++;
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      ScrArea *sa = CTX_wm_area(C);
 +      View3D *v3d = sa->spacedata.first;
 +      ARegion *ar = CTX_wm_region(C);
 +      RegionView3D *rv3d = ar->regiondata;
 +
 +      struct XFormCageWidgetGroup *xmgroup = mgroup->customdata;
 +      wmManipulator *mpr = xmgroup->manipulator;
 +
 +      struct TransformBounds tbounds;
 +
 +      if ((ED_transform_calc_manipulator_stats(
 +                   C, &(struct TransformCalcParams) {
 +                       .use_local_axis = true,
 +                   }, &tbounds) == 0) ||
 +          equals_v3v3(rv3d->tw_axis_min, rv3d->tw_axis_max))
 +      {
 +              WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, true);
 +      }
 +      else {
 +              manipulator_prepare_mat(C, v3d, rv3d, &tbounds);
 +
 +              WM_manipulator_set_flag(mpr, WM_MANIPULATOR_HIDDEN, false);
 +              WM_manipulator_set_flag(mpr, WM_MANIPULATOR_GRAB_CURSOR, true);
 +
 +              float dims[3];
 +              sub_v3_v3v3(dims, rv3d->tw_axis_max, rv3d->tw_axis_min);
 +              RNA_float_set_array(mpr->ptr, "dimensions", dims);
 +              mul_v3_fl(dims, 0.5f);
 +
 +              copy_m4_m3(mpr->matrix_offset, rv3d->tw_axis_matrix);
 +              mid_v3_v3v3(mpr->matrix_offset[3], rv3d->tw_axis_max, rv3d->tw_axis_min);
 +              mul_m3_v3(rv3d->tw_axis_matrix, mpr->matrix_offset[3]);
 +
 +              PropertyRNA *prop_center_override = NULL;
 +              float center[3];
 +              float center_global[3];
 +              int i = ED_MANIPULATOR_CAGE3D_PART_SCALE_MIN_X_MIN_Y_MIN_Z;
 +              for (int x = 0; x < 3; x++) {
 +                      center[0] = (float)(1 - x) * dims[0];
 +                      for (int y = 0; y < 3; y++) {
 +                              center[1] = (float)(1 - y) * dims[1];
 +                              for (int z = 0; z < 3; z++) {
 +                                      center[2] = (float)(1 - z) * dims[2];
 +                                      struct wmManipulatorOpElem *mpop = WM_manipulator_operator_get(mpr, i);
 +                                      if (prop_center_override == NULL) {
 +                                              prop_center_override = RNA_struct_find_property(&mpop->ptr, "center_override");
 +                                      }
 +                                      mul_v3_m4v3(center_global, mpr->matrix_offset, center);
 +                                      RNA_property_float_set_array(&mpop->ptr, prop_center_override, center_global);
 +                                      i++;
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +static void WIDGETGROUP_xform_cage_message_subscribe(
 +        const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      bScreen *screen = CTX_wm_screen(C);
 +      ScrArea *sa = CTX_wm_area(C);
 +      ARegion *ar = CTX_wm_region(C);
 +      manipulator_xform_message_subscribe(mgroup, mbus, scene, screen, sa, ar, VIEW3D_WGT_xform_cage);
 +}
 +
 +static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup)
 +{
 +      struct XFormCageWidgetGroup *xmgroup = mgroup->customdata;
 +      wmManipulator *mpr = xmgroup->manipulator;
 +
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      Object *ob = OBACT(view_layer);
 +      if (ob && ob->mode & OB_MODE_EDIT) {
 +              copy_m4_m4(mpr->matrix_space, ob->obmat);
 +      }
 +      else {
 +              unit_m4(mpr->matrix_space);
 +      }
 +}
 +
 +void VIEW3D_WGT_xform_cage(wmManipulatorGroupType *wgt)
 +{
 +      wgt->name = "Transform Cage";
 +      wgt->idname = "VIEW3D_WGT_xform_cage";
 +
 +      wgt->flag |= WM_MANIPULATORGROUPTYPE_3D;
 +
 +      wgt->mmap_params.spaceid = SPACE_VIEW3D;
 +      wgt->mmap_params.regionid = RGN_TYPE_WINDOW;
 +
 +      wgt->poll = WIDGETGROUP_xform_cage_poll;
 +      wgt->setup = WIDGETGROUP_xform_cage_setup;
 +      wgt->refresh = WIDGETGROUP_xform_cage_refresh;
 +      wgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe;
 +      wgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare;
 +}
 +
 +/** \} */
Simple merge
Simple merge
Simple merge
@@@ -247,19 -238,7 +247,19 @@@ static IDProperty *rna_EditBone_idprops
        return ebone->prop;
  }
  
- static void rna_bone_layer_set(int *layer, const int *values)
 +/* Update the layers_used variable after bones are moved between layer
 + * NOTE: Used to be done in drawing code in 2.7, but that won't work with
 + *       Copy-on-Write, as drawing uses evaluated copies.
 + */
 +static void rna_Armature_layer_used_refresh(bArmature *arm, ListBase *bones)
 +{
 +      for (Bone *bone = bones->first; bone; bone = bone->next) {
 +              arm->layer_used |= bone->layer;
 +              rna_Armature_layer_used_refresh(arm, &bone->childbase);
 +      }
 +}
 +
+ static void rna_bone_layer_set(int *layer, const bool *values)
  {
        int i, tot = 0;
  
        }
  }
  
- static void rna_Bone_layer_set(PointerRNA *ptr, const int *values)
+ static void rna_Bone_layer_set(PointerRNA *ptr, const bool *values)
  {
 +      bArmature *arm = (bArmature *)ptr->id.data;
        Bone *bone = (Bone *)ptr->data;
 +
        rna_bone_layer_set(&bone->layer, values);
 +
 +      arm->layer_used = 0;
 +      rna_Armature_layer_used_refresh(arm, &arm->bonebase);
  }
  
- static void rna_Armature_layer_set(PointerRNA *ptr, const int *values)
+ static void rna_Armature_layer_set(PointerRNA *ptr, const bool *values)
  {
        bArmature *arm = (bArmature *)ptr->data;
        int i, tot = 0;
@@@ -202,173 -79,7 +202,173 @@@ static void rna_Depsgraph_debug_stats(D
        DEG_stats_simple(depsgraph, &outer, &ops, &rels);
        BLI_snprintf(result, STATS_MAX_SIZE,
                    "Approx %lu Operations, %lu Relations, %lu Outer Nodes",
 -                  ops, rels, outer);
 +                   ops, rels, outer);
 +}
 +
 +/* Iteration over objects, simple version */
 +
 +static void rna_Depsgraph_objects_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
 +{
 +      iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
 +      DEGObjectIterData *data = MEM_callocN(sizeof(DEGObjectIterData), __func__);
 +
 +      data->graph = (Depsgraph *)ptr->data;
 +      data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
 +                   DEG_ITER_OBJECT_FLAG_VISIBLE |
 +                   DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
 +
 +      ((BLI_Iterator *)iter->internal.custom)->valid = true;
 +      DEG_iterator_objects_begin(iter->internal.custom, data);
 +      iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
 +}
 +
 +static void rna_Depsgraph_objects_next(CollectionPropertyIterator *iter)
 +{
 +      DEG_iterator_objects_next(iter->internal.custom);
 +      iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
 +}
 +
 +static void rna_Depsgraph_objects_end(CollectionPropertyIterator *iter)
 +{
 +      DEG_iterator_objects_end(iter->internal.custom);
 +      MEM_freeN(((BLI_Iterator *)iter->internal.custom)->data);
 +      MEM_freeN(iter->internal.custom);
 +}
 +
 +static PointerRNA rna_Depsgraph_objects_get(CollectionPropertyIterator *iter)
 +{
 +      Object *ob = ((BLI_Iterator *)iter->internal.custom)->current;
 +      return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ob);
 +}
 +
 +/* Iteration over objects, extended version
 + *
 + * Contains extra information about duplicator and persistent ID.
 + */
 +
 +static void rna_Depsgraph_object_instances_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
 +{
 +      iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
 +      DEGObjectIterData *data = MEM_callocN(sizeof(DEGObjectIterData), __func__);
 +
 +      data->graph = (Depsgraph *)ptr->data;
 +      data->flag = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
 +                   DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
 +                   DEG_ITER_OBJECT_FLAG_VISIBLE |
 +                   DEG_ITER_OBJECT_FLAG_DUPLI;
 +
 +      ((BLI_Iterator *)iter->internal.custom)->valid = true;
 +      DEG_iterator_objects_begin(iter->internal.custom, data);
 +      iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
 +}
 +
 +static void rna_Depsgraph_object_instances_next(CollectionPropertyIterator *iter)
 +{
 +      DEG_iterator_objects_next(iter->internal.custom);
 +      iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
 +}
 +
 +static void rna_Depsgraph_object_instances_end(CollectionPropertyIterator *iter)
 +{
 +      DEG_iterator_objects_end(iter->internal.custom);
 +      MEM_freeN(((BLI_Iterator *)iter->internal.custom)->data);
 +      MEM_freeN(iter->internal.custom);
 +}
 +
 +static PointerRNA rna_Depsgraph_object_instances_get(CollectionPropertyIterator *iter)
 +{
 +      BLI_Iterator *iterator = (BLI_Iterator *)iter->internal.custom;
 +      return rna_pointer_inherit_refine(&iter->parent, &RNA_DepsgraphObjectInstance, iterator);
 +}
 +
 +/* Iteration over evaluated IDs */
 +
 +static void rna_Depsgraph_ids_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
 +{
 +      iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
 +      DEGIDIterData *data = MEM_callocN(sizeof(DEGIDIterData), __func__);
 +
 +      data->graph = (Depsgraph *)ptr->data;
 +
 +      ((BLI_Iterator *)iter->internal.custom)->valid = true;
 +      DEG_iterator_ids_begin(iter->internal.custom, data);
 +      iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
 +}
 +
 +static void rna_Depsgraph_ids_next(CollectionPropertyIterator *iter)
 +{
 +      DEG_iterator_ids_next(iter->internal.custom);
 +      iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
 +}
 +
 +static void rna_Depsgraph_ids_end(CollectionPropertyIterator *iter)
 +{
 +      DEG_iterator_ids_end(iter->internal.custom);
 +      MEM_freeN(((BLI_Iterator *)iter->internal.custom)->data);
 +      MEM_freeN(iter->internal.custom);
 +}
 +
 +static PointerRNA rna_Depsgraph_ids_get(CollectionPropertyIterator *iter)
 +{
 +      ID *id = ((BLI_Iterator *)iter->internal.custom)->current;
 +      return rna_pointer_inherit_refine(&iter->parent, &RNA_ID, id);
 +}
 +
 +static void rna_Depsgraph_updates_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
 +{
 +      iter->internal.custom = MEM_callocN(sizeof(BLI_Iterator), __func__);
 +      DEGIDIterData *data = MEM_callocN(sizeof(DEGIDIterData), __func__);
 +
 +      data->graph = (Depsgraph *)ptr->data;
 +      data->only_updated = true;
 +
 +      ((BLI_Iterator *)iter->internal.custom)->valid = true;
 +      DEG_iterator_ids_begin(iter->internal.custom, data);
 +      iter->valid = ((BLI_Iterator *)iter->internal.custom)->valid;
 +}
 +
 +static PointerRNA rna_Depsgraph_updates_get(CollectionPropertyIterator *iter)
 +{
 +      ID *id = ((BLI_Iterator *)iter->internal.custom)->current;
 +      return rna_pointer_inherit_refine(&iter->parent, &RNA_DepsgraphUpdate, id);
 +}
 +
 +static ID *rna_Depsgraph_id_eval_get(Depsgraph *depsgraph, ID *id_orig)
 +{
 +      return DEG_get_evaluated_id(depsgraph, id_orig);
 +}
 +
- static int rna_Depsgraph_id_type_updated(Depsgraph *depsgraph, int id_type)
++static bool rna_Depsgraph_id_type_updated(Depsgraph *depsgraph, int id_type)
 +{
 +      return DEG_id_type_updated(depsgraph, id_type);
 +}
 +
 +static PointerRNA rna_Depsgraph_scene_get(PointerRNA *ptr)
 +{
 +      Depsgraph *depsgraph = (Depsgraph *)ptr->data;
 +      Scene *scene = DEG_get_input_scene(depsgraph);
 +      return rna_pointer_inherit_refine(ptr, &RNA_Scene, scene);
 +}
 +
 +static PointerRNA rna_Depsgraph_view_layer_get(PointerRNA *ptr)
 +{
 +      Depsgraph *depsgraph = (Depsgraph *)ptr->data;
 +      ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
 +      return rna_pointer_inherit_refine(ptr, &RNA_ViewLayer, view_layer);
 +}
 +
 +static PointerRNA rna_Depsgraph_scene_eval_get(PointerRNA *ptr)
 +{
 +      Depsgraph *depsgraph = (Depsgraph *)ptr->data;
 +      Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
 +      return rna_pointer_inherit_refine(ptr, &RNA_Scene, scene_eval);
 +}
 +
 +static PointerRNA rna_Depsgraph_view_layer_eval_get(PointerRNA *ptr)
 +{
 +      Depsgraph *depsgraph = (Depsgraph *)ptr->data;
 +      ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
 +      return rna_pointer_inherit_refine(ptr, &RNA_ViewLayer, view_layer_eval);
  }
  
  #else
@@@ -481,8 -403,8 +481,8 @@@ PointerRNA rna_pointer_inherit_refine(s
  int rna_parameter_size(struct PropertyRNA *parm);
  
  struct Mesh *rna_Main_meshes_new_from_object(
 -        struct Main *bmain, struct ReportList *reports, struct Scene *sce,
 -        struct Object *ob, bool apply_modifiers, int settings, bool calc_tessface, bool calc_undeformed);
 +        struct Main *bmain, struct ReportList *reports, struct Depsgraph *depsgraph,
-         struct Object *ob, int apply_modifiers, int calc_tessface, int calc_undeformed);
++        struct Object *ob, bool apply_modifiers, bool calc_tessface, bool calc_undeformed);
  
  /* XXX, these should not need to be defined here~! */
  struct MTex *rna_mtex_texture_slots_add(struct ID *self, struct bContext *C, struct ReportList *reports);
@@@ -297,12 -292,11 +298,12 @@@ static Mesh *rna_Main_meshes_new(Main *
  }
  
  /* copied from Mesh_getFromObject and adapted to RNA interface */
 -/* settings: 1 - preview, 2 - render */
  Mesh *rna_Main_meshes_new_from_object(
 -        Main *bmain, ReportList *reports, Scene *sce,
 -        Object *ob, bool apply_modifiers, int settings, bool calc_tessface, bool calc_undeformed)
 +        Main *bmain, ReportList *reports, Depsgraph *depsgraph,
-         Object *ob, int apply_modifiers, int calc_tessface, int calc_undeformed)
++        Object *ob, bool apply_modifiers, bool calc_tessface, bool calc_undeformed)
  {
 +      Scene *sce = DEG_get_evaluated_scene(depsgraph);
 +
        switch (ob->type) {
                case OB_FONT:
                case OB_CURVE:
@@@ -580,21 -574,14 +581,21 @@@ static FreestyleLineStyle *rna_Main_lin
        return linestyle;
  }
  
 -/* tag and is_updated functions, all the same */
 +static LightProbe *rna_Main_lightprobe_new(Main *bmain, const char *name)
 +{
 +      char safe_name[MAX_ID_NAME - 2];
 +      rna_idname_validate(name, safe_name);
 +
 +      LightProbe *probe = BKE_lightprobe_add(bmain, safe_name);
 +      id_us_min(&probe->id);
 +      return probe;
 +}
 +
 +/* tag functions, all the same */
  #define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type)            \
-       static void rna_Main_##_func_name##_tag(Main *bmain, int value) {              \
+       static void rna_Main_##_func_name##_tag(Main *bmain, bool value) {             \
                BKE_main_id_tag_listbase(&bmain->_listbase_name, LIB_TAG_DOIT, value);     \
        }                                                                              \
 -      static bool rna_Main_##_func_name##_is_updated_get(PointerRNA *ptr) {          \
 -              return DAG_id_type_tagged(ptr->data, _id_type) != 0;                       \
 -      }
  
  RNA_MAIN_ID_TAG_FUNCS_DEF(cameras, camera, ID_CA)
  RNA_MAIN_ID_TAG_FUNCS_DEF(scenes, scene, ID_SCE)
@@@ -191,10 -190,10 +191,10 @@@ static void rna_Mesh_normals_split_cust
  
        rna_Mesh_normals_split_custom_do(mesh, vertnors, true);
  
 -      DAG_id_tag_update(&mesh->id, 0);
 +      DEG_id_tag_update(&mesh->id, 0);
  }
  
- static void rna_Mesh_transform(Mesh *mesh, float *mat, int shape_keys)
+ static void rna_Mesh_transform(Mesh *mesh, float *mat, bool shape_keys)
  {
        BKE_mesh_transform(mesh, (float (*)[4])mat, shape_keys);
  
@@@ -207,10 -206,10 +207,10 @@@ static void rna_Mesh_flip_normals(Mesh 
        BKE_mesh_tessface_clear(mesh);
        BKE_mesh_calc_normals(mesh);
  
 -      DAG_id_tag_update(&mesh->id, 0);
 +      DEG_id_tag_update(&mesh->id, 0);
  }
  
- static void rna_Mesh_split_faces(Mesh *mesh, int free_loop_normals)
+ static void rna_Mesh_split_faces(Mesh *mesh, bool free_loop_normals)
  {
        BKE_mesh_split_faces(mesh, free_loop_normals != 0);
  }
@@@ -88,65 -86,9 +88,65 @@@ static const EnumPropertyItem space_ite
  #include "DNA_scene_types.h"
  #include "DNA_view3d_types.h"
  
 +#include "DEG_depsgraph_query.h"
 +
  #include "MEM_guardedalloc.h"
  
 -#include "DEG_depsgraph.h"
 +static void rna_Object_select_set(Object *ob, bContext *C, ReportList *reports, int action)
 +{
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      Base *base = BKE_view_layer_base_find(view_layer, ob);
 +
 +      if (!base) {
 +              BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name);
 +              return;
 +      }
 +
 +      if (action == 2) { /* TOGGLE */
 +              if ((base->flag & BASE_SELECTED) != 0) {
 +                      action = 1; /* DESELECT */
 +              }
 +              else {
 +                      action = 0; /* SELECT */
 +              }
 +      }
 +
 +      switch (action) {
 +              case 1: /* DESELECT */
 +                      base->flag &= ~BASE_SELECTED;
 +                      break;
 +              case 0: /* SELECT */
 +              default:
 +                      BKE_view_layer_base_select(view_layer, base);
 +                      break;
 +      }
 +}
 +
- static int rna_Object_select_get(Object *ob, bContext *C, ReportList *reports)
++static bool rna_Object_select_get(Object *ob, bContext *C, ReportList *reports)
 +{
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      Base *base = BKE_view_layer_base_find(view_layer, ob);
 +
 +      if (!base) {
 +              BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, view_layer->name);
 +              return -1;
 +      }
 +
 +      return ((base->flag & BASE_SELECTED) != 0) ? 1 : 0;
 +}
 +
- static int rna_Object_visible_get(Object *ob, bContext *C, ReportList *reports)
++static bool rna_Object_visible_get(Object *ob, bContext *C, ReportList *reports)
 +{
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      Base *base = BKE_view_layer_base_find(view_layer, ob);
 +
 +      if (!base) {
 +              BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, view_layer->name);
 +              return -1;
 +      }
 +
 +      return ((base->flag & BASE_VISIBLE) != 0) ? 1 : 0;
 +}
  
  /* Convert a given matrix from a space to another (using the object and/or a bone as reference). */
  static void rna_Object_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan,
@@@ -199,12 -140,89 +199,12 @@@ static void rna_Object_camera_fit_coord
  /* copied from Mesh_getFromObject and adapted to RNA interface */
  /* settings: 0 - preview, 1 - render */
  static Mesh *rna_Object_to_mesh(
 -        Object *ob, Main *bmain, ReportList *reports, Scene *sce,
 -        bool apply_modifiers, int settings, bool calc_tessface, bool calc_undeformed)
 -{
 -      return rna_Main_meshes_new_from_object(bmain, reports, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed);
 -}
 -
 -/* mostly a copy from convertblender.c */
 -static void dupli_render_particle_set(Scene *scene, Object *ob, int level, int enable)
 +        Object *ob, bContext *C, ReportList *reports, Depsgraph *depsgraph,
-         int apply_modifiers, int calc_tessface, int calc_undeformed)
++        bool apply_modifiers, bool calc_tessface, bool calc_undeformed)
  {
 -      /* ugly function, but we need to set particle systems to their render
 -       * settings before calling object_duplilist, to get render level duplis */
 -      Group *group;
 -      GroupObject *go;
 -      ParticleSystem *psys;
 -      DerivedMesh *dm;
 -      float mat[4][4];
 -
 -      unit_m4(mat);
 -
 -      if (level >= MAX_DUPLI_RECUR)
 -              return;
 -
 -      if (ob->transflag & OB_DUPLIPARTS) {
 -              for (psys = ob->particlesystem.first; psys; psys = psys->next) {
 -                      if (ELEM(psys->part->ren_as, PART_DRAW_OB, PART_DRAW_GR)) {
 -                              if (enable)
 -                                      psys_render_set(ob, psys, mat, mat, 1, 1, 0.f);
 -                              else
 -                                      psys_render_restore(ob, psys);
 -                      }
 -              }
 -
 -              if (enable) {
 -                      /* this is to make sure we get render level duplis in groups:
 -                       * the derivedmesh must be created before init_render_mesh,
 -                       * since object_duplilist does dupliparticles before that */
 -                      dm = mesh_create_derived_render(scene, ob, CD_MASK_BAREMESH | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL);
 -                      dm->release(dm);
 -
 -                      for (psys = ob->particlesystem.first; psys; psys = psys->next)
 -                              psys_get_modifier(ob, psys)->flag &= ~eParticleSystemFlag_psys_updated;
 -              }
 -      }
 -
 -      if (ob->dup_group == NULL) return;
 -      group = ob->dup_group;
 -
 -      for (go = group->gobject.first; go; go = go->next)
 -              dupli_render_particle_set(scene, go->ob, level + 1, enable);
 -}
 -/* When no longer needed, duplilist should be freed with Object.free_duplilist */
 -static void rna_Object_create_duplilist(Object *ob, Main *bmain, ReportList *reports, Scene *sce, int settings)
 -{
 -      bool for_render = (settings == DAG_EVAL_RENDER);
 -      EvaluationContext eval_ctx;
 -      DEG_evaluation_context_init(&eval_ctx, settings);
 -
 -      if (!(ob->transflag & OB_DUPLI)) {
 -              BKE_report(reports, RPT_ERROR, "Object does not have duplis");
 -              return;
 -      }
 -
 -      /* free duplilist if a user forgets to */
 -      if (ob->duplilist) {
 -              BKE_report(reports, RPT_WARNING, "Object.dupli_list has not been freed");
 +      Main *bmain = CTX_data_main(C);
  
 -              free_object_duplilist(ob->duplilist);
 -              ob->duplilist = NULL;
 -      }
 -      if (for_render)
 -              dupli_render_particle_set(sce, ob, 0, 1);
 -      ob->duplilist = object_duplilist(bmain, &eval_ctx, sce, ob);
 -      if (for_render)
 -              dupli_render_particle_set(sce, ob, 0, 0);
 -      /* ob->duplilist should now be freed with Object.free_duplilist */
 -}
 -
 -static void rna_Object_free_duplilist(Object *ob)
 -{
 -      if (ob->duplilist) {
 -              free_object_duplilist(ob->duplilist);
 -              ob->duplilist = NULL;
 -      }
 +      return rna_Main_meshes_new_from_object(bmain, reports, depsgraph, ob, apply_modifiers, calc_tessface, calc_undeformed);
  }
  
  static PointerRNA rna_Object_shape_key_add(Object *ob, bContext *C, ReportList *reports,
@@@ -397,7 -420,14 +397,7 @@@ finally
        free_bvhtree_from_mesh(&treeData);
  }
  
- static int rna_Object_is_modified(Object *ob, Scene *scene, int settings)
 -/* ObjectBase */
 -
 -static void rna_ObjectBase_layers_from_view(Base *base, View3D *v3d)
 -{
 -      base->lay = base->object->lay = v3d->lay;
 -}
 -
+ static bool rna_Object_is_modified(Object *ob, Scene *scene, int settings)
  {
        return BKE_object_is_modified(scene, ob) & settings;
  }
@@@ -442,9 -475,8 +442,9 @@@ void rna_Object_me_eval_info(struct Obj
  }
  #endif /* NDEBUG */
  
- static int rna_Object_update_from_editmode(Object *ob, Main *bmain)
+ static bool rna_Object_update_from_editmode(Object *ob, Main *bmain)
  {
 +      /* fail gracefully if we aren't in edit-mode. */
        return ED_object_editmode_load(bmain, ob);
  }
  #else /* RNA_RUNTIME */
@@@ -1116,1131 -1106,6 +1116,1131 @@@ static int rna_BlenderRNA_structs_looku
        return false;
  }
  
-                               int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
-                               int *array_a, *array_b;
 +/* Default override (and compare) callbacks. */
 +
 +/* Ensures it makes sense to go inside the pointers to compare their content
 + * (if they are IDs, or have different names or RNA type, then this would be meaningless). */
 +static bool rna_property_override_diff_propptr_validate_diffing(
 +        PointerRNA *propptr_a, PointerRNA *propptr_b, const bool no_prop_name,
 +        bool *r_is_id, bool *r_is_null, bool *r_is_type_diff,
 +        char **r_propname_a, char *propname_a_buff, size_t propname_a_buff_size,
 +        char **r_propname_b, char *propname_b_buff, size_t propname_b_buff_size)
 +{
 +      BLI_assert(propptr_a != NULL);
 +
 +      bool is_valid_for_diffing = true;
 +      const bool do_force_name = !no_prop_name && r_propname_a != NULL;
 +
 +      if (do_force_name) {
 +              BLI_assert(r_propname_a != NULL);
 +              BLI_assert(r_propname_b != NULL);
 +      }
 +
 +      *r_is_id = *r_is_null = *r_is_type_diff = false;
 +
 +      /* Beware, PointerRNA_NULL has no type and is considered a 'blank page'! */
 +      if (propptr_a->type == NULL) {
 +              if (propptr_b == NULL || propptr_b->type == NULL) {
 +                      *r_is_null = true;
 +              }
 +              else {
 +                      *r_is_id = RNA_struct_is_ID(propptr_b->type);
 +                      *r_is_null = true;
 +                      *r_is_type_diff = true;
 +              }
 +              is_valid_for_diffing = false;
 +      }
 +      else {
 +              *r_is_id = RNA_struct_is_ID(propptr_a->type);
 +              *r_is_null = *r_is_type_diff = (ELEM(NULL, propptr_b, propptr_b->type));
 +              is_valid_for_diffing = !(*r_is_id || *r_is_null);
 +      }
 +
 +      if (propptr_b == NULL || propptr_a->type != propptr_b->type) {
 +              *r_is_type_diff = true;
 +              is_valid_for_diffing = false;
 +//            printf("%s: different pointer RNA types\n", rna_path ? rna_path : "<UNKNOWN>");
 +      }
 +
 +      /* We do a generic quick first comparison checking for "name" and/or "type" properties.
 +       * We assume that is any of those are false, then we are not handling the same data.
 +       * This helps a lot in static override case, especially to detect inserted items in collections. */
 +      if (!no_prop_name && (is_valid_for_diffing || do_force_name)) {
 +              PropertyRNA *nameprop_a = RNA_struct_name_property(propptr_a->type);
 +              PropertyRNA *nameprop_b = (propptr_b != NULL) ? RNA_struct_name_property(propptr_b->type) : NULL;
 +
 +              int propname_a_len = 0, propname_b_len = 0;
 +              char *propname_a = NULL;
 +              char *propname_b = NULL;
 +              char buff_a[4096];
 +              char buff_b[4096];
 +              if (nameprop_a != NULL) {
 +                      if (r_propname_a == NULL && propname_a_buff == NULL) {
 +                              propname_a_buff = buff_a;
 +                              propname_a_buff_size = sizeof(buff_a);
 +                      }
 +
 +                      propname_a = RNA_property_string_get_alloc(
 +                                       propptr_a, nameprop_a, propname_a_buff, propname_a_buff_size, &propname_a_len);
 +//                    printf("propname_a = %s\n", propname_a ? propname_a : "<NONE>");
 +
 +                      if (r_propname_a != NULL) {
 +                              *r_propname_a = propname_a;
 +                      }
 +              }
 +//            else printf("item of type %s a has no name property!\n", propptr_a->type->name);
 +              if (nameprop_b != NULL) {
 +                      if (r_propname_b == NULL && propname_b_buff == NULL) {
 +                              propname_b_buff = buff_b;
 +                              propname_b_buff_size = sizeof(buff_b);
 +                      }
 +
 +                      propname_b = RNA_property_string_get_alloc(
 +                                       propptr_b, nameprop_b, propname_b_buff, propname_b_buff_size, &propname_b_len);
 +
 +                      if (r_propname_b != NULL) {
 +                              *r_propname_b = propname_b;
 +                      }
 +              }
 +              if (propname_a != NULL && propname_b != NULL) {
 +                      if (propname_a_len != propname_b_len ||
 +                          propname_a[0] != propname_b[0] ||
 +                          !STREQ(propname_a, propname_b))
 +                      {
 +                              is_valid_for_diffing = false;
 +//                            printf("%s: different names\n", rna_path ? rna_path : "<UNKNOWN>");
 +                      }
 +              }
 +      }
 +
 +      if (*r_is_id) {
 +              BLI_assert(propptr_a->data == propptr_a->id.data && propptr_b->data == propptr_b->id.data);
 +      }
 +
 +      return is_valid_for_diffing;
 +}
 +
 +/* Used for both Pointer and Collection properties. */
 +static int rna_property_override_diff_propptr(
 +        Main *bmain,
 +        PointerRNA *propptr_a, PointerRNA *propptr_b,
 +        eRNACompareMode mode, const bool no_ownership, const bool no_prop_name,
 +        IDOverrideStatic *override, const char *rna_path, const int flags, bool *r_override_changed)
 +{
 +      const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL;
 +
 +      bool is_id = false;
 +      bool is_null = false;
 +      bool is_type_diff = false;
 +      /* If false, it means that the whole data itself is different, so no point in going inside of it at all! */
 +      bool is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing(
 +                                      propptr_a, propptr_b, no_prop_name, &is_id, &is_null, &is_type_diff,
 +                                      NULL, NULL, 0, NULL, NULL, 0);
 +
 +      if (is_id) {
 +              BLI_assert(no_ownership);  /* For now, once we deal with nodetrees we'll want to get rid of that one. */
 +      }
 +
 +      if (override) {
 +              if (no_ownership /* || is_id */ || is_null || is_type_diff || !is_valid_for_diffing) {
 +                      /* In case this pointer prop does not own its data (or one is NULL), do not compare structs!
 +                       * This is a quite safe path to infinite loop, among other nasty issues.
 +                       * Instead, just compare pointers themselves. */
 +                      const int comp = (propptr_a->data != propptr_b->data);
 +
 +                      if (do_create && comp != 0) {
 +                              bool created = false;
 +                              IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
 +
 +                              if (op != NULL && created) {  /* If not yet overridden... */
 +                                      BKE_override_static_property_operation_get(
 +                                                  op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
 +                                      if (r_override_changed) {
 +                                              *r_override_changed = created;
 +                                      }
 +                              }
 +                      }
 +
 +                      return comp;
 +              }
 +              else {
 +                      eRNAOverrideMatchResult report_flags = 0;
 +                      const bool match = RNA_struct_override_matches(
 +                                             bmain, propptr_a, propptr_b, rna_path, override, flags, &report_flags);
 +                      if (r_override_changed && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) != 0) {
 +                              *r_override_changed = true;
 +                      }
 +                      return !match;
 +              }
 +      }
 +      else {
 +              /* We could also use is_diff_pointer, but then we potentially lose the gt/lt info -
 +               * and don't think performances are critical here for now anyway... */
 +              return !RNA_struct_equals(bmain, propptr_a, propptr_b, mode);
 +      }
 +}
 +
 +
 +
 +#define RNA_PROPERTY_GET_SINGLE(_typename, _ptr, _prop, _index) \
 +      (is_array ? RNA_property_##_typename##_get_index((_ptr), (_prop), (_index)) : \
 +                  RNA_property_##_typename##_get((_ptr), (_prop)))
 +#define RNA_PROPERTY_SET_SINGLE(_typename, _ptr, _prop, _index, _value) \
 +      (is_array ? RNA_property_##_typename##_set_index((_ptr), (_prop), (_index), (_value)) : \
 +                  RNA_property_##_typename##_set((_ptr), (_prop), (_value)))
 +
 +int rna_property_override_diff_default(
 +        Main *bmain,
 +        PointerRNA *ptr_a, PointerRNA *ptr_b,
 +        PropertyRNA *prop_a, PropertyRNA *prop_b,
 +        const int len_a, const int len_b,
 +        const int mode,
 +        IDOverrideStatic *override, const char *rna_path,
 +        const int flags, bool *r_override_changed)
 +{
 +      BLI_assert(len_a == len_b);
 +
 +      /* Note: at this point, we are sure that when len_a is zero, we are not handling an (empty) array. */
 +
 +      const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL;
 +
 +      switch (RNA_property_type(prop_a)) {
 +              case PROP_BOOLEAN:
 +              {
 +                      if (len_a) {
-                               array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_a, "RNA equals") : array_stack_a;
-                               array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_b, "RNA equals") : array_stack_b;
++                              bool array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
++                              bool *array_a, *array_b;
 +
-                               const int comp = memcmp(array_a, array_b, sizeof(int) * len_a);
++                              array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(bool) * len_a, "RNA equals") : array_stack_a;
++                              array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(bool) * len_b, "RNA equals") : array_stack_b;
 +
 +                              RNA_property_boolean_get_array(ptr_a, prop_a, array_a);
 +                              RNA_property_boolean_get_array(ptr_b, prop_b, array_b);
 +
-                               const int value_a = RNA_property_boolean_get(ptr_a, prop_a);
-                               const int value_b = RNA_property_boolean_get(ptr_b, prop_b);
++                              const int comp = memcmp(array_a, array_b, sizeof(bool) * len_a);
 +
 +                              if (do_create && comp != 0) {
 +                                      /* XXX TODO this will have to be refined to handle array items */
 +                                      bool created = false;
 +                                      IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
 +
 +                                      if (op != NULL && created) {
 +                                              BKE_override_static_property_operation_get(
 +                                                          op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
 +                                              if (r_override_changed) {
 +                                                      *r_override_changed = created;
 +                                              }
 +                                      }
 +                                      else {
 +                                              /* Already overriden prop, we'll have to check arrays items etc. */
 +                                      }
 +                              }
 +
 +                              if (array_a != array_stack_a) MEM_freeN(array_a);
 +                              if (array_b != array_stack_b) MEM_freeN(array_b);
 +
 +                              return comp;
 +                      }
 +                      else {
-                               int array_stack_a[RNA_STACK_ARRAY];
-                               int *array_a;
++                              const bool value_a = RNA_property_boolean_get(ptr_a, prop_a);
++                              const bool value_b = RNA_property_boolean_get(ptr_b, prop_b);
 +                              const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
 +
 +                              if (do_create && comp != 0) {
 +                                      bool created = false;
 +                                      IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
 +
 +                                      if (op != NULL && created) {  /* If not yet overridden... */
 +                                              BKE_override_static_property_operation_get(
 +                                                          op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
 +                                              if (r_override_changed) {
 +                                                      *r_override_changed = created;
 +                                              }
 +                                      }
 +                              }
 +
 +                              return comp;
 +                      }
 +              }
 +
 +              case PROP_INT:
 +              {
 +                      if (len_a) {
 +                              int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
 +                              int *array_a, *array_b;
 +
 +                              array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_a, "RNA equals") : array_stack_a;
 +                              array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(int) * len_b, "RNA equals") : array_stack_b;
 +
 +                              RNA_property_int_get_array(ptr_a, prop_a, array_a);
 +                              RNA_property_int_get_array(ptr_b, prop_b, array_b);
 +
 +                              const int comp = memcmp(array_a, array_b, sizeof(int) * len_a);
 +
 +                              if (do_create && comp != 0) {
 +                                      /* XXX TODO this will have to be refined to handle array items */
 +                                      bool created = false;
 +                                      IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
 +
 +                                      if (op != NULL && created) {
 +                                              BKE_override_static_property_operation_get(
 +                                                          op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
 +                                              if (r_override_changed) {
 +                                                      *r_override_changed = created;
 +                                              }
 +                                      }
 +                                      else {
 +                                              /* Already overriden prop, we'll have to check arrays items etc. */
 +                                      }
 +                              }
 +
 +                              if (array_a != array_stack_a) MEM_freeN(array_a);
 +                              if (array_b != array_stack_b) MEM_freeN(array_b);
 +
 +                              return comp;
 +                      }
 +                      else {
 +                              const int value_a = RNA_property_int_get(ptr_a, prop_a);
 +                              const int value_b = RNA_property_int_get(ptr_b, prop_b);
 +                              const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
 +
 +                              if (do_create && comp != 0) {
 +                                      bool created = false;
 +                                      IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
 +
 +                                      if (op != NULL && created) {  /* If not yet overridden... */
 +                                              BKE_override_static_property_operation_get(
 +                                                          op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
 +                                              if (r_override_changed) {
 +                                                      *r_override_changed = created;
 +                                              }
 +                                      }
 +                              }
 +
 +                              return comp;
 +                      }
 +              }
 +
 +              case PROP_FLOAT:
 +              {
 +                      if (len_a) {
 +                              float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
 +                              float *array_a, *array_b;
 +
 +                              array_a = (len_a > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(float) * len_a, "RNA equals") : array_stack_a;
 +                              array_b = (len_b > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(float) * len_b, "RNA equals") : array_stack_b;
 +
 +                              RNA_property_float_get_array(ptr_a, prop_a, array_a);
 +                              RNA_property_float_get_array(ptr_b, prop_b, array_b);
 +
 +                              const int comp = memcmp(array_a, array_b, sizeof(float) * len_a);
 +
 +                              if (do_create && comp != 0) {
 +                                      /* XXX TODO this will have to be refined to handle array items */
 +                                      bool created = false;
 +                                      IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
 +
 +                                      if (op != NULL && created) {
 +                                              BKE_override_static_property_operation_get(
 +                                                          op, IDOVERRIDESTATIC_OP_REPLACE,
 +                                                          NULL, NULL, -1, -1, true, NULL, NULL);
 +                                              if (r_override_changed) {
 +                                                      *r_override_changed = created;
 +                                              }
 +                                      }
 +                                      else {
 +                                              /* Already overriden prop, we'll have to check arrays items etc. */
 +                                      }
 +                              }
 +
 +                              if (array_a != array_stack_a) MEM_freeN(array_a);
 +                              if (array_b != array_stack_b) MEM_freeN(array_b);
 +
 +                              return comp;
 +                      }
 +                      else {
 +                              const float value_a = RNA_property_float_get(ptr_a, prop_a);
 +                              const float value_b = RNA_property_float_get(ptr_b, prop_b);
 +                              const int comp = (value_a < value_b) ? -1 : (value_a > value_b) ? 1 : 0;
 +
 +                              if (do_create && comp != 0) {
 +                                      bool created = false;
 +                                      IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
 +
 +                                      if (op != NULL && created) {  /* If not yet overridden... */
 +                                              BKE_override_static_property_operation_get(
 +                                                          op, IDOVERRIDESTATIC_OP_REPLACE,
 +                                                          NULL, NULL, -1, -1, true, NULL, NULL);
 +                                              if (r_override_changed) {
 +                                                      *r_override_changed = created;
 +                                              }
 +                                      }
 +                              }
 +
 +                              return comp ;
 +                      }
 +              }
 +
 +              case PROP_ENUM:
 +              {
 +                      const int value_a = RNA_property_enum_get(ptr_a, prop_a);
 +                      const int value_b = RNA_property_enum_get(ptr_b, prop_b);
 +                      const int comp = value_a != value_b;
 +
 +                      if (do_create && comp != 0) {
 +                              bool created = false;
 +                              IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
 +
 +                              if (op != NULL && created) {  /* If not yet overridden... */
 +                                      BKE_override_static_property_operation_get(
 +                                                  op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
 +                                      if (r_override_changed) {
 +                                              *r_override_changed = created;
 +                                      }
 +                              }
 +                      }
 +
 +                      return comp;
 +              }
 +
 +              case PROP_STRING:
 +              {
 +                      char fixed_a[4096], fixed_b[4096];
 +                      int len_str_a, len_str_b;
 +                      char *value_a = RNA_property_string_get_alloc(ptr_a, prop_a, fixed_a, sizeof(fixed_a), &len_str_a);
 +                      char *value_b = RNA_property_string_get_alloc(ptr_b, prop_b, fixed_b, sizeof(fixed_b), &len_str_b);
 +                      /* TODO we could do a check on length too, but then we would not have a 'real' string comparison...
 +                       * Maybe behind a eRNAOverrideMatch flag? */
 +//                    const int comp = len_str_a < len_str_b ? -1 : len_str_a > len_str_b ? 1 : strcmp(value_a, value_b);
 +                      const int comp = strcmp(value_a, value_b);
 +
 +                      if (do_create && comp != 0) {
 +                              bool created = false;
 +                              IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
 +
 +                              if (op != NULL && created) {  /* If not yet overridden... */
 +                                      BKE_override_static_property_operation_get(
 +                                                  op, IDOVERRIDESTATIC_OP_REPLACE, NULL, NULL, -1, -1, true, NULL, NULL);
 +                                      if (r_override_changed) {
 +                                              *r_override_changed = created;
 +                                      }
 +                              }
 +                      }
 +
 +                      if (value_a != fixed_a) MEM_freeN(value_a);
 +                      if (value_b != fixed_b) MEM_freeN(value_b);
 +
 +                      return comp;
 +              }
 +
 +              case PROP_POINTER:
 +              {
 +                      if (STREQ(RNA_property_identifier(prop_a), "rna_type")) {
 +                              /* Dummy 'pass' answer, this is a meta-data and must be ignored... */
 +                              return 0;
 +                      }
 +                      else {
 +                              PointerRNA propptr_a = RNA_property_pointer_get(ptr_a, prop_a);
 +                              PointerRNA propptr_b = RNA_property_pointer_get(ptr_b, prop_b);
 +                              const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
 +                              const bool no_prop_name = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_NO_PROP_NAME) != 0;
 +                              return rna_property_override_diff_propptr(
 +                                          bmain,
 +                                          &propptr_a, &propptr_b, mode, no_ownership, no_prop_name,
 +                                          override, rna_path, flags, r_override_changed);
 +                      }
 +                      break;
 +              }
 +
 +              case PROP_COLLECTION:
 +              {
 +                      /* Note: we assume we only insert in ptr_a (i.e. we can only get new items in ptr_a),
 +                       * and that we never remove anything. */
 +                      const bool use_insertion = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_STATIC_INSERTION) && do_create;
 +                      const bool no_prop_name = (RNA_property_override_flag(prop_a) & PROPOVERRIDE_NO_PROP_NAME) != 0;
 +                      bool equals = true;
 +                      bool abort = false;
 +                      bool is_first_insert = true;
 +                      int idx_a = 0;
 +                      int idx_b = 0;
 +
 +#define RNA_PATH_BUFFSIZE 8192
 +
 +                      char extended_rna_path_buffer[RNA_PATH_BUFFSIZE];
 +                      char *extended_rna_path = extended_rna_path_buffer;
 +
 +#define RNA_PATH_PRINTF(_str, ...) \
 +                      if (BLI_snprintf(extended_rna_path_buffer, RNA_PATH_BUFFSIZE, \
 +                                       (_str), __VA_ARGS__) >= RNA_PATH_BUFFSIZE - 1) \
 +                      { extended_rna_path = BLI_sprintfN((_str), __VA_ARGS__); }(void)0
 +#define RNA_PATH_FREE() \
 +                      if (extended_rna_path != extended_rna_path_buffer) MEM_freeN(extended_rna_path)
 +
 +                      CollectionPropertyIterator iter_a, iter_b;
 +                      RNA_property_collection_begin(ptr_a, prop_a, &iter_a);
 +                      RNA_property_collection_begin(ptr_b, prop_b, &iter_b);
 +
 +                      char buff_a[4096];
 +                      char buff_prev_a[4096] = {0};
 +                      char buff_b[4096];
 +                      char *propname_a = NULL;
 +                      char *prev_propname_a = buff_prev_a;
 +                      char *propname_b = NULL;
 +
 +                      for (; iter_a.valid && !abort; ) {
 +                              bool is_valid_for_diffing;
 +                              bool is_valid_for_insertion;
 +                              do {
 +                                      bool is_id = false, is_null = false, is_type_diff = false;
 +
 +                                      is_valid_for_insertion = use_insertion;
 +
 +                                      /* If false, it means that the whole data itself is different, so no point in going inside of it at all! */
 +                                      if (iter_b.valid) {
 +                                              is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing(
 +                                                                         &iter_a.ptr, &iter_b.ptr, no_prop_name,
 +                                                                         &is_id, &is_null, &is_type_diff,
 +                                                                         &propname_a, buff_a, sizeof(buff_a),
 +                                                                         &propname_b, buff_b, sizeof(buff_b));
 +                                      }
 +                                      else {
 +                                              is_valid_for_diffing = false;
 +                                              if (is_valid_for_insertion) {
 +                                                      /* We still need propname from 'a' item... */
 +                                                      rna_property_override_diff_propptr_validate_diffing(
 +                                                                  &iter_a.ptr, NULL, no_prop_name,
 +                                                                  &is_id, &is_null, &is_type_diff,
 +                                                                  &propname_a, buff_a, sizeof(buff_a),
 +                                                                  &propname_b, buff_b, sizeof(buff_b));
 +                                              }
 +                                      }
 +
 +                                      /* We do not support insertion of IDs for now, neither handle NULL pointers. */
 +                                      if (is_id || is_valid_for_diffing) {
 +                                              is_valid_for_insertion = false;
 +                                      }
 +
 +#if 0
 +                                      if (rna_path) {
 +                                              printf("Checking %s, %s [%d] vs %s [%d]; is_id: %d, diffing: %d; "
 +                                                     "insert: %d (could be used: %d, do_create: %d)\n",
 +                                                     rna_path, propname_a ? propname_a : "", idx_a, propname_b ? propname_b : "", idx_b,
 +                                                     is_id, is_valid_for_diffing, is_valid_for_insertion,
 +                                                     (RNA_property_override_flag(prop_a) & PROPOVERRIDE_STATIC_INSERTION) != 0, do_create);
 +                                      }
 +#endif
 +
 +                                      if (!(is_id || is_valid_for_diffing || is_valid_for_insertion)) {
 +                                              /* Differences we cannot handle, we can break here
 +                                               * (we do not support replacing ID pointers in collections e.g.). */
 +                                              equals = false;
 +                                              abort = true;
 +                                              break;
 +                                      }
 +
 +                                      /* There may be a propname defined in some cases, while no actual name set
 +                                       * (e.g. happens with point cache), in that case too we want to fall back to index.
 +                                       * Note that we do not need the RNA path for insertion operations. */
 +                                      if (is_id || is_valid_for_diffing) {
 +                                              if ((propname_a != NULL && propname_a[0] != '\0') &&
 +                                                  (propname_b != NULL && propname_b[0] != '\0'))
 +                                              {
 +                                                      if (rna_path) {
 +                                                              /* In case of name, either it is valid for diffing, and _a and _b are identical,
 +                                                               * or it is valid for insertion, and we need to use _a. */
 +                                                              char esc_item_name[RNA_PATH_BUFFSIZE];
 +                                                              BLI_strescape(esc_item_name, propname_a, RNA_PATH_BUFFSIZE);
 +                                                              RNA_PATH_PRINTF("%s[\"%s\"]", rna_path, esc_item_name);
 +                                                      }
 +                                              }
 +                                              else {  /* Based on index... */
 +                                                      if (rna_path) {
 +                                                              /* In case of indices, we need _a one for insertion, but _b ones for in-depth diffing.
 +                                                               * Insertion always happen once all 'replace' operations have been done,
 +                                                               * otherwise local and reference paths for those would have to be different! */
 +                                                              RNA_PATH_PRINTF("%s[%d]", rna_path, is_valid_for_insertion ? idx_a : idx_b);
 +                                                      }
 +                                              }
 +                                      }
 +
 +                                      /* Collections do not support replacement of their data (since they do not support removing),
 +                                       * only in *some* cases, insertion.
 +                                       * We also assume then that _a data is the one where things are inserted. */
 +                                      if (is_valid_for_insertion && use_insertion) {
 +                                              bool created;
 +                                              IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
 +
 +                                              if (is_first_insert) {
 +                                                      /* We need to clean up all possible existing insertion operations, otherwise we'd end up
 +                                                       * with a mess of ops everytime something changes. */
 +                                                      for (IDOverrideStaticPropertyOperation *opop = op->operations.first;
 +                                                           opop != NULL;)
 +                                                      {
 +                                                              IDOverrideStaticPropertyOperation *opop_next = opop->next;
 +                                                              if (ELEM(opop->operation,
 +                                                                       IDOVERRIDESTATIC_OP_INSERT_AFTER, IDOVERRIDESTATIC_OP_INSERT_BEFORE))
 +                                                              {
 +                                                                      BKE_override_static_property_operation_delete(op, opop);
 +                                                              }
 +                                                              opop = opop_next;
 +                                                      }
 +                                                      is_first_insert = false;
 +                                              }
 +
 +                                              BKE_override_static_property_operation_get(
 +                                                          op, IDOVERRIDESTATIC_OP_INSERT_AFTER,
 +                                                          NULL, prev_propname_a, -1, idx_a - 1, true, NULL, NULL);
 +//                                            printf("%s: Adding insertion op override after '%s'/%d\n", rna_path, prev_propname_a, idx_a - 1);
 +                                      }
 +                                      else if (is_id || is_valid_for_diffing) {
 +                                              if (equals || do_create) {
 +                                                      const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
 +                                                      const int eq = rna_property_override_diff_propptr(
 +                                                                         bmain,
 +                                                                         &iter_a.ptr, &iter_b.ptr, mode, no_ownership, no_prop_name,
 +                                                                         override, extended_rna_path, flags, r_override_changed);
 +                                                      equals = equals && eq;
 +                                              }
 +                                      }
 +
 +                                      if (prev_propname_a != buff_prev_a) {
 +                                              MEM_freeN(prev_propname_a);
 +                                              prev_propname_a = buff_prev_a;
 +                                      }
 +                                      prev_propname_a[0] = '\0';
 +                                      if (propname_a != NULL &&
 +                                          BLI_strncpy_rlen(prev_propname_a, propname_a, sizeof(buff_prev_a)) >= sizeof(buff_prev_a) - 1)
 +                                      {
 +                                              prev_propname_a = BLI_strdup(propname_a);
 +                                      }
 +                                      if (propname_a != buff_a) {
 +                                              MEM_SAFE_FREE(propname_a);
 +                                              propname_a = buff_a;
 +                                      }
 +                                      propname_a[0] = '\0';
 +                                      if (propname_b != buff_b) {
 +                                              MEM_SAFE_FREE(propname_b);
 +                                              propname_b = buff_b;
 +                                      }
 +                                      propname_b[0] = '\0';
 +                                      RNA_PATH_FREE();
 +
 +                                      if (!do_create && !equals) {
 +                                              abort = true;  /* Early out in case we do not want to loop over whole collection. */
 +                                              break;
 +                                      }
 +
 +                                      if (!(use_insertion && !(is_id || is_valid_for_diffing))) {
 +                                              break;
 +                                      }
 +
 +                                      if (iter_a.valid) {
 +                                              RNA_property_collection_next(&iter_a);
 +                                              idx_a++;
 +                                      }
 +                              } while (iter_a.valid);
 +
 +                              if (iter_a.valid) {
 +                                      RNA_property_collection_next(&iter_a);
 +                                      idx_a++;
 +                              }
 +                              if (iter_b.valid) {
 +                                      RNA_property_collection_next(&iter_b);
 +                                      idx_b++;
 +                              }
 +
 +#undef RNA_PATH_BUFFSIZE
 +#undef RNA_PATH_PRINTF
 +#undef RNA_PATH_FREE
 +                      }
 +
 +                      equals = equals && !(iter_a.valid || iter_b.valid) && !abort;  /* Not same number of items in both collections... */
 +                      RNA_property_collection_end(&iter_a);
 +                      RNA_property_collection_end(&iter_b);
 +
 +                      return (equals == false);
 +              }
 +
 +              default:
 +                      break;
 +      }
 +
 +      return 0;
 +}
 +
 +bool rna_property_override_store_default(
 +        Main *UNUSED(bmain),
 +        PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage,
 +        PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage,
 +        const int len_local, const int len_reference, const int len_storage,
 +        IDOverrideStaticPropertyOperation *opop)
 +{
 +      BLI_assert(len_local == len_reference && (!ptr_storage || len_local == len_storage));
 +      UNUSED_VARS_NDEBUG(len_reference, len_storage);
 +
 +      bool changed = false;
 +      const bool is_array = len_local > 0;
 +      const int index = is_array ? opop->subitem_reference_index : 0;
 +
 +      if (!ELEM(opop->operation, IDOVERRIDESTATIC_OP_ADD, IDOVERRIDESTATIC_OP_SUBTRACT, IDOVERRIDESTATIC_OP_MULTIPLY)) {
 +              return changed;
 +      }
 +
 +      /* XXX TODO About range limits.
 +       * Ideally, it woudl be great to get rid of RNA range in that specific case.
 +       * However, this won't be that easy and will add yet another layer of complexity in generated code,
 +       * not to mention that we could most likely *not* bypass custom setters anyway.
 +       * So for now, if needed second operand value is not in valid range, we simply fall back
 +       * to a mere REPLACE operation.
 +       * Time will say whether this is acceptable limitation or not. */
 +      switch (RNA_property_type(prop_local)) {
 +              case PROP_BOOLEAN:
 +                      /* TODO support boolean ops? Really doubt this would ever be useful though... */
 +                      BLI_assert(0 && "Boolean properties support no override diff operation");
 +                      break;
 +              case PROP_INT:
 +              {
 +                      int prop_min, prop_max;
 +                      RNA_property_int_range(ptr_local, prop_local, &prop_min, &prop_max);
 +
 +                      if (is_array && index == -1) {
 +                              int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
 +                              int *array_a, *array_b;
 +
 +                              array_a = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_local, __func__) : array_stack_a;
 +                              RNA_property_int_get_array(ptr_reference, prop_reference, array_a);
 +
 +                              switch (opop->operation) {
 +                                      case IDOVERRIDESTATIC_OP_ADD:
 +                                      case IDOVERRIDESTATIC_OP_SUBTRACT:
 +                                      {
 +                                              const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1;
 +                                              const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
 +                                              bool do_set = true;
 +                                              array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
 +                                              RNA_property_int_get_array(ptr_local, prop_local, array_b);
 +                                              for (int i = len_local; i--;) {
 +                                                      array_b[i] = fac * (array_b[i] - array_a[i]);
 +                                                      if (array_b[i] < prop_min || array_b[i] > prop_max) {
 +                                                              opop->operation = other_op;
 +                                                              for (int j = len_local; j--;) {
 +                                                                      array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]);
 +                                                                      if (array_b[j] < prop_min || array_b[j] > prop_max) {
 +                                                                              /* We failed to  find a suitable diff op,
 +                                                                               * fall back to plain REPLACE one. */
 +                                                                              opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
 +                                                                              do_set = false;
 +                                                                              break;
 +                                                                      }
 +                                                              }
 +                                                              break;
 +                                                      }
 +                                              }
 +                                              if (do_set) {
 +                                                      changed = true;
 +                                                      RNA_property_int_set_array(ptr_storage, prop_storage, array_b);
 +                                              }
 +                                              if (array_b != array_stack_b) MEM_freeN(array_b);
 +                                              break;
 +                                      }
 +                                      default:
 +                                              BLI_assert(0 && "Unsupported RNA override diff operation on integer");
 +                                              break;
 +                              }
 +
 +                              if (array_a != array_stack_a) MEM_freeN(array_a);
 +                      }
 +                      else {
 +                              const int value = RNA_PROPERTY_GET_SINGLE(int, ptr_reference, prop_reference, index);
 +
 +                              switch (opop->operation) {
 +                                      case IDOVERRIDESTATIC_OP_ADD:
 +                                      case IDOVERRIDESTATIC_OP_SUBTRACT:
 +                                      {
 +                                              const int fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1 : -1;
 +                                              const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
 +                                              int b = fac * (RNA_PROPERTY_GET_SINGLE(int, ptr_local, prop_local, index) - value);
 +                                              if (b < prop_min || b > prop_max) {
 +                                                      opop->operation = other_op;
 +                                                      b = -b;
 +                                                      if (b < prop_min || b > prop_max) {
 +                                                              opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
 +                                                              break;
 +                                                      }
 +                                              }
 +                                              changed = true;
 +                                              RNA_PROPERTY_SET_SINGLE(int, ptr_storage, prop_storage, index, b);
 +                                              break;
 +                                      }
 +                                      default:
 +                                              BLI_assert(0 && "Unsupported RNA override diff operation on integer");
 +                                              break;
 +                              }
 +                      }
 +                      break;
 +              }
 +              case PROP_FLOAT:
 +              {
 +                      float prop_min, prop_max;
 +                      RNA_property_float_range(ptr_local, prop_local, &prop_min, &prop_max);
 +
 +                      if (is_array && index == -1) {
 +                              float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
 +                              float *array_a, *array_b;
 +
 +                              array_a = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_local, __func__) : array_stack_a;
 +
 +                              RNA_property_float_get_array(ptr_reference, prop_reference, array_a);
 +                              switch (opop->operation) {
 +                                      case IDOVERRIDESTATIC_OP_ADD:
 +                                      case IDOVERRIDESTATIC_OP_SUBTRACT:
 +                                      {
 +                                              const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0 : -1.0;
 +                                              const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
 +                                              bool do_set = true;
 +                                              array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
 +                                              RNA_property_float_get_array(ptr_local, prop_local, array_b);
 +                                              for (int i = len_local; i--;) {
 +                                                      array_b[i] = fac * (array_b[i] - array_a[i]);
 +                                                      if (array_b[i] < prop_min || array_b[i] > prop_max) {
 +                                                              opop->operation = other_op;
 +                                                              for (int j = len_local; j--;) {
 +                                                                      array_b[j] = j >= i ? -array_b[j] : fac * (array_a[j] - array_b[j]);
 +                                                                      if (array_b[j] < prop_min || array_b[j] > prop_max) {
 +                                                                              /* We failed to  find a suitable diff op,
 +                                                                               * fall back to plain REPLACE one. */
 +                                                                              opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
 +                                                                              do_set = false;
 +                                                                              break;
 +                                                                      }
 +                                                              }
 +                                                              break;
 +                                                      }
 +                                              }
 +                                              if (do_set) {
 +                                                      changed = true;
 +                                                      RNA_property_float_set_array(ptr_storage, prop_storage, array_b);
 +                                              }
 +                                              if (array_b != array_stack_b) MEM_freeN(array_b);
 +                                              break;
 +                                      }
 +                                      case IDOVERRIDESTATIC_OP_MULTIPLY:
 +                                      {
 +                                              bool do_set = true;
 +                                              array_b = (len_local > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_local, __func__) : array_stack_b;
 +                                              RNA_property_float_get_array(ptr_local, prop_local, array_b);
 +                                              for (int i = len_local; i--;) {
 +                                                      array_b[i] = array_a[i] == 0.0f ? array_b[i] : array_b[i] / array_a[i];
 +                                                      if (array_b[i] < prop_min || array_b[i] > prop_max) {
 +                                                              opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
 +                                                              do_set = false;
 +                                                              break;
 +                                                      }
 +                                              }
 +                                              if (do_set) {
 +                                                      changed = true;
 +                                                      RNA_property_float_set_array(ptr_storage, prop_storage, array_b);
 +                                              }
 +                                              if (array_b != array_stack_b) MEM_freeN(array_b);
 +                                              break;
 +                                      }
 +                                      default:
 +                                              BLI_assert(0 && "Unsupported RNA override diff operation on float");
 +                                              break;
 +                              }
 +
 +                              if (array_a != array_stack_a) MEM_freeN(array_a);
 +                      }
 +                      else {
 +                              const float value = RNA_PROPERTY_GET_SINGLE(float, ptr_reference, prop_reference, index);
 +
 +                              switch (opop->operation) {
 +                                      case IDOVERRIDESTATIC_OP_ADD:
 +                                      case IDOVERRIDESTATIC_OP_SUBTRACT:
 +                                      {
 +                                              const float fac = opop->operation == IDOVERRIDESTATIC_OP_ADD ? 1.0f : -1.0f;
 +                                              const int other_op = opop->operation == IDOVERRIDESTATIC_OP_ADD ? IDOVERRIDESTATIC_OP_SUBTRACT : IDOVERRIDESTATIC_OP_ADD;
 +                                              float b = fac * (RNA_PROPERTY_GET_SINGLE(float, ptr_local, prop_local, index) - value);
 +                                              if (b < prop_min || b > prop_max) {
 +                                                      opop->operation = other_op;
 +                                                      b = -b;
 +                                                      if (b < prop_min || b > prop_max) {
 +                                                              opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
 +                                                              break;
 +                                                      }
 +                                              }
 +                                              changed = true;
 +                                              RNA_PROPERTY_SET_SINGLE(float, ptr_storage, prop_storage, index, b);
 +                                              break;
 +                                      }
 +                                      case IDOVERRIDESTATIC_OP_MULTIPLY:
 +                                      {
 +                                              const float b = RNA_property_float_get_index(ptr_local, prop_local, index) / (value == 0.0f ?  1.0f : value);
 +                                              if (b < prop_min || b > prop_max) {
 +                                                      opop->operation = IDOVERRIDESTATIC_OP_REPLACE;
 +                                                      break;
 +                                              }
 +                                              changed = true;
 +                                              RNA_property_float_set_index(ptr_storage, prop_storage, index, b);
 +                                              break;
 +                                      }
 +                                      default:
 +                                              BLI_assert(0 && "Unsupported RNA override diff operation on float");
 +                                              break;
 +                              }
 +                      }
 +                      return true;
 +              }
 +              case PROP_ENUM:
 +                      /* TODO support add/sub, for bitflags? */
 +                      BLI_assert(0 && "Enum properties support no override diff operation");
 +                      break;
 +              case PROP_POINTER:
 +                      BLI_assert(0 && "Pointer properties support no override diff operation");
 +                      break;
 +              case PROP_STRING:
 +                      BLI_assert(0 && "String properties support no override diff operation");
 +                      break;
 +              case PROP_COLLECTION:
 +                      /* XXX TODO support this of course... */
 +                      BLI_assert(0 && "Collection properties support no override diff operation");
 +                      break;
 +              default:
 +                      break;
 +      }
 +
 +      return changed;
 +}
 +
 +bool rna_property_override_apply_default(
 +        Main *UNUSED(bmain),
 +        PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage,
 +        PropertyRNA *prop_dst, PropertyRNA *prop_src, PropertyRNA *prop_storage,
 +        const int len_dst, const int len_src, const int len_storage,
 +        PointerRNA *UNUSED(ptr_item_dst), PointerRNA *UNUSED(ptr_item_src), PointerRNA *UNUSED(ptr_item_storage),
 +        IDOverrideStaticPropertyOperation *opop)
 +{
 +      BLI_assert(len_dst == len_src && (!ptr_storage || len_dst == len_storage));
 +      UNUSED_VARS_NDEBUG(len_src, len_storage);
 +
 +      const bool is_array = len_dst > 0;
 +      const int index = is_array ? opop->subitem_reference_index : 0;
 +      const short override_op = opop->operation;
 +
 +      switch (RNA_property_type(prop_dst)) {
 +              case PROP_BOOLEAN:
 +                      if (is_array && index == -1) {
-                               const int value = RNA_PROPERTY_GET_SINGLE(boolean, ptr_src, prop_src, index);
++                              bool array_stack_a[RNA_STACK_ARRAY];
++                              bool *array_a;
 +
 +                              array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
 +
 +                              RNA_property_boolean_get_array(ptr_src, prop_src, array_a);
 +
 +                              switch (override_op) {
 +                                      case IDOVERRIDESTATIC_OP_REPLACE:
 +                                              RNA_property_boolean_set_array(ptr_dst, prop_dst, array_a);
 +                                              break;
 +                                      default:
 +                                              BLI_assert(0 && "Unsupported RNA override operation on boolean");
 +                                              return false;
 +                              }
 +
 +                              if (array_a != array_stack_a) MEM_freeN(array_a);
 +                      }
 +                      else {
++                              const bool value = RNA_PROPERTY_GET_SINGLE(boolean, ptr_src, prop_src, index);
 +
 +                              switch (override_op) {
 +                                      case IDOVERRIDESTATIC_OP_REPLACE:
 +                                              RNA_PROPERTY_SET_SINGLE(boolean, ptr_dst, prop_dst, index, value);
 +                                              break;
 +                                      default:
 +                                              BLI_assert(0 && "Unsupported RNA override operation on boolean");
 +                                              return false;
 +                              }
 +                      }
 +                      return true;
 +              case PROP_INT:
 +                      if (is_array && index == -1) {
 +                              int array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
 +                              int *array_a, *array_b;
 +
 +                              array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
 +
 +                              switch (override_op) {
 +                                      case IDOVERRIDESTATIC_OP_REPLACE:
 +                                              RNA_property_int_get_array(ptr_src, prop_src, array_a);
 +                                              RNA_property_int_set_array(ptr_dst, prop_dst, array_a);
 +                                              break;
 +                                      case IDOVERRIDESTATIC_OP_ADD:
 +                                      case IDOVERRIDESTATIC_OP_SUBTRACT:
 +                                              RNA_property_int_get_array(ptr_dst, prop_dst, array_a);
 +                                              array_b = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_dst, __func__) : array_stack_b;
 +                                              RNA_property_int_get_array(ptr_storage, prop_storage, array_b);
 +                                              if (override_op == IDOVERRIDESTATIC_OP_ADD) {
 +                                                      for (int i = len_dst; i--;) array_a[i] += array_b[i];
 +                                              }
 +                                              else {
 +                                                      for (int i = len_dst; i--;) array_a[i] -= array_b[i];
 +                                              }
 +                                              RNA_property_int_set_array(ptr_dst, prop_dst, array_a);
 +                                              if (array_b != array_stack_b) MEM_freeN(array_b);
 +                                              break;
 +                                      default:
 +                                              BLI_assert(0 && "Unsupported RNA override operation on integer");
 +                                              return false;
 +                              }
 +
 +                              if (array_a != array_stack_a) MEM_freeN(array_a);
 +                      }
 +                      else {
 +                              const int storage_value = ptr_storage ? RNA_PROPERTY_GET_SINGLE(int, ptr_storage, prop_storage, index) : 0;
 +
 +                              switch (override_op) {
 +                                      case IDOVERRIDESTATIC_OP_REPLACE:
 +                                              RNA_PROPERTY_SET_SINGLE(int, ptr_dst, prop_dst, index,
 +                                                                      RNA_PROPERTY_GET_SINGLE(int, ptr_src, prop_src, index));
 +                                              break;
 +                                      case IDOVERRIDESTATIC_OP_ADD:
 +                                              RNA_PROPERTY_SET_SINGLE(int, ptr_dst, prop_dst, index,
 +                                                                      RNA_PROPERTY_GET_SINGLE(int, ptr_dst, prop_dst, index) - storage_value);
 +                                              break;
 +                                      case IDOVERRIDESTATIC_OP_SUBTRACT:
 +                                              RNA_PROPERTY_SET_SINGLE(int, ptr_dst, prop_dst, index,
 +                                                                      RNA_PROPERTY_GET_SINGLE(int, ptr_dst, prop_dst, index) - storage_value);
 +                                              break;
 +                                      default:
 +                                              BLI_assert(0 && "Unsupported RNA override operation on integer");
 +                                              return false;
 +                              }
 +                      }
 +                      return true;
 +              case PROP_FLOAT:
 +                      if (is_array && index == -1) {
 +                              float array_stack_a[RNA_STACK_ARRAY], array_stack_b[RNA_STACK_ARRAY];
 +                              float *array_a, *array_b;
 +
 +                              array_a = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_a) * len_dst, __func__) : array_stack_a;
 +
 +                              switch (override_op) {
 +                                      case IDOVERRIDESTATIC_OP_REPLACE:
 +                                              RNA_property_float_get_array(ptr_src, prop_src, array_a);
 +                                              RNA_property_float_set_array(ptr_dst, prop_dst, array_a);
 +                                              break;
 +                                      case IDOVERRIDESTATIC_OP_ADD:
 +                                      case IDOVERRIDESTATIC_OP_SUBTRACT:
 +                                      case IDOVERRIDESTATIC_OP_MULTIPLY:
 +                                              RNA_property_float_get_array(ptr_dst, prop_dst, array_a);
 +                                              array_b = (len_dst > RNA_STACK_ARRAY) ? MEM_mallocN(sizeof(*array_b) * len_dst, __func__) : array_stack_b;
 +                                              RNA_property_float_get_array(ptr_storage, prop_storage, array_b);
 +                                              if (override_op == IDOVERRIDESTATIC_OP_ADD) {
 +                                                      for (int i = len_dst; i--;) array_a[i] += array_b[i];
 +                                              }
 +                                              else if (override_op == IDOVERRIDESTATIC_OP_SUBTRACT) {
 +                                                      for (int i = len_dst; i--;) array_a[i] -= array_b[i];
 +                                              }
 +                                              else {
 +                                                      for (int i = len_dst; i--;) array_a[i] *= array_b[i];
 +                                              }
 +                                              RNA_property_float_set_array(ptr_dst, prop_dst, array_a);
 +                                              if (array_b != array_stack_b) MEM_freeN(array_b);
 +                                              break;
 +                                      default:
 +                                              BLI_assert(0 && "Unsupported RNA override operation on float");
 +                                              return false;
 +                              }
 +
 +                              if (array_a != array_stack_a) MEM_freeN(array_a);
 +                      }
 +                      else {
 +                              const float storage_value = ptr_storage ? RNA_PROPERTY_GET_SINGLE(float, ptr_storage, prop_storage, index) : 0.0f;
 +
 +                              switch (override_op) {
 +                                      case IDOVERRIDESTATIC_OP_REPLACE:
 +                                              RNA_PROPERTY_SET_SINGLE(float, ptr_dst, prop_dst, index,
 +                                                                      RNA_PROPERTY_GET_SINGLE(float, ptr_src, prop_src, index));
 +                                              break;
 +                                      case IDOVERRIDESTATIC_OP_ADD:
 +                                              RNA_PROPERTY_SET_SINGLE(float, ptr_dst, prop_dst, index,
 +                                                                      RNA_PROPERTY_GET_SINGLE(float, ptr_dst, prop_dst, index) + storage_value);
 +                                              break;
 +                                      case IDOVERRIDESTATIC_OP_SUBTRACT:
 +                                              RNA_PROPERTY_SET_SINGLE(float, ptr_dst, prop_dst, index,
 +                                                                      RNA_PROPERTY_GET_SINGLE(float, ptr_dst, prop_dst, index) - storage_value);
 +                                              break;
 +                                      case IDOVERRIDESTATIC_OP_MULTIPLY:
 +                                              RNA_PROPERTY_SET_SINGLE(float, ptr_dst, prop_dst, index,
 +                                                                      RNA_PROPERTY_GET_SINGLE(float, ptr_dst, prop_dst, index) * storage_value);
 +                                              break;
 +                                      default:
 +                                              BLI_assert(0 && "Unsupported RNA override operation on float");
 +                                              return false;
 +                              }
 +                      }
 +                      return true;
 +              case PROP_ENUM:
 +              {
 +                      const int value = RNA_property_enum_get(ptr_src, prop_src);
 +
 +                      switch (override_op) {
 +                              case IDOVERRIDESTATIC_OP_REPLACE:
 +                                      RNA_property_enum_set(ptr_dst, prop_dst, value);
 +                                      break;
 +                              /* TODO support add/sub, for bitflags? */
 +                              default:
 +                                      BLI_assert(0 && "Unsupported RNA override operation on enum");
 +                                      return false;
 +                      }
 +                      return true;
 +              }
 +              case PROP_POINTER:
 +              {
 +                      PointerRNA value = RNA_property_pointer_get(ptr_src, prop_src);
 +
 +                      switch (override_op) {
 +                              case IDOVERRIDESTATIC_OP_REPLACE:
 +                                      RNA_property_pointer_set(ptr_dst, prop_dst, value);
 +                                      break;
 +                              default:
 +                                      BLI_assert(0 && "Unsupported RNA override operation on pointer");
 +                                      return false;
 +                      }
 +                      return true;
 +              }
 +              case PROP_STRING:
 +              {
 +                      char buff[256];
 +                      char *value = RNA_property_string_get_alloc(ptr_src, prop_src, buff, sizeof(buff), NULL);
 +
 +                      switch (override_op) {
 +                              case IDOVERRIDESTATIC_OP_REPLACE:
 +                                      RNA_property_string_set(ptr_dst, prop_dst, value);
 +                                      break;
 +                              default:
 +                                      BLI_assert(0 && "Unsupported RNA override operation on string");
 +                                      return false;
 +                      }
 +
 +                      if (value != buff) MEM_freeN(value);
 +                      return true;
 +              }
 +              case PROP_COLLECTION:
 +              {
 +                      BLI_assert(!"You need to define a specific override apply callback for enums.");
 +                      return false;
 +              }
 +              default:
 +                      BLI_assert(0);
 +                      return false;
 +      }
 +
 +      return false;
 +}
 +
 +#undef RNA_PROPERTY_GET_SINGLE
 +#undef RNA_PROPERTY_SET_SINGLE
 +
  
  #else
  
@@@ -711,21 -728,7 +711,21 @@@ static void rna_Scene_set_set(PointerRN
        scene->set = set;
  }
  
- static void rna_Scene_layer_set(PointerRNA *ptr, const int *values)
 +void rna_Scene_set_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
 +{
 +      Scene *scene = (Scene *)ptr->id.data;
 +
 +      DEG_relations_tag_update(bmain);
 +      DEG_id_tag_update_ex(bmain, &scene->id, 0);
 +      if (scene->set != NULL) {
 +              /* Objects which are pulled into main scene's depsgraph needs to have
 +               * their base flags updated.
 +               */
 +              DEG_id_tag_update_ex(bmain, &scene->set->id, 0);
 +      }
 +}
 +
+ static void rna_Scene_layer_set(PointerRNA *ptr, const bool *values)
  {
        Scene *scene = (Scene *)ptr->data;
  
@@@ -1539,17 -1673,15 +1539,17 @@@ static void rna_Scene_use_nodes_update(
  static void rna_Physics_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
  {
        Scene *scene = (Scene *)ptr->id.data;
 -      Base *base;
 +      FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
 +      {
 +              BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH);
 +      }
 +      FOREACH_SCENE_OBJECT_END;
  
 -      for (base = scene->base.first; base; base = base->next)
 -              BKE_ptcache_object_reset(scene, base->object, PTCACHE_RESET_DEPSGRAPH);
 +      DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE);
  }
  
- static void rna_Scene_editmesh_select_mode_set(PointerRNA *ptr, const int *value)
+ static void rna_Scene_editmesh_select_mode_set(PointerRNA *ptr, const bool *value)
  {
 -      Scene *scene = (Scene *)ptr->id.data;
        ToolSettings *ts = (ToolSettings *)ptr->data;
        int flag = (value[0] ? SCE_SELECT_VERTEX : 0) | (value[1] ? SCE_SELECT_EDGE : 0) | (value[2] ? SCE_SELECT_FACE : 0);
  
@@@ -164,9 -154,9 +164,9 @@@ static void rna_SceneRender_get_frame_p
  }
  
  static void rna_Scene_ray_cast(
 -        Scene *scene, Main *bmain,
 +        Scene *scene, Main *bmain, ViewLayer *view_layer,
          float origin[3], float direction[3], float ray_dist,
-         int *r_success, float r_location[3], float r_normal[3], int *r_index,
+         bool *r_success, float r_location[3], float r_normal[3], int *r_index,
          Object **r_ob, float r_obmat[16])
  {
        normalize_v3(direction);
@@@ -275,32 -275,9 +275,32 @@@ static void rna_uiItemM
        uiItemM(layout, menuname, name, icon);
  }
  
-         int translate, int icon, int icon_value)
 +static void rna_uiItemPopoverPanel(
 +        uiLayout *layout, bContext *C,
 +        int space_type, int region_type, const char *panel_type,
 +        const char *name, const char *text_ctxt,
++        bool translate, int icon, int icon_value)
 +{
 +      /* Get translated name (label). */
 +      name = rna_translate_ui_text(name, text_ctxt, NULL, NULL, translate);
 +
 +      if (icon_value && !icon) {
 +              icon = icon_value;
 +      }
 +
 +      uiItemPopoverPanel(layout, C, space_type, region_type, panel_type, name, icon);
 +}
 +
 +static void rna_uiItemPopoverPanelFromGroup(
 +        uiLayout *layout, bContext *C,
 +        int space_id, int region_id, const char *context, const char *category)
 +{
 +      uiItemPopoverPanelFromGroup(layout, C, space_id, region_id, context, category);
 +}
 +
  static void rna_uiTemplateAnyID(
          uiLayout *layout, PointerRNA *ptr, const char *propname, const char *proptypename,
-         const char *name, const char *text_ctxt, int translate)
+         const char *name, const char *text_ctxt, bool translate)
  {
        PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
  
index c948f84,0000000..1680404
mode 100644,000000..100644
--- /dev/null
@@@ -1,290 -1,0 +1,290 @@@
- static int rna_manipulator_target_is_valid(
 +/*
 + * ***** 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/makesrna/intern/rna_wm_manipulator_api.c
 + *  \ingroup RNA
 + */
 +
 +
 +#include <stdlib.h>
 +#include <stdio.h>
 +
 +#include "BLI_utildefines.h"
 +
 +#include "BKE_report.h"
 +
 +#include "RNA_define.h"
 +#include "RNA_enum_types.h"
 +
 +#include "DNA_windowmanager_types.h"
 +
 +#include "WM_api.h"
 +
 +#include "rna_internal.h"  /* own include */
 +
 +#ifdef RNA_RUNTIME
 +
 +#include "UI_interface.h"
 +#include "BKE_context.h"
 +
 +#include "ED_manipulator_library.h"
 +
 +static void rna_manipulator_draw_preset_box(
 +        wmManipulator *mpr, float matrix[16], int select_id)
 +{
 +      ED_manipulator_draw_preset_box(mpr, (float (*)[4])matrix, select_id);
 +}
 +
 +static void rna_manipulator_draw_preset_arrow(
 +        wmManipulator *mpr, float matrix[16], int axis, int select_id)
 +{
 +      ED_manipulator_draw_preset_arrow(mpr, (float (*)[4])matrix, axis, select_id);
 +}
 +
 +static void rna_manipulator_draw_preset_circle(
 +        wmManipulator *mpr, float matrix[16], int axis, int select_id)
 +{
 +      ED_manipulator_draw_preset_circle(mpr, (float (*)[4])matrix, axis, select_id);
 +}
 +
 +static void rna_manipulator_draw_preset_facemap(
 +        wmManipulator *mpr, struct bContext *C, struct Object *ob, int facemap, int select_id)
 +{
 +      struct Scene *scene = CTX_data_scene(C);
 +      ED_manipulator_draw_preset_facemap(C, mpr, scene, ob, facemap, select_id);
 +}
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Manipulator Property Define
 + * \{ */
 +
 +static void rna_manipulator_target_set_prop(
 +        wmManipulator *mpr, ReportList *reports, const char *target_propname,
 +        PointerRNA *ptr, const char *propname, int index)
 +{
 +      const wmManipulatorPropertyType *mpr_prop_type =
 +              WM_manipulatortype_target_property_find(mpr->type, target_propname);
 +      if (mpr_prop_type == NULL) {
 +              BKE_reportf(reports, RPT_ERROR, "Manipulator target property '%s.%s' not found",
 +                          mpr->type->idname, target_propname);
 +              return;
 +      }
 +
 +      PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
 +      if (prop == NULL) {
 +              BKE_reportf(reports, RPT_ERROR, "Property '%s.%s' not found",
 +                          RNA_struct_identifier(ptr->type), target_propname);
 +              return;
 +      }
 +
 +      if (mpr_prop_type->data_type != RNA_property_type(prop)) {
 +              const int manipulator_type_index = RNA_enum_from_value(rna_enum_property_type_items, mpr_prop_type->data_type);
 +              const int prop_type_index = RNA_enum_from_value(rna_enum_property_type_items, RNA_property_type(prop));
 +              BLI_assert((manipulator_type_index != -1) && (prop_type_index == -1));
 +
 +              BKE_reportf(reports, RPT_ERROR, "Manipulator target '%s.%s' expects '%s', '%s.%s' is '%s'",
 +                          mpr->type->idname, target_propname,
 +                          rna_enum_property_type_items[manipulator_type_index].identifier,
 +                          RNA_struct_identifier(ptr->type), propname,
 +                          rna_enum_property_type_items[prop_type_index].identifier);
 +              return;
 +      }
 +
 +      if (RNA_property_array_check(prop)) {
 +              if (index == -1) {
 +                      const int prop_array_length = RNA_property_array_length(ptr, prop);
 +                      if (mpr_prop_type->array_length != prop_array_length) {
 +                              BKE_reportf(reports, RPT_ERROR,
 +                                          "Manipulator target property '%s.%s' expects an array of length %d, found %d",
 +                                          mpr->type->idname, target_propname,
 +                                          mpr_prop_type->array_length,
 +                                          prop_array_length);
 +                              return;
 +                      }
 +              }
 +      }
 +      else {
 +              if (mpr_prop_type->array_length != 1) {
 +                      BKE_reportf(reports, RPT_ERROR,
 +                                  "Manipulator target property '%s.%s' expects an array of length %d",
 +                                  mpr->type->idname, target_propname,
 +                                  mpr_prop_type->array_length);
 +                      return;
 +              }
 +      }
 +
 +      if (index >= mpr_prop_type->array_length) {
 +              BKE_reportf(reports, RPT_ERROR, "Manipulator target property '%s.%s', index %d must be below %d",
 +                          mpr->type->idname, target_propname, index, mpr_prop_type->array_length);
 +              return;
 +      }
 +
 +      WM_manipulator_target_property_def_rna_ptr(mpr, mpr_prop_type, ptr, prop, index);
 +}
 +
 +static PointerRNA rna_manipulator_target_set_operator(
 +        wmManipulator *mpr, ReportList *reports, const char *opname, int part_index)
 +{
 +      wmOperatorType *ot;
 +
 +      ot = WM_operatortype_find(opname, 0); /* print error next */
 +      if (!ot || !ot->srna) {
 +              BKE_reportf(reports, RPT_ERROR, "%s '%s'", ot ? "unknown operator" : "operator missing srna", opname);
 +              return PointerRNA_NULL;
 +      }
 +
 +      /* For the return value to be usable, we need 'PointerRNA.data' to be set. */
 +      IDProperty *properties;
 +      {
 +              IDPropertyTemplate val = {0};
 +              properties = IDP_New(IDP_GROUP, &val, "wmManipulatorProperties");
 +      }
 +
 +      return *WM_manipulator_operator_set(mpr, part_index, ot, properties);
 +}
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Manipulator Property Access
 + * \{ */
 +
++static bool rna_manipulator_target_is_valid(
 +        wmManipulator *mpr, ReportList *reports, const char *target_propname)
 +{
 +      wmManipulatorProperty *mpr_prop =
 +              WM_manipulator_target_property_find(mpr, target_propname);
 +      if (mpr_prop == NULL) {
 +              BKE_reportf(reports, RPT_ERROR, "Manipulator target property '%s.%s' not found",
 +                          mpr->type->idname, target_propname);
 +              return false;
 +      }
 +      return WM_manipulator_target_property_is_valid(mpr_prop);
 +}
 +
 +/** \} */
 +
 +#else
 +
 +void RNA_api_manipulator(StructRNA *srna)
 +{
 +      /* Utility draw functions, since we don't expose new OpenGL drawing wrappers via Python yet.
 +       * exactly how these should be exposed isn't totally clear.
 +       * However it's probably good to have some high level API's for this anyway.
 +       * Just note that this could be re-worked once tests are done.
 +       */
 +
 +      FunctionRNA *func;
 +      PropertyRNA *parm;
 +
 +      /* -------------------------------------------------------------------- */
 +      /* Primitive Shapes */
 +
 +      /* draw_preset_box */
 +      func = RNA_def_function(srna, "draw_preset_box", "rna_manipulator_draw_preset_box");
 +      RNA_def_function_ui_description(func, "Draw a box");
 +      parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
 +      RNA_def_property_ui_text(parm, "", "The matrix to transform");
 +      RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
 +
 +      /* draw_preset_box */
 +      func = RNA_def_function(srna, "draw_preset_arrow", "rna_manipulator_draw_preset_arrow");
 +      RNA_def_function_ui_description(func, "Draw a box");
 +      parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
 +      RNA_def_property_ui_text(parm, "", "The matrix to transform");
 +      RNA_def_enum(func, "axis", rna_enum_object_axis_items, 2, "", "Arrow Orientation");
 +      RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
 +
 +      func = RNA_def_function(srna, "draw_preset_circle", "rna_manipulator_draw_preset_circle");
 +      RNA_def_function_ui_description(func, "Draw a box");
 +      parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX);
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
 +      RNA_def_property_ui_text(parm, "", "The matrix to transform");
 +      RNA_def_enum(func, "axis", rna_enum_object_axis_items, 2, "", "Arrow Orientation");
 +      RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
 +
 +      /* -------------------------------------------------------------------- */
 +      /* Other Shapes */
 +
 +      /* draw_preset_facemap */
 +      func = RNA_def_function(srna, "draw_preset_facemap", "rna_manipulator_draw_preset_facemap");
 +      RNA_def_function_ui_description(func, "Draw the face-map of a mesh object");
 +      RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 +      parm = RNA_def_pointer(func, "object", "Object", "", "Object");
 +      RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
 +      RNA_def_int(func, "facemap", 0, 0, INT_MAX, "Face map index", "", 0, INT_MAX);
 +      RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
 +
 +
 +      /* -------------------------------------------------------------------- */
 +      /* Property API */
 +
 +      /* Define Properties */
 +      /* note, 'target_set_handler' is defined in 'bpy_rna_manipulator.c' */
 +      func = RNA_def_function(srna, "target_set_prop", "rna_manipulator_target_set_prop");
 +      RNA_def_function_flag(func, FUNC_USE_REPORTS);
 +      RNA_def_function_ui_description(func, "");
 +      parm = RNA_def_string(func, "target", NULL, 0, "", "Target property");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      /* similar to UILayout.prop */
 +      parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
 +      RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
 +      parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      RNA_def_int(func, "index", -1, -1, INT_MAX, "", "", -1, INT_MAX); /* RNA_NO_INDEX == -1 */
 +
 +      func = RNA_def_function(srna, "target_set_operator", "rna_manipulator_target_set_operator");
 +      RNA_def_function_flag(func, FUNC_USE_REPORTS);
 +      RNA_def_function_ui_description(
 +              func, "Operator to run when activating the manipulator "
 +              "(overrides property targets)");
 +      parm = RNA_def_string(func, "operator", NULL, 0, "", "Target operator");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      RNA_def_int(func, "index", 0, 0, 255, "Part index", "", 0, 255);
 +
 +      /* similar to UILayout.operator */
 +      parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "Operator properties to fill in");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
 +      RNA_def_function_return(func, parm);
 +
 +      /* Access Properties */
 +      /* note, 'target_get', 'target_set' is defined in 'bpy_rna_manipulator.c' */
 +      func = RNA_def_function(srna, "target_is_valid", "rna_manipulator_target_is_valid");
 +      RNA_def_function_flag(func, FUNC_USE_REPORTS);
 +      parm = RNA_def_string(func, "property", NULL, 0, "", "Property identifier");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      RNA_def_function_ui_description(func, "");
 +      parm = RNA_def_boolean(func, "result", 0, "", "");
 +      RNA_def_function_return(func, parm);
 +
 +}
 +
 +
 +void RNA_api_manipulatorgroup(StructRNA *UNUSED(srna))
 +{
 +      /* nothing yet */
 +}
 +
 +#endif
index 041b2b9,0000000..166d716
mode 100644,000000..100644
--- /dev/null
@@@ -1,329 -1,0 +1,329 @@@
-         WorkSpace *workspace, int mode, int create)
 +/*
 + * ***** 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/makesrna/intern/rna_workspace.c
 + *  \ingroup RNA
 + */
 +
 +#include "RNA_define.h"
 +#include "RNA_enum_types.h"
 +#include "RNA_types.h"
 +
 +#include "BKE_workspace.h"
 +
 +#include "ED_render.h"
 +
 +#include "RE_engine.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +
 +#include "rna_internal.h"
 +
 +/* Allow accessing private members of DNA_workspace_types.h */
 +#define DNA_PRIVATE_WORKSPACE_ALLOW
 +#include "DNA_workspace_types.h"
 +
 +#ifdef RNA_RUNTIME
 +
 +#include "BLI_listbase.h"
 +
 +#include "BKE_global.h"
 +
 +#include "DNA_object_types.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_space_types.h"
 +
 +#include "RNA_access.h"
 +
 +#include "WM_toolsystem.h"
 +
 +static void rna_window_update_all(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
 +{
 +      WM_main_add_notifier(NC_WINDOW, NULL);
 +}
 +
 +void rna_workspace_screens_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
 +{
 +      WorkSpace *workspace = ptr->id.data;
 +      rna_iterator_listbase_begin(iter, BKE_workspace_layouts_get(workspace), NULL);
 +}
 +
 +static PointerRNA rna_workspace_screens_item_get(CollectionPropertyIterator *iter)
 +{
 +      WorkSpaceLayout *layout = rna_iterator_listbase_get(iter);
 +      bScreen *screen = BKE_workspace_layout_screen_get(layout);
 +
 +      return rna_pointer_inherit_refine(&iter->parent, &RNA_Screen, screen);
 +}
 +
 +/* workspace.owner_ids */
 +
 +static wmOwnerID *rna_WorkSpace_owner_ids_new(
 +        WorkSpace *workspace, const char *name)
 +{
 +      wmOwnerID *owner_id = MEM_callocN(sizeof(*owner_id), __func__);
 +      BLI_addtail(&workspace->owner_ids, owner_id);
 +      BLI_strncpy(owner_id->name, name, sizeof(owner_id->name));
 +      WM_main_add_notifier(NC_WINDOW, NULL);
 +      return owner_id;
 +}
 +
 +static void rna_WorkSpace_owner_ids_remove(
 +        WorkSpace *workspace, ReportList *reports, PointerRNA *wstag_ptr)
 +{
 +      wmOwnerID *owner_id = wstag_ptr->data;
 +      if (BLI_remlink_safe(&workspace->owner_ids, owner_id) == false) {
 +              BKE_reportf(reports, RPT_ERROR,
 +                          "wmOwnerID '%s' not in workspace '%s'",
 +                          owner_id->name, workspace->id.name + 2);
 +              return;
 +      }
 +
 +      MEM_freeN(owner_id);
 +      RNA_POINTER_INVALIDATE(wstag_ptr);
 +
 +      WM_main_add_notifier(NC_WINDOW, NULL);
 +}
 +
 +static void rna_WorkSpace_owner_ids_clear(
 +        WorkSpace *workspace)
 +{
 +      BLI_freelistN(&workspace->owner_ids);
 +      WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, workspace);
 +}
 +
 +static bToolRef *rna_WorkSpace_tools_from_tkey(WorkSpace *workspace, const bToolKey *tkey, bool create)
 +{
 +      if (create) {
 +              bToolRef *tref;
 +              WM_toolsystem_ref_ensure(workspace, tkey, &tref);
 +              return tref;
 +      }
 +      return WM_toolsystem_ref_find(workspace, tkey);
 +}
 +
 +static bToolRef *rna_WorkSpace_tools_from_space_view3d_mode(
-         WorkSpace *workspace, int mode, int create)
++        WorkSpace *workspace, int mode, bool create)
 +{
 +      return rna_WorkSpace_tools_from_tkey(workspace, &(bToolKey){ .space_type = SPACE_VIEW3D, .mode = mode}, create);
 +}
 +
 +static bToolRef *rna_WorkSpace_tools_from_space_image_mode(
++        WorkSpace *workspace, int mode, bool create)
 +{
 +      return rna_WorkSpace_tools_from_tkey(workspace, &(bToolKey){ .space_type = SPACE_IMAGE, .mode = mode}, create);
 +}
 +
 +const EnumPropertyItem *rna_WorkSpace_tools_mode_itemf(
 +        bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
 +{
 +      WorkSpace *workspace = ptr->id.data;
 +
 +      switch (workspace->tools_space_type) {
 +              case SPACE_VIEW3D:
 +                      return rna_enum_context_mode_items;
 +              case SPACE_IMAGE:
 +                      return rna_enum_space_image_mode_items;
 +      }
 +      return DummyRNA_DEFAULT_items;
 +}
 +
 +static int rna_WorkspaceTool_index_get(PointerRNA *ptr)
 +{
 +      bToolRef *tref = ptr->data;
 +      return (tref->runtime) ? tref->runtime->index : 0;
 +}
 +
 +#else /* RNA_RUNTIME */
 +
 +static void rna_def_workspace_owner(BlenderRNA *brna)
 +{
 +      StructRNA *srna;
 +      PropertyRNA *prop;
 +
 +      srna = RNA_def_struct(brna, "wmOwnerID", NULL);
 +      RNA_def_struct_sdna(srna, "wmOwnerID");
 +      RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
 +      RNA_def_struct_ui_text(srna, "Work Space UI Tag", "");
 +
 +      prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
 +      RNA_def_property_ui_text(prop, "Name", "");
 +      RNA_def_struct_name_property(srna, prop);
 +}
 +
 +static void rna_def_workspace_owner_ids(BlenderRNA *brna, PropertyRNA *cprop)
 +{
 +      StructRNA *srna;
 +
 +      FunctionRNA *func;
 +      PropertyRNA *parm;
 +
 +      RNA_def_property_srna(cprop, "wmOwnerIDs");
 +      srna = RNA_def_struct(brna, "wmOwnerIDs", NULL);
 +      RNA_def_struct_sdna(srna, "WorkSpace");
 +      RNA_def_struct_ui_text(srna, "WorkSpace UI Tags", "");
 +
 +      /* add owner_id */
 +      func = RNA_def_function(srna, "new", "rna_WorkSpace_owner_ids_new");
 +      RNA_def_function_ui_description(func, "Add ui tag");
 +      parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the tag");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      /* return type */
 +      parm = RNA_def_pointer(func, "owner_id", "wmOwnerID", "", "");
 +      RNA_def_function_return(func, parm);
 +
 +      /* remove owner_id */
 +      func = RNA_def_function(srna, "remove", "rna_WorkSpace_owner_ids_remove");
 +      RNA_def_function_flag(func, FUNC_USE_REPORTS);
 +      RNA_def_function_ui_description(func, "Remove ui tag");
 +      /* owner_id to remove */
 +      parm = RNA_def_pointer(func, "owner_id", "wmOwnerID", "", "Tag to remove");
 +      RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
 +      RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
 +
 +      /* clear all modifiers */
 +      func = RNA_def_function(srna, "clear", "rna_WorkSpace_owner_ids_clear");
 +      RNA_def_function_ui_description(func, "Remove all tags");
 +}
 +
 +static void rna_def_workspace_tool(BlenderRNA *brna)
 +{
 +      StructRNA *srna;
 +      PropertyRNA *prop;
 +
 +      srna = RNA_def_struct(brna, "WorkspaceTool", NULL);
 +      RNA_def_struct_sdna(srna, "bToolRef");
 +      RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
 +      RNA_def_struct_ui_text(srna, "Work Space Tool", "");
 +
 +      prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
 +      RNA_def_property_string_sdna(prop, NULL, "idname");
 +      RNA_def_property_ui_text(prop, "Name", "");
 +      RNA_def_struct_name_property(srna, prop);
 +
 +      prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE);
 +      RNA_def_property_clear_flag(prop, PROP_EDITABLE);
 +      RNA_def_property_ui_text(prop, "Index", "");
 +      RNA_def_property_int_funcs(prop, "rna_WorkspaceTool_index_get", NULL, NULL);
 +
 +      RNA_api_workspace_tool(srna);
 +}
 +
 +static void rna_def_workspace_tools(BlenderRNA *brna, PropertyRNA *cprop)
 +{
 +      StructRNA *srna;
 +
 +      FunctionRNA *func;
 +      PropertyRNA *parm;
 +
 +      RNA_def_property_srna(cprop, "wmTools");
 +      srna = RNA_def_struct(brna, "wmTools", NULL);
 +      RNA_def_struct_sdna(srna, "WorkSpace");
 +      RNA_def_struct_ui_text(srna, "WorkSpace UI Tags", "");
 +
 +      /* add owner_id */
 +      func = RNA_def_function(srna, "from_space_view3d_mode", "rna_WorkSpace_tools_from_space_view3d_mode");
 +      RNA_def_function_ui_description(func, "");
 +      parm = RNA_def_enum(func, "mode", rna_enum_context_mode_items, 0, "", "");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      RNA_def_boolean(func, "create", false, "Create", "");
 +      /* return type */
 +      parm = RNA_def_pointer(func, "result", "WorkspaceTool", "", "");
 +      RNA_def_function_return(func, parm);
 +
 +      func = RNA_def_function(srna, "from_space_image_mode", "rna_WorkSpace_tools_from_space_image_mode");
 +      RNA_def_function_ui_description(func, "");
 +      parm = RNA_def_enum(func, "mode", rna_enum_space_image_mode_items, 0, "", "");
 +      RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
 +      RNA_def_boolean(func, "create", false, "Create", "");
 +      /* return type */
 +      parm = RNA_def_pointer(func, "result", "WorkspaceTool", "", "");
 +      RNA_def_function_return(func, parm);
 +}
 +
 +static void rna_def_workspace(BlenderRNA *brna)
 +{
 +      StructRNA *srna;
 +      PropertyRNA *prop;
 +
 +      srna = RNA_def_struct(brna, "WorkSpace", "ID");
 +      RNA_def_struct_sdna(srna, "WorkSpace");
 +      RNA_def_struct_ui_text(srna, "Workspace", "Workspace data-block, defining the working environment for the user");
 +      /* TODO: real icon, just to show something */
 +      RNA_def_struct_ui_icon(srna, ICON_SPLITSCREEN);
 +
 +      prop = RNA_def_property(srna, "screens", PROP_COLLECTION, PROP_NONE);
 +      RNA_def_property_collection_sdna(prop, NULL, "layouts", NULL);
 +      RNA_def_property_struct_type(prop, "Screen");
 +      RNA_def_property_collection_funcs(prop, "rna_workspace_screens_begin", NULL, NULL,
 +                                        "rna_workspace_screens_item_get", NULL, NULL, NULL, NULL);
 +      RNA_def_property_ui_text(prop, "Screens", "Screen layouts of a workspace");
 +
 +      prop = RNA_def_property(srna, "owner_ids", PROP_COLLECTION, PROP_NONE);
 +      RNA_def_property_struct_type(prop, "wmOwnerID");
 +      RNA_def_property_ui_text(prop, "UI Tags", "");
 +      rna_def_workspace_owner_ids(brna, prop);
 +
 +      prop = RNA_def_property(srna, "tools", PROP_COLLECTION, PROP_NONE);
 +      RNA_def_property_collection_sdna(prop, NULL, "tools", NULL);
 +      RNA_def_property_struct_type(prop, "WorkspaceTool");
 +      RNA_def_property_ui_text(prop, "Tools", "");
 +      rna_def_workspace_tools(brna, prop);
 +
 +      prop = RNA_def_property(srna, "tools_space_type", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_sdna(prop, NULL, "tools_space_type");
 +      RNA_def_property_enum_items(prop, rna_enum_space_type_items);
 +      RNA_def_property_ui_text(prop, "Active Tool Space", "Tool space type");
 +      RNA_def_property_clear_flag(prop, PROP_EDITABLE);
 +
 +      prop = RNA_def_property(srna, "tools_mode", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_sdna(prop, NULL, "tools_mode");
 +      RNA_def_property_enum_items(prop, DummyRNA_DEFAULT_items);
 +      RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_WorkSpace_tools_mode_itemf");
 +      RNA_def_property_ui_text(prop, "Active Tool Space", "Tool mode");
 +      RNA_def_property_clear_flag(prop, PROP_EDITABLE);
 +
 +#if 0
 +      prop = RNA_def_property(srna, "object_mode", PROP_ENUM, PROP_NONE);
 +      RNA_def_property_enum_items(prop, rna_enum_object_mode_items);
 +      RNA_def_property_ui_text(prop, "Mode", "Object interaction mode used in this window");
 +#endif
 +
 +      /* Flags */
 +      prop = RNA_def_property(srna, "use_filter_by_owner", PROP_BOOLEAN, PROP_NONE);
 +      RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
 +      RNA_def_property_boolean_sdna(prop, NULL, "flags", WORKSPACE_USE_FILTER_BY_ORIGIN);
 +      RNA_def_property_ui_text(prop, "Use UI Tags",
 +                               "Filter the UI by tags");
 +      RNA_def_property_update(prop, 0, "rna_window_update_all");
 +
 +      RNA_api_workspace(srna);
 +}
 +
 +void RNA_def_workspace(BlenderRNA *brna)
 +{
 +      rna_def_workspace_owner(brna);
 +      rna_def_workspace_tool(brna);
 +
 +      rna_def_workspace(brna);
 +}
 +
 +#endif /* RNA_RUNTIME */
@@@ -418,8 -413,7 +418,8 @@@ float RE_engine_get_camera_shift_x(Rend
        return BKE_camera_multiview_shift_x(re ? &re->r : NULL, camera, re->viewname);
  }
  
 -void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, bool use_spherical_stereo, float *r_modelmat)
 +void RE_engine_get_camera_model_matrix(
-         RenderEngine *engine, Object *camera, int use_spherical_stereo, float *r_modelmat)
++        RenderEngine *engine, Object *camera, bool use_spherical_stereo, float *r_modelmat)
  {
        Render *re = engine->re;