update addons (for 5.2)

This commit is contained in:
Nathan
2026-07-14 14:44:58 -06:00
parent a232ea1c9c
commit e3310263f3
246 changed files with 21097 additions and 9607 deletions
@@ -1,4 +1,4 @@
Documentation: https://weisl.github.io/renaming_overview/
Documentation: https://weisl.github.io/simple_renaming/renaming_overview/
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/donate?hosted_button_id=JV7KRF77TY78A)
@@ -18,22 +18,11 @@ Created by Matthias Patscheider
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
# support reloading sub-modules
if "bpy" in locals():
import importlib
importlib.reload(add_suffix_panel)
importlib.reload(operators)
importlib.reload(preferences)
importlib.reload(ui)
importlib.reload(variable_replacer)
else:
from . import add_suffix_panel
from . import operators
from . import preferences
from . import ui
from . import variable_replacer
from . import add_suffix_panel
from . import operators
from . import preferences
from . import ui
from . import variable_replacer
files = [
add_suffix_panel,
@@ -245,7 +245,7 @@ class VIEW3D_OT_add_type_suf_pre(bpy.types.Operator):
obj_list = []
for obj in self.get_selection_all():
if obj.type == 'GPENCIL':
if obj.type in ('GPENCIL', 'GREASEPENCIL'):
obj_list.append(obj)
self.rename_suffix_prefix(obj_list, pre_suffix=wm.renaming_suffix_prefix_gpencil, object_type='GPENCIL',
icon='OUTLINER_OB_GREASEPENCIL')
@@ -1,13 +1,13 @@
schema_version = "1.0.0"
id = "simple_renaming_panel"
version = "2.1.6"
version = "2.1.8"
name = "Simple Renaming"
tagline = "Effortlessly rename multiple objects with this simple addon"
maintainer = "Matthias Patscheider <patscheider.matthias@gmail.com>"
type = "add-on"
website = "https://weisl.github.io/renaming_overview/"
website = "https://weisl.github.io/simple_renaming/renaming_overview/"
tags = ["3D View", "Scene", "User Interface"]
@@ -1,5 +1,4 @@
import bpy
from bpy.app.handlers import persistent
from bpy.props import (
BoolProperty,
EnumProperty,
@@ -10,15 +9,12 @@ from bpy.props import (
from . import add_pre_suffix
from . import case_transform
from . import reload_addon
from .version_check import start_version_check
from . import name_from_data
from . import name_replace
from . import numerate
from . import search_replace
from . import search_select
from . import trim_string
from .renaming_utilities import update_selection_order
enumObjectTypes = [('EMPTY', "", "Rename empty objects", 'OUTLINER_OB_EMPTY', 1),
('MESH', "", "Rename mesh objects", 'OUTLINER_OB_MESH', 2),
@@ -29,7 +25,7 @@ enumObjectTypes = [('EMPTY', "", "Rename empty objects", 'OUTLINER_OB_EMPTY', 1)
('CURVE', "", "Rename curve objects", 'OUTLINER_OB_CURVE', 64),
('SURFACE', "", "Rename surface objects", 'OUTLINER_OB_SURFACE', 128),
('FONT', "", "Rename font objects", 'OUTLINER_OB_FONT', 256),
('GPENCIL', "", "Rename greace pencil objects", 'OUTLINER_OB_GREASEPENCIL', 512),
('GPENCIL', "", "Rename grease pencil objects", 'OUTLINER_OB_GREASEPENCIL', 512),
('META', "", "Rename metaball objects", 'OUTLINER_OB_META', 1024),
('SPEAKER', "", "Rename empty speakers", 'OUTLINER_OB_SPEAKER', 2048),
('LIGHT_PROBE', "", "Rename mesh lightpropes", 'OUTLINER_OB_LIGHTPROBE', 4096),
@@ -83,36 +79,17 @@ classes = (
case_transform.VIEW3D_OT_case_camel,
case_transform.VIEW3D_OT_case_snake,
case_transform.VIEW3D_OT_case_kebab,
reload_addon.VIEW3D_OT_reload_addon,
)
enum_sort_items = [('X', "X Axis", "Sort the object based on the X axis."),
('Y', "Y Axis", "Sort the object based on the Y axis."),
('Z', "Z Axis", "Sort the object based on the Z axis."),
('SELECTION', "Selection", "Sort the objects based on the selection order"), ]
('Z', "Z Axis", "Sort the object based on the Z axis."), ]
enum_sort_bone_items = [('X', "X Axis", "Sort the object based on the X axis."),
('Y', "Y Axis", "Sort the object based on the Y axis."),
('Z', "Z Axis", "Sort the object based on the Z axis."), ]
# persistent is needed for handler to work in addons https://docs.blender.org/api/current/bpy.app.handlers.html
@persistent
def PostChange(scene):
if bpy.context.mode != "OBJECT":
return
# Any() function returns True if any element of an iterable is True. If not, it returns False.
is_selection_update = any(
not u.is_updated_geometry
and not u.is_updated_transform
and not u.is_updated_shading
for u in bpy.context.view_layer.depsgraph.updates
)
if is_selection_update:
update_selection_order()
def register():
id_store = bpy.types.Scene
@@ -210,8 +187,6 @@ def register():
for cls in classes:
register_class(cls)
bpy.app.handlers.depsgraph_update_post.append(PostChange)
start_version_check()
def unregister():
@@ -237,4 +212,3 @@ def unregister():
del IDStore.renaming_filter_by_index
del IDStore.renaming_index_target
bpy.app.handlers.depsgraph_update_post.remove(PostChange)
@@ -1,61 +0,0 @@
import bpy
from bpy.types import Operator
class VIEW3D_OT_reload_addon(Operator):
"""Reload all Simple Renaming scripts."""
bl_idname = "renaming.reload_addon"
bl_label = "Reload Addon"
bl_description = "Reload all Simple Renaming scripts"
def execute(self, context):
import importlib
import sys
# Derive the addon root package name by stripping the sub-package suffix.
# Works for both legacy addons ("simple_renaming.operators")
# and extensions ("bl_ext.user_default.simple_renaming.operators").
root_pkg = __package__.rsplit(".", 1)[0]
# Snapshot the module names now, before any reload happens.
# Sort key: deeper modules first (so core.* sub-modules reload before
# core.__init__), and alphabetically within the same depth so that
# "core.*" always reloads before "operators.*" before "ui.*".
mod_names = sorted(
[name for name in sys.modules
if name == root_pkg or name.startswith(root_pkg + ".")],
key=lambda n: (-n.count("."), n),
)
# Defer the actual reload to the next event-loop iteration so that this
# operator's own execute() has finished (and its class has been removed
# from the call stack) before we unregister and reload everything.
def _do_reload():
root_mod = sys.modules.get(root_pkg)
if root_mod and hasattr(root_mod, "unregister"):
try:
root_mod.unregister()
except Exception as exc:
print(f"[RENAMING] unregister error: {exc}")
for name in mod_names:
mod = sys.modules.get(name)
if mod is not None:
try:
importlib.reload(mod)
except Exception as exc:
print(f"[RENAMING] reload error for '{name}': {exc}")
# Re-fetch root after in-place reload to pick up any top-level changes.
root_mod = sys.modules.get(root_pkg)
if root_mod and hasattr(root_mod, "register"):
try:
root_mod.register()
except Exception as exc:
print(f"[RENAMING] register error: {exc}")
print(f"[RENAMING] Reloaded {len(mod_names)} modules from '{root_pkg}'")
bpy.app.timers.register(_do_reload, first_interval=0.0)
self.report({'INFO'}, f"Queued reload of {len(mod_names)} modules…")
return {'FINISHED'}
@@ -37,9 +37,7 @@ def get_renaming_list(context):
else:
sort_enum = scene.renaming_sort_enum
if sort_enum == 'SELECTION':
obj_list = get_ordered_selection_objects()
elif sort_enum == 'X':
if sort_enum == 'X':
obj_list = get_sorted_objects_x(obj_list)
elif sort_enum == 'Y':
obj_list = get_sorted_objects_y(obj_list)
@@ -51,7 +49,8 @@ def get_renaming_list(context):
if scene.renaming_object_types == 'OBJECT':
for obj in obj_list:
if obj.type in scene.renaming_object_types_specified:
effective_type = 'GPENCIL' if obj.type == 'GREASEPENCIL' else obj.type
if effective_type in scene.renaming_object_types_specified:
renaming_list.append(obj)
elif scene.renaming_object_types == 'DATA':
@@ -65,8 +64,8 @@ def get_renaming_list(context):
if selection_only:
for obj in context.selected_objects:
for mat in obj.material_slots:
if mat is not None and mat.name != '':
renaming_list.append(bpy.data.materials[mat.name])
if mat.material is not None:
renaming_list.append(mat.material)
else:
renaming_list = list(bpy.data.materials)
@@ -124,7 +123,7 @@ def get_renaming_list(context):
renaming_list.append(new_bone)
elif scene.renaming_object_types == 'COLLECTION':
if bpy.context.space_data.type == 'OUTLINER' and selection_only is True:
if bpy.context.space_data and bpy.context.space_data.type == 'OUTLINER' and selection_only is True:
selected_collections = [c for c in context.selected_ids if c.bl_rna.identifier == "Collection"]
for col in selected_collections:
renaming_list.append(col)
@@ -300,16 +299,6 @@ def get_global_z(obj):
return obj.matrix_world.to_translation().z
def get_ordered_selection_objects():
tagged_objects = []
for o in bpy.data.objects:
order_index = o.get("selection_order", -1)
if order_index >= 0:
tagged_objects.append((order_index, o))
tagged_objects = sorted(tagged_objects, key=lambda item: item[0])
return [o for i, o in tagged_objects]
def get_sorted_objects_x(objects):
# Sort objects by their global X location
sorted_objects = sorted(objects, key=get_global_x)
@@ -368,44 +357,3 @@ def update_bone_drivers(old_name, new_name):
target.data_path = target.data_path.replace(old_token, new_token)
def clear_order_flag(obj):
try:
del obj["selection_order"]
except KeyError:
pass
def update_selection_order():
if not (getattr(bpy.context, 'selected_objects', None) or list(bpy.context.view_layer.objects.selected)):
for o in bpy.data.objects:
clear_order_flag(o)
return
selection_order = get_ordered_selection_objects()
idx = 0
for o in selection_order:
if not o.select_get():
selection_order.remove(o)
clear_order_flag(o)
else:
o["selection_order"] = idx
# Remove any existing fcurves for 'selection_order'
if o.animation_data and o.animation_data.action:
action = o.animation_data.action
import bpy_extras.anim_utils as anim_utils
# Get the default channelbag for the action (slot 0)
channelbag = anim_utils.action_get_channelbag_for_slot(action, 0)
if channelbag:
fcurves = channelbag.fcurves
for fcurve in fcurves:
if fcurve.data_path == '["selection_order"]':
fcurves.remove(fcurve)
idx += 1
for o in bpy.context.selected_objects:
if o not in selection_order:
o["selection_order"] = len(selection_order)
selection_order.append(o)
@@ -1,62 +0,0 @@
import threading
import urllib.request
import urllib.error
import json
# Module-level state — read by the panel draw function
update_available = False
latest_version_str = ""
_RELEASES_URL = "https://api.github.com/repos/Weisl/simple_renaming/releases/latest"
def _parse_version(version_str):
"""Convert '2.1.4' or 'v2.1.4' to (2, 1, 4)."""
return tuple(int(x) for x in version_str.lstrip("v").split("."))
def _fetch():
global update_available, latest_version_str
try:
req = urllib.request.Request(
_RELEASES_URL,
headers={"User-Agent": "simple-renaming-addon"},
)
with urllib.request.urlopen(req, timeout=5) as response:
data = json.loads(response.read().decode())
tag = data.get("tag_name", "")
if not tag:
return
latest = _parse_version(tag)
# Read current version from blender_manifest.toml at the addon root
import os
manifest_path = os.path.join(os.path.dirname(__file__), "..", "blender_manifest.toml")
current_str = ""
with open(manifest_path, encoding="utf-8") as f:
for line in f:
if line.startswith("version"):
current_str = line.split("=")[1].strip().strip('"')
break
if not current_str:
return
current = _parse_version(current_str)
if latest > current:
update_available = True
latest_version_str = tag.lstrip("v")
else:
print(f"[RENAMING] Addon is up to date (v{current_str})")
except Exception as exc:
print(f"[RENAMING] version check failed: {exc}")
def start_version_check():
"""Fire a background thread to check for a newer release on GitHub."""
t = threading.Thread(target=_fetch, daemon=True)
t.start()
@@ -92,8 +92,7 @@ class VIEW3D_OT_renaming_preferences(bpy.types.AddonPreferences):
bl_options = {'REGISTER'}
prefs_tabs: EnumProperty(items=(('UI', "General", "General Settings"),
('KEYMAPS', "Keymaps", "Keymaps"),
('SUPPORT', "Support & Donation", "Support")),
('KEYMAPS', "Keymaps", "Keymaps")),
default='UI')
renaming_category: StringProperty(name="Category",
@@ -382,52 +381,3 @@ class VIEW3D_OT_renaming_preferences(bpy.types.AddonPreferences):
self.keymap_ui(layout, 'Renaming Sub/Prefix', 'renaming_suf_pre',
'wm.call_panel', "VIEW3D_PT_tools_type_suffix")
elif self.prefs_tabs == 'SUPPORT':
text = "Support me developing great tools!"
label_multiline(
context=context,
text=text,
parent=layout
)
# Donations
box = layout.box()
text = "Consider supporting the development of this addon with a donation!"
label_multiline(
context=context,
text=text,
parent=box
)
col = box.column(align=True)
row = col.row()
row.operator("wm.url_open", text="Gumroad",
icon="URL").url = "https://weisl.gumroad.com/l/simple_renaming"
row = col.row()
row.operator("wm.url_open", text="Superhive Market",
icon="URL").url = "https://superhivemarket.com/products/simple-renaming"
row = col.row()
row.operator("wm.url_open", text="PayPal Donation",
icon="URL").url = "https://www.paypal.com/donate?hosted_button_id=JV7KRF77TY78A"
# Cross Promotion
box = layout.box()
text = "Explore my other Blender Addons designed for more efficient game asset workflows!"
label_multiline(
context=context,
text=text,
parent=box
)
col = box.column(align=True)
row = col.row()
row.operator("wm.url_open", text="Simple Collider",
icon="URL").url = "https://superhivemarket.com/products/simple-collider"
row = col.row()
row.operator("wm.url_open", text="Simple Camera Manager",
icon="URL").url = "https://superhivemarket.com/products/simple-camera-manager"
row = col.row()
row.label(text='Support & Feedback')
row = col.row()
row.operator("wm.url_open", text="Join Discord", icon="URL").url = "https://discord.gg/VRzdcFpczm"
@@ -15,13 +15,6 @@ types_of_selected = (
def draw_renaming_panel(layout, context):
from ..operators.version_check import update_available, latest_version_str
if update_available:
row = layout.row(align=True)
row.alert = True
row.label(text=f"Update available: v{latest_version_str}", icon='ERROR')
scene = context.scene
row = layout.row(align=True)
@@ -47,7 +40,7 @@ def draw_renaming_panel(layout, context):
elif str(scene.renaming_object_types) in types_selected:
layout.prop(scene, "renaming_only_selection", text="Only Selected")
elif str(scene.renaming_object_types) == 'COLLECTION':
if bpy.context.space_data.type == 'OUTLINER':
if bpy.context.space_data and bpy.context.space_data.type == 'OUTLINER':
row = layout.row(align=True)
row.prop(scene, "renaming_only_selection", text="Only Selected")
else:
@@ -191,13 +184,12 @@ class VIEW3D_PT_tools_renaming_panel(bpy.types.Panel):
def draw_header(self, context):
layout = self.layout
row = layout.row(align=True)
row.operator("wm.url_open", text="", icon='HELP').url = "https://weisl.github.io/renaming_overview/"
row.operator("wm.url_open", text="", icon='HELP').url = "https://weisl.github.io/simple_renaming/renaming_overview/"
addon_name = get_addon_name()
op = row.operator("preferences.rename_addon_search", text="", icon='PREFERENCES')
op.addon_name = addon_name
op.prefs_tabs = 'UI'
row.operator("renaming.reload_addon", text="", icon='FILE_REFRESH')
def draw(self, context):
layout = self.layout
@@ -21,18 +21,4 @@ class PREFERENCES_OT_open_addon(bpy.types.Operator):
prefs = context.preferences.addons[base_package].preferences
prefs.prefs_tabs = self.prefs_tabs
import addon_utils
mod = addon_utils.addons_fake_modules.get('simple_renaming')
# mod is None the first time the operation is called :/
if mod:
mod.bl_info['show_expanded'] = True
# Find User Preferences area and redraw it
for window in bpy.context.window_manager.windows:
for area in window.screen.areas:
if area.type == 'USER_PREFERENCES':
area.tag_redraw()
bpy.ops.preferences.addon_expand(module=self.addon_name)
return {'FINISHED'}