WIP: Brush assets project #106303
|
@ -107,10 +107,6 @@ def generate(context, space_type, *, use_fallback_keys=True, use_reset=True):
|
|||
kmi_hack_properties = kmi_hack.properties
|
||||
kmi_hack.active = False
|
||||
|
||||
kmi_hack_brush_select = keymap.keymap_items.new("paint.brush_select", 'NONE', 'PRESS')
|
||||
kmi_hack_brush_select_properties = kmi_hack_brush_select.properties
|
||||
kmi_hack_brush_select.active = False
|
||||
|
||||
if use_release_confirm or use_tap_reset:
|
||||
kmi_toolbar = wm.keyconfigs.find_item_from_operator(
|
||||
idname="wm.toolbar",
|
||||
|
@ -169,46 +165,6 @@ def generate(context, space_type, *, use_fallback_keys=True, use_reset=True):
|
|||
include={'KEYBOARD'},
|
||||
)[1]
|
||||
|
||||
if kmi_found is None:
|
||||
if item.data_block:
|
||||
# PAINT_OT_brush_select
|
||||
mode = context.active_object.mode
|
||||
# See: BKE_paint_get_tool_prop_id_from_paintmode
|
||||
if space_type == 'IMAGE_EDITOR':
|
||||
if context.space_data.mode == 'PAINT':
|
||||
attr = "image_tool"
|
||||
else:
|
||||
attr = None
|
||||
elif space_type == 'VIEW_3D':
|
||||
attr = {
|
||||
'SCULPT': "sculpt_tool",
|
||||
'VERTEX_PAINT': "vertex_tool",
|
||||
'WEIGHT_PAINT': "weight_tool",
|
||||
'TEXTURE_PAINT': "image_tool",
|
||||
'PAINT_GPENCIL': "gpencil_tool",
|
||||
'VERTEX_GPENCIL': "gpencil_vertex_tool",
|
||||
'SCULPT_GPENCIL': "gpencil_sculpt_tool",
|
||||
'WEIGHT_GPENCIL': "gpencil_weight_tool",
|
||||
'SCULPT_CURVES': "curves_sculpt_tool",
|
||||
}.get(mode, None)
|
||||
else:
|
||||
attr = None
|
||||
|
||||
if attr is not None:
|
||||
setattr(kmi_hack_brush_select_properties, attr, item.data_block)
|
||||
kmi_found = wm.keyconfigs.find_item_from_operator(
|
||||
idname="paint.brush_select",
|
||||
context='INVOKE_REGION_WIN',
|
||||
properties=kmi_hack_brush_select_properties,
|
||||
include={'KEYBOARD'},
|
||||
)[1]
|
||||
elif mode in {'EDIT', 'PARTICLE_EDIT', 'SCULPT_GPENCIL'}:
|
||||
# Doesn't use brushes
|
||||
pass
|
||||
else:
|
||||
print("Unsupported mode:", mode)
|
||||
del mode, attr
|
||||
|
||||
else:
|
||||
kmi_found = None
|
||||
|
||||
|
|
|
@ -5501,27 +5501,6 @@ def km_sculpt(params):
|
|||
op_menu_pie("VIEW3D_MT_sculpt_automasking_pie", {"type": 'A', "alt": True, "value": 'PRESS'}),
|
||||
op_menu_pie("VIEW3D_MT_sculpt_face_sets_edit_pie", {"type": 'W', "value": 'PRESS', "alt": True}),
|
||||
*_template_items_context_panel("VIEW3D_PT_sculpt_context_menu", params.context_menu_event),
|
||||
# Tools
|
||||
("paint.brush_select", {"type": 'V', "value": 'PRESS'},
|
||||
{"properties": [("sculpt_tool", 'DRAW')]}),
|
||||
("paint.brush_select", {"type": 'S', "value": 'PRESS'},
|
||||
{"properties": [("sculpt_tool", 'SMOOTH')]}),
|
||||
("paint.brush_select", {"type": 'P', "value": 'PRESS'},
|
||||
{"properties": [("sculpt_tool", 'PINCH')]}),
|
||||
("paint.brush_select", {"type": 'I', "value": 'PRESS'},
|
||||
{"properties": [("sculpt_tool", 'INFLATE')]}),
|
||||
("paint.brush_select", {"type": 'G', "value": 'PRESS'},
|
||||
{"properties": [("sculpt_tool", 'GRAB')]}),
|
||||
("paint.brush_select", {"type": 'T', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("sculpt_tool", 'SCRAPE')]}),
|
||||
("paint.brush_select", {"type": 'C', "value": 'PRESS'},
|
||||
{"properties": [("sculpt_tool", 'CLAY_STRIPS')]}),
|
||||
("paint.brush_select", {"type": 'C', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("sculpt_tool", 'CREASE')]}),
|
||||
("paint.brush_select", {"type": 'K', "value": 'PRESS'},
|
||||
{"properties": [("sculpt_tool", 'SNAKE_HOOK')]}),
|
||||
("paint.brush_select", {"type": 'M', "value": 'PRESS'},
|
||||
{"properties": [("sculpt_tool", 'MASK'), ("toggle", True), ("create_missing", True)]}),
|
||||
])
|
||||
|
||||
# Lasso Masking.
|
||||
|
|
|
@ -559,7 +559,6 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
|
|||
/* There are different kinds of shortcuts:
|
||||
*
|
||||
* - Direct access to the tool (as if the toolbar button is pressed).
|
||||
* - The key is bound to a brush type (not the exact brush name).
|
||||
* - The key is assigned to the operator itself
|
||||
* (bypassing the tool, executing the operator).
|
||||
*
|
||||
|
@ -567,36 +566,6 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
|
|||
*/
|
||||
std::string shortcut = UI_but_string_get_operator_keymap(*C, *but);
|
||||
|
||||
if (shortcut.empty()) {
|
||||
const PaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
|
||||
const char *tool_attr = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode);
|
||||
if (tool_attr != nullptr) {
|
||||
const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
|
||||
const char *tool_id_lstrip = strrchr(tool_id, '.');
|
||||
const int tool_id_offset = tool_id_lstrip ? ((tool_id_lstrip - tool_id) + 1) : 0;
|
||||
const int i = RNA_enum_from_name(items, tool_id + tool_id_offset);
|
||||
|
||||
if (i != -1) {
|
||||
wmOperatorType *ot = WM_operatortype_find("paint.brush_select", true);
|
||||
PointerRNA op_props;
|
||||
WM_operator_properties_create_ptr(&op_props, ot);
|
||||
RNA_enum_set(&op_props, tool_attr, items[i].value);
|
||||
|
||||
/* Check for direct access to the tool. */
|
||||
if (std::optional<std::string> shortcut_brush = WM_key_event_operator_string(
|
||||
C,
|
||||
ot->idname,
|
||||
WM_OP_INVOKE_REGION_WIN,
|
||||
static_cast<IDProperty *>(op_props.data),
|
||||
true))
|
||||
{
|
||||
shortcut = *shortcut_brush;
|
||||
}
|
||||
WM_operator_properties_free(&op_props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shortcut.empty()) {
|
||||
/* Check for direct access to the tool. */
|
||||
if (std::optional<std::string> shortcut_toolbar = WM_key_event_operator_string(
|
||||
|
|
|
@ -754,206 +754,6 @@ static void BRUSH_OT_reset(wmOperatorType *ot)
|
|||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static int brush_tool(const Brush *brush, size_t tool_offset)
|
||||
{
|
||||
return *(((char *)brush) + tool_offset);
|
||||
}
|
||||
|
||||
static void brush_tool_set(const Brush *brush, size_t tool_offset, int tool)
|
||||
{
|
||||
*(((char *)brush) + tool_offset) = tool;
|
||||
}
|
||||
|
||||
static Brush *brush_tool_cycle(Main *bmain, Paint *paint, Brush *brush_orig, const int tool)
|
||||
{
|
||||
Brush *brush, *first_brush;
|
||||
|
||||
if (!brush_orig && !(brush_orig = static_cast<Brush *>(bmain->brushes.first))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (brush_tool(brush_orig, paint->runtime.tool_offset) != tool) {
|
||||
/* If current brush's tool is different from what we need,
|
||||
* start cycling from the beginning of the list.
|
||||
* Such logic will activate the same exact brush not relating from
|
||||
* which tool user requests other tool.
|
||||
*/
|
||||
|
||||
/* Try to tool-slot first. */
|
||||
first_brush = BKE_paint_toolslots_brush_get(paint, tool);
|
||||
if (first_brush == nullptr) {
|
||||
first_brush = static_cast<Brush *>(bmain->brushes.first);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* If user wants to switch to brush with the same tool as
|
||||
* currently active brush do a cycling via all possible
|
||||
* brushes with requested tool. */
|
||||
first_brush = brush_orig->id.next ? static_cast<Brush *>(brush_orig->id.next) :
|
||||
static_cast<Brush *>(bmain->brushes.first);
|
||||
}
|
||||
|
||||
/* get the next brush with the active tool */
|
||||
brush = first_brush;
|
||||
do {
|
||||
if ((brush->ob_mode & paint->runtime.ob_mode) &&
|
||||
(brush_tool(brush, paint->runtime.tool_offset) == tool))
|
||||
{
|
||||
return brush;
|
||||
}
|
||||
|
||||
brush = brush->id.next ? static_cast<Brush *>(brush->id.next) :
|
||||
static_cast<Brush *>(bmain->brushes.first);
|
||||
} while (brush != first_brush);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Brush *brush_tool_toggle(Main *bmain, Paint *paint, Brush *brush_orig, const int tool)
|
||||
{
|
||||
if (!brush_orig || brush_tool(brush_orig, paint->runtime.tool_offset) != tool) {
|
||||
Brush *br;
|
||||
/* if the current brush is not using the desired tool, look
|
||||
* for one that is */
|
||||
br = brush_tool_cycle(bmain, paint, brush_orig, tool);
|
||||
/* store the previously-selected brush */
|
||||
if (br) {
|
||||
br->toggle_brush = brush_orig;
|
||||
}
|
||||
|
||||
return br;
|
||||
}
|
||||
if (brush_orig->toggle_brush) {
|
||||
/* if current brush is using the desired tool, try to toggle
|
||||
* back to the previously selected brush. */
|
||||
return brush_orig->toggle_brush;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool brush_generic_tool_set(bContext *C,
|
||||
Main *bmain,
|
||||
Paint *paint,
|
||||
const int tool,
|
||||
const char *tool_name,
|
||||
const bool create_missing,
|
||||
const bool toggle)
|
||||
{
|
||||
Brush *brush, *brush_orig = BKE_paint_brush(paint);
|
||||
|
||||
if (toggle) {
|
||||
brush = brush_tool_toggle(bmain, paint, brush_orig, tool);
|
||||
}
|
||||
else {
|
||||
brush = brush_tool_cycle(bmain, paint, brush_orig, tool);
|
||||
}
|
||||
|
||||
if (((brush == nullptr) && create_missing) &&
|
||||
((brush_orig == nullptr) || brush_tool(brush_orig, paint->runtime.tool_offset) != tool))
|
||||
{
|
||||
brush = BKE_brush_add(bmain, tool_name, eObjectMode(paint->runtime.ob_mode));
|
||||
id_us_min(&brush->id); /* fake user only */
|
||||
brush_tool_set(brush, paint->runtime.tool_offset, tool);
|
||||
brush->toggle_brush = brush_orig;
|
||||
}
|
||||
|
||||
if (brush) {
|
||||
BKE_paint_brush_set(paint, brush);
|
||||
BKE_paint_invalidate_overlay_all();
|
||||
|
||||
WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
|
||||
WM_toolsystem_ref_set_by_id(C, "builtin.brush");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const PaintMode brush_select_paint_modes[] = {
|
||||
PaintMode::Sculpt,
|
||||
PaintMode::Vertex,
|
||||
PaintMode::Weight,
|
||||
PaintMode::Texture3D,
|
||||
PaintMode::GPencil,
|
||||
PaintMode::VertexGPencil,
|
||||
PaintMode::SculptGPencil,
|
||||
PaintMode::WeightGPencil,
|
||||
PaintMode::SculptCurves,
|
||||
};
|
||||
|
||||
static int brush_select_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
const bool create_missing = RNA_boolean_get(op->ptr, "create_missing");
|
||||
const bool toggle = RNA_boolean_get(op->ptr, "toggle");
|
||||
const char *tool_name = "Brush";
|
||||
int tool = 0;
|
||||
|
||||
PaintMode paint_mode = PaintMode::Invalid;
|
||||
for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) {
|
||||
paint_mode = brush_select_paint_modes[i];
|
||||
const char *op_prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode);
|
||||
PropertyRNA *prop = RNA_struct_find_property(op->ptr, op_prop_id);
|
||||
if (RNA_property_is_set(op->ptr, prop)) {
|
||||
tool = RNA_property_enum_get(op->ptr, prop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (paint_mode == PaintMode::Invalid) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
|
||||
if (paint == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
// TODO: won't work with asset brushes, needs different main.
|
||||
if (brush_generic_tool_set(C, bmain, paint, tool, tool_name, create_missing, toggle)) {
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
static void PAINT_OT_brush_select(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Brush Select";
|
||||
ot->description = "Select a paint mode's brush by tool type";
|
||||
ot->idname = "PAINT_OT_brush_select";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = brush_select_exec;
|
||||
|
||||
/* flags */
|
||||
ot->flag = 0;
|
||||
|
||||
/* props */
|
||||
/* All properties are hidden, so as not to show the redo panel. */
|
||||
for (int i = 0; i < ARRAY_SIZE(brush_select_paint_modes); i++) {
|
||||
const PaintMode paint_mode = brush_select_paint_modes[i];
|
||||
const char *prop_id = BKE_paint_get_tool_prop_id_from_paintmode(paint_mode);
|
||||
prop = RNA_def_enum(
|
||||
ot->srna, prop_id, BKE_paint_get_tool_enum_from_paintmode(paint_mode), 0, prop_id, "");
|
||||
RNA_def_property_translation_context(
|
||||
prop, BKE_paint_get_tool_enum_translation_context_from_paintmode(paint_mode));
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
prop = RNA_def_boolean(
|
||||
ot->srna, "toggle", false, "Toggle", "Toggle between two brushes rather than cycling");
|
||||
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE));
|
||||
prop = RNA_def_boolean(ot->srna,
|
||||
"create_missing",
|
||||
false,
|
||||
"Create Missing",
|
||||
"If the requested brush type does not exist, create a new brush");
|
||||
RNA_def_property_flag(prop, PropertyFlag(PROP_HIDDEN | PROP_SKIP_SAVE));
|
||||
}
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
/**************************** Brush Assets **********************************/
|
||||
|
@ -2078,9 +1878,6 @@ void ED_operatortypes_paint()
|
|||
WM_operatortype_append(BRUSH_OT_asset_update);
|
||||
WM_operatortype_append(BRUSH_OT_asset_revert);
|
||||
|
||||
/* NOTE: particle uses a different system, can be added with existing operators in `wm.py`. */
|
||||
WM_operatortype_append(PAINT_OT_brush_select);
|
||||
|
||||
/* image */
|
||||
WM_operatortype_append(PAINT_OT_texture_paint_toggle);
|
||||
WM_operatortype_append(PAINT_OT_image_paint);
|
||||
|
|
Loading…
Reference in New Issue