Merge branch 'master' into blender2.8
authorBastien Montagne <montagne29@wanadoo.fr>
Thu, 31 May 2018 14:21:47 +0000 (16:21 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Thu, 31 May 2018 14:21:47 +0000 (16:21 +0200)
Conflicts:
source/blender/editors/object/object_add.c
source/blender/editors/object/object_select.c
source/blender/editors/space_outliner/outliner_edit.c

18 files changed:
1  2 
source/blender/blenkernel/BKE_library.h
source/blender/blenkernel/intern/bpath.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/scene.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/versioning_defaults.c
source/blender/editors/object/object_add.c
source/blender/editors/object/object_relations.c
source/blender/editors/object/object_select.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/space_node/node_add.c
source/blender/editors/space_outliner/outliner_draw.c
source/blender/editors/space_outliner/outliner_edit.c
source/blender/makesrna/intern/rna_ID.c
source/blender/windowmanager/intern/wm_files_link.c
source/blender/windowmanager/intern/wm_operators.c
source/blender/windowmanager/intern/wm_toolsystem.c
source/creator/creator_args.c

@@@ -1047,11 -963,12 +1047,12 @@@ void OBJECT_OT_lamp_add(wmOperatorType 
        ED_object_add_generic_props(ot, false);
  }
  
 -/********************* Add Group Instance Operator ********************/
 +/********************* Add Collection Instance Operator ********************/
  
 -static int group_instance_add_exec(bContext *C, wmOperator *op)
 +static int collection_instance_add_exec(bContext *C, wmOperator *op)
  {
 -      Group *group;
+       Main *bmain = CTX_data_main(C);
 +      Collection *collection;
        unsigned int layer;
        float loc[3], rot[3];
        
                char name[MAX_ID_NAME - 2];
                
                RNA_string_get(op->ptr, "name", name);
-               collection = (Collection *)BKE_libblock_find_name(ID_GR, name);
 -              group = (Group *)BKE_libblock_find_name(bmain, ID_GR, name);
++              collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, name);
                
                if (0 == RNA_struct_property_is_set(op->ptr, "location")) {
                        const wmEvent *event = CTX_wm_window(C)->eventstate;
        if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &layer, NULL))
                return OPERATOR_CANCELLED;
  
 -      if (group) {
 +      if (collection) {
-               Main *bmain = CTX_data_main(C);
                Scene *scene = CTX_data_scene(C);
 -              Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, loc, rot, false, layer);
 -              ob->dup_group = group;
 -              ob->transflag |= OB_DUPLIGROUP;
 -              id_us_plus(&group->id);
 +              ViewLayer *view_layer = CTX_data_view_layer(C);
 +
 +              /* Avoid dependency cycles. */
 +              LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer);
 +              while (BKE_collection_find_cycle(active_lc->collection, collection)) {
 +                      active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc);
 +              }
 +
 +              Object *ob = ED_object_add_type(C, OB_EMPTY, collection->id.name + 2, loc, rot, false, layer);
 +              ob->dup_group = collection;
 +              ob->transflag |= OB_DUPLICOLLECTION;
 +              id_us_plus(&collection->id);
  
                /* works without this except if you try render right after, see: 22027 */
 -              DAG_relations_tag_update(bmain);
 +              DEG_relations_tag_update(bmain);
 +              DEG_id_tag_update(&collection->id, 0);
  
                WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
  
