Fix #130527: Brush related keybinds do not import into 4.3 correctly

With the introduction of the brush assets project, there were a number
of changes to the overall API and UI that affect how user-defined
keymaps were made.

In all modes, users could either assign activating a brush via
right-clicking on the toolbar and assigning a shortcut, which would
bind to the `wm.set_tool_by_id` operator, or by manually inserting an
entry for `paint.brush_select`

For tools that have a one to one mapping for versions prior to 4.3
and ones post brush assets, we migrate the `wm.set_tool_by_id` `name`
property to the new name

For manually added entries, we swap from `paint.brush_select` to
activating the specific essential brush asset.

For Sculpt mode specifically, the number of tools in the toolbar
dropped significantly, any shortcuts that were created for these need
to be transitioned to activating a particular asset.

Finally, there are certain brushes that were expanded from a single
entry into multiple (e.g. multiple cloth brushes, paint brushes, etc)

For all of these cases, a reasonable default was picked.

Pull Request: https://projects.blender.org/blender/blender/pulls/130930
This commit is contained in:
Sean Kim
2024-12-02 19:54:29 +01:00
committed by Sean Kim
parent 3d9ffa5085
commit 66bbdeba77

View File

@@ -10,7 +10,10 @@
#define DNA_DEPRECATED_ALLOW
#include <cstring>
#include "fmt/format.h"
#include "BLI_listbase.h"
#include "BLI_map.hh"
#include "BLI_math_rotation.h"
#include "BLI_math_vector.h"
#include "BLI_string.h"
@@ -38,12 +41,15 @@
#include "BLT_translation.hh"
#include "DNA_brush_enums.h"
#include "GPU_platform.hh"
#include "MEM_guardedalloc.h"
#include "readfile.hh" /* Own include. */
#include "WM_keymap.hh"
#include "WM_types.hh"
#include "wm_event_types.hh"
@@ -301,6 +307,289 @@ static bool keymap_item_update_tweak_event(wmKeyMapItem *kmi, void * /*user_data
return false;
}
static void keymap_update_brushes_handle_add_item(
const blender::StringRef asset_prefix,
const blender::StringRef tool_property,
const blender::Map<blender::StringRef, blender::StringRefNull> &tool_tool_map,
const blender::Map<blender::StringRef, blender::StringRef> &tool_asset_map,
const blender::Map<int, blender::StringRef> &id_asset_map,
wmKeyMapItem *kmi)
{
std::optional<blender::StringRef> asset_id = {};
std::optional<blender::StringRefNull> tool_id = {};
if (STREQ(kmi->idname, "WM_OT_tool_set_by_id")) {
IDProperty *idprop = IDP_GetPropertyFromGroup(kmi->properties, "name");
if (idprop && (idprop->type == IDP_STRING)) {
const blender::StringRef prop_val = IDP_String(idprop);
if (!prop_val.startswith("builtin_brush.")) {
return;
}
if (tool_asset_map.contains(prop_val)) {
asset_id = tool_asset_map.lookup(prop_val);
}
else if (tool_tool_map.contains(prop_val)) {
tool_id = tool_tool_map.lookup(prop_val);
}
}
}
else if (STREQ(kmi->idname, "PAINT_OT_brush_select")) {
IDProperty *idprop = IDP_GetPropertyFromGroup(kmi->properties, tool_property);
if (idprop && (idprop->type == IDP_INT)) {
const int prop_val = IDP_Int(idprop);
if (id_asset_map.contains(prop_val)) {
asset_id = id_asset_map.lookup(prop_val);
}
}
}
if (asset_id) {
const std::string full_path = fmt::format("{}{}", asset_prefix, *asset_id);
WM_keymap_item_properties_reset(kmi, nullptr);
STRNCPY(kmi->idname, "BRUSH_OT_asset_activate");
IDP_AddToGroup(
kmi->properties,
blender::bke::idprop::create("asset_library_type", ASSET_LIBRARY_ESSENTIALS).release());
IDP_AddToGroup(kmi->properties,
blender::bke::idprop::create("relative_asset_identifier", full_path).release());
}
else if (tool_id) {
WM_keymap_item_properties_reset(kmi, nullptr);
IDP_AddToGroup(kmi->properties, blender::bke::idprop::create("name", *tool_id).release());
}
}
static void keymap_update_brushes_handle_remove_item(
const blender::StringRef asset_prefix,
const blender::StringRef tool_property,
const blender::Map<int, blender::StringRef> &id_asset_map,
wmKeyMapItem *kmi)
{
std::optional<blender::StringRef> asset_id = {};
/* Only the paint.brush_select operator is stored in the default keymap & applicable to be
* updated if the user removed it in a previous version. */
if (STREQ(kmi->idname, "PAINT_OT_brush_select")) {
IDProperty *idprop = IDP_GetPropertyFromGroup(kmi->properties, tool_property);
if (idprop && (idprop->type == IDP_INT)) {
const int prop_val = IDP_Int(idprop);
if (id_asset_map.contains(prop_val)) {
asset_id = id_asset_map.lookup(prop_val);
}
}
}
if (asset_id) {
const std::string full_path = fmt::format("{}{}", asset_prefix, *asset_id);
WM_keymap_item_properties_reset(kmi, nullptr);
STRNCPY(kmi->idname, "BRUSH_OT_asset_activate");
IDP_AddToGroup(
kmi->properties,
blender::bke::idprop::create("asset_library_type", ASSET_LIBRARY_ESSENTIALS).release());
IDP_AddToGroup(kmi->properties,
blender::bke::idprop::create("relative_asset_identifier", full_path).release());
}
}
static void keymap_update_brushes(
wmKeyMap *keymap,
const blender::StringRef asset_prefix,
const blender::StringRef tool_property,
const blender::Map<blender::StringRef, blender::StringRefNull> &tool_tool_map,
const blender::Map<blender::StringRef, blender::StringRef> &tool_asset_map,
const blender::Map<int, blender::StringRef> &id_asset_map)
{
LISTBASE_FOREACH (wmKeyMapDiffItem *, kmid, &keymap->diff_items) {
if (kmid->add_item) {
keymap_update_brushes_handle_add_item(asset_prefix,
tool_property,
tool_tool_map,
tool_asset_map,
id_asset_map,
kmid->add_item);
}
if (kmid->remove_item) {
keymap_update_brushes_handle_remove_item(
asset_prefix, tool_property, id_asset_map, kmid->remove_item);
}
}
}
static void keymap_update_mesh_sculpt_brushes(wmKeyMap *keymap)
{
constexpr blender::StringRef asset_prefix =
"brushes/essentials_brushes-mesh_sculpt.blend/Brush/";
constexpr blender::StringRef tool_property = "sculpt_tool";
const auto tool_asset_map = []() {
blender::Map<blender::StringRef, blender::StringRef> map;
map.add_new("builtin_brush.Draw Sharp", "Draw Sharp");
map.add_new("builtin_brush.Clay", "Clay");
map.add_new("builtin_brush.Clay Strips", "Clay Strips");
map.add_new("builtin_brush.Clay Thumb", "Clay Thumb");
map.add_new("builtin_brush.Layer", "Layer");
map.add_new("builtin_brush.Inflate", "Inflate/Deflate");
map.add_new("builtin_brush.Blob", "Blob");
map.add_new("builtin_brush.Crease", "Crease Polish");
map.add_new("builtin_brush.Smooth", "Smooth");
map.add_new("builtin_brush.Flatten", "Flatten/Contrast");
map.add_new("builtin_brush.Fill", "Fill/Deepen");
map.add_new("builtin_brush.Scrape", "Scrape/Fill");
map.add_new("builtin_brush.Multi-plane Scrape", "Scrape Multiplane");
map.add_new("builtin_brush.Pinch", "Pinch/Magnify");
map.add_new("builtin_brush.Grab", "Grab");
map.add_new("builtin_brush.Elastic Deform", "Elastic Grab");
map.add_new("builtin_brush.Snake Hook", "Snake Hook");
map.add_new("builtin_brush.Thumb", "Thumb");
map.add_new("builtin_brush.Pose", "Pose");
map.add_new("builtin_brush.Nudge", "Nudge");
map.add_new("builtin_brush.Rotate", "Twist");
map.add_new("builtin_brush.Slide Relax", "Relax Slide");
map.add_new("builtin_brush.Boundary", "Boundary");
map.add_new("builtin_brush.Cloth", "Drag Cloth");
map.add_new("builtin_brush.Simplify", "Density");
map.add_new("builtin_brush.Multires Displacement Eraser", "Erase Multires Displacement");
map.add_new("builtin_brush.Multires Displacement Smear", "Smear Multires Displacement");
map.add_new("builtin_brush.Smear", "Smear");
return map;
}();
const auto tool_tool_map = []() {
blender::Map<blender::StringRef, blender::StringRefNull> map;
map.add_new("builtin_brush.Draw", "builtin.brush");
map.add_new("builtin_brush.Paint", "builtin_brush.paint");
map.add_new("builtin_brush.Mask", "builtin_brush.mask");
map.add_new("builtin_brush.Draw Face Sets", "builtin_brush.draw_face_sets");
return map;
}();
const auto id_asset_map = []() {
blender::Map<int, blender::StringRef> map;
map.add_new(SCULPT_BRUSH_TYPE_DRAW, "Draw");
map.add_new(SCULPT_BRUSH_TYPE_DRAW_SHARP, "Draw Sharp");
map.add_new(SCULPT_BRUSH_TYPE_CLAY, "Clay");
map.add_new(SCULPT_BRUSH_TYPE_CLAY_STRIPS, "Clay Strips");
map.add_new(SCULPT_BRUSH_TYPE_CLAY_THUMB, "Clay Thumb");
map.add_new(SCULPT_BRUSH_TYPE_LAYER, "Layer");
map.add_new(SCULPT_BRUSH_TYPE_INFLATE, "Inflate/Deflate");
map.add_new(SCULPT_BRUSH_TYPE_BLOB, "Blob");
map.add_new(SCULPT_BRUSH_TYPE_CREASE, "Crease Polish");
map.add_new(SCULPT_BRUSH_TYPE_SMOOTH, "Smooth");
map.add_new(SCULPT_BRUSH_TYPE_FLATTEN, "Flatten/Contrast");
map.add_new(SCULPT_BRUSH_TYPE_FILL, "Fill/Deepen");
map.add_new(SCULPT_BRUSH_TYPE_SCRAPE, "Scrape/Fill");
map.add_new(SCULPT_BRUSH_TYPE_MULTIPLANE_SCRAPE, "Scrape Multiplane");
map.add_new(SCULPT_BRUSH_TYPE_PINCH, "Pinch/Magnify");
map.add_new(SCULPT_BRUSH_TYPE_GRAB, "Grab");
map.add_new(SCULPT_BRUSH_TYPE_ELASTIC_DEFORM, "Elastic Grab");
map.add_new(SCULPT_BRUSH_TYPE_SNAKE_HOOK, "Snake Hook");
map.add_new(SCULPT_BRUSH_TYPE_THUMB, "Thumb");
map.add_new(SCULPT_BRUSH_TYPE_POSE, "Pose");
map.add_new(SCULPT_BRUSH_TYPE_NUDGE, "Nudge");
map.add_new(SCULPT_BRUSH_TYPE_ROTATE, "Twist");
map.add_new(SCULPT_BRUSH_TYPE_SLIDE_RELAX, "Relax Slide");
map.add_new(SCULPT_BRUSH_TYPE_BOUNDARY, "Boundary");
map.add_new(SCULPT_BRUSH_TYPE_CLOTH, "Drag Cloth");
map.add_new(SCULPT_BRUSH_TYPE_SIMPLIFY, "Density");
map.add_new(SCULPT_BRUSH_TYPE_MASK, "Mask");
map.add_new(SCULPT_BRUSH_TYPE_DRAW_FACE_SETS, "Face Set Paint");
map.add_new(SCULPT_BRUSH_TYPE_DISPLACEMENT_ERASER, "Erase Multires Displacement");
map.add_new(SCULPT_BRUSH_TYPE_DISPLACEMENT_SMEAR, "Smear Multires Displacement");
map.add_new(SCULPT_BRUSH_TYPE_PAINT, "Paint Hard");
map.add_new(SCULPT_BRUSH_TYPE_SMEAR, "Smear");
return map;
}();
keymap_update_brushes(
keymap, asset_prefix, tool_property, tool_tool_map, tool_asset_map, id_asset_map);
}
static void keymap_update_mesh_vertex_paint_brushes(wmKeyMap *keymap)
{
constexpr blender::StringRef asset_prefix =
"brushes/essentials_brushes-mesh_vertex.blend/Brush/";
constexpr blender::StringRef tool_property = "vertex_tool";
const auto tool_tool_map = []() {
blender::Map<blender::StringRef, blender::StringRefNull> map;
map.add_new("builtin_brush.Draw", "builtin.brush");
map.add_new("builtin_brush.Blur", "builtin_brush.blur");
map.add_new("builtin_brush.Average", "builtin_brush.average");
map.add_new("builtin_brush.Smear", "builtin_brush.smear");
return map;
}();
const auto id_asset_map = []() {
blender::Map<int, blender::StringRef> map;
map.add_new(VPAINT_BRUSH_TYPE_DRAW, "Paint Hard");
map.add_new(VPAINT_BRUSH_TYPE_BLUR, "Blur");
map.add_new(VPAINT_BRUSH_TYPE_AVERAGE, "Average");
map.add_new(VPAINT_BRUSH_TYPE_SMEAR, "Smear");
return map;
}();
keymap_update_brushes(keymap, asset_prefix, tool_property, tool_tool_map, {}, id_asset_map);
}
static void keymap_update_mesh_weight_paint_brushes(wmKeyMap *keymap)
{
constexpr blender::StringRef asset_prefix =
"brushes/essentials_brushes-mesh_weight.blend/Brush/";
constexpr blender::StringRef tool_property = "weight_tool";
const auto tool_tool_map = []() {
blender::Map<blender::StringRef, blender::StringRefNull> map;
map.add_new("builtin_brush.Draw", "builtin.brush");
map.add_new("builtin_brush.Blur", "builtin_brush.blur");
map.add_new("builtin_brush.Average", "builtin_brush.average");
map.add_new("builtin_brush.Smear", "builtin_brush.smear");
return map;
}();
const auto asset_id_map = []() {
blender::Map<int, blender::StringRef> map;
map.add_new(WPAINT_BRUSH_TYPE_DRAW, "Paint");
map.add_new(WPAINT_BRUSH_TYPE_BLUR, "Blur");
map.add_new(WPAINT_BRUSH_TYPE_AVERAGE, "Average");
map.add_new(WPAINT_BRUSH_TYPE_SMEAR, "Smear");
return map;
}();
keymap_update_brushes(keymap, asset_prefix, tool_property, tool_tool_map, {}, asset_id_map);
}
static void keymap_update_mesh_texture_paint_brushes(wmKeyMap *keymap)
{
constexpr blender::StringRef asset_prefix =
"brushes/essentials_brushes-mesh_texture.blend/Brush/";
constexpr blender::StringRef tool_property = "image_tool";
const auto tool_tool_map = []() {
blender::Map<blender::StringRef, blender::StringRefNull> map;
map.add_new("builtin_brush.Draw", "builtin.brush");
map.add_new("builtin_brush.Soften", "builtin_brush.soften");
map.add_new("builtin_brush.Smear", "builtin_brush.smear");
map.add_new("builtin_brush.Clone", "builtin_brush.clone");
map.add_new("builtin_brush.Fill", "builtin_brush.fill");
map.add_new("builtin_brush.Mask", "builtin_brush.mask");
return map;
}();
const auto id_asset_map = []() {
blender::Map<int, blender::StringRef> map;
map.add_new(IMAGE_PAINT_BRUSH_TYPE_DRAW, "Paint Hard");
map.add_new(IMAGE_PAINT_BRUSH_TYPE_SOFTEN, "Blur");
map.add_new(IMAGE_PAINT_BRUSH_TYPE_SMEAR, "Smear");
map.add_new(IMAGE_PAINT_BRUSH_TYPE_CLONE, "Clone");
map.add_new(IMAGE_PAINT_BRUSH_TYPE_FILL, "Fill");
map.add_new(IMAGE_PAINT_BRUSH_TYPE_MASK, "Mask");
return map;
}();
keymap_update_brushes(keymap, asset_prefix, tool_property, tool_tool_map, {}, id_asset_map);
}
void blo_do_versions_userdef(UserDef *userdef)
{
/* #UserDef & #Main happen to have the same struct member. */
@@ -1068,6 +1357,24 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->sequencer_editor_flag |= USER_SEQ_ED_CONNECT_STRIPS_BY_DEFAULT;
}
if (!USER_VERSION_ATLEAST(403, 33)) {
LISTBASE_FOREACH (wmKeyMap *, keymap, &userdef->user_keymaps) {
if (STREQ("Sculpt", keymap->idname)) {
keymap_update_mesh_sculpt_brushes(keymap);
}
else if (STREQ("Vertex Paint", keymap->idname)) {
keymap_update_mesh_vertex_paint_brushes(keymap);
}
else if (STREQ("Weight Paint", keymap->idname)) {
keymap_update_mesh_weight_paint_brushes(keymap);
}
else if (STREQ("Image Paint", keymap->idname)) {
keymap_update_mesh_texture_paint_brushes(keymap);
}
}
}
if (!USER_VERSION_ATLEAST(404, 3)) {
userdef->uiflag &= ~USER_FILTER_BRUSHES_BY_TOOL;