This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/windowmanager/intern/wm_toolsystem.c
Campbell Barton c9d9bfa84a Keymap: preference for fallback-tool with RMB select
Expose a key-map preference "Fallback Tool (RMB)",
disabled by default.

The right mouse button uses the fallback tool
(currently visible selection tool in the toolbar),
instead of always tweaking.

When any selection tool is active, right mouse always tweaks.

To enable fallback selection on RMB, set the "Right Mouse Select Action"
to "Selection Tool".

Internal changes:

- Add fall-back key-maps, separate key-maps needed for when the tool is
  run as a fall-back. This is needed so RMB-select can support fall-back
  tools, so left-mouse can be used when it's the active tool and RMB
  can be used as a fall-back action when another tool is active.
- Add options field to tools so tools without gizmos can enable the
  full-back tool keymap.
- Support multiple key-maps for keymap handlers.
- Fall-back keymaps now co-exist with the tool-keymaps.
  So both keymaps may be active at once - using different mouse buttons.
  When gizmos are in use, a highlighted gizmo prioritizes the
  tool-keymap over the fall-back keymap.

Resolves T83690.

Reviewed By: JulienKaspar

Ref D12493
2021-09-21 18:14:11 +10:00

903 lines
29 KiB
C

/*
* 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.
*/
/** \file
* \ingroup wm
*
* Experimental tool-system>
*/
#include <string.h>
#include "CLG_log.h"
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_ID.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_paint.h"
#include "BKE_workspace.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_message.h"
#include "WM_toolsystem.h" /* own include */
#include "WM_types.h"
static void toolsystem_reinit_with_toolref(bContext *C,
WorkSpace *UNUSED(workspace),
bToolRef *tref);
static bToolRef *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);
ViewLayer *view_layer = CTX_data_view_layer(C);
ScrArea *area = CTX_wm_area(C);
if ((area == NULL) || ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) {
return NULL;
}
const bToolKey tkey = {
.space_type = area->spacetype,
.mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
};
bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
/* We could return 'area->runtime.tool' in this case. */
if (area->runtime.is_tool_set) {
BLI_assert(tref == area->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)
{
BLI_assert((1 << tkey->space_type) & WM_TOOLSYSTEM_SPACE_MASK);
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 *UNUSED(workspace), bToolRef *tref)
{
bToolRef_Runtime *tref_rt = tref->runtime;
if (tref_rt->gizmo_group[0]) {
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(tref_rt->gizmo_group, false);
if (gzgt != NULL) {
Main *bmain = CTX_data_main(C);
WM_gizmo_group_remove_by_tool(C, bmain, gzgt, tref);
}
}
}
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->gizmo_group[0]) {
const char *idname = tref_rt->gizmo_group;
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
if (gzgt != NULL) {
if ((gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_INIT) == 0) {
if (!WM_gizmo_group_type_ensure_ptr(gzgt)) {
/* Even if the group-type was has been linked, it's possible the space types
* were not previously using it. (happens with multiple windows.) */
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
WM_gizmoconfig_update_tag_group_type_init(gzmap_type, gzgt);
}
}
}
else {
CLOG_WARN(WM_LOG_TOOLS, "'%s' widget not found", idname);
}
}
if (tref_rt->data_block[0]) {
Main *bmain = CTX_data_main(C);
if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_PARTICLE)) {
const EnumPropertyItem *items = rna_enum_particle_edit_hair_brush_items;
const int i = RNA_enum_from_identifier(items, tref_rt->data_block);
if (i != -1) {
const int value = items[i].value;
wmWindowManager *wm = bmain->wm.first;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (workspace == WM_window_get_active_workspace(win)) {
Scene *scene = WM_window_get_active_scene(win);
ToolSettings *ts = scene->toolsettings;
ts->particle.brushtype = value;
}
}
}
}
else {
const ePaintMode paint_mode = BKE_paintmode_get_from_tool(tref);
BLI_assert(paint_mode != PAINT_MODE_INVALID);
const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
BLI_assert(items != NULL);
const int i = items ? RNA_enum_from_identifier(items, tref_rt->data_block) : -1;
if (i != -1) {
const int slot_index = items[i].value;
wmWindowManager *wm = bmain->wm.first;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (workspace == WM_window_get_active_workspace(win)) {
Scene *scene = WM_window_get_active_scene(win);
BKE_paint_ensure_from_paintmode(scene, paint_mode);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
struct Brush *brush = BKE_paint_toolslots_brush_get(paint, slot_index);
if (brush == NULL) {
/* Could make into a function. */
brush = (struct Brush *)BKE_libblock_find_name(bmain, ID_BR, items[i].name);
if (brush && slot_index == BKE_brush_tool_get(brush, paint)) {
/* pass */
}
else {
brush = BKE_brush_add(bmain, items[i].name, paint->runtime.ob_mode);
BKE_brush_tool_set(brush, paint, slot_index);
}
BKE_paint_brush_set(paint, 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);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) {
continue;
}
WorkSpace *workspace = WM_window_get_active_workspace(win);
const bToolKey tkey = {
.space_type = area->spacetype,
.mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->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);
if (tref->runtime == NULL) {
tref->runtime = MEM_callocN(sizeof(*tref->runtime), __func__);
}
if (tref_rt != tref->runtime) {
*tref->runtime = *tref_rt;
}
/* Ideally Python could check this gizmo group flag and not
* pass in the argument to begin with. */
bool use_fallback_keymap = false;
if (tref->idname_fallback[0] || tref->runtime->keymap_fallback[0]) {
if (tref_rt->flag & TOOLREF_FLAG_FALLBACK_KEYMAP) {
use_fallback_keymap = true;
}
else if (tref_rt->gizmo_group[0]) {
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(tref_rt->gizmo_group, false);
if (gzgt) {
if (gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
use_fallback_keymap = true;
}
}
}
}
if (use_fallback_keymap == false) {
tref->idname_fallback[0] = '\0';
tref->runtime->keymap_fallback[0] = '\0';
}
toolsystem_ref_link(C, workspace, tref);
toolsystem_refresh_screen_from_active_tool(bmain, workspace, tref);
/* Set the cursor if possible, if not - it's fine as entering the region will refresh it. */
{
wmWindow *win = CTX_wm_window(C);
if (win != NULL) {
win->addmousemove = true;
win->tag_cursor_refresh = true;
}
}
{
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
WM_msg_publish_rna_prop(mbus, &workspace->id, workspace, WorkSpace, tools);
}
}
/**
* Sync the internal active state of a tool back into the tool system,
* this is needed for active brushes where the real active state is not stored in the tool system.
*
* \see #toolsystem_ref_link
*/
void WM_toolsystem_ref_sync_from_context(Main *bmain, WorkSpace *workspace, bToolRef *tref)
{
bToolRef_Runtime *tref_rt = tref->runtime;
if ((tref_rt == NULL) || (tref_rt->data_block[0] == '\0')) {
return;
}
wmWindowManager *wm = bmain->wm.first;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (workspace != WM_window_get_active_workspace(win)) {
continue;
}
Scene *scene = WM_window_get_active_scene(win);
ToolSettings *ts = scene->toolsettings;
const ViewLayer *view_layer = WM_window_get_active_view_layer(win);
const Object *ob = OBACT(view_layer);
if (ob == NULL) {
/* pass */
}
if ((tref->space_type == SPACE_VIEW3D) && (tref->mode == CTX_MODE_PARTICLE)) {
if (ob->mode & OB_MODE_PARTICLE_EDIT) {
const EnumPropertyItem *items = rna_enum_particle_edit_hair_brush_items;
const int i = RNA_enum_from_value(items, ts->particle.brushtype);
const EnumPropertyItem *item = &items[i];
if (!STREQ(tref_rt->data_block, item->identifier)) {
STRNCPY(tref_rt->data_block, item->identifier);
SNPRINTF(tref->idname, "builtin_brush.%s", item->name);
}
}
}
else {
const ePaintMode paint_mode = BKE_paintmode_get_from_tool(tref);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
if (paint && paint->brush && items) {
const ID *brush = (ID *)paint->brush;
const char tool_type = BKE_brush_tool_get((struct Brush *)brush, paint);
const int i = RNA_enum_from_value(items, tool_type);
/* Possible when loading files from the future. */
if (i != -1) {
const char *name = items[i].name;
const char *identifier = items[i].identifier;
if (!STREQ(tref_rt->data_block, identifier)) {
STRNCPY(tref_rt->data_block, identifier);
SNPRINTF(tref->idname, "builtin_brush.%s", name);
}
}
}
}
}
}
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);
}
}
/* Rely on screen initialization for gizmos. */
}
static bool toolsystem_key_ensure_check(const bToolKey *tkey)
{
switch (tkey->space_type) {
case SPACE_VIEW3D:
return true;
case SPACE_IMAGE:
if (ELEM(tkey->mode, SI_MODE_PAINT, SI_MODE_UV)) {
return true;
}
break;
case SPACE_NODE:
return true;
case SPACE_SEQ:
return true;
}
return false;
}
int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *area, int space_type)
{
int mode = -1;
switch (space_type) {
case SPACE_VIEW3D: {
/* 'area' may be NULL in this case. */
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 = area->spacedata.first;
mode = sima->mode;
break;
}
case SPACE_NODE: {
mode = 0;
break;
}
case SPACE_SEQ: {
SpaceSeq *sseq = area->spacedata.first;
mode = sseq->view;
break;
}
}
return mode;
}
bool WM_toolsystem_key_from_context(ViewLayer *view_layer, ScrArea *area, bToolKey *tkey)
{
int space_type = SPACE_EMPTY;
int mode = -1;
if (area != NULL) {
space_type = area->spacetype;
mode = WM_toolsystem_mode_from_spacetype(view_layer, area, space_type);
}
if (mode != -1) {
tkey->space_type = space_type;
tkey->mode = mode;
return true;
}
return false;
}
/**
* Use to update the active tool (shown in the top bar) in the least disruptive way.
*
* This is a little involved since there may be multiple valid active tools
* depending on the mode and space type.
*
* Used when undoing since the active mode may have changed.
*/
void WM_toolsystem_refresh_active(bContext *C)
{
Main *bmain = CTX_data_main(C);
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
WorkSpace *workspace = WM_window_get_active_workspace(win);
bScreen *screen = WM_window_get_active_screen(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
/* Could skip loop for modes that don't depend on space type. */
int space_type_mask_handled = 0;
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
/* Don't change the space type of the active tool, only update its mode. */
const int space_type_mask = (1 << area->spacetype);
if ((space_type_mask & WM_TOOLSYSTEM_SPACE_MASK) &&
((space_type_mask_handled & space_type_mask) == 0)) {
space_type_mask_handled |= space_type_mask;
const bToolKey tkey = {
.space_type = area->spacetype,
.mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
};
bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
if (tref != area->runtime.tool) {
toolsystem_reinit_ensure_toolref(C, workspace, &tkey, NULL);
}
}
}
}
}
BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_DOIT);
LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
if (workspace->id.tag & LIB_TAG_DOIT) {
workspace->id.tag &= ~LIB_TAG_DOIT;
/* Refresh to ensure data is initialized.
* This is needed because undo can load a state which no longer has the underlying DNA data
* needed for the tool (un-initialized paint-slots for eg), see: T64339. */
LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
toolsystem_refresh_ref(C, workspace, tref);
}
}
}
}
void WM_toolsystem_refresh_screen_area(WorkSpace *workspace, ViewLayer *view_layer, ScrArea *area)
{
area->runtime.tool = NULL;
area->runtime.is_tool_set = true;
const int mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype);
LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
if (tref->space_type == area->spacetype) {
if (tref->mode == mode) {
area->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) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
WorkSpace *workspace = WM_window_get_active_workspace(win);
bool space_type_has_tools[SPACE_TYPE_LAST + 1] = {0};
LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
space_type_has_tools[tref->space_type] = true;
}
bScreen *screen = WM_window_get_active_screen(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
area->runtime.tool = NULL;
area->runtime.is_tool_set = true;
if (space_type_has_tools[area->spacetype]) {
WM_toolsystem_refresh_screen_area(workspace, view_layer, area);
}
}
}
}
}
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) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (workspace == WM_window_get_active_workspace(win)) {
bScreen *screen = WM_window_get_active_screen(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype == tref->space_type) {
int mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype);
if (mode == tref->mode) {
area->runtime.tool = tref;
area->runtime.is_tool_set = true;
}
}
}
}
}
}
}
bToolRef *WM_toolsystem_ref_set_by_id_ex(
bContext *C, WorkSpace *workspace, const bToolKey *tkey, const char *name, bool cycle)
{
wmOperatorType *ot = WM_operatortype_find("WM_OT_tool_set_by_id", false);
/* On startup, Python operators 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);
BLI_assert((1 << tkey->space_type) & WM_TOOLSYSTEM_SPACE_MASK);
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;
}
bToolRef *WM_toolsystem_ref_set_by_id(bContext *C, const char *name)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
ScrArea *area = CTX_wm_area(C);
bToolKey tkey;
if (WM_toolsystem_key_from_context(view_layer, area, &tkey)) {
WorkSpace *workspace = CTX_wm_workspace(C);
return WM_toolsystem_ref_set_by_id_ex(C, workspace, &tkey, name, false);
}
return 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_id_ex(C, workspace, &tkey, tref->idname, false);
}
static const char *toolsystem_default_tool(const bToolKey *tkey)
{
switch (tkey->space_type) {
case SPACE_VIEW3D:
switch (tkey->mode) {
/* Use the names of the enums for each brush tool. */
case CTX_MODE_SCULPT:
case CTX_MODE_PAINT_VERTEX:
case CTX_MODE_PAINT_WEIGHT:
case CTX_MODE_PAINT_TEXTURE:
case CTX_MODE_PAINT_GPENCIL:
return "builtin_brush.Draw";
case CTX_MODE_SCULPT_GPENCIL:
return "builtin_brush.Push";
case CTX_MODE_WEIGHT_GPENCIL:
return "builtin_brush.Weight";
case CTX_MODE_VERTEX_GPENCIL:
return "builtin_brush.Draw";
/* end temporary hack. */
case CTX_MODE_PARTICLE:
return "builtin_brush.Comb";
case CTX_MODE_EDIT_TEXT:
return "builtin.cursor";
}
break;
case SPACE_IMAGE:
switch (tkey->mode) {
case SI_MODE_PAINT:
return "builtin_brush.Draw";
}
break;
case SPACE_NODE: {
return "builtin.select_box";
}
case SPACE_SEQ: {
switch (tkey->mode) {
case SEQ_VIEW_SEQUENCE:
return "builtin.select";
case SEQ_VIEW_PREVIEW:
return "builtin.sample";
case SEQ_VIEW_SEQUENCE_PREVIEW:
return "builtin.select";
}
return "builtin.select_box";
}
}
return "builtin.select_box";
}
/**
* Run after changing modes.
*/
static bToolRef *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)) {
if (default_tool == NULL) {
default_tool = toolsystem_default_tool(tkey);
}
STRNCPY(tref->idname, default_tool);
}
toolsystem_reinit_with_toolref(C, workspace, tref);
return tref;
}
static void wm_toolsystem_update_from_context_view3d_impl(bContext *C, WorkSpace *workspace)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
int space_type = SPACE_VIEW3D;
const bToolKey tkey = {
.space_type = space_type,
.mode = WM_toolsystem_mode_from_spacetype(view_layer, NULL, space_type),
};
toolsystem_reinit_ensure_toolref(C, workspace, &tkey, NULL);
}
void WM_toolsystem_update_from_context_view3d(bContext *C)
{
WorkSpace *workspace = CTX_wm_workspace(C);
wm_toolsystem_update_from_context_view3d_impl(C, workspace);
/* Multi window support. */
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = bmain->wm.first;
if (!BLI_listbase_is_single(&wm->windows)) {
wmWindow *win_prev = CTX_wm_window(C);
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win != win_prev) {
WorkSpace *workspace_iter = WM_window_get_active_workspace(win);
if (workspace_iter != workspace) {
CTX_wm_window_set(C, win);
wm_toolsystem_update_from_context_view3d_impl(C, workspace_iter);
CTX_wm_window_set(C, win_prev);
CTX_wm_area_set(C, area_prev);
CTX_wm_region_set(C, region_prev);
}
}
}
}
}
void WM_toolsystem_update_from_context(bContext *C,
WorkSpace *workspace,
ViewLayer *view_layer,
ScrArea *area)
{
const bToolKey tkey = {
.space_type = area->spacetype,
.mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
};
if (toolsystem_key_ensure_check(&tkey)) {
toolsystem_reinit_ensure_toolref(C, workspace, &tkey, NULL);
}
}
/**
* 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 && (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)
{
ScrArea *area = msg_val->user_data;
Main *bmain = CTX_data_main(C);
wmWindow *win = ((wmWindowManager *)bmain->wm.first)->windows.first;
if (win->next != NULL) {
do {
bScreen *screen = WM_window_get_active_screen(win);
if (BLI_findindex(&screen->areabase, area) != -1) {
break;
}
} while ((win = win->next));
}
WorkSpace *workspace = WM_window_get_active_workspace(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
const bToolKey tkey = {
.space_type = area->spacetype,
.mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
};
WM_toolsystem_refresh(C, workspace, &tkey);
WM_toolsystem_refresh_screen_area(workspace, view_layer, area);
}
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;
}
bool WM_toolsystem_ref_properties_get_ex(bToolRef *tref,
const char *idname,
StructRNA *type,
PointerRNA *r_ptr)
{
IDProperty *group = tref->properties;
IDProperty *prop = group ? IDP_GetPropertyFromGroup(group, idname) : NULL;
RNA_pointer_create(NULL, type, prop, r_ptr);
return (prop != NULL);
}
void WM_toolsystem_ref_properties_ensure_ex(bToolRef *tref,
const char *idname,
StructRNA *type,
PointerRNA *r_ptr)
{
IDProperty *group = WM_toolsystem_ref_properties_ensure_idprops(tref);
IDProperty *prop = IDP_GetPropertyFromGroup(group, idname);
if (prop == NULL) {
IDPropertyTemplate val = {0};
prop = IDP_New(IDP_GROUP, &val, "wmGenericProperties");
STRNCPY(prop->name, idname);
IDP_ReplaceInGroup_ex(group, prop, NULL);
}
else {
BLI_assert(prop->type == IDP_GROUP);
}
RNA_pointer_create(NULL, type, prop, r_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) {
/* Important key-map items properties don't get overwritten by the tools.
* - When a key-map item doesn't set a property, the tool-systems is used.
* - When it does, it overrides the tool-system.
*
* This way the default action can be to follow the top-bar tool-settings &
* modifier keys can be used to perform different actions that aren't clobbered here.
*/
IDP_MergeGroup(dst_ptr->data, prop, false);
}
}
}