Sculpt: UI organization

* Brush channels can now be grouped in
  categories.
* TODO: let user edit and create the
  categories.
This commit is contained in:
Joseph Eagar 2021-09-29 19:31:44 -07:00
parent 82bc438cfb
commit abbba7371f
4 changed files with 243 additions and 27 deletions

View File

@ -17,7 +17,168 @@
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
from bpy.types import Menu
from bpy.types import Menu, Panel
classes = []
class DynamicBrushCategoryPanel(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "Tool"
@classmethod
def poll(self, context):
ok = context.mode == "SCULPT" and context.tool_settings.sculpt and context.tool_settings.sculpt.brush
ok = ok and len(self.get_channels(context)) > 0
return ok
@classmethod
def get_channels(self, context):
brush = context.tool_settings.sculpt.brush
idname = self.get_category(self)
channels = list(filter(lambda ch: ch.show_in_workspace and ch.category == idname, brush.channels))
channels.sort(key=lambda ch: ch.ui_order)
return channels
def draw(self, context):
layout = self.layout
brush = context.tool_settings.sculpt.brush
idname = self.get_category()
opt = self.get_options()
layout.use_property_split = True
channels = self.get_channels(context)
for ch in channels:
ok = ch.show_in_workspace
ok = ok and ch.category == idname
if not ok:
continue
UnifiedPaintPanel.channel_unified(
layout,
context,
brush,
ch.idname,
slider=True,
ui_editing=opt["ui_editing"],
show_reorder=opt["show_reorder"])
class DynamicPaintPanelGen:
class Group:
def __init__(self, idname, name, prefix, parent):
self.idname = idname
self.name = name
self.prefix = prefix
self.rnaclass = None
self.parent = parent
self.options = {}
groups = {}
@staticmethod
def ensureCategory(idname, name=None, prefix="VIEW3D_PT_brush_category_", parent=None, show_reorder=False, ui_editing=False):
if name is None:
name = idname
groupid = prefix + idname.lower()
if groupid in DynamicPaintPanelGen.groups:
return DynamicPaintPanelGen.groups[groupid]
group = DynamicPaintPanelGen.Group(idname, name, prefix, parent)
DynamicPaintPanelGen.groups[groupid] = group
group.options={
"ui_editing" : ui_editing,
"show_reorder" : show_reorder
}
def callback():
print("creating panel")
DynamicPaintPanelGen.createPanel(group)
pass
import bpy
bpy.app.timers.register(callback)
return group
@staticmethod
def get(idname, prefix):
return DynamicPaintPanelGen.groups[idname]
@staticmethod
def createPanel(group):
from bpy.utils import register_class, unregister_class
from bpy.types import Panel
global classes
name = group.prefix + group.idname.lower()
name2 = ""
for c in name:
n = ord(c)
ok = n >= ord("a") and n <= ord("a")
ok = ok or n >= ord("A") and n <= ord("Z")
ok = ok or n >= ord("0") and n <= ord("9")
ok = ok or c == "_"
if not ok:
c = "_"
name2 += c
name = name2
for cls in classes[:]:
print("_", cls.bl_rna.identifier, cls.bl_rna.identifier == name) #r, dir(cls.bl_rna)) #.name)
if cls.bl_rna.identifier == name:
try:
unregister_class(cls)
except:
print("failed to unregister", name)
classes.remove(cls)
if group.parent:
parent = 'bl_parent_id = "%s"' % group.parent
else:
parent = ""
opt = repr(group.options)
code = """
global classes
class CLASSNAME (DynamicBrushCategoryPanel):
bl_label = "LABEL"
PARENT
def get_category(self):
return "IDNAME"
def get_options(self):
return OPT
register_class(CLASSNAME)
classes.append(CLASSNAME)
""".strip().replace("CLASSNAME", name).replace("PARENT", parent).replace("LABEL", group.name).replace("OPT", opt)
code = code.replace("IDNAME", group.idname)
print("\n", code)
exec(code)
channel_name_map = {
"size" : "radius",
@ -1556,15 +1717,30 @@ class ReorderBrushChannel(Operator):
return {'FINISHED'}
def brush_settings_channels(layout, context, brush, ui_editing=False, popover=False, filterkey="show_in_workspace"):
def brush_settings_channels(layout, context, brush, ui_editing=False, popover=False, show_reorder=None, filterkey="show_in_workspace",
parent="VIEW3D_PT_tools_brush_settings_channels", prefix="VIEW3D_PT_brush_category_"):
channels = get_ui_channels(brush.channels, [filterkey])
if show_reorder is None:
show_reorder = ui_editing
DynamicPaintPanelGen.ensureCategory("Basic", "Basic", parent=parent,
prefix=prefix, ui_editing=ui_editing,
show_reorder=show_reorder)
for ch in channels:
if len(ch.category) > 0:
DynamicPaintPanelGen.ensureCategory(ch.category, ch.category, parent=parent,
prefix=prefix, ui_editing=ui_editing,
show_reorder=show_reorder)
continue
#VIEW3D_PT_brush_category_edit_
UnifiedPaintPanel.channel_unified(
layout.column(),
context,
brush,
ch.idname, show_reorder = ui_editing, expand=False, ui_editing=False)
ch.idname, show_reorder = show_reorder, expand=False, ui_editing=ui_editing)
def brush_settings_advanced(layout, context, brush, popover=False):
@ -2047,10 +2223,10 @@ def brush_basic_gpencil_vertex_settings(layout, _context, brush, *, compact=Fals
row.prop(gp_settings, "vertex_mode", text="Mode")
classes = (
classes += [
VIEW3D_MT_tools_projectpaint_clone,
ReorderBrushChannel
)
]
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class

View File

@ -452,8 +452,13 @@ class VIEW3D_PT_tools_brush_settings_channels_preview(Panel, View3DPaintBrushPan
settings = self.paint_settings(context)
brush = settings.brush
brush_settings_channels(layout.column(), context, brush, show_reorder=True, ui_editing=False,
popover=self.is_popover,
prefix="VIEW3D_PT_brush_category_edit_",
parent="VIEW3D_PT_tools_brush_settings_channels_preview"
)
brush_settings_channels(layout.column(), context, brush, ui_editing=True, popover=self.is_popover)
class VIEW3D_PT_tools_brush_settings_advanced(Panel, View3DPaintBrushPanel):
bl_context = ".paint_common"

View File

@ -421,8 +421,8 @@ MAKE_ENUM(deform_target, "Deformation Target", "How the deformation of the brush
{-1}
})
MAKE_CURVE(autosmooth_falloff_curve, "Falloff", "Custom curve for autosmooth", BRUSH_CURVE_SMOOTH)
MAKE_CURVE(topology_rake_falloff_curve, "Falloff", "Custom curve for topolgoy rake", BRUSH_CURVE_SMOOTH)
MAKE_CURVE(autosmooth_falloff_curve, "Autosmooth Falloff", "Custom curve for autosmooth", BRUSH_CURVE_SMOOTH)
MAKE_CURVE(topology_rake_falloff_curve, "Rake Falloff", "Custom curve for topolgoy rake", BRUSH_CURVE_SMOOTH)
MAKE_CURVE(falloff_curve, "Falloff", "Falloff curve", BRUSH_CURVE_SMOOTH)
MAKE_FLOAT_EX(unprojected_radius, "Unprojected Radius", "Radius of brush in Blender units", 0.1f, 0.001, FLT_MAX, 0.001, 1.0f, false)
MAKE_ENUM_EX(radius_unit, "Radius Unit", "Measure brush size relative to the view or the scene", 0, BRUSH_CHANNEL_SHOW_IN_WORKSPACE, {\

View File

@ -212,7 +212,7 @@ static BrushChannelType *_get_def(const char *idname)
BLI_strncpy(GETDEF(idname)->category, cat, sizeof(GETDEF(idname)->category))
static bool do_builtin_init = true;
ATTR_NO_OPT static bool check_builtin_init()
static bool check_builtin_init()
{
if (!do_builtin_init || !BLI_thread_is_main()) {
return false;
@ -225,35 +225,70 @@ ATTR_NO_OPT static bool check_builtin_init()
// BKE_brush_channeltype_rna_check(brush_builtin_channels + i);
//}
SETCAT(strength, "Basic");
SETCAT(radius, "Basic");
SETCAT(direction, "Basic");
// don't group strength/radius/direction in subpanels
// SETCAT(strength, "Basic");
// SETCAT(radius, "Basic");
// SETCAT(direction, "Basic");
SETCAT(accumulate, "Basic");
SETCAT(tip_roundness, "Basic");
SETCAT(hardness, "Basic");
SETCAT(tip_scale_x, "Basic");
SETCAT(tip_roundness, "Basic");
SETCAT(normal_radius_factor, "Basic");
SETCAT(plane_offset, "Clay");
SETCAT(plane_trim, "Clay");
SETCAT(original_normal, "Clay");
SETCAT(original_plane, "Clay");
SETCAT(spacing, "Stroke");
SETCAT(use_space_attenuation, "Stroke");
SETCAT(autosmooth, "Smoothers");
SETCAT(autosmooth_projection, "Smoothers");
SETCAT(autosmooth_radius_scale, "Smoothers");
SETCAT(autosmooth_spacing, "Smoothers");
SETCAT(autosmooth_use_spacing, "Smoothers");
SETCAT(autosmooth, "Smoothing");
SETCAT(autosmooth_projection, "Smoothing");
SETCAT(autosmooth_radius_scale, "Smoothing");
SETCAT(autosmooth_spacing, "Smoothing");
SETCAT(autosmooth_use_spacing, "Smoothing");
SETCAT(topology_rake, "Smoothers");
SETCAT(topology_rake_radius_scale, "Smoothers");
SETCAT(topology_rake_projection, "Smoothers");
SETCAT(topology_rake_use_spacing, "Smoothers");
SETCAT(topology_rake_spacing, "Smoothers");
SETCAT(topology_rake, "Smoothing");
SETCAT(topology_rake_radius_scale, "Smoothing");
SETCAT(topology_rake_projection, "Smoothing");
SETCAT(topology_rake_use_spacing, "Smoothing");
SETCAT(topology_rake_spacing, "Smoothing");
SETCAT(boundary_smooth, "Smoothing");
SETCAT(fset_slide, "Smoothing");
SETCAT(preserve_faceset_boundary, "Smoothing");
SETCAT(use_weighted_smooth, "Smoothing");
SETCAT(boundary_offset, "Boundary Tool");
SETCAT(boundary_deform_type, "Boundary Tool");
SETCAT(boundary_falloff_type, "Boundary Tool");
SETCAT(cloth_deform_type, "Cloth Tool");
SETCAT(cloth_simulation_area_type, "Cloth Tool");
SETCAT(cloth_force_falloff_type, "Cloth Tool");
SETCAT(cloth_mass, "Cloth Tool");
SETCAT(cloth_damping, "Cloth Tool");
SETCAT(cloth_sim_limit, "Cloth Tool");
SETCAT(cloth_sim_falloff, "Cloth Tool");
SETCAT(cloth_constraint_softbody_strength, "Cloth Tool");
SETCAT(cloth_use_collision, "Cloth Tool");
SETCAT(cloth_pin_simulation_boundary, "Cloth Tool");
SETCAT(pose_offset, "Pose Tool");
SETCAT(pose_smooth_iterations, "Pose Tool");
SETCAT(pose_ik_segments, "Pose Tool");
SETCAT(use_pose_ik_anchored, "Pose Tool");
SETCAT(use_pose_lock_rotation, "Pose Tool");
SETCAT(pose_deform_type, "Pose Tool");
SETCAT(pose_origin_type, "Pose Tool");
SETCAT(pose_origin_type, "Pose Tool");
SETCAT(pose_origin_type, "Pose Tool");
SETCAT(pose_origin_type, "Pose Tool");
SETCAT(pose_origin_type, "Pose Tool");
SETCAT(pose_origin_type, "Pose Tool");
SETCAT(color, "Color");
SETCAT(secondary_color, "Color");
@ -1151,10 +1186,10 @@ void BKE_brush_channelset_ui_init(Brush *brush, int tool)
SHOWCTX(plane_trim);
break;
case SCULPT_TOOL_GRAB:
SHOWCTX(normal_weight);
SHOWWRK(normal_weight);
SHOWCTX(normal_weight);
SHOWWRK(normal_weight);
break;
break;
case SCULPT_TOOL_CLAY_STRIPS:
SHOWWRK(area_radius_factor);
SHOWWRK(plane_offset);