MegaBag/data/bpy_sys.py

408 lines
19 KiB
Python

#!/usr/bin/env python -------------------------------- -*- coding: utf-8 -*-#
# 2023 3DMish <Mish7913@gmail.com> #
# ----- ##### 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. #
# #
# ----- ##### END GPL LICENSE BLOCK ##### ----- #
import bpy, os;
def ver_less(v1, v2, v3): return True if ((v1, v2, v3) > bpy.app.version) else False;
def ver_more(v1, v2, v3): return True if ((v1, v2, v3) <= bpy.app.version) else False;
if ver_more(2,78,0): import bpy.utils.previews;
if ver_more(2,60,0): lc_prew = bpy.utils.previews.new();
data_path = os.path.dirname(os.path.abspath(__file__));
icons_path = os.path.dirname(os.path.abspath(__file__)) + "/m7a_icons";
addon_id = os.path.basename(os.path.abspath(os.path.join(__file__, os.pardir, os.pardir)));
if (ver_more(2,80,0)): asset_libraries = bpy.context.preferences.filepaths.asset_libraries;
user_path = bpy.utils.resource_path('USER');
config_path = os.path.join(user_path, "config");
# --------------------------------------------------------
def m7a_load_icon(image):
if (image in lc_prew): thumb = lc_prew[image];
else: thumb = lc_prew.load(image, image, 'IMAGE');
return thumb.icon_id;
def lc_icon (code):
path = data_path + "/m7a_icons/";
images = {
"KNIFE": m7a_load_icon(path + "m7a_knife" + ".png"),
"LOOP_CUT": m7a_load_icon(path + "m7a_loop_cut" + ".png"),
"INSET": m7a_load_icon(path + "m7a_inset" + ".png"),
"EXTRUDE": m7a_load_icon(path + "m7a_extrude" + ".png"),
"EXTRUDE_NORMALS": m7a_load_icon(path + "m7a_extrude_normals" + ".png"),
"EDGE_SLIDE": m7a_load_icon(path + "m7a_edge_slide" + ".png"),
"VERTEX_SLIDE": m7a_load_icon(path + "m7a_vertex_slide" + ".png"),
"X0": m7a_load_icon(path + "m7a_x0" + ".png"),
"FILL": m7a_load_icon(path + "m7a_fill" + ".png"),
"FILL_GRID": m7a_load_icon(path + "m7a_fill_grid" + ".png"),
"VIEW_3D": m7a_load_icon(path + "m7a_view3d" + ".png"),
"TO_QUADS": m7a_load_icon(path + "m7a_to_quads" + ".png"),
"BIRD": m7a_load_icon(path + "m7a_bird" + ".png"),
"EXTRUDE_INTERSECT": m7a_load_icon(path + "m7a_extrude_intersect" + ".png"),
"FROSTING": m7a_load_icon(path + "m7a_frosting" + ".png"),
"FLOWER": m7a_load_icon(path + "m7a_flower" + ".png"),
"SPRINKLES": m7a_load_icon(path + "m7a_sprinkles" + ".png"),
"CHERRY": m7a_load_icon(path + "m7a_cherry" + ".png"),
"LIGHTNING": m7a_load_icon(path + "m7a_lightning" + ".png"),
"BEADS_WIREFRAME": m7a_load_icon(path + "m7a_beads_wireframe" + ".png"),
"ELECTRIC": m7a_load_icon(path + "m7a_electric" + ".png"),
"CIRCLE_ARRAY": m7a_load_icon(path + "m7a_circle_array" + ".png"),
"BRIDGE": m7a_load_icon(path + "m7a_bridge" + ".png"),
"DUPLICATE": m7a_load_icon(path + "m7a_duplicate" + ".png"),
"DUPLICATE_LINKED": m7a_load_icon(path + "m7a_duplicate_linked" + ".png"),
"MALE": m7a_load_icon(path + "m7a_male" + ".png"),
"FEMALE": m7a_load_icon(path + "m7a_female" + ".png"),
"DEL_KEYS": m7a_load_icon(path + "m7a_delete_keys" + ".png"),
"DUP_MOVE": m7a_load_icon(path + "m7a_duplicate_move" + ".png"),
"COLOR_FILL": m7a_load_icon(path + "m7a_to_fill" + ".png"),
"KEYBOARD": m7a_load_icon(path + "m7a_keyboard" + ".png"),
}
if code in images: return images[code];
else: return 0;
# --------------------------------------------------------
def lc_split_row (lc_layout, width, align=True):
return lc_layout.row(align=align) if (lc_width() > width) else lc_layout;
def lc_width (): return bpy.context.region.width;
def lc_min (width): return lc_width() > width;
def lc_set_width (lc_element, width, width_x = 0):
if ver_more(2,80,0): lc_element.ui_units_x = width;
else: lc_element.scale_x = width/10 if (width_x == 0) else width_x;
def lc_cont_x (lc_layout, width=1.0, is_row=True, active=True, is_align=True, alert=False):
if is_row: lc_cont_btn = lc_layout.row(align=is_align);
else: lc_cont_btn = lc_layout.column(align=is_align);
lc_cont_btn.scale_x = width if ver_more(2,80,0) else width+0.05 if (width != 1.0) else width;
lc_cont_btn.active = active;
lc_cont_btn.alert = alert;
return lc_cont_btn;
def lc_scale (lc_layout, width=1.0, is_row=True, active=True, is_align=True, y=None):
if is_row: lc_cont_btn = lc_layout.row(align=is_align);
else: lc_cont_btn = lc_layout.column(align=is_align);
lc_cont_btn.scale_x = width;
lc_cont_btn.scale_y = y if (y != None) else width;
lc_cont_btn.active = active;
return lc_cont_btn;
def lc_cont_y (lc_layout, height=1.0, is_row=True, active=True):
if is_row: lc_cont_btn = lc_layout.row(align=True);
else: lc_cont_btn = lc_layout.column(align=True);
lc_cont_btn.scale_y = height;
lc_cont_btn.active = active;
return lc_cont_btn;
def lc_fixed (lc_layout, value, is_row=True):
if is_row: lc_cont_btn = lc_layout.row(align=True);
else: lc_cont_btn = lc_layout.column(align=True);
lc_cont_btn.ui_units_x = value;
lc_cont_btn.scale_y = value;
return lc_cont_btn;
def lc_fixed_x (lc_layout, width, is_row=True):
if is_row: lc_cont_btn = lc_layout.row(align=True);
else: lc_cont_btn = lc_layout.column(align=True);
lc_cont_btn.ui_units_x = width;
return lc_cont_btn;
# --------------------------------------------------------
def lc_return (small, large, min = None, max = None):
if (min != None) and (max != None):
return small if (lc_width() > min) and (lc_width() < max) else large;
elif (min != None) and (max == None):
return small if (lc_width() > min) else large;
elif (min == None) and (max != None):
return small if (lc_width() < max) else large;
else: return small;
# --------------------------------------------------------
def q_register_class (classes):
for cls in classes:
if (cls):
try: bpy.utils.register_class(cls);
except: pass
def q_unregister_class (classes):
for cls in classes:
if (cls):
try: bpy.utils.unregister_class(cls);
except: pass
# --------------------------------------------------------
def r_remove_attr (cont, name):
if hasattr(cont, name): delattr(cont, name);
def r_register_class (cont, name = ""):
def func_reg (f_name):
if not (hasattr(bpy.types, f_name)) and (f_name in cont):
if (cont[f_name] != None):
bpy.utils.register_class(cont[f_name]);
if (name == ""):
for key in cont.keys():
func_reg (key);
else: func_reg (name);
def r_unregister_class (cont, name = ""):
def func_unreg (f_name):
if hasattr(bpy.types, f_name):
if not (cont == None): cont[f_name] = getattr(bpy.types, f_name);
bpy.utils.unregister_class(getattr(bpy.types, f_name));
if (name == ""):
for key in cont.keys():
func_unreg (key);
else: func_unreg (name);
# --------------------------------------------------------
def bpy_preferences (path = "", name = ""):
if (path == "addons"):
if ver_more(2,80,0):
if (name in bpy.context.preferences.addons.keys()):
return bpy.context.preferences.addons[name].preferences;
else: return None;
else:
if (name in bpy.context.user_preferences.addons.keys()):
return bpy.context.user_preferences.addons[name].preferences;
else: return None;
else:
if ver_more(2,80,0): return bpy.context.preferences;
else: return bpy.context.user_preferences;
# --------------------------------------------------------
def get_prop (prop_name):
if hasattr(bpy_preferences("addons", addon_id), "m7a_props"):
if hasattr(bpy_preferences("addons", addon_id).m7a_props, prop_name):
return getattr(bpy_preferences("addons", addon_id).m7a_props, prop_name);
return False;
def get_class (cont, name):
if hasattr(bpy.types, name):
return getattr(bpy.types, name);
else: return None;
# --------------------------------------------------------
def lc_switcher (lc_layout, context, label, icon, convert=True, asset=True, delete=True):
a_obj = context.active_object;
lc_row = lc_layout.row(align=True);
lc_row.label(text=label, icon=icon);
if (convert):
if ver_more(3,0,0): lc_row.menu("VIEW3D_MT_object_convert", text="", icon="MAT_SPHERE_SKY");
else: lc_row.operator_menu_enum("object.convert", "target", text="", icon="MAT_SPHERE_SKY")
if ver_more(3,0,0):
if (asset) and not (context.mode.split("_")[0] in {"EDIT", "PAINT", "SCULPT", "VERTEX"}):
lc_row.separator();
if not (a_obj.asset_data): lc_row.operator("asset.mark", text="", icon="ASSET_MANAGER", emboss=False);
else: lc_row.operator("asset.clear", text="", icon="ASSET_MANAGER", depress=True).set_fake_user = False;
lc_row_append = lc_row.row(align = True);
if (delete):
lc_row_del = lc_row.row(align = True);
lc_row_del.separator();
lc_row_del.operator("object.delete", text="", icon="TRASH" if ver_more(3,0,0) else "ZOOMOUT", emboss=False);
lc_row_del.active = not (context.selected_objects == []);
return lc_row_append;
def lc_add_btn (lc_layout, id, text="", icon=None, mode=None, toggle=None, hint=None):
lc_layout.separator();
if (icon == None): lc_btn = lc_layout.operator(id, text=text, emboss=False);
else: lc_btn = lc_layout.operator(id, text=text, icon=icon, emboss=False);
if (hint != None): lc_btn.hint = "Set UI Mode: " + hint;
if (mode != None): lc_btn.mode = mode;
if (mode != None): lc_btn.toggle = toggle;
return lc_btn;
def lc_tool_data():
return bpy.context.workspace.tools.from_space_view3d_mode(bpy.context.mode, create=False);
def lc_panel (lc_layout, context, lc_prop, lc_label, lc_icon=None, add_btn=None, empty=False, c_label=""):
lc_box = lc_layout.box().column(align = True); is_open = False;
lc_icon_1 = "DOWNARROW_HLT" if ver_more(3,0,0) else "TRIA_DOWN";
lc_icon_2 = "RIGHTARROW" if ver_more(3,0,0) else "TRIA_RIGHT";
lc_label_row = lc_box.row(align = True);
lc_label_opt = lc_label_row.row(align = True);
if (empty): lc_label_row.label(text=lc_label, icon="DOT");
lc_label_row.separator();
if not (empty):
if (getattr(context.scene, lc_prop)):
if (add_btn == None) and (lc_icon != None):
lc_label_row.label(text="", icon=lc_icon);
lc_box.separator(); is_open = True;
else:
if (lc_icon != None):
lc_label_row.label(text="", icon=lc_icon);
lc_label_opt.prop(
context.scene, lc_prop, emboss=False,
icon=lc_icon_1 if (getattr(context.scene, lc_prop)) else lc_icon_2,
text=lc_label if (is_open == False) else c_label if (c_label != "") else lc_label,
);
return lc_box, lc_label_row, is_open;
def lc_center_label (lc_layout, text):
lc_row = lc_layout.row(align = True);
lc_row.alignment = "CENTER";
lc_row.label(text=text);
return lc_row;
# --------------------------------------------------------
def lc_template_switcher (lc_main, context):
if (context.object):
lc_icon_name = context.object.type.upper();
lc_icon_name = lc_icon_name.replace("LIGHT_PROBE", "LIGHTPROBE");
lc_icon_name = lc_icon_name.replace("GPENCIL", "GREASEPENCIL");
lc_text_name = context.object.type.replace("_", " ").title();
lc_swtch_row = lc_switcher(
lc_main, context, lc_text_name,
icon="OUTLINER_DATA_"+lc_icon_name,
convert=context.object.type in {'MESH','CURVE','SURFACE','GPENCIL','FONT'} and context.mode in {"OBJECT"},
delete=context.mode in {"OBJECT","EDIT_CURVE","EDIT_ARMATURE","POSE",
'EDIT_TEXT','EDIT_METABALL','EDIT_LATTICE'},
asset=ver_more(2,79,5)
);
sw = 240 if ver_more(2,79,5) else 180;
if (context.object.type in {'MESH'}):
if (context.mode in {"OBJECT"}):
if lc_min(sw): lc_add_btn(lc_swtch_row, "object.mode_set", "", "VPAINT_HLT", 'VERTEX_PAINT', False);
if lc_min(sw+30):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "TPAINT_HLT", 'TEXTURE_PAINT', False);
if lc_min(sw+50):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "WPAINT_HLT", 'WEIGHT_PAINT', False);
lc_add_btn(lc_swtch_row, "object.mode_set", "", "EDITMODE_HLT", 'EDIT', False);
if lc_min(sw+70):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "SCULPTMODE_HLT", 'SCULPT', False);
else: # -------------------------------------------------------------------------------------
if (context.mode not in {"PAINT_VERTEX"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "VPAINT_HLT", 'VERTEX_PAINT', False);
if (context.mode not in {"SCULPT"}):
if ver_more(2,79,5) or lc_min(sw+30):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "SCULPTMODE_HLT", 'SCULPT', False);
if (context.mode not in {"EDIT_MESH"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "EDITMODE_HLT", 'EDIT', False);
if (context.mode not in {"PAINT_WEIGHT"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "WPAINT_HLT", 'WEIGHT_PAINT', False);
lc_add_btn(lc_swtch_row, "object.mode_set", "", "OBJECT_DATAMODE", 'OBJECT', False);
if (context.mode not in {"PAINT_TEXTURE"}) and lc_min(sw):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "TPAINT_HLT", 'TEXTURE_PAINT', False);
elif (context.object.type in {'CURVE', 'FONT', 'META', 'LATTICE'}):
if (context.mode in {"OBJECT"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "EDITMODE_HLT", 'EDIT', False);
else: # -------------------------------------------------------------------------------------
lc_add_btn(lc_swtch_row, "object.mode_set", "", "OBJECT_DATAMODE", 'OBJECT', False);
elif (context.object.type == "ARMATURE"):
if (context.mode in {"OBJECT"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "EDITMODE_HLT", 'EDIT', False);
lc_add_btn(lc_swtch_row, "object.mode_set", "", "ARMATURE_DATA", 'POSE', False);
else: # -------------------------------------------------------------------------------------
if (context.mode not in {"EDIT_ARMATURE"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "EDITMODE_HLT", 'EDIT', False);
lc_add_btn(lc_swtch_row, "object.mode_set", "", "OBJECT_DATAMODE", 'OBJECT', False);
if (context.mode not in {"POSE"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "ARMATURE_DATA", 'POSE', False);
elif (context.object.type == "GPENCIL"):
if (context.mode in {"OBJECT"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "GREASEPENCIL", 'PAINT_GPENCIL', False);
if lc_min(sw+30):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "EDITMODE_HLT", 'EDIT_GPENCIL', False);
if lc_min(sw+50):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "SCULPTMODE_HLT", 'SCULPT_GPENCIL', False);
else: # -------------------------------------------------------------------------------------
if (context.mode not in {"SCULPT_GPENCIL"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "SCULPTMODE_HLT", 'SCULPT_GPENCIL', False);
if (context.mode not in {"PAINT_GPENCIL"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "GREASEPENCIL", 'PAINT_GPENCIL', False);
if (context.mode not in {"EDIT_GPENCIL"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "EDITMODE_HLT", 'EDIT_GPENCIL', False);
lc_add_btn(lc_swtch_row, "object.mode_set", "", "OBJECT_DATAMODE", 'OBJECT', False);
if (context.mode not in {"VERTEX_GPENCIL"}):
lc_add_btn(lc_swtch_row, "object.mode_set", "", "VPAINT_HLT", 'VERTEX_GPENCIL', False);
# --------------------------------------------------------
def new_asset_path (name, path):
bpy.ops.preferences.asset_library_add();
asset = asset_libraries[''];
asset.name = name; asset.path = path;
return asset;
def remove_asset_path (name):
for i in range(0, len(asset_libraries)):
if (asset_libraries[i].name == name):
bpy.ops.preferences.asset_library_remove(i);
break;
def is_exist_asset_pack (name): return name in asset_libraries;
# --------------------------------------------------------
def bezier (value, h1, h2):
v2 = 1 - value;
return 3.0 * (v2 ** 2.0 * value) * h1 + 3.0 * (v2 * value ** 2.0) * h2 + value ** 3.0;
def float_curve (input): return bezier(input, 0.010575, 0.2393);
# --------------------------------------------------------
def lc_space_separator (cont, left_size, right_size, center_size = 0, math = 1):
if ver_more(2,79,5):
return cont.separator_spacer();
else:
lc_size = lc_width();
if ((left_size+right_size+center_size) < lc_size):
scale = ((lc_size-(left_size+right_size+center_size))/33)/math;
lc_separator = lc_cont_x(cont, width=scale).label(text=" ");
return lc_separator;
# --------------------------------------------------------
def get_data_display_type (obj):
if ver_less(2,79,5): return obj.data.draw_type;
else: return obj.data.display_type;