update addons (for 5.2)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
Documentation: https://weisl.github.io/renaming_overview/
|
||||
Documentation: https://weisl.github.io/simple_renaming/renaming_overview/
|
||||
|
||||
[](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,
|
||||
|
||||
+1
-1
@@ -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'}
|
||||
|
||||
Reference in New Issue
Block a user