@@@ -901,21 -1072,22 +901,22 @@@ void OBJECT_OT_select_all(wmOperatorTyp
        WM_operator_properties_select_all(ot);
  }
  
 -/**************************** Select In The Same Group ****************************/
 +/**************************** Select In The Same Collection ****************************/
  
 -static int object_select_same_group_exec(bContext *C, wmOperator *op)
 +static int object_select_same_collection_exec(bContext *C, wmOperator *op)
  {
 -      Group *group;
 -      char group_name[MAX_ID_NAME];
+       Main *bmain = CTX_data_main(C);
 +      Collection *collection;
 +      char collection_name[MAX_ID_NAME];
  
        /* passthrough if no objects are visible */
        if (CTX_DATA_COUNT(C, visible_bases) == 0) return OPERATOR_PASS_THROUGH;
  
 -      RNA_string_get(op->ptr, "group", group_name);
 +      RNA_string_get(op->ptr, "collection", collection_name);
  
-       collection = (Collection *)BKE_libblock_find_name(ID_GR, collection_name);
 -      group = (Group *)BKE_libblock_find_name(bmain, ID_GR, group_name);
++      collection = (Collection *)BKE_libblock_find_name(bmain, ID_GR, collection_name);
  
 -      if (!group) {
 +      if (!collection) {
                return OPERATOR_PASS_THROUGH;
        }
  
@@@ -955,8 -1124,8 +956,9 @@@ void OBJECT_OT_select_same_collection(w
  /**************************** Select Mirror ****************************/
  static int object_select_mirror_exec(bContext *C, wmOperator *op)
  {
+       Main *bmain = CTX_data_main(C);
        Scene *scene = CTX_data_scene(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
        bool extend;
        
        extend = RNA_boolean_get(op->ptr, "extend");
                BLI_string_flip_side_name(name_flip, primbase->object->id.name + 2, true, sizeof(name_flip));
                
                if (!STREQ(name_flip, primbase->object->id.name + 2)) {
-                       Object *ob = (Object *)BKE_libblock_find_name(ID_OB, name_flip);
+                       Object *ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name_flip);
                        if (ob) {
 -                              Base *secbase = BKE_scene_base_find(scene, ob);
 +                              Base *secbase = BKE_view_layer_base_find(view_layer, ob);
  
                                if (secbase) {
 -                                      ED_base_object_select(secbase, BA_SELECT);
 +                                      ED_object_base_select(secbase, BA_SELECT);
                                }
                        }
                }
@@@ -2135,11 -2233,13 +2135,11 @@@ static int scene_drop_invoke(bContext *
        te = outliner_dropzone_find(soops, fmval, false);
  
        if (te) {
 -              Base *base;
 -
                RNA_string_set(op->ptr, "scene", te->name);
-               scene = (Scene *)BKE_libblock_find_name(ID_SCE, te->name);
+               scene = (Scene *)BKE_libblock_find_name(bmain, ID_SCE, te->name);
  
                RNA_string_get(op->ptr, "object", obname);
-               ob = (Object *)BKE_libblock_find_name(ID_OB, obname);
+               ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, obname);
  
                if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) {
                        return OPERATOR_CANCELLED;
@@@ -2298,38 -2360,44 +2298,38 @@@ static int collection_drop_invoke(bCont
        UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
  
        /* Find object hovered over */
 -      te = outliner_dropzone_find(soops, fmval, true);
 -
 -      if (te) {
 -              group = (Group *)BKE_libblock_find_name(bmain, ID_GR, te->name);
 +      TreeElement *te = outliner_dropzone_find(soops, fmval, true);
  
 -              RNA_string_get(op->ptr, "object", ob_name);
 -              ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, ob_name);
 -
 -              if (ELEM(NULL, group, ob)) {
 -                      return OPERATOR_CANCELLED;
 -              }
 -              if (BKE_group_object_exists(group, ob)) {
 -                      return OPERATOR_FINISHED;
 -              }
 +      if (!te || !outliner_is_collection_tree_element(te)) {
 +              return OPERATOR_CANCELLED;
 +      }
  
 -              if (BKE_group_object_cyclic_check(bmain, ob, group)) {
 -                      BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected");
 -                      return OPERATOR_CANCELLED;
 -              }
 +      Collection *collection = outliner_collection_from_tree_element(te);
  
 -              BKE_group_object_add(group, ob, scene, NULL);
 -              WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
 +      // TODO: don't use scene, makes no sense anymore
 +      // TODO: move rather than link, change hover text
 +      Scene *scene = BKE_scene_find_from_collection(bmain, collection);
 +      BLI_assert(scene);
 +      RNA_string_get(op->ptr, "child", childname);
-       Object *ob = (Object *)BKE_libblock_find_name(ID_OB, childname);
++      Object *ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname);
 +      BKE_collection_object_add(bmain, collection, ob);
  
 -              return OPERATOR_FINISHED;
 -      }
 +      DEG_relations_tag_update(bmain);
 +      WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene);
  
 -      return OPERATOR_CANCELLED;
 +      return OPERATOR_FINISHED;
  }
  
 -void OUTLINER_OT_group_link(wmOperatorType *ot)
 +void OUTLINER_OT_collection_drop(wmOperatorType *ot)
  {
        /* identifiers */
 -      ot->name = "Link Object to Group";
 -      ot->description = "Link Object to Group in Outliner";
 -      ot->idname = "OUTLINER_OT_group_link";
 +      ot->name = "Link to Collection"; // TODO: rename to move?
 +      ot->description = "Drag to move to collection in Outliner";
 +      ot->idname = "OUTLINER_OT_collection_drop";
  
        /* api callbacks */
 -      ot->invoke = group_link_invoke;
 +      ot->invoke = collection_drop_invoke;
 +      ot->exec = collection_drop_exec;
  
        ot->poll = ED_operator_outliner_active;
  
index 0ea933a,0000000..508713c
mode 100644,000000..100644
--- /dev/null
@@@ -1,605 -1,0 +1,605 @@@
-               struct Brush *brush = (struct Brush *)BKE_libblock_find_name(ID_BR, tref_rt->data_block);
 +/*
 + * ***** 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/windowmanager/intern/wm_toolsystem.c
 + *  \ingroup wm
 + *
 + * Experimental tool-system>
 + */
 +
 +#include <string.h>
 +
 +#include "CLG_log.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_string.h"
 +#include "BLI_listbase.h"
 +
 +#include "DNA_ID.h"
 +#include "DNA_scene_types.h"
 +#include "DNA_space_types.h"
 +#include "DNA_windowmanager_types.h"
 +#include "DNA_workspace_types.h"
 +#include "DNA_object_types.h"
 +
 +#include "BKE_context.h"
 +#include "BKE_library.h"
 +#include "BKE_main.h"
 +#include "BKE_paint.h"
 +#include "BKE_idprop.h"
 +#include "BKE_workspace.h"
 +
 +#include "RNA_access.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +#include "WM_message.h"
 +#include "WM_toolsystem.h"  /* own include */
 +
 +static void toolsystem_reinit_with_toolref(
 +        bContext *C, WorkSpace *UNUSED(workspace), bToolRef *tref);
 +static void toolsystem_reinit_ensure_toolref(
 +        bContext *C, WorkSpace *workspace, const bToolKey *tkey, const char *default_tool);
 +static void toolsystem_refresh_screen_from_active_tool(
 +        Main *bmain, WorkSpace *workspace, bToolRef *tref);
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Tool Reference API
 + * \{ */
 +
 +struct bToolRef *WM_toolsystem_ref_from_context(struct bContext *C)
 +{
 +      WorkSpace *workspace = CTX_wm_workspace(C);
 +      Scene *scene = CTX_data_scene(C);
 +      ScrArea *sa = CTX_wm_area(C);
 +      const bToolKey tkey = {
 +              .space_type = sa->spacetype,
 +              .mode = WM_toolsystem_mode_from_spacetype(workspace, scene, sa, sa->spacetype),
 +      };
 +      bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
 +      /* We could return 'sa->runtime.tool' in this case. */
 +      if (sa->runtime.is_tool_set) {
 +              BLI_assert(tref == sa->runtime.tool);
 +      }
 +      return tref;
 +}
 +
 +struct bToolRef_Runtime *WM_toolsystem_runtime_from_context(struct bContext *C)
 +{
 +      bToolRef *tref = WM_toolsystem_ref_from_context(C);
 +      return tref ? tref->runtime : NULL;
 +}
 +
 +bToolRef *WM_toolsystem_ref_find(WorkSpace *workspace, const bToolKey *tkey)
 +{
 +      LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
 +              if ((tref->space_type == tkey->space_type) &&
 +                  (tref->mode == tkey->mode))
 +              {
 +                      return tref;
 +              }
 +      }
 +      return NULL;
 +}
 +
 +bToolRef_Runtime *WM_toolsystem_runtime_find(WorkSpace *workspace, const bToolKey *tkey)
 +{
 +      bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
 +      return tref ? tref->runtime : NULL;
 +}
 +
 +bool WM_toolsystem_ref_ensure(
 +        struct WorkSpace *workspace, const bToolKey *tkey,
 +        bToolRef **r_tref)
 +{
 +      bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
 +      if (tref) {
 +              *r_tref = tref;
 +              return false;
 +      }
 +      tref = MEM_callocN(sizeof(*tref), __func__);
 +      BLI_addhead(&workspace->tools, tref);
 +      tref->space_type = tkey->space_type;
 +      tref->mode = tkey->mode;
 +      *r_tref = tref;
 +      return true;
 +}
 +
 +/** \} */
 +
 +
 +static void toolsystem_unlink_ref(bContext *C, WorkSpace *workspace, bToolRef *tref)
 +{
 +      bToolRef_Runtime *tref_rt = tref->runtime;
 +
 +      if (tref_rt->manipulator_group[0]) {
 +              wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(tref_rt->manipulator_group, false);
 +              if (wgt != NULL) {
 +                      bool found = false;
 +
 +                      /* TODO(campbell) */
 +                      Main *bmain = CTX_data_main(C);
 +#if 0
 +                      wmWindowManager *wm = bmain->wm.first;
 +                      /* Check another workspace isn't using this tool. */
 +                      for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +                              const WorkSpace *workspace_iter = WM_window_get_active_workspace(win);
 +                              if (workspace != workspace_iter) {
 +                                      if (STREQ(workspace->tool.manipulator_group, workspace_iter->tool.manipulator_group)) {
 +                                              found = true;
 +                                              break;
 +                                      }
 +                              }
 +                      }
 +#else
 +                      UNUSED_VARS(workspace);
 +#endif
 +                      if (!found) {
 +                              wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params);
 +                              WM_manipulatormaptype_group_unlink(C, bmain, mmap_type, wgt);
 +                      }
 +              }
 +      }
 +}
 +void WM_toolsystem_unlink(bContext *C, WorkSpace *workspace, const bToolKey *tkey)
 +{
 +      bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
 +      if (tref && tref->runtime) {
 +              toolsystem_unlink_ref(C, workspace, tref);
 +      }
 +}
 +
 +static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tref)
 +{
 +      bToolRef_Runtime *tref_rt = tref->runtime;
 +      if (tref_rt->manipulator_group[0]) {
 +              const char *idname = tref_rt->manipulator_group;
 +              wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false);
 +              if (wgt != NULL) {
 +                      WM_manipulator_group_type_ensure_ptr(wgt);
 +              }
 +              else {
 +                      CLOG_WARN(WM_LOG_TOOLS, "'%s' widget not found", idname);
 +              }
 +      }
 +
 +      if (tref_rt->data_block[0]) {
 +              Main *bmain = CTX_data_main(C);
 +
 +              /* Currently only brush data-blocks supported. */
++              struct Brush *brush = (struct Brush *)BKE_libblock_find_name(bmain, ID_BR, tref_rt->data_block);
 +
 +              if (brush) {
 +                      wmWindowManager *wm = bmain->wm.first;
 +                      for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +                              if (workspace == WM_window_get_active_workspace(win)) {
 +                                      Scene *scene = win->scene;
 +                                      ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene);
 +                                      Paint *paint = BKE_paint_get_active(scene, view_layer);
 +                                      if (paint) {
 +                                              if (brush) {
 +                                                      BKE_paint_brush_set(paint, brush);
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +static void toolsystem_refresh_ref(bContext *C, WorkSpace *workspace, bToolRef *tref)
 +{
 +      if (tref->runtime == NULL) {
 +              return;
 +      }
 +      /* currently same operation. */
 +      toolsystem_ref_link(C, workspace, tref);
 +}
 +void WM_toolsystem_refresh(bContext *C, WorkSpace *workspace, const bToolKey *tkey)
 +{
 +      bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
 +      if (tref) {
 +              toolsystem_refresh_ref(C, workspace, tref);
 +      }
 +}
 +
 +static void toolsystem_reinit_ref(bContext *C, WorkSpace *workspace, bToolRef *tref)
 +{
 +      toolsystem_reinit_with_toolref(C, workspace, tref);
 +}
 +void WM_toolsystem_reinit(bContext *C, WorkSpace *workspace, const bToolKey *tkey)
 +{
 +      bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
 +      if (tref) {
 +              toolsystem_reinit_ref(C, workspace, tref);
 +      }
 +}
 +
 +/* Operate on all active tools. */
 +void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace)
 +{
 +      LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
 +              tref->tag = 0;
 +      }
 +
 +      LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
 +              if (tref->runtime) {
 +                      if (tref->tag == 0) {
 +                              toolsystem_unlink_ref(C, workspace, tref);
 +                              tref->tag = 1;
 +                      }
 +              }
 +      }
 +}
 +
 +void WM_toolsystem_refresh_all(struct bContext *C, struct WorkSpace *workspace)
 +{
 +      BLI_assert(0);
 +      LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
 +              toolsystem_refresh_ref(C, workspace, tref);
 +      }
 +}
 +void WM_toolsystem_reinit_all(struct bContext *C, wmWindow *win)
 +{
 +      bScreen *screen = WM_window_get_active_screen(win);
 +      Scene *scene = WM_window_get_active_scene(win);
 +      for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +              WorkSpace *workspace = WM_window_get_active_workspace(win);
 +              const bToolKey tkey = {
 +                      .space_type = sa->spacetype,
 +                      .mode = WM_toolsystem_mode_from_spacetype(workspace, scene, sa, sa->spacetype),
 +              };
 +              bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
 +              if (tref) {
 +                      if (tref->tag == 0) {
 +                              toolsystem_reinit_ref(C, workspace, tref);
 +                              tref->tag = 1;
 +                      }
 +              }
 +      }
 +}
 +
 +void WM_toolsystem_ref_set_from_runtime(
 +        struct bContext *C, struct WorkSpace *workspace, bToolRef *tref,
 +        const bToolRef_Runtime *tref_rt, const char *idname)
 +{
 +      Main *bmain = CTX_data_main(C);
 +
 +      if (tref->runtime) {
 +              toolsystem_unlink_ref(C, workspace, tref);
 +      }
 +
 +      STRNCPY(tref->idname, idname);
 +
 +      /* BAD DESIGN WARNING: used for topbar. */
 +      workspace->tools_space_type = tref->space_type;
 +      workspace->tools_mode = tref->mode;
 +
 +      if (tref->runtime == NULL) {
 +              tref->runtime = MEM_callocN(sizeof(*tref->runtime), __func__);
 +      }
 +
 +      if (tref_rt != tref->runtime) {
 +              *tref->runtime = *tref_rt;
 +      }
 +
 +      toolsystem_ref_link(C, workspace, tref);
 +
 +      toolsystem_refresh_screen_from_active_tool(bmain, workspace, tref);
 +
 +      {
 +              struct wmMsgBus *mbus = CTX_wm_message_bus(C);
 +              WM_msg_publish_rna_prop(
 +                      mbus, &workspace->id, workspace, WorkSpace, tools);
 +      }
 +}
 +
 +void WM_toolsystem_init(bContext *C)
 +{
 +      Main *bmain = CTX_data_main(C);
 +
 +      BLI_assert(CTX_wm_window(C) == NULL);
 +
 +      LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
 +              LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
 +                      MEM_SAFE_FREE(tref->runtime);
 +                      tref->tag = 0;
 +              }
 +      }
 +
 +      for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
 +              for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +                      CTX_wm_window_set(C, win);
 +                      WorkSpace *workspace = WM_window_get_active_workspace(win);
 +                      bScreen *screen = WM_window_get_active_screen(win);
 +                      Scene *scene = WM_window_get_active_scene(win);
 +                      for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                              const bToolKey tkey = {
 +                                      .space_type = sa->spacetype,
 +                                      .mode = WM_toolsystem_mode_from_spacetype(workspace, scene, sa, sa->spacetype),
 +                              };
 +                              bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
 +                              if (tref) {
 +                                      if (tref->tag == 0) {
 +                                              toolsystem_reinit_ref(C, workspace, tref);
 +                                              tref->tag = 1;
 +                                      }
 +                              }
 +                      }
 +                      CTX_wm_window_set(C, NULL);
 +              }
 +      }
 +}
 +
 +int WM_toolsystem_mode_from_spacetype(
 +        WorkSpace *workspace, Scene *scene, ScrArea *sa,
 +        int spacetype)
 +{
 +      int mode = -1;
 +      switch (spacetype) {
 +              case SPACE_VIEW3D:
 +              {
 +                      /* 'sa' may be NULL in this case. */
 +                      ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene);
 +                      Object *obact = OBACT(view_layer);
 +                      if (obact != NULL) {
 +                              Object *obedit = OBEDIT_FROM_OBACT(obact);
 +                              mode = CTX_data_mode_enum_ex(obedit, obact, obact->mode);
 +                      }
 +                      else {
 +                              mode = CTX_MODE_OBJECT;
 +                      }
 +                      break;
 +              }
 +              case SPACE_IMAGE:
 +              {
 +                      SpaceImage *sima = sa->spacedata.first;
 +                      mode = sima->mode;
 +                      break;
 +              }
 +      }
 +      return mode;
 +}
 +
 +bool WM_toolsystem_key_from_context(
 +        WorkSpace *workspace, Scene *scene, ScrArea *sa,
 +        bToolKey *tkey)
 +{
 +      int space_type = SPACE_EMPTY;
 +      int mode = -1;
 +
 +      if (sa != NULL) {
 +              space_type = sa->spacetype;
 +              mode = WM_toolsystem_mode_from_spacetype(workspace, scene, sa, space_type);
 +      }
 +
 +      if (mode != -1) {
 +              tkey->space_type = space_type;
 +              tkey->mode = mode;
 +              return true;
 +      }
 +      return false;
 +}
 +
 +void WM_toolsystem_refresh_screen_area(WorkSpace *workspace, Scene *scene, ScrArea *sa)
 +{
 +      sa->runtime.tool = NULL;
 +      sa->runtime.is_tool_set = true;
 +      const int mode = WM_toolsystem_mode_from_spacetype(workspace, scene, sa, sa->spacetype);
 +      for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
 +              if (tref->space_type == sa->spacetype) {
 +                      if (tref->mode == mode) {
 +                              sa->runtime.tool = tref;
 +                              break;
 +                      }
 +              }
 +      }
 +}
 +
 +void WM_toolsystem_refresh_screen_all(Main *bmain)
 +{
 +      /* Update all ScrArea's tools */
 +      for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
 +              for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +                      WorkSpace *workspace = WM_window_get_active_workspace(win);
 +                      bool space_type_has_tools[SPACE_TYPE_LAST + 1] = {0};
 +                      for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
 +                              space_type_has_tools[tref->space_type] = true;
 +                      }
 +                      bScreen *screen = WM_window_get_active_screen(win);
 +                      Scene *scene = WM_window_get_active_scene(win);
 +                      for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                              sa->runtime.tool = NULL;
 +                              sa->runtime.is_tool_set = true;
 +                              if (space_type_has_tools[sa->spacetype]) {
 +                                      WM_toolsystem_refresh_screen_area(workspace, scene, sa);
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +static void toolsystem_refresh_screen_from_active_tool(
 +        Main *bmain, WorkSpace *workspace, bToolRef *tref)
 +{
 +      /* Update all ScrArea's tools */
 +      for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
 +              for (wmWindow *win = wm->windows.first; win; win = win->next) {
 +                      if (workspace == WM_window_get_active_workspace(win)) {
 +                              bScreen *screen = WM_window_get_active_screen(win);
 +                              Scene *scene = WM_window_get_active_scene(win);
 +                              for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
 +                                      if (sa->spacetype == tref->space_type) {
 +                                              int mode = WM_toolsystem_mode_from_spacetype(workspace, scene, sa, sa->spacetype);
 +                                              if (mode == tref->mode) {
 +                                                      sa->runtime.tool = tref;
 +                                                      sa->runtime.is_tool_set = true;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +bToolRef *WM_toolsystem_ref_set_by_name(
 +        bContext *C, WorkSpace *workspace, const bToolKey *tkey,
 +        const char *name, bool cycle)
 +{
 +      wmOperatorType *ot = WM_operatortype_find("WM_OT_tool_set_by_name", false);
 +      /* On startup, Python operatores are not yet loaded. */
 +      if (ot == NULL) {
 +              return NULL;
 +      }
 +      PointerRNA op_props;
 +      WM_operator_properties_create_ptr(&op_props, ot);
 +      RNA_string_set(&op_props, "name", name);
 +
 +      /* Will get from context if not set. */
 +      bToolKey tkey_from_context;
 +      if (tkey == NULL) {
 +              Scene *scene = CTX_data_scene(C);
 +              ScrArea *sa = CTX_wm_area(C);
 +              WM_toolsystem_key_from_context(workspace, scene, sa, &tkey_from_context);
 +              tkey = &tkey_from_context;
 +      }
 +
 +      RNA_enum_set(&op_props, "space_type", tkey->space_type);
 +      RNA_boolean_set(&op_props, "cycle", cycle);
 +
 +      WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props);
 +      WM_operator_properties_free(&op_props);
 +
 +      bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
 +
 +      if (tref) {
 +              Main *bmain = CTX_data_main(C);
 +              toolsystem_refresh_screen_from_active_tool(bmain, workspace, tref);
 +      }
 +
 +      return (tref && STREQ(tref->idname, name)) ? tref : NULL;
 +}
 +
 +static void toolsystem_reinit_with_toolref(
 +        bContext *C, WorkSpace *workspace, bToolRef *tref)
 +{
 +      bToolKey tkey = {
 +              .space_type = tref->space_type,
 +              .mode = tref->mode,
 +      };
 +      WM_toolsystem_ref_set_by_name(C, workspace, &tkey, tref->idname, false);
 +}
 +
 +/**
 + * Run after changing modes.
 + */
 +static void toolsystem_reinit_ensure_toolref(
 +        bContext *C, WorkSpace *workspace, const bToolKey *tkey, const char *default_tool)
 +{
 +      bToolRef *tref;
 +      if (WM_toolsystem_ref_ensure(workspace, tkey, &tref)) {
 +              STRNCPY(tref->idname, default_tool);
 +      }
 +
 +      toolsystem_reinit_with_toolref(C, workspace, tref);
 +}
 +
 +void WM_toolsystem_update_from_context_view3d(bContext *C)
 +{
 +      WorkSpace *workspace = CTX_wm_workspace(C);
 +      Scene *scene = CTX_data_scene(C);
 +      int space_type = SPACE_VIEW3D;
 +      const bToolKey tkey = {
 +              .space_type = space_type,
 +              .mode = WM_toolsystem_mode_from_spacetype(workspace, scene, NULL, space_type),
 +      };
 +      toolsystem_reinit_ensure_toolref(C, workspace, &tkey, "Cursor");
 +}
 +
 +/**
 + * For paint modes to support non-brush tools.
 + */
 +bool WM_toolsystem_active_tool_is_brush(const bContext *C)
 +{
 +      bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
 +      return tref_rt->data_block[0] != '\0';
 +}
 +
 +/* Follow wmMsgNotifyFn spec */
 +void WM_toolsystem_do_msg_notify_tag_refresh(
 +        bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
 +{
 +      WorkSpace *workspace = CTX_wm_workspace(C);
 +      Scene *scene = CTX_data_scene(C);
 +      ScrArea *sa = msg_val->user_data;
 +      int space_type = sa->spacetype;
 +      const bToolKey tkey = {
 +              .space_type = space_type,
 +              .mode = WM_toolsystem_mode_from_spacetype(workspace, scene, sa, sa->spacetype),
 +      };
 +      WM_toolsystem_refresh(C, workspace, &tkey);
 +}
 +
 +IDProperty *WM_toolsystem_ref_properties_ensure_idprops(bToolRef *tref)
 +{
 +      if (tref->properties == NULL) {
 +              IDPropertyTemplate val = {0};
 +              tref->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
 +      }
 +      return tref->properties;
 +}
 +
 +void WM_toolsystem_ref_properties_ensure(bToolRef *tref, wmOperatorType *ot, PointerRNA *ptr)
 +{
 +      IDProperty *group = WM_toolsystem_ref_properties_ensure_idprops(tref);
 +      IDProperty *prop = IDP_GetPropertyFromGroup(group, ot->idname);
 +      if (prop == NULL) {
 +              IDPropertyTemplate val = {0};
 +              prop = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
 +              STRNCPY(prop->name, ot->idname);
 +              IDP_ReplaceInGroup_ex(group, prop, NULL);
 +      }
 +      else {
 +              BLI_assert(prop->type == IDP_GROUP);
 +      }
 +
 +      RNA_pointer_create(NULL, ot->srna, prop, ptr);
 +}
 +
 +void WM_toolsystem_ref_properties_init_for_keymap(
 +        bToolRef *tref, PointerRNA *dst_ptr, PointerRNA *src_ptr, wmOperatorType *ot)
 +{
 +      *dst_ptr = *src_ptr;
 +      if (dst_ptr->data) {
 +              dst_ptr->data = IDP_CopyProperty(dst_ptr->data);
 +      }
 +      else {
 +              IDPropertyTemplate val = {0};
 +              dst_ptr->data = IDP_New(IDP_GROUP, &val, "wmOpItemProp");
 +      }
 +      if (tref->properties != NULL) {
 +              IDProperty *prop = IDP_GetPropertyFromGroup(tref->properties, ot->idname);
 +              if (prop) {
 +                      IDP_MergeGroup(dst_ptr->data, prop, true);
 +              }
 +      }
 +}
Simple merge